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