~bzr-pqm/bzr/bzr.dev

4095.1.3 by Martin Pool
Add test for failures inside pyrex readdir
1
# Copyright (C) 2006, 2008, 2009 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
109
_directory = 'directory'
110
_chardev = 'chardev'
111
_block = 'block'
112
_file = 'file'
113
_fifo = 'fifo'
114
_symlink = 'symlink'
115
_socket = 'socket'
116
_unknown = '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)
117
_missing = 'missing'
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
119
# add a typedef struct dirent dirent to workaround pyrex
120
cdef extern from 'readdir.h':
121
    pass
122
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)
123
124
cdef class _Stat:
125
    """Represent a 'stat' result."""
126
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.
127
    cdef stat _st
128
129
    property st_dev:
130
        def __get__(self):
131
            return self._st.st_dev
132
133
    property st_ino:
134
        def __get__(self):
135
            return self._st.st_ino
136
137
    property st_mode:
138
        def __get__(self):
139
            return self._st.st_mode
140
141
    property st_ctime:
142
        def __get__(self):
143
            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)
144
145
    property st_mtime:
146
        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.
147
            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)
148
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.
149
    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)
150
        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.
151
            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)
152
153
    def __repr__(self):
154
        """Repr is the same as a Stat object.
155
3696.3.6 by Robert Collins
Partial review feedback fixups.
156
        (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)
157
        """
158
        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.
159
                     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)
160
161
162
from bzrlib import osutils
163
164
165
cdef class UTF8DirReader:
166
    """A dir reader for utf8 file systems."""
167
168
    cdef readonly object _safe_utf8
169
    cdef _directory, _chardev, _block, _file, _fifo, _symlink
170
    cdef _socket, _unknown
171
172
    def __init__(self):
173
        self._safe_utf8 = osutils.safe_utf8
174
        self._directory = _directory
175
        self._chardev = _chardev
176
        self._block = _block
177
        self._file = _file
178
        self._fifo = _fifo
179
        self._symlink = _symlink
180
        self._socket = _socket
181
        self._unknown = _unknown
182
183
    def kind_from_mode(self, int mode):
184
        """Get the kind of a path from a mode status."""
185
        return self._kind_from_mode(mode)
186
187
    cdef _kind_from_mode(self, int mode):
3696.3.10 by Robert Collins
Review feedback.
188
        # 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)
189
        if S_ISREG(mode):
190
            return self._file
191
        if S_ISDIR(mode):
192
            return self._directory
193
        if S_ISCHR(mode):
194
            return self._chardev
195
        if S_ISBLK(mode):
196
            return self._block
197
        if S_ISLNK(mode):
198
            return self._symlink
199
        if S_ISFIFO(mode):
200
            return self._fifo
201
        if S_ISSOCK(mode):
202
            return self._socket
203
        return self._unknown
204
205
    def top_prefix_to_starting_dir(self, top, prefix=""):
206
        """See DirReader.top_prefix_to_starting_dir."""
207
        return (self._safe_utf8(prefix), None, None, None,
208
            self._safe_utf8(top))
209
210
    def read_dir(self, prefix, top):
211
        """Read a single directory from a utf8 file system.
212
213
        All paths in and out are utf8.
214
215
        This sub-function is called when we know the filesystem is already in utf8
216
        encoding. So we don't need to transcode filenames.
217
218
        See DirReader.read_dir for details.
219
        """
220
        #cdef char *_prefix = prefix
221
        #cdef char *_top = top
222
        # Use C accelerated directory listing.
223
        cdef object newval
224
        cdef int index
225
        cdef int length
226
        cdef void * atuple
227
        cdef object name
3696.3.7 by Robert Collins
Use PyString_Concat directly for another small boost.
228
        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)
229
230
        if PyString_Size(prefix):
231
            relprefix = prefix + '/'
232
        else:
233
            relprefix = ''
234
        top_slash = top + '/'
235
236
        # read_dir supplies in should-stat order.
237
        # for _, name in sorted(_listdir(top)):
238
        result = _read_dir(top)
239
        length = len(result)
240
        # result.sort()
241
        for index from 0 <= index < length:
242
            atuple = PyList_GetItem_object_void(result, index)
243
            name = <object>PyTuple_GetItem_void_void(atuple, 1)
3696.3.10 by Robert Collins
Review feedback.
244
            # We have a tuple with (inode, name, None, statvalue, None)
245
            # 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)
246
            # inode -> path_from_top
3696.3.7 by Robert Collins
Use PyString_Concat directly for another small boost.
247
            # direct concat - faster than operator +.
248
            new_val_obj = <PyObject *>relprefix
249
            Py_INCREF(relprefix)
250
            PyString_Concat(&new_val_obj, name)
251
            if NULL == new_val_obj:
252
                # PyString_Concat will have setup an exception, but how to get
253
                # at it?
254
                raise Exception("failed to strcat")
255
            PyTuple_SetItem_obj(atuple, 0, new_val_obj)
3696.3.10 by Robert Collins
Review feedback.
256
            # 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)
257
            newval = self._kind_from_mode(
258
                (<_Stat>PyTuple_GetItem_void_void(atuple, 3)).st_mode)
259
            Py_INCREF(newval)
260
            PyTuple_SetItem(atuple, 2, newval)
3696.3.10 by Robert Collins
Review feedback.
261
            # 2nd None -> abspath # for all - the caller may need to stat files
262
            # etc.
3696.3.7 by Robert Collins
Use PyString_Concat directly for another small boost.
263
            # direct concat - faster than operator +.
264
            new_val_obj = <PyObject *>top_slash
265
            Py_INCREF(top_slash)
266
            PyString_Concat(&new_val_obj, name)
