1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
# Copyright (C) 2006, 2008 Canonical Ltd
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""Wrapper for readdir which returns files ordered by inode."""
import os
import sys
# the opaque C library DIR type.
cdef extern from 'errno.h':
int ENOENT
int ENOTDIR
int EAGAIN
int errno
char *strerror(int errno)
cdef extern from 'sys/types.h':
ctypedef long ssize_t
ctypedef unsigned long size_t
cdef extern from 'dirent.h':
int DT_UNKNOWN
int DT_REG
int DT_DIR
int DT_FIFO
int DT_SOCK
int DT_CHR
int DT_BLK
ctypedef struct dirent:
char d_name[256]
# this will fail to compile if d_type is not defined.
# if this module fails to compile, use the .py version.
unsigned char d_type
int d_ino
ctypedef struct DIR
# should be DIR *, pyrex barfs.
DIR * opendir(char * name)
int closedir(DIR * dir)
dirent *readdir(DIR *dir)
_directory = 'directory'
_chardev = 'chardev'
_block = 'block'
_file = 'file'
_fifo = 'fifo'
_symlink = 'symlink'
_socket = 'socket'
_unknown = 'unknown'
dot = ord('.')
# add a typedef struct dirent dirent to workaround pyrex
cdef extern from 'readdir.h':
pass
def read_dir(path):
"""Like os.listdir, this reads a directories contents.
:param path: the directory to list.
:return: a list of (sort_key, basename) tuples.
"""
cdef DIR *the_dir
# currently this needs a fixup - the C code says 'dirent' but should say
# 'struct dirent'
cdef dirent * entry
cdef dirent sentinel
cdef char *name
the_dir = opendir(path)
if NULL == the_dir:
raise OSError(errno, strerror(errno))
result = []
try:
entry = &sentinel
while entry != NULL:
entry = readdir(the_dir)
if entry == NULL:
if errno == EAGAIN:
# try again
continue
elif errno != ENOTDIR and errno != ENOENT and errno != 0:
# We see ENOTDIR at the end of a normal directory.
# As ENOTDIR for read_dir(file) is triggered on opendir,
# we consider ENOTDIR to be 'no error'.
# ENOENT is listed as 'invalid position in the dir stream' for
# readdir. We swallow this for now and just keep reading.
raise OSError(errno, strerror(errno))
else:
# done
continue
name = entry.d_name
if not (name[0] == dot and (
(name[1] == 0) or
(name[1] == dot and name [2] == 0))
):
result.append((entry.d_ino, entry.d_name))
finally:
if -1 == closedir(the_dir):
raise OSError(errno, strerror(errno))
return result
# vim: tw=79 ai expandtab sw=4 sts=4
|