~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/readdir.pyx

  • Committer: Robert Collins
  • Date: 2006-06-09 15:34:26 UTC
  • mto: This revision was merged to the branch mainline in revision 3682.
  • Revision ID: robertc@robertcollins.net-20060609153426-803129580b26d89f
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.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Bazaar-NG -- distributed version control
 
2
#
 
3
# Copyright (C) 2006 by Canonical Ltd
 
4
#
 
5
# This program is free software; you can redistribute it and/or modify
 
6
# it under the terms of the GNU General Public License as published by
 
7
# the Free Software Foundation; either version 2 of the License, or
 
8
# (at your option) any later version.
 
9
#
 
10
# This program is distributed in the hope that it will be useful,
 
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
# GNU General Public License for more details.
 
14
#
 
15
# You should have received a copy of the GNU General Public License
 
16
# along with this program; if not, write to the Free Software
 
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 
 
19
"""Wrapper for readdir which grabs file type from d_type."""
 
20
 
 
21
 
 
22
import os
 
23
import sys
 
24
 
 
25
 
 
26
# the opaque C library DIR type.
 
27
cdef extern from 'errno.h':
 
28
    int ENOENT
 
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
 
49
    ctypedef struct DIR
 
50
    # should be DIR *, pyrex barfs.
 
51
    DIR * opendir(char * name) except NULL
 
52
    int closedir(DIR * dir) except -1
 
53
    dirent *readdir(DIR *dir)
 
54
 
 
55
_directory = 'directory'
 
56
_chardev = 'chardev'
 
57
_block = 'block'
 
58
_file = 'file'
 
59
_fifo = 'fifo'
 
60
_symlink = 'symlink'
 
61
_socket = 'socket'
 
62
_unknown = 'unknown'
 
63
 
 
64
dot = ord('.')
 
65
 
 
66
# add a typedef struct dirent dirent to workaround pyrex
 
67
cdef extern from 'readdir.h':
 
68
    pass
 
69
 
 
70
def read_dir(path):
 
71
    """Like os.listdir, this reads a directories contents.
 
72
 
 
73
    :param path: the directory to list.
 
74
    :return: a list of (basename, kind) tuples.
 
75
    """
 
76
    cdef DIR *the_dir
 
77
    # currently this needs a fixup - the C code says 'dirent' but should say
 
78
    # 'struct dirent'
 
79
    cdef dirent * entry
 
80
    cdef char *name 
 
81
    the_dir = opendir(path)
 
82
    result = []
 
83
    try:
 
84
        entry = readdir(the_dir)
 
85
        while entry != NULL:
 
86
            name = entry.d_name
 
87
            if not (name[0] == dot and (
 
88
                (name[1] == 0) or 
 
89
                (name[1] == dot and name [2] == 0))
 
90
                ):
 
91
                if entry.d_type == DT_UNKNOWN:
 
92
                    type = _unknown
 
93
                elif entry.d_type == DT_REG:
 
94
                    type = _file
 
95
                elif entry.d_type == DT_DIR:
 
96
                    type = _directory
 
97
                elif entry.d_type == DT_FIFO:
 
98
                    type = _fifo
 
99
                elif entry.d_type == DT_SOCK:
 
100
                    type = _socket
 
101
                elif entry.d_type == DT_CHR:
 
102
                    type = _chardev
 
103
                elif entry.d_type == DT_BLK:
 
104
                    type = _block
 
105
                else:
 
106
                    type = _unknown
 
107
                result.append((entry.d_name, type))
 
108
            entry = readdir(the_dir)
 
109
        if entry == NULL and errno != ENOENT:
 
110
            raise OSError(errno, strerror(errno))
 
111
    finally:
 
112
        closedir(the_dir)
 
113
    return result