267
            if NULL == new_val_obj:
268
                # PyString_Concat will have setup an exception, but how to get
269
                # at it?
270
                raise Exception("failed to strcat")
271
            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)
272
        return result
273
274
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
275
cdef raise_os_error(int errnum, char *msg_prefix, path):
276
    if errnum == EINTR:
277
        PyErr_CheckSignals()
278
    raise OSError(errnum, msg_prefix + strerror(errnum), path)
279
280
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)
281
cdef _read_dir(path):
1739.2.11 by Robert Collins
Docstring and copyright header update per Martin's review.
282
    """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.
283
284
    :param path: the directory to list.
3696.3.10 by Robert Collins
Review feedback.
285
    :return: a list of single-owner (the list) tuples ready for editing into
286
        the result tuples walkdirs needs to yield. They contain (inode, name,
287
        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.
288
    """
289
    cdef DIR *the_dir
290
    # currently this needs a fixup - the C code says 'dirent' but should say
291
    # 'struct dirent'
292
    cdef dirent * entry
1739.2.6 by Robert Collins
Merge bzr.dev
293
    cdef dirent sentinel
294
    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)
295
    cdef int stat_result
296
    cdef _Stat statvalue
3766.1.6 by Martin Pool
We need a 'global' declaration to assign to errno; and fix comments
297
    global errno
3841.1.4 by Martin Pool
Use open/fchdir rather than getcwd/chdir to save and restore directory location
298
    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)
299
3841.1.4 by Martin Pool
Use open/fchdir rather than getcwd/chdir to save and restore directory location
300
    # Avoid chdir('') because it causes problems on Sun OS, and avoid this if
301
    # staying in .
302
    if path != "" and path != '.':
303
        # we change into the requested directory before reading, and back at the
304
        # end, because that turns out to make the stat calls measurably faster than
305
        # passing full paths every time.
306
        orig_dir_fd = open(".", O_RDONLY, 0)
307
        if orig_dir_fd == -1:
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
308
            raise_os_error(errno, "open: ", ".")
3841.1.2 by Martin Pool
Don't call chdir('')
309
        if -1 == chdir(path):
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
310
            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
311
    else:
312
        orig_dir_fd = -1
313
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.
314
    try:
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
315
        the_dir = opendir(".")
316
        if NULL == the_dir:
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
317
            raise_os_error(errno, "opendir: ", path)
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
318
        try:
319
            result = []
320
            entry = &sentinel
321
            while entry != NULL:
322
                # Unlike most libc functions, readdir needs errno set to 0
323
                # beforehand so that eof can be distinguished from errors.  See
324
                # <https://bugs.launchpad.net/bzr/+bug/279381>
325
                while True:
3841.1.5 by Martin Pool
Review cleanups on readdir
326
                    errno = 0
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
327
                    entry = readdir(the_dir)
328
                    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.
329
                        if errno == EINTR:
330
                            PyErr_CheckSignals()
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
331
                        # try again
332
                        continue
333
                    else:
334
                        break
335
                if entry == NULL:
336
                    if errno == ENOTDIR or errno == 0:
337
                        # We see ENOTDIR at the end of a normal directory.
338
                        # As ENOTDIR for read_dir(file) is triggered on opendir,
339
                        # we consider ENOTDIR to be 'no error'.
340
                        continue
341
                    else:
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
342
                        raise_os_error(errno, "readdir: ", path)
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
343
                name = entry.d_name
344
                if not (name[0] == c"." and (
345
                    (name[1] == 0) or 
346
                    (name[1] == c"." and name[2] == 0))
347
                    ):
348
                    statvalue = _Stat()
349
                    stat_result = lstat(entry.d_name, &statvalue._st)
350
                    if stat_result != 0:
351
                        if errno != ENOENT:
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
352
                            raise_os_error(errno, "lstat: ",
4095.1.3 by Martin Pool
Add test for failures inside pyrex readdir
353
                                path + "/" + entry.d_name)
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
354
                        else:
4634.75.1 by Martin Pool
Cope with files disappearing between readdir and stat
355
                            # the file seems to have disappeared after being
356
                            # seen by readdir - perhaps a transient temporary
357
                            # file.  there's no point returning it.
358
                            continue
3841.1.1 by Martin Pool
Fix try/finally block after chdir in readdir_pyx
359
                    # We append a 5-tuple that can be modified in-place by the C
360
                    # api:
361
                    # inode to sort on (to replace with top_path)
362
                    # name (to keep)
363
                    # kind (None, to set)
364
                    # statvalue (to keep)
365
                    # abspath (None, to set)
366
                    PyList_Append(result, (entry.d_ino, entry.d_name, None,
367
                        statvalue, None))
368
        finally:
369
            if -1 == closedir(the_dir):
4634.115.1 by Andrew Bennetts
Check for signals whenever an EINTR might have occurred in _readdir_pyx.
370
                raise_os_error(errno, "closedir: ", path)
1739.2.6 by Robert Collins
Merge bzr.dev
371
    finally:
3841.1.4 by Martin Pool
Use open/fchdir rather than getcwd/chdir to save and restore directory location
372
        if -1 != orig_dir_fd:
3841.1.5 by Martin Pool
Review cleanups on readdir
373
            failed = False
3841.1.4 by Martin Pool
Use open/fchdir rather than getcwd/chdir to save and restore directory location
374
            if -1 == fchdir(orig_dir_fd):
3841.1.5 by Martin Pool
Review cleanups on readdir
375
                # try to close the original directory anyhow
376
                failed = True
377
            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.
378
                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
379
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.
380
    return result
1739.2.6 by Robert Collins
Merge bzr.dev
381
382
383
# vim: tw=79 ai expandtab sw=4 sts=4