/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/_readdir_pyx.pyx

Merge with bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
import os
21
21
import sys
22
22
 
 
23
#python2.4 support
 
24
cdef extern from "python-compat.h":
 
25
    pass
 
26
 
23
27
 
24
28
# the opaque C library DIR type.
25
29
cdef extern from 'errno.h':
29
33
    int errno
30
34
    char *strerror(int errno)
31
35
 
 
36
cdef extern from 'unistd.h':
 
37
    int chdir(char *path)
 
38
    char *getcwd(char *, int size)
 
39
 
 
40
cdef extern from 'stdlib.h':
 
41
    void *malloc(int)
 
42
    void free(void *)
 
43
 
 
44
 
32
45
cdef extern from 'sys/types.h':
33
46
    ctypedef long ssize_t
34
47
    ctypedef unsigned long size_t
 
48
    ctypedef long time_t
 
49
    ctypedef unsigned long ino_t
 
50
    ctypedef unsigned long long off_t
 
51
 
 
52
 
 
53
cdef extern from 'sys/stat.h':
 
54
    cdef struct stat:
 
55
        int st_mode
 
56
        off_t st_size
 
57
        int st_dev
 
58
        ino_t st_ino
 
59
        int st_mtime
 
60
        int st_ctime
 
61
    int lstat(char *path, stat *buf)
 
62
    int S_ISDIR(int mode)
 
63
    int S_ISCHR(int mode)
 
64
    int S_ISBLK(int mode)
 
65
    int S_ISREG(int mode)
 
66
    int S_ISFIFO(int mode)
 
67
    int S_ISLNK(int mode)
 
68
    int S_ISSOCK(int mode)
 
69
 
 
70
 
 
71
cdef extern from 'Python.h':
 
72
    char * PyString_AS_STRING(object)
 
73
    ctypedef int Py_ssize_t # Required for older pyrex versions
 
74
    ctypedef struct PyObject:
 
75
        pass
 
76
    Py_ssize_t PyString_Size(object s)
 
77
    object PyList_GetItem(object lst, Py_ssize_t index)
 
78
    void *PyList_GetItem_object_void "PyList_GET_ITEM" (object lst, int index)
 
79
    int PyList_Append(object lst, object item) except -1
 
80
    void *PyTuple_GetItem_void_void "PyTuple_GET_ITEM" (void* tpl, int index)
 
81
    int PyTuple_SetItem(void *, Py_ssize_t pos, object item) except -1
 
82
    int PyTuple_SetItem_obj "PyTuple_SetItem" (void *, Py_ssize_t pos, PyObject * item) except -1
 
83
    void Py_INCREF(object o)
 
84
    void Py_DECREF(object o)
 
85
    void PyString_Concat(PyObject **string, object newpart)
 
86
 
35
87
 
36
88
cdef extern from 'dirent.h':
37
 
    int DT_UNKNOWN
38
 
    int DT_REG
39
 
    int DT_DIR
40
 
    int DT_FIFO
41
 
    int DT_SOCK
42
 
    int DT_CHR
43
 
    int DT_BLK
44
89
    ctypedef struct dirent:
45
90
        char d_name[256]
46
 
        # this will fail to compile if d_type is not defined.
47
 
        # if this module fails to compile, use the .py version.
48
 
        unsigned char d_type
49
 
        int d_ino
 
91
        ino_t d_ino
50
92
    ctypedef struct DIR
51
93
    # should be DIR *, pyrex barfs.
52
94
    DIR * opendir(char * name)
61
103
_symlink = 'symlink'
62
104
_socket = 'socket'
63
105
_unknown = 'unknown'
64
 
 
65
 
dot = ord('.')
 
106
_missing = 'missing'
66
107
 
67
108
# add a typedef struct dirent dirent to workaround pyrex
68
109
cdef extern from 'readdir.h':
69
110
    pass
70
111
 
71
 
def read_dir(path):
 
112
 
 
113
cdef class _Stat:
 
114
    """Represent a 'stat' result."""
 
115
 
 
116
    cdef stat _st
 
117
 
 
118
    property st_dev:
 
119
        def __get__(self):
 
120
            return self._st.st_dev
 
121
 
 
122
    property st_ino:
 
