python3 os.mkdir() 不强制执行正确模式

python3 os.mkdir() does not enforce correct mode

这是错误还是功能?

当我使用 os.mkdir(同上 pathlib.Path.mkdir)和显式模式创建目录时,创建目录的权限不适合。如果我再次使用 os.chmod 强制执行,它会起作用...

>>> import sys, os
>>> sys.version
'3.4.3 (default, Feb 27 2015, 18:13:37) \n[GCC 4.4.5]'
>>> os.mkdir('truite', mode=0o2770)
>>> oct(os.stat('truite').st_mode)
'0o40750'
>>> os.chmod('truite', 0o2770)
>>> oct(os.stat('truite').st_mode)
'0o42770'

因为我希望能够创建一个目录,父目录和模式 o2770,这里是代码(pth 是一个 pathlib.Path 对象):

def make_shared_dir(pth) :
    if not pth.parent.is_dir() :
        make_shared_dir(pth.parent)
    if not pth.is_dir() :
        pth.mkdir()
    pth.chmod(0o2770)   

这是一项功能。

documentation 提到了它,尽管很简短:

os.mkdir(path[, mode])

Create a directory named path with numeric mode mode. The default mode is 0777 (octal). On some systems, mode is ignored. Where it is used, the current umask value is first masked out.

A umask 是每个进程的设置,它限制应用于所有新创建的权限 files/directories。

umask 是一个数字(通常以八进制表示)就像权限本身一样,但是在 umask 中 set 的任何位都是 disallowed 在生成的权限中。例如,如果您的 umask 是 0o022(常见默认值),则新创建的 file/directory 将永远不会拥有组或世界写入权限。

对新创建的 files/directories 的权限也始终限于最后三个八进制数字(即 0o777)。因此,如果您的 umask 是 0o022,则一切都表现得好像它真的是 0o7022。 这就是为什么您的 setgid 位也被删除的原因。

顺便说一下,这不是 Python 的事情;这是一个 Unix 的东西。它不仅适用于 Python,还适用于 Ubuntu 中的所有程序。您可以通过在终端中输入 umask 命令来检查当前的 umask。事实上,当 Linux 内核执行 Python(以及所有其他程序)调用以创建目录的 mkdir() 系统调用时,umask 由内核强制执行。

您可以在 the documentation for mkdir() 中亲自查看:man 2 mkdir:

The argument mode specifies the permissions to use. It is modified by the process's umask in the usual way: the permissions of the created directory are (mode & ~umask & 0777).

当然是安全问题。使用 umask,用户可以对默认权限进行大量控制(例如,阻止世界甚至组的默认读取权限)。如果您想要粘性文件、setuid、setgid、组可写或世界可写(假设 0o022 umask),您需要使用 chmod 显式地执行此操作。