为什么openat()需要避免使用stat然后open()的两步竞争条件?

Mar*_*eck 12 linux-kernel

解释在

http://man7.org/linux/man-pages/man2/open.2.html

关于为什么openat需要,请参阅:

openat()允许应用程序避免在使用open()打开当前工作目录以外的目录中的文件时可能发生的竞争条件.这些竞争条件是由于open()的目录前缀的某些组件 可以与open()的调用并行更改.例如,假设我们希望在文件 路径/到/ xxx存在时创建文件路径/到/ xxx.dep.问题是在存在检查和文件创建步骤之间,可以修改path或to(可能是符号链接)以指向不同的位置.

我不明白为什么这场比赛是一个问题.如果一个应用程序想要检查是否存在某个文件,如果是,则创建一个不同的文件,然后,这当然是两个步骤,应用程序要么应该确保之间没有任何干扰,要么接受做两个的后果 - 步骤操作.只有在单个调用open()可能导致竞争条件时,才可能openat()需要其他一些系统调用.否则,这不是系统调用解决的问题,但应用程序负责处理.

我在这里不理解什么?

skr*_*sme 8

TL; DR
openat()允许您锁定整个目录路径,仅解决竞争条件一次,然后安全地打开相对于该路径的文件而不必担心竞争条件.

详细信息
您是正确的,竞争条件仍然是您的程序预期和处理的责任,但该openat()功能允许您对多个文件执行一次.如果要在同一目录中打开多个文件,可以通过单独调用来执行此操作open(),但每次都必须预期并处理竞争条件.相反,使用openat(),您可以首先将文件描述符获取到父目录,这将阻止其他进程修改或删除该路径.您现在可以使用openat()相对于该锁定路径安全地打开多个文件,而不必担心打开绝对路径通常需要的竞争条件.

其他用例
还要注意,竞争条件不一定在程序打开文件和其他程序更改或删除路径之间 - 它也在程序中的线程之间.openat()当您想要使用相对路径并处于多线程环境中时,它非常有用.请记住,如果您在一个线程中更改工作目录,则会针对整个进程及其线程更改它.

因此,当你分叉多个线程时,他们每个人都可以获取不同目录的文件描述符,并使用openat()这些目录文件描述符和它们的相对路径来打开文件,而不必担心其他线程在整个进程的工作中做了什么目录,或保持绝对路径的负载.

此用例由手册页中的第二个注释描述openat:

其次,了openat()允许每个线程的"当前工作目录"的实施,通过由应用程序维护文件描述符(一个或多个).(此功能也可以通过基于使用/ proc/self/fd/dirfd的技巧获得,但效率较低.

旁注
我不想深入讨论系统调用应该承担什么责任,因为它会变得主观,但请注意,这openat并不能真正解决竞争条件 - 当你试图锁定时,你仍然可以拥有一个父目录,这完全是您的程序负责处理.在您获得一次解决方案后,它是一种帮助您预防竞争条件的工具.我认为这是一个有用且合理的机制,可以作为系统调用包含在操作系统中.