在 Linux 中,是否有一个层/脚本来处理打开文件的程序请求?
就像你在 bash: 中打开文件描述符一样:exec 3 <>/documents/foo.txt
或者你的文本编辑器打开/documents/foo.txt
我不敢相信一个编辑器可以“打开一个文件”自己进行读/写访问。
我宁愿想象这是对“层”(init.d 脚本?)的请求,它可以从只打开一定数量的文件开始,并通过它们的访问类型,通过它们是什么进程保持打开文件的标签打开等
在 linux 中打开文件是由内核直接处理的,但是你可以做一些事情来影响和研究这个过程。
从顶部开始,您可以看到应用程序用于与文件交互的接口是系统调用。
Open,read和write做你期望的,而stat返回有关文件的信息而不打开它。
您可以使用 strace 研究程序对文件相关系统调用的使用:
$ strace -e trace=%file /bin/ls /etc
[...]
stat("/etc", {st_mode=S_IFDIR|0755, ...}) = 0
openat(AT_FDCWD, "/etc", O_RDONLY...) = 3
Run Code Online (Sandbox Code Playgroud)
这会分析由 引起的系统调用ls /etc
,显示stat
和openat
在/etc
目录上被调用。
您可能想知道为什么我们要对目录调用文件操作。在 UNIX 中,目录也是文件。事实上一切都是一个文件!
您可能想知道openat() = 3
上面输出中的 。
在 UNIX 中,打开的文件由文件描述符表示,它是某个进程打开文件的唯一表示。文件描述符 0、1 和 2 通常为标准流(用户输入/输出)保留,因此第一个打开的文件将为 3。
您可以通过使用得到给定的进程打开文件的描述符列表lsof
(升我小号牛逼Ø笔˚F尔斯):
$ cat /dev/urandom > /dev/null &
[1] 3242
$ lsof -p 3242
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
...
cat 3242 user 0u CHR 136,0 0t0 3 /dev/pts/0
cat 3242 user 1w CHR 1,3 0t0 1028 /dev/null
cat 3242 user 2u CHR 136,0 0t0 3 /dev/pts/0
cat 3242 user 3r CHR 1,9 0t0 1033 /dev/urandom
Run Code Online (Sandbox Code Playgroud)
该FD
列显示文件描述符编号以及访问权限。
您还可以使用fuser
搜索保存特定文件的进程:
$ fuser /dev/urandom
/dev/urandom: ... 3242 ...
Run Code Online (Sandbox Code Playgroud)
现在您可能想知道:但是首先如何lsof
知道哪些文件是打开的?
好吧,让我们来看看!
$ strace -e trace=%file lsof -p 3242
...
stat("/proc/3242/", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0
openat(AT_FDCWD, "/proc/3242/stat", O_RDONLY) = 4
...
openat(AT_FDCWD, "/proc/3242/fd", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 4
readlink("/proc/3242/fd/0", "/dev/pts/0", 4096) = 10
lstat("/proc/3242/fd/0", {st_mode=S_IFLNK|0700, st_size=64, ...}) = 0
stat("/proc/3242/fd/0", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0
openat(AT_FDCWD, "/proc/3242/fdinfo/0", O_RDONLY) = 7
...
Run Code Online (Sandbox Code Playgroud)
所以lsof
知道知道哪些文件是通过...阅读更多文件打开的!具体来说,目录/proc/3242/fd
. 下面的一切都是/proc
内核保存的“假”文件系统。你可以ls -l
看看它的结构。
您可以使用多种方法来影响文件打开,尽管它们并不像仅仅替换一些脚本那么简单。
如果您希望改变文件的存储或访问方式,例如提供加密、缓存、将其分布到多个磁盘或类似的东西,那么很有可能已经有一个适合您需求的现有设备映射器。
如果您想对特定目录/挂载中的文件打开进行细粒度控制,您可以编写一个简单的FUSE文件系统并挂载它。
在程序/进程级别,您可以使用LD_PRELOAD来更改 C 库调用并阻止它们执行正常的系统调用。
最困难但最灵活的方法是编写自己的文件系统驱动程序。
管理对文件的访问是操作系统的第一个也是最重要的功能。DOS 是个人计算机上最古老的操作系统之一,意思是磁盘操作系统。它允许程序在大多数情况下直接访问硬件,但不允许访问文件。程序必须使用 DOS 调用,而 DOS 会为程序管理将数据放入和取出文件。只有磁盘实用程序才能在 DOS 下直接访问硬盘驱动器和文件。
像 Linux 这样的现代保护模式操作系统可以像 DOS 那样处理文件的访问,但它们也要求每次访问程序本身(或任何其他被配置为与之共享内存的程序)之外的任何东西,以通过内核(Linux 是一个内核)。
Linux 上的程序可能会调用 C 库中的函数来读取数据或将数据写入文件。然后,C 库会组织对文件中数据的访问,同时仍与您的程序在相同的上下文中运行。然后 C 库将调用具有正确函数的内核 (Linux) 来访问文件,从而将 CPU 切换到 ring 0 或特权模式。CPU现在以特权模式运行Linux文件系统驱动程序和硬盘驱动器驱动软件,直接访问硬件访问文件。数据被复制到 C 库指示 Linux 放置数据的内存区域,CPU 切换回用户模式,并使用程序的安全上下文,C 库恢复并执行它需要执行的任何处理该数据,然后返回执行您的程序。
归档时间: |
|
查看次数: |
1352 次 |
最近记录: |