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