##// END OF EJS Templates
osutil: make statfiles check for interrupts periodically...
Bryan O'Sullivan -
r26983:f9f2f29c default
parent child Browse files
Show More
@@ -1,848 +1,853
1 /*
1 /*
2 osutil.c - native operating system services
2 osutil.c - native operating system services
3
3
4 Copyright 2007 Matt Mackall and others
4 Copyright 2007 Matt Mackall and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
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 #include <fcntl.h>
12 #include <fcntl.h>
13 #include <stdio.h>
13 #include <stdio.h>
14 #include <string.h>
14 #include <string.h>
15 #include <errno.h>
15 #include <errno.h>
16
16
17 #ifdef _WIN32
17 #ifdef _WIN32
18 #include <windows.h>
18 #include <windows.h>
19 #include <io.h>
19 #include <io.h>
20 #else
20 #else
21 #include <dirent.h>
21 #include <dirent.h>
22 #include <sys/stat.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
23 #include <sys/types.h>
24 #include <unistd.h>
24 #include <unistd.h>
25 #endif
25 #endif
26
26
27 #ifdef __APPLE__
27 #ifdef __APPLE__
28 #include <sys/attr.h>
28 #include <sys/attr.h>
29 #include <sys/vnode.h>
29 #include <sys/vnode.h>
30 #endif
30 #endif
31
31
32 #include "util.h"
32 #include "util.h"
33
33
34 /* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
34 /* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
35 #ifndef PATH_MAX
35 #ifndef PATH_MAX
36 #define PATH_MAX 4096
36 #define PATH_MAX 4096
37 #endif
37 #endif
38
38
39 #ifdef _WIN32
39 #ifdef _WIN32
40 /*
40 /*
41 stat struct compatible with hg expectations
41 stat struct compatible with hg expectations
42 Mercurial only uses st_mode, st_size and st_mtime
42 Mercurial only uses st_mode, st_size and st_mtime
43 the rest is kept to minimize changes between implementations
43 the rest is kept to minimize changes between implementations
44 */
44 */
45 struct hg_stat {
45 struct hg_stat {
46 int st_dev;
46 int st_dev;
47 int st_mode;
47 int st_mode;
48 int st_nlink;
48 int st_nlink;
49 __int64 st_size;
49 __int64 st_size;
50 int st_mtime;
50 int st_mtime;
51 int st_ctime;
51 int st_ctime;
52 };
52 };
53 struct listdir_stat {
53 struct listdir_stat {
54 PyObject_HEAD
54 PyObject_HEAD
55 struct hg_stat st;
55 struct hg_stat st;
56 };
56 };
57 #else
57 #else
58 struct listdir_stat {
58 struct listdir_stat {
59 PyObject_HEAD
59 PyObject_HEAD
60 struct stat st;
60 struct stat st;
61 };
61 };
62 #endif
62 #endif
63
63
64 #define listdir_slot(name) \
64 #define listdir_slot(name) \
65 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
65 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
66 { \
66 { \
67 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
67 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
68 }
68 }
69
69
70 listdir_slot(st_dev)
70 listdir_slot(st_dev)
71 listdir_slot(st_mode)
71 listdir_slot(st_mode)
72 listdir_slot(st_nlink)
72 listdir_slot(st_nlink)
73 #ifdef _WIN32
73 #ifdef _WIN32
74 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
74 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
75 {
75 {
76 return PyLong_FromLongLong(
76 return PyLong_FromLongLong(
77 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
77 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
78 }
78 }
79 #else
79 #else
80 listdir_slot(st_size)
80 listdir_slot(st_size)
81 #endif
81 #endif
82 listdir_slot(st_mtime)
82 listdir_slot(st_mtime)
83 listdir_slot(st_ctime)
83 listdir_slot(st_ctime)
84
84
85 static struct PyGetSetDef listdir_stat_getsets[] = {
85 static struct PyGetSetDef listdir_stat_getsets[] = {
86 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
86 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
87 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
87 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
88 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
88 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
89 {"st_size", listdir_stat_st_size, 0, 0, 0},
89 {"st_size", listdir_stat_st_size, 0, 0, 0},
90 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
90 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
91 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
91 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
92 {0, 0, 0, 0, 0}
92 {0, 0, 0, 0, 0}
93 };
93 };
94
94
95 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
95 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
96 {
96 {
97 return t->tp_alloc(t, 0);
97 return t->tp_alloc(t, 0);
98 }
98 }
99
99
100 static void listdir_stat_dealloc(PyObject *o)
100 static void listdir_stat_dealloc(PyObject *o)
101 {
101 {
102 o->ob_type->tp_free(o);
102 o->ob_type->tp_free(o);
103 }
103 }
104
104
105 static PyTypeObject listdir_stat_type = {
105 static PyTypeObject listdir_stat_type = {
106 PyVarObject_HEAD_INIT(NULL, 0)
106 PyVarObject_HEAD_INIT(NULL, 0)
107 "osutil.stat", /*tp_name*/
107 "osutil.stat", /*tp_name*/
108 sizeof(struct listdir_stat), /*tp_basicsize*/
108 sizeof(struct listdir_stat), /*tp_basicsize*/
109 0, /*tp_itemsize*/
109 0, /*tp_itemsize*/
110 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
110 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
111 0, /*tp_print*/
111 0, /*tp_print*/
112 0, /*tp_getattr*/
112 0, /*tp_getattr*/
113 0, /*tp_setattr*/
113 0, /*tp_setattr*/
114 0, /*tp_compare*/
114 0, /*tp_compare*/
115 0, /*tp_repr*/
115 0, /*tp_repr*/
116 0, /*tp_as_number*/
116 0, /*tp_as_number*/
117 0, /*tp_as_sequence*/
117 0, /*tp_as_sequence*/
118 0, /*tp_as_mapping*/
118 0, /*tp_as_mapping*/
119 0, /*tp_hash */
119 0, /*tp_hash */
120 0, /*tp_call*/
120 0, /*tp_call*/
121 0, /*tp_str*/
121 0, /*tp_str*/
122 0, /*tp_getattro*/
122 0, /*tp_getattro*/
123 0, /*tp_setattro*/
123 0, /*tp_setattro*/
124 0, /*tp_as_buffer*/
124 0, /*tp_as_buffer*/
125 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
125 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
126 "stat objects", /* tp_doc */
126 "stat objects", /* tp_doc */
127 0, /* tp_traverse */
127 0, /* tp_traverse */
128 0, /* tp_clear */
128 0, /* tp_clear */
129 0, /* tp_richcompare */
129 0, /* tp_richcompare */
130 0, /* tp_weaklistoffset */
130 0, /* tp_weaklistoffset */
131 0, /* tp_iter */
131 0, /* tp_iter */
132 0, /* tp_iternext */
132 0, /* tp_iternext */
133 0, /* tp_methods */
133 0, /* tp_methods */
134 0, /* tp_members */
134 0, /* tp_members */
135 listdir_stat_getsets, /* tp_getset */
135 listdir_stat_getsets, /* tp_getset */
136 0, /* tp_base */
136 0, /* tp_base */
137 0, /* tp_dict */
137 0, /* tp_dict */
138 0, /* tp_descr_get */
138 0, /* tp_descr_get */
139 0, /* tp_descr_set */
139 0, /* tp_descr_set */
140 0, /* tp_dictoffset */
140 0, /* tp_dictoffset */
141 0, /* tp_init */
141 0, /* tp_init */
142 0, /* tp_alloc */
142 0, /* tp_alloc */
143 listdir_stat_new, /* tp_new */
143 listdir_stat_new, /* tp_new */
144 };
144 };
145
145
146 #ifdef _WIN32
146 #ifdef _WIN32
147
147
148 static int to_python_time(const FILETIME *tm)
148 static int to_python_time(const FILETIME *tm)
149 {
149 {
150 /* number of seconds between epoch and January 1 1601 */
150 /* number of seconds between epoch and January 1 1601 */
151 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
151 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
152 /* conversion factor from 100ns to 1s */
152 /* conversion factor from 100ns to 1s */
153 const __int64 a1 = 10000000;
153 const __int64 a1 = 10000000;
154 /* explicit (int) cast to suspend compiler warnings */
154 /* explicit (int) cast to suspend compiler warnings */
155 return (int)((((__int64)tm->dwHighDateTime << 32)
155 return (int)((((__int64)tm->dwHighDateTime << 32)
156 + tm->dwLowDateTime) / a1 - a0);
156 + tm->dwLowDateTime) / a1 - a0);
157 }
157 }
158
158
159 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
159 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
160 {
160 {
161 PyObject *py_st;
161 PyObject *py_st;
162 struct hg_stat *stp;
162 struct hg_stat *stp;
163
163
164 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
164 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
165 ? _S_IFDIR : _S_IFREG;
165 ? _S_IFDIR : _S_IFREG;
166
166
167 if (!wantstat)
167 if (!wantstat)
168 return Py_BuildValue("si", fd->cFileName, kind);
168 return Py_BuildValue("si", fd->cFileName, kind);
169
169
170 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
170 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
171 if (!py_st)
171 if (!py_st)
172 return NULL;
172 return NULL;
173
173
174 stp = &((struct listdir_stat *)py_st)->st;
174 stp = &((struct listdir_stat *)py_st)->st;
175 /*
175 /*
176 use kind as st_mode
176 use kind as st_mode
177 rwx bits on Win32 are meaningless
177 rwx bits on Win32 are meaningless
178 and Hg does not use them anyway
178 and Hg does not use them anyway
179 */
179 */
180 stp->st_mode = kind;
180 stp->st_mode = kind;
181 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
181 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
182 stp->st_ctime = to_python_time(&fd->ftCreationTime);
182 stp->st_ctime = to_python_time(&fd->ftCreationTime);
183 if (kind == _S_IFREG)
183 if (kind == _S_IFREG)
184 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
184 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
185 + fd->nFileSizeLow;
185 + fd->nFileSizeLow;
186 return Py_BuildValue("siN", fd->cFileName,
186 return Py_BuildValue("siN", fd->cFileName,
187 kind, py_st);
187 kind, py_st);
188 }
188 }
189
189
190 static PyObject *_listdir(char *path, int plen, int wantstat, char *skip)
190 static PyObject *_listdir(char *path, int plen, int wantstat, char *skip)
191 {
191 {
192 PyObject *rval = NULL; /* initialize - return value */
192 PyObject *rval = NULL; /* initialize - return value */
193 PyObject *list;
193 PyObject *list;
194 HANDLE fh;
194 HANDLE fh;
195 WIN32_FIND_DATAA fd;
195 WIN32_FIND_DATAA fd;
196 char *pattern;
196 char *pattern;
197
197
198 /* build the path + \* pattern string */
198 /* build the path + \* pattern string */
199 pattern = malloc(plen + 3); /* path + \* + \0 */
199 pattern = malloc(plen + 3); /* path + \* + \0 */
200 if (!pattern) {
200 if (!pattern) {
201 PyErr_NoMemory();
201 PyErr_NoMemory();
202 goto error_nomem;
202 goto error_nomem;
203 }
203 }
204 strcpy(pattern, path);
204 strcpy(pattern, path);
205
205
206 if (plen > 0) {
206 if (plen > 0) {
207 char c = path[plen-1];
207 char c = path[plen-1];
208 if (c != ':' && c != '/' && c != '\\')
208 if (c != ':' && c != '/' && c != '\\')
209 pattern[plen++] = '\\';
209 pattern[plen++] = '\\';
210 }
210 }
211 strcpy(pattern + plen, "*");
211 strcpy(pattern + plen, "*");
212
212
213 fh = FindFirstFileA(pattern, &fd);
213 fh = FindFirstFileA(pattern, &fd);
214 if (fh == INVALID_HANDLE_VALUE) {
214 if (fh == INVALID_HANDLE_VALUE) {
215 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
215 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
216 goto error_file;
216 goto error_file;
217 }
217 }
218
218
219 list = PyList_New(0);
219 list = PyList_New(0);
220 if (!list)
220 if (!list)
221 goto error_list;
221 goto error_list;
222
222
223 do {
223 do {
224 PyObject *item;
224 PyObject *item;
225
225
226 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
226 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
227 if (!strcmp(fd.cFileName, ".")
227 if (!strcmp(fd.cFileName, ".")
228 || !strcmp(fd.cFileName, ".."))
228 || !strcmp(fd.cFileName, ".."))
229 continue;
229 continue;
230
230
231 if (skip && !strcmp(fd.cFileName, skip)) {
231 if (skip && !strcmp(fd.cFileName, skip)) {
232 rval = PyList_New(0);
232 rval = PyList_New(0);
233 goto error;
233 goto error;
234 }
234 }
235 }
235 }
236
236
237 item = make_item(&fd, wantstat);
237 item = make_item(&fd, wantstat);
238 if (!item)
238 if (!item)
239 goto error;
239 goto error;
240
240
241 if (PyList_Append(list, item)) {
241 if (PyList_Append(list, item)) {
242 Py_XDECREF(item);
242 Py_XDECREF(item);
243 goto error;
243 goto error;
244 }
244 }
245
245
246 Py_XDECREF(item);
246 Py_XDECREF(item);
247 } while (FindNextFileA(fh, &fd));
247 } while (FindNextFileA(fh, &fd));
248
248
249 if (GetLastError() != ERROR_NO_MORE_FILES) {
249 if (GetLastError() != ERROR_NO_MORE_FILES) {
250 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
250 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
251 goto error;
251 goto error;
252 }
252 }
253
253
254 rval = list;
254 rval = list;
255 Py_XINCREF(rval);
255 Py_XINCREF(rval);
256 error:
256 error:
257 Py_XDECREF(list);
257 Py_XDECREF(list);
258 error_list:
258 error_list:
259 FindClose(fh);
259 FindClose(fh);
260 error_file:
260 error_file:
261 free(pattern);
261 free(pattern);
262 error_nomem:
262 error_nomem:
263 return rval;
263 return rval;
264 }
264 }
265
265
266 #else
266 #else
267
267
268 int entkind(struct dirent *ent)
268 int entkind(struct dirent *ent)
269 {
269 {
270 #ifdef DT_REG
270 #ifdef DT_REG
271 switch (ent->d_type) {
271 switch (ent->d_type) {
272 case DT_REG: return S_IFREG;
272 case DT_REG: return S_IFREG;
273 case DT_DIR: return S_IFDIR;
273 case DT_DIR: return S_IFDIR;
274 case DT_LNK: return S_IFLNK;
274 case DT_LNK: return S_IFLNK;
275 case DT_BLK: return S_IFBLK;
275 case DT_BLK: return S_IFBLK;
276 case DT_CHR: return S_IFCHR;
276 case DT_CHR: return S_IFCHR;
277 case DT_FIFO: return S_IFIFO;
277 case DT_FIFO: return S_IFIFO;
278 case DT_SOCK: return S_IFSOCK;
278 case DT_SOCK: return S_IFSOCK;
279 }
279 }
280 #endif
280 #endif
281 return -1;
281 return -1;
282 }
282 }
283
283
284 static PyObject *makestat(const struct stat *st)
284 static PyObject *makestat(const struct stat *st)
285 {
285 {
286 PyObject *stat;
286 PyObject *stat;
287
287
288 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
288 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
289 if (stat)
289 if (stat)
290 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
290 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
291 return stat;
291 return stat;
292 }
292 }
293
293
294 static PyObject *_listdir_stat(char *path, int pathlen, int keepstat,
294 static PyObject *_listdir_stat(char *path, int pathlen, int keepstat,
295 char *skip)
295 char *skip)
296 {
296 {
297 PyObject *list, *elem, *stat = NULL, *ret = NULL;
297 PyObject *list, *elem, *stat = NULL, *ret = NULL;
298 char fullpath[PATH_MAX + 10];
298 char fullpath[PATH_MAX + 10];
299 int kind, err;
299 int kind, err;
300 struct stat st;
300 struct stat st;
301 struct dirent *ent;
301 struct dirent *ent;
302 DIR *dir;
302 DIR *dir;
303 #ifdef AT_SYMLINK_NOFOLLOW
303 #ifdef AT_SYMLINK_NOFOLLOW
304 int dfd = -1;
304 int dfd = -1;
305 #endif
305 #endif
306
306
307 if (pathlen >= PATH_MAX) {
307 if (pathlen >= PATH_MAX) {
308 errno = ENAMETOOLONG;
308 errno = ENAMETOOLONG;
309 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
309 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
310 goto error_value;
310 goto error_value;
311 }
311 }
312 strncpy(fullpath, path, PATH_MAX);
312 strncpy(fullpath, path, PATH_MAX);
313 fullpath[pathlen] = '/';
313 fullpath[pathlen] = '/';
314
314
315 #ifdef AT_SYMLINK_NOFOLLOW
315 #ifdef AT_SYMLINK_NOFOLLOW
316 dfd = open(path, O_RDONLY);
316 dfd = open(path, O_RDONLY);
317 if (dfd == -1) {
317 if (dfd == -1) {
318 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
318 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
319 goto error_value;
319 goto error_value;
320 }
320 }
321 dir = fdopendir(dfd);
321 dir = fdopendir(dfd);
322 #else
322 #else
323 dir = opendir(path);
323 dir = opendir(path);
324 #endif
324 #endif
325 if (!dir) {
325 if (!dir) {
326 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
326 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
327 goto error_dir;
327 goto error_dir;
328 }
328 }
329
329
330 list = PyList_New(0);
330 list = PyList_New(0);
331 if (!list)
331 if (!list)
332 goto error_list;
332 goto error_list;
333
333
334 while ((ent = readdir(dir))) {
334 while ((ent = readdir(dir))) {
335 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
335 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
336 continue;
336 continue;
337
337
338 kind = entkind(ent);
338 kind = entkind(ent);
339 if (kind == -1 || keepstat) {
339 if (kind == -1 || keepstat) {
340 #ifdef AT_SYMLINK_NOFOLLOW
340 #ifdef AT_SYMLINK_NOFOLLOW
341 err = fstatat(dfd, ent->d_name, &st,
341 err = fstatat(dfd, ent->d_name, &st,
342 AT_SYMLINK_NOFOLLOW);
342 AT_SYMLINK_NOFOLLOW);
343 #else
343 #else
344 strncpy(fullpath + pathlen + 1, ent->d_name,
344 strncpy(fullpath + pathlen + 1, ent->d_name,
345 PATH_MAX - pathlen);
345 PATH_MAX - pathlen);
346 fullpath[PATH_MAX] = '\0';
346 fullpath[PATH_MAX] = '\0';
347 err = lstat(fullpath, &st);
347 err = lstat(fullpath, &st);
348 #endif
348 #endif
349 if (err == -1) {
349 if (err == -1) {
350 /* race with file deletion? */
350 /* race with file deletion? */
351 if (errno == ENOENT)
351 if (errno == ENOENT)
352 continue;
352 continue;
353 strncpy(fullpath + pathlen + 1, ent->d_name,
353 strncpy(fullpath + pathlen + 1, ent->d_name,
354 PATH_MAX - pathlen);
354 PATH_MAX - pathlen);
355 fullpath[PATH_MAX] = 0;
355 fullpath[PATH_MAX] = 0;
356 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
356 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
357 fullpath);
357 fullpath);
358 goto error;
358 goto error;
359 }
359 }
360 kind = st.st_mode & S_IFMT;
360 kind = st.st_mode & S_IFMT;
361 }
361 }
362
362
363 /* quit early? */
363 /* quit early? */
364 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
364 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
365 ret = PyList_New(0);
365 ret = PyList_New(0);
366 goto error;
366 goto error;
367 }
367 }
368
368
369 if (keepstat) {
369 if (keepstat) {
370 stat = makestat(&st);
370 stat = makestat(&st);
371 if (!stat)
371 if (!stat)
372 goto error;
372 goto error;
373 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
373 elem = Py_BuildValue("siN", ent->d_name, kind, stat);
374 } else
374 } else
375 elem = Py_BuildValue("si", ent->d_name, kind);
375 elem = Py_BuildValue("si", ent->d_name, kind);
376 if (!elem)
376 if (!elem)
377 goto error;
377 goto error;
378 stat = NULL;
378 stat = NULL;
379
379
380 PyList_Append(list, elem);
380 PyList_Append(list, elem);
381 Py_DECREF(elem);
381 Py_DECREF(elem);
382 }
382 }
383
383
384 ret = list;
384 ret = list;
385 Py_INCREF(ret);
385 Py_INCREF(ret);
386
386
387 error:
387 error:
388 Py_DECREF(list);
388 Py_DECREF(list);
389 Py_XDECREF(stat);
389 Py_XDECREF(stat);
390 error_list:
390 error_list:
391 closedir(dir);
391 closedir(dir);
392 error_dir:
392 error_dir:
393 #ifdef AT_SYMLINK_NOFOLLOW
393 #ifdef AT_SYMLINK_NOFOLLOW
394 close(dfd);
394 close(dfd);
395 #endif
395 #endif
396 error_value:
396 error_value:
397 return ret;
397 return ret;
398 }
398 }
399
399
400 #ifdef __APPLE__
400 #ifdef __APPLE__
401
401
402 typedef struct {
402 typedef struct {
403 u_int32_t length;
403 u_int32_t length;
404 attrreference_t name;
404 attrreference_t name;
405 fsobj_type_t obj_type;
405 fsobj_type_t obj_type;
406 struct timespec mtime;
406 struct timespec mtime;
407 #if __LITTLE_ENDIAN__
407 #if __LITTLE_ENDIAN__
408 mode_t access_mask;
408 mode_t access_mask;
409 uint16_t padding;
409 uint16_t padding;
410 #else
410 #else
411 uint16_t padding;
411 uint16_t padding;
412 mode_t access_mask;
412 mode_t access_mask;
413 #endif
413 #endif
414 off_t size;
414 off_t size;
415 } __attribute__((packed)) attrbuf_entry;
415 } __attribute__((packed)) attrbuf_entry;
416
416
417 int attrkind(attrbuf_entry *entry)
417 int attrkind(attrbuf_entry *entry)
418 {
418 {
419 switch (entry->obj_type) {
419 switch (entry->obj_type) {
420 case VREG: return S_IFREG;
420 case VREG: return S_IFREG;
421 case VDIR: return S_IFDIR;
421 case VDIR: return S_IFDIR;
422 case VLNK: return S_IFLNK;
422 case VLNK: return S_IFLNK;
423 case VBLK: return S_IFBLK;
423 case VBLK: return S_IFBLK;
424 case VCHR: return S_IFCHR;
424 case VCHR: return S_IFCHR;
425 case VFIFO: return S_IFIFO;
425 case VFIFO: return S_IFIFO;
426 case VSOCK: return S_IFSOCK;
426 case VSOCK: return S_IFSOCK;
427 }
427 }
428 return -1;
428 return -1;
429 }
429 }
430
430
431 /* get these many entries at a time */
431 /* get these many entries at a time */
432 #define LISTDIR_BATCH_SIZE 50
432 #define LISTDIR_BATCH_SIZE 50
433
433
434 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
434 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
435 char *skip, bool *fallback)
435 char *skip, bool *fallback)
436 {
436 {
437 PyObject *list, *elem, *stat = NULL, *ret = NULL;
437 PyObject *list, *elem, *stat = NULL, *ret = NULL;
438 int kind, err;
438 int kind, err;
439 unsigned long index;
439 unsigned long index;
440 unsigned int count, old_state, new_state;
440 unsigned int count, old_state, new_state;
441 bool state_seen = false;
441 bool state_seen = false;
442 attrbuf_entry *entry;
442 attrbuf_entry *entry;
443 /* from the getattrlist(2) man page: a path can be no longer than
443 /* from the getattrlist(2) man page: a path can be no longer than
444 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
444 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
445 silently truncate attribute data if attrBufSize is too small." So
445 silently truncate attribute data if attrBufSize is too small." So
446 pass in a buffer big enough for the worst case. */
446 pass in a buffer big enough for the worst case. */
447 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
447 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
448 unsigned int basep_unused;
448 unsigned int basep_unused;
449
449
450 struct stat st;
450 struct stat st;
451 int dfd = -1;
451 int dfd = -1;
452
452
453 /* these must match the attrbuf_entry struct, otherwise you'll end up
453 /* these must match the attrbuf_entry struct, otherwise you'll end up
454 with garbage */
454 with garbage */
455 struct attrlist requested_attr = {0};
455 struct attrlist requested_attr = {0};
456 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
456 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
457 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
457 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
458 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
458 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
459 requested_attr.fileattr = ATTR_FILE_TOTALSIZE;
459 requested_attr.fileattr = ATTR_FILE_TOTALSIZE;
460
460
461 *fallback = false;
461 *fallback = false;
462
462
463 if (pathlen >= PATH_MAX) {
463 if (pathlen >= PATH_MAX) {
464 errno = ENAMETOOLONG;
464 errno = ENAMETOOLONG;
465 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
465 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
466 goto error_value;
466 goto error_value;
467 }
467 }
468
468
469 dfd = open(path, O_RDONLY);
469 dfd = open(path, O_RDONLY);
470 if (dfd == -1) {
470 if (dfd == -1) {
471 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
471 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
472 goto error_value;
472 goto error_value;
473 }
473 }
474
474
475 list = PyList_New(0);
475 list = PyList_New(0);
476 if (!list)
476 if (!list)
477 goto error_dir;
477 goto error_dir;
478
478
479 do {
479 do {
480 count = LISTDIR_BATCH_SIZE;
480 count = LISTDIR_BATCH_SIZE;
481 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
481 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
482 sizeof(attrbuf), &count, &basep_unused,
482 sizeof(attrbuf), &count, &basep_unused,
483 &new_state, 0);
483 &new_state, 0);
484 if (err < 0) {
484 if (err < 0) {
485 if (errno == ENOTSUP) {
485 if (errno == ENOTSUP) {
486 /* We're on a filesystem that doesn't support
486 /* We're on a filesystem that doesn't support
487 getdirentriesattr. Fall back to the
487 getdirentriesattr. Fall back to the
488 stat-based implementation. */
488 stat-based implementation. */
489 *fallback = true;
489 *fallback = true;
490 } else
490 } else
491 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
491 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
492 goto error;
492 goto error;
493 }
493 }
494
494
495 if (!state_seen) {
495 if (!state_seen) {
496 old_state = new_state;
496 old_state = new_state;
497 state_seen = true;
497 state_seen = true;
498 } else if (old_state != new_state) {
498 } else if (old_state != new_state) {
499 /* There's an edge case with getdirentriesattr. Consider
499 /* There's an edge case with getdirentriesattr. Consider
500 the following initial list of files:
500 the following initial list of files:
501
501
502 a
502 a
503 b
503 b
504 <--
504 <--
505 c
505 c
506 d
506 d
507
507
508 If the iteration is paused at the arrow, and b is
508 If the iteration is paused at the arrow, and b is
509 deleted before it is resumed, getdirentriesattr will
509 deleted before it is resumed, getdirentriesattr will
510 not return d at all! Ordinarily we're expected to
510 not return d at all! Ordinarily we're expected to
511 restart the iteration from the beginning. To avoid
511 restart the iteration from the beginning. To avoid
512 getting stuck in a retry loop here, fall back to
512 getting stuck in a retry loop here, fall back to
513 stat. */
513 stat. */
514 *fallback = true;
514 *fallback = true;
515 goto error;
515 goto error;
516 }
516 }
517
517
518 entry = (attrbuf_entry *)attrbuf;
518 entry = (attrbuf_entry *)attrbuf;
519
519
520 for (index = 0; index < count; index++) {
520 for (index = 0; index < count; index++) {
521 char *filename = ((char *)&entry->name) +
521 char *filename = ((char *)&entry->name) +
522 entry->name.attr_dataoffset;
522 entry->name.attr_dataoffset;
523
523
524 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
524 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
525 continue;
525 continue;
526
526
527 kind = attrkind(entry);
527 kind = attrkind(entry);
528 if (kind == -1) {
528 if (kind == -1) {
529 PyErr_Format(PyExc_OSError,
529 PyErr_Format(PyExc_OSError,
530 "unknown object type %u for file "
530 "unknown object type %u for file "
531 "%s%s!",
531 "%s%s!",
532 entry->obj_type, path, filename);
532 entry->obj_type, path, filename);
533 goto error;
533 goto error;
534 }
534 }
535
535
536 /* quit early? */
536 /* quit early? */
537 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
537 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
538 ret = PyList_New(0);
538 ret = PyList_New(0);
539 goto error;
539 goto error;
540 }
540 }
541
541
542 if (keepstat) {
542 if (keepstat) {
543 /* from the getattrlist(2) man page: "Only the
543 /* from the getattrlist(2) man page: "Only the
544 permission bits ... are valid". */
544 permission bits ... are valid". */
545 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
545 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
546 st.st_mtime = entry->mtime.tv_sec;
546 st.st_mtime = entry->mtime.tv_sec;
547 st.st_size = entry->size;
547 st.st_size = entry->size;
548 stat = makestat(&st);
548 stat = makestat(&st);
549 if (!stat)
549 if (!stat)
550 goto error;
550 goto error;
551 elem = Py_BuildValue("siN", filename, kind, stat);
551 elem = Py_BuildValue("siN", filename, kind, stat);
552 } else
552 } else
553 elem = Py_BuildValue("si", filename, kind);
553 elem = Py_BuildValue("si", filename, kind);
554 if (!elem)
554 if (!elem)
555 goto error;
555 goto error;
556 stat = NULL;
556 stat = NULL;
557
557
558 PyList_Append(list, elem);
558 PyList_Append(list, elem);
559 Py_DECREF(elem);
559 Py_DECREF(elem);
560
560
561 entry = (attrbuf_entry *)((char *)entry + entry->length);
561 entry = (attrbuf_entry *)((char *)entry + entry->length);
562 }
562 }
563 } while (err == 0);
563 } while (err == 0);
564
564
565 ret = list;
565 ret = list;
566 Py_INCREF(ret);
566 Py_INCREF(ret);
567
567
568 error:
568 error:
569 Py_DECREF(list);
569 Py_DECREF(list);
570 Py_XDECREF(stat);
570 Py_XDECREF(stat);
571 error_dir:
571 error_dir:
572 close(dfd);
572 close(dfd);
573 error_value:
573 error_value:
574 return ret;
574 return ret;
575 }
575 }
576
576
577 #endif /* __APPLE__ */
577 #endif /* __APPLE__ */
578
578
579 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
579 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
580 {
580 {
581 #ifdef __APPLE__
581 #ifdef __APPLE__
582 PyObject *ret;
582 PyObject *ret;
583 bool fallback = false;
583 bool fallback = false;
584
584
585 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
585 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
586 if (ret != NULL || !fallback)
586 if (ret != NULL || !fallback)
587 return ret;
587 return ret;
588 #endif
588 #endif
589 return _listdir_stat(path, pathlen, keepstat, skip);
589 return _listdir_stat(path, pathlen, keepstat, skip);
590 }
590 }
591
591
592 static PyObject *statfiles(PyObject *self, PyObject *args)
592 static PyObject *statfiles(PyObject *self, PyObject *args)
593 {
593 {
594 PyObject *names, *stats;
594 PyObject *names, *stats;
595 Py_ssize_t i, count;
595 Py_ssize_t i, count;
596
596
597 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
597 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
598 return NULL;
598 return NULL;
599
599
600 count = PySequence_Length(names);
600 count = PySequence_Length(names);
601 if (count == -1) {
601 if (count == -1) {
602 PyErr_SetString(PyExc_TypeError, "not a sequence");
602 PyErr_SetString(PyExc_TypeError, "not a sequence");
603 return NULL;
603 return NULL;
604 }
604 }
605
605
606 stats = PyList_New(count);
606 stats = PyList_New(count);
607 if (stats == NULL)
607 if (stats == NULL)
608 return NULL;
608 return NULL;
609
609
610 for (i = 0; i < count; i++) {
610 for (i = 0; i < count; i++) {
611 PyObject *stat, *pypath;
611 PyObject *stat, *pypath;
612 struct stat st;
612 struct stat st;
613 int ret, kind;
613 int ret, kind;
614 char *path;
614 char *path;
615
615
616 /* With a large file count or on a slow filesystem,
617 don't block signals for long (issue4878). */
618 if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
619 goto bail;
620
616 pypath = PySequence_GetItem(names, i);
621 pypath = PySequence_GetItem(names, i);
617 if (!pypath)
622 if (!pypath)
618 goto bail;
623 goto bail;
619 path = PyString_AsString(pypath);
624 path = PyString_AsString(pypath);
620 if (path == NULL) {
625 if (path == NULL) {
621 Py_DECREF(pypath);
626 Py_DECREF(pypath);
622 PyErr_SetString(PyExc_TypeError, "not a string");
627 PyErr_SetString(PyExc_TypeError, "not a string");
623 goto bail;
628 goto bail;
624 }
629 }
625 ret = lstat(path, &st);
630 ret = lstat(path, &st);
626 Py_DECREF(pypath);
631 Py_DECREF(pypath);
627 kind = st.st_mode & S_IFMT;
632 kind = st.st_mode & S_IFMT;
628 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
633 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
629 stat = makestat(&st);
634 stat = makestat(&st);
630 if (stat == NULL)
635 if (stat == NULL)
631 goto bail;
636 goto bail;
632 PyList_SET_ITEM(stats, i, stat);
637 PyList_SET_ITEM(stats, i, stat);
633 } else {
638 } else {
634 Py_INCREF(Py_None);
639 Py_INCREF(Py_None);
635 PyList_SET_ITEM(stats, i, Py_None);
640 PyList_SET_ITEM(stats, i, Py_None);
636 }
641 }
637 }
642 }
638
643
639 return stats;
644 return stats;
640
645
641 bail:
646 bail:
642 Py_DECREF(stats);
647 Py_DECREF(stats);
643 return NULL;
648 return NULL;
644 }
649 }
645
650
646 #endif /* ndef _WIN32 */
651 #endif /* ndef _WIN32 */
647
652
648 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
653 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
649 {
654 {
650 PyObject *statobj = NULL; /* initialize - optional arg */
655 PyObject *statobj = NULL; /* initialize - optional arg */
651 PyObject *skipobj = NULL; /* initialize - optional arg */
656 PyObject *skipobj = NULL; /* initialize - optional arg */
652 char *path, *skip = NULL;
657 char *path, *skip = NULL;
653 int wantstat, plen;
658 int wantstat, plen;
654
659
655 static char *kwlist[] = {"path", "stat", "skip", NULL};
660 static char *kwlist[] = {"path", "stat", "skip", NULL};
656
661
657 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
662 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
658 kwlist, &path, &plen, &statobj, &skipobj))
663 kwlist, &path, &plen, &statobj, &skipobj))
659 return NULL;
664 return NULL;
660
665
661 wantstat = statobj && PyObject_IsTrue(statobj);
666 wantstat = statobj && PyObject_IsTrue(statobj);
662
667
663 if (skipobj && skipobj != Py_None) {
668 if (skipobj && skipobj != Py_None) {
664 skip = PyBytes_AsString(skipobj);
669 skip = PyBytes_AsString(skipobj);
665 if (!skip)
670 if (!skip)
666 return NULL;
671 return NULL;
667 }
672 }
668
673
669 return _listdir(path, plen, wantstat, skip);
674 return _listdir(path, plen, wantstat, skip);
670 }
675 }
671
676
672 #ifdef _WIN32
677 #ifdef _WIN32
673 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
678 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
674 {
679 {
675 static char *kwlist[] = {"name", "mode", "buffering", NULL};
680 static char *kwlist[] = {"name", "mode", "buffering", NULL};
676 PyObject *file_obj = NULL;
681 PyObject *file_obj = NULL;
677 char *name = NULL;
682 char *name = NULL;
678 char *mode = "rb";
683 char *mode = "rb";
679 DWORD access = 0;
684 DWORD access = 0;
680 DWORD creation;
685 DWORD creation;
681 HANDLE handle;
686 HANDLE handle;
682 int fd, flags = 0;
687 int fd, flags = 0;
683 int bufsize = -1;
688 int bufsize = -1;
684 char m0, m1, m2;
689 char m0, m1, m2;
685 char fpmode[4];
690 char fpmode[4];
686 int fppos = 0;
691 int fppos = 0;
687 int plus;
692 int plus;
688 FILE *fp;
693 FILE *fp;
689
694
690 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
695 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
691 Py_FileSystemDefaultEncoding,
696 Py_FileSystemDefaultEncoding,
692 &name, &mode, &bufsize))
697 &name, &mode, &bufsize))
693 return NULL;
698 return NULL;
694
699
695 m0 = mode[0];
700 m0 = mode[0];
696 m1 = m0 ? mode[1] : '\0';
701 m1 = m0 ? mode[1] : '\0';
697 m2 = m1 ? mode[2] : '\0';
702 m2 = m1 ? mode[2] : '\0';
698 plus = m1 == '+' || m2 == '+';
703 plus = m1 == '+' || m2 == '+';
699
704
700 fpmode[fppos++] = m0;
705 fpmode[fppos++] = m0;
701 if (m1 == 'b' || m2 == 'b') {
706 if (m1 == 'b' || m2 == 'b') {
702 flags = _O_BINARY;
707 flags = _O_BINARY;
703 fpmode[fppos++] = 'b';
708 fpmode[fppos++] = 'b';
704 }
709 }
705 else
710 else
706 flags = _O_TEXT;
711 flags = _O_TEXT;
707 if (m0 == 'r' && !plus) {
712 if (m0 == 'r' && !plus) {
708 flags |= _O_RDONLY;
713 flags |= _O_RDONLY;
709 access = GENERIC_READ;
714 access = GENERIC_READ;
710 } else {
715 } else {
711 /*
716 /*
712 work around http://support.microsoft.com/kb/899149 and
717 work around http://support.microsoft.com/kb/899149 and
713 set _O_RDWR for 'w' and 'a', even if mode has no '+'
718 set _O_RDWR for 'w' and 'a', even if mode has no '+'
714 */
719 */
715 flags |= _O_RDWR;
720 flags |= _O_RDWR;
716 access = GENERIC_READ | GENERIC_WRITE;
721 access = GENERIC_READ | GENERIC_WRITE;
717 fpmode[fppos++] = '+';
722 fpmode[fppos++] = '+';
718 }
723 }
719 fpmode[fppos++] = '\0';
724 fpmode[fppos++] = '\0';
720
725
721 switch (m0) {
726 switch (m0) {
722 case 'r':
727 case 'r':
723 creation = OPEN_EXISTING;
728 creation = OPEN_EXISTING;
724 break;
729 break;
725 case 'w':
730 case 'w':
726 creation = CREATE_ALWAYS;
731 creation = CREATE_ALWAYS;
727 break;
732 break;
728 case 'a':
733 case 'a':
729 creation = OPEN_ALWAYS;
734 creation = OPEN_ALWAYS;
730 flags |= _O_APPEND;
735 flags |= _O_APPEND;
731 break;
736 break;
732 default:
737 default:
733 PyErr_Format(PyExc_ValueError,
738 PyErr_Format(PyExc_ValueError,
734 "mode string must begin with one of 'r', 'w', "
739 "mode string must begin with one of 'r', 'w', "
735 "or 'a', not '%c'", m0);
740 "or 'a', not '%c'", m0);
736 goto bail;
741 goto bail;
737 }
742 }
738
743
739 handle = CreateFile(name, access,
744 handle = CreateFile(name, access,
740 FILE_SHARE_READ | FILE_SHARE_WRITE |
745 FILE_SHARE_READ | FILE_SHARE_WRITE |
741 FILE_SHARE_DELETE,
746 FILE_SHARE_DELETE,
742 NULL,
747 NULL,
743 creation,
748 creation,
744 FILE_ATTRIBUTE_NORMAL,
749 FILE_ATTRIBUTE_NORMAL,
745 0);
750 0);
746
751
747 if (handle == INVALID_HANDLE_VALUE) {
752 if (handle == INVALID_HANDLE_VALUE) {
748 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
753 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
749 goto bail;
754 goto bail;
750 }
755 }
751
756
752 fd = _open_osfhandle((intptr_t)handle, flags);
757 fd = _open_osfhandle((intptr_t)handle, flags);
753
758
754 if (fd == -1) {
759 if (fd == -1) {
755 CloseHandle(handle);
760 CloseHandle(handle);
756 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
761 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
757 goto bail;
762 goto bail;
758 }
763 }
759 #ifndef IS_PY3K
764 #ifndef IS_PY3K
760 fp = _fdopen(fd, fpmode);
765 fp = _fdopen(fd, fpmode);
761 if (fp == NULL) {
766 if (fp == NULL) {
762 _close(fd);
767 _close(fd);
763 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
768 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
764 goto bail;
769 goto bail;
765 }
770 }
766
771
767 file_obj = PyFile_FromFile(fp, name, mode, fclose);
772 file_obj = PyFile_FromFile(fp, name, mode, fclose);
768 if (file_obj == NULL) {
773 if (file_obj == NULL) {
769 fclose(fp);
774 fclose(fp);
770 goto bail;
775 goto bail;
771 }
776 }
772
777
773 PyFile_SetBufSize(file_obj, bufsize);
778 PyFile_SetBufSize(file_obj, bufsize);
774 #else
779 #else
775 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
780 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
776 if (file_obj == NULL)
781 if (file_obj == NULL)
777 goto bail;
782 goto bail;
778 #endif
783 #endif
779 bail:
784 bail:
780 PyMem_Free(name);
785 PyMem_Free(name);
781 return file_obj;
786 return file_obj;
782 }
787 }
783 #endif
788 #endif
784
789
785 #ifdef __APPLE__
790 #ifdef __APPLE__
786 #include <ApplicationServices/ApplicationServices.h>
791 #include <ApplicationServices/ApplicationServices.h>
787
792
788 static PyObject *isgui(PyObject *self)
793 static PyObject *isgui(PyObject *self)
789 {
794 {
790 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
795 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
791
796
792 if (dict != NULL) {
797 if (dict != NULL) {
793 CFRelease(dict);
798 CFRelease(dict);
794 Py_RETURN_TRUE;
799 Py_RETURN_TRUE;
795 } else {
800 } else {
796 Py_RETURN_FALSE;
801 Py_RETURN_FALSE;
797 }
802 }
798 }
803 }
799 #endif
804 #endif
800
805
801 static char osutil_doc[] = "Native operating system services.";
806 static char osutil_doc[] = "Native operating system services.";
802
807
803 static PyMethodDef methods[] = {
808 static PyMethodDef methods[] = {
804 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
809 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
805 "list a directory\n"},
810 "list a directory\n"},
806 #ifdef _WIN32
811 #ifdef _WIN32
807 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
812 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
808 "Open a file with POSIX-like semantics.\n"
813 "Open a file with POSIX-like semantics.\n"
809 "On error, this function may raise either a WindowsError or an IOError."},
814 "On error, this function may raise either a WindowsError or an IOError."},
810 #else
815 #else
811 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
816 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
812 "stat a series of files or symlinks\n"
817 "stat a series of files or symlinks\n"
813 "Returns None for non-existent entries and entries of other types.\n"},
818 "Returns None for non-existent entries and entries of other types.\n"},
814 #endif
819 #endif
815 #ifdef __APPLE__
820 #ifdef __APPLE__
816 {
821 {
817 "isgui", (PyCFunction)isgui, METH_NOARGS,
822 "isgui", (PyCFunction)isgui, METH_NOARGS,
818 "Is a CoreGraphics session available?"
823 "Is a CoreGraphics session available?"
819 },
824 },
820 #endif
825 #endif
821 {NULL, NULL}
826 {NULL, NULL}
822 };
827 };
823
828
824 #ifdef IS_PY3K
829 #ifdef IS_PY3K
825 static struct PyModuleDef osutil_module = {
830 static struct PyModuleDef osutil_module = {
826 PyModuleDef_HEAD_INIT,
831 PyModuleDef_HEAD_INIT,
827 "osutil",
832 "osutil",
828 osutil_doc,
833 osutil_doc,
829 -1,
834 -1,
830 methods
835 methods
831 };
836 };
832
837
833 PyMODINIT_FUNC PyInit_osutil(void)
838 PyMODINIT_FUNC PyInit_osutil(void)
834 {
839 {
835 if (PyType_Ready(&listdir_stat_type) < 0)
840 if (PyType_Ready(&listdir_stat_type) < 0)
836 return NULL;
841 return NULL;
837
842
838 return PyModule_Create(&osutil_module);
843 return PyModule_Create(&osutil_module);
839 }
844 }
840 #else
845 #else
841 PyMODINIT_FUNC initosutil(void)
846 PyMODINIT_FUNC initosutil(void)
842 {
847 {
843 if (PyType_Ready(&listdir_stat_type) == -1)
848 if (PyType_Ready(&listdir_stat_type) == -1)
844 return;
849 return;
845
850
846 Py_InitModule3("osutil", methods, osutil_doc);
851 Py_InitModule3("osutil", methods, osutil_doc);
847 }
852 }
848 #endif
853 #endif
General Comments 0
You need to be logged in to leave comments. Login now