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