rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

rpmfts-py.c
Go to the documentation of this file.
1
5 #include "system.h"
6
7 #include "structmember.h"
8
9 #ifdef __LCLINT__
10 #undef PyObject_HEAD
11 #define PyObject_HEAD int _PyObjectHead;
12 #endif
13
14 #include <fts.h>
15
16 #include "rpmfts-py.h"
17
18 #include <rpmiotypes.h>
19
20 #include "debug.h"
21
22 /*@unchecked@*/
23 static int _rpmfts_debug = 1;
24
25 #define infoBit(_ix) (1 << (((unsigned)(_ix)) & 0x1f))
26
27 static const char * ftsInfoStrings[] = {
28 "UNKNOWN",
29 "D",
30 "DC",
31 "DEFAULT",
32 "DNR",
33 "DOT",
34 "DP",
35 "ERR",
36 "F",
37 "INIT",
38 "NS",
39 "NSOK",
40 "SL",
41 "SLNONE",
42 "W",
43 };
44
45 /*@observer@*/
46 static const char * ftsInfoStr(int fts_info)
47 /*@*/
48 {
49 if (!(fts_info >= 1 && fts_info <= 14))
50 fts_info = 0;
51 return ftsInfoStrings[ fts_info ];
52 }
53
54 #define RPMFTS_CLOSE 0
55 #define RPMFTS_OPEN 1
56 #define RPMFTS_OPEN_LAZY 2
57
58 static void
59 rpmfts_debug (const char * msg, rpmftsObject * s)
60 {
61 if (_rpmfts_debug == 0)
62 return;
63 if (msg)
64 fprintf(stderr, "*** %s(%p)", msg, s);
65 if (s)
66 fprintf(stderr, " %u %d ftsp %p fts %p\n", (unsigned) s->ob_refcnt, s->active, s->ftsp, s->fts);
67 }
68
69 static int
70 rpmfts_initialize(rpmftsObject * s, const char * root, int options, int ignore)
71 /*@modifies s @*/
72 {
73 int ac = 1;
74 size_t nb;
75
76 /*@-branchstate@*/
77 if (root == NULL) root = "/";
78 /*@=branchstate@*/
79 if (options == -1) options = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
80 if (ignore == -1) ignore = infoBit(FTS_DP);
81
82 s->roots = _free(s->roots);
83
84 nb = (ac + 1) * sizeof(*s->roots);
85 nb += strlen(root) + 1;
86 s->roots = malloc(nb);
87 if (s->roots != NULL) {
88 char *t = (char *) &s->roots[ac + 1];
89 s->roots[0] = t;
90 s->roots[ac] = NULL;
91 (void) stpcpy(t, root);
92 }
93
94 s->options = options;
95 s->ignore = ignore;
96 s->compare = NULL;
97
98 s->ftsp = NULL;
99 s->fts = NULL;
100 s->active = RPMFTS_CLOSE;
101
102 return 0;
103
104 }
105
106 static int
107 rpmfts_state(rpmftsObject * s, int nactive)
108 /*@modifies s @*/
109 {
110 int rc = 0;
111
112 rpmfts_debug("rpmfts_state", s);
113 switch (nactive) {
114 case RPMFTS_CLOSE:
115 if (s->ftsp != NULL) {
116 Py_BEGIN_ALLOW_THREADS
117 rc = Fts_close(s->ftsp);
118 Py_END_ALLOW_THREADS
119 s->ftsp = NULL;
120 }
121 break;
122 case RPMFTS_OPEN_LAZY:
123 case RPMFTS_OPEN:
124 if (s->ftsp == NULL) {
125 Py_BEGIN_ALLOW_THREADS
126 s->ftsp = Fts_open((char *const *)s->roots, s->options, (int (*)(const FTSENT **, const FTSENT **))s->compare);
127 Py_END_ALLOW_THREADS
128 }
129 break;
130 }
131 s->fts = NULL;
132 s->active = nactive;
133 return rc;
134 }
135
136 /*@null@*/
137 static PyObject *
138 rpmfts_step(rpmftsObject * s)
139 /*@modifies s @*/
140 {
141 PyObject * result = NULL;
142 int xx;
143
144 rpmfts_debug("rpmfts_step", s);
145 if (s->ftsp == NULL)
146 return NULL;
147
148 do {
149 Py_BEGIN_ALLOW_THREADS
150 s->fts = Fts_read(s->ftsp);
151 Py_END_ALLOW_THREADS
152 } while (s->fts && (infoBit(s->fts->fts_info) & s->ignore));
153
154 if (s->fts != NULL) {
155 Py_INCREF(s);
156 result = (PyObject *)s;
157 } else {
158 if (s->active == RPMFTS_OPEN_LAZY)
159 xx = rpmfts_state(s, RPMFTS_CLOSE);
160 s->active = RPMFTS_CLOSE;
161 }
162
163 return result;
164 }
165
166 /* ---------- */
167
178 /*@null@*/
179 static PyObject *
180 rpmfts_Debug(/*@unused@*/ rpmftsObject * s, PyObject * args,
181 PyObject * kwds)
182 /*@globals _Py_NoneStruct @*/
183 /*@modifies _Py_NoneStruct @*/
184 {
185 char * kwlist[] = {"debugLevel", NULL};
186
187 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Debug", kwlist,
188 &_rpmfts_debug))
189 return NULL;
190
191 Py_INCREF(Py_None);
192 return Py_None;
193 }
194
195 /*@null@*/
196 static PyObject *
197 rpmfts_Open(rpmftsObject * s, PyObject * args, PyObject * kwds)
198 /*@modifies s @*/
199 {
200 char * root = NULL;
201 int options = -1;
202 int ignore = -1;
203 int xx;
204 /* XXX: there's bound to be a better name than "ignore" */
205 char * kwlist[] = {"root", "options", "ignore", NULL};
206
207 rpmfts_debug("rpmfts_Open", s);
208 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sii:Open", kwlist,
209 &root, &options, &ignore))
210 return NULL;
211
212 xx = rpmfts_initialize(s, root, options, ignore);
213 xx = rpmfts_state(s, RPMFTS_OPEN);
214
215 return (PyObject *)s;
216 }
217
218 /*@null@*/
219 static PyObject *
220 rpmfts_Read(rpmftsObject * s)
221 /*@globals _Py_NoneStruct @*/
222 /*@modifies s, _Py_NoneStruct @*/
223 {
224 PyObject * result;
225
226 rpmfts_debug("rpmfts_Read", s);
227
228 result = rpmfts_step(s);
229
230 if (result == NULL) {
231 Py_INCREF(Py_None);
232 return Py_None;
233 }
234
235 return result;
236 }
237
238 /*@null@*/
239 static PyObject *
240 rpmfts_Children(rpmftsObject * s, PyObject * args, PyObject * kwds)
241 /*@globals _Py_NoneStruct @*/
242 /*@modifies s, _Py_NoneStruct @*/
243 {
244 int instr;
245 char * kwlist[] = {"instructions", NULL};
246
247 rpmfts_debug("rpmfts_Children", s);
248 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Children", kwlist, &instr))
249 return NULL;
250
251 if (!(s && s->ftsp))
252 return NULL;
253
254 Py_BEGIN_ALLOW_THREADS
255 s->fts = Fts_children(s->ftsp, instr);
256 Py_END_ALLOW_THREADS
257
258 Py_INCREF(Py_None);
259 return Py_None;
260 }
261
262 /*@null@*/
263 static PyObject *
264 rpmfts_Close(rpmftsObject * s)
265 /*@modifies s @*/
266 {
267
268 rpmfts_debug("rpmfts_Close", s);
269
270 return Py_BuildValue("i", rpmfts_state(s, RPMFTS_CLOSE));
271 }
272
273 /*@null@*/
274 static PyObject *
275 rpmfts_Set(rpmftsObject * s, PyObject * args, PyObject * kwds)
276 /*@modifies s @*/
277 {
278 int instr = 0;
279 int rc = 0;
280 char * kwlist[] = {"instructions", NULL};
281
282 rpmfts_debug("rpmfts_Set", s);
283 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Set", kwlist, &instr))
284 return NULL;
285
286 if (s->ftsp && s->fts)
287 rc = Fts_set(s->ftsp, s->fts, instr);
288
289 return Py_BuildValue("i", rc);
290 }
295 /*@-fullinitblock@*/
296 /*@unchecked@*/ /*@observer@*/
297 static struct PyMethodDef rpmfts_methods[] = {
298 {"Debug", (PyCFunction)rpmfts_Debug, METH_VARARGS|METH_KEYWORDS,
299 NULL},
300 {"open", (PyCFunction)rpmfts_Open, METH_VARARGS|METH_KEYWORDS,
301 NULL},
302 {"read", (PyCFunction)rpmfts_Read, METH_NOARGS,
303 NULL},
304 {"children",(PyCFunction)rpmfts_Children, METH_VARARGS|METH_KEYWORDS,
305 NULL},
306 {"close", (PyCFunction)rpmfts_Close, METH_NOARGS,
307 NULL},
308 {"set", (PyCFunction)rpmfts_Set, METH_VARARGS|METH_KEYWORDS,
309 NULL},
310 {NULL, NULL} /* sentinel */
311 };
312 /*@=fullinitblock@*/
313
314 /* ---------- */
315
316 static PyMemberDef rpmfts_members[] = {
317 {"__dict__",T_OBJECT,offsetof(rpmftsObject, md_dict), READONLY,
318 NULL},
319 {"callbacks",T_OBJECT,offsetof(rpmftsObject, callbacks), 0,
320 "Callback dictionary per fts_info state: FTS_{D|DC|DEFAULT|DNR|DOT|DP|ERR|F|INIT|NS|NSOK|SL|SLNONE|W}"},
321 {"options", T_INT, offsetof(rpmftsObject, options), 0,
322 "Option bit(s): FTS_{COMFOLLOW|LOGICAL|NOCHDIR|NOSTAT|PHYSICAL|SEEDOT|XDEV}"},
323 {"ignore", T_INT, offsetof(rpmftsObject, ignore), 0,
324 "Ignore bit(s): (1 << info) with info one of FTS_{D|DC|DEFAULT|DNR|DOT|DP|ERR|F|INIT|NS|NSOK|SL|SLNONE|W}"},
325 {NULL, 0, 0, 0, NULL}
326 };
327
328 static PyObject * rpmfts_getattro(PyObject * o, PyObject * n)
329 /*@*/
330 {
331 rpmfts_debug("rpmfts_getattro", (rpmftsObject *)o);
332 return PyObject_GenericGetAttr(o, n);
333 }
334
335 static int rpmfts_setattro(PyObject * o, PyObject * n, PyObject * v)
336 /*@*/
337 {
338 rpmfts_debug("rpmfts_setattro", (rpmftsObject *)o);
339 return PyObject_GenericSetAttr(o, n, v);
340 }
341
342 /* ---------- */
343
344 static PyObject *
345 rpmfts_iter(rpmftsObject * s)
346 /*@*/
347 {
348 Py_INCREF(s);
349 return (PyObject *)s;
350 }
351
352 /*@null@*/
353 static PyObject *
354 rpmfts_iternext(rpmftsObject * s)
355 /*@modifies s @*/
356 {
357 int xx;
358
359 /* Reset loop indices on 1st entry. */
360 if (s->active == RPMFTS_CLOSE)
361 xx = rpmfts_state(s, RPMFTS_OPEN_LAZY);
362 return rpmfts_step(s);
363 }
364
365 /* ---------- */
366
367 static void rpmfts_free(/*@only@*/ PyObject * s)
368 /*@*/
369 {
370 _PyObject_GC_Del(s);
371 }
372
373 static PyObject * rpmfts_alloc(PyTypeObject * type, Py_ssize_t nitems)
374 /*@*/
375 {
376 return PyType_GenericAlloc(type, nitems);
377 }
378
379 static void rpmfts_dealloc(/*@only@*/ rpmftsObject * s)
380 /*@modifies s @*/
381 {
382 int xx;
383
384 rpmfts_debug("rpmfts_dealloc", s);
385 xx = rpmfts_state(s, RPMFTS_CLOSE);
386
387 s->roots = _free(s->roots);
388
389 PyObject_GC_UnTrack((PyObject *)s);
390 if (s->md_dict != NULL) {
391 _PyModule_Clear((PyObject *)s);
392 Py_DECREF(s->md_dict);
393 }
394 if (s->callbacks != NULL) {
395 _PyModule_Clear((PyObject *)s);
396 Py_DECREF(s->callbacks);
397 }
398 _PyObject_GC_Del((PyObject *)s);
399 }
400
401 static int rpmfts_init(rpmftsObject * s, PyObject *args, PyObject *kwds)
402 /*@modifies s @*/
403 {
404 char * root = NULL;
405 int options = -1;
406 int ignore = -1;
407 char * kwlist[] = {"root", "options", "ignore", NULL};
408
409 rpmfts_debug("rpmfts_init", s);
410 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sii:rpmfts_init", kwlist,
411 &root, &options, &ignore))
412 return -1;
413
414 return rpmfts_initialize(s, root, options, ignore);
415 }
416
417 /*@null@*/
418 static PyObject * rpmfts_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
419 /*@*/
420 {
421 rpmftsObject *s;
422 PyObject *o;
423 PyObject *n = NULL;
424 char * kwlist[] = {0};
425
426 /* All the other _new() functions claim to be _init in their errors...*/
427 if (!PyArg_ParseTupleAndKeywords(args, kwds, ":rpmfts_new", kwlist))
428 return NULL;
429
430 if ((s = PyObject_GC_New(rpmftsObject, type)) == NULL)
431 return NULL;
432 rpmfts_debug("rpmfts_new", s);
433
434 s->md_dict = PyDict_New();
435 if (s->md_dict == NULL)
436 goto fail;
437 s->callbacks = PyDict_New();
438 if (s->md_dict == NULL)
439 goto fail;
440 if (type->tp_name) {
441 const char * name;
442 if ((name = strrchr(type->tp_name, '.')) != NULL)
443 name++;
444 else
445 name = type->tp_name;
446 n = PyString_FromString(name);
447 }
448 if (n != NULL && PyDict_SetItemString(s->md_dict, "__name__", n) != 0)
449 goto fail;
450 if (PyDict_SetItemString(s->md_dict, "__doc__", Py_None) != 0)
451 goto fail;
452
453 #define CONSTANT(_v) \
454 PyDict_SetItemString(s->md_dict, #_v, o=PyInt_FromLong(_v)); Py_DECREF(o)
455
456 CONSTANT(FTS_ROOTPARENTLEVEL);
457 CONSTANT(FTS_ROOTLEVEL);
458
459 CONSTANT(FTS_COMFOLLOW);
460 CONSTANT(FTS_LOGICAL);
461 CONSTANT(FTS_NOCHDIR);
462 CONSTANT(FTS_NOSTAT);
463 CONSTANT(FTS_PHYSICAL);
464 CONSTANT(FTS_SEEDOT);
465 CONSTANT(FTS_XDEV);
466 CONSTANT(FTS_WHITEOUT);
467 CONSTANT(FTS_OPTIONMASK);
468
469 CONSTANT(FTS_NAMEONLY);
470 CONSTANT(FTS_STOP);
471
472 CONSTANT(FTS_D);
473 CONSTANT(FTS_DC);
474 CONSTANT(FTS_DEFAULT);
475 CONSTANT(FTS_DNR);
476 CONSTANT(FTS_DOT);
477 CONSTANT(FTS_DP);
478 CONSTANT(FTS_ERR);
479 CONSTANT(FTS_F);
480 CONSTANT(FTS_NS);
481 CONSTANT(FTS_NSOK);
482 CONSTANT(FTS_SL);
483 CONSTANT(FTS_SLNONE);
484 CONSTANT(FTS_W);
485
486 CONSTANT(FTS_DONTCHDIR);
487 CONSTANT(FTS_SYMFOLLOW);
488
489 CONSTANT(FTS_AGAIN);
490 CONSTANT(FTS_FOLLOW);
491 CONSTANT(FTS_NOINSTR);
492 CONSTANT(FTS_SKIP);
493
494 s->roots = NULL;
495 s->compare = NULL;
496 s->ftsp = NULL;
497 s->fts = NULL;
498
499 Py_XDECREF(n);
500 PyObject_GC_Track((PyObject *)s);
501 return (PyObject *)s;
502
503 fail:
504 Py_XDECREF(n);
505 Py_DECREF(s);
506 return NULL;
507 }
508
509 static int rpmfts_traverse(rpmftsObject * s, visitproc visit, void * arg)
510 /*@*/
511 {
512 if (s->md_dict != NULL)
513 return visit(s->md_dict, arg);
514 if (s->callbacks != NULL)
515 return visit(s->callbacks, arg);
516 return 0;
517 }
518
519 static int rpmfts_print(rpmftsObject * s, FILE * fp,
520 /*@unused@*/ int flags)
521 /*@globals fileSystem @*/
522 /*@modifies fp, fileSystem @*/
523 {
524 static int indent = 2;
525
526 if (!(s != NULL && s->ftsp != NULL && s->fts != NULL))
527 return -1;
528 fprintf(fp, "FTS_%-7s %*s%s", ftsInfoStr(s->fts->fts_info),
529 indent * (s->fts->fts_level < 0 ? 0 : s->fts->fts_level), "",
530 s->fts->fts_name);
531 return 0;
532 }
533
536 /*@unchecked@*/ /*@observer@*/
537 static char rpmfts_doc[] =
538 "";
539
542 /*@-fullinitblock@*/
543 PyTypeObject rpmfts_Type = {
544 PyObject_HEAD_INIT(&PyType_Type)
545 0, /* ob_size */
546 "rpm.fts", /* tp_name */
547 sizeof(rpmftsObject), /* tp_size */
548 0, /* tp_itemsize */
549 /* methods */
550 (destructor) rpmfts_dealloc, /* tp_dealloc */
551 (printfunc) rpmfts_print, /* tp_print */
552 (getattrfunc)0, /* tp_getattr */
553 (setattrfunc)0, /* tp_setattr */
554 (cmpfunc)0, /* tp_compare */
555 (reprfunc)0, /* tp_repr */
556 0, /* tp_as_number */
557 0, /* tp_as_sequence */
558 0, /* tp_as_mapping */
559 (hashfunc)0, /* tp_hash */
560 (ternaryfunc)0, /* tp_call */
561 (reprfunc)0, /* tp_str */
562 (getattrofunc) rpmfts_getattro, /* tp_getattro */
563 (setattrofunc) rpmfts_setattro, /* tp_setattro */
564 0, /* tp_as_buffer */
565 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
566 rpmfts_doc, /* tp_doc */
567 (traverseproc) rpmfts_traverse, /* tp_traverse */
568 0, /* tp_clear */
569 0, /* tp_richcompare */
570 0, /* tp_weaklistoffset */
571 (getiterfunc) rpmfts_iter, /* tp_iter */
572 (iternextfunc) rpmfts_iternext, /* tp_iternext */
573 rpmfts_methods, /* tp_methods */
574 rpmfts_members, /* tp_members */
575 0, /* tp_getset */
576 0, /* tp_base */
577 0, /* tp_dict */
578 0, /* tp_descr_get */
579 0, /* tp_descr_set */
580 offsetof(rpmftsObject, md_dict),/* tp_dictoffset */
581 (initproc) rpmfts_init, /* tp_init */
582 rpmfts_alloc, /* tp_alloc */
583 rpmfts_new, /* tp_new */
584 (freefunc) rpmfts_free, /* tp_free */
585 0, /* tp_is_gc */
586 };
587 /*@=fullinitblock@*/