Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

os.makedirs' mode argument has bad default value #49470

Closed
jab mannequin opened this issue Feb 11, 2009 · 11 comments
Closed

os.makedirs' mode argument has bad default value #49470

jab mannequin opened this issue Feb 11, 2009 · 11 comments

Comments

@jab
Copy link
Mannequin

jab mannequin commented Feb 11, 2009

BPO 5220
Nosy @loewis, @bitdancer, @jab

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = <Date 2009-02-11.20:50:55.583>
created_at = <Date 2009-02-11.20:36:09.801>
labels = ['invalid']
title = "os.makedirs' mode argument has bad default value"
updated_at = <Date 2010-06-15.06:49:07.459>
user = 'https://github.com/jab'

bugs.python.org fields:

activity = <Date 2010-06-15.06:49:07.459>
actor = 'smyrman'
assignee = 'none'
closed = True
closed_date = <Date 2009-02-11.20:50:55.583>
closer = 'loewis'
components = []
creation = <Date 2009-02-11.20:36:09.801>
creator = 'jab'
dependencies = []
files = []
hgrepos = []
issue_num = 5220
keywords = []
message_count = 11.0
messages = ['81666', '81669', '81674', '81677', '81680', '107764', '107773', '107840', '107842', '107843', '107847']
nosy_count = 4.0
nosy_names = ['loewis', 'r.david.murray', 'jab', 'smyrman']
pr_nums = []
priority = 'normal'
resolution = 'not a bug'
stage = None
status = 'closed'
superseder = None
type = None
url = 'https://bugs.python.org/issue5220'
versions = ['Python 2.6', 'Python 2.5', 'Python 2.4', 'Python 3.0', 'Python 3.1', 'Python 2.7']

@jab
Copy link
Mannequin Author

jab mannequin commented Feb 11, 2009

os.makedirs' mode argument defaults to a hardcoded value of 511 (0777 in
octal). This forces the caller to either pass in a different hardcoded value
(commonly 0750), or to implement a workaround that calculates the expected
mode based on the process owner's umask:

umask, _ = subprocess.Popen(['sh', '-c', 'umask'],
               stdout=subprocess.PIPE).communicate()
umask = int(umask, 8)
mode = 0777 ^ umask
os.makedirs(dir, mode)

Preferred behavior would be to have the mode default to the value which
takes the umask into account rather than the hardcoded value 0777, so that
directories would be created with the same permissions as e.g. files created
via open(..).

N.B. I'm guessing the above workaround won't work on Windows (please excuse
my poor Windows knowledge). All the more reason to have os.makedirs
calculate the mode properly if none is given.

@loewis
Copy link
Mannequin

loewis mannequin commented Feb 11, 2009

I don't understand the problem. The directory creation *does* take the
umask into account - that's the whole point of the umask! The directory
being created has the bits (mode & ~umask & 0777) set - because of the
semantics of mkdir(2), not because of Python's doing.

Closing the report as invalid.

@loewis loewis mannequin closed this as completed Feb 11, 2009
@loewis loewis mannequin added the invalid label Feb 11, 2009
@jab
Copy link
Mannequin Author

jab mannequin commented Feb 11, 2009

Ah, I was misunderstanding the behavior of mkdir, thank you for the
explanation.

My misunderstanding stemmed from recently coming across two widely-used
packages which both pass mode=0750 to os.makedirs. I have no idea why
they would be doing this (as it effectively throws away part of the
umask), unless they too are misunderstanding the mode parameter. My
suspicion is that the mode parameter is widely misunderstood to mean the
desired permissions of the created directory. I have filed tickets in
the packages in which I came across this to make sure they're doing what
they intend.

Could the __doc__ for os.mkdir and os.makedirs be expanded to make this
clearer?

@loewis
Copy link
Mannequin

loewis mannequin commented Feb 11, 2009

My misunderstanding stemmed from recently coming across two widely-used
packages which both pass mode=0750 to os.makedirs. I have no idea why
they would be doing this (as it effectively throws away part of the
umask), unless they too are misunderstanding the mode parameter.

You use such a mode if you want the resulting directory definitely not
world-readable, and definitely not group-writable, despite what umask
the user running the program may have set.

A common case is installation programs, where the installer wants to
create directories independent of the umask root may have set when
running the installer.

My
suspicion is that the mode parameter is widely misunderstood to mean the
desired permissions of the created directory. I have filed tickets in
the packages in which I came across this to make sure they're doing what
they intend.

My suspicion is that people setting explicit file permissions typically
know what they are doing, and that you will find that your tickets get
closed as invalid, explaining to you that this mode usage is fully
intentional.

