[PATCH] osutil.c: one more refactoring

Petr Kodl petrkodl at gmail.com
Thu Sep 11 00:36:11 CDT 2008


# HG changeset patch
# User Petr Kodl <petrkodl at gmail.com>
# Date 1221111205 14400
# Node ID 8cb79f6c5fa8bc61c5daf4bbfb24257b84c348a1
# Parent  75ce89ed3b6e0789f4d95017b34d6d1060cc5d92
osutil: implementation for Win32

diff -r 75ce89ed3b6e -r 8cb79f6c5fa8 mercurial/osutil.c
--- a/mercurial/osutil.c	Wed Sep 10 09:41:42 2008 -0400
+++ b/mercurial/osutil.c	Thu Sep 11 01:33:25 2008 -0400
@@ -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,144 @@
 	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 shutdown compiler warnings */
+	return (int)((((__int64)tm->dwHighDateTime << 32)
+			+ tm->dwLowDateTime) / a1 - a0);
+}
+
+static PyObject* make_item(const WIN32_FIND_DATAA* fd, int wantstat)
+{
+	PyObject *rval = 0; /* initialize - return value */
+	PyObject *py_st;
+	struct hg_stat* stp;
+
+	int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+		? _S_IFDIR : _S_IFREG;
+
+	if (!wantstat) {
+		rval = Py_BuildValue("si",fd->cFileName,kind);
+		goto done;
+	}
+
+	py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
+	if (!py_st)
+		goto done;
+
+	stp = &((struct listdir_stat *)py_st)->st;
+	/*
+	rwx bits on Win32 are meaningless
+	and Hg does not use them
+	so restrict the value to kind
+	*/
+	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;
+	rval = Py_BuildValue("siO", fd->cFileName,
+		kind, py_st);
+	Py_XDECREF(py_st);
+done:
+	return rval;
+}
+
+static PyObject* listdir(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+	PyObject *rval = NULL; /* initialize - return value */
+	PyObject *statobj = NULL; /* initialize - optional arg */
+	PyObject *list;
+	HANDLE fh;
+	WIN32_FIND_DATAA fd;
+
+	char *path;
+	int plen;
+	char *pattern;
+
+	int wantstat;
+
+	static char *kwlist[] = {"path", "stat", NULL};
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|O:listdir",
+			kwlist, &path, &plen, &statobj))
+		goto error_parse;
+
+	wantstat = statobj && PyObject_IsTrue(statobj);
+	pattern = malloc(plen+3); /* path + \* */
+	if (!pattern) {
+		PyErr_NoMemory();
+		goto error_parse;
+	}
+
+	strcpy(pattern,path);
+
+	if (plen > 0) {
+		char c = path[plen-1];
+		if (c != ':' && c != '/' && c != '\\')
+			pattern[plen++] = '\\';
+	}
+	strcpy(pattern + plen, "*");
+
+	fh = FindFirstFileA(pattern, &fd);
+	if (fh == INVALID_HANDLE_VALUE) {
+		PyErr_SetExcFromWindowsErrWithFilename(PyExc_OSError,
+							GetLastError(),
+							path);
+		goto error_file;
+	}
+
+	list = PyList_New(0);
+	if (!list)
+		goto error_list;
+
+	do {
+		PyObject *item;
+
+		if ( (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+			&& (!strcmp(fd.cFileName, ".")
+			|| !strcmp(fd.cFileName, "..")))
+			continue;
+
+		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_SetExcFromWindowsErrWithFilename(PyExc_OSError,
+							GetLastError(),
+							path);
+		goto error;
+	}
+	rval = list;
+	Py_XINCREF(list);
+error:
+	Py_XDECREF(list);
+error_list:
+	FindClose(fh);
+error_file:
+	free(pattern);
+error_parse:
+	return rval;
+}
+
+#else
 
 static PyObject *listfiles(PyObject *list, DIR *dir,
 			   int keep_stat, int *need_stat)
@@ -296,6 +467,7 @@
 	return err ? err : list;
 }
 
+#endif
 
 static char osutil_doc[] = "Native operating system services.";
 
diff -r 75ce89ed3b6e -r 8cb79f6c5fa8 setup.py
--- a/setup.py	Wed Sep 10 09:41:42 2008 -0400
+++ b/setup.py	Thu Sep 11 01:33:25 2008 -0400
@@ -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