fsnix: file system API for Python 2.x
This library provides modules for Python 2.x that expose some of the useful File System related API calls, including some of those added in POSIX.1-2008. This includes the functions openat, mkdirat, unlinkat, and other similar calls suffixed with "at". These calls exist to help defend against race conditions and support thread-level working directories. Typically these functions take one or more directory file descriptor and a relative path as arguments. This library also comes with custom directory listing functions that mimic os.listdir by default but can provide additional information (d_type) when passed a flag. Similarly, file descriptor and iterator based versions are also available.
Additionally, this library provides a util module that has a higher level interface for working with open directories and other functions that use the lower level library calls.
Open a directory, and create a file in that directory, then remove it.
>>> import tempfile, os >>> from fsnix import fs >>> root = tempfile.mkdtemp() >>> dirfd = os.open(root, os.O_RDONLY) >>> fd = fs.openat(dirfd, "foobar.txt", os.O_CREAT | os.O_RDWR) >>> os.write(fd, "Hello World\n") 12 >>> os.close(fd) >>> os.listdir(root) ['foobar.txt'] >>> fs.unlinkat(dirfd, 'foobar.txt') >>> os.close(dirfd) >>> os.listdir(root) 
This example shows how to create a subdirectory, write a file into that and then rename the directory, all using the low-level APIs.
>>> import tempfile, os >>> from fsnix import fs >>> root = tempfile.mkdtemp() >>> dirfd = os.open(root, os.O_RDONLY) >>> fs.mkdirat(dirfd, 'ham') >>> dirfd2 = fs.openat(dirfd, 'ham', os.O_RDONLY) >>> os.close(fs.openat(dirfd2, "foobar.txt", os.O_CREAT | os.O_RDWR)) >>> os.close(dirfd2) >>> fs.renameat(dirfd, 'ham', dirfd, 'bacon') >>> os.close(dirfd) >>> os.listdir(os.path.join(root, 'bacon')) ['foobar.txt']
The util module aims at providing a higher level interface to make some common actions simpler. This example tries to wipe out any empty directories in the example directory.
>>> import tempfile, os, errno >>> from fsnix import fs >>> from fsnix import util >>> root = tempfile.mkdtemp() >>> for i in range(0, 19): ... if i & 1: ... open(os.path.join(root, str(i)), 'w').close() ... else: ... os.mkdir(os.path.join(root, str(i))) >>> open(os.path.join(root, '0', 'foo'), 'w').close() >>> with util.opendir(root) as dh: ... for name in dh.listdir(): ... try: ... fs.unlinkat(dh.fileno(), name, fs.AT_REMOVEDIR) ... except OSError, e: ... if e.errno != errno.ENOTDIR and e.errno != errno.ENOTEMPTY: ... raise >>> sorted(os.listdir(root), key=int) ['0', '1', '3', '5', '7', '9', '11', '13', '15', '17']
The API for the POSIX.1-2008 *at functions should be compatible with the functions that will be available in Python 3.3 and above, if said function is present in the posix module. If you use both and find differences, please let me know.
The listdir-like functions should behave similarly to os.listdir when not passed any flags. The extended listdir calls are designed only to vary where appropriate.
I am currently testing against Linux and FreeBSD. Specifically, Fedora 14 and up and FreeBSD 9.0. If you think the module should work on your platform and it does not, please report a bug. Please be aware that I do not have access to proprietary/esoteric platforms. This module will not work on Windows systems.