~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/_readdir_pyx.pyx

Merge with __contains__

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006, 2008 Canonical Ltd
 
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
 
 
17
"""Wrapper for readdir which returns files ordered by inode."""
 
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
 
27
    int ENOTDIR
 
28
    int EAGAIN
 
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
        int d_ino
 
50
    ctypedef struct DIR
 
51
    # should be DIR *, pyrex barfs.
 
52
    DIR * opendir(char * name)
 
53
    int closedir(DIR * dir)
 
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):
 
72
    """Like os.listdir, this reads the contents of a directory.
 
73
 
 
74
    :param path: the directory to list.
 
75
    :return: a list of (sort_key, basename) tuples.
 
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
 
81
    cdef dirent sentinel
 
82
    cdef char *name
 
83
    the_dir = opendir(path)
 
84
    if NULL == the_dir:
 
85
        raise OSError(errno, strerror(errno))
 
86
    result = []
 
87
    try:
 
88
        entry = &sentinel
 
89
        while entry != NULL:
 
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
 
105
            name = entry.d_name
 
106
            if not (name[0] == dot and (
 
107
                (name[1] == 0) or 
 
108
                (name[1] == dot and name[2] == 0))
 
109
                ):
 
110
                result.append((entry.d_ino, entry.d_name))
 
111
    finally:
 
112
        if -1 == closedir(the_dir):
 
113
            raise OSError(errno, strerror(errno))
 
114
    return result
 
115
 
 
116
 
 
117
# vim: tw=79 ai expandtab sw=4 sts=4