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 <rpmlib.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, " %d %d ftsp %p fts %p\n", 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(__FUNCTION__, 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(__FUNCTION__, 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
00174
00175 static PyObject *
00176 rpmfts_Debug( rpmftsObject * s, PyObject * args)
00177
00178
00179 {
00180 if (!PyArg_ParseTuple(args, "i:Debug", &_rpmfts_debug))
00181 return NULL;
00182
00183 Py_INCREF(Py_None);
00184 return Py_None;
00185 }
00186
00187
00188 static PyObject *
00189 rpmfts_Open(rpmftsObject * s, PyObject * args)
00190
00191 {
00192 char * root = NULL;
00193 int options = -1;
00194 int ignore = -1;
00195 int xx;
00196
00197 rpmfts_debug(__FUNCTION__, s);
00198 if (!PyArg_ParseTuple(args, "|sii:Open", &root, &options, &ignore))
00199 return NULL;
00200
00201 xx = rpmfts_initialize(s, root, options, ignore);
00202 xx = rpmfts_state(s, RPMFTS_OPEN);
00203
00204 return (PyObject *)s;
00205 }
00206
00207
00208 static PyObject *
00209 rpmfts_Read(rpmftsObject * s, PyObject * args)
00210
00211
00212 {
00213 PyObject * result;
00214
00215 rpmfts_debug(__FUNCTION__, s);
00216 if (!PyArg_ParseTuple(args, ":Read")) return NULL;
00217
00218 result = rpmfts_step(s);
00219
00220 if (result == NULL) {
00221 Py_INCREF(Py_None);
00222 return Py_None;
00223 }
00224
00225 return result;
00226 }
00227
00228
00229 static PyObject *
00230 rpmfts_Children(rpmftsObject * s, PyObject * args)
00231
00232
00233 {
00234 int instr;
00235
00236 rpmfts_debug(__FUNCTION__, s);
00237 if (!PyArg_ParseTuple(args, "i:Children", &instr)) return NULL;
00238
00239 if (!(s && s->ftsp))
00240 return NULL;
00241
00242 Py_BEGIN_ALLOW_THREADS
00243 s->fts = Fts_children(s->ftsp, instr);
00244 Py_END_ALLOW_THREADS
00245
00246 Py_INCREF(Py_None);
00247 return Py_None;
00248 }
00249
00250
00251 static PyObject *
00252 rpmfts_Close(rpmftsObject * s, PyObject * args)
00253
00254 {
00255
00256 rpmfts_debug(__FUNCTION__, s);
00257 if (!PyArg_ParseTuple(args, ":Close")) return NULL;
00258
00259 return Py_BuildValue("i", rpmfts_state(s, RPMFTS_CLOSE));
00260 }
00261
00262
00263 static PyObject *
00264 rpmfts_Set(rpmftsObject * s, PyObject * args)
00265
00266 {
00267 int instr = 0;
00268 int rc = 0;
00269
00270 rpmfts_debug(__FUNCTION__, s);
00271 if (!PyArg_ParseTuple(args, "i:Set", &instr)) return NULL;
00272
00273 if (s->ftsp && s->fts)
00274 rc = Fts_set(s->ftsp, s->fts, instr);
00275
00276 return Py_BuildValue("i", rc);
00277 }
00278
00281
00282
00283 static struct PyMethodDef rpmfts_methods[] = {
00284 {"Debug", (PyCFunction)rpmfts_Debug, METH_VARARGS,
00285 NULL},
00286 {"open", (PyCFunction)rpmfts_Open, METH_VARARGS,
00287 NULL},
00288 {"read", (PyCFunction)rpmfts_Read, METH_VARARGS,
00289 NULL},
00290 {"children",(PyCFunction)rpmfts_Children, METH_VARARGS,
00291 NULL},
00292 {"close", (PyCFunction)rpmfts_Close, METH_VARARGS,
00293 NULL},
00294 {"set", (PyCFunction)rpmfts_Set, METH_VARARGS,
00295 NULL},
00296 {NULL, NULL}
00297 };
00298
00299
00300
00301
00302 static PyMemberDef rpmfts_members[] = {
00303 {"__dict__",T_OBJECT,offsetof(rpmftsObject, md_dict), READONLY,
00304 NULL},
00305 {"callbacks",T_OBJECT,offsetof(rpmftsObject, callbacks), 0,
00306 "Callback dictionary per fts_info state: FTS_{D|DC|DEFAULT|DNR|DOT|DP|ERR|F|INIT|NS|NSOK|SL|SLNONE|W}"},
00307 {"options", T_INT, offsetof(rpmftsObject, options), 0,
00308 "Option bit(s): FTS_{COMFOLLOW|LOGICAL|NOCHDIR|NOSTAT|PHYSICAL|SEEDOT|XDEV}"},
00309 {"ignore", T_INT, offsetof(rpmftsObject, ignore), 0,
00310 "Ignore bit(s): (1 << info) with info one of FTS_{D|DC|DEFAULT|DNR|DOT|DP|ERR|F|INIT|NS|NSOK|SL|SLNONE|W}"},
00311 {NULL, 0, 0, 0, NULL}
00312 };
00313
00314 static PyObject * rpmfts_getattro(PyObject * o, PyObject * n)
00315
00316 {
00317 rpmfts_debug(__FUNCTION__, (rpmftsObject *)o);
00318 return PyObject_GenericGetAttr(o, n);
00319 }
00320
00321 static int rpmfts_setattro(PyObject * o, PyObject * n, PyObject * v)
00322
00323 {
00324 rpmfts_debug(__FUNCTION__, (rpmftsObject *)o);
00325 return PyObject_GenericSetAttr(o, n, v);
00326 }
00327
00328
00329
00330 static PyObject *
00331 rpmfts_iter(rpmftsObject * s)
00332
00333 {
00334 Py_INCREF(s);
00335 return (PyObject *)s;
00336 }
00337
00338
00339 static PyObject *
00340 rpmfts_iternext(rpmftsObject * s)
00341
00342 {
00343 int xx;
00344
00345
00346 if (s->active == RPMFTS_CLOSE)
00347 xx = rpmfts_state(s, RPMFTS_OPEN_LAZY);
00348 return rpmfts_step(s);
00349 }
00350
00351
00352
00353 static void rpmfts_free( PyObject * s)
00354
00355 {
00356 _PyObject_GC_Del(s);
00357 }
00358
00359 static PyObject * rpmfts_alloc(PyTypeObject * type, int nitems)
00360
00361 {
00362 return PyType_GenericAlloc(type, nitems);
00363 }
00364
00365 static void rpmfts_dealloc( rpmftsObject * s)
00366
00367 {
00368 int xx;
00369
00370 rpmfts_debug(__FUNCTION__, s);
00371 xx = rpmfts_state(s, RPMFTS_CLOSE);
00372
00373 s->roots = _free(s->roots);
00374
00375 PyObject_GC_UnTrack((PyObject *)s);
00376 if (s->md_dict != NULL) {
00377 _PyModule_Clear((PyObject *)s);
00378 Py_DECREF(s->md_dict);
00379 }
00380 if (s->callbacks != NULL) {
00381 _PyModule_Clear((PyObject *)s);
00382 Py_DECREF(s->callbacks);
00383 }
00384 _PyObject_GC_Del((PyObject *)s);
00385 }
00386
00387 static int rpmfts_init(rpmftsObject * s, PyObject *args, PyObject *kwds)
00388
00389 {
00390 char * root = NULL;
00391 int options = -1;
00392 int ignore = -1;
00393
00394 rpmfts_debug(__FUNCTION__, s);
00395 if (!PyArg_ParseTuple(args, "|sii:rpmfts_init", &root, &options, &ignore))
00396 return -1;
00397
00398 return rpmfts_initialize(s, root, options, ignore);
00399 }
00400
00401
00402 static PyObject * rpmfts_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
00403
00404 {
00405 rpmftsObject *s;
00406 PyObject *o;
00407 PyObject *n = NULL;
00408
00409
00410 if ((s = PyObject_GC_New(rpmftsObject, type)) == NULL)
00411 return NULL;
00412 rpmfts_debug(__FUNCTION__, s);
00413
00414 s->md_dict = PyDict_New();
00415 if (s->md_dict == NULL)
00416 goto fail;
00417 s->callbacks = PyDict_New();
00418 if (s->md_dict == NULL)
00419 goto fail;
00420 if (type->tp_name) {
00421 char * name;
00422 if ((name = strrchr(type->tp_name, '.')) != NULL)
00423 name++;
00424 else
00425 name = type->tp_name;
00426 n = PyString_FromString(name);
00427 }
00428 if (n != NULL && PyDict_SetItemString(s->md_dict, "__name__", n) != 0)
00429 goto fail;
00430 if (PyDict_SetItemString(s->md_dict, "__doc__", Py_None) != 0)
00431 goto fail;
00432
00433 #define CONSTANT(_v) \
00434 PyDict_SetItemString(s->md_dict, #_v, o=PyInt_FromLong(_v)); Py_DECREF(o)
00435
00436 CONSTANT(FTS_ROOTPARENTLEVEL);
00437 CONSTANT(FTS_ROOTLEVEL);
00438
00439 CONSTANT(FTS_COMFOLLOW);
00440 CONSTANT(FTS_LOGICAL);
00441 CONSTANT(FTS_NOCHDIR);
00442 CONSTANT(FTS_NOSTAT);
00443 CONSTANT(FTS_PHYSICAL);
00444 CONSTANT(FTS_SEEDOT);
00445 CONSTANT(FTS_XDEV);
00446 CONSTANT(FTS_WHITEOUT);
00447 CONSTANT(FTS_OPTIONMASK);
00448
00449 CONSTANT(FTS_NAMEONLY);
00450 CONSTANT(FTS_STOP);
00451
00452 CONSTANT(FTS_D);
00453 CONSTANT(FTS_DC);
00454 CONSTANT(FTS_DEFAULT);
00455 CONSTANT(FTS_DNR);
00456 CONSTANT(FTS_DOT);
00457 CONSTANT(FTS_DP);
00458 CONSTANT(FTS_ERR);
00459 CONSTANT(FTS_F);
00460 CONSTANT(FTS_NS);
00461 CONSTANT(FTS_NSOK);
00462 CONSTANT(FTS_SL);
00463 CONSTANT(FTS_SLNONE);
00464 CONSTANT(FTS_W);
00465
00466 CONSTANT(FTS_DONTCHDIR);
00467 CONSTANT(FTS_SYMFOLLOW);
00468
00469 CONSTANT(FTS_AGAIN);
00470 CONSTANT(FTS_FOLLOW);
00471 CONSTANT(FTS_NOINSTR);
00472 CONSTANT(FTS_SKIP);
00473
00474 s->roots = NULL;
00475 s->compare = NULL;
00476 s->ftsp = NULL;
00477 s->fts = NULL;
00478
00479 Py_XDECREF(n);
00480 PyObject_GC_Track((PyObject *)s);
00481 return (PyObject *)s;
00482
00483 fail:
00484 Py_XDECREF(n);
00485 Py_DECREF(s);
00486 return NULL;
00487 }
00488
00489 static int rpmfts_traverse(rpmftsObject * s, visitproc visit, void * arg)
00490
00491 {
00492 if (s->md_dict != NULL)
00493 return visit(s->md_dict, arg);
00494 if (s->callbacks != NULL)
00495 return visit(s->callbacks, arg);
00496 return 0;
00497 }
00498
00499 static int rpmfts_print(rpmftsObject * s, FILE * fp, int flags)
00500
00501
00502 {
00503 static int indent = 2;
00504
00505 if (!(s != NULL && s->ftsp != NULL && s->fts != NULL))
00506 return -1;
00507 fprintf(fp, "FTS_%-7s %*s%s", ftsInfoStr(s->fts->fts_info),
00508 indent * (s->fts->fts_level < 0 ? 0 : s->fts->fts_level), "",
00509 s->fts->fts_name);
00510 return 0;
00511 }
00512
00515
00516 static char rpmfts_doc[] =
00517 "";
00518
00521
00522 PyTypeObject rpmfts_Type = {
00523 PyObject_HEAD_INIT(&PyType_Type)
00524 0,
00525 "rpm.fts",
00526 sizeof(rpmftsObject),
00527 0,
00528
00529 (destructor) rpmfts_dealloc,
00530 (printfunc) rpmfts_print,
00531 (getattrfunc)0,
00532 (setattrfunc)0,
00533 (cmpfunc)0,
00534 (reprfunc)0,
00535 0,
00536 0,
00537 0,
00538 (hashfunc)0,
00539 (ternaryfunc)0,
00540 (reprfunc)0,
00541 (getattrofunc) rpmfts_getattro,
00542 (setattrofunc) rpmfts_setattro,
00543 0,
00544 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
00545 rpmfts_doc,
00546 (traverseproc) rpmfts_traverse,
00547 0,
00548 0,
00549 0,
00550 (getiterfunc) rpmfts_iter,
00551 (iternextfunc) rpmfts_iternext,
00552 rpmfts_methods,
00553 rpmfts_members,
00554 0,
00555 0,
00556 0,
00557 0,
00558 0,
00559 offsetof(rpmftsObject, md_dict),
00560 (initproc) rpmfts_init,
00561 rpmfts_alloc,
00562 rpmfts_new,
00563 rpmfts_free,
00564 0,
00565 };
00566