7 the GNU General Public License, incorporated herein by reference. |
7 the GNU General Public License, incorporated herein by reference. |
8 */ |
8 */ |
9 |
9 |
10 #define _ATFILE_SOURCE |
10 #define _ATFILE_SOURCE |
11 #include <Python.h> |
11 #include <Python.h> |
|
12 #ifdef _WIN32 |
|
13 #include <windows.h> |
|
14 #else |
12 #include <dirent.h> |
15 #include <dirent.h> |
13 #include <fcntl.h> |
16 #include <fcntl.h> |
14 #include <string.h> |
17 #include <string.h> |
15 #include <sys/stat.h> |
18 #include <sys/stat.h> |
16 #include <sys/types.h> |
19 #include <sys/types.h> |
17 #include <unistd.h> |
20 #include <unistd.h> |
18 |
21 #endif |
|
22 |
|
23 #ifdef _WIN32 |
|
24 /* |
|
25 stat struct compatible with hg expectations |
|
26 Mercurial only uses st_mode, st_size and st_mtime |
|
27 the rest is kept to minimize changes between implementations |
|
28 */ |
|
29 struct hg_stat { |
|
30 int st_dev; |
|
31 int st_mode; |
|
32 int st_nlink; |
|
33 __int64 st_size; |
|
34 int st_mtime; |
|
35 int st_ctime; |
|
36 }; |
|
37 struct listdir_stat { |
|
38 PyObject_HEAD |
|
39 struct hg_stat st; |
|
40 }; |
|
41 #else |
19 struct listdir_stat { |
42 struct listdir_stat { |
20 PyObject_HEAD |
43 PyObject_HEAD |
21 struct stat st; |
44 struct stat st; |
22 }; |
45 }; |
|
46 #endif |
23 |
47 |
24 #define listdir_slot(name) \ |
48 #define listdir_slot(name) \ |
25 static PyObject *listdir_stat_##name(PyObject *self, void *x) \ |
49 static PyObject *listdir_stat_##name(PyObject *self, void *x) \ |
26 { \ |
50 { \ |
27 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \ |
51 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \ |
28 } |
52 } |
29 |
53 |
30 listdir_slot(st_dev) |
54 listdir_slot(st_dev) |
31 listdir_slot(st_mode) |
55 listdir_slot(st_mode) |
32 listdir_slot(st_nlink) |
56 listdir_slot(st_nlink) |
|
57 #ifdef _WIN32 |
|
58 static PyObject *listdir_stat_st_size(PyObject *self, void *x) |
|
59 { |
|
60 return PyLong_FromLongLong( |
|
61 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size); |
|
62 } |
|
63 #else |
33 listdir_slot(st_size) |
64 listdir_slot(st_size) |
|
65 #endif |
34 listdir_slot(st_mtime) |
66 listdir_slot(st_mtime) |
35 listdir_slot(st_ctime) |
67 listdir_slot(st_ctime) |
36 |
68 |
37 static struct PyGetSetDef listdir_stat_getsets[] = { |
69 static struct PyGetSetDef listdir_stat_getsets[] = { |
38 {"st_dev", listdir_stat_st_dev, 0, 0, 0}, |
70 {"st_dev", listdir_stat_st_dev, 0, 0, 0}, |
94 0, /* tp_init */ |
126 0, /* tp_init */ |
95 0, /* tp_alloc */ |
127 0, /* tp_alloc */ |
96 listdir_stat_new, /* tp_new */ |
128 listdir_stat_new, /* tp_new */ |
97 }; |
129 }; |
98 |
130 |
|
131 #ifdef _WIN32 |
|
132 |
|
133 static int to_python_time(const FILETIME *tm) |
|
134 { |
|
135 /* number of seconds between epoch and January 1 1601 */ |
|
136 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L; |
|
137 /* conversion factor from 100ns to 1s */ |
|
138 const __int64 a1 = 10000000; |
|
139 /* explicit (int) cast to suspend compiler warnings */ |
|
140 return (int)((((__int64)tm->dwHighDateTime << 32) |
|
141 + tm->dwLowDateTime) / a1 - a0); |
|
142 } |
|
143 |
|
144 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat) |
|
145 { |
|
146 PyObject *py_st; |
|
147 struct hg_stat *stp; |
|
148 |
|
149 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) |
|
150 ? _S_IFDIR : _S_IFREG; |
|
151 |
|
152 if (!wantstat) |
|
153 return Py_BuildValue("si", fd->cFileName, kind); |
|
154 |
|
155 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL); |
|
156 if (!py_st) |
|
157 return NULL; |
|
158 |
|
159 stp = &((struct listdir_stat *)py_st)->st; |
|
160 /* |
|
161 use kind as st_mode |
|
162 rwx bits on Win32 are meaningless |
|
163 and Hg does not use them anyway |
|
164 */ |
|
165 stp->st_mode = kind; |
|
166 stp->st_mtime = to_python_time(&fd->ftLastWriteTime); |
|
167 stp->st_ctime = to_python_time(&fd->ftCreationTime); |
|
168 if (kind == _S_IFREG) |
|
169 stp->st_size = ((__int64)fd->nFileSizeHigh << 32) |
|
170 + fd->nFileSizeLow; |
|
171 return Py_BuildValue("siN", fd->cFileName, |
|
172 kind, py_st); |
|
173 } |
|
174 |
|
175 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs) |
|
176 { |
|
177 PyObject *rval = NULL; /* initialize - return value */ |
|
178 PyObject *statobj = NULL; /* initialize - optional arg */ |
|
179 PyObject *list; |
|
180 HANDLE fh; |
|
181 WIN32_FIND_DATAA fd; |
|
182 char *path, *pattern, *skip = NULL; |
|
183 int plen, wantstat; |
|
184 |
|
185 static char *kwlist[] = {"path", "stat", "skip", NULL}; |
|
186 |
|
187 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|Os:listdir", |
|
188 kwlist, &path, &plen, &statobj, &skip)) |
|
189 goto error_parse; |
|
190 |
|
191 wantstat = statobj && PyObject_IsTrue(statobj); |
|
192 |
|
193 /* build the path + \* pattern string */ |
|
194 pattern = malloc(plen+3); /* path + \* + \0 */ |
|
195 if (!pattern) { |
|
196 PyErr_NoMemory(); |
|
197 goto error_parse; |
|
198 } |
|
199 strcpy(pattern, path); |
|
200 |
|
201 if (plen > 0) { |
|
202 char c = path[plen-1]; |
|
203 if (c != ':' && c != '/' && c != '\\') |
|
204 pattern[plen++] = '\\'; |
|
205 } |
|
206 strcpy(pattern + plen, "*"); |
|
207 |
|
208 fh = FindFirstFileA(pattern, &fd); |
|
209 if (fh == INVALID_HANDLE_VALUE) { |
|
210 PyErr_SetExcFromWindowsErrWithFilename(PyExc_OSError, |
|
211 GetLastError(), |
|
212 path); |
|
213 goto error_file; |
|
214 } |
|
215 |
|
216 list = PyList_New(0); |
|
217 if (!list) |
|
218 goto error_list; |
|
219 |
|
220 do { |
|
221 PyObject *item; |
|
222 |
|
223 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { |
|
224 if (!strcmp(fd.cFileName, ".") |
|
225 || !strcmp(fd.cFileName, "..")) |
|
226 continue; |
|
227 |
|
228 if (skip && !strcmp(fd.cFileName, skip)) { |
|
229 rval = PyList_New(0); |
|
230 goto error; |
|
231 } |
|
232 } |
|
233 |
|
234 item = make_item(&fd, wantstat); |
|
235 if (!item) |
|
236 goto error; |
|
237 |
|
238 if (PyList_Append(list, item)) { |
|
239 Py_XDECREF(item); |
|
240 goto error; |
|
241 } |
|
242 |
|
243 Py_XDECREF(item); |
|
244 } while (FindNextFileA(fh, &fd)); |
|
245 |
|
246 if (GetLastError() != ERROR_NO_MORE_FILES) { |
|
247 PyErr_SetExcFromWindowsErrWithFilename(PyExc_OSError, |
|
248 GetLastError(), |
|
249 path); |
|
250 goto error; |
|
251 } |
|
252 |
|
253 rval = list; |
|
254 Py_XINCREF(rval); |
|
255 error: |
|
256 Py_XDECREF(list); |
|
257 error_list: |
|
258 FindClose(fh); |
|
259 error_file: |
|
260 free(pattern); |
|
261 error_parse: |
|
262 return rval; |
|
263 } |
|
264 |
|
265 #else |
|
266 |
99 int entkind(struct dirent *ent) |
267 int entkind(struct dirent *ent) |
100 { |
268 { |
101 #ifdef DT_REG |
269 #ifdef DT_REG |
102 switch (ent->d_type) { |
270 switch (ent->d_type) { |
103 case DT_REG: return S_IFREG; |
271 case DT_REG: return S_IFREG; |