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
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
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
00072 {
00073 int ac = 1;
00074 size_t nb;
00075
00076
00077 if (root == NULL) root = "/";
00078
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
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
00137 static PyObject *
00138 rpmfts_step(rpmftsObject * s)
00139
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
00179 static PyObject *
00180 rpmfts_Debug( rpmftsObject * s, PyObject * args,
00181 PyObject * kwds)
00182
00183
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
00196 static PyObject *
00197 rpmfts_Open(rpmftsObject * s, PyObject * args, PyObject * kwds)
00198
00199 {
00200 char * root = NULL;
00201 int options = -1;
00202 int ignore = -1;
00203 int xx;
00204
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
00219 static PyObject *
00220 rpmfts_Read(rpmftsObject * s)
00221
00222
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
00239 static PyObject *
00240 rpmfts_Children(rpmftsObject * s, PyObject * args, PyObject * kwds)
00241
00242
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
00263 static PyObject *
00264 rpmfts_Close(rpmftsObject * s)
00265
00266 {
00267
00268 rpmfts_debug("rpmfts_Close", s);
00269
00270 return Py_BuildValue("i", rpmfts_state(s, RPMFTS_CLOSE));
00271 }
00272
00273
00274 static PyObject *
00275 rpmfts_Set(rpmftsObject * s, PyObject * args, PyObject * kwds)
00276
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
00296
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}
00311 };
00312
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
00353 static PyObject *
00354 rpmfts_iternext(rpmftsObject * s)
00355
00356 {
00357 int xx;
00358
00359
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( 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( rpmftsObject * s)
00380
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
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
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
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 int flags)
00521
00522
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
00537 static char rpmfts_doc[] =
00538 "";
00539
00542
00543 PyTypeObject rpmfts_Type = {
00544 PyObject_HEAD_INIT(&PyType_Type)
00545 0,
00546 "rpm.fts",
00547 sizeof(rpmftsObject),
00548 0,
00549
00550 (destructor) rpmfts_dealloc,
00551 (printfunc) rpmfts_print,
00552 (getattrfunc)0,
00553 (setattrfunc)0,
00554 (cmpfunc)0,
00555 (reprfunc)0,
00556 0,
00557 0,
00558 0,
00559 (hashfunc)0,
00560 (ternaryfunc)0,
00561 (reprfunc)0,
00562 (getattrofunc) rpmfts_getattro,
00563 (setattrofunc) rpmfts_setattro,
00564 0,
00565 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
00566 rpmfts_doc,
00567 (traverseproc) rpmfts_traverse,
00568 0,
00569 0,
00570 0,
00571 (getiterfunc) rpmfts_iter,
00572 (iternextfunc) rpmfts_iternext,
00573 rpmfts_methods,
00574 rpmfts_members,
00575 0,
00576 0,
00577 0,
00578 0,
00579 0,
00580 offsetof(rpmftsObject, md_dict),
00581 (initproc) rpmfts_init,
00582 rpmfts_alloc,
00583 rpmfts_new,
00584 (freefunc) rpmfts_free,
00585 0,
00586 };
00587