[PATCH] osutil: implementation for Win32

Adrian Buehlmann adrian at cadifra.com
Tue Sep 9 18:51:34 UTC 2008


# HG changeset patch
# User Petr Kodl <petrkodl at gmail.com>
# Date 1220959680 14400
# Node ID 020fe75b47f569a29c25f8a5fef7451100d72772
# Parent  9141bebefe3ed0498ff07271214bfca8b4eb0d27
osutil: implementation for Win32

diff --git a/mercurial/osutil.c b/mercurial/osutil.c
--- a/mercurial/osutil.c
+++ b/mercurial/osutil.c
@@ -9,17 +9,42 @@
 
 #define _ATFILE_SOURCE
 #include <Python.h>
+#ifdef _WIN32
+#include <windows.h>
+#else
 #include <dirent.h>
 #include <fcntl.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#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
 
 #define listdir_slot(name) \
     static PyObject *listdir_stat_##name(PyObject *self, void *x) \
@@ -30,7 +55,15 @@
 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)
 
@@ -95,6 +128,153 @@
 	0,                         /* tp_alloc */
 	listdir_stat_new,          /* tp_new */
 };
+
+#ifdef _WIN32
+
+static int to_python_time(FILETIME* ms_time)
+{
+	/* this is number of 100-nanoseconds between epoch and January 1 1601 */
+	static __int64 a0 = (__int64)134774L * (__int64)24L
+						* (__int64)3600L * (__int64)1000L
+						* (__int64)1000L * (__int64)10L;
+	/* conversion factor back to 1s resolution required by Python ctime */
+	static __int64 a1 = 1000 * 1000 * 10;
+	__int64 tmp;
+	memcpy(&tmp, ms_time, sizeof(__int64));
+	return (int)((tmp - a0) / a1);
+}
+
+static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+	PyObject *statobj = NULL;
+	PyObject *list = NULL;
+	PyObject *items = NULL;
+	PyObject *ctor_args = NULL;
+	PyObject *item0 = NULL;
+	PyObject *item1 = NULL;
+	PyObject *py_st = NULL;
+
+	HANDLE fh = INVALID_HANDLE_VALUE;
+	WIN32_FIND_DATAA fd;
+
+	char path[_MAX_PATH + 1];
+	char *buffer = path;
+	int plen = _MAX_PATH - 2;
+
+	int keepstat = 0;
+
+	static char *kwlist[] = {"path", "stat", NULL};
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "et#|O:listdir",
+			kwlist, Py_FileSystemDefaultEncoding, &buffer, &plen, &statobj))
+		goto error;
+
+	keepstat = statobj && PyObject_IsTrue(statobj);
+
+	if (plen > 0) {
+		char c = path[plen-1];
+		if (c != ':' && c != '/' && c != '\\')
+			path[plen++] = '\\';
+	}
+
+	strcpy(path + plen, "*");
+
+	fh = FindFirstFileA(path, &fd);
+	if (INVALID_HANDLE_VALUE == fh) {
+		PyErr_SetExcFromWindowsErr(PyExc_OSError, GetLastError());
+		goto error;
+	}
+
+	list = PyList_New(0);
+	ctor_args = PyTuple_New(0);
+
+	if (!list || !ctor_args) {
+		PyErr_NoMemory();
+		goto error;
+	}
+
+	do {
+		int isdir = fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+		int isro  = fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY;
+
+		if (isdir && (!strcmp(fd.cFileName, ".")
+						|| !strcmp(fd.cFileName, "..")))
+			continue;
+
+		items = PyTuple_New(keepstat ? 3 : 2);
+
+		item0 = PyString_FromString(fd.cFileName);
+		item1 = PyInt_FromLong(isdir ? _S_IFDIR : _S_IFREG);
+
+		if (!items || !item0 || !item1) {
+			PyErr_NoMemory();
+			goto error;
+		}
+
+		PyTuple_SetItem(items, 0, item0);
+		PyTuple_SetItem(items, 1, item1);
+		item0 = item1 = NULL;
+
+		if (keepstat) {
+			struct hg_stat* stp = NULL;
+
+			py_st = PyObject_CallObject(
+						(PyObject *)&listdir_stat_type, ctor_args);
+
+			if (!py_st) {
+				PyErr_NoMemory();
+				goto error;
+			}
+
+			stp = &((struct listdir_stat *)py_st)->st;
+			stp->st_dev = 0;
+			stp->st_nlink = 0;
+			stp->st_mtime = to_python_time(&fd.ftLastWriteTime);
+			stp->st_ctime = to_python_time(&fd.ftCreationTime);
+			stp->st_size = isdir ? 0 :
+						(((__int64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow;
+			stp->st_mode = (isdir ? (S_IFDIR | 0111) : S_IFREG)
+							| (isro ? 0444 : 0666);
+
+			PyTuple_SET_ITEM(items, 2, py_st);
+			py_st = NULL;
+		}
+
+		if (PyList_Append(list, items))
+			goto error;
+
+		Py_XDECREF(items);
+		items = NULL;
+	}
+	while (FindNextFileA(fh, &fd));
+
+	if (GetLastError() != ERROR_NO_MORE_FILES || !FindClose(fh)) {
+		PyErr_SetExcFromWindowsErr(PyExc_OSError, GetLastError());
+		goto error;
+	}
+
+	fh = INVALID_HANDLE_VALUE;
+
+	if (PyList_Sort(list))
+		goto error;
+
+	goto ok;
+
+ error:
+	Py_XDECREF(list);
+	list = NULL;
+	Py_XDECREF(items);
+	Py_XDECREF(item0);
+	Py_XDECREF(item1);
+	if (fh != INVALID_HANDLE_VALUE)
+		FindClose(fh);
+
+ ok:
+	Py_XDECREF(ctor_args);
+	return list;
+}
+
+#else
 
 static PyObject *listfiles(PyObject *list, DIR *dir,
 			   int keep_stat, int *need_stat)
@@ -296,6 +476,7 @@
 	return err ? err : list;
 }
 
+#endif
 
 static char osutil_doc[] = "Native operating system services.";
 
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -102,6 +102,12 @@
             'hgext.highlight']
 
 try:
+    import msvcrt
+    ext_modules.append(Extension('mercurial.osutil', ['mercurial/osutil.c']))
+except ImportError:
+    pass
+
+try:
     import posix
     ext_modules.append(Extension('mercurial.osutil', ['mercurial/osutil.c']))
 



More information about the Mercurial-devel mailing list