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