在 Linux 中,是否有处理文件打开的系统层/脚本?

von*_*otz 6 linux files

在 Linux 中,是否有一个层/脚本来处理打开文件的程序请求?

就像你在 bash: 中打开文件描述符一样:exec 3 <>/documents/foo.txt或者你的文本编辑器打开/documents/foo.txt

我不敢相信一个编辑器可以“打开一个文件”自己进行读/写访问。

我宁愿想象这是对“层”(init.d 脚本?)的请求,它可以从只打开一定数量的文件开始,并通过它们的访问类型,通过它们是什么进程保持打开文件的标签打开等

Gil*_*il' 12

这一层位于 Linux 和其他与历史 Unix 设计相差不远的系统(以及大多数非 Unix 操作系统中)的内核内部。

内核的这部分称为VFS(虚拟文件系统)层。VFS 的作用是管理有关打开文件的信息(文件描述符打开文件描述和目录条目之间的对应关系)、解析文件路径(解释/...),并将目录条目上的操作分派给正确的文件系统驱动程序。

大多数文件系统驱动程序也在内核中,但FUSE文件系统驱动程序允许将此功能委托给内核之外。如果较低级别的存储这样做,文件系统操作也可能涉及用户土地代码,例如,如果磁盘文件系统在循环设备上


loo*_*bee 9

在 linux 中打开文件是由内核直接处理的,但是你可以做一些事情来影响和研究这个过程。


Linux 存储堆栈图


系统调用

从顶部开始,您可以看到应用程序用于与文件交互的接口是系统调用

Openreadwrite做你期望的,而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,显示statopenat/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)

进程信息伪文件系统 - /proc

现在您可能想知道:但是首先如何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 库调用并阻止它们执行正常的系统调用。

最困难但最灵活的方法是编写自己的文件系统驱动程序。


Ale*_*non 6

管理对文件的访问是操作系统的第一个也是最重要的功能。DOS 是个人计算机上最古老的操作系统之一,意思是磁盘操作系统。它允许程序在大多数情况下直接访问硬件,但不允许访问文件。程序必须使用 DOS 调用,而 DOS 会为程序管理将数据放入和取出文件。只有磁盘实用程序才能在 DOS 下直接访问硬盘驱动器和文件。

像 Linux 这样的现代保护模式操作系统可以像 DOS 那样处理文件的访问,但它们也要求每次访问程序本身(或任何其他被配置为与之共享内存的程序)之外的任何东西,以通过内核(Linux 是一个内核)。

Linux 上的程序可能会调用 C 库中的函数来读取数据或将数据写入文件。然后,C 库会组织对文件中数据的访问,同时仍与您的程序在相同的上下文中运行。然后 C 库将调用具有正确函数的内核 (Linux) 来访问文件,从而将 CPU 切换到 ring 0 或特权模式。CPU现在以特权模式运行Linux文件系统驱动程序和硬盘驱动器驱动软件,直接访问硬件访问文件。数据被复制到 C 库指示 Linux 放置数据的内存区域,CPU 切换回用户模式,并使用程序的安全上下文,C 库恢复并执行它需要执行的任何处理该数据,然后返回执行您的程序。