~bzr-pqm/bzr/bzr.dev

1739.2.6 by Robert Collins
Merge bzr.dev
1
# Copyright (C) 2006, 2008 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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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
23
24
# the opaque C library DIR type.
25
cdef extern from 'errno.h':
26
    int ENOENT
1739.2.6 by Robert Collins
Merge bzr.dev
27
    int ENOTDIR
28
    int EAGAIN
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.
29
    int errno
30
    char *strerror(int errno)
31
32
cdef extern from 'sys/types.h':
33
    ctypedef long ssize_t
34
    ctypedef unsigned long size_t
35
36
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
    ctypedef struct dirent:
45
        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
1739.2.7 by Robert Collins
Update readdir pyrex source files and usage in line with current practice.
49
        int d_ino
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.
50
    ctypedef struct DIR
51
    # should be DIR *, pyrex barfs.
1739.2.6 by Robert Collins
Merge bzr.dev
52
    DIR * opendir(char * name)
53
    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.
54
    dirent *readdir(DIR *dir)
55
56
_directory = 'directory'
57
_chardev = 'chardev'
58
_block = 'block'
59
_file = 'file'
60
_fifo = 'fifo'
61
_symlink = 'symlink'
62
_socket = 'socket'
63
_unknown = 'unknown'
64
65
dot = ord('.')
66
67
# add a typedef struct dirent dirent to workaround pyrex
68
cdef extern from 'readdir.h':
69
    pass
70
71
def read_dir(path):
1739.2.11 by Robert Collins
Docstring and copyright header update per Martin's review.
72
    """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.
73
74
    :param path: the directory to list.
1739.2.7 by Robert Collins
Update readdir pyrex source files and usage in line with current practice.
75
    :return: a list of (sort_key, basename) tuples.
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.
76
    """
77
    cdef DIR *the_dir
78
    # currently this needs a fixup - the C code says 'dirent' but should say
79
    # 'struct dirent'
80
    cdef dirent * entry
1739.2.6 by Robert Collins
Merge bzr.dev
81
    cdef dirent sentinel
82
    cdef char *name
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.
83
    the_dir = opendir(path)
1739.2.6 by Robert Collins
Merge bzr.dev
84
    if NULL == the_dir:
85
        raise OSError(errno, strerror(errno))
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.
86
    result = []
87
    try:
1739.2.6 by Robert Collins
Merge bzr.dev
88
        entry = &sentinel
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.
89
        while entry != NULL:
1739.2.6 by Robert Collins
Merge bzr.dev
90
            entry = readdir(the_dir)
91
            if entry == NULL:
92
                if errno == EAGAIN:
93
                    # try again
94
                    continue
95
                elif errno != ENOTDIR and errno != ENOENT and errno != 0:
96
                    # We see ENOTDIR at the end of a normal directory.
97
                    # As ENOTDIR for read_dir(file) is triggered on opendir,
98
                    # we consider ENOTDIR to be 'no error'.
99
                    # ENOENT is listed as 'invalid position in the dir stream' for
100
                    # readdir. We swallow this for now and just keep reading.
101
                    raise OSError(errno, strerror(errno))
102
                else:
103
                    # done
104
                    continue
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.
105
            name = entry.d_name
106
            if not (name[0] == dot and (
107
                (name[1] == 0) or 
1739.2.9 by Robert Collins
Review feedback.
108
                (name[1] == dot and name[2] == 0))
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.
109
                ):
1739.2.7 by Robert Collins
Update readdir pyrex source files and usage in line with current practice.
110
                result.append((entry.d_ino, entry.d_name))
1739.2.6 by Robert Collins
Merge bzr.dev
111
    finally:
112
        if -1 == closedir(the_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.
113
            raise OSError(errno, strerror(errno))
114
    return result
1739.2.6 by Robert Collins
Merge bzr.dev
115
116
117
# vim: tw=79 ai expandtab sw=4 sts=4