Determining Whether a Directory is Writeable

82,656

Solution 1

Although what Christophe suggested is a more Pythonic solution, the os module does have the os.access function to check access:

os.access('/path/to/folder', os.W_OK) # W_OK is for writing, R_OK for reading, etc.

Solution 2

It may seem strange to suggest this, but a common Python idiom is

It's easier to ask for forgiveness than for permission

Following that idiom, one might say:

Try writing to the directory in question, and catch the error if you don't have the permission to do so.

Solution 3

My solution using the tempfile module:

import tempfile
import errno

def isWritable(path):
    try:
        testfile = tempfile.TemporaryFile(dir = path)
        testfile.close()
    except OSError as e:
        if e.errno == errno.EACCES:  # 13
            return False
        e.filename = path
        raise
    return True

Update: After testing the code again on Windows I see that there is indeed an issue when using tempfile there, see issue22107: tempfile module misinterprets access denied error on Windows. In the case of a non-writable directory, the code hangs for several seconds and finally throws an IOError: [Errno 17] No usable temporary file name found. Maybe this is what user2171842 was observing? Unfortunately the issue is not resolved for now so to handle this, the error needs to be caught as well:

    except (OSError, IOError) as e:
        if e.errno == errno.EACCES or e.errno == errno.EEXIST:  # 13, 17

The delay is of course still present in these cases then.

Solution 4

Stumbled across this thread searching for examples for someone. First result on Google, congrats!

People talk about the Pythonic way of doing it in this thread, but no simple code examples? Here you go, for anyone else who stumbles in:

import sys

filepath = 'C:\\path\\to\\your\\file.txt'

try:
    filehandle = open( filepath, 'w' )
except IOError:
    sys.exit( 'Unable to write to file ' + filepath )

filehandle.write("I am writing this text to the file\n")

This attempts to open a filehandle for writing, and exits with an error if the file specified cannot be written to: This is far easier to read, and is a much better way of doing it rather than doing prechecks on the file path or the directory, as it avoids race conditions; cases where the file becomes unwriteable between the time you run the precheck, and when you actually attempt to write to the file.

Solution 5

