/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
6015.56.1 by Alexander Belchenko
_Win32Stat object provides members st_uid and st_gid, those are present in Python's os.stat object. These members required for external tools like bzr-git and dulwich.
1
# Copyright (C) 2008-2012 Canonical Ltd
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
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
7509.1.1 by Jelmer Vernooij
Set cython language level to Python 3.
16
#
17
# cython: language_level=3
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
18
19
"""Helper functions for Walkdirs on win32."""
20
21
3737.1.3 by John Arbash Meinel
Move more compatibility code into python-compat.h
22
cdef extern from "python-compat.h":
3557.2.8 by Alexander Belchenko
We don't need all the extra cdef statments in a cdef extern block
23
    struct _HANDLE:
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
24
        pass
25
    ctypedef _HANDLE *HANDLE
3504.4.8 by John Arbash Meinel
Some code cleanups.
26
    ctypedef unsigned long DWORD
3504.4.10 by John Arbash Meinel
Move the helpers to be standalone, rather than members
27
    ctypedef long long __int64
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
28
    ctypedef unsigned short WCHAR
3557.2.8 by Alexander Belchenko
We don't need all the extra cdef statments in a cdef extern block
29
    struct _FILETIME:
3504.4.6 by John Arbash Meinel
Start exposing the times on the stat, this now seems to be a complete walkdirs implementation.
30
        DWORD dwHighDateTime
31
        DWORD dwLowDateTime
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
32
    ctypedef _FILETIME FILETIME
33
3557.2.8 by Alexander Belchenko
We don't need all the extra cdef statments in a cdef extern block
34
    struct _WIN32_FIND_DATAW:
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
35
        DWORD dwFileAttributes
36
        FILETIME ftCreationTime
37
        FILETIME ftLastAccessTime
38
        FILETIME ftLastWriteTime
39
        DWORD nFileSizeHigh
40
        DWORD nFileSizeLow
41
        # Some reserved stuff here
42
        WCHAR cFileName[260] # MAX_PATH
43
        WCHAR cAlternateFilename[14]
44
45
    # We have to use the typedef trick, otherwise pyrex uses:
46
    #  struct WIN32_FIND_DATAW
47
    # which fails due to 'incomplete type'
48
    ctypedef _WIN32_FIND_DATAW WIN32_FIND_DATAW
49
3557.2.8 by Alexander Belchenko
We don't need all the extra cdef statments in a cdef extern block
50
    HANDLE INVALID_HANDLE_VALUE
51
    HANDLE FindFirstFileW(WCHAR *path, WIN32_FIND_DATAW *data)
52
    int FindNextFileW(HANDLE search, WIN32_FIND_DATAW *data)
53
    int FindClose(HANDLE search)
54
55
    DWORD FILE_ATTRIBUTE_READONLY
56
    DWORD FILE_ATTRIBUTE_DIRECTORY
57
    int ERROR_NO_MORE_FILES
58
59
    int GetLastError()
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
60
3504.4.4 by John Arbash Meinel
We have walkdirs basically working, only without timestamps
61
    # Wide character functions
62
    DWORD wcslen(WCHAR *)
63
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
64
65
cdef extern from "Python.h":
66
    WCHAR *PyUnicode_AS_UNICODE(object)
67
    Py_ssize_t PyUnicode_GET_SIZE(object)
3504.4.4 by John Arbash Meinel
We have walkdirs basically working, only without timestamps
68
    object PyUnicode_FromUnicode(WCHAR *, Py_ssize_t)
3504.4.8 by John Arbash Meinel
Some code cleanups.
69
    int PyList_Append(object, object) except -1
70
    object PyUnicode_AsUTF8String(object)
71
72
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
73
import operator
5609.29.5 by John Arbash Meinel
Fix bug #740932. Transform should update the sha cache.
74
import os
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
75
import stat
76
6656.2.2 by Jelmer Vernooij
Use absolute_import.
77
from . import _readdir_py
5609.29.5 by John Arbash Meinel
Fix bug #740932. Transform should update the sha cache.
78
79
cdef object osutils
80
osutils = None
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
81
82
3504.4.9 by John Arbash Meinel
Switch to using a cdef object with readonly attributes.
83
cdef class _Win32Stat:
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
84
    """Represent a 'stat' result generated from WIN32_FIND_DATA"""
85
3504.4.10 by John Arbash Meinel
Move the helpers to be standalone, rather than members
86
    cdef readonly int st_mode
87
    cdef readonly double st_ctime
88
    cdef readonly double st_mtime
