Determining Whether a Directory is Writeable

PythonFilePermissionsDirectoryOperating System

Python Problem Overview


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.

Python Solutions


Solution 1 - Python

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

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

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 https://bugs.python.org/issue22107">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 - Python

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

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.

Solution 6 - Python

Check the mode bits:

import os, stat

def isWritable(dirname):
  uid = os.geteuid()
  gid = os.getegid()
  s = os.stat(dirname)
  mode = s[stat.ST_MODE]
  return (
     ((s[stat.ST_UID] == uid) and (mode & stat.S_IWUSR)) or
     ((s[stat.ST_GID] == gid) and (mode & stat.S_IWGRP)) or
     (mode & stat.S_IWOTH)
     )

Solution 7 - Python

Here is something I created based on ChristopheD's answer:

import os

def isWritable(directory):
	try:
		tmp_prefix = "write_tester";
		count = 0
		filename = os.path.join(directory, tmp_prefix)
		while(os.path.exists(filename)):
			filename = "{}.{}".format(os.path.join(directory, tmp_prefix),count)
			count = count + 1
		f = open(filename,"w")
		f.close()
		os.remove(filename)
		return True
	except Exception as e:
		#print "{}".format(e)
		return False
		
directory = "c:\\"
if (isWritable(directory)):
	print "directory is writable"
else:
	print "directory is not writable"

Solution 8 - Python

 if os.access(path_to_folder, os.W_OK) is not True:
            print("Folder not writable")
 else :
            print("Folder writable")

more info about access can be find it here

Solution 9 - Python

If you need to check the permission of another user (yes, I realize this contradicts the question, but may come in handy for someone), you can do it through the pwd module, and the directory's mode bits.

Disclaimer - does not work on Windows, as it doesn't use the POSIX permissions model (and the pwd module is not available there), e.g. - solution only for *nix systems.

Note that a directory has to have all the 3 bits set - Read, Write and eXecute.
Ok, R is not an absolute must, but w/o it you cannot list the entries in the directory (so you have to know their names). Execute on the other hand is absolutely needed - w/o it the user cannot read the file's inodes; so even having W, without X files cannot be created or modified. More detailed explanation at this link.

Finally, the modes are available in the stat module, their descriptions are in inode(7) man.

Sample code how to check:

import pwd
import stat
import os

def check_user_dir(user, directory):
    dir_stat = os.stat(directory)

    user_id, group_id = pwd.getpwnam(user).pw_uid, pwd.getpwnam(user).pw_gid
    directory_mode = dir_stat[stat.ST_MODE]

    # use directory_mode as mask 
    if user_id == dir_stat[stat.ST_UID] and stat.S_IRWXU & directory_mode == stat.S_IRWXU:     # owner and has RWX
        return True
    elif group_id == dir_stat[stat.ST_GID] and stat.S_IRWXG & directory_mode == stat.S_IRWXG:  # in group & it has RWX
        return True
    elif stat.S_IRWXO & directory_mode == stat.S_IRWXO:                                        # everyone has RWX
        return True

    # no permissions
    return False

Solution 10 - Python

I ran into this same need while adding an argument via argparse. The built in type=FileType('w') wouldn't work for me as I was looking for a directory. I ended up writing my own method to solve my problem. Here is the result with argparse snippet.

#! /usr/bin/env python
import os
import argparse

def writable_dir(dir):
    if os.access(dir, os.W_OK) and os.path.isdir(dir):
        return os.path.abspath(dir)
    else:
        raise argparse.ArgumentTypeError(dir + " is not writable or does not exist.")

parser = argparse.ArgumentParser()
parser.add_argument("-d","--dir", type=writable_dir(), default='/tmp/',
    help="Directory to use. Default: /tmp")
opts = parser.parse_args()

That results in the following:

$ python dir-test.py -h
usage: dir-test.py [-h] [-d DIR]

optional arguments:
  -h, --help         show this help message and exit
  -d DIR, --dir DIR  Directory to use. Default: /tmp

$ python dir-test.py -d /not/real
usage: dir-test.py [-h] [-d DIR]
dir-test.py: error: argument -d/--dir: /not/real is not writable or does not exist.

$ python dir-test.py -d ~

I went back and added print opts.dir to the end, and everything appears to be functioning as desired.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionilluminatedtigerView Question on Stackoverflow
Solution 1 - PythonMax ShawabkehView Answer on Stackoverflow
Solution 2 - PythonChristopheDView Answer on Stackoverflow
Solution 3 - PythonzakView Answer on Stackoverflow
Solution 4 - PythonRohaqView Answer on Stackoverflow
Solution 5 - PythonsverkerwView Answer on Stackoverflow
Solution 6 - PythonJoe KobergView Answer on Stackoverflow
Solution 7 - PythonkhattamView Answer on Stackoverflow
Solution 8 - PythonSoftmixtView Answer on Stackoverflow
Solution 9 - PythonTodor MinakovView Answer on Stackoverflow
Solution 10 - Python796m9XfYTkmpView Answer on Stackoverflow