“Education is the most powerful weapon which you can use to change the world.” ― Nelson Mandela
Contents
1. Introduction
It can be a bit cumbersome at times to check for read or write permission on a file. The check might succeed but the actual operation could fail. Also, quite a few edge cases need to be covered to get a reasonable answer from such a check. In this article, we cover some issues with regards to checking read and write permission on a file.
See Also: How to Check Whether a File Exists in Python?
2. Check if File can be Read
A file can be read if it exists and has read permission for the user. Attempting to open the file is the simplest way you can find out if a file can be read. You get an IOError exception if the file cannot be read and you can check errno in the exception for details.
- If errno is errno.ENOENT, the file does not exist.
- If errno is errno.EACCES, the user does not have permission to read the file.
try: with open(argv[1]) as f: s = f.read() print 'read', len(s), 'bytes.' except IOError as x: if x.errno == errno.ENOENT: print argv[1], '- does not exist' elif x.errno == errno.EACCES: print argv[1], '- cannot be read' else: print argv[1], '- some other error'
Pros
- Easy.
Cons
- Raising and catching exceptions are expensive.
2.1. Using access()
Sometimes, you don’t care about the reason that open() fails. You just want to know if it succeeds. In such cases, os.access() is an option.
Check non-existent file.
print os.access('joe.txt', os.R_OK) # prints False
Create the file.
touch joe.txt
Check again.
print os.access('joe.txt', os.R_OK) # prints False
Remove read permissions.
chmod -r joe.txt
And check again.
print os.access('joe.txt', os.R_OK) # prints False
Pros
- Cheap. No hassle of catching exceptions and the associated cost
Cons
- By the time you check access() and attempt to actually open the file, the situation may have changed. A readable file might be gone or have its permission changed.
3. Checking if file can be written
Check for file-write is a little bit different from checking readability. If the file does not exist, we need to check the parent directory for write permission.
3.1. Attempt to Write File
Sometimes, the easiest way is to just attempt to write the file. And catch the exception if any is raised.
try: with open(argv[1], 'w') as f: # file opened for writing. write to it here print 'ok' pass except IOError as x: print 'error ', x.errno, ',', x.strerror if x.errno == errno.EACCES: print argv[1], 'no perms' elif x.errno == errno.EISDIR: print argv[1], 'is directory'
As above, the disadvantage of this method is the expense of raising and checking an exception.
3.2. Using access() for checking
When using access() to check permissions, you need not actually open the file. You can apply various conditions to verify writability. In the following procedure, we describe how to go about checking whether a particular file is writable.
- Check if the path exists. Different conditions need to be checked depending on whether it exists or not.
if os.path.exists(fnm): ...
- If path does exist, check if it is a file.
if os.path.exists(fnm): # path exists if os.path.isfile(fnm): # is it a file or a dir? ...
- If path is a file, check whether it can be written to. This is the final check in this branch and access() can tell us whether the file can be written.
if os.path.exists(fnm): # path exists if os.path.isfile(fnm): # is it a file or a dir? # also works when file is a link and the target is writable return os.access(fnm, os.W_OK) ...
- If the path is not a file, the file writability check fails. This is because you cannot create a file where a directory of that name exists.
if os.path.exists(fnm): # path exists if os.path.isfile(fnm): # is it a file or a dir? # also works when file is a link and the target is writable return os.access(fnm, os.W_OK) else: return False # path is a dir, so cannot write as a file ...
- Now, if the target does not exist, we check the parent folder for write permission. That should finally tell us whether the path is writable.
Here is the complete program.
import os.path def check_file_writable(fnm): if os.path.exists(fnm): # path exists if os.path.isfile(fnm): # is it a file or a dir? # also works when file is a link and the target is writable return os.access(fnm, os.W_OK) else: return False # path is a dir, so cannot write as a file # target does not exist, check perms on parent dir pdir = os.path.dirname(fnm) if not pdir: pdir = '.' # target is creatable if parent dir is writable return os.access(pdir, os.W_OK) if __name__ == '__main__': from sys import argv print argv[1], '=>', check_file_writable(argv[1])
3.3. Checking Results
Let us now check to see how it works.
- First, remove the checked file and check.
rm joe python check.py joe # prints joe => True
- Create a file.
touch joe ls -l joe # prints -rw-rw-r-- 1 xxxxxxx xxxxxxx 0 Feb 10 12:01 joe
Now perform the check.
python check.py joe # prints joe => True
- Remove write permission and check.
chmod -w joe python check.py joe # prints joe => False
- Remove file and remove write permission from parent directory.
rm joe; chmod -w . python check.py joe # prints joe => False
- Turn back permissions, create directory and check. Note that even though the target exists and is writable, the function returns False since it cannot be written to as a file.
chmod +w . mkdir joe python check.py joe # prints joe => False
- Remove entry and make a link to a non-existent file.
rmdir joe ln -s not-exists joe python check.py joe # prints joe => True
- Turn off permissions on the link target.
touch not-exists chmod -w not-exists python check.py joe # prints joe => False
Conclusion
In this article, we have presented a review of methods to check for readability and writability of a file. Opening the file is the surest way to check, but has the cost of raising and catching an exception. Using access() will work, but might be subject to race conditions. Use the knowledge presented here to adjust to your needs.