Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python3 os.mkdir() does not enforce correct mode

Is it a bug or a feature ?

When I create a directory with os.mkdir (idem with pathlib.Path.mkdir) and an explicit mode, the permissions of the created directory does not fit. If I enforce with os.chmod again, it works...

>>> 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'

since I wanted to be able to make a directory with parents and mode o2770, here is the code (pth is a pathlib.Path object) :

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)   
like image 978
yota Avatar asked May 09 '16 14:05

yota


People also ask

What is mode in OS mkdir?

os.mkdir(path[,mode]) path is the path where you want to complete the new directory. mode is the mode of the directory to be given. The default mode is 0777 ( o c t a l ) 0777 (octal) 0777(octal).

What does OS mkdir do in Python?

mkdir() method in Python is used to create a directory named path with the specified numeric mode. This method raise FileExistsError if the directory to be created already exists.

How do I run mkdir in Python?

Python method mkdir() 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.

What is the use of mkdir () and Mkdirs () methods in Python?

mkdir() method creates a blank directory on your file system. You cannot use this method to create a folder in a folder that does not exist. The os. mkdirs() method recursively creates a blank directory.


1 Answers

It's a feature.

The documentation mentions it, albeit briefly:

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 is a per-process setting that limits the permissions applied to all newly created files/directories.

A umask is a number (usually presented in octal) just like permissions themselves, but any bit that is set in the umask is disallowed in the resulting permissions. For example, if your umask is 0o022 (a common default), no newly created file/directory will ever have group or world write permissions.

Permissions on newly created files/directories are also always restricted to the last three octal digits (i.e. 0o777). So if your umask is 0o022, everything behaves as if it were really 0o7022. This is why your setgid bit is also dropped.

By the way, this is not a Python thing; it's a Unix thing. It doesn't just apply to Python, but to all programs in Ubuntu. You can check your current umask by entering the umask command in your terminal. In fact, the umask is enforced by the Linux kernel when it performs the mkdir() systemcall that Python (and every other program) invokes to create a directory.

You can see this for yourself in 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).

The reason is, of course, security. With umask, users have a great deal of control over default permissions (to e.g. block default read permissions for world or even group). If you want files that are sticky, setuid, setgid, group-writable, or world-writable (assuming a 0o022 umask), you need to do this explicitly using a chmod.

like image 152
marcelm Avatar answered Oct 01 '22 01:10

marcelm