##// END OF EJS Templates
osutil: move file list loop to its own function
osutil: move file list loop to its own function

File last commit:

r5427:dae6188e default
r5427:dae6188e default
Show More
osutil.c
307 lines | 7.3 KiB | text/x-c | CLexer
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 /*
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
Alexis S. L. Carvalho
osutil.c: include Python.h before the other headers...
r5397 #include <Python.h>
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 #include <alloca.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
struct listdir_stat {
Matt Mackall
osutil: cleanups...
r5421 PyObject_HEAD
struct stat st;
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 };
#define listdir_slot(name) \
static PyObject *listdir_stat_##name(PyObject *self, void *x) \
{ \
Matt Mackall
osutil: cleanups...
r5421 return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 }
listdir_slot(st_dev);
listdir_slot(st_mode);
listdir_slot(st_nlink);
listdir_slot(st_size);
listdir_slot(st_mtime);
listdir_slot(st_ctime);
static struct PyGetSetDef listdir_stat_getsets[] = {
Matt Mackall
osutil: cleanups...
r5421 {"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}
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 };
static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k)
{
Matt Mackall
osutil: cleanups...
r5421 return t->tp_alloc(t, 0);
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 }
static void listdir_stat_dealloc(PyObject *o)
{
Matt Mackall
osutil: cleanups...
r5421 o->ob_type->tp_free(o);
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 }
static PyTypeObject listdir_stat_type = {
Matt Mackall
osutil: cleanups...
r5421 PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"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 */
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 };
static inline int mode_to_kind(int mode)
{
Matt Mackall
osutil: cleanups...
r5421 if (S_ISREG(mode)) return S_IFREG;
if (S_ISDIR(mode)) return S_IFDIR;
if (S_ISLNK(mode)) return S_IFLNK;
if (S_ISBLK(mode)) return S_IFBLK;
if (S_ISCHR(mode)) return S_IFCHR;
if (S_ISFIFO(mode)) return S_IFIFO;
if (S_ISSOCK(mode)) return S_IFSOCK;
return mode;
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 }
Matt Mackall
osutil: move file list loop to its own function
r5427 static PyObject *listfiles(PyObject *list, DIR *dir, int stat, int *all)
{
struct dirent *ent;
PyObject *name, *py_kind, *val;
for (ent = readdir(dir); ent; ent = readdir(dir)) {
int kind = -1;
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))
continue;
#ifdef DT_REG
if (!stat)
switch (ent->d_type) {
case DT_REG: kind = S_IFREG; break;
case DT_DIR: kind = S_IFDIR; break;
case DT_LNK: kind = S_IFLNK; break;
case DT_BLK: kind = S_IFBLK; break;
case DT_CHR: kind = S_IFCHR; break;
case DT_FIFO: kind = S_IFIFO; break;
case DT_SOCK: kind = S_IFSOCK; break;
default:
*all = 0;
break;
}
#else
*all = 0;
#endif
if (kind != -1)
py_kind = PyInt_FromLong(kind);
else {
py_kind = Py_None;
Py_INCREF(Py_None);
}
val = PyTuple_New(stat ? 3 : 2);
name = PyString_FromString(ent->d_name);
if (!name || !py_kind || !val) {
Py_XDECREF(name);
Py_XDECREF(py_kind);
Py_XDECREF(val);
return PyErr_NoMemory();
}
PyTuple_SET_ITEM(val, 0, name);
PyTuple_SET_ITEM(val, 1, py_kind);
if (stat) {
PyTuple_SET_ITEM(val, 2, Py_None);
Py_INCREF(Py_None);
}
PyList_Append(list, val);
Py_DECREF(val);
}
return 0;
}
Matt Mackall
osutils: pull file stat loop into its own function
r5425 static PyObject *statfiles(PyObject *list, PyObject *ctor_args, int keep,
char *path, int len, DIR *dir)
{
struct stat buf;
struct stat *stp = &buf;
int kind;
int ret;
ssize_t i;
ssize_t size = PyList_Size(list);
#ifdef AT_SYMLINK_NOFOLLOW
int dfd = dirfd(dir);
#endif
for (i = 0; i < size; i++) {
PyObject *elt = PyList_GetItem(list, i);
char *name = PyString_AsString(PyTuple_GET_ITEM(elt, 0));
PyObject *py_st = NULL;
PyObject *py_kind = PyTuple_GET_ITEM(elt, 1);
kind = py_kind == Py_None ? -1 : PyInt_AsLong(py_kind);
if (kind != -1 && !keep)
continue;
strncat(path + len + 1, name, PATH_MAX - len);
path[PATH_MAX] = 0;
if (keep) {
py_st = PyObject_CallObject(
(PyObject *)&listdir_stat_type, ctor_args);
if (!py_st)
return PyErr_NoMemory();
stp = &((struct listdir_stat *)py_st)->st;
PyTuple_SET_ITEM(elt, 2, py_st);
}
#ifdef AT_SYMLINK_NOFOLLOW
ret = fstatat(dfd, name, stp, AT_SYMLINK_NOFOLLOW);
#else
ret = lstat(path, stp);
#endif
if (ret == -1)
return PyErr_SetFromErrnoWithFilename(PyExc_OSError,
path);
if (kind == -1)
kind = mode_to_kind(stp->st_mode);
if (py_kind == Py_None && kind != -1) {
py_kind = PyInt_FromLong(kind);
if (!py_kind)
return PyErr_NoMemory();
Py_XDECREF(Py_None);
PyTuple_SET_ITEM(elt, 1, py_kind);
}
}
return 0;
}
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs)
{
Giorgos Keramidas
osutil.c: style fix - delete trailing end-of-line spaces
r5416 static char *kwlist[] = { "path", "stat", NULL };
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 PyObject *statobj = NULL;
Matt Mackall
osutil: cleanups...
r5421 DIR *dir = NULL;
PyObject *list = NULL;
Matt Mackall
osutils: pull file stat loop into its own function
r5425 PyObject *err = NULL;
Matt Mackall
osutil: cleanups...
r5421 PyObject *ctor_args = NULL;
int all_kinds = 1;
Matt Mackall
osutil: eliminate alloca call...
r5422 char full_path[PATH_MAX + 10];
Matt Mackall
osutil: cleanups...
r5421 int path_len;
int do_stat;
char *path;
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|O:listdir", kwlist,
&path, &path_len, &statobj))
Matt Mackall
osutil: cleanups...
r5421 goto bail;
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396
do_stat = statobj && PyObject_IsTrue(statobj);
Giorgos Keramidas
osutil.c: style fix - delete trailing end-of-line spaces
r5416
Matt Mackall
osutil: cleanups...
r5421 dir = opendir(path);
if (!dir) {
list = PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
goto bail;
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 }
Matt Mackall
osutil: cleanups...
r5421 list = PyList_New(0);
if (!list)
goto bail;
Giorgos Keramidas
osutil.c: style fix - delete trailing end-of-line spaces
r5416
Matt Mackall
osutil: eliminate alloca call...
r5422 strncpy(full_path, path, PATH_MAX);
Matt Mackall
osutil: cleanups...
r5421 full_path[path_len] = '/';
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396
Matt Mackall
osutil: move file list loop to its own function
r5427 err = listfiles(list, dir, do_stat, &all_kinds);
if (err)
goto bail;
Matt Mackall
osutil: cleanups...
r5421
PyList_Sort(list);
Matt Mackall
osutils: pull file stat loop into its own function
r5425 if (do_stat) {
ctor_args = PyTuple_New(0);
if (!ctor_args)
Matt Mackall
osutil: fold stat paths together...
r5424 goto bail;
Matt Mackall
osutil: cleanups...
r5421 }
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396
Matt Mackall
osutils: pull file stat loop into its own function
r5425 if (do_stat || !all_kinds)
if (statfiles(list, ctor_args, do_stat, full_path, path_len,
dir))
goto bail;
Matt Mackall
osutil: cleanups...
r5421 goto done;
Matt Mackall
osutil: more cleanups...
r5423 bail:
Py_XDECREF(list);
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396
Matt Mackall
osutil: more cleanups...
r5423 done:
Py_XDECREF(ctor_args);
if (dir)
closedir(dir);
Matt Mackall
osutils: pull file stat loop into its own function
r5425 return err ? err : list;
Matt Mackall
osutil: cleanups...
r5421 }
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396
static char osutil_doc[] = "Native operating system services.";
static PyMethodDef methods[] = {
Matt Mackall
osutil: cleanups...
r5421 {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS,
"list a directory\n"},
{NULL, NULL}
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 };
PyMODINIT_FUNC initosutil(void)
{
Matt Mackall
osutil: cleanups...
r5421 if (PyType_Ready(&listdir_stat_type) == -1)
return;
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396
Matt Mackall
osutil: cleanups...
r5421 Py_InitModule3("osutil", methods, osutil_doc);
Bryan O'Sullivan
Add osutil module, containing a listdir function....
r5396 }