AFAIK this code can be used to lock a directory:
class LockDirectory(object):
def __init__(self, directory):
assert os.path.exists(directory)
If all you need is a read lock, then there is only a minor error in the code you have. It is perfectly feasible to get a read lock on a directory.
You'll need to alter your __exit__
function to use os.close() to close the file descriptor; a file descriptor is just an integer, and integers have no .close()
method:
def __exit__(self, exc_type, exc_val, exc_tb):
os.close(self.dir_fd)
The usual confusion for people that think you can't, are those that have tried with the open()
function. Python won't let you open a directory node with that function because there is no point in creating a Python file object for a directory. Or perhaps there is an assumption that you wanted the OS to enforce access to the directory via the lock (as opposed to an advisory lock that a cooperative set of processes agree to obtain first before attempting access).
So no, there is nothing wrong with the code if all you want is an advisory lock, and are fine with this only working on Linux.
I'd drop the directory
distinction from the code. The lock will work on any path that you have read access to. It is not exclusive to directories.
The downside of locking the directory is that this doesn't give you a place to store lock metadata. While lsof
can give you the PID of the current owner of the lock, you may want to communicate some other information with the lock to help troubleshoot or automate lock breaking. A .lock
file or symlink would let you record additional information. For example, Mercurial will create a symlink with the hostname, the PID namespace identifier (Linux only) and the PID in the target name; you can create such a symlink atomically, while writing that data to a file would require creating a file under a temp name followed by a rename.