##// END OF EJS Templates
osutil: implement setprocname to set process title for some platforms...
Jun Wu -
r30409:08521615 default
parent child Browse files
Show More
@@ -1,936 +1,997 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 = malloc(plen + 3); /* path + \* + \0 */
209 pattern = 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 free(pattern);
272 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 error_dir:
403 error_dir:
404 #ifdef AT_SYMLINK_NOFOLLOW
404 #ifdef AT_SYMLINK_NOFOLLOW
405 close(dfd);
405 close(dfd);
406 #endif
406 #endif
407 error_value:
407 error_value:
408 return ret;
408 return ret;
409 }
409 }
410
410
411 #ifdef __APPLE__
411 #ifdef __APPLE__
412
412
413 typedef struct {
413 typedef struct {
414 u_int32_t length;
414 u_int32_t length;
415 attrreference_t name;
415 attrreference_t name;
416 fsobj_type_t obj_type;
416 fsobj_type_t obj_type;
417 struct timespec mtime;
417 struct timespec mtime;
418 #if __LITTLE_ENDIAN__
418 #if __LITTLE_ENDIAN__
419 mode_t access_mask;
419 mode_t access_mask;
420 uint16_t padding;
420 uint16_t padding;
421 #else
421 #else
422 uint16_t padding;
422 uint16_t padding;
423 mode_t access_mask;
423 mode_t access_mask;
424 #endif
424 #endif
425 off_t size;
425 off_t size;
426 } __attribute__((packed)) attrbuf_entry;
426 } __attribute__((packed)) attrbuf_entry;
427
427
428 int attrkind(attrbuf_entry *entry)
428 int attrkind(attrbuf_entry *entry)
429 {
429 {
430 switch (entry->obj_type) {
430 switch (entry->obj_type) {
431 case VREG: return S_IFREG;
431 case VREG: return S_IFREG;
432 case VDIR: return S_IFDIR;
432 case VDIR: return S_IFDIR;
433 case VLNK: return S_IFLNK;
433 case VLNK: return S_IFLNK;
434 case VBLK: return S_IFBLK;
434 case VBLK: return S_IFBLK;
435 case VCHR: return S_IFCHR;
435 case VCHR: return S_IFCHR;
436 case VFIFO: return S_IFIFO;
436 case VFIFO: return S_IFIFO;
437 case VSOCK: return S_IFSOCK;
437 case VSOCK: return S_IFSOCK;
438 }
438 }
439 return -1;
439 return -1;
440 }
440 }
441
441
442 /* get these many entries at a time */
442 /* get these many entries at a time */
443 #define LISTDIR_BATCH_SIZE 50
443 #define LISTDIR_BATCH_SIZE 50
444
444
445 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
445 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
446 char *skip, bool *fallback)
446 char *skip, bool *fallback)
447 {
447 {
448 PyObject *list, *elem, *stat = NULL, *ret = NULL;
448 PyObject *list, *elem, *stat = NULL, *ret = NULL;
449 int kind, err;
449 int kind, err;
450 unsigned long index;
450 unsigned long index;
451 unsigned int count, old_state, new_state;
451 unsigned int count, old_state, new_state;
452 bool state_seen = false;
452 bool state_seen = false;
453 attrbuf_entry *entry;
453 attrbuf_entry *entry;
454 /* from the getattrlist(2) man page: a path can be no longer than
454 /* from the getattrlist(2) man page: a path can be no longer than
455 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
455 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
456 silently truncate attribute data if attrBufSize is too small." So
456 silently truncate attribute data if attrBufSize is too small." So
457 pass in a buffer big enough for the worst case. */
457 pass in a buffer big enough for the worst case. */
458 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
458 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
459 unsigned int basep_unused;
459 unsigned int basep_unused;
460
460
461 struct stat st;
461 struct stat st;
462 int dfd = -1;
462 int dfd = -1;
463
463
464 /* these must match the attrbuf_entry struct, otherwise you'll end up
464 /* these must match the attrbuf_entry struct, otherwise you'll end up
465 with garbage */
465 with garbage */
466 struct attrlist requested_attr = {0};
466 struct attrlist requested_attr = {0};
467 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
467 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
468 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
468 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
469 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
469 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
470 requested_attr.fileattr = ATTR_FILE_DATALENGTH;
470 requested_attr.fileattr = ATTR_FILE_DATALENGTH;
471
471
472 *fallback = false;
472 *fallback = false;
473
473
474 if (pathlen >= PATH_MAX) {
474 if (pathlen >= PATH_MAX) {
475 errno = ENAMETOOLONG;
475 errno = ENAMETOOLONG;
476 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
476 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
477 goto error_value;
477 goto error_value;
478 }
478 }
479
479
480 dfd = open(path, O_RDONLY);
480 dfd = open(path, O_RDONLY);
481 if (dfd == -1) {
481 if (dfd == -1) {
482 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
482 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
483 goto error_value;
483 goto error_value;
484 }
484 }
485
485
486 list = PyList_New(0);
486 list = PyList_New(0);
487 if (!list)
487 if (!list)
488 goto error_dir;
488 goto error_dir;
489
489
490 do {
490 do {
491 count = LISTDIR_BATCH_SIZE;
491 count = LISTDIR_BATCH_SIZE;
492 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
492 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
493 sizeof(attrbuf), &count, &basep_unused,
493 sizeof(attrbuf), &count, &basep_unused,
494 &new_state, 0);
494 &new_state, 0);
495 if (err < 0) {
495 if (err < 0) {
496 if (errno == ENOTSUP) {
496 if (errno == ENOTSUP) {
497 /* We're on a filesystem that doesn't support
497 /* We're on a filesystem that doesn't support
498 getdirentriesattr. Fall back to the
498 getdirentriesattr. Fall back to the
499 stat-based implementation. */
499 stat-based implementation. */
500 *fallback = true;
500 *fallback = true;
501 } else
501 } else
502 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
502 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
503 goto error;
503 goto error;
504 }
504 }
505
505
506 if (!state_seen) {
506 if (!state_seen) {
507 old_state = new_state;
507 old_state = new_state;
508 state_seen = true;
508 state_seen = true;
509 } else if (old_state != new_state) {
509 } else if (old_state != new_state) {
510 /* There's an edge case with getdirentriesattr. Consider
510 /* There's an edge case with getdirentriesattr. Consider
511 the following initial list of files:
511 the following initial list of files:
512
512
513 a
513 a
514 b
514 b
515 <--
515 <--
516 c
516 c
517 d
517 d
518
518
519 If the iteration is paused at the arrow, and b is
519 If the iteration is paused at the arrow, and b is
520 deleted before it is resumed, getdirentriesattr will
520 deleted before it is resumed, getdirentriesattr will
521 not return d at all! Ordinarily we're expected to
521 not return d at all! Ordinarily we're expected to
522 restart the iteration from the beginning. To avoid
522 restart the iteration from the beginning. To avoid
523 getting stuck in a retry loop here, fall back to
523 getting stuck in a retry loop here, fall back to
524 stat. */
524 stat. */
525 *fallback = true;
525 *fallback = true;
526 goto error;
526 goto error;
527 }
527 }
528
528
529 entry = (attrbuf_entry *)attrbuf;
529 entry = (attrbuf_entry *)attrbuf;
530
530
531 for (index = 0; index < count; index++) {
531 for (index = 0; index < count; index++) {
532 char *filename = ((char *)&entry->name) +
532 char *filename = ((char *)&entry->name) +
533 entry->name.attr_dataoffset;
533 entry->name.attr_dataoffset;
534
534
535 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
535 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
536 continue;
536 continue;
537
537
538 kind = attrkind(entry);
538 kind = attrkind(entry);
539 if (kind == -1) {
539 if (kind == -1) {
540 PyErr_Format(PyExc_OSError,
540 PyErr_Format(PyExc_OSError,
541 "unknown object type %u for file "
541 "unknown object type %u for file "
542 "%s%s!",
542 "%s%s!",
543 entry->obj_type, path, filename);
543 entry->obj_type, path, filename);
544 goto error;
544 goto error;
545 }
545 }
546
546
547 /* quit early? */
547 /* quit early? */
548 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
548 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
549 ret = PyList_New(0);
549 ret = PyList_New(0);
550 goto error;
550 goto error;
551 }
551 }
552
552
553 if (keepstat) {
553 if (keepstat) {
554 /* from the getattrlist(2) man page: "Only the
554 /* from the getattrlist(2) man page: "Only the
555 permission bits ... are valid". */
555 permission bits ... are valid". */
556 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
556 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
557 st.st_mtime = entry->mtime.tv_sec;
557 st.st_mtime = entry->mtime.tv_sec;
558 st.st_size = entry->size;
558 st.st_size = entry->size;
559 stat = makestat(&st);
559 stat = makestat(&st);
560 if (!stat)
560 if (!stat)
561 goto error;
561 goto error;
562 elem = Py_BuildValue("siN", filename, kind, stat);
562 elem = Py_BuildValue("siN", filename, kind, stat);
563 } else
563 } else
564 elem = Py_BuildValue("si", filename, kind);
564 elem = Py_BuildValue("si", filename, kind);
565 if (!elem)
565 if (!elem)
566 goto error;
566 goto error;
567 stat = NULL;
567 stat = NULL;
568
568
569 PyList_Append(list, elem);
569 PyList_Append(list, elem);
570 Py_DECREF(elem);
570 Py_DECREF(elem);
571
571
572 entry = (attrbuf_entry *)((char *)entry + entry->length);
572 entry = (attrbuf_entry *)((char *)entry + entry->length);
573 }
573 }
574 } while (err == 0);
574 } while (err == 0);
575
575
576 ret = list;
576 ret = list;
577 Py_INCREF(ret);
577 Py_INCREF(ret);
578
578
579 error:
579 error:
580 Py_DECREF(list);
580 Py_DECREF(list);
581 Py_XDECREF(stat);
581 Py_XDECREF(stat);
582 error_dir:
582 error_dir:
583 close(dfd);
583 close(dfd);
584 error_value:
584 error_value:
585 return ret;
585 return ret;
586 }
586 }
587
587
588 #endif /* __APPLE__ */
588 #endif /* __APPLE__ */
589
589
590 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
590 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
591 {
591 {
592 #ifdef __APPLE__
592 #ifdef __APPLE__
593 PyObject *ret;
593 PyObject *ret;
594 bool fallback = false;
594 bool fallback = false;
595
595
596 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
596 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
597 if (ret != NULL || !fallback)
597 if (ret != NULL || !fallback)
598 return ret;
598 return ret;
599 #endif
599 #endif
600 return _listdir_stat(path, pathlen, keepstat, skip);
600 return _listdir_stat(path, pathlen, keepstat, skip);
601 }
601 }
602
602
603 static PyObject *statfiles(PyObject *self, PyObject *args)
603 static PyObject *statfiles(PyObject *self, PyObject *args)
604 {
604 {
605 PyObject *names, *stats;
605 PyObject *names, *stats;
606 Py_ssize_t i, count;
606 Py_ssize_t i, count;
607
607
608 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
608 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
609 return NULL;
609 return NULL;
610
610
611 count = PySequence_Length(names);
611 count = PySequence_Length(names);
612 if (count == -1) {
612 if (count == -1) {
613 PyErr_SetString(PyExc_TypeError, "not a sequence");
613 PyErr_SetString(PyExc_TypeError, "not a sequence");
614 return NULL;
614 return NULL;
615 }
615 }
616
616
617 stats = PyList_New(count);
617 stats = PyList_New(count);
618 if (stats == NULL)
618 if (stats == NULL)
619 return NULL;
619 return NULL;
620
620
621 for (i = 0; i < count; i++) {
621 for (i = 0; i < count; i++) {
622 PyObject *stat, *pypath;
622 PyObject *stat, *pypath;
623 struct stat st;
623 struct stat st;
624 int ret, kind;
624 int ret, kind;
625 char *path;
625 char *path;
626
626
627 /* With a large file count or on a slow filesystem,
627 /* With a large file count or on a slow filesystem,
628 don't block signals for long (issue4878). */
628 don't block signals for long (issue4878). */
629 if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
629 if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
630 goto bail;
630 goto bail;
631
631
632 pypath = PySequence_GetItem(names, i);
632 pypath = PySequence_GetItem(names, i);
633 if (!pypath)
633 if (!pypath)
634 goto bail;
634 goto bail;
635 path = PyBytes_AsString(pypath);
635 path = PyBytes_AsString(pypath);
636 if (path == NULL) {
636 if (path == NULL) {
637 Py_DECREF(pypath);
637 Py_DECREF(pypath);
638 PyErr_SetString(PyExc_TypeError, "not a string");
638 PyErr_SetString(PyExc_TypeError, "not a string");
639 goto bail;
639 goto bail;
640 }
640 }
641 ret = lstat(path, &st);
641 ret = lstat(path, &st);
642 Py_DECREF(pypath);
642 Py_DECREF(pypath);
643 kind = st.st_mode & S_IFMT;
643 kind = st.st_mode & S_IFMT;
644 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
644 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
645 stat = makestat(&st);
645 stat = makestat(&st);
646 if (stat == NULL)
646 if (stat == NULL)
647 goto bail;
647 goto bail;
648 PyList_SET_ITEM(stats, i, stat);
648 PyList_SET_ITEM(stats, i, stat);
649 } else {
649 } else {
650 Py_INCREF(Py_None);
650 Py_INCREF(Py_None);
651 PyList_SET_ITEM(stats, i, Py_None);
651 PyList_SET_ITEM(stats, i, Py_None);
652 }
652 }
653 }
653 }
654
654
655 return stats;
655 return stats;
656
656
657 bail:
657 bail:
658 Py_DECREF(stats);
658 Py_DECREF(stats);
659 return NULL;
659 return NULL;
660 }
660 }
661
661
662 /*
662 /*
663 * recvfds() simply does not release GIL during blocking io operation because
663 * recvfds() simply does not release GIL during blocking io operation because
664 * command server is known to be single-threaded.
664 * command server is known to be single-threaded.
665 *
665 *
666 * Old systems such as Solaris don't provide CMSG_LEN, msg_control, etc.
666 * Old systems such as Solaris don't provide CMSG_LEN, msg_control, etc.
667 * Currently, recvfds() is not supported on these platforms.
667 * Currently, recvfds() is not supported on these platforms.
668 */
668 */
669 #ifdef CMSG_LEN
669 #ifdef CMSG_LEN
670
670
671 static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize)
671 static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize)
672 {
672 {
673 char dummy[1];
673 char dummy[1];
674 struct iovec iov = {dummy, sizeof(dummy)};
674 struct iovec iov = {dummy, sizeof(dummy)};
675 struct msghdr msgh = {0};
675 struct msghdr msgh = {0};
676 struct cmsghdr *cmsg;
676 struct cmsghdr *cmsg;
677
677
678 msgh.msg_iov = &iov;
678 msgh.msg_iov = &iov;
679 msgh.msg_iovlen = 1;
679 msgh.msg_iovlen = 1;
680 msgh.msg_control = cbuf;
680 msgh.msg_control = cbuf;
681 msgh.msg_controllen = (socklen_t)cbufsize;
681 msgh.msg_controllen = (socklen_t)cbufsize;
682 if (recvmsg(sockfd, &msgh, 0) < 0)
682 if (recvmsg(sockfd, &msgh, 0) < 0)
683 return -1;
683 return -1;
684
684
685 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
685 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
686 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
686 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
687 if (cmsg->cmsg_level != SOL_SOCKET ||
687 if (cmsg->cmsg_level != SOL_SOCKET ||
688 cmsg->cmsg_type != SCM_RIGHTS)
688 cmsg->cmsg_type != SCM_RIGHTS)
689 continue;
689 continue;
690 *rfds = (int *)CMSG_DATA(cmsg);
690 *rfds = (int *)CMSG_DATA(cmsg);
691 return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
691 return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
692 }
692 }
693
693
694 *rfds = cbuf;
694 *rfds = cbuf;
695 return 0;
695 return 0;
696 }
696 }
697
697
698 static PyObject *recvfds(PyObject *self, PyObject *args)
698 static PyObject *recvfds(PyObject *self, PyObject *args)
699 {
699 {
700 int sockfd;
700 int sockfd;
701 int *rfds = NULL;
701 int *rfds = NULL;
702 ssize_t rfdscount, i;
702 ssize_t rfdscount, i;
703 char cbuf[256];
703 char cbuf[256];
704 PyObject *rfdslist = NULL;
704 PyObject *rfdslist = NULL;
705
705
706 if (!PyArg_ParseTuple(args, "i", &sockfd))
706 if (!PyArg_ParseTuple(args, "i", &sockfd))
707 return NULL;
707 return NULL;
708
708
709 rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf));
709 rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf));
710 if (rfdscount < 0)
710 if (rfdscount < 0)
711 return PyErr_SetFromErrno(PyExc_OSError);
711 return PyErr_SetFromErrno(PyExc_OSError);
712
712
713 rfdslist = PyList_New(rfdscount);
713 rfdslist = PyList_New(rfdscount);
714 if (!rfdslist)
714 if (!rfdslist)
715 goto bail;
715 goto bail;
716 for (i = 0; i < rfdscount; i++) {
716 for (i = 0; i < rfdscount; i++) {
717 PyObject *obj = PyLong_FromLong(rfds[i]);
717 PyObject *obj = PyLong_FromLong(rfds[i]);
718 if (!obj)
718 if (!obj)
719 goto bail;
719 goto bail;
720 PyList_SET_ITEM(rfdslist, i, obj);
720 PyList_SET_ITEM(rfdslist, i, obj);
721 }
721 }
722 return rfdslist;
722 return rfdslist;
723
723
724 bail:
724 bail:
725 Py_XDECREF(rfdslist);
725 Py_XDECREF(rfdslist);
726 return NULL;
726 return NULL;
727 }
727 }
728
728
729 #endif /* CMSG_LEN */
729 #endif /* CMSG_LEN */
730
731 #if defined(HAVE_SETPROCTITLE)
732 /* setproctitle is the first choice - available in FreeBSD */
733 #define SETPROCNAME_USE_SETPROCTITLE
734 #elif (defined(__linux__) || defined(__APPLE__)) && PY_MAJOR_VERSION == 2
735 /* 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. */
737 #define SETPROCNAME_USE_ARGVREWRITE
738 #else
739 #define SETPROCNAME_USE_NONE
740 #endif
741
742 #ifndef SETPROCNAME_USE_NONE
743 static PyObject *setprocname(PyObject *self, PyObject *args)
744 {
745 const char *name = NULL;
746 if (!PyArg_ParseTuple(args, "s", &name))
747 return NULL;
748
749 #if defined(SETPROCNAME_USE_SETPROCTITLE)
750 setproctitle("%s", name);
751 #elif defined(SETPROCNAME_USE_ARGVREWRITE)
752 {
753 static char *argvstart = NULL;
754 static size_t argvsize = 0;
755 if (argvstart == NULL) {
756 int argc = 0, i;
757 char **argv = NULL;
758 char *argvend;
759 extern void Py_GetArgcArgv(int *argc, char ***argv);
760 Py_GetArgcArgv(&argc, &argv);
761
762 /* Check the memory we can use. Typically, argv[i] and
763 * argv[i + 1] are continuous. */
764 argvend = argvstart = argv[0];
765 for (i = 0; i < argc; ++i) {
766 if (argv[i] > argvend || argv[i] < argvstart)
767 break; /* not continuous */
768 size_t len = strlen(argv[i]);
769 argvend = argv[i] + len + 1 /* '\0' */;
770 }
771 if (argvend > argvstart) /* sanity check */
772 argvsize = argvend - argvstart;
773 }
774
775 if (argvstart && argvsize > 1) {
776 int n = snprintf(argvstart, argvsize, "%s", name);
777 if (n >= 0 && (size_t)n < argvsize)
778 memset(argvstart + n, 0, argvsize - n);
779 }
780 }
781 #endif
782
783 Py_RETURN_NONE;
784 }
785 #endif /* ndef SETPROCNAME_USE_NONE */
786
730 #endif /* ndef _WIN32 */
787 #endif /* ndef _WIN32 */
731
788
732 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
789 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
733 {
790 {
734 PyObject *statobj = NULL; /* initialize - optional arg */
791 PyObject *statobj = NULL; /* initialize - optional arg */
735 PyObject *skipobj = NULL; /* initialize - optional arg */
792 PyObject *skipobj = NULL; /* initialize - optional arg */
736 char *path, *skip = NULL;
793 char *path, *skip = NULL;
737 int wantstat, plen;
794 int wantstat, plen;
738
795
739 static char *kwlist[] = {"path", "stat", "skip", NULL};
796 static char *kwlist[] = {"path", "stat", "skip", NULL};
740
797
741 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
798 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
742 kwlist, &path, &plen, &statobj, &skipobj))
799 kwlist, &path, &plen, &statobj, &skipobj))
743 return NULL;
800 return NULL;
744
801
745 wantstat = statobj && PyObject_IsTrue(statobj);
802 wantstat = statobj && PyObject_IsTrue(statobj);
746
803
747 if (skipobj && skipobj != Py_None) {
804 if (skipobj && skipobj != Py_None) {
748 skip = PyBytes_AsString(skipobj);
805 skip = PyBytes_AsString(skipobj);
749 if (!skip)
806 if (!skip)
750 return NULL;
807 return NULL;
751 }
808 }
752
809
753 return _listdir(path, plen, wantstat, skip);
810 return _listdir(path, plen, wantstat, skip);
754 }
811 }
755
812
756 #ifdef _WIN32
813 #ifdef _WIN32
757 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
814 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
758 {
815 {
759 static char *kwlist[] = {"name", "mode", "buffering", NULL};
816 static char *kwlist[] = {"name", "mode", "buffering", NULL};
760 PyObject *file_obj = NULL;
817 PyObject *file_obj = NULL;
761 char *name = NULL;
818 char *name = NULL;
762 char *mode = "rb";
819 char *mode = "rb";
763 DWORD access = 0;
820 DWORD access = 0;
764 DWORD creation;
821 DWORD creation;
765 HANDLE handle;
822 HANDLE handle;
766 int fd, flags = 0;
823 int fd, flags = 0;
767 int bufsize = -1;
824 int bufsize = -1;
768 char m0, m1, m2;
825 char m0, m1, m2;
769 char fpmode[4];
826 char fpmode[4];
770 int fppos = 0;
827 int fppos = 0;
771 int plus;
828 int plus;
772 FILE *fp;
829 FILE *fp;
773
830
774 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
831 if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
775 Py_FileSystemDefaultEncoding,
832 Py_FileSystemDefaultEncoding,
776 &name, &mode, &bufsize))
833 &name, &mode, &bufsize))
777 return NULL;
834 return NULL;
778
835
779 m0 = mode[0];
836 m0 = mode[0];
780 m1 = m0 ? mode[1] : '\0';
837 m1 = m0 ? mode[1] : '\0';
781 m2 = m1 ? mode[2] : '\0';
838 m2 = m1 ? mode[2] : '\0';
782 plus = m1 == '+' || m2 == '+';
839 plus = m1 == '+' || m2 == '+';
783
840
784 fpmode[fppos++] = m0;
841 fpmode[fppos++] = m0;
785 if (m1 == 'b' || m2 == 'b') {
842 if (m1 == 'b' || m2 == 'b') {
786 flags = _O_BINARY;
843 flags = _O_BINARY;
787 fpmode[fppos++] = 'b';
844 fpmode[fppos++] = 'b';
788 }
845 }
789 else
846 else
790 flags = _O_TEXT;
847 flags = _O_TEXT;
791 if (m0 == 'r' && !plus) {
848 if (m0 == 'r' && !plus) {
792 flags |= _O_RDONLY;
849 flags |= _O_RDONLY;
793 access = GENERIC_READ;
850 access = GENERIC_READ;
794 } else {
851 } else {
795 /*
852 /*
796 work around http://support.microsoft.com/kb/899149 and
853 work around http://support.microsoft.com/kb/899149 and
797 set _O_RDWR for 'w' and 'a', even if mode has no '+'
854 set _O_RDWR for 'w' and 'a', even if mode has no '+'
798 */
855 */
799 flags |= _O_RDWR;
856 flags |= _O_RDWR;
800 access = GENERIC_READ | GENERIC_WRITE;
857 access = GENERIC_READ | GENERIC_WRITE;
801 fpmode[fppos++] = '+';
858 fpmode[fppos++] = '+';
802 }
859 }
803 fpmode[fppos++] = '\0';
860 fpmode[fppos++] = '\0';
804
861
805 switch (m0) {
862 switch (m0) {
806 case 'r':
863 case 'r':
807 creation = OPEN_EXISTING;
864 creation = OPEN_EXISTING;
808 break;
865 break;
809 case 'w':
866 case 'w':
810 creation = CREATE_ALWAYS;
867 creation = CREATE_ALWAYS;
811 break;
868 break;
812 case 'a':
869 case 'a':
813 creation = OPEN_ALWAYS;
870 creation = OPEN_ALWAYS;
814 flags |= _O_APPEND;
871 flags |= _O_APPEND;
815 break;
872 break;
816 default:
873 default:
817 PyErr_Format(PyExc_ValueError,
874 PyErr_Format(PyExc_ValueError,
818 "mode string must begin with one of 'r', 'w', "
875 "mode string must begin with one of 'r', 'w', "
819 "or 'a', not '%c'", m0);
876 "or 'a', not '%c'", m0);
820 goto bail;
877 goto bail;
821 }
878 }
822
879
823 handle = CreateFile(name, access,
880 handle = CreateFile(name, access,
824 FILE_SHARE_READ | FILE_SHARE_WRITE |
881 FILE_SHARE_READ | FILE_SHARE_WRITE |
825 FILE_SHARE_DELETE,
882 FILE_SHARE_DELETE,
826 NULL,
883 NULL,
827 creation,
884 creation,
828 FILE_ATTRIBUTE_NORMAL,
885 FILE_ATTRIBUTE_NORMAL,
829 0);
886 0);
830
887
831 if (handle == INVALID_HANDLE_VALUE) {
888 if (handle == INVALID_HANDLE_VALUE) {
832 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
889 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
833 goto bail;
890 goto bail;
834 }
891 }
835
892
836 fd = _open_osfhandle((intptr_t)handle, flags);
893 fd = _open_osfhandle((intptr_t)handle, flags);
837
894
838 if (fd == -1) {
895 if (fd == -1) {
839 CloseHandle(handle);
896 CloseHandle(handle);
840 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
897 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
841 goto bail;
898 goto bail;
842 }
899 }
843 #ifndef IS_PY3K
900 #ifndef IS_PY3K
844 fp = _fdopen(fd, fpmode);
901 fp = _fdopen(fd, fpmode);
845 if (fp == NULL) {
902 if (fp == NULL) {
846 _close(fd);
903 _close(fd);
847 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
904 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
848 goto bail;
905 goto bail;
849 }
906 }
850
907
851 file_obj = PyFile_FromFile(fp, name, mode, fclose);
908 file_obj = PyFile_FromFile(fp, name, mode, fclose);
852 if (file_obj == NULL) {
909 if (file_obj == NULL) {
853 fclose(fp);
910 fclose(fp);
854 goto bail;
911 goto bail;
855 }
912 }
856
913
857 PyFile_SetBufSize(file_obj, bufsize);
914 PyFile_SetBufSize(file_obj, bufsize);
858 #else
915 #else
859 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
916 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
860 if (file_obj == NULL)
917 if (file_obj == NULL)
861 goto bail;
918 goto bail;
862 #endif
919 #endif
863 bail:
920 bail:
864 PyMem_Free(name);
921 PyMem_Free(name);
865 return file_obj;
922 return file_obj;
866 }
923 }
867 #endif
924 #endif
868
925
869 #ifdef __APPLE__
926 #ifdef __APPLE__
870 #include <ApplicationServices/ApplicationServices.h>
927 #include <ApplicationServices/ApplicationServices.h>
871
928
872 static PyObject *isgui(PyObject *self)
929 static PyObject *isgui(PyObject *self)
873 {
930 {
874 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
931 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
875
932
876 if (dict != NULL) {
933 if (dict != NULL) {
877 CFRelease(dict);
934 CFRelease(dict);
878 Py_RETURN_TRUE;
935 Py_RETURN_TRUE;
879 } else {
936 } else {
880 Py_RETURN_FALSE;
937 Py_RETURN_FALSE;
881 }
938 }
882 }
939 }
883 #endif
940 #endif
884
941
885 static char osutil_doc[] = "Native operating system services.";
942 static char osutil_doc[] = "Native operating system services.";
886
943
887 static PyMethodDef methods[] = {
944 static PyMethodDef methods[] = {
888 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
945 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
889 "list a directory\n"},
946 "list a directory\n"},
890 #ifdef _WIN32
947 #ifdef _WIN32
891 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
948 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
892 "Open a file with POSIX-like semantics.\n"
949 "Open a file with POSIX-like semantics.\n"
893 "On error, this function may raise either a WindowsError or an IOError."},
950 "On error, this function may raise either a WindowsError or an IOError."},
894 #else
951 #else
895 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
952 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
896 "stat a series of files or symlinks\n"
953 "stat a series of files or symlinks\n"
897 "Returns None for non-existent entries and entries of other types.\n"},
954 "Returns None for non-existent entries and entries of other types.\n"},
898 #ifdef CMSG_LEN
955 #ifdef CMSG_LEN
899 {"recvfds", (PyCFunction)recvfds, METH_VARARGS,
956 {"recvfds", (PyCFunction)recvfds, METH_VARARGS,
900 "receive list of file descriptors via socket\n"},
957 "receive list of file descriptors via socket\n"},
901 #endif
958 #endif
959 #ifndef SETPROCNAME_USE_NONE
960 {"setprocname", (PyCFunction)setprocname, METH_VARARGS,
961 "set process title (best-effort)\n"},
902 #endif
962 #endif
963 #endif /* ndef _WIN32 */
903 #ifdef __APPLE__
964 #ifdef __APPLE__
904 {
965 {
905 "isgui", (PyCFunction)isgui, METH_NOARGS,
966 "isgui", (PyCFunction)isgui, METH_NOARGS,
906 "Is a CoreGraphics session available?"
967 "Is a CoreGraphics session available?"
907 },
968 },
908 #endif
969 #endif
909 {NULL, NULL}
970 {NULL, NULL}
910 };
971 };
911
972
912 #ifdef IS_PY3K
973 #ifdef IS_PY3K
913 static struct PyModuleDef osutil_module = {
974 static struct PyModuleDef osutil_module = {
914 PyModuleDef_HEAD_INIT,
975 PyModuleDef_HEAD_INIT,
915 "osutil",
976 "osutil",
916 osutil_doc,
977 osutil_doc,
917 -1,
978 -1,
918 methods
979 methods
919 };
980 };
920
981
921 PyMODINIT_FUNC PyInit_osutil(void)
982 PyMODINIT_FUNC PyInit_osutil(void)
922 {
983 {
923 if (PyType_Ready(&listdir_stat_type) < 0)
984 if (PyType_Ready(&listdir_stat_type) < 0)
924 return NULL;
985 return NULL;
925
986
926 return PyModule_Create(&osutil_module);
987 return PyModule_Create(&osutil_module);
927 }
988 }
928 #else
989 #else
929 PyMODINIT_FUNC initosutil(void)
990 PyMODINIT_FUNC initosutil(void)
930 {
991 {
931 if (PyType_Ready(&listdir_stat_type) == -1)
992 if (PyType_Ready(&listdir_stat_type) == -1)
932 return;
993 return;
933
994
934 Py_InitModule3("osutil", methods, osutil_doc);
995 Py_InitModule3("osutil", methods, osutil_doc);
935 }
996 }
936 #endif
997 #endif
General Comments 0
You need to be logged in to leave comments. Login now