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