root/releases/pkgcore/0.2.1/src/readdir.c @ marienz%2540gentoo.org-20061129021619-h92kexkktibvv60m

Revision marienz%2540gentoo.org-20061129021619-h92kexkktibvv60m, 10.8 KB (checked in by Marien Zwart <marienz@…>, 2 years ago)

Improve error handling in cpython module initialization.

Line 
1/*
2 * Copyright: 2006 Brian Harring <ferringb@gmail.com>
3 * Copyright: 2006 Marien Zwart <marienz@gentoo.org>
4 * License: GPL2
5 *
6 * C version of some of pkgcore (for extra speed).
7 */
8
9/* This does not really do anything since we do not use the "#"
10 * specifier in a PyArg_Parse or similar call, but hey, not using it
11 * means we are Py_ssize_t-clean too!
12 */
13
14#define PY_SSIZE_T_CLEAN
15
16#include "Python.h"
17
18/* Compatibility with python < 2.5 */
19
20#if PY_VERSION_HEX < 0x02050000
21typedef int Py_ssize_t;
22#define PY_SSIZE_T_MAX INT_MAX
23#define PY_SSIZE_T_MIN INT_MIN
24#endif
25
26#include <dirent.h>
27#include <sys/stat.h>
28
29
30static PyObject *pkgcore_DIRSTR,
31    *pkgcore_CHRSTR,
32    *pkgcore_BLKSTR,
33    *pkgcore_REGSTR,
34    *pkgcore_FIFOSTR,
35    *pkgcore_LNKSTR,
36    *pkgcore_SOCKSTR,
37    *pkgcore_UNKNOWNSTR;
38
39/* This function does the actual work for listdir_files and listdir_dirs. */
40
41static PyObject*
42pkgcore_readdir_actual_listdir(const char* path, int followsyms,
43    int dkind, int skind)
44{
45    DIR *the_dir;
46    struct dirent *entry;
47
48    PyObject *string;
49
50    int pathlen = strlen(path);
51
52    PyObject *result = PyList_New(0);
53    if (!result) {
54        return NULL;
55    }
56    if (!(the_dir = opendir(path))) {
57        return PyErr_SetFromErrno(PyExc_OSError);
58    }
59    errno = 0;
60    while ((entry = readdir(the_dir))) {
61        const char *name = entry->d_name;
62        /* skip over "." and ".." */
63        if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' &&
64            name[2] == 0))) {
65            continue;
66        }
67        if (entry->d_type == DT_UNKNOWN ||
68            (followsyms && entry->d_type == DT_LNK)) {
69           
70            /* both path components, the "/", the trailing null */
71           
72            size_t size = pathlen + strlen(name) + 2;
73            char *buffer = (char *) malloc(size);
74            if (!buffer) {
75                Py_DECREF(result);
76                return PyErr_NoMemory();
77            }
78            snprintf(buffer, size, "%s/%s", path, name);
79
80            struct stat st;
81            int ret;
82            if (followsyms) {
83                ret = stat(buffer, &st);
84            } else {
85                ret = lstat(buffer, &st);
86            }
87            free(buffer);
88            if (ret != 0) {
89                if (followsyms && errno == ENOENT) {
90                    /* hit a dangling symlimk; skip. */
91                    errno = 0;
92                    continue;
93                }
94                Py_DECREF(result);
95                result = NULL;
96                break;
97            }
98
99            if ((st.st_mode & S_IFMT) != skind) {
100                continue;
101            }
102        } else if (entry->d_type != dkind) {
103            continue;
104        }
105        if (!(string = PyString_FromString(name))) {
106            Py_DECREF(result);
107            result = NULL;
108            break;
109        }
110        if (PyList_Append(result, string) == -1) {
111            Py_DECREF(string);
112            Py_DECREF(result);
113            result = NULL;
114            break;
115        }
116        Py_DECREF(string);
117    }
118    closedir(the_dir);
119    if (errno) {
120        return PyErr_SetFromErrno(PyExc_OSError);
121    }
122    return result;
123}
124
125static PyObject*
126pkgcore_readdir_listdir_dirs(PyObject* self, PyObject* args)
127{
128    char *path;
129    PyObject *follow_symlinks_obj = Py_True;
130
131    if (!PyArg_ParseTuple(args, "s|O", &path, &follow_symlinks_obj)) {
132        return NULL;
133    }
134
135    int follow_symlinks = PyObject_IsTrue(follow_symlinks_obj);
136    if (follow_symlinks == -1) {
137        return NULL;
138    }
139
140    return pkgcore_readdir_actual_listdir(path, follow_symlinks,
141        DT_DIR, S_IFDIR);
142}
143
144static PyObject*
145pkgcore_readdir_listdir_files(PyObject* self, PyObject* args)
146{
147    char *path;
148    PyObject *follow_symlinks_obj = Py_True;
149
150    if (!PyArg_ParseTuple(args, "s|O", &path, &follow_symlinks_obj)) {
151        return NULL;
152    }
153
154    int follow_symlinks = PyObject_IsTrue(follow_symlinks_obj);
155    if (follow_symlinks == -1) {
156        return NULL;
157    }
158
159    return pkgcore_readdir_actual_listdir(path, follow_symlinks,
160        DT_REG, S_IFREG);
161}
162
163static PyObject*
164pkgcore_readdir_listdir(PyObject* self, PyObject* args)
165{
166    char *path;
167
168    if (!PyArg_ParseTuple(args, "s", &path)) {
169        return NULL;
170    }
171
172    PyObject *result = PyList_New(0);
173    if (!result) {
174        return NULL;
175    }
176
177    DIR *the_dir = opendir(path);
178    if (!the_dir) {
179        return PyErr_SetFromErrno(PyExc_OSError);
180    }
181    errno = 0;
182    struct dirent *entry;
183    while ((entry = readdir(the_dir))) {
184        const char *name = entry->d_name;
185        /* skip over "." and ".." */
186        if (!(name[0] == '.' && (name[1] == 0 ||
187            (name[1] == '.' && name[2] == 0)))) {
188
189            PyObject *string = PyString_FromString(name);
190            if (!string) {
191                Py_DECREF(result);
192                result = NULL;
193                break;
194            }
195            int res = PyList_Append(result, string);
196            Py_DECREF(string);
197            if (res == -1) {
198                Py_DECREF(result);
199                result = NULL;
200                break;
201            }
202        }
203    }
204    closedir(the_dir);
205    if (errno) {
206        return PyErr_SetFromErrno(PyExc_OSError);
207    }
208    return result;
209}
210
211static PyObject*
212pkgcore_readdir_read_dir(PyObject* self, PyObject* args)
213{
214    char *path;
215
216    if (!PyArg_ParseTuple(args, "s", &path)) {
217        return NULL;
218    }
219    ssize_t pathlen = strlen(path);
220
221    PyObject *result = PyList_New(0);
222    if (!result) {
223        return NULL;
224    }
225
226    DIR *the_dir = opendir(path);
227    if (!the_dir) {
228        return PyErr_SetFromErrno(PyExc_OSError);
229    }
230
231    struct dirent *entry;
232    while ((entry = readdir(the_dir))) {
233        const char *name = entry->d_name;
234        /* skip over "." and ".." */
235        if (name[0] == '.' && (name[1] == 0 ||
236            (name[1] == '.' && name[2] == 0))) {
237            continue;
238        }
239
240         PyObject *typestr;
241        switch (entry->d_type) {
242            case DT_REG:
243                typestr = pkgcore_REGSTR;
244                break;
245            case DT_DIR:
246                typestr = pkgcore_DIRSTR;
247                break;
248            case DT_FIFO:
249                typestr = pkgcore_FIFOSTR;
250                break;
251            case DT_SOCK:
252                typestr = pkgcore_SOCKSTR;
253                break;
254            case DT_CHR:
255                typestr = pkgcore_CHRSTR;
256                break;
257            case DT_BLK:
258                typestr = pkgcore_BLKSTR;
259                break;
260            case DT_LNK:
261                typestr = pkgcore_LNKSTR;
262                break;
263            case DT_UNKNOWN:
264            {
265                /* both path components, the "/", the trailing null */
266                size_t size = pathlen + strlen(name) + 2;
267                char *buffer = (char *) malloc(size);
268                if (!buffer) {
269                    return PyErr_NoMemory();
270                }
271                snprintf(buffer, size, "%s/%s", path, name);
272                struct stat st;
273                int ret = lstat(buffer, &st);
274                free(buffer);
275                if (ret == -1) {
276                    return PyErr_SetFromErrno(PyExc_OSError);
277                }
278                switch (st.st_mode & S_IFMT) {
279                    case S_IFDIR:
280                        typestr = pkgcore_DIRSTR;
281                        break;
282                    case S_IFCHR:
283                        typestr = pkgcore_CHRSTR;
284                        break;
285                    case S_IFBLK:
286                        typestr = pkgcore_BLKSTR;
287                        break;
288                    case S_IFREG:
289                        typestr = pkgcore_REGSTR;
290                        break;
291                    case S_IFLNK:
292                        typestr = pkgcore_LNKSTR;
293                        break;
294                    case S_IFSOCK:
295                        typestr = pkgcore_SOCKSTR;
296                        break;
297                    case S_IFIFO:
298                        typestr = pkgcore_FIFOSTR;
299                        break;
300                    default:
301                        /* XXX does this make sense? probably not. */
302                        typestr = pkgcore_UNKNOWNSTR;
303                }
304            }
305            break;
306
307            default:
308                /* XXX does this make sense? probably not. */
309                typestr = pkgcore_UNKNOWNSTR;
310        }
311
312        PyObject *namestr = PyString_FromString(name);
313        if (!namestr) {
314            Py_DECREF(result);
315            result = NULL;
316            break;
317        }
318        /* Slight hack: incref typestr after our error checks. */
319        PyObject *tuple = PyTuple_Pack(2, namestr, typestr);
320        Py_DECREF(namestr);
321        if (!tuple) {
322            Py_DECREF(result);
323            result = NULL;
324            break;
325        }
326        Py_INCREF(typestr);
327
328        int res = PyList_Append(result, tuple);
329        Py_DECREF(tuple);
330        if (res == -1) {
331            Py_DECREF(result);
332            result = NULL;
333            break;
334        }
335    }
336    closedir(the_dir);
337    if (errno) {
338        return PyErr_SetFromErrno(PyExc_OSError);
339    }
340    return result;
341}
342
343/* Module initialization */
344
345static PyMethodDef pkgcore_readdir_methods[] = {
346    {"listdir", (PyCFunction)pkgcore_readdir_listdir, METH_VARARGS,
347     "listdir(path, followSymlinks=True, kinds=everything)"},
348    {"listdir_dirs", (PyCFunction)pkgcore_readdir_listdir_dirs, METH_VARARGS,
349     "listdir_dirs(path, followSymlinks=True)"},
350    {"listdir_files", (PyCFunction)pkgcore_readdir_listdir_files, METH_VARARGS,
351     "listdir_files(path, followSymlinks=True)"},
352    {"readdir", (PyCFunction)pkgcore_readdir_read_dir, METH_VARARGS,
353     "read_dir(path)"},
354    {NULL}
355};
356
357PyDoc_STRVAR(
358    pkgcore_module_documentation,
359    "C reimplementation of some of pkgcore.util.osutils");
360
361PyMODINIT_FUNC
362init_readdir()
363{
364    PyObject *m;
365
366    /* XXX we have to initialize these before we call InitModule3 because
367     * the pkgcore_readdir_methods use them, which screws up error handling.
368     */
369    pkgcore_DIRSTR = PyString_FromString("directory");
370    pkgcore_CHRSTR = PyString_FromString("chardev");
371    pkgcore_BLKSTR = PyString_FromString("block");
372    pkgcore_REGSTR = PyString_FromString("file");
373    pkgcore_FIFOSTR = PyString_FromString("fifo");
374    pkgcore_LNKSTR = PyString_FromString("symlink");
375    pkgcore_SOCKSTR = PyString_FromString("socket");
376    pkgcore_UNKNOWNSTR = PyString_FromString("unknown");
377
378    if (!(pkgcore_DIRSTR &&
379          pkgcore_CHRSTR &&
380          pkgcore_BLKSTR &&
381          pkgcore_REGSTR &&
382          pkgcore_FIFOSTR &&
383          pkgcore_LNKSTR &&
384          pkgcore_SOCKSTR &&
385          pkgcore_UNKNOWNSTR)) {
386        Py_FatalError("Can't initialize module _readdir (strings)");
387    }
388
389    /* Create the module and add the functions */
390    m = Py_InitModule3("_readdir", pkgcore_readdir_methods,
391                       pkgcore_module_documentation);
392    if (!m)
393        return;
394
395    /* Success! */
396}
Note: See TracBrowser for help on using the browser.