[PATCH] osutil.c: Win32 implementation - make coding style Linux kernel compliant

Petr Kodl petrkodl at gmail.com
Mon Sep 8 16:37:13 CDT 2008


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

diff -r 9141bebefe3e -r 878cdfe38f73 mercurial/osutil.c
--- a/mercurial/osutil.c	Mon Sep 08 14:22:14 2008 +0200
+++ b/mercurial/osutil.c	Mon Sep 08 17:34:49 2008 -0400
@@ -9,16 +9,40 @@
 
 #define _ATFILE_SOURCE
 #include <Python.h>
+#include <string.h>
+#ifdef _WIN32
+#include <windows.h>
+#include <malloc.h>   /* for _alloca */
+#else
 #include <dirent.h>
 #include <fcntl.h>
-#include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#endif
+
+#ifdef _WIN32
+/*
+minimal stat struct compatible with hg expectations
+supporting large files (64 bit size)
+*/
+struct non_posix_stat
+{
+	int     st_dev;
+	int     st_mode;
+	int     st_nlink;
+	__int64 st_size;
+	int     st_mtime;
+	int     st_ctime;
+};
+typedef struct non_posix_stat hg_stat;
+#else
+typedef struct stat hg_stat;
+#endif
 
 struct listdir_stat {
 	PyObject_HEAD
-	struct stat st;
+	hg_stat st;
 };
 
 #define listdir_slot(name) \
@@ -30,9 +54,17 @@
 listdir_slot(st_dev)
 listdir_slot(st_mode)
 listdir_slot(st_nlink)
-listdir_slot(st_size)
 listdir_slot(st_mtime)
 listdir_slot(st_ctime)
+#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
 
 static struct PyGetSetDef listdir_stat_getsets[] = {
 	{"st_dev", listdir_stat_st_dev, 0, 0, 0},
@@ -95,6 +127,206 @@
 	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, s_time, izeof(__int64));
