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