How to avoid a race condition with makedirs?

directory, python, race-condition

Solution

I'll note that all of this is quite a bit more sane in python 3; `FileExistsError` and `PermissionError` are separate (subclass of `OSError`) exceptions that you can catch, and `os.makedirs` even has a `exist_ok` kwarg to suppress the former when you're ok with the directory already existing.

If you want to inspect the reason for the `OSError`, that info is in a tuple in `e.args` (or optionally `e.errno` if you just want to look at the error code):

try:
    os.makedirs('/etc/python')
except OSError as e:
    print e.args

(17, 'File exists')

try:
    os.makedirs('/etc/stuff')
except OSError as e:
    print e.args

(13, 'Permission denied')

try:
    os.makedirs('/etc/stuff')
except OSError as e:
    print e.errno

13

So you'll have to do a bit of introspection and handle the two error codes differently in your `except` block.

Problem

I am attempting to convert the following pseudo-code to Python: ``` If <directory> does not exist: Create all subdirectories for <directory> Create a file in <directory> ``` This sounds simple enough to accomplish with `os.makedirs` and `os.path.isdir`: ``` if not os.path.isdir('/some/path'): os.makedirs('/some/path') open('/some/path/test.txt', 'w') ``` However, upon further inspection there is clearly a race condition present. Consider the following timeline: - the specified directory (`/some/path`) does not exist - the Python interpreter executes the first line, which evaluates to `True` - another process creates the directory (`/some/path`) - `makedirs` raises an `OSError` exception since the directory already exists There are also problems if the directory does initially exist but is removed by another process before the final line is executed. When it comes to Python, "it's easier to ask for forgiveness than permission." With that in mind, the fragment above could be better written: ``` try: os.makedirs('/some/path') except OSError: pass open('/some/path/test.txt', 'w') ``` This solves the two problems described above but creates a third: `os.makedirs` raises an `OSError` exception when one of the following conditions occurs: - the directory already exists - the directory could not be created This means that there is no way to determine which of the two conditions caused the exception to be raised. In other words, actual failures will be silently ignored, which is not what I want. How can I work around this problem?

Original source