rpm 5.2.1

python/rpmfts-py.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include "structmember.h"
00008 
00009 #ifdef __LCLINT__
00010 #undef  PyObject_HEAD
00011 #define PyObject_HEAD   int _PyObjectHead;
00012 #endif
00013 
00014 #include <fts.h>
00015 
00016 #include "rpmfts-py.h"
00017 
00018 #include <rpmiotypes.h>
00019 
00020 #include "debug.h"
00021 
00022 /*@unchecked@*/
00023 static int _rpmfts_debug = 1;
00024 
00025 #define infoBit(_ix)    (1 << (((unsigned)(_ix)) & 0x1f))
00026 
00027 static const char * ftsInfoStrings[] = {
00028     "UNKNOWN",
00029     "D",
00030     "DC",
00031     "DEFAULT",
00032     "DNR",
00033     "DOT",
00034     "DP",
00035     "ERR",
00036     "F",
00037     "INIT",
00038     "NS",
00039     "NSOK",
00040     "SL",
00041     "SLNONE",
00042     "W",
00043 };
00044 
00045 /*@observer@*/
00046 static const char * ftsInfoStr(int fts_info)
00047         /*@*/
00048 {
00049     if (!(fts_info >= 1 && fts_info <= 14))
00050         fts_info = 0;
00051     return ftsInfoStrings[ fts_info ];
00052 }
00053 
00054 #define RPMFTS_CLOSE            0
00055 #define RPMFTS_OPEN             1
00056 #define RPMFTS_OPEN_LAZY        2
00057 
00058 static void
00059 rpmfts_debug (const char * msg, rpmftsObject * s)
00060 {
00061     if (_rpmfts_debug == 0)
00062         return;
00063     if (msg)
00064         fprintf(stderr, "*** %s(%p)", msg, s);
00065     if (s)
00066         fprintf(stderr, " %u %d ftsp %p fts %p\n", (unsigned) s->ob_refcnt, s->active, s->ftsp, s->fts);
00067 }
00068 
00069 static int
00070 rpmfts_initialize(rpmftsObject * s, const char * root, int options, int ignore)
00071         /*@modifies s @*/
00072 {
00073     int ac = 1;
00074     size_t nb;
00075 
00076 /*@-branchstate@*/
00077     if (root == NULL)   root = "/";
00078 /*@=branchstate@*/
00079     if (options == -1)  options = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
00080     if (ignore == -1)   ignore = infoBit(FTS_DP);
00081 
00082     s->roots = _free(s->roots);
00083 
00084     nb = (ac + 1) * sizeof(*s->roots);
00085     nb += strlen(root) + 1;
00086     s->roots = malloc(nb);
00087     if (s->roots != NULL) {
00088         char *t = (char *) &s->roots[ac + 1];
00089         s->roots[0] = t;
00090         s->roots[ac] = NULL;
00091         (void) stpcpy(t, root);
00092     }
00093 
00094     s->options = options;
00095     s->ignore = ignore;
00096     s->compare = NULL;
00097 
00098     s->ftsp = NULL;
00099     s->fts = NULL;
00100     s->active = RPMFTS_CLOSE;
00101 
00102     return 0;
00103 
00104 }
00105 
00106 static int
00107 rpmfts_state(rpmftsObject * s, int nactive)
00108         /*@modifies s @*/
00109 {
00110     int rc = 0;
00111 
00112 rpmfts_debug("rpmfts_state", s);
00113     switch (nactive) {
00114     case RPMFTS_CLOSE:
00115         if (s->ftsp != NULL) {
00116             Py_BEGIN_ALLOW_THREADS
00117             rc = Fts_close(s->ftsp);
00118             Py_END_ALLOW_THREADS
00119             s->ftsp = NULL;
00120         }
00121         break;
00122     case RPMFTS_OPEN_LAZY:
00123     case RPMFTS_OPEN:
00124         if (s->ftsp == NULL) {
00125             Py_BEGIN_ALLOW_THREADS
00126             s->ftsp = Fts_open((char *const *)s->roots, s->options, (int (*)(const FTSENT **, const FTSENT **))s->compare);
00127             Py_END_ALLOW_THREADS
00128         }
00129         break;
00130     }
00131     s->fts = NULL;
00132     s->active = nactive;
00133     return rc;
00134 }
00135 
00136 /*@null@*/
00137 static PyObject *
00138 rpmfts_step(rpmftsObject * s)
00139         /*@modifies s @*/
00140 {
00141     PyObject * result = NULL;
00142     int xx;
00143 
00144 rpmfts_debug("rpmfts_step", s);
00145     if (s->ftsp == NULL)
00146         return NULL;
00147 
00148     do {
00149         Py_BEGIN_ALLOW_THREADS
00150         s->fts = Fts_read(s->ftsp);
00151         Py_END_ALLOW_THREADS
00152     } while (s->fts && (infoBit(s->fts->fts_info) & s->ignore));
00153 
00154     if (s->fts != NULL) {
00155         Py_INCREF(s);
00156         result = (PyObject *)s;
00157     } else {
00158         if (s->active == RPMFTS_OPEN_LAZY)
00159             xx = rpmfts_state(s, RPMFTS_CLOSE);
00160         s->active = RPMFTS_CLOSE;
00161     }
00162 
00163     return result;
00164 }
00165 
00166 /* ---------- */
00167 
00178 /*@null@*/
00179 static PyObject *
00180 rpmfts_Debug(/*@unused@*/ rpmftsObject * s, PyObject * args,
00181                 PyObject * kwds)
00182         /*@globals _Py_NoneStruct @*/
00183         /*@modifies _Py_NoneStruct @*/
00184 {
00185     char * kwlist[] = {"debugLevel", NULL};
00186 
00187     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Debug", kwlist,
00188             &_rpmfts_debug))
00189         return NULL;
00190 
00191     Py_INCREF(Py_None);
00192     return Py_None;
00193 }
00194 
00195 /*@null@*/
00196 static PyObject *
00197 rpmfts_Open(rpmftsObject * s, PyObject * args, PyObject * kwds)
00198         /*@modifies s @*/
00199 {
00200     char * root = NULL;
00201     int options = -1;
00202     int ignore = -1;
00203     int xx;
00204     /* XXX: there's bound to be a better name than "ignore" */
00205     char * kwlist[] = {"root", "options", "ignore", NULL};
00206 
00207 rpmfts_debug("rpmfts_Open", s);
00208     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sii:Open", kwlist,
00209             &root, &options, &ignore))
00210         return NULL;
00211 
00212     xx = rpmfts_initialize(s, root, options, ignore);
00213     xx = rpmfts_state(s, RPMFTS_OPEN);
00214 
00215     return (PyObject *)s;
00216 }
00217 
00218 /*@null@*/
00219 static PyObject *
00220 rpmfts_Read(rpmftsObject * s)
00221         /*@globals _Py_NoneStruct @*/
00222         /*@modifies s, _Py_NoneStruct @*/
00223 {
00224     PyObject * result;
00225 
00226 rpmfts_debug("rpmfts_Read", s);
00227 
00228     result = rpmfts_step(s);
00229 
00230     if (result == NULL) {
00231         Py_INCREF(Py_None);
00232         return Py_None;
00233     }
00234 
00235     return result;
00236 }
00237 
00238 /*@null@*/
00239 static PyObject *
00240 rpmfts_Children(rpmftsObject * s, PyObject * args, PyObject * kwds)
00241         /*@globals _Py_NoneStruct @*/
00242         /*@modifies s, _Py_NoneStruct @*/
00243 {
00244     int instr;
00245     char * kwlist[] = {"instructions", NULL};
00246 
00247 rpmfts_debug("rpmfts_Children", s);
00248     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Children", kwlist, &instr))
00249         return NULL;
00250 
00251     if (!(s && s->ftsp))
00252         return NULL;
00253 
00254     Py_BEGIN_ALLOW_THREADS
00255     s->fts = Fts_children(s->ftsp, instr);
00256     Py_END_ALLOW_THREADS
00257 
00258     Py_INCREF(Py_None);
00259     return Py_None;
00260 }
00261 
00262 /*@null@*/
00263 static PyObject *
00264 rpmfts_Close(rpmftsObject * s)
00265         /*@modifies s @*/
00266 {
00267 
00268 rpmfts_debug("rpmfts_Close", s);
00269 
00270     return Py_BuildValue("i", rpmfts_state(s, RPMFTS_CLOSE));
00271 }
00272 
00273 /*@null@*/
00274 static PyObject *
00275 rpmfts_Set(rpmftsObject * s, PyObject * args, PyObject * kwds)
00276         /*@modifies s @*/
00277 {
00278     int instr = 0;
00279     int rc = 0;
00280     char * kwlist[] = {"instructions", NULL};
00281 
00282 rpmfts_debug("rpmfts_Set", s);
00283     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Set", kwlist, &instr))
00284         return NULL;
00285 
00286     if (s->ftsp && s->fts)
00287         rc = Fts_set(s->ftsp, s->fts, instr);
00288 
00289     return Py_BuildValue("i", rc);
00290 }
00295 /*@-fullinitblock@*/
00296 /*@unchecked@*/ /*@observer@*/
00297 static struct PyMethodDef rpmfts_methods[] = {
00298     {"Debug",   (PyCFunction)rpmfts_Debug,      METH_VARARGS|METH_KEYWORDS,
00299         NULL},
00300     {"open",    (PyCFunction)rpmfts_Open,       METH_VARARGS|METH_KEYWORDS,
00301         NULL},
00302     {"read",    (PyCFunction)rpmfts_Read,       METH_NOARGS,
00303         NULL},
00304     {"children",(PyCFunction)rpmfts_Children,   METH_VARARGS|METH_KEYWORDS,
00305         NULL},
00306     {"close",   (PyCFunction)rpmfts_Close,      METH_NOARGS,
00307         NULL},
00308     {"set",     (PyCFunction)rpmfts_Set,        METH_VARARGS|METH_KEYWORDS,
00309         NULL},
00310     {NULL,              NULL}           /* sentinel */
00311 };
00312 /*@=fullinitblock@*/
00313 
00314 /* ---------- */
00315 
00316 static PyMemberDef rpmfts_members[] = {
00317     {"__dict__",T_OBJECT,offsetof(rpmftsObject, md_dict),       READONLY,
00318         NULL},
00319     {"callbacks",T_OBJECT,offsetof(rpmftsObject, callbacks),    0,
00320 "Callback dictionary per fts_info state: FTS_{D|DC|DEFAULT|DNR|DOT|DP|ERR|F|INIT|NS|NSOK|SL|SLNONE|W}"},
00321     {"options", T_INT,  offsetof(rpmftsObject, options),        0,
00322 "Option bit(s): FTS_{COMFOLLOW|LOGICAL|NOCHDIR|NOSTAT|PHYSICAL|SEEDOT|XDEV}"},
00323     {"ignore",  T_INT,  offsetof(rpmftsObject, ignore),         0,
00324 "Ignore bit(s): (1 << info) with info one of FTS_{D|DC|DEFAULT|DNR|DOT|DP|ERR|F|INIT|NS|NSOK|SL|SLNONE|W}"},
00325     {NULL, 0, 0, 0, NULL}
00326 };
00327 
00328 static PyObject * rpmfts_getattro(PyObject * o, PyObject * n)
00329         /*@*/
00330 {
00331 rpmfts_debug("rpmfts_getattro", (rpmftsObject *)o);
00332     return PyObject_GenericGetAttr(o, n);
00333 }
00334 
00335 static int rpmfts_setattro(PyObject * o, PyObject * n, PyObject * v)
00336         /*@*/
00337 {
00338 rpmfts_debug("rpmfts_setattro", (rpmftsObject *)o);
00339     return PyObject_GenericSetAttr(o, n, v);
00340 }
00341 
00342 /* ---------- */
00343 
00344 static PyObject *
00345 rpmfts_iter(rpmftsObject * s)
00346         /*@*/
00347 {
00348     Py_INCREF(s);
00349     return (PyObject *)s;
00350 }
00351 
00352 /*@null@*/
00353 static PyObject *
00354 rpmfts_iternext(rpmftsObject * s)
00355         /*@modifies s @*/
00356 {
00357     int xx;
00358 
00359     /* Reset loop indices on 1st entry. */
00360     if (s->active == RPMFTS_CLOSE)
00361         xx = rpmfts_state(s, RPMFTS_OPEN_LAZY);
00362     return rpmfts_step(s);
00363 }
00364 
00365 /* ---------- */
00366 
00367 static void rpmfts_free(/*@only@*/ PyObject * s)
00368         /*@*/
00369 {
00370     _PyObject_GC_Del(s);
00371 }
00372 
00373 static PyObject * rpmfts_alloc(PyTypeObject * type, Py_ssize_t nitems)
00374         /*@*/
00375 {
00376     return PyType_GenericAlloc(type, nitems);
00377 }
00378 
00379 static void rpmfts_dealloc(/*@only@*/ rpmftsObject * s)
00380         /*@modifies s @*/
00381 {
00382     int xx;
00383 
00384 rpmfts_debug("rpmfts_dealloc", s);
00385     xx = rpmfts_state(s, RPMFTS_CLOSE);
00386 
00387     s->roots = _free(s->roots);
00388 
00389     PyObject_GC_UnTrack((PyObject *)s);
00390     if (s->md_dict != NULL) {
00391         _PyModule_Clear((PyObject *)s);
00392         Py_DECREF(s->md_dict);
00393     }
00394     if (s->callbacks != NULL) {
00395         _PyModule_Clear((PyObject *)s);
00396         Py_DECREF(s->callbacks);
00397     }
00398     _PyObject_GC_Del((PyObject *)s);
00399 }
00400 
00401 static int rpmfts_init(rpmftsObject * s, PyObject *args, PyObject *kwds)
00402         /*@modifies s @*/
00403 {
00404     char * root = NULL;
00405     int options = -1;
00406     int ignore = -1;
00407     char * kwlist[] = {"root", "options", "ignore", NULL};
00408 
00409 rpmfts_debug("rpmfts_init", s);
00410     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sii:rpmfts_init", kwlist,
00411             &root, &options, &ignore))
00412         return -1;
00413 
00414     return rpmfts_initialize(s, root, options, ignore);
00415 }
00416 
00417 /*@null@*/
00418 static PyObject * rpmfts_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
00419         /*@*/
00420 {
00421     rpmftsObject *s;
00422     PyObject *o;
00423     PyObject *n = NULL;
00424     char * kwlist[] = {0};
00425 
00426     /* All the other _new() functions claim to be _init in their errors...*/
00427     if (!PyArg_ParseTupleAndKeywords(args, kwds, ":rpmfts_new", kwlist))
00428         return NULL;
00429 
00430     if ((s = PyObject_GC_New(rpmftsObject, type)) == NULL)
00431         return NULL;
00432 rpmfts_debug("rpmfts_new", s);
00433 
00434     s->md_dict = PyDict_New();
00435     if (s->md_dict == NULL)
00436         goto fail;
00437     s->callbacks = PyDict_New();
00438     if (s->md_dict == NULL)
00439         goto fail;
00440     if (type->tp_name) {
00441         const char * name;
00442         if ((name = strrchr(type->tp_name, '.')) != NULL)
00443             name++;
00444         else
00445             name = type->tp_name;
00446         n = PyString_FromString(name);
00447     }
00448     if (n != NULL && PyDict_SetItemString(s->md_dict, "__name__", n) != 0)
00449         goto fail;
00450     if (PyDict_SetItemString(s->md_dict, "__doc__", Py_None) != 0)
00451         goto fail;
00452 
00453 #define CONSTANT(_v) \
00454     PyDict_SetItemString(s->md_dict, #_v, o=PyInt_FromLong(_v)); Py_DECREF(o)
00455 
00456     CONSTANT(FTS_ROOTPARENTLEVEL);
00457     CONSTANT(FTS_ROOTLEVEL);
00458 
00459     CONSTANT(FTS_COMFOLLOW);
00460     CONSTANT(FTS_LOGICAL);
00461     CONSTANT(FTS_NOCHDIR);
00462     CONSTANT(FTS_NOSTAT);
00463     CONSTANT(FTS_PHYSICAL);
00464     CONSTANT(FTS_SEEDOT);
00465     CONSTANT(FTS_XDEV);
00466     CONSTANT(FTS_WHITEOUT);
00467     CONSTANT(FTS_OPTIONMASK);
00468 
00469     CONSTANT(FTS_NAMEONLY);
00470     CONSTANT(FTS_STOP);
00471 
00472     CONSTANT(FTS_D);
00473     CONSTANT(FTS_DC);
00474     CONSTANT(FTS_DEFAULT);
00475     CONSTANT(FTS_DNR);
00476     CONSTANT(FTS_DOT);
00477     CONSTANT(FTS_DP);
00478     CONSTANT(FTS_ERR);
00479     CONSTANT(FTS_F);
00480     CONSTANT(FTS_NS);
00481     CONSTANT(FTS_NSOK);
00482     CONSTANT(FTS_SL);
00483     CONSTANT(FTS_SLNONE);
00484     CONSTANT(FTS_W);
00485 
00486     CONSTANT(FTS_DONTCHDIR);
00487     CONSTANT(FTS_SYMFOLLOW);
00488 
00489     CONSTANT(FTS_AGAIN);
00490     CONSTANT(FTS_FOLLOW);
00491     CONSTANT(FTS_NOINSTR);
00492     CONSTANT(FTS_SKIP);
00493 
00494     s->roots = NULL;
00495     s->compare = NULL;
00496     s->ftsp = NULL;
00497     s->fts = NULL;
00498 
00499     Py_XDECREF(n);
00500     PyObject_GC_Track((PyObject *)s);
00501     return (PyObject *)s;
00502 
00503  fail:
00504     Py_XDECREF(n);
00505     Py_DECREF(s);
00506     return NULL;
00507 }
00508 
00509 static int rpmfts_traverse(rpmftsObject * s, visitproc visit, void * arg)
00510         /*@*/
00511 {
00512     if (s->md_dict != NULL)
00513         return visit(s->md_dict, arg);
00514     if (s->callbacks != NULL)
00515         return visit(s->callbacks, arg);
00516     return 0;
00517 }
00518 
00519 static int rpmfts_print(rpmftsObject * s,  FILE * fp,
00520                 /*@unused@*/ int flags)
00521         /*@globals fileSystem @*/
00522         /*@modifies fp, fileSystem @*/
00523 {
00524     static int indent = 2;
00525 
00526     if (!(s != NULL && s->ftsp != NULL && s->fts != NULL))
00527         return -1;
00528     fprintf(fp, "FTS_%-7s %*s%s", ftsInfoStr(s->fts->fts_info),
00529         indent * (s->fts->fts_level < 0 ? 0 : s->fts->fts_level), "",
00530         s->fts->fts_name);
00531     return 0;
00532 }
00533 
00536 /*@unchecked@*/ /*@observer@*/
00537 static char rpmfts_doc[] =
00538 "";
00539 
00542 /*@-fullinitblock@*/
00543 PyTypeObject rpmfts_Type = {
00544         PyObject_HEAD_INIT(&PyType_Type)
00545         0,                              /* ob_size */
00546         "rpm.fts",                      /* tp_name */
00547         sizeof(rpmftsObject),           /* tp_size */
00548         0,                              /* tp_itemsize */
00549         /* methods */
00550         (destructor) rpmfts_dealloc,    /* tp_dealloc */
00551         (printfunc) rpmfts_print,       /* tp_print */
00552         (getattrfunc)0,                 /* tp_getattr */
00553         (setattrfunc)0,                 /* tp_setattr */
00554         (cmpfunc)0,                     /* tp_compare */
00555         (reprfunc)0,                    /* tp_repr */
00556         0,                              /* tp_as_number */
00557         0,                              /* tp_as_sequence */
00558         0,                              /* tp_as_mapping */
00559         (hashfunc)0,                    /* tp_hash */
00560         (ternaryfunc)0,                 /* tp_call */
00561         (reprfunc)0,                    /* tp_str */
00562         (getattrofunc) rpmfts_getattro, /* tp_getattro */
00563         (setattrofunc) rpmfts_setattro, /* tp_setattro */
00564         0,                              /* tp_as_buffer */
00565         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
00566         rpmfts_doc,                     /* tp_doc */
00567         (traverseproc) rpmfts_traverse, /* tp_traverse */
00568         0,                              /* tp_clear */
00569         0,                              /* tp_richcompare */
00570         0,                              /* tp_weaklistoffset */
00571         (getiterfunc) rpmfts_iter,      /* tp_iter */
00572         (iternextfunc) rpmfts_iternext, /* tp_iternext */
00573         rpmfts_methods,                 /* tp_methods */
00574         rpmfts_members,                 /* tp_members */
00575         0,                              /* tp_getset */
00576         0,                              /* tp_base */
00577         0,                              /* tp_dict */
00578         0,                              /* tp_descr_get */
00579         0,                              /* tp_descr_set */
00580         offsetof(rpmftsObject, md_dict),/* tp_dictoffset */
00581         (initproc) rpmfts_init,         /* tp_init */
00582         rpmfts_alloc,                   /* tp_alloc */
00583         rpmfts_new,                     /* tp_new */
00584         (freefunc) rpmfts_free,         /* tp_free */
00585         0,                              /* tp_is_gc */
00586 };
00587 /*@=fullinitblock@*/