+	return (int)((tmp - a0) / a1);
+}
+
+static int allow_unicode()
+{
+	static int allow = -1;
+	/* unicode supported for NT */
+	if (allow==-1) allow = (GetVersion() < 0x80000000) ? 1 : 0;
+	return allow;
+}
+
+static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+	PyObject *pathobj = NULL, *statobj = NULL, *list = NULL, *items = NULL;
+	PyObject *ctor_args = NULL, *item0 = NULL, *item1 = NULL, *py_st = NULL;
+	HANDLE    fh = INVALID_HANDLE_VALUE;
+	WIN32_FIND_DATAA fd_a;
+	WIN32_FIND_DATAW fd_w;
+	hg_stat* stp=NULL;
+	int keepstat = 0, nicode = 0;
+	static char *kwlist[] = { "path", "stat", NULL };
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:listdir",
+		kwlist, &pathobj, &statobj))
+		goto error;
+
+	keepstat= statobj && PyObject_IsTrue(statobj);
+	unicode = allow_unicode() && PyUnicode_CheckExact(pathobj);
+	
+	if (unicode)
+	{
+		Py_ssize_t len = PyUnicode_GET_SIZE(pathobj);
+		wchar_t *wpath = _alloca((len+3)*sizeof(wchar_t));
+		memset(wpath, 0, (len+3)*sizeof(wchar_t));
+		if (PyUnicode_AsWideChar((PyUnicodeObject*)pathobj, wpath, len)!=len)
+			goto error;
+		if (len>0 && wpath[len-1]!=L':'
+			&& wpath[len - 1] != L'/' && wpath[len - 1] != L'\\')
+			wpath[len++] = L'\\';
+		wcscpy(wpath+len, L"*");
+		fh = FindFirstFileW(wpath, &fd_w);
+	}
+	else if (PyString_CheckExact(pathobj))
+	{
+		char path[_MAX_PATH+3];
+		Py_ssize_t len = PyString_GET_SIZE(pathobj);
+		if (len < _MAX_PATH)
+		{
+			strcpy(path, PyString_AS_STRING(pathobj));
+			if (len > 0 && path[len - 1] != ':'
+				&& path[len - 1] != '/' && path[len - 1] != '\\')
+				path[len++]='\\';
+			strcpy(path + len, "*");
+		}
+		if ((1 + len) > _MAX_PATH)
+		{
+			PyErr_Format( PyExc_ValueError, listdir - ANSI path length can not exceed %d characters", MAX_PATH);
+			goto error;
+		}
+		fh = FindFirstFileA(path, &fd_a);
+	}
+	else
+	{
+		PyErr_SetString(PyExc_TypeError,
+		"listdir - expected string or unicode as first argument");
+		goto error;
+	}
+	
+	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
+	{
+		#define FD(NAME) (unicode ? fd_w.NAME : fd_a.NAME)
+		int isdir = (FD(dwFileAttributes) & FILE_ATTRIBUTE_DIRECTORY);
+		int isro  = (FD(dwFileAttributes) & FILE_ATTRIBUTE_READONLY);
+		
+		if (isdir &&
+			(( unicode && (!wcscmp(fd_w.cFileName, L".") || wcscmp(fd_w.cFileName, L"..")))
+			|| (!unicode && (!strcmp(fd_a.cFileName, ".")  || !strcmp(fd_a.cFileName, "..")))))
+			continue;
+
+		items = PyTuple_New(keepstat ? 3 : 2);
+		item0 = unicode ?
+				PyUnicode_FromWideChar(fd_w.cFileName, wcslen(fd_w.cFileName))
+				: PyString_FromString(fd_a.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)
+		{
+			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_mtime = to_python_time(unicode
+							? &fd_w.ftLastWriteTime
+							: &fd_a.ftLastWriteTime);
+			stp->st_ctime = to_python_time(unicode
+							? &fd_w.ftCreationTime
+							: &fd_a.ftCreationTime);
+			stp->st_dev = 0;
+			stp->st_size = 0;
+			stp->st_mode = (isdir ? (S_IFDIR | 0111) : S_IFREG)
+							| (isro ? 0444 : 0666);
+			if (!isdir)
+			{
+				stp->st_size = ((__int64)FD(nFileSizeHigh) << 32)
+								+ FD(nFileSizeLow);
+				if (!unicode)
+				{
+					char* dot = strrchr(fd_a.cFileName, '.');
+					if (dot)
+					{
+						if ( !stricmp(dot, ".bat") || !stricmp(dot, ".cmd")
+							|| !stricmp(dot, ".exe") || !stricmp(dot, ".com"))
+						stp->st_mode |= 0111;
+					}
+				}
+				else
+				{
+					wchar_t* dot = wcsrchr(fd_w.cFileName, L'.');
+					if (dot)
+					{
+						if ( !_wcsicmp(dot, L".bat") || !_wcsicmp(dot, L".cmd")
+							|| !_wcsicmp(dot, L".exe") || !_wcsicmp(dot, L".com"))
+						stp->st_mode |= 0111;
+					}
+				}
+			}
+			PyTuple_SET_ITEM(items, 2, py_st);
+			py_st = NULL;
+		}
+		
+		if (PyList_Append(list, items))
+			goto error;
+
+		Py_XDECREF(items);
+		items = NULL;
+		#undef FD
+	}
+	while (unicode ? FindNextFileW(fh, &fd_w) : FindNextFileA(fh, &fd_a));
+
+	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)
@@ -295,7 +527,7 @@
 		closedir(dir);
 	return err ? err : list;
 }
-
+#endif
 
 static char osutil_doc[] = "Native operating system services.";
 
diff -r 9141bebefe3e -r 878cdfe38f73 setup.py
--- a/setup.py	Mon Sep 08 14:22:14 2008 +0200
+++ b/setup.py	Mon Sep 08 17:34:49 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