O_EXCL 的写出字是什么

nyr*_*ium 6 c++ linux posix system-calls c++11

当我注意到我找不到 的写出单词时,我正在enum class为 中列出的不同文件标志编写一个保险箱。open(3)O_EXCL

enum class Flags {
    readOnly, // O_RDONLY
    truncate, // O_TRUNC
    ?         // O_EXCL
};
Run Code Online (Sandbox Code Playgroud)

我想到了两种可能的含义:

  • OPEN_EXCLUSIVE
  • OPEN_EXISTS_CLOSE

但我找不到任何有关其预期含义的资源。

Mec*_*cki 20

真正的含义O_EXCL是“如果创建且文件存在则出错”,但该名称源自“ EXCLusive ”,但这有点误导并导致许多人误解该标志。

正如某些人错误地认为的那样,打开文件O_EXCL不会为您提供对它的独占访问权限。一个进程打开的文件O_EXCL可以同时被其他进程打开进行读取甚至写入,没有问题,因此访问显然不具有排他性。

该标志存在的主要原因是“锁定文件”。早在出现fcntl可以在进程之间共享的文件咨询锁定(使用)和信号量/互斥体之前,就需要一种简单的方法来确保跨多个进程对某些系统资源的原子访问。实现这一点的方法是锁定文件。第一个想要访问资源的进程将创建一个锁定文件来/var/lock声明该资源的所有权,并在使用完毕后再次将其删除。其他进程将监视该目录,从而知道资源是否可用。

问题:如果两个进程查看目录并且都发现某个文件不存在,因此资源可用,并且现在都尝试创建该文件,如何确保两者中只有一个会成功?这就是O_EXCL发挥作用的地方。如果它们都尝试使用 set 创建该文件O_EXCL,则此操作只会对其中一个成功,并且该进程现在拥有资源锁。

所以O_EXCL不是为了获得对文件的独占访问,而是为了创建独占访问文件,其目的是调节对某种资源的独占访问。

当今第二个最重要的用途O_EXCL是文件访问安全。考虑这种情况:根进程想要创建一个文件并填充只有根用户(而不是普通用户)才能看到的内容,但它在普通用户有写访问权限的目录中创建它(例如/tmp)。如果该过程将创建文件如下

open("/tmp/root-only", O_CREAT | O_WRONLY, 0600);
Run Code Online (Sandbox Code Playgroud)

并且该文件不存在,它是由 root 创建并拥有的,并且只有 root 对其具有读写权限,因此普通用户无法看到其内容。任务完成。

但是如果普通用户/tmp/root-only之前已经创建过怎么办?那么该文件就归该用户所有,该用户可以对其具有读取权限,并且上面的 open 调用将仅打开现有文件。即使根进程在打开文件后直接更改所有权和文件权限,这对之前已经打开过该文件的进程也没有影响(例如tail -f)。

所以实现该案例的正确方法实际上是:

unlink("/tmp/root-only"); // best effort, may not even exist
open("/tmp/root-only", O_CREAT | O_EXCL | O_WRONLY, 0600);
Run Code Online (Sandbox Code Playgroud)

如果open成功,进程可以依赖该文件由进程所有者拥有,并且其他人没有访问权限来读/写它。


mda*_*sev 3

此处的“独占”一词是正确的,因为该标志是该O_CREAT标志所独占的,并且如果文件存在则会使该函数失败。(如果O_CREAT未设置该标志,则行为未定义。)