Could the __doc__ for os.mkdir and os.makedirs be expanded to make this
clearer?

I'm skeptical that this should be necessary. Whoever explained umask to
you should have mentioned how it really works (i.e. that it is built
into and considered by the operating system every time a file or
directory is created).

By the same pattern, the doc string of mkdir should also explain what
relative file names are and how the current directory affects their
interpretation. IMO, the doc string shouldn't teach fundamental system
principles.

@jab
Copy link
Mannequin Author

jab mannequin commented Feb 11, 2009

My suspicion is that people setting explicit file permissions
typically know what they are doing, and that you will find that
your tickets get closed as invalid, explaining to you that this
mode usage is fully intentional.

For what it's worth, I asked Mike Bayer (author of Beaker and Mako, the
packages in question) what the intention was, and the 0750 seems to have
been an error: Apparently HTML::Mason (what Myghty was based on) may
have originally used 0750 but has since changed it to 0775 (search for
"0775" in http://svn.urth.org/filedetails.php?
repname=Mason&path=%2Ftrunk%2Flib%2FHTML%2FMason%2FInterp.pm&rev=0&sc=0)
. The 0750 propagated from Myghty into Mako and Beaker, but has no
apparent reason to be there.

For what else it's worth, I've run this by a few other programmers I
consider quite smart and experienced (including Ian Bicking), and none
of them realized the meaning of the mode parameter either. (If they had
I never would have filed this ticket, as I checked with them first!)

I agree that knowledge of relative paths should be assumed, but I'm
convinced that the mode behavior is widely misunderstood enough to
warrant at least one-line "gotcha" in the docstring.
</$.02>

@smyrman
Copy link
Mannequin

smyrman mannequin commented Jun 13, 2010

I have to agree with jab. While the way relative paths works are more or less common knowledge, the way umask does and does not work in relation to python isn't.

It is however given a short description at http://docs.python.org/library/os.html#os.makedirs:
...The default mode is 0777 (octal). On some systems, mode is ignored. Where it is used, the current umask value is first masked out.

And as it is documented (briefly) online that the umask *is* used, perhaps it is not necessary to add it to the doc-string?

@bitdancer
Copy link
Member

I don't understand what you mean when you say "how umask works in relation to Python". How it works in relation to Python isn't different from how it works for any other Unix program. Consider, for example, the unix man page for 'open'.

I don't think a docstring change is called for; the docstrings are brief summaries to act as memory aids, the real docs are the docs. If someone does want to propose such a change they should open a new issue.

@smyrman
Copy link
Mannequin

smyrman mannequin commented Jun 14, 2010

I don't understand what you mean when you say "how umask works in
relation to Python". How it works in relation to Python isn't different
from how it works for any other Unix program. Consider, for example,
the unix man page for 'open'.

This is what I mean.
The following gnu commands give (on Archlinux):
$ umask
0022
$ mkdir test1
$ mkdir test2 --mode 0777
$ ls -l
drwxr-xr-x 2 sindrero users 4096 Jun 15 00:59 test
drwxrwxrwx 2 sindrero users 4096 Jun 15 00:59 test2

So we see that new folder created with the --mode parameter to gnu's mkdir does not get the umask masked out.

The following code in python gives:

> import os
> os.mkdir('test3')
> os.mkdir('test4')
> exit()
$ ls -l
drwxr-xr-x 2 sindrero users 4096 Jun 15 01:01 test3
drwxr-xr-x 2 sindrero users 4096 Jun 15 01:01 test4

I (as a programmer) have never seen the specific code for python's mkdir function, And I have no way to know whether I should presume that mkdir in python works the same way as the gnu command or not. Unless it is documented that is.

Cheers :)

@smyrman
Copy link
Mannequin

smyrman mannequin commented Jun 14, 2010

*Sorry.. A bit quick there. The line

> os.mkdir('test4')
should have been:
> os.mkdir('test4', 0777)

@loewis
Copy link
Mannequin

loewis mannequin commented Jun 14, 2010

I (as a programmer) have never seen the specific code for python's
mkdir function, And I have no way to know whether I should presume
that mkdir in python works the same way as the gnu command or not.
Unless it is documented that is.

You should assume that Python's mkdir does the same as Linux' mkdir
system call (which is different from the mkdir utility). You can
see mkdir's document with "man 2 mkdir", or on

http://linux.die.net/man/2/mkdir

@smyrman
Copy link
Mannequin

smyrman mannequin commented Jun 15, 2010

Thank you very much for the clarification :)

@ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant