Commits

Armin Rigo committed a82b0eb

A ctypes version of readdir.py.

Comments (0)

Files changed (1)

demo/readdir_ctypes.py

+# A Linux-only demo
+#
+# For comparison purposes, this is a ctypes version of readdir.py.
+import sys
+import ctypes
+
+if not sys.platform.startswith('linux'):
+    raise Exception("Linux-only demo")
+
+
+DIR_p = ctypes.c_void_p
+ino_t = ctypes.c_long
+off_t = ctypes.c_long
+
+class DIRENT(ctypes.Structure):
+    _fields_ = [
+        ('d_ino', ino_t),                 # inode number
+        ('d_off', off_t),                 # offset to the next dirent
+        ('d_reclen', ctypes.c_ushort),    # length of this record
+        ('d_type', ctypes.c_ubyte),       # type of file; not supported
+                                          #   by all file system types
+        ('d_name', ctypes.c_char * 256),  # filename
+        ]
+DIRENT_p = ctypes.POINTER(DIRENT)
+DIRENT_pp = ctypes.POINTER(DIRENT_p)
+
+C = ctypes.CDLL(None)
+
+readdir_r = C.readdir_r
+readdir_r.argtypes = [DIR_p, DIRENT_p, DIRENT_pp]
+readdir_r.restype = ctypes.c_int
+
+openat = C.openat
+openat.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int]
+openat.restype = ctypes.c_int
+
+fdopendir = C.fdopendir
+fdopendir.argtypes = [ctypes.c_int]
+fdopendir.restype = DIR_p
+
+closedir = C.closedir
+closedir.argtypes = [DIR_p]
+closedir.restype = ctypes.c_int
+
+
+def walk(basefd, path):
+    print '{', path
+    dirfd = openat(basefd, path, 0)
+    if dirfd < 0:
+        # error in openat()
+        return
+    dir = fdopendir(dirfd)
+    print dir
+    dirent = DIRENT()
+    result = DIRENT_p()
+    while True:
+        if readdir_r(dir, dirent, result):
+            # error in readdir_r()
+            break
+        if not result:
+            break
+        name = dirent.d_name
+        print '%3d %s' % (dirent.d_type, name)
+        if dirent.d_type == 4 and name != '.' and name != '..':
+            walk(dirfd, name)
+    closedir(dir)
+    print '}'
+
+
+walk(-1, "/tmp")