123
        def __get__(self):
 
124
            return self._st.st_ino
 
125
 
 
126
    property st_mode:
 
127
        def __get__(self):
 
128
            return self._st.st_mode
 
129
 
 
130
    property st_ctime:
 
131
        def __get__(self):
 
132
            return self._st.st_ctime
 
133
 
 
134
    property st_mtime:
 
135
        def __get__(self):
 
136
            return self._st.st_mtime
 
137
 
 
138
    property st_size:
 
139
        def __get__(self):
 
140
            return self._st.st_size
 
141
 
 
142
    def __repr__(self):
 
143
        """Repr is the same as a Stat object.
 
144
 
 
145
        (mode, ino, dev, nlink, uid, gid, size, None(atime), mtime, ctime)
 
146
        """
 
147
        return repr((self.st_mode, 0, 0, 0, 0, 0, self.st_size, None,
 
148
                     self._mtime, self._ctime))
 
149
 
 
150
 
 
151
from bzrlib import osutils
 
152
 
 
153
 
 
154
cdef class UTF8DirReader:
 
155
    """A dir reader for utf8 file systems."""
 
156
 
 
157
    cdef readonly object _safe_utf8
 
158
    cdef _directory, _chardev, _block, _file, _fifo, _symlink
 
159
    cdef _socket, _unknown
 
160
 
 
161
    def __init__(self):
 
162
        self._safe_utf8 = osutils.safe_utf8
 
163
        self._directory = _directory
 
164
        self._chardev = _chardev
 
165
        self._block = _block
 
166
        self._file = _file
 
167
        self._fifo = _fifo
 
168
        self._symlink = _symlink
 
169
        self._socket = _socket
 
170
        self._unknown = _unknown
 
171
 
 
172
    def kind_from_mode(self, int mode):
 
173
        """Get the kind of a path from a mode status."""
 
174
        return self._kind_from_mode(mode)
 
175
 
 
176
    cdef _kind_from_mode(self, int mode):
 
177
        # Files and directories are the most common - check them first.
 
178
        if S_ISREG(mode):
 
179
            return self._file
 
180
        if S_ISDIR(mode):
 
181
            return self._directory
 
182
        if S_ISCHR(mode):
 
183
            return self._chardev
 
184
        if S_ISBLK(mode):
 
185
            return self._block
 
186
        if S_ISLNK(mode):
 
187
            return self._symlink
 
188
        if S_ISFIFO(mode):
 
189
            return self._fifo
 
190
        if S_ISSOCK(mode):
 
191
            return self._socket
 
192
        return self._unknown
 
193
 
 
194
    def top_prefix_to_starting_dir(self, top, prefix=""):
 
195
        """See DirReader.top_prefix_to_starting_dir."""
 
196
        return (self._safe_utf8(prefix), None, None, None,
 
197
            self._safe_utf8(top))
 
198
 
 
199
    def read_dir(self, prefix, top):
 
200
        """Read a single directory from a utf8 file system.
 
201
 
 
202
        All paths in and out are utf8.
 
203
 
 
204
        This sub-function is called when we know the filesystem is already in utf8
 
205
        encoding. So we don't need to transcode filenames.
 
206
 
 
207
        See DirReader.read_dir for details.
 
208
        """
 
209
        #cdef char *_prefix = prefix
 
210
        #cdef char *_top = top
 
211
        # Use C accelerated directory listing.
 
212
        cdef object newval
 
213
        cdef int index
 
214
        cdef int length
 
215
        cdef void * atuple
 
216
        cdef object name
 
217
        cdef PyObject * new_val_obj
 
218
 
 
219
        if PyString_Size(prefix):
 
220
            relprefix = prefix + '/'
 
221
        else:
 
222
            relprefix = ''
 
223
        top_slash = top + '/'
 
224
 
 
225
        # read_dir supplies in should-stat order.
 
226
        # for _, name in sorted(_listdir(top)):
 
227
        result = _read_dir(top)
 
228
        length = len(result)
 
229
        # result.sort()
 
230
        for index from 0 <= index < length:
 
231
            atuple = PyList_GetItem_object_void(result, index)
 
232
            name = <object>PyTuple_GetItem_void_void(atuple, 1)
 
