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