rpm
4.5
|
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> /* XXX _free */ 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, " %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 /*@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(__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 /*@null@*/ 00137 static PyObject * 00138 rpmfts_step(rpmftsObject * s) 00139 /*@modifies s @*/ 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 00178 /*@null@*/ 00179 static PyObject * 00180 rpmfts_Debug(/*@unused@*/ rpmftsObject * s, PyObject * args, PyObject * kwds) 00181 /*@globals _Py_NoneStruct @*/ 00182 /*@modifies _Py_NoneStruct @*/ 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 /*@null@*/ 00195 static PyObject * 00196 rpmfts_Open(rpmftsObject * s, PyObject * args, PyObject * kwds) 00197 /*@modifies s @*/ 00198 { 00199 char * root = NULL; 00200 int options = -1; 00201 int ignore = -1; 00202 int xx; 00203 /* XXX: there's bound to be a better name than "ignore" */ 00204 char * kwlist[] = {"root", "options", "ignore", NULL}; 00205 00206 rpmfts_debug(__FUNCTION__, 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 /*@null@*/ 00218 static PyObject * 00219 rpmfts_Read(rpmftsObject * s) 00220 /*@globals _Py_NoneStruct @*/ 00221 /*@modifies s, _Py_NoneStruct @*/ 00222 { 00223 PyObject * result; 00224 00225 rpmfts_debug(__FUNCTION__, 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 /*@null@*/ 00238 static PyObject * 00239 rpmfts_Children(rpmftsObject * s, PyObject * args, PyObject * kwds) 00240 /*@globals _Py_NoneStruct @*/ 00241 /*@modifies s, _Py_NoneStruct @*/ 00242 { 00243 int instr; 00244 char * kwlist[] = {"instructions", NULL}; 00245 00246 rpmfts_debug(__FUNCTION__, 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 /*@null@*/ 00262 static PyObject * 00263 rpmfts_Close(rpmftsObject * s) 00264 /*@modifies s @*/ 00265 { 00266 00267 rpmfts_debug(__FUNCTION__, s); 00268 00269 return Py_BuildValue("i", rpmfts_state(s, RPMFTS_CLOSE)); 00270 } 00271 00272 /*@null@*/ 00273 static PyObject * 00274 rpmfts_Set(rpmftsObject * s, PyObject * args, PyObject * kwds) 00275 /*@modifies s @*/ 00276 { 00277 int instr = 0; 00278 int rc = 0; 00279 char * kwlist[] = {"instructions", NULL}; 00280 00281 rpmfts_debug(__FUNCTION__, 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 /*@-fullinitblock@*/ 00295 /*@unchecked@*/ /*@observer@*/ 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} /* sentinel */ 00310 }; 00311 /*@=fullinitblock@*/ 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(__FUNCTION__, (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(__FUNCTION__, (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 /*@null@*/ 00352 static PyObject * 00353 rpmfts_iternext(rpmftsObject * s) 00354 /*@modifies s @*/ 00355 { 00356 int xx; 00357 00358 /* Reset loop indices on 1st entry. */ 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(/*@only@*/ 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(/*@only@*/ rpmftsObject * s) 00379 /*@modifies s @*/ 00380 { 00381 int xx; 00382 00383 rpmfts_debug(__FUNCTION__, 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 /*@modifies s @*/ 00402 { 00403 char * root = NULL; 00404 int options = -1; 00405 int ignore = -1; 00406 char * kwlist[] = {"root", "options", "ignore", NULL}; 00407 00408 rpmfts_debug(__FUNCTION__, 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 /*@null@*/ 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 /* All the other _new() functions claim to be _init in their errors...*/ 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(__FUNCTION__, 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, /*@unused@*/ int flags) 00519 /*@globals fileSystem @*/ 00520 /*@modifies fp, fileSystem @*/ 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 /*@unchecked@*/ /*@observer@*/ 00535 static char rpmfts_doc[] = 00536 ""; 00537 00540 /*@-fullinitblock@*/ 00541 PyTypeObject rpmfts_Type = { 00542 PyObject_HEAD_INIT(&PyType_Type) 00543 0, /* ob_size */ 00544 "rpm.fts", /* tp_name */ 00545 sizeof(rpmftsObject), /* tp_size */ 00546 0, /* tp_itemsize */ 00547 /* methods */ 00548 (destructor) rpmfts_dealloc, /* tp_dealloc */ 00549 (printfunc) rpmfts_print, /* tp_print */ 00550 (getattrfunc)0, /* tp_getattr */ 00551 (setattrfunc)0, /* tp_setattr */ 00552 (cmpfunc)0, /* tp_compare */ 00553 (reprfunc)0, /* tp_repr */ 00554 0, /* tp_as_number */ 00555 0, /* tp_as_sequence */ 00556 0, /* tp_as_mapping */ 00557 (hashfunc)0, /* tp_hash */ 00558 (ternaryfunc)0, /* tp_call */ 00559 (reprfunc)0, /* tp_str */ 00560 (getattrofunc) rpmfts_getattro, /* tp_getattro */ 00561 (setattrofunc) rpmfts_setattro, /* tp_setattro */ 00562 0, /* tp_as_buffer */ 00563 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 00564 rpmfts_doc, /* tp_doc */ 00565 (traverseproc) rpmfts_traverse, /* tp_traverse */ 00566 0, /* tp_clear */ 00567 0, /* tp_richcompare */ 00568 0, /* tp_weaklistoffset */ 00569 (getiterfunc) rpmfts_iter, /* tp_iter */ 00570 (iternextfunc) rpmfts_iternext, /* tp_iternext */ 00571 rpmfts_methods, /* tp_methods */ 00572 rpmfts_members, /* tp_members */ 00573 0, /* tp_getset */ 00574 0, /* tp_base */ 00575 0, /* tp_dict */ 00576 0, /* tp_descr_get */ 00577 0, /* tp_descr_set */ 00578 offsetof(rpmftsObject, md_dict),/* tp_dictoffset */ 00579 (initproc) rpmfts_init, /* tp_init */ 00580 rpmfts_alloc, /* tp_alloc */ 00581 rpmfts_new, /* tp_new */ 00582 rpmfts_free, /* tp_free */ 00583 0, /* tp_is_gc */ 00584 }; 00585 /*@=fullinitblock@*/