233
            # We have a tuple with (inode, name, None, statvalue, None)
 
234
            # Now edit it:
 
235
            # inode -> path_from_top
 
236
            # direct concat - faster than operator +.
 
237
            new_val_obj = <PyObject *>relprefix
 
238
            Py_INCREF(relprefix)
 
239
            PyString_Concat(&new_val_obj, name)
 
240
            if NULL == new_val_obj:
 
241
                # PyString_Concat will have setup an exception, but how to get
 
242
                # at it?
 
243
                raise Exception("failed to strcat")
 
244
            PyTuple_SetItem_obj(atuple, 0, new_val_obj)
 
245
            # 1st None -> kind
 
246
            newval = self._kind_from_mode(
 
247
                (<_Stat>PyTuple_GetItem_void_void(atuple, 3)).st_mode)
 
248
            Py_INCREF(newval)
 
249
            PyTuple_SetItem(atuple, 2, newval)
 
250
            # 2nd None -> abspath # for all - the caller may need to stat files
 
251
            # etc.
 
252
            # direct concat - faster than operator +.
 
253
            new_val_obj = <PyObject *>top_slash
 
254
            Py_INCREF(top_slash)
 
255
            PyString_Concat(&new_val_obj, name)
 
256
            if NULL == new_val_obj:
 
257
                # PyString_Concat will have setup an exception, but how to get
 
258
                # at it?
 
259
                raise Exception("failed to strcat")
 
260
            PyTuple_SetItem_obj(atuple, 4, new_val_obj)
 
261
        return result
 
262
 
 
263
 
 
264
cdef _read_dir(path):
72
265
    """Like os.listdir, this reads the contents of a directory.
73
266
 
74
267
    :param path: the directory to list.
75
 
    :return: a list of (sort_key, basename) tuples.
 
268
    :return: a list of single-owner (the list) tuples ready for editing into
 
269
        the result tuples walkdirs needs to yield. They contain (inode, name,
 
270
        None, statvalue, None).
76
271
    """
77
272
    cdef DIR *the_dir
78
273
    # currently this needs a fixup - the C code says 'dirent' but should say
80
275
    cdef dirent * entry
81
276
    cdef dirent sentinel
82
277
    cdef char *name
83
 
    the_dir = opendir(path)
 
278
    cdef int stat_result
 
279
    cdef _Stat statvalue
 
280
    cdef char *cwd
 
281
 
 
282
    cwd = getcwd(NULL, 0)
 
283
    if -1 == chdir(path):
 
284
        raise OSError(errno, strerror(errno))
 
285
    the_dir = opendir(".")
84
286
    if NULL == the_dir:
85
287
        raise OSError(errno, strerror(errno))
86
288
    result = []
103
305
                    # done
104
306
                    continue
105
307
            name = entry.d_name
106
 
            if not (name[0] == dot and (
 
308
            if not (name[0] == c"." and (
107
309
                (name[1] == 0) or 
108
 
                (name[1] == dot and name[2] == 0))
 
310
                (name[1] == c"." and name[2] == 0))
109
311
                ):
110
 
                result.append((entry.d_ino, entry.d_name))
 
312
                statvalue = _Stat()
 
313
                stat_result = lstat(entry.d_name, &statvalue._st)
 
314
                if stat_result != 0:
 
315
                    if errno != ENOENT:
 
316
                        raise OSError(errno, strerror(errno))
 
317
                    else:
 
318
                        kind = _missing
 
319
                        statvalue = None
 
320
                # We append a 5-tuple that can be modified in-place by the C
 
321
                # api:
 
322
                # inode to sort on (to replace with top_path)
 
323
                # name (to keep)
 
324
                # kind (None, to set)
 
325
                # statvalue (to keep)
 
326
                # abspath (None, to set)
 
327
                PyList_Append(result, (entry.d_ino, entry.d_name, None,
 
328
                    statvalue, None))
111
329
    finally:
 
330
        if -1 == chdir(cwd):
 
331
            free(cwd)
 
332
            raise OSError(errno, strerror(errno))
 
333
        free(cwd)
112
334
        if -1 == closedir(the_dir):
113
335
            raise OSError(errno, strerror(errno))
114
336
    return result