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