【问题标题】:Is there a way on a POSIX system to atomically create a directory if it doesn't exist?如果目录不存在,POSIX 系统有没有办法自动创建目录?
【发布时间】:2021-03-04 21:35:37
【问题描述】:

在 POSIX 系统上是否有任何方法可以仅在目录尚不存在时自动创建目录?

类似于

int fd = open( "/path/to/file", O_CREAT | O_EXCL | O_RDWR, 0644 );

这不起作用:

int dfd = open( "/path/to/dir", O_DIRECTORY | O_CREAT | O_EXCL | O_RDWR, 0755 );

在我的 Solaris 11 和 Ubuntu 20.04 系统上失败,errno 在 Solaris 上设置为 EINVAL,在 Ubuntu 上设置为 ENOTDIR

POSIX open() documentationO_CREAT 声明了这一点:

如果文件存在,则此标志无效,除非在下面的O_EXCL 中注明。否则,如果没有设置O_DIRECTORY ...

嗯,它不是一个文件,并且设置了O_DIRECTORY

(受Race condition stat and mkdir 问题的启发 - 如果目录尚不存在,POSIX 中似乎没有任何方法可以自动创建目录。)

【问题讨论】:

  • 类似mkdir -p "/path/to/dir"?
  • 为什么不mkdir()
  • 好吧,我很想用“我已阅读整个 POSIX 标准”来写一个“不”的答案,但那将是......夸张;)
  • @BlockofDiamond mkdir() 不保证会同时创建一个目录自动打开它。据我所知,在 POSIX 下没有办法做到这一点。我不知道是否需要它类似于导致O_EXCL 的安全原因以及在C11 中添加到fopen()"x" 独占模式,但我确实感到惊讶的是没有办法我已经能够找到执行它。
  • @KamilCuk 我怀疑你是对的——但仅仅因为我找不到东西或想出办法来做这件事并不意味着其他人不能。我确实挖掘了一段时间 - 你认为我如何知道尝试产生的 errno 值? :-)

标签: c posix


【解决方案1】:

要回答您标题中的问题,mkdir 会这样做 - 不需要额外的标志,因为 mkdir 将始终“原子地”创建一个目录,当且仅当它不存在时(并且路径不是文件)。

从 cmets 看来,您实际上想自动创建并打开一个目录,但这似乎是一个 XY 问题。为什么,因为无论如何您都无法打开目录进行写入?如果您首先创建然后打开目录(非原子方式),那么行为没有差异(也没有竞争条件),就好像在此期间有人删除了目录,打开将失败。

如果您担心只在设置了权限的目录中创建文件,使得没有人(其他)可以读取它们,您可以在打开目录后检查目录的权限和所有权(使用 fstat)。

【讨论】:

  • 因为openat() 和亲戚,有一个目录的fd 确实允许你在某种意义上“写”它。您可能担心的竞争是您创建目录,然后其他人将其删除并创建指向其他目录的同名符号链接,然后您打开它。
  • 如果他们可以修改包含目录,他们甚至可以在 mkdir 之前做到这一点,并且即使使用原子 mkdir+open 也可以修改您创建的目录,所以不清楚可以获得什么.
  • 假设我的对手可以写信给/foo/bar,但不能写给/foo。如果我有一个原子mkopendir,我可以安全地做int d = mkopendir("/foo/bar/baz", 0700); int fd = openat(d, "/foo/bar/baz/important.txt", O_WRONLY | O_CREAT | O_TRUNC, 0600);。如果/foo/bar/baz 在两者之间被删除,openat 将失败。但是,如果我使用mkdir / open / openat 进行操作,那么在mkdiropen 之间,我的对手可以rmdir /foo/bar/baz ; ln -s /home/nate /foo/bar/baz 并且我将覆盖/home/nate/important.txt
  • 要回答您标题中的问题,mkdir 会这样做... 我不太确定。在mkdir() 调用和任何以后调用使用该目录的东西之间,例如opendir()chdir,甚至是该目录中文件的open(),原始目录可以替换为其他内容,例如作为指向其他目录的软链接。如果您能够使用open()O_DIRECTORY | O_CREAT | O_EXCL 在一个原子操作中创建打开一个目录,则该打开描述符可以用作对已创建目录的保证引用,没有可以参加比赛。
  • (cont) 我不相信这种能力有任何使用,但似乎缺乏这样做的能力。即使可以找到合法的用途来解决利用该竞争条件的某种方式,我怀疑还有其他方法可以防止该攻击向量可用。
猜你喜欢
  • 2010-10-07
  • 2016-04-28
  • 1970-01-01
  • 2017-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-17
  • 2018-08-01
  • 1970-01-01
相关资源
最近更新 更多