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