mercurial/osutil.c
changeset 7056 2c1f18b88b6a
parent 7034 0d513661d6c2
child 7059 6a76cf980999
equal deleted inserted replaced
7055:0f4564b4cc2c 7056:2c1f18b88b6a
     7  the GNU General Public License, incorporated herein by reference.
     7  the GNU General Public License, incorporated herein by reference.
     8 */
     8 */
     9 
     9 
    10 #define _ATFILE_SOURCE
    10 #define _ATFILE_SOURCE
    11 #include <Python.h>
    11 #include <Python.h>
       
    12 #ifdef _WIN32
       
    13 #include <windows.h>
       
    14 #else
    12 #include <dirent.h>
    15 #include <dirent.h>
    13 #include <fcntl.h>
    16 #include <fcntl.h>
    14 #include <string.h>
    17 #include <string.h>
    15 #include <sys/stat.h>
    18 #include <sys/stat.h>
    16 #include <sys/types.h>
    19 #include <sys/types.h>
    17 #include <unistd.h>
    20 #include <unistd.h>
    18 
    21 #endif
       
    22 
       
    23 #ifdef _WIN32
       
    24 /*
       
    25 stat struct compatible with hg expectations
       
    26 Mercurial only uses st_mode, st_size and st_mtime
       
    27 the rest is kept to minimize changes between implementations
       
    28 */
       
    29 struct hg_stat {
       
    30 	int st_dev;
       
    31 	int st_mode;
       
    32 	int st_nlink;
       
    33 	__int64 st_size;
       
    34 	int st_mtime;
       
    35 	int st_ctime;
       
    36 };
       
    37 struct listdir_stat {
       
    38 	PyObject_HEAD
       
    39 	struct hg_stat st;
       
    40 };
       
    41 #else
    19 struct listdir_stat {
    42 struct listdir_stat {
    20 	PyObject_HEAD
    43 	PyObject_HEAD
    21 	struct stat st;
    44 	struct stat st;
    22 };
    45 };
       
    46 #endif
    23 
    47 
    24 #define listdir_slot(name) \
    48 #define listdir_slot(name) \
    25     static PyObject *listdir_stat_##name(PyObject *self, void *x) \
    49     static PyObject *listdir_stat_##name(PyObject *self, void *x) \
    26     { \
    50     { \
    27         return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
    51         return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
    28     }
    52     }
    29 
    53 
    30 listdir_slot(st_dev)
    54 listdir_slot(st_dev)
    31 listdir_slot(st_mode)
    55 listdir_slot(st_mode)
    32 listdir_slot(st_nlink)
    56 listdir_slot(st_nlink)
       
    57 #ifdef _WIN32
       
    58 static PyObject *listdir_stat_st_size(PyObject *self, void *x)
       
    59 {
       
    60 	return PyLong_FromLongLong(
       
    61 		(PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size);
       
    62 }
       
    63 #else
    33 listdir_slot(st_size)
    64 listdir_slot(st_size)
       
    65 #endif
    34 listdir_slot(st_mtime)
    66 listdir_slot(st_mtime)
    35 listdir_slot(st_ctime)
    67 listdir_slot(st_ctime)
    36 
    68 
    37 static struct PyGetSetDef listdir_stat_getsets[] = {
    69 static struct PyGetSetDef listdir_stat_getsets[] = {
    38 	{"st_dev", listdir_stat_st_dev, 0, 0, 0},
    70 	{"st_dev", listdir_stat_st_dev, 0, 0, 0},
    94 	0,                         /* tp_init */
   126 	0,                         /* tp_init */
    95 	0,                         /* tp_alloc */
   127 	0,                         /* tp_alloc */
    96 	listdir_stat_new,          /* tp_new */
   128 	listdir_stat_new,          /* tp_new */
    97 };
   129 };
    98 
   130 
       
   131 #ifdef _WIN32
       
   132 
       
   133 static int to_python_time(const FILETIME *tm)
       
   134 {
       
   135 	/* number of seconds between epoch and January 1 1601 */
       
   136 	const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L;
       
   137 	/* conversion factor from 100ns to 1s */
       
   138 	const __int64 a1 = 10000000;
       
   139 	/* explicit (int) cast to suspend compiler warnings */
       
   140 	return (int)((((__int64)tm->dwHighDateTime << 32)
       
   141 			+ tm->dwLowDateTime) / a1 - a0);
       
   142 }
       
   143 
       
   144 static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat)
       
   145 {
       
   146 	PyObject *py_st;
       
   147 	struct hg_stat *stp;
       
   148 
       
   149 	int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
       
   150 		? _S_IFDIR : _S_IFREG;
       
   151 
       
   152 	if (!wantstat)
       
   153 		return Py_BuildValue("si", fd->cFileName, kind);
       
   154 
       
   155 	py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL);
       
   156 	if (!py_st)
       
   157 		return NULL;
       
   158 
       
   159 	stp = &((struct listdir_stat *)py_st)->st;
       
   160 	/*
       
   161 	use kind as st_mode
       
   162 	rwx bits on Win32 are meaningless
       
   163 	and Hg does not use them anyway
       
   164 	*/
       
   165 	stp->st_mode  = kind;
       
   166 	stp->st_mtime = to_python_time(&fd->ftLastWriteTime);
       
   167 	stp->st_ctime = to_python_time(&fd->ftCreationTime);
       
   168 	if (kind == _S_IFREG)
       
   169 		stp->st_size =	((__int64)fd->nFileSizeHigh << 32)
       
   170 				+ fd->nFileSizeLow;
       
   171 	return Py_BuildValue("siN", fd->cFileName,
       
   172 		kind, py_st);
       
   173 }
       
   174 
       
   175 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
       
   176 {
       
   177 	PyObject *rval = NULL; /* initialize - return value */
       
   178 	PyObject *statobj = NULL; /* initialize - optional arg */
       
   179 	PyObject *list;
       
   180 	HANDLE fh;
       
   181 	WIN32_FIND_DATAA fd;
       
   182 	char *path, *pattern, *skip = NULL;
       
   183 	int plen, wantstat;
       
   184 
       
   185 	static char *kwlist[] = {"path", "stat", "skip", NULL};
       
   186 
       
   187 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|Os:listdir",
       
   188 			kwlist, &path, &plen, &statobj, &skip))
       
   189 		goto error_parse;
       
   190 
       
   191 	wantstat = statobj && PyObject_IsTrue(statobj);
       
   192 
       
   193 	/* build the path + \* pattern string */
       
   194 	pattern = malloc(plen+3); /* path + \* + \0 */
       
   195 	if (!pattern) {
       
   196 		PyErr_NoMemory();
       
   197 		goto error_parse;
       
   198 	}
       
   199 	strcpy(pattern, path);
       
   200 
       
   201 	if (plen > 0) {
       
   202 		char c = path[plen-1];
       
   203 		if (c != ':' && c != '/' && c != '\\')
       
   204 			pattern[plen++] = '\\';
       
   205 	}
       
   206 	strcpy(pattern + plen, "*");
       
   207 
       
   208 	fh = FindFirstFileA(pattern, &fd);
       
   209 	if (fh == INVALID_HANDLE_VALUE) {
       
   210 		PyErr_SetExcFromWindowsErrWithFilename(PyExc_OSError,
       
   211 							GetLastError(),
       
   212 							path);
       
   213 		goto error_file;
       
   214 	}
       
   215 
       
   216 	list = PyList_New(0);
       
   217 	if (!list)
       
   218 		goto error_list;
       
   219 
       
   220 	do {
       
   221 		PyObject *item;
       
   222 
       
   223 		if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
       
   224 			if (!strcmp(fd.cFileName, ".")
       
   225 			|| !strcmp(fd.cFileName, ".."))
       
   226 				continue;
       
   227 
       
   228 			if (skip && !strcmp(fd.cFileName, skip)) {
       
   229 				rval = PyList_New(0);
       
   230 				goto error;
       
   231 			}
       
   232 		}
       
   233 
       
   234 		item = make_item(&fd, wantstat);
       
   235 		if (!item)
       
   236 			goto error;
       
   237 
       
   238 		if (PyList_Append(list, item)) {
       
   239 			Py_XDECREF(item);
       
   240 			goto error;
       
   241 		}
       
   242 
       
   243 		Py_XDECREF(item);
       
   244 	} while (FindNextFileA(fh, &fd));
       
   245 
       
   246 	if (GetLastError() != ERROR_NO_MORE_FILES) {
       
   247 		PyErr_SetExcFromWindowsErrWithFilename(PyExc_OSError,
       
   248 							GetLastError(),
       
   249 							path);
       
   250 		goto error;
       
   251 	}
       
   252 
       
   253 	rval = list;
       
   254 	Py_XINCREF(rval);
       
   255 error:
       
   256 	Py_XDECREF(list);
       
   257 error_list:
       
   258 	FindClose(fh);
       
   259 error_file:
       
   260 	free(pattern);
       
   261 error_parse:
       
   262 	return rval;
       
   263 }
       
   264 
       
   265 #else
       
   266 
    99 int entkind(struct dirent *ent)
   267 int entkind(struct dirent *ent)
   100 {
   268 {
   101 #ifdef DT_REG
   269 #ifdef DT_REG
   102 	switch (ent->d_type) {
   270 	switch (ent->d_type) {
   103 	case DT_REG: return S_IFREG;
   271 	case DT_REG: return S_IFREG;
   212 #endif
   380 #endif
   213 error_parse:
   381 error_parse:
   214 	return ret;
   382 	return ret;
   215 }
   383 }
   216 
   384 
       
   385 #endif /* ndef _WIN32 */
       
   386 
   217 static char osutil_doc[] = "Native operating system services.";
   387 static char osutil_doc[] = "Native operating system services.";
   218 
   388 
   219 static PyMethodDef methods[] = {
   389 static PyMethodDef methods[] = {
   220 	{"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
   390 	{"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
   221 	 "list a directory\n"},
   391 	 "list a directory\n"},