89
    cdef readonly double st_atime
3788.1.2 by John Arbash Meinel
Switch from using cdef readonly __int64 to using a property.
90
    # We can't just declare this as 'readonly' because python2.4 doesn't define
91
    # T_LONGLONG as a structure member. So instead we just use a property that
92
    # will convert it correctly anyway.
93
    cdef __int64 _st_size
94
95
    property st_size:
96
        def __get__(self):
97
            return self._st_size
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
98
99
    # os.stat always returns 0, so we hard code it here
6015.56.2 by Alexander Belchenko
change st_dev, st_ino, st_uid, st_gid from int members to properties.
100
    property st_dev:
101
        def __get__(self):
102
            return 0
103
    property st_ino:
104
        def __get__(self):
105
            return 0
6015.56.1 by Alexander Belchenko
_Win32Stat object provides members st_uid and st_gid, those are present in Python's os.stat object. These members required for external tools like bzr-git and dulwich.
106
    # st_uid and st_gid required for some external tools like bzr-git & dulwich
6015.56.2 by Alexander Belchenko
change st_dev, st_ino, st_uid, st_gid from int members to properties.
107
    property st_uid:
108
        def __get__(self):
109
            return 0
110
    property st_gid:
111
        def __get__(self):
112
            return 0
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
113
114
    def __repr__(self):
115
        """Repr is the same as a Stat object.
116
117
        (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)
118
        """
119
        return repr((self.st_mode, 0, 0, 0, 0, 0, self.st_size, self.st_atime,
120
                     self.st_mtime, self.st_ctime))
121
122
3504.4.11 by John Arbash Meinel
A bit more reorganizing.
123
cdef object _get_name(WIN32_FIND_DATAW *data):
124
    """Extract the Unicode name for this file/dir."""
125
    return PyUnicode_FromUnicode(data.cFileName,
126
                                 wcslen(data.cFileName))
127
128
4634.117.10 by John Arbash Meinel
Change 'no except' to 'cannot_raise'
129
cdef int _get_mode_bits(WIN32_FIND_DATAW *data): # cannot_raise
3504.4.10 by John Arbash Meinel
Move the helpers to be standalone, rather than members
130
    cdef int mode_bits
131
132
    mode_bits = 0100666 # writeable file, the most common
133
    if data.dwFileAttributes & FILE_ATTRIBUTE_READONLY == FILE_ATTRIBUTE_READONLY:
3557.2.5 by John Arbash Meinel
Test that the empty-directory logic for all _walkdirs implementations is correct.
134
        mode_bits = mode_bits ^ 0222 # remove the write bits
3504.4.10 by John Arbash Meinel
Move the helpers to be standalone, rather than members
135
    if data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY:
136
        # Remove the FILE bit, set the DIR bit, and set the EXEC bits
3557.2.5 by John Arbash Meinel
Test that the empty-directory logic for all _walkdirs implementations is correct.
137
        mode_bits = mode_bits ^ 0140111
3504.4.10 by John Arbash Meinel
Move the helpers to be standalone, rather than members
138
    return mode_bits
139
140
4634.117.10 by John Arbash Meinel
Change 'no except' to 'cannot_raise'
141
cdef __int64 _get_size(WIN32_FIND_DATAW *data): # cannot_raise
3504.4.10 by John Arbash Meinel
Move the helpers to be standalone, rather than members
142
    # Pyrex casts a DWORD into a PyLong anyway, so it is safe to do << 32
143
    # on a DWORD
144
    return ((<__int64>data.nFileSizeHigh) << 32) + data.nFileSizeLow
145
146
4634.117.10 by John Arbash Meinel
Change 'no except' to 'cannot_raise'
147
cdef double _ftime_to_timestamp(FILETIME *ft): # cannot_raise
3504.4.10 by John Arbash Meinel
Move the helpers to be standalone, rather than members
148
    """Convert from a FILETIME struct into a floating point timestamp.
149
150
    The fields of a FILETIME structure are the hi and lo part
151
    of a 64-bit value expressed in 100 nanosecond units.
152
    1e7 is one second in such units; 1e-7 the inverse.
153
    429.4967296 is 2**32 / 1e7 or 2**32 * 1e-7.
154
    It also uses the epoch 1601-01-01 rather than 1970-01-01
155
    (taken from posixmodule.c)
156
    """
157
    cdef __int64 val
158
    # NB: This gives slightly different results versus casting to a 64-bit
159
    #     integer and doing integer math before casting into a floating
160
    #     point number. But the difference is in the sub millisecond range,
