##// END OF EJS Templates
cext: remove Python 2 file handling code...
Gregory Szorc -
r49670:e9ca736f default
parent child Browse files
Show More
@@ -1,1399 +1,1391 b''
1 /*
1 /*
2 osutil.c - native operating system services
2 osutil.c - native operating system services
3
3
4 Copyright 2007 Olivia Mackall and others
4 Copyright 2007 Olivia 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 #define PY_SSIZE_T_CLEAN
11 #define PY_SSIZE_T_CLEAN
12 #include <Python.h>
12 #include <Python.h>
13 #include <errno.h>
13 #include <errno.h>
14 #include <fcntl.h>
14 #include <fcntl.h>
15 #include <stdio.h>
15 #include <stdio.h>
16 #include <stdlib.h>
16 #include <stdlib.h>
17 #include <string.h>
17 #include <string.h>
18
18
19 #ifdef _WIN32
19 #ifdef _WIN32
20 #include <io.h>
20 #include <io.h>
21 #include <windows.h>
21 #include <windows.h>
22 #else
22 #else
23 #include <dirent.h>
23 #include <dirent.h>
24 #include <signal.h>
24 #include <signal.h>
25 #include <sys/socket.h>
25 #include <sys/socket.h>
26 #include <sys/stat.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
27 #include <sys/types.h>
28 #include <unistd.h>
28 #include <unistd.h>
29 #ifdef HAVE_LINUX_STATFS
29 #ifdef HAVE_LINUX_STATFS
30 #include <linux/magic.h>
30 #include <linux/magic.h>
31 #include <sys/vfs.h>
31 #include <sys/vfs.h>
32 #endif
32 #endif
33 #ifdef HAVE_BSD_STATFS
33 #ifdef HAVE_BSD_STATFS
34 #include <sys/mount.h>
34 #include <sys/mount.h>
35 #include <sys/param.h>
35 #include <sys/param.h>
36 #endif
36 #endif
37 #endif
37 #endif
38
38
39 #ifdef __APPLE__
39 #ifdef __APPLE__
40 #include <sys/attr.h>
40 #include <sys/attr.h>
41 #include <sys/vnode.h>
41 #include <sys/vnode.h>
42 #endif
42 #endif
43
43
44 #include "util.h"
44 #include "util.h"
45
45
46 /* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
46 /* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
47 #ifndef PATH_MAX
47 #ifndef PATH_MAX
48 #define PATH_MAX 4096
48 #define PATH_MAX 4096
49 #endif
49 #endif
50
50
51 #ifdef _WIN32
51 #ifdef _WIN32
52 /*
52 /*
53 stat struct compatible with hg expectations
53 stat struct compatible with hg expectations
54 Mercurial only uses st_mode, st_size and st_mtime
54 Mercurial only uses st_mode, st_size and st_mtime
55 the rest is kept to minimize changes between implementations
55 the rest is kept to minimize changes between implementations
56 */
56 */
57 struct hg_stat {
57 struct hg_stat {
58 int st_dev;
58 int st_dev;
59 int st_mode;
59 int st_mode;
60 int st_nlink;
60 int st_nlink;
61 __int64 st_size;
61 __int64 st_size;
62 int st_mtime;
62 int st_mtime;
63 int st_ctime;
63 int st_ctime;
64 };
64 };
65 struct listdir_stat {
65 struct listdir_stat {
66 PyObject_HEAD
66 PyObject_HEAD
67 struct hg_stat st;
67 struct hg_stat st;
68 };
68 };
69 #else
69 #else
70 struct listdir_stat {
70 struct listdir_stat {
71 PyObject_HEAD
71 PyObject_HEAD
72 struct stat st;
72 struct stat st;
73 };
73 };
74 #endif
74 #endif
75
75
76 #define listdir_slot(name) \
76 #define listdir_slot(name) \
77 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
77 static PyObject *listdir_stat_##name(PyObject *self, void *x) \
78 { \
78 { \
79 return PyLong_FromLong(((struct listdir_stat *)self)->st.name); \
79 return PyLong_FromLong(((struct listdir_stat *)self)->st.name); \
80 }
80 }
81
81
82 listdir_slot(st_dev)
82 listdir_slot(st_dev)
83 listdir_slot(st_mode)
83 listdir_slot(st_mode)
84 listdir_slot(st_nlink)
84 listdir_slot(st_nlink)
85 #ifdef _WIN32
85 #ifdef _WIN32
86 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
86 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
87 {
87 {
88 return PyLong_FromLongLong(
88 return PyLong_FromLongLong(
89 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
89 (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
90 }
90 }
91 #else
91 #else
92 listdir_slot(st_size)
92 listdir_slot(st_size)
93 #endif
93 #endif
94 listdir_slot(st_mtime)
94 listdir_slot(st_mtime)
95 listdir_slot(st_ctime)
95 listdir_slot(st_ctime)
96
96
97 static struct PyGetSetDef listdir_stat_getsets[] = {
97 static struct PyGetSetDef listdir_stat_getsets[] = {
98 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
98 {"st_dev", listdir_stat_st_dev, 0, 0, 0},
99 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
99 {"st_mode", listdir_stat_st_mode, 0, 0, 0},
100 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
100 {"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
101 {"st_size", listdir_stat_st_size, 0, 0, 0},
101 {"st_size", listdir_stat_st_size, 0, 0, 0},
102 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
102 {"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
103 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
103 {"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
104 {0, 0, 0, 0, 0}
104 {0, 0, 0, 0, 0}
105 };
105 };
106
106
107 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
107 static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
108 {
108 {
109 return t->tp_alloc(t, 0);
109 return t->tp_alloc(t, 0);
110 }
110 }
111
111
112 static void listdir_stat_dealloc(PyObject *o)
112 static void listdir_stat_dealloc(PyObject *o)
113 {
113 {
114 Py_TYPE(o)->tp_free(o);
114 Py_TYPE(o)->tp_free(o);
115 }
115 }
116
116
117 static PyObject *listdir_stat_getitem(PyObject *self, PyObject *key)
117 static PyObject *listdir_stat_getitem(PyObject *self, PyObject *key)
118 {
118 {
119 long index = PyLong_AsLong(key);
119 long index = PyLong_AsLong(key);
120 if (index == -1 && PyErr_Occurred()) {
120 if (index == -1 && PyErr_Occurred()) {
121 return NULL;
121 return NULL;
122 }
122 }
123 if (index != 8) {
123 if (index != 8) {
124 PyErr_Format(PyExc_IndexError, "osutil.stat objects only "
124 PyErr_Format(PyExc_IndexError, "osutil.stat objects only "
125 "support stat.ST_MTIME in "
125 "support stat.ST_MTIME in "
126 "__getitem__");
126 "__getitem__");
127 return NULL;
127 return NULL;
128 }
128 }
129 return listdir_stat_st_mtime(self, NULL);
129 return listdir_stat_st_mtime(self, NULL);
130 }
130 }
131
131
132 static PyMappingMethods listdir_stat_type_mapping_methods = {
132 static PyMappingMethods listdir_stat_type_mapping_methods = {
133 (lenfunc)NULL, /* mp_length */
133 (lenfunc)NULL, /* mp_length */
134 (binaryfunc)listdir_stat_getitem, /* mp_subscript */
134 (binaryfunc)listdir_stat_getitem, /* mp_subscript */
135 (objobjargproc)NULL, /* mp_ass_subscript */
135 (objobjargproc)NULL, /* mp_ass_subscript */
136 };
136 };
137
137
138 static PyTypeObject listdir_stat_type = {
138 static PyTypeObject listdir_stat_type = {
139 PyVarObject_HEAD_INIT(NULL, 0) /* header */
139 PyVarObject_HEAD_INIT(NULL, 0) /* header */
140 "osutil.stat", /*tp_name*/
140 "osutil.stat", /*tp_name*/
141 sizeof(struct listdir_stat), /*tp_basicsize*/
141 sizeof(struct listdir_stat), /*tp_basicsize*/
142 0, /*tp_itemsize*/
142 0, /*tp_itemsize*/
143 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
143 (destructor)listdir_stat_dealloc, /*tp_dealloc*/
144 0, /*tp_print*/
144 0, /*tp_print*/
145 0, /*tp_getattr*/
145 0, /*tp_getattr*/
146 0, /*tp_setattr*/
146 0, /*tp_setattr*/
147 0, /*tp_compare*/
147 0, /*tp_compare*/
148 0, /*tp_repr*/
148 0, /*tp_repr*/
149 0, /*tp_as_number*/
149 0, /*tp_as_number*/
150 0, /*tp_as_sequence*/
150 0, /*tp_as_sequence*/
151 &listdir_stat_type_mapping_methods, /*tp_as_mapping*/
151 &listdir_stat_type_mapping_methods, /*tp_as_mapping*/
152 0, /*tp_hash */
152 0, /*tp_hash */
153 0, /*tp_call*/
153 0, /*tp_call*/
154 0, /*tp_str*/
154 0, /*tp_str*/
155 0, /*tp_getattro*/
155 0, /*tp_getattro*/
156 0, /*tp_setattro*/
156 0, /*tp_setattro*/
157 0, /*tp_as_buffer*/
157 0, /*tp_as_buffer*/
158 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
158 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
159 "stat objects", /* tp_doc */
159 "stat objects", /* tp_doc */
160 0, /* tp_traverse */
160 0, /* tp_traverse */
161 0, /* tp_clear */
161 0, /* tp_clear */
162 0, /* tp_richcompare */
162 0, /* tp_richcompare */
163 0, /* tp_weaklistoffset */
163 0, /* tp_weaklistoffset */
164 0, /* tp_iter */
164 0, /* tp_iter */
165 0, /* tp_iternext */
165 0, /* tp_iternext */
166 0, /* tp_methods */
166 0, /* tp_methods */
167 0, /* tp_members */
167 0, /* tp_members */
168 listdir_stat_getsets, /* tp_getset */
168 listdir_stat_getsets, /* tp_getset */
169 0, /* tp_base */
169 0, /* tp_base */
170 0, /* tp_dict */
170 0, /* tp_dict */
171 0, /* tp_descr_get */
171 0, /* tp_descr_get */
172 0, /* tp_descr_set */
172 0, /* tp_descr_set */
173 0, /* tp_dictoffset */
173 0, /* tp_dictoffset */
174 0, /* tp_init */
174 0, /* tp_init */
175 0, /* tp_alloc */
175 0, /* tp_alloc */
176 listdir_stat_new, /* tp_new */
176 listdir_stat_new, /* tp_new */
177 };
177 };
178
178
179 #ifdef _WIN32
179 #ifdef _WIN32
180
180
181 static int to_python_time(const FILETIME *tm)
181 static int to_python_time(const FILETIME *tm)
182 {
182 {
183 /* number of seconds between epoch and January 1 1601 */
183 /* number of seconds between epoch and January 1 1601 */
184 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
184 const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
185 /* conversion factor from 100ns to 1s */
185 /* conversion factor from 100ns to 1s */
186 const __int64 a1 = 10000000;
186 const __int64 a1 = 10000000;
187 /* explicit (int) cast to suspend compiler warnings */
187 /* explicit (int) cast to suspend compiler warnings */
188 return (int)((((__int64)tm->dwHighDateTime << 32)
188 return (int)((((__int64)tm->dwHighDateTime << 32)
189 + tm->dwLowDateTime) / a1 - a0);
189 + tm->dwLowDateTime) / a1 - a0);
190 }
190 }
191
191
192 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
192 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
193 {
193 {
194 PyObject *py_st;
194 PyObject *py_st;
195 struct hg_stat *stp;
195 struct hg_stat *stp;
196
196
197 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
197 int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
198 ? _S_IFDIR : _S_IFREG;
198 ? _S_IFDIR : _S_IFREG;
199
199
200 if (!wantstat)
200 if (!wantstat)
201 return Py_BuildValue(PY23("si", "yi"), fd->cFileName, kind);
201 return Py_BuildValue(PY23("si", "yi"), fd->cFileName, kind);
202
202
203 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
203 py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
204 if (!py_st)
204 if (!py_st)
205 return NULL;
205 return NULL;
206
206
207 stp = &((struct listdir_stat *)py_st)->st;
207 stp = &((struct listdir_stat *)py_st)->st;
208 /*
208 /*
209 use kind as st_mode
209 use kind as st_mode
210 rwx bits on Win32 are meaningless
210 rwx bits on Win32 are meaningless
211 and Hg does not use them anyway
211 and Hg does not use them anyway
212 */
212 */
213 stp->st_mode = kind;
213 stp->st_mode = kind;
214 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
214 stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
215 stp->st_ctime = to_python_time(&fd->ftCreationTime);
215 stp->st_ctime = to_python_time(&fd->ftCreationTime);
216 if (kind == _S_IFREG)
216 if (kind == _S_IFREG)
217 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
217 stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
218 + fd->nFileSizeLow;
218 + fd->nFileSizeLow;
219 return Py_BuildValue(PY23("siN", "yiN"), fd->cFileName,
219 return Py_BuildValue(PY23("siN", "yiN"), fd->cFileName,
220 kind, py_st);
220 kind, py_st);
221 }
221 }
222
222
223 static PyObject *_listdir(char *path, Py_ssize_t plen, int wantstat, char *skip)
223 static PyObject *_listdir(char *path, Py_ssize_t plen, int wantstat, char *skip)
224 {
224 {
225 PyObject *rval = NULL; /* initialize - return value */
225 PyObject *rval = NULL; /* initialize - return value */
226 PyObject *list;
226 PyObject *list;
227 HANDLE fh;
227 HANDLE fh;
228 WIN32_FIND_DATAA fd;
228 WIN32_FIND_DATAA fd;
229 char *pattern;
229 char *pattern;
230
230
231 /* build the path + \* pattern string */
231 /* build the path + \* pattern string */
232 pattern = PyMem_Malloc(plen + 3); /* path + \* + \0 */
232 pattern = PyMem_Malloc(plen + 3); /* path + \* + \0 */
233 if (!pattern) {
233 if (!pattern) {
234 PyErr_NoMemory();
234 PyErr_NoMemory();
235 goto error_nomem;
235 goto error_nomem;
236 }
236 }
237 memcpy(pattern, path, plen);
237 memcpy(pattern, path, plen);
238
238
239 if (plen > 0) {
239 if (plen > 0) {
240 char c = path[plen-1];
240 char c = path[plen-1];
241 if (c != ':' && c != '/' && c != '\\')
241 if (c != ':' && c != '/' && c != '\\')
242 pattern[plen++] = '\\';
242 pattern[plen++] = '\\';
243 }
243 }
244 pattern[plen++] = '*';
244 pattern[plen++] = '*';
245 pattern[plen] = '\0';
245 pattern[plen] = '\0';
246
246
247 fh = FindFirstFileA(pattern, &fd);
247 fh = FindFirstFileA(pattern, &fd);
248 if (fh == INVALID_HANDLE_VALUE) {
248 if (fh == INVALID_HANDLE_VALUE) {
249 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
249 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
250 goto error_file;
250 goto error_file;
251 }
251 }
252
252
253 list = PyList_New(0);
253 list = PyList_New(0);
254 if (!list)
254 if (!list)
255 goto error_list;
255 goto error_list;
256
256
257 do {
257 do {
258 PyObject *item;
258 PyObject *item;
259
259
260 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
260 if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
261 if (!strcmp(fd.cFileName, ".")
261 if (!strcmp(fd.cFileName, ".")
262 || !strcmp(fd.cFileName, ".."))
262 || !strcmp(fd.cFileName, ".."))
263 continue;
263 continue;
264
264
265 if (skip && !strcmp(fd.cFileName, skip)) {
265 if (skip && !strcmp(fd.cFileName, skip)) {
266 rval = PyList_New(0);
266 rval = PyList_New(0);
267 goto error;
267 goto error;
268 }
268 }
269 }
269 }
270
270
271 item = make_item(&fd, wantstat);
271 item = make_item(&fd, wantstat);
272 if (!item)
272 if (!item)
273 goto error;
273 goto error;
274
274
275 if (PyList_Append(list, item)) {
275 if (PyList_Append(list, item)) {
276 Py_XDECREF(item);
276 Py_XDECREF(item);
277 goto error;
277 goto error;
278 }
278 }
279
279
280 Py_XDECREF(item);
280 Py_XDECREF(item);
281 } while (FindNextFileA(fh, &fd));
281 } while (FindNextFileA(fh, &fd));
282
282
283 if (GetLastError() != ERROR_NO_MORE_FILES) {
283 if (GetLastError() != ERROR_NO_MORE_FILES) {
284 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
284 PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
285 goto error;
285 goto error;
286 }
286 }
287
287
288 rval = list;
288 rval = list;
289 Py_XINCREF(rval);
289 Py_XINCREF(rval);
290 error:
290 error:
291 Py_XDECREF(list);
291 Py_XDECREF(list);
292 error_list:
292 error_list:
293 FindClose(fh);
293 FindClose(fh);
294 error_file:
294 error_file:
295 PyMem_Free(pattern);
295 PyMem_Free(pattern);
296 error_nomem:
296 error_nomem:
297 return rval;
297 return rval;
298 }
298 }
299
299
300 #else
300 #else
301
301
302 int entkind(struct dirent *ent)
302 int entkind(struct dirent *ent)
303 {
303 {
304 #ifdef DT_REG
304 #ifdef DT_REG
305 switch (ent->d_type) {
305 switch (ent->d_type) {
306 case DT_REG: return S_IFREG;
306 case DT_REG: return S_IFREG;
307 case DT_DIR: return S_IFDIR;
307 case DT_DIR: return S_IFDIR;
308 case DT_LNK: return S_IFLNK;
308 case DT_LNK: return S_IFLNK;
309 case DT_BLK: return S_IFBLK;
309 case DT_BLK: return S_IFBLK;
310 case DT_CHR: return S_IFCHR;
310 case DT_CHR: return S_IFCHR;
311 case DT_FIFO: return S_IFIFO;
311 case DT_FIFO: return S_IFIFO;
312 case DT_SOCK: return S_IFSOCK;
312 case DT_SOCK: return S_IFSOCK;
313 }
313 }
314 #endif
314 #endif
315 return -1;
315 return -1;
316 }
316 }
317
317
318 static PyObject *makestat(const struct stat *st)
318 static PyObject *makestat(const struct stat *st)
319 {
319 {
320 PyObject *stat;
320 PyObject *stat;
321
321
322 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
322 stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
323 if (stat)
323 if (stat)
324 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
324 memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
325 return stat;
325 return stat;
326 }
326 }
327
327
328 static PyObject *_listdir_stat(char *path, int pathlen, int keepstat,
328 static PyObject *_listdir_stat(char *path, int pathlen, int keepstat,
329 char *skip)
329 char *skip)
330 {
330 {
331 PyObject *list, *elem, *ret = NULL;
331 PyObject *list, *elem, *ret = NULL;
332 char fullpath[PATH_MAX + 10];
332 char fullpath[PATH_MAX + 10];
333 int kind, err;
333 int kind, err;
334 struct stat st;
334 struct stat st;
335 struct dirent *ent;
335 struct dirent *ent;
336 DIR *dir;
336 DIR *dir;
337 #ifdef AT_SYMLINK_NOFOLLOW
337 #ifdef AT_SYMLINK_NOFOLLOW
338 int dfd = -1;
338 int dfd = -1;
339 #endif
339 #endif
340
340
341 if (pathlen >= PATH_MAX) {
341 if (pathlen >= PATH_MAX) {
342 errno = ENAMETOOLONG;
342 errno = ENAMETOOLONG;
343 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
343 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
344 goto error_value;
344 goto error_value;
345 }
345 }
346 strncpy(fullpath, path, PATH_MAX);
346 strncpy(fullpath, path, PATH_MAX);
347 fullpath[pathlen] = '/';
347 fullpath[pathlen] = '/';
348
348
349 #ifdef AT_SYMLINK_NOFOLLOW
349 #ifdef AT_SYMLINK_NOFOLLOW
350 dfd = open(path, O_RDONLY);
350 dfd = open(path, O_RDONLY);
351 if (dfd == -1) {
351 if (dfd == -1) {
352 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
352 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
353 goto error_value;
353 goto error_value;
354 }
354 }
355 dir = fdopendir(dfd);
355 dir = fdopendir(dfd);
356 #else
356 #else
357 dir = opendir(path);
357 dir = opendir(path);
358 #endif
358 #endif
359 if (!dir) {
359 if (!dir) {
360 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
360 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
361 goto error_dir;
361 goto error_dir;
362 }
362 }
363
363
364 list = PyList_New(0);
364 list = PyList_New(0);
365 if (!list)
365 if (!list)
366 goto error_list;
366 goto error_list;
367
367
368 while ((ent = readdir(dir))) {
368 while ((ent = readdir(dir))) {
369 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
369 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
370 continue;
370 continue;
371
371
372 kind = entkind(ent);
372 kind = entkind(ent);
373 if (kind == -1 || keepstat) {
373 if (kind == -1 || keepstat) {
374 #ifdef AT_SYMLINK_NOFOLLOW
374 #ifdef AT_SYMLINK_NOFOLLOW
375 err = fstatat(dfd, ent->d_name, &st,
375 err = fstatat(dfd, ent->d_name, &st,
376 AT_SYMLINK_NOFOLLOW);
376 AT_SYMLINK_NOFOLLOW);
377 #else
377 #else
378 strncpy(fullpath + pathlen + 1, ent->d_name,
378 strncpy(fullpath + pathlen + 1, ent->d_name,
379 PATH_MAX - pathlen);
379 PATH_MAX - pathlen);
380 fullpath[PATH_MAX] = '\0';
380 fullpath[PATH_MAX] = '\0';
381 err = lstat(fullpath, &st);
381 err = lstat(fullpath, &st);
382 #endif
382 #endif
383 if (err == -1) {
383 if (err == -1) {
384 /* race with file deletion? */
384 /* race with file deletion? */
385 if (errno == ENOENT)
385 if (errno == ENOENT)
386 continue;
386 continue;
387 strncpy(fullpath + pathlen + 1, ent->d_name,
387 strncpy(fullpath + pathlen + 1, ent->d_name,
388 PATH_MAX - pathlen);
388 PATH_MAX - pathlen);
389 fullpath[PATH_MAX] = 0;
389 fullpath[PATH_MAX] = 0;
390 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
390 PyErr_SetFromErrnoWithFilename(PyExc_OSError,
391 fullpath);
391 fullpath);
392 goto error;
392 goto error;
393 }
393 }
394 kind = st.st_mode & S_IFMT;
394 kind = st.st_mode & S_IFMT;
395 }
395 }
396
396
397 /* quit early? */
397 /* quit early? */
398 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
398 if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
399 ret = PyList_New(0);
399 ret = PyList_New(0);
400 goto error;
400 goto error;
401 }
401 }
402
402
403 if (keepstat) {
403 if (keepstat) {
404 PyObject *stat = makestat(&st);
404 PyObject *stat = makestat(&st);
405 if (!stat)
405 if (!stat)
406 goto error;
406 goto error;
407 elem = Py_BuildValue(PY23("siN", "yiN"), ent->d_name,
407 elem = Py_BuildValue(PY23("siN", "yiN"), ent->d_name,
408 kind, stat);
408 kind, stat);
409 } else
409 } else
410 elem = Py_BuildValue(PY23("si", "yi"), ent->d_name,
410 elem = Py_BuildValue(PY23("si", "yi"), ent->d_name,
411 kind);
411 kind);
412 if (!elem)
412 if (!elem)
413 goto error;
413 goto error;
414
414
415 PyList_Append(list, elem);
415 PyList_Append(list, elem);
416 Py_DECREF(elem);
416 Py_DECREF(elem);
417 }
417 }
418
418
419 ret = list;
419 ret = list;
420 Py_INCREF(ret);
420 Py_INCREF(ret);
421
421
422 error:
422 error:
423 Py_DECREF(list);
423 Py_DECREF(list);
424 error_list:
424 error_list:
425 closedir(dir);
425 closedir(dir);
426 /* closedir also closes its dirfd */
426 /* closedir also closes its dirfd */
427 goto error_value;
427 goto error_value;
428 error_dir:
428 error_dir:
429 #ifdef AT_SYMLINK_NOFOLLOW
429 #ifdef AT_SYMLINK_NOFOLLOW
430 close(dfd);
430 close(dfd);
431 #endif
431 #endif
432 error_value:
432 error_value:
433 return ret;
433 return ret;
434 }
434 }
435
435
436 #ifdef __APPLE__
436 #ifdef __APPLE__
437
437
438 typedef struct {
438 typedef struct {
439 u_int32_t length;
439 u_int32_t length;
440 attrreference_t name;
440 attrreference_t name;
441 fsobj_type_t obj_type;
441 fsobj_type_t obj_type;
442 struct timespec mtime;
442 struct timespec mtime;
443 #if __LITTLE_ENDIAN__
443 #if __LITTLE_ENDIAN__
444 mode_t access_mask;
444 mode_t access_mask;
445 uint16_t padding;
445 uint16_t padding;
446 #else
446 #else
447 uint16_t padding;
447 uint16_t padding;
448 mode_t access_mask;
448 mode_t access_mask;
449 #endif
449 #endif
450 off_t size;
450 off_t size;
451 } __attribute__((packed)) attrbuf_entry;
451 } __attribute__((packed)) attrbuf_entry;
452
452
453 int attrkind(attrbuf_entry *entry)
453 int attrkind(attrbuf_entry *entry)
454 {
454 {
455 switch (entry->obj_type) {
455 switch (entry->obj_type) {
456 case VREG: return S_IFREG;
456 case VREG: return S_IFREG;
457 case VDIR: return S_IFDIR;
457 case VDIR: return S_IFDIR;
458 case VLNK: return S_IFLNK;
458 case VLNK: return S_IFLNK;
459 case VBLK: return S_IFBLK;
459 case VBLK: return S_IFBLK;
460 case VCHR: return S_IFCHR;
460 case VCHR: return S_IFCHR;
461 case VFIFO: return S_IFIFO;
461 case VFIFO: return S_IFIFO;
462 case VSOCK: return S_IFSOCK;
462 case VSOCK: return S_IFSOCK;
463 }
463 }
464 return -1;
464 return -1;
465 }
465 }
466
466
467 /* get these many entries at a time */
467 /* get these many entries at a time */
468 #define LISTDIR_BATCH_SIZE 50
468 #define LISTDIR_BATCH_SIZE 50
469
469
470 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
470 static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
471 char *skip, bool *fallback)
471 char *skip, bool *fallback)
472 {
472 {
473 PyObject *list, *elem, *ret = NULL;
473 PyObject *list, *elem, *ret = NULL;
474 int kind, err;
474 int kind, err;
475 unsigned long index;
475 unsigned long index;
476 unsigned int count, old_state, new_state;
476 unsigned int count, old_state, new_state;
477 bool state_seen = false;
477 bool state_seen = false;
478 attrbuf_entry *entry;
478 attrbuf_entry *entry;
479 /* from the getattrlist(2) man page: a path can be no longer than
479 /* from the getattrlist(2) man page: a path can be no longer than
480 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
480 (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
481 silently truncate attribute data if attrBufSize is too small." So
481 silently truncate attribute data if attrBufSize is too small." So
482 pass in a buffer big enough for the worst case. */
482 pass in a buffer big enough for the worst case. */
483 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
483 char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
484 unsigned int basep_unused;
484 unsigned int basep_unused;
485
485
486 struct stat st;
486 struct stat st;
487 int dfd = -1;
487 int dfd = -1;
488
488
489 /* these must match the attrbuf_entry struct, otherwise you'll end up
489 /* these must match the attrbuf_entry struct, otherwise you'll end up
490 with garbage */
490 with garbage */
491 struct attrlist requested_attr = {0};
491 struct attrlist requested_attr = {0};
492 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
492 requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
493 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
493 requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
494 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
494 ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
495 requested_attr.fileattr = ATTR_FILE_DATALENGTH;
495 requested_attr.fileattr = ATTR_FILE_DATALENGTH;
496
496
497 *fallback = false;
497 *fallback = false;
498
498
499 if (pathlen >= PATH_MAX) {
499 if (pathlen >= PATH_MAX) {
500 errno = ENAMETOOLONG;
500 errno = ENAMETOOLONG;
501 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
501 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
502 goto error_value;
502 goto error_value;
503 }
503 }
504
504
505 dfd = open(path, O_RDONLY);
505 dfd = open(path, O_RDONLY);
506 if (dfd == -1) {
506 if (dfd == -1) {
507 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
507 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
508 goto error_value;
508 goto error_value;
509 }
509 }
510
510
511 list = PyList_New(0);
511 list = PyList_New(0);
512 if (!list)
512 if (!list)
513 goto error_dir;
513 goto error_dir;
514
514
515 do {
515 do {
516 count = LISTDIR_BATCH_SIZE;
516 count = LISTDIR_BATCH_SIZE;
517 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
517 err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
518 sizeof(attrbuf), &count, &basep_unused,
518 sizeof(attrbuf), &count, &basep_unused,
519 &new_state, 0);
519 &new_state, 0);
520 if (err < 0) {
520 if (err < 0) {
521 if (errno == ENOTSUP) {
521 if (errno == ENOTSUP) {
522 /* We're on a filesystem that doesn't support
522 /* We're on a filesystem that doesn't support
523 getdirentriesattr. Fall back to the
523 getdirentriesattr. Fall back to the
524 stat-based implementation. */
524 stat-based implementation. */
525 *fallback = true;
525 *fallback = true;
526 } else
526 } else
527 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
527 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
528 goto error;
528 goto error;
529 }
529 }
530
530
531 if (!state_seen) {
531 if (!state_seen) {
532 old_state = new_state;
532 old_state = new_state;
533 state_seen = true;
533 state_seen = true;
534 } else if (old_state != new_state) {
534 } else if (old_state != new_state) {
535 /* There's an edge case with getdirentriesattr. Consider
535 /* There's an edge case with getdirentriesattr. Consider
536 the following initial list of files:
536 the following initial list of files:
537
537
538 a
538 a
539 b
539 b
540 <--
540 <--
541 c
541 c
542 d
542 d
543
543
544 If the iteration is paused at the arrow, and b is
544 If the iteration is paused at the arrow, and b is
545 deleted before it is resumed, getdirentriesattr will
545 deleted before it is resumed, getdirentriesattr will
546 not return d at all! Ordinarily we're expected to
546 not return d at all! Ordinarily we're expected to
547 restart the iteration from the beginning. To avoid
547 restart the iteration from the beginning. To avoid
548 getting stuck in a retry loop here, fall back to
548 getting stuck in a retry loop here, fall back to
549 stat. */
549 stat. */
550 *fallback = true;
550 *fallback = true;
551 goto error;
551 goto error;
552 }
552 }
553
553
554 entry = (attrbuf_entry *)attrbuf;
554 entry = (attrbuf_entry *)attrbuf;
555
555
556 for (index = 0; index < count; index++) {
556 for (index = 0; index < count; index++) {
557 char *filename = ((char *)&entry->name) +
557 char *filename = ((char *)&entry->name) +
558 entry->name.attr_dataoffset;
558 entry->name.attr_dataoffset;
559
559
560 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
560 if (!strcmp(filename, ".") || !strcmp(filename, ".."))
561 continue;
561 continue;
562
562
563 kind = attrkind(entry);
563 kind = attrkind(entry);
564 if (kind == -1) {
564 if (kind == -1) {
565 PyErr_Format(PyExc_OSError,
565 PyErr_Format(PyExc_OSError,
566 "unknown object type %u for file "
566 "unknown object type %u for file "
567 "%s%s!",
567 "%s%s!",
568 entry->obj_type, path, filename);
568 entry->obj_type, path, filename);
569 goto error;
569 goto error;
570 }
570 }
571
571
572 /* quit early? */
572 /* quit early? */
573 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
573 if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
574 ret = PyList_New(0);
574 ret = PyList_New(0);
575 goto error;
575 goto error;
576 }
576 }
577
577
578 if (keepstat) {
578 if (keepstat) {
579 PyObject *stat = NULL;
579 PyObject *stat = NULL;
580 /* from the getattrlist(2) man page: "Only the
580 /* from the getattrlist(2) man page: "Only the
581 permission bits ... are valid". */
581 permission bits ... are valid". */
582 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
582 st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
583 st.st_mtime = entry->mtime.tv_sec;
583 st.st_mtime = entry->mtime.tv_sec;
584 st.st_size = entry->size;
584 st.st_size = entry->size;
585 stat = makestat(&st);
585 stat = makestat(&st);
586 if (!stat)
586 if (!stat)
587 goto error;
587 goto error;
588 elem = Py_BuildValue(PY23("siN", "yiN"),
588 elem = Py_BuildValue(PY23("siN", "yiN"),
589 filename, kind, stat);
589 filename, kind, stat);
590 } else
590 } else
591 elem = Py_BuildValue(PY23("si", "yi"),
591 elem = Py_BuildValue(PY23("si", "yi"),
592 filename, kind);
592 filename, kind);
593 if (!elem)
593 if (!elem)
594 goto error;
594 goto error;
595
595
596 PyList_Append(list, elem);
596 PyList_Append(list, elem);
597 Py_DECREF(elem);
597 Py_DECREF(elem);
598
598
599 entry = (attrbuf_entry *)((char *)entry + entry->length);
599 entry = (attrbuf_entry *)((char *)entry + entry->length);
600 }
600 }
601 } while (err == 0);
601 } while (err == 0);
602
602
603 ret = list;
603 ret = list;
604 Py_INCREF(ret);
604 Py_INCREF(ret);
605
605
606 error:
606 error:
607 Py_DECREF(list);
607 Py_DECREF(list);
608 error_dir:
608 error_dir:
609 close(dfd);
609 close(dfd);
610 error_value:
610 error_value:
611 return ret;
611 return ret;
612 }
612 }
613
613
614 #endif /* __APPLE__ */
614 #endif /* __APPLE__ */
615
615
616 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
616 static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
617 {
617 {
618 #ifdef __APPLE__
618 #ifdef __APPLE__
619 PyObject *ret;
619 PyObject *ret;
620 bool fallback = false;
620 bool fallback = false;
621
621
622 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
622 ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
623 if (ret != NULL || !fallback)
623 if (ret != NULL || !fallback)
624 return ret;
624 return ret;
625 #endif
625 #endif
626 return _listdir_stat(path, pathlen, keepstat, skip);
626 return _listdir_stat(path, pathlen, keepstat, skip);
627 }
627 }
628
628
629 static PyObject *statfiles(PyObject *self, PyObject *args)
629 static PyObject *statfiles(PyObject *self, PyObject *args)
630 {
630 {
631 PyObject *names, *stats;
631 PyObject *names, *stats;
632 Py_ssize_t i, count;
632 Py_ssize_t i, count;
633
633
634 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
634 if (!PyArg_ParseTuple(args, "O:statfiles", &names))
635 return NULL;
635 return NULL;
636
636
637 count = PySequence_Length(names);
637 count = PySequence_Length(names);
638 if (count == -1) {
638 if (count == -1) {
639 PyErr_SetString(PyExc_TypeError, "not a sequence");
639 PyErr_SetString(PyExc_TypeError, "not a sequence");
640 return NULL;
640 return NULL;
641 }
641 }
642
642
643 stats = PyList_New(count);
643 stats = PyList_New(count);
644 if (stats == NULL)
644 if (stats == NULL)
645 return NULL;
645 return NULL;
646
646
647 for (i = 0; i < count; i++) {
647 for (i = 0; i < count; i++) {
648 PyObject *stat, *pypath;
648 PyObject *stat, *pypath;
649 struct stat st;
649 struct stat st;
650 int ret, kind;
650 int ret, kind;
651 char *path;
651 char *path;
652
652
653 /* With a large file count or on a slow filesystem,
653 /* With a large file count or on a slow filesystem,
654 don't block signals for long (issue4878). */
654 don't block signals for long (issue4878). */
655 if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
655 if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
656 goto bail;
656 goto bail;
657
657
658 pypath = PySequence_GetItem(names, i);
658 pypath = PySequence_GetItem(names, i);
659 if (!pypath)
659 if (!pypath)
660 goto bail;
660 goto bail;
661 path = PyBytes_AsString(pypath);
661 path = PyBytes_AsString(pypath);
662 if (path == NULL) {
662 if (path == NULL) {
663 Py_DECREF(pypath);
663 Py_DECREF(pypath);
664 PyErr_SetString(PyExc_TypeError, "not a string");
664 PyErr_SetString(PyExc_TypeError, "not a string");
665 goto bail;
665 goto bail;
666 }
666 }
667 ret = lstat(path, &st);
667 ret = lstat(path, &st);
668 Py_DECREF(pypath);
668 Py_DECREF(pypath);
669 kind = st.st_mode & S_IFMT;
669 kind = st.st_mode & S_IFMT;
670 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
670 if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
671 stat = makestat(&st);
671 stat = makestat(&st);
672 if (stat == NULL)
672 if (stat == NULL)
673 goto bail;
673 goto bail;
674 PyList_SET_ITEM(stats, i, stat);
674 PyList_SET_ITEM(stats, i, stat);
675 } else {
675 } else {
676 Py_INCREF(Py_None);
676 Py_INCREF(Py_None);
677 PyList_SET_ITEM(stats, i, Py_None);
677 PyList_SET_ITEM(stats, i, Py_None);
678 }
678 }
679 }
679 }
680
680
681 return stats;
681 return stats;
682
682
683 bail:
683 bail:
684 Py_DECREF(stats);
684 Py_DECREF(stats);
685 return NULL;
685 return NULL;
686 }
686 }
687
687
688 /*
688 /*
689 * recvfds() simply does not release GIL during blocking io operation because
689 * recvfds() simply does not release GIL during blocking io operation because
690 * command server is known to be single-threaded.
690 * command server is known to be single-threaded.
691 *
691 *
692 * Old systems such as Solaris don't provide CMSG_LEN, msg_control, etc.
692 * Old systems such as Solaris don't provide CMSG_LEN, msg_control, etc.
693 * Currently, recvfds() is not supported on these platforms.
693 * Currently, recvfds() is not supported on these platforms.
694 */
694 */
695 #ifdef CMSG_LEN
695 #ifdef CMSG_LEN
696
696
697 static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize)
697 static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize)
698 {
698 {
699 char dummy[1];
699 char dummy[1];
700 struct iovec iov = {dummy, sizeof(dummy)};
700 struct iovec iov = {dummy, sizeof(dummy)};
701 struct msghdr msgh = {0};
701 struct msghdr msgh = {0};
702 struct cmsghdr *cmsg;
702 struct cmsghdr *cmsg;
703
703
704 msgh.msg_iov = &iov;
704 msgh.msg_iov = &iov;
705 msgh.msg_iovlen = 1;
705 msgh.msg_iovlen = 1;
706 msgh.msg_control = cbuf;
706 msgh.msg_control = cbuf;
707 msgh.msg_controllen = (socklen_t)cbufsize;
707 msgh.msg_controllen = (socklen_t)cbufsize;
708 if (recvmsg(sockfd, &msgh, 0) < 0)
708 if (recvmsg(sockfd, &msgh, 0) < 0)
709 return -1;
709 return -1;
710
710
711 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
711 for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
712 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
712 cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
713 if (cmsg->cmsg_level != SOL_SOCKET ||
713 if (cmsg->cmsg_level != SOL_SOCKET ||
714 cmsg->cmsg_type != SCM_RIGHTS)
714 cmsg->cmsg_type != SCM_RIGHTS)
715 continue;
715 continue;
716 *rfds = (int *)CMSG_DATA(cmsg);
716 *rfds = (int *)CMSG_DATA(cmsg);
717 return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
717 return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
718 }
718 }
719
719
720 *rfds = cbuf;
720 *rfds = cbuf;
721 return 0;
721 return 0;
722 }
722 }
723
723
724 static PyObject *recvfds(PyObject *self, PyObject *args)
724 static PyObject *recvfds(PyObject *self, PyObject *args)
725 {
725 {
726 int sockfd;
726 int sockfd;
727 int *rfds = NULL;
727 int *rfds = NULL;
728 ssize_t rfdscount, i;
728 ssize_t rfdscount, i;
729 char cbuf[256];
729 char cbuf[256];
730 PyObject *rfdslist = NULL;
730 PyObject *rfdslist = NULL;
731
731
732 if (!PyArg_ParseTuple(args, "i", &sockfd))
732 if (!PyArg_ParseTuple(args, "i", &sockfd))
733 return NULL;
733 return NULL;
734
734
735 rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf));
735 rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf));
736 if (rfdscount < 0)
736 if (rfdscount < 0)
737 return PyErr_SetFromErrno(PyExc_OSError);
737 return PyErr_SetFromErrno(PyExc_OSError);
738
738
739 rfdslist = PyList_New(rfdscount);
739 rfdslist = PyList_New(rfdscount);
740 if (!rfdslist)
740 if (!rfdslist)
741 goto bail;
741 goto bail;
742 for (i = 0; i < rfdscount; i++) {
742 for (i = 0; i < rfdscount; i++) {
743 PyObject *obj = PyLong_FromLong(rfds[i]);
743 PyObject *obj = PyLong_FromLong(rfds[i]);
744 if (!obj)
744 if (!obj)
745 goto bail;
745 goto bail;
746 PyList_SET_ITEM(rfdslist, i, obj);
746 PyList_SET_ITEM(rfdslist, i, obj);
747 }
747 }
748 return rfdslist;
748 return rfdslist;
749
749
750 bail:
750 bail:
751 Py_XDECREF(rfdslist);
751 Py_XDECREF(rfdslist);
752 return NULL;
752 return NULL;
753 }
753 }
754
754
755 #endif /* CMSG_LEN */
755 #endif /* CMSG_LEN */
756
756
757 /* allow disabling setprocname via compiler flags */
757 /* allow disabling setprocname via compiler flags */
758 #ifndef SETPROCNAME_USE_NONE
758 #ifndef SETPROCNAME_USE_NONE
759 #if defined(HAVE_SETPROCTITLE)
759 #if defined(HAVE_SETPROCTITLE)
760 /* setproctitle is the first choice - available in FreeBSD */
760 /* setproctitle is the first choice - available in FreeBSD */
761 #define SETPROCNAME_USE_SETPROCTITLE
761 #define SETPROCNAME_USE_SETPROCTITLE
762 #elif (defined(__linux__) || defined(__APPLE__)) && PY_MAJOR_VERSION == 2
762 #elif (defined(__linux__) || defined(__APPLE__)) && PY_MAJOR_VERSION == 2
763 /* rewrite the argv buffer in place - works in Linux and OS X. Py_GetArgcArgv
763 /* rewrite the argv buffer in place - works in Linux and OS X. Py_GetArgcArgv
764 * in Python 3 returns the copied wchar_t **argv, thus unsupported. */
764 * in Python 3 returns the copied wchar_t **argv, thus unsupported. */
765 #define SETPROCNAME_USE_ARGVREWRITE
765 #define SETPROCNAME_USE_ARGVREWRITE
766 #else
766 #else
767 #define SETPROCNAME_USE_NONE
767 #define SETPROCNAME_USE_NONE
768 #endif
768 #endif
769 #endif /* ndef SETPROCNAME_USE_NONE */
769 #endif /* ndef SETPROCNAME_USE_NONE */
770
770
771 #ifndef SETPROCNAME_USE_NONE
771 #ifndef SETPROCNAME_USE_NONE
772 static PyObject *setprocname(PyObject *self, PyObject *args)
772 static PyObject *setprocname(PyObject *self, PyObject *args)
773 {
773 {
774 const char *name = NULL;
774 const char *name = NULL;
775 if (!PyArg_ParseTuple(args, PY23("s", "y"), &name))
775 if (!PyArg_ParseTuple(args, PY23("s", "y"), &name))
776 return NULL;
776 return NULL;
777
777
778 #if defined(SETPROCNAME_USE_SETPROCTITLE)
778 #if defined(SETPROCNAME_USE_SETPROCTITLE)
779 setproctitle("%s", name);
779 setproctitle("%s", name);
780 #elif defined(SETPROCNAME_USE_ARGVREWRITE)
780 #elif defined(SETPROCNAME_USE_ARGVREWRITE)
781 {
781 {
782 static char *argvstart = NULL;
782 static char *argvstart = NULL;
783 static size_t argvsize = 0;
783 static size_t argvsize = 0;
784 if (argvstart == NULL) {
784 if (argvstart == NULL) {
785 int argc = 0, i;
785 int argc = 0, i;
786 char **argv = NULL;
786 char **argv = NULL;
787 char *argvend;
787 char *argvend;
788 extern void Py_GetArgcArgv(int *argc, char ***argv);
788 extern void Py_GetArgcArgv(int *argc, char ***argv);
789 Py_GetArgcArgv(&argc, &argv);
789 Py_GetArgcArgv(&argc, &argv);
790 /* Py_GetArgcArgv may not do much if a custom python
790 /* Py_GetArgcArgv may not do much if a custom python
791 * launcher is used that doesn't record the information
791 * launcher is used that doesn't record the information
792 * it needs. Let's handle this gracefully instead of
792 * it needs. Let's handle this gracefully instead of
793 * segfaulting. */
793 * segfaulting. */
794 if (argv != NULL)
794 if (argv != NULL)
795 argvend = argvstart = argv[0];
795 argvend = argvstart = argv[0];
796 else
796 else
797 argvend = argvstart = NULL;
797 argvend = argvstart = NULL;
798
798
799 /* Check the memory we can use. Typically, argv[i] and
799 /* Check the memory we can use. Typically, argv[i] and
800 * argv[i + 1] are continuous. */
800 * argv[i + 1] are continuous. */
801 for (i = 0; i < argc; ++i) {
801 for (i = 0; i < argc; ++i) {
802 size_t len;
802 size_t len;
803 if (argv[i] > argvend || argv[i] < argvstart)
803 if (argv[i] > argvend || argv[i] < argvstart)
804 break; /* not continuous */
804 break; /* not continuous */
805 len = strlen(argv[i]);
805 len = strlen(argv[i]);
806 argvend = argv[i] + len + 1 /* '\0' */;
806 argvend = argv[i] + len + 1 /* '\0' */;
807 }
807 }
808 if (argvend > argvstart) /* sanity check */
808 if (argvend > argvstart) /* sanity check */
809 argvsize = argvend - argvstart;
809 argvsize = argvend - argvstart;
810 }
810 }
811
811
812 if (argvstart && argvsize > 1) {
812 if (argvstart && argvsize > 1) {
813 int n = snprintf(argvstart, argvsize, "%s", name);
813 int n = snprintf(argvstart, argvsize, "%s", name);
814 if (n >= 0 && (size_t)n < argvsize)
814 if (n >= 0 && (size_t)n < argvsize)
815 memset(argvstart + n, 0, argvsize - n);
815 memset(argvstart + n, 0, argvsize - n);
816 }
816 }
817 }
817 }
818 #endif
818 #endif
819
819
820 Py_RETURN_NONE;
820 Py_RETURN_NONE;
821 }
821 }
822 #endif /* ndef SETPROCNAME_USE_NONE */
822 #endif /* ndef SETPROCNAME_USE_NONE */
823
823
824 #if defined(HAVE_BSD_STATFS)
824 #if defined(HAVE_BSD_STATFS)
825 static const char *describefstype(const struct statfs *pbuf)
825 static const char *describefstype(const struct statfs *pbuf)
826 {
826 {
827 /* BSD or OSX provides a f_fstypename field */
827 /* BSD or OSX provides a f_fstypename field */
828 return pbuf->f_fstypename;
828 return pbuf->f_fstypename;
829 }
829 }
830 #elif defined(HAVE_LINUX_STATFS)
830 #elif defined(HAVE_LINUX_STATFS)
831 static const char *describefstype(const struct statfs *pbuf)
831 static const char *describefstype(const struct statfs *pbuf)
832 {
832 {
833 /* Begin of Linux filesystems */
833 /* Begin of Linux filesystems */
834 #ifdef ADFS_SUPER_MAGIC
834 #ifdef ADFS_SUPER_MAGIC
835 if (pbuf->f_type == ADFS_SUPER_MAGIC)
835 if (pbuf->f_type == ADFS_SUPER_MAGIC)
836 return "adfs";
836 return "adfs";
837 #endif
837 #endif
838 #ifdef AFFS_SUPER_MAGIC
838 #ifdef AFFS_SUPER_MAGIC
839 if (pbuf->f_type == AFFS_SUPER_MAGIC)
839 if (pbuf->f_type == AFFS_SUPER_MAGIC)
840 return "affs";
840 return "affs";
841 #endif
841 #endif
842 #ifdef AUTOFS_SUPER_MAGIC
842 #ifdef AUTOFS_SUPER_MAGIC
843 if (pbuf->f_type == AUTOFS_SUPER_MAGIC)
843 if (pbuf->f_type == AUTOFS_SUPER_MAGIC)
844 return "autofs";
844 return "autofs";
845 #endif
845 #endif
846 #ifdef BDEVFS_MAGIC
846 #ifdef BDEVFS_MAGIC
847 if (pbuf->f_type == BDEVFS_MAGIC)
847 if (pbuf->f_type == BDEVFS_MAGIC)
848 return "bdevfs";
848 return "bdevfs";
849 #endif
849 #endif
850 #ifdef BEFS_SUPER_MAGIC
850 #ifdef BEFS_SUPER_MAGIC
851 if (pbuf->f_type == BEFS_SUPER_MAGIC)
851 if (pbuf->f_type == BEFS_SUPER_MAGIC)
852 return "befs";
852 return "befs";
853 #endif
853 #endif
854 #ifdef BFS_MAGIC
854 #ifdef BFS_MAGIC
855 if (pbuf->f_type == BFS_MAGIC)
855 if (pbuf->f_type == BFS_MAGIC)
856 return "bfs";
856 return "bfs";
857 #endif
857 #endif
858 #ifdef BINFMTFS_MAGIC
858 #ifdef BINFMTFS_MAGIC
859 if (pbuf->f_type == BINFMTFS_MAGIC)
859 if (pbuf->f_type == BINFMTFS_MAGIC)
860 return "binfmtfs";
860 return "binfmtfs";
861 #endif
861 #endif
862 #ifdef BTRFS_SUPER_MAGIC
862 #ifdef BTRFS_SUPER_MAGIC
863 if (pbuf->f_type == BTRFS_SUPER_MAGIC)
863 if (pbuf->f_type == BTRFS_SUPER_MAGIC)
864 return "btrfs";
864 return "btrfs";
865 #endif
865 #endif
866 #ifdef CGROUP_SUPER_MAGIC
866 #ifdef CGROUP_SUPER_MAGIC
867 if (pbuf->f_type == CGROUP_SUPER_MAGIC)
867 if (pbuf->f_type == CGROUP_SUPER_MAGIC)
868 return "cgroup";
868 return "cgroup";
869 #endif
869 #endif
870 #ifdef CIFS_MAGIC_NUMBER
870 #ifdef CIFS_MAGIC_NUMBER
871 if (pbuf->f_type == CIFS_MAGIC_NUMBER)
871 if (pbuf->f_type == CIFS_MAGIC_NUMBER)
872 return "cifs";
872 return "cifs";
873 #endif
873 #endif
874 #ifdef CODA_SUPER_MAGIC
874 #ifdef CODA_SUPER_MAGIC
875 if (pbuf->f_type == CODA_SUPER_MAGIC)
875 if (pbuf->f_type == CODA_SUPER_MAGIC)
876 return "coda";
876 return "coda";
877 #endif
877 #endif
878 #ifdef COH_SUPER_MAGIC
878 #ifdef COH_SUPER_MAGIC
879 if (pbuf->f_type == COH_SUPER_MAGIC)
879 if (pbuf->f_type == COH_SUPER_MAGIC)
880 return "coh";
880 return "coh";
881 #endif
881 #endif
882 #ifdef CRAMFS_MAGIC
882 #ifdef CRAMFS_MAGIC
883 if (pbuf->f_type == CRAMFS_MAGIC)
883 if (pbuf->f_type == CRAMFS_MAGIC)
884 return "cramfs";
884 return "cramfs";
885 #endif
885 #endif
886 #ifdef DEBUGFS_MAGIC
886 #ifdef DEBUGFS_MAGIC
887 if (pbuf->f_type == DEBUGFS_MAGIC)
887 if (pbuf->f_type == DEBUGFS_MAGIC)
888 return "debugfs";
888 return "debugfs";
889 #endif
889 #endif
890 #ifdef DEVFS_SUPER_MAGIC
890 #ifdef DEVFS_SUPER_MAGIC
891 if (pbuf->f_type == DEVFS_SUPER_MAGIC)
891 if (pbuf->f_type == DEVFS_SUPER_MAGIC)
892 return "devfs";
892 return "devfs";
893 #endif
893 #endif
894 #ifdef DEVPTS_SUPER_MAGIC
894 #ifdef DEVPTS_SUPER_MAGIC
895 if (pbuf->f_type == DEVPTS_SUPER_MAGIC)
895 if (pbuf->f_type == DEVPTS_SUPER_MAGIC)
896 return "devpts";
896 return "devpts";
897 #endif
897 #endif
898 #ifdef EFIVARFS_MAGIC
898 #ifdef EFIVARFS_MAGIC
899 if (pbuf->f_type == EFIVARFS_MAGIC)
899 if (pbuf->f_type == EFIVARFS_MAGIC)
900 return "efivarfs";
900 return "efivarfs";
901 #endif
901 #endif
902 #ifdef EFS_SUPER_MAGIC
902 #ifdef EFS_SUPER_MAGIC
903 if (pbuf->f_type == EFS_SUPER_MAGIC)
903 if (pbuf->f_type == EFS_SUPER_MAGIC)
904 return "efs";
904 return "efs";
905 #endif
905 #endif
906 #ifdef EXT_SUPER_MAGIC
906 #ifdef EXT_SUPER_MAGIC
907 if (pbuf->f_type == EXT_SUPER_MAGIC)
907 if (pbuf->f_type == EXT_SUPER_MAGIC)
908 return "ext";
908 return "ext";
909 #endif
909 #endif
910 #ifdef EXT2_OLD_SUPER_MAGIC
910 #ifdef EXT2_OLD_SUPER_MAGIC
911 if (pbuf->f_type == EXT2_OLD_SUPER_MAGIC)
911 if (pbuf->f_type == EXT2_OLD_SUPER_MAGIC)
912 return "ext2";
912 return "ext2";
913 #endif
913 #endif
914 #ifdef EXT2_SUPER_MAGIC
914 #ifdef EXT2_SUPER_MAGIC
915 if (pbuf->f_type == EXT2_SUPER_MAGIC)
915 if (pbuf->f_type == EXT2_SUPER_MAGIC)
916 return "ext2";
916 return "ext2";
917 #endif
917 #endif
918 #ifdef EXT3_SUPER_MAGIC
918 #ifdef EXT3_SUPER_MAGIC
919 if (pbuf->f_type == EXT3_SUPER_MAGIC)
919 if (pbuf->f_type == EXT3_SUPER_MAGIC)
920 return "ext3";
920 return "ext3";
921 #endif
921 #endif
922 #ifdef EXT4_SUPER_MAGIC
922 #ifdef EXT4_SUPER_MAGIC
923 if (pbuf->f_type == EXT4_SUPER_MAGIC)
923 if (pbuf->f_type == EXT4_SUPER_MAGIC)
924 return "ext4";
924 return "ext4";
925 #endif
925 #endif
926 #ifdef F2FS_SUPER_MAGIC
926 #ifdef F2FS_SUPER_MAGIC
927 if (pbuf->f_type == F2FS_SUPER_MAGIC)
927 if (pbuf->f_type == F2FS_SUPER_MAGIC)
928 return "f2fs";
928 return "f2fs";
929 #endif
929 #endif
930 #ifdef FUSE_SUPER_MAGIC
930 #ifdef FUSE_SUPER_MAGIC
931 if (pbuf->f_type == FUSE_SUPER_MAGIC)
931 if (pbuf->f_type == FUSE_SUPER_MAGIC)
932 return "fuse";
932 return "fuse";
933 #endif
933 #endif
934 #ifdef FUTEXFS_SUPER_MAGIC
934 #ifdef FUTEXFS_SUPER_MAGIC
935 if (pbuf->f_type == FUTEXFS_SUPER_MAGIC)
935 if (pbuf->f_type == FUTEXFS_SUPER_MAGIC)
936 return "futexfs";
936 return "futexfs";
937 #endif
937 #endif
938 #ifdef HFS_SUPER_MAGIC
938 #ifdef HFS_SUPER_MAGIC
939 if (pbuf->f_type == HFS_SUPER_MAGIC)
939 if (pbuf->f_type == HFS_SUPER_MAGIC)
940 return "hfs";
940 return "hfs";
941 #endif
941 #endif
942 #ifdef HOSTFS_SUPER_MAGIC
942 #ifdef HOSTFS_SUPER_MAGIC
943 if (pbuf->f_type == HOSTFS_SUPER_MAGIC)
943 if (pbuf->f_type == HOSTFS_SUPER_MAGIC)
944 return "hostfs";
944 return "hostfs";
945 #endif
945 #endif
946 #ifdef HPFS_SUPER_MAGIC
946 #ifdef HPFS_SUPER_MAGIC
947 if (pbuf->f_type == HPFS_SUPER_MAGIC)
947 if (pbuf->f_type == HPFS_SUPER_MAGIC)
948 return "hpfs";
948 return "hpfs";
949 #endif
949 #endif
950 #ifdef HUGETLBFS_MAGIC
950 #ifdef HUGETLBFS_MAGIC
951 if (pbuf->f_type == HUGETLBFS_MAGIC)
951 if (pbuf->f_type == HUGETLBFS_MAGIC)
952 return "hugetlbfs";
952 return "hugetlbfs";
953 #endif
953 #endif
954 #ifdef ISOFS_SUPER_MAGIC
954 #ifdef ISOFS_SUPER_MAGIC
955 if (pbuf->f_type == ISOFS_SUPER_MAGIC)
955 if (pbuf->f_type == ISOFS_SUPER_MAGIC)
956 return "isofs";
956 return "isofs";
957 #endif
957 #endif
958 #ifdef JFFS2_SUPER_MAGIC
958 #ifdef JFFS2_SUPER_MAGIC
959 if (pbuf->f_type == JFFS2_SUPER_MAGIC)
959 if (pbuf->f_type == JFFS2_SUPER_MAGIC)
960 return "jffs2";
960 return "jffs2";
961 #endif
961 #endif
962 #ifdef JFS_SUPER_MAGIC
962 #ifdef JFS_SUPER_MAGIC
963 if (pbuf->f_type == JFS_SUPER_MAGIC)
963 if (pbuf->f_type == JFS_SUPER_MAGIC)
964 return "jfs";
964 return "jfs";
965 #endif
965 #endif
966 #ifdef MINIX_SUPER_MAGIC
966 #ifdef MINIX_SUPER_MAGIC
967 if (pbuf->f_type == MINIX_SUPER_MAGIC)
967 if (pbuf->f_type == MINIX_SUPER_MAGIC)
968 return "minix";
968 return "minix";
969 #endif
969 #endif
970 #ifdef MINIX2_SUPER_MAGIC
970 #ifdef MINIX2_SUPER_MAGIC
971 if (pbuf->f_type == MINIX2_SUPER_MAGIC)
971 if (pbuf->f_type == MINIX2_SUPER_MAGIC)
972 return "minix2";
972 return "minix2";
973 #endif
973 #endif
974 #ifdef MINIX3_SUPER_MAGIC
974 #ifdef MINIX3_SUPER_MAGIC
975 if (pbuf->f_type == MINIX3_SUPER_MAGIC)
975 if (pbuf->f_type == MINIX3_SUPER_MAGIC)
976 return "minix3";
976 return "minix3";
977 #endif
977 #endif
978 #ifdef MQUEUE_MAGIC
978 #ifdef MQUEUE_MAGIC
979 if (pbuf->f_type == MQUEUE_MAGIC)
979 if (pbuf->f_type == MQUEUE_MAGIC)
980 return "mqueue";
980 return "mqueue";
981 #endif
981 #endif
982 #ifdef MSDOS_SUPER_MAGIC
982 #ifdef MSDOS_SUPER_MAGIC
983 if (pbuf->f_type == MSDOS_SUPER_MAGIC)
983 if (pbuf->f_type == MSDOS_SUPER_MAGIC)
984 return "msdos";
984 return "msdos";
985 #endif
985 #endif
986 #ifdef NCP_SUPER_MAGIC
986 #ifdef NCP_SUPER_MAGIC
987 if (pbuf->f_type == NCP_SUPER_MAGIC)
987 if (pbuf->f_type == NCP_SUPER_MAGIC)
988 return "ncp";
988 return "ncp";
989 #endif
989 #endif
990 #ifdef NFS_SUPER_MAGIC
990 #ifdef NFS_SUPER_MAGIC
991 if (pbuf->f_type == NFS_SUPER_MAGIC)
991 if (pbuf->f_type == NFS_SUPER_MAGIC)
992 return "nfs";
992 return "nfs";
993 #endif
993 #endif
994 #ifdef NILFS_SUPER_MAGIC
994 #ifdef NILFS_SUPER_MAGIC
995 if (pbuf->f_type == NILFS_SUPER_MAGIC)
995 if (pbuf->f_type == NILFS_SUPER_MAGIC)
996 return "nilfs";
996 return "nilfs";
997 #endif
997 #endif
998 #ifdef NTFS_SB_MAGIC
998 #ifdef NTFS_SB_MAGIC
999 if (pbuf->f_type == NTFS_SB_MAGIC)
999 if (pbuf->f_type == NTFS_SB_MAGIC)
1000 return "ntfs-sb";
1000 return "ntfs-sb";
1001 #endif
1001 #endif
1002 #ifdef OCFS2_SUPER_MAGIC
1002 #ifdef OCFS2_SUPER_MAGIC
1003 if (pbuf->f_type == OCFS2_SUPER_MAGIC)
1003 if (pbuf->f_type == OCFS2_SUPER_MAGIC)
1004 return "ocfs2";
1004 return "ocfs2";
1005 #endif
1005 #endif
1006 #ifdef OPENPROM_SUPER_MAGIC
1006 #ifdef OPENPROM_SUPER_MAGIC
1007 if (pbuf->f_type == OPENPROM_SUPER_MAGIC)
1007 if (pbuf->f_type == OPENPROM_SUPER_MAGIC)
1008 return "openprom";
1008 return "openprom";
1009 #endif
1009 #endif
1010 #ifdef OVERLAYFS_SUPER_MAGIC
1010 #ifdef OVERLAYFS_SUPER_MAGIC
1011 if (pbuf->f_type == OVERLAYFS_SUPER_MAGIC)
1011 if (pbuf->f_type == OVERLAYFS_SUPER_MAGIC)
1012 return "overlay";
1012 return "overlay";
1013 #endif
1013 #endif
1014 #ifdef PIPEFS_MAGIC
1014 #ifdef PIPEFS_MAGIC
1015 if (pbuf->f_type == PIPEFS_MAGIC)
1015 if (pbuf->f_type == PIPEFS_MAGIC)
1016 return "pipefs";
1016 return "pipefs";
1017 #endif
1017 #endif
1018 #ifdef PROC_SUPER_MAGIC
1018 #ifdef PROC_SUPER_MAGIC
1019 if (pbuf->f_type == PROC_SUPER_MAGIC)
1019 if (pbuf->f_type == PROC_SUPER_MAGIC)
1020 return "proc";
1020 return "proc";
1021 #endif
1021 #endif
1022 #ifdef PSTOREFS_MAGIC
1022 #ifdef PSTOREFS_MAGIC
1023 if (pbuf->f_type == PSTOREFS_MAGIC)
1023 if (pbuf->f_type == PSTOREFS_MAGIC)
1024 return "pstorefs";
1024 return "pstorefs";
1025 #endif
1025 #endif
1026 #ifdef QNX4_SUPER_MAGIC
1026 #ifdef QNX4_SUPER_MAGIC
1027 if (pbuf->f_type == QNX4_SUPER_MAGIC)
1027 if (pbuf->f_type == QNX4_SUPER_MAGIC)
1028 return "qnx4";
1028 return "qnx4";
1029 #endif
1029 #endif
1030 #ifdef QNX6_SUPER_MAGIC
1030 #ifdef QNX6_SUPER_MAGIC
1031 if (pbuf->f_type == QNX6_SUPER_MAGIC)
1031 if (pbuf->f_type == QNX6_SUPER_MAGIC)
1032 return "qnx6";
1032 return "qnx6";
1033 #endif
1033 #endif
1034 #ifdef RAMFS_MAGIC
1034 #ifdef RAMFS_MAGIC
1035 if (pbuf->f_type == RAMFS_MAGIC)
1035 if (pbuf->f_type == RAMFS_MAGIC)
1036 return "ramfs";
1036 return "ramfs";
1037 #endif
1037 #endif
1038 #ifdef REISERFS_SUPER_MAGIC
1038 #ifdef REISERFS_SUPER_MAGIC
1039 if (pbuf->f_type == REISERFS_SUPER_MAGIC)
1039 if (pbuf->f_type == REISERFS_SUPER_MAGIC)
1040 return "reiserfs";
1040 return "reiserfs";
1041 #endif
1041 #endif
1042 #ifdef ROMFS_MAGIC
1042 #ifdef ROMFS_MAGIC
1043 if (pbuf->f_type == ROMFS_MAGIC)
1043 if (pbuf->f_type == ROMFS_MAGIC)
1044 return "romfs";
1044 return "romfs";
1045 #endif
1045 #endif
1046 #ifdef SECURITYFS_MAGIC
1046 #ifdef SECURITYFS_MAGIC
1047 if (pbuf->f_type == SECURITYFS_MAGIC)
1047 if (pbuf->f_type == SECURITYFS_MAGIC)
1048 return "securityfs";
1048 return "securityfs";
1049 #endif
1049 #endif
1050 #ifdef SELINUX_MAGIC
1050 #ifdef SELINUX_MAGIC
1051 if (pbuf->f_type == SELINUX_MAGIC)
1051 if (pbuf->f_type == SELINUX_MAGIC)
1052 return "selinux";
1052 return "selinux";
1053 #endif
1053 #endif
1054 #ifdef SMACK_MAGIC
1054 #ifdef SMACK_MAGIC
1055 if (pbuf->f_type == SMACK_MAGIC)
1055 if (pbuf->f_type == SMACK_MAGIC)
1056 return "smack";
1056 return "smack";
1057 #endif
1057 #endif
1058 #ifdef SMB_SUPER_MAGIC
1058 #ifdef SMB_SUPER_MAGIC
1059 if (pbuf->f_type == SMB_SUPER_MAGIC)
1059 if (pbuf->f_type == SMB_SUPER_MAGIC)
1060 return "smb";
1060 return "smb";
1061 #endif
1061 #endif
1062 #ifdef SOCKFS_MAGIC
1062 #ifdef SOCKFS_MAGIC
1063 if (pbuf->f_type == SOCKFS_MAGIC)
1063 if (pbuf->f_type == SOCKFS_MAGIC)
1064 return "sockfs";
1064 return "sockfs";
1065 #endif
1065 #endif
1066 #ifdef SQUASHFS_MAGIC
1066 #ifdef SQUASHFS_MAGIC
1067 if (pbuf->f_type == SQUASHFS_MAGIC)
1067 if (pbuf->f_type == SQUASHFS_MAGIC)
1068 return "squashfs";
1068 return "squashfs";
1069 #endif
1069 #endif
1070 #ifdef SYSFS_MAGIC
1070 #ifdef SYSFS_MAGIC
1071 if (pbuf->f_type == SYSFS_MAGIC)
1071 if (pbuf->f_type == SYSFS_MAGIC)
1072 return "sysfs";
1072 return "sysfs";
1073 #endif
1073 #endif
1074 #ifdef SYSV2_SUPER_MAGIC
1074 #ifdef SYSV2_SUPER_MAGIC
1075 if (pbuf->f_type == SYSV2_SUPER_MAGIC)
1075 if (pbuf->f_type == SYSV2_SUPER_MAGIC)
1076 return "sysv2";
1076 return "sysv2";
1077 #endif
1077 #endif
1078 #ifdef SYSV4_SUPER_MAGIC
1078 #ifdef SYSV4_SUPER_MAGIC
1079 if (pbuf->f_type == SYSV4_SUPER_MAGIC)
1079 if (pbuf->f_type == SYSV4_SUPER_MAGIC)
1080 return "sysv4";
1080 return "sysv4";
1081 #endif
1081 #endif
1082 #ifdef TMPFS_MAGIC
1082 #ifdef TMPFS_MAGIC
1083 if (pbuf->f_type == TMPFS_MAGIC)
1083 if (pbuf->f_type == TMPFS_MAGIC)
1084 return "tmpfs";
1084 return "tmpfs";
1085 #endif
1085 #endif
1086 #ifdef UDF_SUPER_MAGIC
1086 #ifdef UDF_SUPER_MAGIC
1087 if (pbuf->f_type == UDF_SUPER_MAGIC)
1087 if (pbuf->f_type == UDF_SUPER_MAGIC)
1088 return "udf";
1088 return "udf";
1089 #endif
1089 #endif
1090 #ifdef UFS_MAGIC
1090 #ifdef UFS_MAGIC
1091 if (pbuf->f_type == UFS_MAGIC)
1091 if (pbuf->f_type == UFS_MAGIC)
1092 return "ufs";
1092 return "ufs";
1093 #endif
1093 #endif
1094 #ifdef USBDEVICE_SUPER_MAGIC
1094 #ifdef USBDEVICE_SUPER_MAGIC
1095 if (pbuf->f_type == USBDEVICE_SUPER_MAGIC)
1095 if (pbuf->f_type == USBDEVICE_SUPER_MAGIC)
1096 return "usbdevice";
1096 return "usbdevice";
1097 #endif
1097 #endif
1098 #ifdef V9FS_MAGIC
1098 #ifdef V9FS_MAGIC
1099 if (pbuf->f_type == V9FS_MAGIC)
1099 if (pbuf->f_type == V9FS_MAGIC)
1100 return "v9fs";
1100 return "v9fs";
1101 #endif
1101 #endif
1102 #ifdef VXFS_SUPER_MAGIC
1102 #ifdef VXFS_SUPER_MAGIC
1103 if (pbuf->f_type == VXFS_SUPER_MAGIC)
1103 if (pbuf->f_type == VXFS_SUPER_MAGIC)
1104 return "vxfs";
1104 return "vxfs";
1105 #endif
1105 #endif
1106 #ifdef XENFS_SUPER_MAGIC
1106 #ifdef XENFS_SUPER_MAGIC
1107 if (pbuf->f_type == XENFS_SUPER_MAGIC)
1107 if (pbuf->f_type == XENFS_SUPER_MAGIC)
1108 return "xenfs";
1108 return "xenfs";
1109 #endif
1109 #endif
1110 #ifdef XENIX_SUPER_MAGIC
1110 #ifdef XENIX_SUPER_MAGIC
1111 if (pbuf->f_type == XENIX_SUPER_MAGIC)
1111 if (pbuf->f_type == XENIX_SUPER_MAGIC)
1112 return "xenix";
1112 return "xenix";
1113 #endif
1113 #endif
1114 #ifdef XFS_SUPER_MAGIC
1114 #ifdef XFS_SUPER_MAGIC
1115 if (pbuf->f_type == XFS_SUPER_MAGIC)
1115 if (pbuf->f_type == XFS_SUPER_MAGIC)
1116 return "xfs";
1116 return "xfs";
1117 #endif
1117 #endif
1118 /* End of Linux filesystems */
1118 /* End of Linux filesystems */
1119 return NULL;
1119 return NULL;
1120 }
1120 }
1121 #endif /* def HAVE_LINUX_STATFS */
1121 #endif /* def HAVE_LINUX_STATFS */
1122
1122
1123 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
1123 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
1124 /* given a directory path, return filesystem type name (best-effort) */
1124 /* given a directory path, return filesystem type name (best-effort) */
1125 static PyObject *getfstype(PyObject *self, PyObject *args)
1125 static PyObject *getfstype(PyObject *self, PyObject *args)
1126 {
1126 {
1127 const char *path = NULL;
1127 const char *path = NULL;
1128 struct statfs buf;
1128 struct statfs buf;
1129 int r;
1129 int r;
1130 if (!PyArg_ParseTuple(args, PY23("s", "y"), &path))
1130 if (!PyArg_ParseTuple(args, PY23("s", "y"), &path))
1131 return NULL;
1131 return NULL;
1132
1132
1133 memset(&buf, 0, sizeof(buf));
1133 memset(&buf, 0, sizeof(buf));
1134 r = statfs(path, &buf);
1134 r = statfs(path, &buf);
1135 if (r != 0)
1135 if (r != 0)
1136 return PyErr_SetFromErrno(PyExc_OSError);
1136 return PyErr_SetFromErrno(PyExc_OSError);
1137 return Py_BuildValue(PY23("s", "y"), describefstype(&buf));
1137 return Py_BuildValue(PY23("s", "y"), describefstype(&buf));
1138 }
1138 }
1139 #endif /* defined(HAVE_LINUX_STATFS) || defined(HAVE_BSD_STATFS) */
1139 #endif /* defined(HAVE_LINUX_STATFS) || defined(HAVE_BSD_STATFS) */
1140
1140
1141 #if defined(HAVE_BSD_STATFS)
1141 #if defined(HAVE_BSD_STATFS)
1142 /* given a directory path, return filesystem mount point (best-effort) */
1142 /* given a directory path, return filesystem mount point (best-effort) */
1143 static PyObject *getfsmountpoint(PyObject *self, PyObject *args)
1143 static PyObject *getfsmountpoint(PyObject *self, PyObject *args)
1144 {
1144 {
1145 const char *path = NULL;
1145 const char *path = NULL;
1146 struct statfs buf;
1146 struct statfs buf;
1147 int r;
1147 int r;
1148 if (!PyArg_ParseTuple(args, PY23("s", "y"), &path))
1148 if (!PyArg_ParseTuple(args, PY23("s", "y"), &path))
1149 return NULL;
1149 return NULL;
1150
1150
1151 memset(&buf, 0, sizeof(buf));
1151 memset(&buf, 0, sizeof(buf));
1152 r = statfs(path, &buf);
1152 r = statfs(path, &buf);
1153 if (r != 0)
1153 if (r != 0)
1154 return PyErr_SetFromErrno(PyExc_OSError);
1154 return PyErr_SetFromErrno(PyExc_OSError);
1155 return Py_BuildValue(PY23("s", "y"), buf.f_mntonname);
1155 return Py_BuildValue(PY23("s", "y"), buf.f_mntonname);
1156 }
1156 }
1157 #endif /* defined(HAVE_BSD_STATFS) */
1157 #endif /* defined(HAVE_BSD_STATFS) */
1158
1158
1159 static PyObject *unblocksignal(PyObject *self, PyObject *args)
1159 static PyObject *unblocksignal(PyObject *self, PyObject *args)
1160 {
1160 {
1161 int sig = 0;
1161 int sig = 0;
1162 sigset_t set;
1162 sigset_t set;
1163 int r;
1163 int r;
1164 if (!PyArg_ParseTuple(args, "i", &sig))
1164 if (!PyArg_ParseTuple(args, "i", &sig))
1165 return NULL;
1165 return NULL;
1166 r = sigemptyset(&set);
1166 r = sigemptyset(&set);
1167 if (r != 0)
1167 if (r != 0)
1168 return PyErr_SetFromErrno(PyExc_OSError);
1168 return PyErr_SetFromErrno(PyExc_OSError);
1169 r = sigaddset(&set, sig);
1169 r = sigaddset(&set, sig);
1170 if (r != 0)
1170 if (r != 0)
1171 return PyErr_SetFromErrno(PyExc_OSError);
1171 return PyErr_SetFromErrno(PyExc_OSError);
1172 r = sigprocmask(SIG_UNBLOCK, &set, NULL);
1172 r = sigprocmask(SIG_UNBLOCK, &set, NULL);
1173 if (r != 0)
1173 if (r != 0)
1174 return PyErr_SetFromErrno(PyExc_OSError);
1174 return PyErr_SetFromErrno(PyExc_OSError);
1175 Py_RETURN_NONE;
1175 Py_RETURN_NONE;
1176 }
1176 }
1177
1177
1178 #endif /* ndef _WIN32 */
1178 #endif /* ndef _WIN32 */
1179
1179
1180 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
1180 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
1181 {
1181 {
1182 PyObject *statobj = NULL; /* initialize - optional arg */
1182 PyObject *statobj = NULL; /* initialize - optional arg */
1183 PyObject *skipobj = NULL; /* initialize - optional arg */
1183 PyObject *skipobj = NULL; /* initialize - optional arg */
1184 char *path, *skip = NULL;
1184 char *path, *skip = NULL;
1185 Py_ssize_t plen;
1185 Py_ssize_t plen;
1186 int wantstat;
1186 int wantstat;
1187
1187
1188 static char *kwlist[] = {"path", "stat", "skip", NULL};
1188 static char *kwlist[] = {"path", "stat", "skip", NULL};
1189
1189
1190 if (!PyArg_ParseTupleAndKeywords(args, kwargs, PY23("s#|OO:listdir",
1190 if (!PyArg_ParseTupleAndKeywords(args, kwargs, PY23("s#|OO:listdir",
1191 "y#|OO:listdir"),
1191 "y#|OO:listdir"),
1192 kwlist, &path, &plen, &statobj, &skipobj))
1192 kwlist, &path, &plen, &statobj, &skipobj))
1193 return NULL;
1193 return NULL;
1194
1194
1195 wantstat = statobj && PyObject_IsTrue(statobj);
1195 wantstat = statobj && PyObject_IsTrue(statobj);
1196
1196
1197 if (skipobj && skipobj != Py_None) {
1197 if (skipobj && skipobj != Py_None) {
1198 skip = PyBytes_AsString(skipobj);
1198 skip = PyBytes_AsString(skipobj);
1199 if (!skip)
1199 if (!skip)
1200 return NULL;
1200 return NULL;
1201 }
1201 }
1202
1202
1203 return _listdir(path, plen, wantstat, skip);
1203 return _listdir(path, plen, wantstat, skip);
1204 }
1204 }
1205
1205
1206 #ifdef _WIN32
1206 #ifdef _WIN32
1207 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
1207 static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
1208 {
1208 {
1209 static char *kwlist[] = {"name", "mode", "buffering", NULL};
1209 static char *kwlist[] = {"name", "mode", "buffering", NULL};
1210 PyObject *file_obj = NULL;
1210 PyObject *file_obj = NULL;
1211 char *name = NULL;
1211 char *name = NULL;
1212 char *mode = "rb";
1212 char *mode = "rb";
1213 DWORD access = 0;
1213 DWORD access = 0;
1214 DWORD creation;
1214 DWORD creation;
1215 HANDLE handle;
1215 HANDLE handle;
1216 int fd, flags = 0;
1216 int fd, flags = 0;
1217 int bufsize = -1;
1217 int bufsize = -1;
1218 char m0, m1, m2;
1218 char m0, m1, m2;
1219 char fpmode[4];
1219 char fpmode[4];
1220 int fppos = 0;
1220 int fppos = 0;
1221 int plus;
1221 int plus;
1222 #ifndef IS_PY3K
1223 FILE *fp;
1222 FILE *fp;
1224 #endif
1225
1223
1226 if (!PyArg_ParseTupleAndKeywords(args, kwds, PY23("et|si:posixfile",
1224 if (!PyArg_ParseTupleAndKeywords(args, kwds, PY23("et|si:posixfile",
1227 "et|yi:posixfile"),
1225 "et|yi:posixfile"),
1228 kwlist,
1226 kwlist,
1229 Py_FileSystemDefaultEncoding,
1227 Py_FileSystemDefaultEncoding,
1230 &name, &mode, &bufsize))
1228 &name, &mode, &bufsize))
1231 return NULL;
1229 return NULL;
1232
1230
1233 m0 = mode[0];
1231 m0 = mode[0];
1234 m1 = m0 ? mode[1] : '\0';
1232 m1 = m0 ? mode[1] : '\0';
1235 m2 = m1 ? mode[2] : '\0';
1233 m2 = m1 ? mode[2] : '\0';
1236 plus = m1 == '+' || m2 == '+';
1234 plus = m1 == '+' || m2 == '+';
1237
1235
1238 fpmode[fppos++] = m0;
1236 fpmode[fppos++] = m0;
1239 if (m1 == 'b' || m2 == 'b') {
1237 if (m1 == 'b' || m2 == 'b') {
1240 flags = _O_BINARY;
1238 flags = _O_BINARY;
1241 fpmode[fppos++] = 'b';
1239 fpmode[fppos++] = 'b';
1242 }
1240 }
1243 else
1241 else
1244 flags = _O_TEXT;
1242 flags = _O_TEXT;
1245 if (m0 == 'r' && !plus) {
1243 if (m0 == 'r' && !plus) {
1246 flags |= _O_RDONLY;
1244 flags |= _O_RDONLY;
1247 access = GENERIC_READ;
1245 access = GENERIC_READ;
1248 } else {
1246 } else {
1249 /*
1247 /*
1250 work around http://support.microsoft.com/kb/899149 and
1248 work around http://support.microsoft.com/kb/899149 and
1251 set _O_RDWR for 'w' and 'a', even if mode has no '+'
1249 set _O_RDWR for 'w' and 'a', even if mode has no '+'
1252 */
1250 */
1253 flags |= _O_RDWR;
1251 flags |= _O_RDWR;
1254 access = GENERIC_READ | GENERIC_WRITE;
1252 access = GENERIC_READ | GENERIC_WRITE;
1255 fpmode[fppos++] = '+';
1253 fpmode[fppos++] = '+';
1256 }
1254 }
1257 fpmode[fppos++] = '\0';
1255 fpmode[fppos++] = '\0';
1258
1256
1259 switch (m0) {
1257 switch (m0) {
1260 case 'r':
1258 case 'r':
1261 creation = OPEN_EXISTING;
1259 creation = OPEN_EXISTING;
1262 break;
1260 break;
1263 case 'w':
1261 case 'w':
1264 creation = CREATE_ALWAYS;
1262 creation = CREATE_ALWAYS;
1265 break;
1263 break;
1266 case 'a':
1264 case 'a':
1267 creation = OPEN_ALWAYS;
1265 creation = OPEN_ALWAYS;
1268 flags |= _O_APPEND;
1266 flags |= _O_APPEND;
1269 break;
1267 break;
1270 default:
1268 default:
1271 PyErr_Format(PyExc_ValueError,
1269 PyErr_Format(PyExc_ValueError,
1272 "mode string must begin with one of 'r', 'w', "
1270 "mode string must begin with one of 'r', 'w', "
1273 "or 'a', not '%c'", m0);
1271 "or 'a', not '%c'", m0);
1274 goto bail;
1272 goto bail;
1275 }
1273 }
1276
1274
1277 handle = CreateFile(name, access,
1275 handle = CreateFile(name, access,
1278 FILE_SHARE_READ | FILE_SHARE_WRITE |
1276 FILE_SHARE_READ | FILE_SHARE_WRITE |
1279 FILE_SHARE_DELETE,
1277 FILE_SHARE_DELETE,
1280 NULL,
1278 NULL,
1281 creation,
1279 creation,
1282 FILE_ATTRIBUTE_NORMAL,
1280 FILE_ATTRIBUTE_NORMAL,
1283 0);
1281 0);
1284
1282
1285 if (handle == INVALID_HANDLE_VALUE) {
1283 if (handle == INVALID_HANDLE_VALUE) {
1286 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
1284 PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
1287 goto bail;
1285 goto bail;
1288 }
1286 }
1289
1287
1290 fd = _open_osfhandle((intptr_t)handle, flags);
1288 fd = _open_osfhandle((intptr_t)handle, flags);
1291
1289
1292 if (fd == -1) {
1290 if (fd == -1) {
1293 CloseHandle(handle);
1291 CloseHandle(handle);
1294 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
1292 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
1295 goto bail;
1293 goto bail;
1296 }
1294 }
1297 #ifndef IS_PY3K
1298 fp = _fdopen(fd, fpmode);
1295 fp = _fdopen(fd, fpmode);
1299 if (fp == NULL) {
1296 if (fp == NULL) {
1300 _close(fd);
1297 _close(fd);
1301 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
1298 PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
1302 goto bail;
1299 goto bail;
1303 }
1300 }
1304
1301
1305 file_obj = PyFile_FromFile(fp, name, mode, fclose);
1302 file_obj = PyFile_FromFile(fp, name, mode, fclose);
1306 if (file_obj == NULL) {
1303 if (file_obj == NULL) {
1307 fclose(fp);
1304 fclose(fp);
1308 goto bail;
1305 goto bail;
1309 }
1306 }
1310
1307
1311 PyFile_SetBufSize(file_obj, bufsize);
1308 PyFile_SetBufSize(file_obj, bufsize);
1312 #else
1313 file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
1314 if (file_obj == NULL)
1315 goto bail;
1316 #endif
1317 bail:
1309 bail:
1318 PyMem_Free(name);
1310 PyMem_Free(name);
1319 return file_obj;
1311 return file_obj;
1320 }
1312 }
1321 #endif
1313 #endif
1322
1314
1323 #ifdef __APPLE__
1315 #ifdef __APPLE__
1324 #include <ApplicationServices/ApplicationServices.h>
1316 #include <ApplicationServices/ApplicationServices.h>
1325
1317
1326 static PyObject *isgui(PyObject *self)
1318 static PyObject *isgui(PyObject *self)
1327 {
1319 {
1328 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
1320 CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
1329
1321
1330 if (dict != NULL) {
1322 if (dict != NULL) {
1331 CFRelease(dict);
1323 CFRelease(dict);
1332 Py_RETURN_TRUE;
1324 Py_RETURN_TRUE;
1333 } else {
1325 } else {
1334 Py_RETURN_FALSE;
1326 Py_RETURN_FALSE;
1335 }
1327 }
1336 }
1328 }
1337 #endif
1329 #endif
1338
1330
1339 static char osutil_doc[] = "Native operating system services.";
1331 static char osutil_doc[] = "Native operating system services.";
1340
1332
1341 static PyMethodDef methods[] = {
1333 static PyMethodDef methods[] = {
1342 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
1334 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
1343 "list a directory\n"},
1335 "list a directory\n"},
1344 #ifdef _WIN32
1336 #ifdef _WIN32
1345 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
1337 {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
1346 "Open a file with POSIX-like semantics.\n"
1338 "Open a file with POSIX-like semantics.\n"
1347 "On error, this function may raise either a WindowsError or an IOError."},
1339 "On error, this function may raise either a WindowsError or an IOError."},
1348 #else
1340 #else
1349 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
1341 {"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
1350 "stat a series of files or symlinks\n"
1342 "stat a series of files or symlinks\n"
1351 "Returns None for non-existent entries and entries of other types.\n"},
1343 "Returns None for non-existent entries and entries of other types.\n"},
1352 #ifdef CMSG_LEN
1344 #ifdef CMSG_LEN
1353 {"recvfds", (PyCFunction)recvfds, METH_VARARGS,
1345 {"recvfds", (PyCFunction)recvfds, METH_VARARGS,
1354 "receive list of file descriptors via socket\n"},
1346 "receive list of file descriptors via socket\n"},
1355 #endif
1347 #endif
1356 #ifndef SETPROCNAME_USE_NONE
1348 #ifndef SETPROCNAME_USE_NONE
1357 {"setprocname", (PyCFunction)setprocname, METH_VARARGS,
1349 {"setprocname", (PyCFunction)setprocname, METH_VARARGS,
1358 "set process title (best-effort)\n"},
1350 "set process title (best-effort)\n"},
1359 #endif
1351 #endif
1360 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
1352 #if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
1361 {"getfstype", (PyCFunction)getfstype, METH_VARARGS,
1353 {"getfstype", (PyCFunction)getfstype, METH_VARARGS,
1362 "get filesystem type (best-effort)\n"},
1354 "get filesystem type (best-effort)\n"},
1363 #endif
1355 #endif
1364 #if defined(HAVE_BSD_STATFS)
1356 #if defined(HAVE_BSD_STATFS)
1365 {"getfsmountpoint", (PyCFunction)getfsmountpoint, METH_VARARGS,
1357 {"getfsmountpoint", (PyCFunction)getfsmountpoint, METH_VARARGS,
1366 "get filesystem mount point (best-effort)\n"},
1358 "get filesystem mount point (best-effort)\n"},
1367 #endif
1359 #endif
1368 {"unblocksignal", (PyCFunction)unblocksignal, METH_VARARGS,
1360 {"unblocksignal", (PyCFunction)unblocksignal, METH_VARARGS,
1369 "change signal mask to unblock a given signal\n"},
1361 "change signal mask to unblock a given signal\n"},
1370 #endif /* ndef _WIN32 */
1362 #endif /* ndef _WIN32 */
1371 #ifdef __APPLE__
1363 #ifdef __APPLE__
1372 {
1364 {
1373 "isgui", (PyCFunction)isgui, METH_NOARGS,
1365 "isgui", (PyCFunction)isgui, METH_NOARGS,
1374 "Is a CoreGraphics session available?"
1366 "Is a CoreGraphics session available?"
1375 },
1367 },
1376 #endif
1368 #endif
1377 {NULL, NULL}
1369 {NULL, NULL}
1378 };
1370 };
1379
1371
1380 static const int version = 4;
1372 static const int version = 4;
1381
1373
1382 static struct PyModuleDef osutil_module = {
1374 static struct PyModuleDef osutil_module = {
1383 PyModuleDef_HEAD_INIT,
1375 PyModuleDef_HEAD_INIT,
1384 "osutil",
1376 "osutil",
1385 osutil_doc,
1377 osutil_doc,
1386 -1,
1378 -1,
1387 methods
1379 methods
1388 };
1380 };
1389
1381
1390 PyMODINIT_FUNC PyInit_osutil(void)
1382 PyMODINIT_FUNC PyInit_osutil(void)
1391 {
1383 {
1392 PyObject *m;
1384 PyObject *m;
1393 if (PyType_Ready(&listdir_stat_type) < 0)
1385 if (PyType_Ready(&listdir_stat_type) < 0)
1394 return NULL;
1386 return NULL;
1395
1387
1396 m = PyModule_Create(&osutil_module);
1388 m = PyModule_Create(&osutil_module);
1397 PyModule_AddIntConstant(m, "version", version);
1389 PyModule_AddIntConstant(m, "version", version);
1398 return m;
1390 return m;
1399 }
1391 }
General Comments 0
You need to be logged in to leave comments. Login now