1from _recopendirtype import ffi, lib
2
3
4def _posix_error():
5    raise OSError(ffi.errno, os.strerror(ffi.errno))
6
7_dtype_to_smode = {
8    lib.DT_BLK:  0o060000,
9    lib.DT_CHR:  0o020000,
10    lib.DT_DIR:  0o040000,
11    lib.DT_FIFO: 0o010000,
12    lib.DT_LNK:  0o120000,
13    lib.DT_REG:  0o100000,
14    lib.DT_SOCK: 0o140000,
15}
16
17def opendir(dir):
18    if len(dir) == 0:
19        dir = b'.'
20    dirname = dir
21    if not dirname.endswith(b'/'):
22        dirname += b'/'
23    dirp = lib.opendir(dir)
24    if dirp == ffi.NULL:
25        raise _posix_error()
26    dirent = ffi.new("struct dirent *")
27    result = ffi.new("struct dirent **")
28    try:
29        while True:
30            ffi.errno = 0
31            err = lib.readdir_r(dirp, dirent, result)
32            if err:       # really got an error
33                raise OSError(err, os.strerror(err))
34            if result[0] == ffi.NULL:
35                return    #
36            name = ffi.string(dirent.d_name)
37            if name == b'.' or name == b'..':
38                continue
39            name = dirname + name
40            try:
41                smode = _dtype_to_smode[dirent.d_type]
42            except KeyError:
43                smode = os.lstat(name).st_mode
44            yield name, smode
45    finally:
46        lib.closedir(dirp)
47
48if __name__ == '__main__':
49    for name, smode in opendir(b'/tmp'):
50        print(hex(smode), name)
51