mercurial/osutil.c
branchstable
changeset 33572 857876ebaed4
parent 33202 c1994c986d77
parent 33571 9a944e908ecf
child 33573 9e0fea06ae2c
--- a/mercurial/osutil.c	Wed Jul 05 11:24:22 2017 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1328 +0,0 @@
-/*
- osutil.c - native operating system services
-
- Copyright 2007 Matt Mackall and others
-
- This software may be used and distributed according to the terms of
- the GNU General Public License, incorporated herein by reference.
-*/
-
-#define _ATFILE_SOURCE
-#include <Python.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#ifdef _WIN32
-#include <windows.h>
-#include <io.h>
-#else
-#include <dirent.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#ifdef HAVE_LINUX_STATFS
-#include <linux/magic.h>
-#include <sys/vfs.h>
-#endif
-#ifdef HAVE_BSD_STATFS
-#include <sys/mount.h>
-#include <sys/param.h>
-#endif
-#endif
-
-#ifdef __APPLE__
-#include <sys/attr.h>
-#include <sys/vnode.h>
-#endif
-
-#include "util.h"
-
-/* some platforms lack the PATH_MAX definition (eg. GNU/Hurd) */
-#ifndef PATH_MAX
-#define PATH_MAX 4096
-#endif
-
-#ifdef _WIN32
-/*
-stat struct compatible with hg expectations
-Mercurial only uses st_mode, st_size and st_mtime
-the rest is kept to minimize changes between implementations
-*/
-struct hg_stat {
-	int st_dev;
-	int st_mode;
-	int st_nlink;
-	__int64 st_size;
-	int st_mtime;
-	int st_ctime;
-};
-struct listdir_stat {
-	PyObject_HEAD
-	struct hg_stat st;
-};
-#else
-struct listdir_stat {
-	PyObject_HEAD
-	struct stat st;
-};
-#endif
-
-#ifdef IS_PY3K
-#define listdir_slot(name) \
-	static PyObject *listdir_stat_##name(PyObject *self, void *x) \
-	{ \
-		return PyLong_FromLong(((struct listdir_stat *)self)->st.name); \
-	}
-#else
-#define listdir_slot(name) \
-	static PyObject *listdir_stat_##name(PyObject *self, void *x) \
-	{ \
-		return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
-	}
-#endif
-
-listdir_slot(st_dev)
-listdir_slot(st_mode)
-listdir_slot(st_nlink)
-#ifdef _WIN32
-static PyObject *listdir_stat_st_size(PyObject *self, void *x)
-{
-	return PyLong_FromLongLong(
-		(PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
-}
-#else
-listdir_slot(st_size)
-#endif
-listdir_slot(st_mtime)
-listdir_slot(st_ctime)
-
-static struct PyGetSetDef listdir_stat_getsets[] = {
-	{"st_dev", listdir_stat_st_dev, 0, 0, 0},
-	{"st_mode", listdir_stat_st_mode, 0, 0, 0},
-	{"st_nlink", listdir_stat_st_nlink, 0, 0, 0},
-	{"st_size", listdir_stat_st_size, 0, 0, 0},
-	{"st_mtime", listdir_stat_st_mtime, 0, 0, 0},
-	{"st_ctime", listdir_stat_st_ctime, 0, 0, 0},
-	{0, 0, 0, 0, 0}
-};
-
-static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
-{
-	return t->tp_alloc(t, 0);
-}
-
-static void listdir_stat_dealloc(PyObject *o)
-{
-	o->ob_type->tp_free(o);
-}
-
-static PyTypeObject listdir_stat_type = {
-	PyVarObject_HEAD_INIT(NULL, 0)
-	"osutil.stat",             /*tp_name*/
-	sizeof(struct listdir_stat), /*tp_basicsize*/
-	0,                         /*tp_itemsize*/
-	(destructor)listdir_stat_dealloc, /*tp_dealloc*/
-	0,                         /*tp_print*/
-	0,                         /*tp_getattr*/
-	0,                         /*tp_setattr*/
-	0,                         /*tp_compare*/
-	0,                         /*tp_repr*/
-	0,                         /*tp_as_number*/
-	0,                         /*tp_as_sequence*/
-	0,                         /*tp_as_mapping*/
-	0,                         /*tp_hash */
-	0,                         /*tp_call*/
-	0,                         /*tp_str*/
-	0,                         /*tp_getattro*/
-	0,                         /*tp_setattro*/
-	0,                         /*tp_as_buffer*/
-	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
-	"stat objects",            /* tp_doc */
-	0,                         /* tp_traverse */
-	0,                         /* tp_clear */
-	0,                         /* tp_richcompare */
-	0,                         /* tp_weaklistoffset */
-	0,                         /* tp_iter */
-	0,                         /* tp_iternext */
-	0,                         /* tp_methods */
-	0,                         /* tp_members */
-	listdir_stat_getsets,      /* tp_getset */
-	0,                         /* tp_base */
-	0,                         /* tp_dict */
-	0,                         /* tp_descr_get */
-	0,                         /* tp_descr_set */
-	0,                         /* tp_dictoffset */
-	0,                         /* tp_init */
-	0,                         /* tp_alloc */
-	listdir_stat_new,          /* tp_new */
-};
-
-#ifdef _WIN32
-
-static int to_python_time(const FILETIME *tm)
-{
-	/* number of seconds between epoch and January 1 1601 */
-	const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
-	/* conversion factor from 100ns to 1s */
-	const __int64 a1 = 10000000;
-	/* explicit (int) cast to suspend compiler warnings */
-	return (int)((((__int64)tm->dwHighDateTime << 32)
-			+ tm->dwLowDateTime) / a1 - a0);
-}
-
-static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
-{
-	PyObject *py_st;
-	struct hg_stat *stp;
-
-	int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-		? _S_IFDIR : _S_IFREG;
-
-	if (!wantstat)
-		return Py_BuildValue("si", fd->cFileName, kind);
-
-	py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
-	if (!py_st)
-		return NULL;
-
-	stp = &((struct listdir_stat *)py_st)->st;
-	/*
-	use kind as st_mode
-	rwx bits on Win32 are meaningless
-	and Hg does not use them anyway
-	*/
-	stp->st_mode  = kind;
-	stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
-	stp->st_ctime = to_python_time(&fd->ftCreationTime);
-	if (kind == _S_IFREG)
-		stp->st_size = ((__int64)fd->nFileSizeHigh << 32)
-				+ fd->nFileSizeLow;
-	return Py_BuildValue("siN", fd->cFileName,
-		kind, py_st);
-}
-
-static PyObject *_listdir(char *path, int plen, int wantstat, char *skip)
-{
-	PyObject *rval = NULL; /* initialize - return value */
-	PyObject *list;
-	HANDLE fh;
-	WIN32_FIND_DATAA fd;
-	char *pattern;
-
-	/* build the path + \* pattern string */
-	pattern = PyMem_Malloc(plen + 3); /* path + \* + \0 */
-	if (!pattern) {
-		PyErr_NoMemory();
-		goto error_nomem;
-	}
-	memcpy(pattern, path, plen);
-
-	if (plen > 0) {
-		char c = path[plen-1];
-		if (c != ':' && c != '/' && c != '\\')
-			pattern[plen++] = '\\';
-	}
-	pattern[plen++] = '*';
-	pattern[plen] = '\0';
-
-	fh = FindFirstFileA(pattern, &fd);
-	if (fh == INVALID_HANDLE_VALUE) {
-		PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
-		goto error_file;
-	}
-
-	list = PyList_New(0);
-	if (!list)
-		goto error_list;
-
-	do {
-		PyObject *item;
-
-		if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
-			if (!strcmp(fd.cFileName, ".")
-			|| !strcmp(fd.cFileName, ".."))
-				continue;
-
-			if (skip && !strcmp(fd.cFileName, skip)) {
-				rval = PyList_New(0);
-				goto error;
-			}
-		}
-
-		item = make_item(&fd, wantstat);
-		if (!item)
-			goto error;
-
-		if (PyList_Append(list, item)) {
-			Py_XDECREF(item);
-			goto error;
-		}
-
-		Py_XDECREF(item);
-	} while (FindNextFileA(fh, &fd));
-
-	if (GetLastError() != ERROR_NO_MORE_FILES) {
-		PyErr_SetFromWindowsErrWithFilename(GetLastError(), path);
-		goto error;
-	}
-
-	rval = list;
-	Py_XINCREF(rval);
-error:
-	Py_XDECREF(list);
-error_list:
-	FindClose(fh);
-error_file:
-	PyMem_Free(pattern);
-error_nomem:
-	return rval;
-}
-
-#else
-
-int entkind(struct dirent *ent)
-{
-#ifdef DT_REG
-	switch (ent->d_type) {
-	case DT_REG: return S_IFREG;
-	case DT_DIR: return S_IFDIR;
-	case DT_LNK: return S_IFLNK;
-	case DT_BLK: return S_IFBLK;
-	case DT_CHR: return S_IFCHR;
-	case DT_FIFO: return S_IFIFO;
-	case DT_SOCK: return S_IFSOCK;
-	}
-#endif
-	return -1;
-}
-
-static PyObject *makestat(const struct stat *st)
-{
-	PyObject *stat;
-
-	stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
-	if (stat)
-		memcpy(&((struct listdir_stat *)stat)->st, st, sizeof(*st));
-	return stat;
-}
-
-static PyObject *_listdir_stat(char *path, int pathlen, int keepstat,
-			       char *skip)
-{
-	PyObject *list, *elem, *stat = NULL, *ret = NULL;
-	char fullpath[PATH_MAX + 10];
-	int kind, err;
-	struct stat st;
-	struct dirent *ent;
-	DIR *dir;
-#ifdef AT_SYMLINK_NOFOLLOW
-	int dfd = -1;
-#endif
-
-	if (pathlen >= PATH_MAX) {
-		errno = ENAMETOOLONG;
-		PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
-		goto error_value;
-	}
-	strncpy(fullpath, path, PATH_MAX);
-	fullpath[pathlen] = '/';
-
-#ifdef AT_SYMLINK_NOFOLLOW
-	dfd = open(path, O_RDONLY);
-	if (dfd == -1) {
-		PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
-		goto error_value;
-	}
-	dir = fdopendir(dfd);
-#else
-	dir = opendir(path);
-#endif
-	if (!dir) {
-		PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
-		goto error_dir;
-	}
-
-	list = PyList_New(0);
-	if (!list)
-		goto error_list;
-
-	while ((ent = readdir(dir))) {
-		if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
-			continue;
-
-		kind = entkind(ent);
-		if (kind == -1 || keepstat) {
-#ifdef AT_SYMLINK_NOFOLLOW
-			err = fstatat(dfd, ent->d_name, &st,
-				      AT_SYMLINK_NOFOLLOW);
-#else
-			strncpy(fullpath + pathlen + 1, ent->d_name,
-				PATH_MAX - pathlen);
-			fullpath[PATH_MAX] = '\0';
-			err = lstat(fullpath, &st);
-#endif
-			if (err == -1) {
-				/* race with file deletion? */
-				if (errno == ENOENT)
-					continue;
-				strncpy(fullpath + pathlen + 1, ent->d_name,
-					PATH_MAX - pathlen);
-				fullpath[PATH_MAX] = 0;
-				PyErr_SetFromErrnoWithFilename(PyExc_OSError,
-							       fullpath);
-				goto error;
-			}
-			kind = st.st_mode & S_IFMT;
-		}
-
-		/* quit early? */
-		if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) {
-			ret = PyList_New(0);
-			goto error;
-		}
-
-		if (keepstat) {
-			stat = makestat(&st);
-			if (!stat)
-				goto error;
-			elem = Py_BuildValue("siN", ent->d_name, kind, stat);
-		} else
-			elem = Py_BuildValue("si", ent->d_name, kind);
-		if (!elem)
-			goto error;
-		stat = NULL;
-
-		PyList_Append(list, elem);
-		Py_DECREF(elem);
-	}
-
-	ret = list;
-	Py_INCREF(ret);
-
-error:
-	Py_DECREF(list);
-	Py_XDECREF(stat);
-error_list:
-	closedir(dir);
-	/* closedir also closes its dirfd */
-	goto error_value;
-error_dir:
-#ifdef AT_SYMLINK_NOFOLLOW
-	close(dfd);
-#endif
-error_value:
-	return ret;
-}
-
-#ifdef __APPLE__
-
-typedef struct {
-	u_int32_t length;
-	attrreference_t name;
-	fsobj_type_t obj_type;
-	struct timespec mtime;
-#if __LITTLE_ENDIAN__
-	mode_t access_mask;
-	uint16_t padding;
-#else
-	uint16_t padding;
-	mode_t access_mask;
-#endif
-	off_t size;
-} __attribute__((packed)) attrbuf_entry;
-
-int attrkind(attrbuf_entry *entry)
-{
-	switch (entry->obj_type) {
-	case VREG: return S_IFREG;
-	case VDIR: return S_IFDIR;
-	case VLNK: return S_IFLNK;
-	case VBLK: return S_IFBLK;
-	case VCHR: return S_IFCHR;
-	case VFIFO: return S_IFIFO;
-	case VSOCK: return S_IFSOCK;
-	}
-	return -1;
-}
-
-/* get these many entries at a time */
-#define LISTDIR_BATCH_SIZE 50
-
-static PyObject *_listdir_batch(char *path, int pathlen, int keepstat,
-				char *skip, bool *fallback)
-{
-	PyObject *list, *elem, *stat = NULL, *ret = NULL;
-	int kind, err;
-	unsigned long index;
-	unsigned int count, old_state, new_state;
-	bool state_seen = false;
-	attrbuf_entry *entry;
-	/* from the getattrlist(2) man page: a path can be no longer than
-	   (NAME_MAX * 3 + 1) bytes. Also, "The getattrlist() function will
-	   silently truncate attribute data if attrBufSize is too small." So
-	   pass in a buffer big enough for the worst case. */
-	char attrbuf[LISTDIR_BATCH_SIZE * (sizeof(attrbuf_entry) + NAME_MAX * 3 + 1)];
-	unsigned int basep_unused;
-
-	struct stat st;
-	int dfd = -1;
-
-	/* these must match the attrbuf_entry struct, otherwise you'll end up
-	   with garbage */
-	struct attrlist requested_attr = {0};
-	requested_attr.bitmapcount = ATTR_BIT_MAP_COUNT;
-	requested_attr.commonattr = (ATTR_CMN_NAME | ATTR_CMN_OBJTYPE |
-				     ATTR_CMN_MODTIME | ATTR_CMN_ACCESSMASK);
-	requested_attr.fileattr = ATTR_FILE_DATALENGTH;
-
-	*fallback = false;
-
-	if (pathlen >= PATH_MAX) {
-		errno = ENAMETOOLONG;
-		PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
-		goto error_value;
-	}
-
-	dfd = open(path, O_RDONLY);
-	if (dfd == -1) {
-		PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
-		goto error_value;
-	}
-
-	list = PyList_New(0);
-	if (!list)
-		goto error_dir;
-
-	do {
-		count = LISTDIR_BATCH_SIZE;
-		err = getdirentriesattr(dfd, &requested_attr, &attrbuf,
-					sizeof(attrbuf), &count, &basep_unused,
-					&new_state, 0);
-		if (err < 0) {
-			if (errno == ENOTSUP) {
-				/* We're on a filesystem that doesn't support
-				   getdirentriesattr. Fall back to the
-				   stat-based implementation. */
-				*fallback = true;
-			} else
-				PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
-			goto error;
-		}
-
-		if (!state_seen) {
-			old_state = new_state;
-			state_seen = true;
-		} else if (old_state != new_state) {
-			/* There's an edge case with getdirentriesattr. Consider
-			   the following initial list of files:
-
-			   a
-			   b
-			   <--
-			   c
-			   d
-
-			   If the iteration is paused at the arrow, and b is
-			   deleted before it is resumed, getdirentriesattr will
-			   not return d at all!  Ordinarily we're expected to
-			   restart the iteration from the beginning. To avoid
-			   getting stuck in a retry loop here, fall back to
-			   stat. */
-			*fallback = true;
-			goto error;
-		}
-
-		entry = (attrbuf_entry *)attrbuf;
-
-		for (index = 0; index < count; index++) {
-			char *filename = ((char *)&entry->name) +
-				entry->name.attr_dataoffset;
-
-			if (!strcmp(filename, ".") || !strcmp(filename, ".."))
-				continue;
-
-			kind = attrkind(entry);
-			if (kind == -1) {
-				PyErr_Format(PyExc_OSError,
-					     "unknown object type %u for file "
-					     "%s%s!",
-					     entry->obj_type, path, filename);
-				goto error;
-			}
-
-			/* quit early? */
-			if (skip && kind == S_IFDIR && !strcmp(filename, skip)) {
-				ret = PyList_New(0);
-				goto error;
-			}
-
-			if (keepstat) {
-				/* from the getattrlist(2) man page: "Only the
-				   permission bits ... are valid". */
-				st.st_mode = (entry->access_mask & ~S_IFMT) | kind;
-				st.st_mtime = entry->mtime.tv_sec;
-				st.st_size = entry->size;
-				stat = makestat(&st);
-				if (!stat)
-					goto error;
-				elem = Py_BuildValue("siN", filename, kind, stat);
-			} else
-				elem = Py_BuildValue("si", filename, kind);
-			if (!elem)
-				goto error;
-			stat = NULL;
-
-			PyList_Append(list, elem);
-			Py_DECREF(elem);
-
-			entry = (attrbuf_entry *)((char *)entry + entry->length);
-		}
-	} while (err == 0);
-
-	ret = list;
-	Py_INCREF(ret);
-
-error:
-	Py_DECREF(list);
-	Py_XDECREF(stat);
-error_dir:
-	close(dfd);
-error_value:
-	return ret;
-}
-
-#endif /* __APPLE__ */
-
-static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip)
-{
-#ifdef __APPLE__
-	PyObject *ret;
-	bool fallback = false;
-
-	ret = _listdir_batch(path, pathlen, keepstat, skip, &fallback);
-	if (ret != NULL || !fallback)
-		return ret;
-#endif
-	return _listdir_stat(path, pathlen, keepstat, skip);
-}
-
-static PyObject *statfiles(PyObject *self, PyObject *args)
-{
-	PyObject *names, *stats;
-	Py_ssize_t i, count;
-
-	if (!PyArg_ParseTuple(args, "O:statfiles", &names))
-		return NULL;
-
-	count = PySequence_Length(names);
-	if (count == -1) {
-		PyErr_SetString(PyExc_TypeError, "not a sequence");
-		return NULL;
-	}
-
-	stats = PyList_New(count);
-	if (stats == NULL)
-		return NULL;
-
-	for (i = 0; i < count; i++) {
-		PyObject *stat, *pypath;
-		struct stat st;
-		int ret, kind;
-		char *path;
-
-		/* With a large file count or on a slow filesystem,
-		   don't block signals for long (issue4878). */
-		if ((i % 1000) == 999 && PyErr_CheckSignals() == -1)
-			goto bail;
-
-		pypath = PySequence_GetItem(names, i);
-		if (!pypath)
-			goto bail;
-		path = PyBytes_AsString(pypath);
-		if (path == NULL) {
-			Py_DECREF(pypath);
-			PyErr_SetString(PyExc_TypeError, "not a string");
-			goto bail;
-		}
-		ret = lstat(path, &st);
-		Py_DECREF(pypath);
-		kind = st.st_mode & S_IFMT;
-		if (ret != -1 && (kind == S_IFREG || kind == S_IFLNK)) {
-			stat = makestat(&st);
-			if (stat == NULL)
-				goto bail;
-			PyList_SET_ITEM(stats, i, stat);
-		} else {
-			Py_INCREF(Py_None);
-			PyList_SET_ITEM(stats, i, Py_None);
-		}
-	}
-
-	return stats;
-
-bail:
-	Py_DECREF(stats);
-	return NULL;
-}
-
-/*
- * recvfds() simply does not release GIL during blocking io operation because
- * command server is known to be single-threaded.
- *
- * Old systems such as Solaris don't provide CMSG_LEN, msg_control, etc.
- * Currently, recvfds() is not supported on these platforms.
- */
-#ifdef CMSG_LEN
-
-static ssize_t recvfdstobuf(int sockfd, int **rfds, void *cbuf, size_t cbufsize)
-{
-	char dummy[1];
-	struct iovec iov = {dummy, sizeof(dummy)};
-	struct msghdr msgh = {0};
-	struct cmsghdr *cmsg;
-
-	msgh.msg_iov = &iov;
-	msgh.msg_iovlen = 1;
-	msgh.msg_control = cbuf;
-	msgh.msg_controllen = (socklen_t)cbufsize;
-	if (recvmsg(sockfd, &msgh, 0) < 0)
-		return -1;
-
-	for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg;
-	     cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
-		if (cmsg->cmsg_level != SOL_SOCKET ||
-		    cmsg->cmsg_type != SCM_RIGHTS)
-			continue;
-		*rfds = (int *)CMSG_DATA(cmsg);
-		return (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
-	}
-
-	*rfds = cbuf;
-	return 0;
-}
-
-static PyObject *recvfds(PyObject *self, PyObject *args)
-{
-	int sockfd;
-	int *rfds = NULL;
-	ssize_t rfdscount, i;
-	char cbuf[256];
-	PyObject *rfdslist = NULL;
-
-	if (!PyArg_ParseTuple(args, "i", &sockfd))
-		return NULL;
-
-	rfdscount = recvfdstobuf(sockfd, &rfds, cbuf, sizeof(cbuf));
-	if (rfdscount < 0)
-		return PyErr_SetFromErrno(PyExc_OSError);
-
-	rfdslist = PyList_New(rfdscount);
-	if (!rfdslist)
-		goto bail;
-	for (i = 0; i < rfdscount; i++) {
-		PyObject *obj = PyLong_FromLong(rfds[i]);
-		if (!obj)
-			goto bail;
-		PyList_SET_ITEM(rfdslist, i, obj);
-	}
-	return rfdslist;
-
-bail:
-	Py_XDECREF(rfdslist);
-	return NULL;
-}
-
-#endif /* CMSG_LEN */
-
-#if defined(HAVE_SETPROCTITLE)
-/* setproctitle is the first choice - available in FreeBSD */
-#define SETPROCNAME_USE_SETPROCTITLE
-#elif (defined(__linux__) || defined(__APPLE__)) && PY_MAJOR_VERSION == 2
-/* rewrite the argv buffer in place - works in Linux and OS X. Py_GetArgcArgv
- * in Python 3 returns the copied wchar_t **argv, thus unsupported. */
-#define SETPROCNAME_USE_ARGVREWRITE
-#else
-#define SETPROCNAME_USE_NONE
-#endif
-
-#ifndef SETPROCNAME_USE_NONE
-static PyObject *setprocname(PyObject *self, PyObject *args)
-{
-	const char *name = NULL;
-	if (!PyArg_ParseTuple(args, "s", &name))
-		return NULL;
-
-#if defined(SETPROCNAME_USE_SETPROCTITLE)
-	setproctitle("%s", name);
-#elif defined(SETPROCNAME_USE_ARGVREWRITE)
-	{
-		static char *argvstart = NULL;
-		static size_t argvsize = 0;
-		if (argvstart == NULL) {
-			int argc = 0, i;
-			char **argv = NULL;
-			char *argvend;
-			extern void Py_GetArgcArgv(int *argc, char ***argv);
-			Py_GetArgcArgv(&argc, &argv);
-
-			/* Check the memory we can use. Typically, argv[i] and
-			 * argv[i + 1] are continuous. */
-			argvend = argvstart = argv[0];
-			for (i = 0; i < argc; ++i) {
-				if (argv[i] > argvend || argv[i] < argvstart)
-					break; /* not continuous */
-				size_t len = strlen(argv[i]);
-				argvend = argv[i] + len + 1 /* '\0' */;
-			}
-			if (argvend > argvstart) /* sanity check */
-				argvsize = argvend - argvstart;
-		}
-
-		if (argvstart && argvsize > 1) {
-			int n = snprintf(argvstart, argvsize, "%s", name);
-			if (n >= 0 && (size_t)n < argvsize)
-				memset(argvstart + n, 0, argvsize - n);
-		}
-	}
-#endif
-
-	Py_RETURN_NONE;
-}
-#endif /* ndef SETPROCNAME_USE_NONE */
-
-#if defined(HAVE_BSD_STATFS)
-static const char *describefstype(const struct statfs *pbuf)
-{
-	/* BSD or OSX provides a f_fstypename field */
-	return pbuf->f_fstypename;
-}
-#elif defined(HAVE_LINUX_STATFS)
-static const char *describefstype(const struct statfs *pbuf)
-{
-	/* Begin of Linux filesystems */
-#ifdef ADFS_SUPER_MAGIC
-	if (pbuf->f_type == ADFS_SUPER_MAGIC)
-		return "adfs";
-#endif
-#ifdef AFFS_SUPER_MAGIC
-	if (pbuf->f_type == AFFS_SUPER_MAGIC)
-		return "affs";
-#endif
-#ifdef AUTOFS_SUPER_MAGIC
-	if (pbuf->f_type == AUTOFS_SUPER_MAGIC)
-		return "autofs";
-#endif
-#ifdef BDEVFS_MAGIC
-	if (pbuf->f_type == BDEVFS_MAGIC)
-		return "bdevfs";
-#endif
-#ifdef BEFS_SUPER_MAGIC
-	if (pbuf->f_type == BEFS_SUPER_MAGIC)
-		return "befs";
-#endif
-#ifdef BFS_MAGIC
-	if (pbuf->f_type == BFS_MAGIC)
-		return "bfs";
-#endif
-#ifdef BINFMTFS_MAGIC
-	if (pbuf->f_type == BINFMTFS_MAGIC)
-		return "binfmtfs";
-#endif
-#ifdef BTRFS_SUPER_MAGIC
-	if (pbuf->f_type == BTRFS_SUPER_MAGIC)
-		return "btrfs";
-#endif
-#ifdef CGROUP_SUPER_MAGIC
-	if (pbuf->f_type == CGROUP_SUPER_MAGIC)
-		return "cgroup";
-#endif
-#ifdef CIFS_MAGIC_NUMBER
-	if (pbuf->f_type == CIFS_MAGIC_NUMBER)
-		return "cifs";
-#endif
-#ifdef CODA_SUPER_MAGIC
-	if (pbuf->f_type == CODA_SUPER_MAGIC)
-		return "coda";
-#endif
-#ifdef COH_SUPER_MAGIC
-	if (pbuf->f_type == COH_SUPER_MAGIC)
-		return "coh";
-#endif
-#ifdef CRAMFS_MAGIC
-	if (pbuf->f_type == CRAMFS_MAGIC)
-		return "cramfs";
-#endif
-#ifdef DEBUGFS_MAGIC
-	if (pbuf->f_type == DEBUGFS_MAGIC)
-		return "debugfs";
-#endif
-#ifdef DEVFS_SUPER_MAGIC
-	if (pbuf->f_type == DEVFS_SUPER_MAGIC)
-		return "devfs";
-#endif
-#ifdef DEVPTS_SUPER_MAGIC
-	if (pbuf->f_type == DEVPTS_SUPER_MAGIC)
-		return "devpts";
-#endif
-#ifdef EFIVARFS_MAGIC
-	if (pbuf->f_type == EFIVARFS_MAGIC)
-		return "efivarfs";
-#endif
-#ifdef EFS_SUPER_MAGIC
-	if (pbuf->f_type == EFS_SUPER_MAGIC)
-		return "efs";
-#endif
-#ifdef EXT_SUPER_MAGIC
-	if (pbuf->f_type == EXT_SUPER_MAGIC)
-		return "ext";
-#endif
-#ifdef EXT2_OLD_SUPER_MAGIC
-	if (pbuf->f_type == EXT2_OLD_SUPER_MAGIC)
-		return "ext2";
-#endif
-#ifdef EXT2_SUPER_MAGIC
-	if (pbuf->f_type == EXT2_SUPER_MAGIC)
-		return "ext2";
-#endif
-#ifdef EXT3_SUPER_MAGIC
-	if (pbuf->f_type == EXT3_SUPER_MAGIC)
-		return "ext3";
-#endif
-#ifdef EXT4_SUPER_MAGIC
-	if (pbuf->f_type == EXT4_SUPER_MAGIC)
-		return "ext4";
-#endif
-#ifdef F2FS_SUPER_MAGIC
-	if (pbuf->f_type == F2FS_SUPER_MAGIC)
-		return "f2fs";
-#endif
-#ifdef FUSE_SUPER_MAGIC
-	if (pbuf->f_type == FUSE_SUPER_MAGIC)
-		return "fuse";
-#endif
-#ifdef FUTEXFS_SUPER_MAGIC
-	if (pbuf->f_type == FUTEXFS_SUPER_MAGIC)
-		return "futexfs";
-#endif
-#ifdef HFS_SUPER_MAGIC
-	if (pbuf->f_type == HFS_SUPER_MAGIC)
-		return "hfs";
-#endif
-#ifdef HOSTFS_SUPER_MAGIC
-	if (pbuf->f_type == HOSTFS_SUPER_MAGIC)
-		return "hostfs";
-#endif
-#ifdef HPFS_SUPER_MAGIC
-	if (pbuf->f_type == HPFS_SUPER_MAGIC)
-		return "hpfs";
-#endif
-#ifdef HUGETLBFS_MAGIC
-	if (pbuf->f_type == HUGETLBFS_MAGIC)
-		return "hugetlbfs";
-#endif
-#ifdef ISOFS_SUPER_MAGIC
-	if (pbuf->f_type == ISOFS_SUPER_MAGIC)
-		return "isofs";
-#endif
-#ifdef JFFS2_SUPER_MAGIC
-	if (pbuf->f_type == JFFS2_SUPER_MAGIC)
-		return "jffs2";
-#endif
-#ifdef JFS_SUPER_MAGIC
-	if (pbuf->f_type == JFS_SUPER_MAGIC)
-		return "jfs";
-#endif
-#ifdef MINIX_SUPER_MAGIC
-	if (pbuf->f_type == MINIX_SUPER_MAGIC)
-		return "minix";
-#endif
-#ifdef MINIX2_SUPER_MAGIC
-	if (pbuf->f_type == MINIX2_SUPER_MAGIC)
-		return "minix2";
-#endif
-#ifdef MINIX3_SUPER_MAGIC
-	if (pbuf->f_type == MINIX3_SUPER_MAGIC)
-		return "minix3";
-#endif
-#ifdef MQUEUE_MAGIC
-	if (pbuf->f_type == MQUEUE_MAGIC)
-		return "mqueue";
-#endif
-#ifdef MSDOS_SUPER_MAGIC
-	if (pbuf->f_type == MSDOS_SUPER_MAGIC)
-		return "msdos";
-#endif
-#ifdef NCP_SUPER_MAGIC
-	if (pbuf->f_type == NCP_SUPER_MAGIC)
-		return "ncp";
-#endif
-#ifdef NFS_SUPER_MAGIC
-	if (pbuf->f_type == NFS_SUPER_MAGIC)
-		return "nfs";
-#endif
-#ifdef NILFS_SUPER_MAGIC
-	if (pbuf->f_type == NILFS_SUPER_MAGIC)
-		return "nilfs";
-#endif
-#ifdef NTFS_SB_MAGIC
-	if (pbuf->f_type == NTFS_SB_MAGIC)
-		return "ntfs-sb";
-#endif
-#ifdef OCFS2_SUPER_MAGIC
-	if (pbuf->f_type == OCFS2_SUPER_MAGIC)
-		return "ocfs2";
-#endif
-#ifdef OPENPROM_SUPER_MAGIC
-	if (pbuf->f_type == OPENPROM_SUPER_MAGIC)
-		return "openprom";
-#endif
-#ifdef OVERLAYFS_SUPER_MAGIC
-	if (pbuf->f_type == OVERLAYFS_SUPER_MAGIC)
-		return "overlay";
-#endif
-#ifdef PIPEFS_MAGIC
-	if (pbuf->f_type == PIPEFS_MAGIC)
-		return "pipefs";
-#endif
-#ifdef PROC_SUPER_MAGIC
-	if (pbuf->f_type == PROC_SUPER_MAGIC)
-		return "proc";
-#endif
-#ifdef PSTOREFS_MAGIC
-	if (pbuf->f_type == PSTOREFS_MAGIC)
-		return "pstorefs";
-#endif
-#ifdef QNX4_SUPER_MAGIC
-	if (pbuf->f_type == QNX4_SUPER_MAGIC)
-		return "qnx4";
-#endif
-#ifdef QNX6_SUPER_MAGIC
-	if (pbuf->f_type == QNX6_SUPER_MAGIC)
-		return "qnx6";
-#endif
-#ifdef RAMFS_MAGIC
-	if (pbuf->f_type == RAMFS_MAGIC)
-		return "ramfs";
-#endif
-#ifdef REISERFS_SUPER_MAGIC
-	if (pbuf->f_type == REISERFS_SUPER_MAGIC)
-		return "reiserfs";
-#endif
-#ifdef ROMFS_MAGIC
-	if (pbuf->f_type == ROMFS_MAGIC)
-		return "romfs";
-#endif
-#ifdef SECURITYFS_MAGIC
-	if (pbuf->f_type == SECURITYFS_MAGIC)
-		return "securityfs";
-#endif
-#ifdef SELINUX_MAGIC
-	if (pbuf->f_type == SELINUX_MAGIC)
-		return "selinux";
-#endif
-#ifdef SMACK_MAGIC
-	if (pbuf->f_type == SMACK_MAGIC)
-		return "smack";
-#endif
-#ifdef SMB_SUPER_MAGIC
-	if (pbuf->f_type == SMB_SUPER_MAGIC)
-		return "smb";
-#endif
-#ifdef SOCKFS_MAGIC
-	if (pbuf->f_type == SOCKFS_MAGIC)
-		return "sockfs";
-#endif
-#ifdef SQUASHFS_MAGIC
-	if (pbuf->f_type == SQUASHFS_MAGIC)
-		return "squashfs";
-#endif
-#ifdef SYSFS_MAGIC
-	if (pbuf->f_type == SYSFS_MAGIC)
-		return "sysfs";
-#endif
-#ifdef SYSV2_SUPER_MAGIC
-	if (pbuf->f_type == SYSV2_SUPER_MAGIC)
-		return "sysv2";
-#endif
-#ifdef SYSV4_SUPER_MAGIC
-	if (pbuf->f_type == SYSV4_SUPER_MAGIC)
-		return "sysv4";
-#endif
-#ifdef TMPFS_MAGIC
-	if (pbuf->f_type == TMPFS_MAGIC)
-		return "tmpfs";
-#endif
-#ifdef UDF_SUPER_MAGIC
-	if (pbuf->f_type == UDF_SUPER_MAGIC)
-		return "udf";
-#endif
-#ifdef UFS_MAGIC
-	if (pbuf->f_type == UFS_MAGIC)
-		return "ufs";
-#endif
-#ifdef USBDEVICE_SUPER_MAGIC
-	if (pbuf->f_type == USBDEVICE_SUPER_MAGIC)
-		return "usbdevice";
-#endif
-#ifdef V9FS_MAGIC
-	if (pbuf->f_type == V9FS_MAGIC)
-		return "v9fs";
-#endif
-#ifdef VXFS_SUPER_MAGIC
-	if (pbuf->f_type == VXFS_SUPER_MAGIC)
-		return "vxfs";
-#endif
-#ifdef XENFS_SUPER_MAGIC
-	if (pbuf->f_type == XENFS_SUPER_MAGIC)
-		return "xenfs";
-#endif
-#ifdef XENIX_SUPER_MAGIC
-	if (pbuf->f_type == XENIX_SUPER_MAGIC)
-		return "xenix";
-#endif
-#ifdef XFS_SUPER_MAGIC
-	if (pbuf->f_type == XFS_SUPER_MAGIC)
-		return "xfs";
-#endif
-	/* End of Linux filesystems */
-	return NULL;
-}
-#endif /* def HAVE_LINUX_STATFS */
-
-#if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
-/* given a directory path, return filesystem type name (best-effort) */
-static PyObject *getfstype(PyObject *self, PyObject *args)
-{
-	const char *path = NULL;
-	struct statfs buf;
-	int r;
-	if (!PyArg_ParseTuple(args, "s", &path))
-		return NULL;
-
-	memset(&buf, 0, sizeof(buf));
-	r = statfs(path, &buf);
-	if (r != 0)
-		return PyErr_SetFromErrno(PyExc_OSError);
-	return Py_BuildValue("s", describefstype(&buf));
-}
-#endif /* defined(HAVE_LINUX_STATFS) || defined(HAVE_BSD_STATFS) */
-
-#endif /* ndef _WIN32 */
-
-static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
-{
-	PyObject *statobj = NULL; /* initialize - optional arg */
-	PyObject *skipobj = NULL; /* initialize - optional arg */
-	char *path, *skip = NULL;
-	int wantstat, plen;
-
-	static char *kwlist[] = {"path", "stat", "skip", NULL};
-
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir",
-			kwlist, &path, &plen, &statobj, &skipobj))
-		return NULL;
-
-	wantstat = statobj && PyObject_IsTrue(statobj);
-
-	if (skipobj && skipobj != Py_None) {
-		skip = PyBytes_AsString(skipobj);
-		if (!skip)
-			return NULL;
-	}
-
-	return _listdir(path, plen, wantstat, skip);
-}
-
-#ifdef _WIN32
-static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds)
-{
-	static char *kwlist[] = {"name", "mode", "buffering", NULL};
-	PyObject *file_obj = NULL;
-	char *name = NULL;
-	char *mode = "rb";
-	DWORD access = 0;
-	DWORD creation;
-	HANDLE handle;
-	int fd, flags = 0;
-	int bufsize = -1;
-	char m0, m1, m2;
-	char fpmode[4];
-	int fppos = 0;
-	int plus;
-	FILE *fp;
-
-	if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist,
-					 Py_FileSystemDefaultEncoding,
-					 &name, &mode, &bufsize))
-		return NULL;
-
-	m0 = mode[0];
-	m1 = m0 ? mode[1] : '\0';
-	m2 = m1 ? mode[2] : '\0';
-	plus = m1 == '+' || m2 == '+';
-
-	fpmode[fppos++] = m0;
-	if (m1 == 'b' || m2 == 'b') {
-		flags = _O_BINARY;
-		fpmode[fppos++] = 'b';
-	}
-	else
-		flags = _O_TEXT;
-	if (m0 == 'r' && !plus) {
-		flags |= _O_RDONLY;
-		access = GENERIC_READ;
-	} else {
-		/*
-		work around http://support.microsoft.com/kb/899149 and
-		set _O_RDWR for 'w' and 'a', even if mode has no '+'
-		*/
-		flags |= _O_RDWR;
-		access = GENERIC_READ | GENERIC_WRITE;
-		fpmode[fppos++] = '+';
-	}
-	fpmode[fppos++] = '\0';
-
-	switch (m0) {
-	case 'r':
-		creation = OPEN_EXISTING;
-		break;
-	case 'w':
-		creation = CREATE_ALWAYS;
-		break;
-	case 'a':
-		creation = OPEN_ALWAYS;
-		flags |= _O_APPEND;
-		break;
-	default:
-		PyErr_Format(PyExc_ValueError,
-			     "mode string must begin with one of 'r', 'w', "
-			     "or 'a', not '%c'", m0);
-		goto bail;
-	}
-
-	handle = CreateFile(name, access,
-			    FILE_SHARE_READ | FILE_SHARE_WRITE |
-			    FILE_SHARE_DELETE,
-			    NULL,
-			    creation,
-			    FILE_ATTRIBUTE_NORMAL,
-			    0);
-
-	if (handle == INVALID_HANDLE_VALUE) {
-		PyErr_SetFromWindowsErrWithFilename(GetLastError(), name);
-		goto bail;
-	}
-
-	fd = _open_osfhandle((intptr_t)handle, flags);
-
-	if (fd == -1) {
-		CloseHandle(handle);
-		PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
-		goto bail;
-	}
-#ifndef IS_PY3K
-	fp = _fdopen(fd, fpmode);
-	if (fp == NULL) {
-		_close(fd);
-		PyErr_SetFromErrnoWithFilename(PyExc_IOError, name);
-		goto bail;
-	}
-
-	file_obj = PyFile_FromFile(fp, name, mode, fclose);
-	if (file_obj == NULL) {
-		fclose(fp);
-		goto bail;
-	}
-
-	PyFile_SetBufSize(file_obj, bufsize);
-#else
-	file_obj = PyFile_FromFd(fd, name, mode, bufsize, NULL, NULL, NULL, 1);
-	if (file_obj == NULL)
-		goto bail;
-#endif
-bail:
-	PyMem_Free(name);
-	return file_obj;
-}
-#endif
-
-#ifdef __APPLE__
-#include <ApplicationServices/ApplicationServices.h>
-
-static PyObject *isgui(PyObject *self)
-{
-	CFDictionaryRef dict = CGSessionCopyCurrentDictionary();
-
-	if (dict != NULL) {
-		CFRelease(dict);
-		Py_RETURN_TRUE;
-	} else {
-		Py_RETURN_FALSE;
-	}
-}
-#endif
-
-static char osutil_doc[] = "Native operating system services.";
-
-static PyMethodDef methods[] = {
-	{"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
-	 "list a directory\n"},
-#ifdef _WIN32
-	{"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS,
-	 "Open a file with POSIX-like semantics.\n"
-"On error, this function may raise either a WindowsError or an IOError."},
-#else
-	{"statfiles", (PyCFunction)statfiles, METH_VARARGS | METH_KEYWORDS,
-	 "stat a series of files or symlinks\n"
-"Returns None for non-existent entries and entries of other types.\n"},
-#ifdef CMSG_LEN
-	{"recvfds", (PyCFunction)recvfds, METH_VARARGS,
-	 "receive list of file descriptors via socket\n"},
-#endif
-#ifndef SETPROCNAME_USE_NONE
-	{"setprocname", (PyCFunction)setprocname, METH_VARARGS,
-	 "set process title (best-effort)\n"},
-#endif
-#if defined(HAVE_BSD_STATFS) || defined(HAVE_LINUX_STATFS)
-	{"getfstype", (PyCFunction)getfstype, METH_VARARGS,
-	 "get filesystem type (best-effort)\n"},
-#endif
-#endif /* ndef _WIN32 */
-#ifdef __APPLE__
-	{
-		"isgui", (PyCFunction)isgui, METH_NOARGS,
-		"Is a CoreGraphics session available?"
-	},
-#endif
-	{NULL, NULL}
-};
-
-#ifdef IS_PY3K
-static struct PyModuleDef osutil_module = {
-	PyModuleDef_HEAD_INIT,
-	"osutil",
-	osutil_doc,
-	-1,
-	methods
-};
-
-PyMODINIT_FUNC PyInit_osutil(void)
-{
-	if (PyType_Ready(&listdir_stat_type) < 0)
-		return NULL;
-
-	return PyModule_Create(&osutil_module);
-}
-#else
-PyMODINIT_FUNC initosutil(void)
-{
-	if (PyType_Ready(&listdir_stat_type) == -1)
-		return;
-
-	Py_InitModule3("osutil", methods, osutil_doc);
-}
-#endif