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