62
64
WCHAR *PyUnicode_AS_UNICODE(object)
63
65
Py_ssize_t PyUnicode_GET_SIZE(object)
64
66
object PyUnicode_FromUnicode(WCHAR *, Py_ssize_t)
67
int PyList_Append(object, object) except -1
68
object PyUnicode_AsUTF8String(object)
113
115
self._prefix = prefix
115
self._utf8_encode = codecs.getencoder('utf8')
116
117
self._directory_kind = osutils._directory_kind
117
118
self._file_kind = osutils._formats[stat.S_IFREG]
119
self._pending = [(osutils.safe_utf8(prefix), None, None, None,
120
osutils.safe_unicode(top))]
120
self._pending = [(osutils.safe_utf8(prefix), osutils.safe_unicode(top))]
121
121
self._last_dirblock = None
123
123
def __iter__(self):
143
143
cdef object _get_size(self, WIN32_FIND_DATAW *data):
144
return long(data.nFileSizeLow) + (long(data.nFileSizeHigh) << 32)
144
# Pyrex casts a DWORD into a PyLong anyway, so it is safe to do << 32
147
val = ((<__int64>data.nFileSizeHigh) << 32) + data.nFileSizeLow
146
150
cdef object _get_stat_value(self, WIN32_FIND_DATAW *data):
147
151
"""Get the filename and the stat information."""
179
183
It also uses the epoch 1601-01-01 rather than 1970-01-01
180
184
(taken from posixmodule.c)
182
187
# NB: This gives slightly different results versus casting to a 64-bit
183
188
# integer and doing integer math before casting into a floating
184
189
# point number. But the difference is in the sub millisecond range,
185
190
# which doesn't seem critical here.
186
return ((ft.dwHighDateTime * 429.4967296 + ft.dwLowDateTime * 1e-7)
191
# secs between epochs: 11,644,473,600
192
val = ((<__int64>ft.dwHighDateTime) << 32) + ft.dwLowDateTime
193
return (val / 1.0e7) - 11644473600.0
189
195
def _get_files_in(self, directory, relprefix):
190
196
cdef WIN32_FIND_DATAW search_data
196
202
top_star = directory + '*'
199
append = dirblock.append
201
206
query = PyUnicode_AS_UNICODE(top_star)
202
207
hFindFile = FindFirstFileW(query, &search_data)
203
208
if hFindFile == INVALID_HANDLE_VALUE:
204
209
# Raise an exception? This path doesn't seem to exist
205
last_err = GetLastError()
206
# Could be last_err == ERROR_FILE_NOT_FOUND
210
raise WindowsError(GetLastError(), top_star)
214
217
result = FindNextFileW(hFindFile, &search_data)
216
219
name_unicode = self._get_name(&search_data)
217
name_utf8 = self._utf8_encode(name_unicode)[0]
220
name_utf8 = PyUnicode_AsUTF8String(name_unicode)
218
221
relpath = relprefix + name_utf8
219
222
abspath = directory + name_unicode
220
append((relpath, name_utf8,
221
self._get_kind(&search_data),
222
self._get_stat_value(&search_data),
223
PyList_Append(dirblock,
225
self._get_kind(&search_data),
226
self._get_stat_value(&search_data),
225
229
result = FindNextFileW(hFindFile, &search_data)
230
# FindNextFileW sets GetLastError() == ERROR_NO_MORE_FILES when it
231
# actually finishes. If we have anything else, then we have a
233
last_err = GetLastError()
234
if last_err != ERROR_NO_MORE_FILES:
235
raise WindowsError(last_err)
227
237
result = FindClose(hFindFile)
233
# for record in FindFilesIterator(top_star):
235
# if name in ('.', '..'):
238
# statvalue = osutils._Win32Stat(record)
239
# name_utf8 = _utf8_encode(name)[0]
240
# abspath = top_slash + name
241
# if DIRECTORY & attrib == DIRECTORY:
245
# append((relprefix + name_utf8, name_utf8, kind, statvalue, abspath))
243
cdef _update_pending(self):
244
"""If we had a result before, add the subdirs to pending."""
248
245
if self._last_dirblock is not None:
249
246
# push the entries left in the dirblock onto the pending queue
250
247
# we do this here, because we allow the user to modified the
251
248
# queue before the next iteration
252
249
for d in reversed(self._last_dirblock):
253
250
if d[2] == self._directory_kind:
254
self._pending.append(d)
251
self._pending.append((d[0], d[-1]))
252
self._last_dirblock = None
255
self._update_pending()
256
256
if not self._pending:
257
257
raise StopIteration()
258
relroot, _, _, _, top = self._pending.pop()
258
relroot, top = self._pending.pop()
259
259
# NB: At the moment Pyrex doesn't support Unicode literals, which means
260
260
# that all of these string literals are going to be upcasted to Unicode
261
261
# at runtime... :(