161
    #     which doesn't seem critical here.
162
    # secs between epochs: 11,644,473,600
163
    val = ((<__int64>ft.dwHighDateTime) << 32) + ft.dwLowDateTime
164
    return (val * 1.0e-7) - 11644473600.0
165
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
166
4634.117.10 by John Arbash Meinel
Change 'no except' to 'cannot_raise'
167
cdef int _should_skip(WIN32_FIND_DATAW *data): # cannot_raise
3504.4.11 by John Arbash Meinel
A bit more reorganizing.
168
    """Is this '.' or '..' so we should skip it?"""
169
    if (data.cFileName[0] != c'.'):
170
        return 0
171
    if data.cFileName[1] == c'\0':
172
        return 1
173
    if data.cFileName[1] == c'.' and data.cFileName[2] == c'\0':
174
        return 1
175
    return 0
176
177
3696.3.1 by Robert Collins
Refactor bzrlib.osutils._walkdirs_utf8 to aid API migration in future.
178
cdef class Win32ReadDir:
179
    """Read directories on win32."""
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
180
3504.4.4 by John Arbash Meinel
We have walkdirs basically working, only without timestamps
181
    cdef object _directory_kind
182
    cdef object _file_kind
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
183
3696.3.1 by Robert Collins
Refactor bzrlib.osutils._walkdirs_utf8 to aid API migration in future.
184
    def __init__(self):
3696.3.10 by Robert Collins
Review feedback.
185
        self._directory_kind = _readdir_py._directory
186
        self._file_kind = _readdir_py._file
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
187
3696.3.1 by Robert Collins
Refactor bzrlib.osutils._walkdirs_utf8 to aid API migration in future.
188
    def top_prefix_to_starting_dir(self, top, prefix=""):
189
        """See DirReader.top_prefix_to_starting_dir."""
5752.2.8 by John Arbash Meinel
Use global osutils, otherwise it creates a local var.
190
        global osutils
5609.29.5 by John Arbash Meinel
Fix bug #740932. Transform should update the sha cache.
191
        if osutils is None:
6656.2.2 by Jelmer Vernooij
Use absolute_import.
192
            from . import osutils
3696.3.2 by John Arbash Meinel
Fix up some of the path joining logic.
193
        return (osutils.safe_utf8(prefix), None, None, None,
194
                osutils.safe_unicode(top))
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
195
3504.4.12 by John Arbash Meinel
A couple small cleanups, make test_osutils more correct
196
    cdef object _get_kind(self, WIN32_FIND_DATAW *data):
197
        if data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY:
198
            return self._directory_kind
199
        return self._file_kind
200
3504.4.9 by John Arbash Meinel
Switch to using a cdef object with readonly attributes.
201
    cdef _Win32Stat _get_stat_value(self, WIN32_FIND_DATAW *data):
3504.4.4 by John Arbash Meinel
We have walkdirs basically working, only without timestamps
202
        """Get the filename and the stat information."""
3504.4.10 by John Arbash Meinel
Move the helpers to be standalone, rather than members
203
        cdef _Win32Stat statvalue
204
205
        statvalue = _Win32Stat()
206
        statvalue.st_mode = _get_mode_bits(data)
207
        statvalue.st_ctime = _ftime_to_timestamp(&data.ftCreationTime)
208
        statvalue.st_mtime = _ftime_to_timestamp(&data.ftLastWriteTime)
209
        statvalue.st_atime = _ftime_to_timestamp(&data.ftLastAccessTime)
3788.1.6 by John Arbash Meinel
Quick fix for win32 extension.
210
        statvalue._st_size = _get_size(data)
3504.4.10 by John Arbash Meinel
Move the helpers to be standalone, rather than members
211
        return statvalue
3504.4.4 by John Arbash Meinel
We have walkdirs basically working, only without timestamps
212
3696.3.1 by Robert Collins
Refactor bzrlib.osutils._walkdirs_utf8 to aid API migration in future.
213
    def read_dir(self, prefix, top):
214
        """Win32 implementation of DirReader.read_dir.
3557.2.2 by John Arbash Meinel
Include better documentation about what is going on. (suggested by Bialix)
215
3696.3.1 by Robert Collins
Refactor bzrlib.osutils._walkdirs_utf8 to aid API migration in future.
216
        :seealso: DirReader.read_dir
3557.2.2 by John Arbash Meinel
Include better documentation about what is going on. (suggested by Bialix)
217
        """
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
218
        cdef WIN32_FIND_DATAW search_data
