~bzr-pqm/bzr/bzr.dev

4763.2.4 by John Arbash Meinel
merge bzr.2.1 in preparation for NEWS entry.
1
# Copyright (C) 2006, 2008, 2009, 2010 Canonical Ltd
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
16
1739.2.7 by Robert Collins
Update readdir pyrex source files and usage in line with current practice.
17
"""Wrapper for readdir which returns files ordered by inode."""
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
18
19
20
import os
21
import sys
22
3731.1.1 by Robert Collins
* The C extensions now build on python 2.4 (Robert Collins, #271939)
23
#python2.4 support
24
cdef extern from "python-compat.h":
25
    pass
26
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
27
28
cdef extern from 'errno.h':
29
    int ENOENT
1739.2.6 by Robert Collins
Merge bzr.dev
30
    int ENOTDIR
31
    int EAGAIN
3766.1.5 by Martin Pool
add missing pyrex import
32
    int EINTR
3766.1.6 by Martin Pool
We need a 'global' declaration to assign to errno; and fix comments
33
    char *strerror(int errno)
34
    # not necessarily a real variable, but this should be close enough
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
35
    int errno
36
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
37
cdef extern from 'unistd.h':
38
    int chdir(char *path)
3841.1.4 by Martin Pool
Use open/fchdir rather than getcwd/chdir to save and restore directory location
39
    int close(int fd)
40
    int fchdir(int fd)
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
41
    char *getcwd(char *, int size)
42
43
cdef extern from 'stdlib.h':
44
    void *malloc(int)
45
    void free(void *)
46
3696.3.10 by Robert Collins
Review feedback.
47
48
cdef extern from 'sys/types.h':
49
    ctypedef long ssize_t
50
    ctypedef unsigned long size_t
51
    ctypedef long time_t
52
    ctypedef unsigned long ino_t
53
    ctypedef unsigned long long off_t
3841.1.4 by Martin Pool
Use open/fchdir rather than getcwd/chdir to save and restore directory location
54
    ctypedef int mode_t
3696.3.10 by Robert Collins
Review feedback.
55
56
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
57
cdef extern from 'sys/stat.h':
58
    cdef struct stat:
59
        int st_mode
3696.3.10 by Robert Collins
Review feedback.
60
        off_t st_size
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
61
        int st_dev
3696.3.10 by Robert Collins
Review feedback.
62
        ino_t st_ino
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
63
        int st_mtime
64
        int st_ctime
65
    int lstat(char *path, stat *buf)
66
    int S_ISDIR(int mode)
67
    int S_ISCHR(int mode)
68
    int S_ISBLK(int mode)
69
    int S_ISREG(int mode)
70
    int S_ISFIFO(int mode)
71
    int S_ISLNK(int mode)
72
    int S_ISSOCK(int mode)
73
74
3841.1.4 by Martin Pool
Use open/fchdir rather than getcwd/chdir to save and restore directory location
75
cdef extern from 'fcntl.h':
76
    int O_RDONLY
77
    int open(char *pathname, int flags, mode_t mode)
78
79
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
80
cdef extern from 'Python.h':
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
81
    int PyErr_CheckSignals() except -1
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
82
    char * PyString_AS_STRING(object)
83
    ctypedef int Py_ssize_t # Required for older pyrex versions
3696.3.7 by Robert Collins
Use PyString_Concat directly for another small boost.
84
    ctypedef struct PyObject:
85
        pass
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
86
    Py_ssize_t PyString_Size(object s)
87
    object PyList_GetItem(object lst, Py_ssize_t index)
88
    void *PyList_GetItem_object_void "PyList_GET_ITEM" (object lst, int index)
89
    int PyList_Append(object lst, object item) except -1
90
    void *PyTuple_GetItem_void_void "PyTuple_GET_ITEM" (void* tpl, int index)
91
    int PyTuple_SetItem(void *, Py_ssize_t pos, object item) except -1
3696.3.7 by Robert Collins
Use PyString_Concat directly for another small boost.
92
    int PyTuple_SetItem_obj "PyTuple_SetItem" (void *, Py_ssize_t pos, PyObject * item) except -1
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
93
    void Py_INCREF(object o)
94
    void Py_DECREF(object o)
3696.3.7 by Robert Collins
Use PyString_Concat directly for another small boost.
95
    void PyString_Concat(PyObject **string, object newpart)
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
96
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
97
98
cdef extern from 'dirent.h':
99
    ctypedef struct dirent:
100
        char d_name[256]
3696.3.6 by Robert Collins
Partial review feedback fixups.
101
        ino_t d_ino
3766.1.6 by Martin Pool
We need a 'global' declaration to assign to errno; and fix comments
102
    # the opaque C library DIR type.
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
103
    ctypedef struct DIR
104
    # should be DIR *, pyrex barfs.
1739.2.6 by Robert Collins
Merge bzr.dev
105
    DIR * opendir(char * name)
106
    int closedir(DIR * dir)
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
107
    dirent *readdir(DIR *dir)
108
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
109
cdef object _directory
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
110
_directory = 'directory'
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
111
cdef object _chardev
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
112
_chardev = 'chardev'
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
113
cdef object _block
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
114
_block = 'block'
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
115
cdef object _file
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
116
_file = 'file'
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
117
cdef object _fifo
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
118
_fifo = 'fifo'
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
119
cdef object _symlink
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
120
_symlink = 'symlink'
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
121
cdef object _socket
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
122
_socket = 'socket'
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
123
cdef object _unknown
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
124
_unknown = 'unknown'
125
126
# add a typedef struct dirent dirent to workaround pyrex
127
cdef extern from 'readdir.h':
128
    pass
129
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
130
131
cdef class _Stat:
132
    """Represent a 'stat' result."""
133
3696.3.8 by Robert Collins
Just embed a struct st in the python result object, avoids converting things we don't need converted, and copying values around always.
134
    cdef stat _st
135
136
    property st_dev:
137
        def __get__(self):
138
            return self._st.st_dev
139
140
    property st_ino:
141
        def __get__(self):
142
            return self._st.st_ino
143
144
    property st_mode:
145
        def __get__(self):
146
            return self._st.st_mode
147
148
    property st_ctime:
149
        def __get__(self):
150
            return self._st.st_ctime
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
151
152
    property st_mtime:
153
        def __get__(self):
3696.3.8 by Robert Collins
Just embed a struct st in the python result object, avoids converting things we don't need converted, and copying values around always.
154
            return self._st.st_mtime
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
155
3696.3.8 by Robert Collins
Just embed a struct st in the python result object, avoids converting things we don't need converted, and copying values around always.
156
    property st_size:
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
157
        def __get__(self):
3696.3.8 by Robert Collins
Just embed a struct st in the python result object, avoids converting things we don't need converted, and copying values around always.
158
            return self._st.st_size
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
159
160
    def __repr__(self):
161
        """Repr is the same as a Stat object.
162
3696.3.6 by Robert Collins
Partial review feedback fixups.
163
        (mode, ino, dev, nlink, uid, gid, size, None(atime), mtime, ctime)
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
164
        """
165
        return repr((self.st_mode, 0, 0, 0, 0, 0, self.st_size, None,
4570.1.1 by Robert Collins
Fix repr() on Stat objects from the readdir C extension.
166
                     self.st_mtime, self.st_ctime))
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
167
168
169
from bzrlib import osutils
170
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
171
cdef object _safe_utf8
172
_safe_utf8 = osutils.safe_utf8
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
173
174
cdef class UTF8DirReader:
175
    """A dir reader for utf8 file systems."""
176
177
    def kind_from_mode(self, int mode):
178
        """Get the kind of a path from a mode status."""
179
        return self._kind_from_mode(mode)
180
181
    cdef _kind_from_mode(self, int mode):
3696.3.10 by Robert Collins
Review feedback.
182
        # Files and directories are the most common - check them first.
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
183
        if S_ISREG(mode):
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
184
            return _file
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
185
        if S_ISDIR(mode):
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
186
            return _directory
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
187
        if S_ISCHR(mode):
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
188
            return _chardev
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
189
        if S_ISBLK(mode):
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
190
            return _block
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
191
        if S_ISLNK(mode):
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
192
            return _symlink
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
193
        if S_ISFIFO(mode):
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
194
            return _fifo
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
195
        if S_ISSOCK(mode):
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
196
            return _socket
197
        return _unknown
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
198
199
    def top_prefix_to_starting_dir(self, top, prefix=""):
200
        """See DirReader.top_prefix_to_starting_dir."""
5243.2.1 by John Arbash Meinel
Change the object-level functions into module-level functions.
201
        return (_safe_utf8(prefix), None, None, None, _safe_utf8(top))
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
202
203
    def read_dir(self, prefix, top):
204
        """Read a single directory from a utf8 file system.
205
206
        All paths in and out are utf8.
207
208
        This sub-function is called when we know the filesystem is already in utf8
209
        encoding. So we don't need to transcode filenames.
210
211
        See DirReader.read_dir for details.
212
        """
213
        #cdef char *_prefix = prefix
214
        #cdef char *_top = top
215
        # Use C accelerated directory listing.
216
        cdef object newval
217
        cdef int index
218
        cdef int length
219
        cdef void * atuple
220
        cdef object name
3696.3.7 by Robert Collins
Use PyString_Concat directly for another small boost.
221
        cdef PyObject * new_val_obj
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
222
223
        if PyString_Size(prefix):
224
            relprefix = prefix + '/'
225
        else:
226
            relprefix = ''
227
        top_slash = top + '/'
228
229
        # read_dir supplies in should-stat order.
230
        # for _, name in sorted(_listdir(top)):
231
        result = _read_dir(top)
232
        length = len(result)
233
        # result.sort()
234
        for index from 0 <= index < length:
235
            atuple = PyList_GetItem_object_void(result, index)
236
            name = <object>PyTuple_GetItem_void_void(atuple, 1)
3696.3.10 by Robert Collins
Review feedback.
237
            # We have a tuple with (inode, name, None, statvalue, None)
238
            # Now edit it:
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
239
            # inode -> path_from_top
3696.3.7 by Robert Collins
Use PyString_Concat directly for another small boost.
240
            # direct concat - faster than operator +.
241
            new_val_obj = <PyObject *>relprefix
242
            Py_INCREF(relprefix)
243
            PyString_Concat(&new_val_obj, name)
244
            if NULL == new_val_obj:
245
                # PyString_Concat will have setup an exception, but how to get
246
                # at it?
247
                raise Exception("failed to strcat")
248
            PyTuple_SetItem_obj(atuple, 0, new_val_obj)
3696.3.10 by Robert Collins
Review feedback.
249
            # 1st None -> kind
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
250
            newval = self._kind_from_mode(
251
                (<_Stat>PyTuple_GetItem_void_void(atuple, 3)).st_mode)
252
            Py_INCREF(newval)
253
            PyTuple_SetItem(atuple, 2, newval)
3696.3.10 by Robert Collins
Review feedback.
254
            # 2nd None -> abspath # for all - the caller may need to stat files
255
            # etc.
3696.3.7 by Robert Collins
Use PyString_Concat directly for another small boost.
256
            # direct concat - faster than operator +.
257
            new_val_obj = <PyObject *>top_slash
258
            Py_INCREF(top_slash)
259
            PyString_Concat(&new_val_obj, name)
260
            if NULL == new_val_obj:
261
                # PyString_Concat will have setup an exception, but how to get
262
                # at it?
263
                raise Exception("failed to strcat")
264
            PyTuple_SetItem_obj(atuple, 4, new_val_obj)
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
265
        return result
266
267
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
268
cdef raise_os_error(int errnum, char *msg_prefix, path):
269
    if errnum == EINTR:
270
        PyErr_CheckSignals()
271
    raise OSError(errnum, msg_prefix + strerror(errnum), path)
272
273
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
274
cdef _read_dir(path):
1739.2.11 by Robert Collins
Docstring and copyright header update per Martin's review.
275
    """Like os.listdir, this reads the contents of a directory.
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
276
277
    :param path: the directory to list.
3696.3.10 by Robert Collins
Review feedback.
278
    :return: a list of single-owner (the list) tuples ready for editing into
279
        the result tuples walkdirs needs to yield. They contain (inode, name,
280
        None, statvalue, None).
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
281
    """
282
    cdef DIR *the_dir
283
    # currently this needs a fixup - the C code says 'dirent' but should say
284
    # 'struct dirent'
285
    cdef dirent * entry
1739.2.6 by Robert Collins
Merge bzr.dev
286
    cdef dirent sentinel
287
    cdef char *name
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
288
    cdef int stat_result
289
    cdef _Stat statvalue
3766.1.6 by Martin Pool
We need a 'global' declaration to assign to errno; and fix comments
290
    global errno
3841.1.4 by Martin Pool
Use open/fchdir rather than getcwd/chdir to save and restore directory location
291
    cdef int orig_dir_fd
3696.3.5 by Robert Collins
Streamline _walkdirs_utf8 for utf8 file systems, reducing time to traverse a mozilla tree from 1s to .6 seconds. (Robert Collins)
292
3841.1.4 by Martin Pool
Use open/fchdir rather than getcwd/chdir to save and restore directory location
293
    # Avoid chdir('') because it causes problems on Sun OS, and avoid this if
294
    # staying in .
295
    if path != "" and path != '.':
296
        # we change into the requested directory before reading, and back at the
297
        # end, because that turns out to make the stat calls measurably faster than
298
        # passing full paths every time.
299
        orig_dir_fd = open(".", O_RDONLY, 0)
300
        if orig_dir_fd == -1:
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
301
            raise_os_error(errno, "open: ", ".")
3841.1.2 by Martin Pool
Don't call chdir('')
302
        if -1 == chdir(path):
4634.154.1 by John Arbash Meinel
Bug #583486, close the current-dir file descriptor
303
            # Ignore the return value, because we are already raising an
304
            # exception
305
            close(orig_dir_fd)
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
306
            raise_os_error(errno, "chdir: ", path)
3841.1.4 by Martin Pool
Use open/fchdir rather than getcwd/chdir to save and restore directory location
307
    else:
308
        orig_dir_fd = -1
309
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
310
    try:
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
311
        the_dir = opendir(".")
312
        if NULL == the_dir:
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
313
            raise_os_error(errno, "opendir: ", path)
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
314
        try:
315
            result = []
316
            entry = &sentinel
317
            while entry != NULL:
318
                # Unlike most libc functions, readdir needs errno set to 0
319
                # beforehand so that eof can be distinguished from errors.  See
320
                # <https://bugs.launchpad.net/bzr/+bug/279381>
321
                while True:
3841.1.5 by Martin Pool
Review cleanups on readdir
322
                    errno = 0
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
323
                    entry = readdir(the_dir)
324
                    if entry == NULL and (errno == EAGAIN or errno == EINTR):
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
325
                        if errno == EINTR:
326
                            PyErr_CheckSignals()
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
327
                        # try again
328
                        continue
329
                    else:
330
                        break
331
                if entry == NULL:
332
                    if errno == ENOTDIR or errno == 0:
333
                        # We see ENOTDIR at the end of a normal directory.
334
                        # As ENOTDIR for read_dir(file) is triggered on opendir,
335
                        # we consider ENOTDIR to be 'no error'.
336
                        continue
337
                    else:
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
338
                        raise_os_error(errno, "readdir: ", path)
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
339
                name = entry.d_name
340
                if not (name[0] == c"." and (
341
                    (name[1] == 0) or 
342
                    (name[1] == c"." and name[2] == 0))
343
                    ):
344
                    statvalue = _Stat()
345
                    stat_result = lstat(entry.d_name, &statvalue._st)
346
                    if stat_result != 0:
347
                        if errno != ENOENT:
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
348
                            raise_os_error(errno, "lstat: ",
4095.1.3 by Martin Pool
Add test for failures inside pyrex readdir
349
                                path + "/" + entry.d_name)
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
350
                        else:
4634.75.1 by Martin Pool
Cope with files disappearing between readdir and stat
351
                            # the file seems to have disappeared after being
352
                            # seen by readdir - perhaps a transient temporary
353
                            # file.  there's no point returning it.
354
                            continue
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
355
                    # We append a 5-tuple that can be modified in-place by the C
356
                    # api:
357
                    # inode to sort on (to replace with top_path)
358
                    # name (to keep)
359
                    # kind (None, to set)
360
                    # statvalue (to keep)
361
                    # abspath (None, to set)
362
                    PyList_Append(result, (entry.d_ino, entry.d_name, None,
363
                        statvalue, None))
364
        finally:
365
            if -1 == closedir(the_dir):
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
366
                raise_os_error(errno, "closedir: ", path)
1739.2.6 by Robert Collins
Merge bzr.dev
367
    finally:
3841.1.4 by Martin Pool
Use open/fchdir rather than getcwd/chdir to save and restore directory location
368
        if -1 != orig_dir_fd:
3841.1.5 by Martin Pool
Review cleanups on readdir
369
            failed = False
3841.1.4 by Martin Pool
Use open/fchdir rather than getcwd/chdir to save and restore directory location
370
            if -1 == fchdir(orig_dir_fd):
3841.1.5 by Martin Pool
Review cleanups on readdir
371
                # try to close the original directory anyhow
372
                failed = True
373
            if -1 == close(orig_dir_fd) or failed:
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
374
                raise_os_error(errno, "return to orig_dir: ", "")
3841.1.4 by Martin Pool
Use open/fchdir rather than getcwd/chdir to save and restore directory location
375
1739.2.3 by Robert Collins
Add a replacement for os.listdir which returns file kind information from readdir when it is available. This drops our osutils.walkdirs time further, down to 77ms.
376
    return result
1739.2.6 by Robert Collins
Merge bzr.dev
377
378
379
# vim: tw=79 ai expandtab sw=4 sts=4