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