219
        cdef HANDLE hFindFile
220
        cdef int last_err
221
        cdef WCHAR *query
222
        cdef int result
223
3696.3.1 by Robert Collins
Refactor bzrlib.osutils._walkdirs_utf8 to aid API migration in future.
224
        if prefix:
225
            relprefix = prefix + '/'
226
        else:
227
            relprefix = ''
228
        top_slash = top + '/'
229
3696.3.2 by John Arbash Meinel
Fix up some of the path joining logic.
230
        top_star = top_slash + '*'
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
231
232
        dirblock = []
233
234
        query = PyUnicode_AS_UNICODE(top_star)
235
        hFindFile = FindFirstFileW(query, &search_data)
236
        if hFindFile == INVALID_HANDLE_VALUE:
237
            # Raise an exception? This path doesn't seem to exist
3504.4.8 by John Arbash Meinel
Some code cleanups.
238
            raise WindowsError(GetLastError(), top_star)
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
239
240
        try:
241
            result = 1
242
            while result:
243
                # Skip '.' and '..'
3504.4.11 by John Arbash Meinel
A bit more reorganizing.
244
                if _should_skip(&search_data):
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
245
                    result = FindNextFileW(hFindFile, &search_data)
246
                    continue
3504.4.12 by John Arbash Meinel
A couple small cleanups, make test_osutils more correct
247
                name_unicode = _get_name(&search_data)
3504.4.8 by John Arbash Meinel
Some code cleanups.
248
                name_utf8 = PyUnicode_AsUTF8String(name_unicode)
3696.3.2 by John Arbash Meinel
Fix up some of the path joining logic.
249
                PyList_Append(dirblock,
250
                    (relprefix + name_utf8, name_utf8,
3504.4.8 by John Arbash Meinel
Some code cleanups.
251
                     self._get_kind(&search_data),
252
                     self._get_stat_value(&search_data),
3696.3.2 by John Arbash Meinel
Fix up some of the path joining logic.
253
                     top_slash + name_unicode))
3504.4.4 by John Arbash Meinel
We have walkdirs basically working, only without timestamps
254
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
255
                result = FindNextFileW(hFindFile, &search_data)
3504.4.8 by John Arbash Meinel
Some code cleanups.
256
            # FindNextFileW sets GetLastError() == ERROR_NO_MORE_FILES when it
257
            # actually finishes. If we have anything else, then we have a
258
            # genuine problem
259
            last_err = GetLastError()
260
            if last_err != ERROR_NO_MORE_FILES:
261
                raise WindowsError(last_err)
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
262
        finally:
263
            result = FindClose(hFindFile)
264
            if result == 0:
265
                last_err = GetLastError()
3557.2.2 by John Arbash Meinel
Include better documentation about what is going on. (suggested by Bialix)
266
                # TODO: We should probably raise an exception if FindClose
267
                #       returns an error, however, I don't want to supress an
268
                #       earlier Exception, so for now, I'm ignoring this
3696.3.1 by Robert Collins
Refactor bzrlib.osutils._walkdirs_utf8 to aid API migration in future.
269
        dirblock.sort(key=operator.itemgetter(1))
3504.4.3 by John Arbash Meinel
Start working on an extension specifically for win32,
270
        return dirblock
5609.29.5 by John Arbash Meinel
Fix bug #740932. Transform should update the sha cache.
271
272
273
def lstat(path):
274
    """Equivalent to os.lstat, except match Win32ReadDir._get_stat_value.
275
    """
276
    return wrap_stat(os.lstat(path))
277
278
279
def fstat(fd):
280
    """Like os.fstat, except match Win32ReadDir._get_stat_value
281
282
    :seealso: wrap_stat
283
    """
284
    return wrap_stat(os.fstat(fd))
285
286
287
def wrap_stat(st):
288
    """Return a _Win32Stat object, based on the given stat result.
289
290
    On Windows, os.fstat(open(fname).fileno()) != os.lstat(fname). This is
291
    generally because os.lstat and os.fstat differ in what they put into st_ino
292
    and st_dev. What gets set where seems to also be dependent on the python
293
    version. So we always set it to 0 to avoid worrying about it.
294
    """
295
    cdef _Win32Stat statvalue
296
    statvalue = _Win32Stat()
297
    statvalue.st_mode = st.st_mode
298
    statvalue.st_ctime = st.st_ctime
299
    statvalue.st_mtime = st.st_mtime
300
    statvalue.st_atime = st.st_atime
301
    statvalue._st_size = st.st_size
302
    return statvalue