/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 bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
 
37
37
cdef extern from 'unistd.h':
38
38
    int chdir(char *path)
 
39
    int close(int fd)
 
40
    int fchdir(int fd)
39
41
    char *getcwd(char *, int size)
40
42
 
41
43
cdef extern from 'stdlib.h':
49
51
    ctypedef long time_t
50
52
    ctypedef unsigned long ino_t
51
53
    ctypedef unsigned long long off_t
 
54
    ctypedef int mode_t
52
55
 
53
56
 
54
57
cdef extern from 'sys/stat.h':
69
72
    int S_ISSOCK(int mode)
70
73
 
71
74
 
 
75
cdef extern from 'fcntl.h':
 
76
    int O_RDONLY
 
77
    int open(char *pathname, int flags, mode_t mode)
 
78
 
 
79
 
72
80
cdef extern from 'Python.h':
73
81
    char * PyString_AS_STRING(object)
74
82
    ctypedef int Py_ssize_t # Required for older pyrex versions
279
287
    cdef char *name
280
288
    cdef int stat_result
281
289
    cdef _Stat statvalue
282
 
    cdef char *cwd
283
290
    global errno
284
 
 
285
 
    cwd = getcwd(NULL, 0)
286
 
    if -1 == chdir(path):
287
 
        raise OSError(errno, strerror(errno))
288
 
    the_dir = opendir(".")
289
 
    if NULL == the_dir:
290
 
        raise OSError(errno, strerror(errno))
291
 
    result = []
 
291
    cdef int orig_dir_fd
 
292
 
 
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:
 
301
            raise OSError(errno, strerror(errno))
 
302
        if -1 == chdir(path):
 
303
            raise OSError(errno, strerror(errno))
 
304
    else:
 
305
        orig_dir_fd = -1
 
306
 
292
307
    try:
293
 
        entry = &sentinel
294
 
        while entry != NULL:
295
 
            # Unlike most libc functions, readdir needs errno set to 0
296
 
            # beforehand so that eof can be distinguished from errors.  See
297
 
            # <https://bugs.launchpad.net/bzr/+bug/279381>
298
 
            while True:
299
 
                errno = 0;
300
 
                entry = readdir(the_dir)
301
 
                if entry == NULL and (errno == EAGAIN or errno == EINTR):
302
 
                    # try again
303
 
                    continue
304
 
                else:
305
 
                    break
306
 
            if entry == NULL:
307
 
                if errno == ENOTDIR or errno == 0:
308
 
                    # We see ENOTDIR at the end of a normal directory.
309
 
                    # As ENOTDIR for read_dir(file) is triggered on opendir,
310
 
                    # we consider ENOTDIR to be 'no error'.
311
 
                    continue
312
 
                else:
313
 
                    raise OSError(errno, strerror(errno))
314
 
            name = entry.d_name
315
 
            if not (name[0] == c"." and (
316
 
                (name[1] == 0) or 
317
 
                (name[1] == c"." and name[2] == 0))
318
 
                ):
319
 
                statvalue = _Stat()
320
 
                stat_result = lstat(entry.d_name, &statvalue._st)
321
 
                if stat_result != 0:
322
 
                    if errno != ENOENT:
 
308
        the_dir = opendir(".")
 
309
        if NULL == the_dir:
 
310
            raise OSError(errno, strerror(errno))
 
311
        try:
 
312
            result = []
 
313
            entry = &sentinel
 
314
            while entry != NULL:
 
315
                # Unlike most libc functions, readdir needs errno set to 0
 
316
                # beforehand so that eof can be distinguished from errors.  See
 
317
                # <https://bugs.launchpad.net/bzr/+bug/279381>
 
318
                while True:
 
319
                    errno = 0
 
320
                    entry = readdir(the_dir)
 
321
                    if entry == NULL and (errno == EAGAIN or errno == EINTR):
 
322
                        # try again
 
323
                        continue
 
324
                    else:
 
325
                        break
 
326
                if entry == NULL:
 
327
                    if errno == ENOTDIR or errno == 0:
 
328
                        # We see ENOTDIR at the end of a normal directory.
 
329
                        # As ENOTDIR for read_dir(file) is triggered on opendir,
 
330
                        # we consider ENOTDIR to be 'no error'.
 
331
                        continue
 
332
                    else:
323
333
                        raise OSError(errno, strerror(errno))
324
 
                    else:
325
 
                        kind = _missing
326
 
                        statvalue = None
327
 
                # We append a 5-tuple that can be modified in-place by the C
328
 
                # api:
329
 
                # inode to sort on (to replace with top_path)
330
 
                # name (to keep)
331
 
                # kind (None, to set)
332
 
                # statvalue (to keep)
333
 
                # abspath (None, to set)
334
 
                PyList_Append(result, (entry.d_ino, entry.d_name, None,
335
 
                    statvalue, None))
 
334
                name = entry.d_name
 
335
                if not (name[0] == c"." and (
 
336
                    (name[1] == 0) or 
 
337
                    (name[1] == c"." and name[2] == 0))
 
338
                    ):
 
339
                    statvalue = _Stat()
 
340
                    stat_result = lstat(entry.d_name, &statvalue._st)
 
341
                    if stat_result != 0:
 
342
                        if errno != ENOENT:
 
343
                            raise OSError(errno, strerror(errno))
 
344
                        else:
 
345
                            kind = _missing
 
346
                            statvalue = None
 
347
                    # We append a 5-tuple that can be modified in-place by the C
 
348
                    # api:
 
349
                    # inode to sort on (to replace with top_path)
 
350
                    # name (to keep)
 
351
                    # kind (None, to set)
 
352
                    # statvalue (to keep)
 
353
                    # abspath (None, to set)
 
354
                    PyList_Append(result, (entry.d_ino, entry.d_name, None,
 
355
                        statvalue, None))
 
356
        finally:
 
357
            if -1 == closedir(the_dir):
 
358
                raise OSError(errno, strerror(errno))
336
359
    finally:
337
 
        if -1 == chdir(cwd):
338
 
            free(cwd)
339
 
            raise OSError(errno, strerror(errno))
340
 
        free(cwd)
341
 
        if -1 == closedir(the_dir):
342
 
            raise OSError(errno, strerror(errno))
 
360
        if -1 != orig_dir_fd:
 
361
            failed = False
 
362
            if -1 == fchdir(orig_dir_fd):
 
363
                # try to close the original directory anyhow
 
364
                failed = True
 
365
            if -1 == close(orig_dir_fd) or failed:
 
366
                raise OSError(errno, strerror(errno))
 
367
 
343
368
    return result
344
369
 
345
370