If you only care about the file perms, os.access(path, os.W_OK) should do what you ask for. If you instead want to know whether you can write to the directory, open() a test file for writing (it shouldn't exist beforehand), catch and examine any IOError, and clean up the test file afterwards.

More generally, to avoid TOCTOU attacks (only a problem if your script runs with elevated privileges -- suid or cgi or so), you shouldn't really trust these ahead-of-time tests, but drop privs, do the open(), and expect the IOError.

Share:
82,656
illuminatedtiger
Author by

illuminatedtiger

Updated on June 04, 2021

Comments

  • illuminatedtiger
    illuminatedtiger about 3 years

    What would be the best way in Python to determine whether a directory is writeable for the user executing the script? Since this will likely involve using the os module I should mention I'm running it under a *nix environment.

  • John Knoeller
    John Knoeller over 14 years
    +1 Python or not, this is really the most reliable way to test for access.
  • Jochen Ritzel
    Jochen Ritzel over 14 years
    This also takes care of other errors that can happen when writing to the disk - no diskspace left for example. That's the power of trying .. you dont need to remember everything that can go wrong ;-)
  • illuminatedtiger
    illuminatedtiger over 14 years
    Thanks guys. Decided to go with os.access as speed is an important factor in what I'm doing here although I can certainly understand the merits in "it's easier to ask for forgiveness than for permission." ;)
  • ChristopheD
    ChristopheD over 14 years
    @illuminatedtiger: that's perfectfly fine, just be aware of the notes in the documentation (docs.python.org/library/os.html#os.access)
  • mjv
    mjv over 14 years
    Depending on the situation, the "easier to ask for forgiveness" is not the best way, even in Python. It is sometimes advisable to "ask permission" as with the os.access() method mentioned, for example when the probability of having to catch an error is high.
  • fthinker
    fthinker over 12 years
    Testing a directory for just the write bit isn't enough if you want to write files to the directory. You will need to test for the execute bit as well if you want to write into the directory. os.access('/path/to/folder', os.W_OK | os.X_OK) With os.W_OK by itself you can only delete the directory (and only if that directory is empty)
  • Björn Lindqvist
    Björn Lindqvist almost 11 years
    This solution is Unix only.
  • grasshopper
    grasshopper over 9 years
    I think the one using tempfile is the cleaner because it for sure doesnt leave residuals.
  • Tomasz Gandor
    Tomasz Gandor about 8 years
    It's a great IDIO...m - especially when coupled with another idiom except: pass - this way you can always be optimistic and think highly of yourself. /sarcasm off. Now why would I want to, e.g. try to write something into every directory in my filesystem, to produce a list of writable locations?
  • ChristopheD
    ChristopheD about 8 years
    @Tomasz Gandor: I don't think except: pass is a generally accepted idiom :-) (in any language). That being said, compiling a list of writable locations on your filesystem is doomed to be out of date from the moment you create it. What use case does this have? Even checking if you can write to a directory just one line before you try to write (in code) is not a guarantee of any sorts (since it is not an atomic operation). Just "trying" is still what you'll need to do anyway.
  • Tomasz Gandor
    Tomasz Gandor about 8 years
    I agree. The right approach depends on a situation - if you want to write to the directory anyway - just go for it, and catch errors (EAFP). But, if you need to write to directories A, B, and C - and you only find out that C fails down the road - you may have wasted (computation) time and... money (think - cloud computing). Or you need to be able to clean up after such failed "transaction". Well, the last one you may need anyway; you may still loose permissions in TOCTOU.
  • Admin
    Admin about 8 years
    this method is not working using tempfile. it only works when there is no OSError meaning it has permission to write/delete. otherwise it will not return False because no error is returned, and the script won't continue to execute or exit. nothing is returned. it's just stuck at that line. however, creating a non-temporary file such as khattam's answer does work both when permission is allowed or denied. help?
  • Alexios
    Alexios about 8 years
    Another gotcha of os.access() is it checks using the real UID and GID, not the effective ones. This could cause weirdness in SUID/SGID environments. (‘but the script runs setuid root, why can't it write to the file?’)
  • Ray Salemi
    Ray Salemi over 7 years
    I will look it up, but it would be useful to see what os.access() returns here in the solution. I presume it's a boolean.
  • Mike S
    Mike S about 7 years
    This applies to a file, not directory which is what the OP asked. You can have a file in a directory and have the directory not be writable but the file itself is, should the file already exist. This may be important in systems administration where you're eg creating log files that you want to already exist but don't want people using a log directory for temp space.
  • Mike S
    Mike S about 7 years
    ...and actually I voted it down, which I now think was a mistake. There are issues, as Rohaq mentioned, with race conditions. There are other issues on various platforms where you may test the directory, and it looks writable, but it actually isn't. Performing cross-platform directory writable checks is harder than it looks. So as long as you're aware of the issues, this may be a fine technique. I was looking at it from a too UNIX-y perspective, which is my mistake. Someone edit this answer so I can remove my -1.
  • Rohaq
    Rohaq about 7 years
    I've edited it, in case you want to remove the -1 :) And yes, cross-platform directory checks can get more complicated, but generally you're looking to create/write to a file in that directory - in which case the example I've given should still apply. If some directory permission related issue comes up, it should still throw an IOError when attempting to open the filehandle.
  • Mike S
    Mike S about 7 years
    I removed my downvote. Sorry about that, and thanks for your contribution.
  • Rohaq
    Rohaq about 7 years
    No worries, people questioning answers is always welcomed!
  • Jorrick Sleijster
    Jorrick Sleijster almost 7 years
    This is basically a copy of Max Shawabkeh's answer with a little wrapper around it. Makes it a quick copy paste but a better idea would be to have added it to the original post of Max.
  • Bachsau
    Bachsau about 6 years
    Maybe a program just wants to know without having the need to actually write. It might just want to change the look and/or behaviour of a GUI according to the property. In that case I would not consider it pythonic to write and delete a file just as a test.
  • Bachsau
    Bachsau about 6 years
    Maybe a program just wants to know without having the need to actually write. It might just want to change the look and/or behaviour of a GUI according to the property. In that case I would not consider it pythonic to write and delete a file just as a test.
  • iamanigeeit
    iamanigeeit over 5 years
    Just tested on a Windows network share. os.access(dirpath, os.W_OK | os.X_OK) returns True even if i have no write access.
  • schlamar
    schlamar over 5 years
    As already said, this give wrong results on Windows... Please add a comment in your answer, then I will remove the downvote.
  • sivann
    sivann over 4 years
    That was not the question though.
  • BubuIIC
    BubuIIC almost 4 years
    This can also throw OSError: [Errno 30] Read-only file system
  • Brōtsyorfuzthrāx
    Brōtsyorfuzthrāx almost 3 years
    An issue with this is you don't always get a 'Python' error that you can easily catch, per se. I mean, if you're doing such as subprocess.run(...) then Python won't throw permission errors for those subprocess calls.
  • milahu
    milahu almost 2 years
    except PermissionError