rpm  5.4.15
rpmfts-py.c
Go to the documentation of this file.
1 
5 #include "system-py.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 *
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_RETURN_NONE;
192 }
193 
194 /*@null@*/
195 static PyObject *
196 rpmfts_Open(rpmftsObject * s, PyObject * args, PyObject * kwds)
197  /*@modifies s @*/
198 {
199  char * root = NULL;
200  int options = -1;
201  int ignore = -1;
202  int xx;
203  /* XXX: there's bound to be a better name than "ignore" */
204  char * kwlist[] = {"root", "options", "ignore", NULL};
205 
206 rpmfts_debug("rpmfts_Open", s);
207  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sii:Open", kwlist,
208  &root, &options, &ignore))
209  return NULL;
210 
211  xx = rpmfts_initialize(s, root, options, ignore);
212  xx = rpmfts_state(s, RPMFTS_OPEN);
213 
214  return (PyObject *)s;
215 }
216 
217 /*@null@*/
218 static PyObject *
220  /*@globals _Py_NoneStruct @*/
221  /*@modifies s, _Py_NoneStruct @*/
222 {
223  PyObject * result;
224 
225 rpmfts_debug("rpmfts_Read", s);
226 
227  result = rpmfts_step(s);
228 
229  if (result == NULL) {
230  Py_RETURN_NONE;
231  }
232 
233  return result;
234 }
235 
236 /*@null@*/
237 static PyObject *
238 rpmfts_Children(rpmftsObject * s, PyObject * args, PyObject * kwds)
239  /*@globals _Py_NoneStruct @*/
240  /*@modifies s, _Py_NoneStruct @*/
241 {
242  int instr;
243  char * kwlist[] = {"instructions", NULL};
244 
245 rpmfts_debug("rpmfts_Children", s);
246  if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Children", kwlist, &instr))
247  return NULL;
248 
249  if (!(s && s->ftsp))
250  return NULL;
251 
252  Py_BEGIN_ALLOW_THREADS
253  s->fts = Fts_children(s->ftsp, instr);
254  Py_END_ALLOW_THREADS
255 
256  Py_RETURN_NONE;
257 }
258 
259 /*@null@*/
260 static PyObject *
262  /*@modifies s @*/
263 {
264 
265 rpmfts_debug("rpmfts_Close", s);
266 
267  return Py_BuildValue("i", rpmfts_state(s, RPMFTS_CLOSE));
268 }
269 
270 /*@null@*/
271 static PyObject *
272 rpmfts_Set(rpmftsObject * s, PyObject * args, PyObject * kwds)
273  /*@modifies s @*/
274 {
275  int instr = 0;
276  int rc = 0;
277  char * kwlist[] = {"instructions", NULL};
278 
279 rpmfts_debug("rpmfts_Set", s);
280  if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Set", kwlist, &instr))
281  return NULL;
282 
283  if (s->ftsp && s->fts)
284  rc = Fts_set(s->ftsp, s->fts, instr);
285 
286  return Py_BuildValue("i", rc);
287 }
292 /*@-fullinitblock@*/
293 /*@unchecked@*/ /*@observer@*/
294 static struct PyMethodDef rpmfts_methods[] = {
295  {"Debug", (PyCFunction)rpmfts_Debug, METH_VARARGS|METH_KEYWORDS,
296  NULL},
297  {"open", (PyCFunction)rpmfts_Open, METH_VARARGS|METH_KEYWORDS,
298  NULL},
299  {"read", (PyCFunction)rpmfts_Read, METH_NOARGS,
300  NULL},
301  {"children",(PyCFunction)rpmfts_Children, METH_VARARGS|METH_KEYWORDS,
302  NULL},
303  {"close", (PyCFunction)rpmfts_Close, METH_NOARGS,
304  NULL},
305  {"set", (PyCFunction)rpmfts_Set, METH_VARARGS|METH_KEYWORDS,
306  NULL},
307  {NULL, NULL} /* sentinel */
308 };
309 /*@=fullinitblock@*/
310 
311 /* ---------- */
312 
313 static PyMemberDef rpmfts_members[] = {
314  {"__dict__",T_OBJECT,offsetof(rpmftsObject, md_dict), READONLY,
315  NULL},
316  {"callbacks",T_OBJECT,offsetof(rpmftsObject, callbacks), 0,
317 "Callback dictionary per fts_info state: FTS_{D|DC|DEFAULT|DNR|DOT|DP|ERR|F|INIT|NS|NSOK|SL|SLNONE|W}"},
318  {"options", T_INT, offsetof(rpmftsObject, options), 0,
319 "Option bit(s): FTS_{COMFOLLOW|LOGICAL|NOCHDIR|NOSTAT|PHYSICAL|SEEDOT|XDEV}"},
320  {"ignore", T_INT, offsetof(rpmftsObject, ignore), 0,
321 "Ignore bit(s): (1 << info) with info one of FTS_{D|DC|DEFAULT|DNR|DOT|DP|ERR|F|INIT|NS|NSOK|SL|SLNONE|W}"},
322  {NULL, 0, 0, 0, NULL}
323 };
324 
325 /* ---------- */
326 
327 static PyObject *
329  /*@*/
330 {
331  Py_INCREF(s);
332  return (PyObject *)s;
333 }
334 
335 /*@null@*/
336 static PyObject *
338  /*@modifies s @*/
339 {
340  int xx;
341 
342  /* Reset loop indices on 1st entry. */
343  if (s->active == RPMFTS_CLOSE)
345  return rpmfts_step(s);
346 }
347 
348 /* ---------- */
349 
350 static void rpmfts_free(/*@only@*/ PyObject * s)
351  /*@*/
352 {
353  _PyObject_GC_Del(s);
354 }
355 
356 static PyObject * rpmfts_alloc(PyTypeObject * type, Py_ssize_t nitems)
357  /*@*/
358 {
359  return PyType_GenericAlloc(type, nitems);
360 }
361 
362 static void rpmfts_dealloc(/*@only@*/ rpmftsObject * s)
363  /*@modifies s @*/
364 {
365  int xx;
366 
367 rpmfts_debug("rpmfts_dealloc", s);
368  xx = rpmfts_state(s, RPMFTS_CLOSE);
369 
370  s->roots = _free(s->roots);
371 
372  PyObject_GC_UnTrack((PyObject *)s);
373  if (s->md_dict != NULL) {
374  _PyModule_Clear((PyObject *)s);
375  Py_XDECREF(s->md_dict);
376  }
377  if (s->callbacks != NULL) {
378  _PyModule_Clear((PyObject *)s);
379  Py_XDECREF(s->callbacks);
380  }
381  _PyObject_GC_Del((PyObject *)s);
382 }
383 
384 static int rpmfts_init(rpmftsObject * s, PyObject *args, PyObject *kwds)
385  /*@modifies s @*/
386 {
387  char * root = NULL;
388  int options = -1;
389  int ignore = -1;
390  char * kwlist[] = {"root", "options", "ignore", NULL};
391 
392 rpmfts_debug("rpmfts_init", s);
393  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sii:rpmfts_init", kwlist,
394  &root, &options, &ignore))
395  return -1;
396 
397  return rpmfts_initialize(s, root, options, ignore);
398 }
399 
400 /*@null@*/
401 static PyObject * rpmfts_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
402  /*@*/
403 {
404  rpmftsObject *s;
405  PyObject *o;
406  PyObject *n = NULL;
407  char * kwlist[] = {0};
408 
409  /* All the other _new() functions claim to be _init in their errors...*/
410  if (!PyArg_ParseTupleAndKeywords(args, kwds, ":rpmfts_new", kwlist))
411  return NULL;
412 
413  if ((s = PyObject_GC_New(rpmftsObject, type)) == NULL)
414  return NULL;
415 rpmfts_debug("rpmfts_new", s);
416 
417  s->md_dict = PyDict_New();
418  if (s->md_dict == NULL)
419  goto fail;
420  s->callbacks = PyDict_New();
421  if (s->md_dict == NULL)
422  goto fail;
423  if (type->tp_name) {
424  const char * name;
425  if ((name = strrchr(type->tp_name, '.')) != NULL)
426  name++;
427  else
428  name = type->tp_name;
429  n = PyString_FromString(name);
430  }
431  if (n != NULL && PyDict_SetItemString(s->md_dict, "__name__", n) != 0)
432  goto fail;
433  if (PyDict_SetItemString(s->md_dict, "__doc__", Py_None) != 0)
434  goto fail;
435 
436 #define CONSTANT(_v) \
437  PyDict_SetItemString(s->md_dict, #_v, o=PyInt_FromLong(_v)); Py_XDECREF(o)
438 
441 
451 
454 
455  CONSTANT(FTS_D);
456  CONSTANT(FTS_DC);
458  CONSTANT(FTS_DNR);
459  CONSTANT(FTS_DOT);
460  CONSTANT(FTS_DP);
461  CONSTANT(FTS_ERR);
462  CONSTANT(FTS_F);
463  CONSTANT(FTS_NS);
465  CONSTANT(FTS_SL);
467  CONSTANT(FTS_W);
468 
471 
476 
477  s->roots = NULL;
478  s->compare = NULL;
479  s->ftsp = NULL;
480  s->fts = NULL;
481 
482  Py_XDECREF(n);
483  PyObject_GC_Track((PyObject *)s);
484  return (PyObject *)s;
485 
486  fail:
487  Py_XDECREF(n);
488  Py_XDECREF(s);
489  return NULL;
490 }
491 
492 static int rpmfts_traverse(rpmftsObject * s, visitproc visit, void * arg)
493  /*@*/
494 {
495  if (s->md_dict != NULL)
496  return visit(s->md_dict, arg);
497  if (s->callbacks != NULL)
498  return visit(s->callbacks, arg);
499  return 0;
500 }
501 
502 static int rpmfts_print(rpmftsObject * s, FILE * fp,
503  /*@unused@*/ int flags)
504  /*@globals fileSystem @*/
505  /*@modifies fp, fileSystem @*/
506 {
507  static int indent = 2;
508 
509  if (!(s != NULL && s->ftsp != NULL && s->fts != NULL))
510  return -1;
511  fprintf(fp, "FTS_%-7s %*s%s", ftsInfoStr(s->fts->fts_info),
512  indent * (s->fts->fts_level < 0 ? 0 : s->fts->fts_level), "",
513  s->fts->fts_name);
514  return 0;
515 }
516 
519 /*@unchecked@*/ /*@observer@*/
520 static char rpmfts_doc[] =
521 "";
522 
525 /*@-fullinitblock@*/
526 PyTypeObject rpmfts_Type = {
527  PyVarObject_HEAD_INIT(&PyType_Type, 0)
528  "rpm.fts", /* tp_name */
529  sizeof(rpmftsObject), /* tp_size */
530  0, /* tp_itemsize */
531  /* methods */
532  (destructor) rpmfts_dealloc, /* tp_dealloc */
533  (printfunc) rpmfts_print, /* tp_print */
534  (getattrfunc)0, /* tp_getattr */
535  (setattrfunc)0, /* tp_setattr */
536  (cmpfunc)0, /* tp_compare */
537  (reprfunc)0, /* tp_repr */
538  0, /* tp_as_number */
539  0, /* tp_as_sequence */
540  0, /* tp_as_mapping */
541  (hashfunc)0, /* tp_hash */
542  (ternaryfunc)0, /* tp_call */
543  (reprfunc)0, /* tp_str */
544  PyObject_GenericGetAttr, /* tp_getattro */
545  PyObject_GenericSetAttr, /* tp_setattro */
546  0, /* tp_as_buffer */
547  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
548  rpmfts_doc, /* tp_doc */
549  (traverseproc) rpmfts_traverse, /* tp_traverse */
550  0, /* tp_clear */
551  0, /* tp_richcompare */
552  0, /* tp_weaklistoffset */
553  (getiterfunc) rpmfts_iter, /* tp_iter */
554  (iternextfunc) rpmfts_iternext, /* tp_iternext */
555  rpmfts_methods, /* tp_methods */
556  rpmfts_members, /* tp_members */
557  0, /* tp_getset */
558  0, /* tp_base */
559  0, /* tp_dict */
560  0, /* tp_descr_get */
561  0, /* tp_descr_set */
562  offsetof(rpmftsObject, md_dict),/* tp_dictoffset */
563  (initproc) rpmfts_init, /* tp_init */
564  rpmfts_alloc, /* tp_alloc */
565  rpmfts_new, /* tp_new */
566  (freefunc) rpmfts_free, /* tp_free */
567  0, /* tp_is_gc */
568 };
569 /*@=fullinitblock@*/
#define FTS_FOLLOW
Definition: fts.h:150
#define FTS_SLNONE
Definition: fts.h:141
static PyObject * rpmfts_Set(rpmftsObject *s, PyObject *args, PyObject *kwds)
Definition: rpmfts-py.c:272
static PyObject * rpmfts_step(rpmftsObject *s)
Definition: rpmfts-py.c:138
static const char * ftsInfoStrings[]
Definition: rpmfts-py.c:27
#define FTS_XDEV
Definition: fts.h:93
static char rpmfts_doc[]
Definition: rpmfts-py.c:520
FTS * Fts_open(char *const *argv, int options, int(*compar)(const FTSENT **, const FTSENT **))
Create a handle for file hierarchy traversal.
Definition: fts.c:207
PyObject * callbacks
Definition: rpmfts-py.h:18
FTSENT * fts
Definition: rpmfts-py.h:31
#define FTS_SYMFOLLOW
Definition: fts.h:146
static PyObject * rpmfts_iter(rpmftsObject *s)
Definition: rpmfts-py.c:328
FTSENT * Fts_children(FTS *sp, int instr)
Return list of children of the current node.
Definition: fts.c:705
static int rpmfts_print(rpmftsObject *s, FILE *fp, int flags)
Definition: rpmfts-py.c:502
static PyObject * rpmfts_alloc(PyTypeObject *type, Py_ssize_t nitems)
Definition: rpmfts-py.c:356
#define FTS_ROOTLEVEL
Definition: fts.h:126
#define FTS_W
Definition: fts.h:142
static PyObject * rpmfts_Debug(rpmftsObject *s, PyObject *args, PyObject *kwds)
Definition: rpmfts-py.c:180
#define FTS_SL
Definition: fts.h:140
static PyObject * rpmfts_Close(rpmftsObject *s)
Definition: rpmfts-py.c:261
#define FTS_NS
Definition: fts.h:138
short fts_level
Definition: fts.h:127
#define RPMFTS_CLOSE
Definition: rpmfts-py.c:54
#define CONSTANT(_v)
#define RPMFTS_OPEN_LAZY
Definition: rpmfts-py.c:56
static PyObject * rpmfts_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Definition: rpmfts-py.c:401
u_short fts_info
Definition: fts.h:143
#define FTS_D
Definition: fts.h:129
#define FTS_NOINSTR
Definition: fts.h:151
static int rpmfts_initialize(rpmftsObject *s, const char *root, int options, int ignore)
Definition: rpmfts-py.c:70
static PyObject * rpmfts_Read(rpmftsObject *s)
Definition: rpmfts-py.c:219
static int rpmfts_state(rpmftsObject *s, int nactive)
Definition: rpmfts-py.c:107
#define FTS_NSOK
Definition: fts.h:139
static PyObject * rpmfts_Children(rpmftsObject *s, PyObject *args, PyObject *kwds)
Definition: rpmfts-py.c:238
#define FTS_COMFOLLOW
Definition: fts.h:87
static const char * ftsInfoStr(int fts_info)
Definition: rpmfts-py.c:46
static struct PyMethodDef rpmfts_methods[]
Definition: rpmfts-py.c:294
#define FTS_DEFAULT
Definition: fts.h:131
#define FTS_DC
Definition: fts.h:130
#define fail(_err)
Definition: yarn.c:199
#define FTS_DONTCHDIR
Definition: fts.h:145
#define FTS_DOT
Definition: fts.h:133
static PyObject * rpmfts_Open(rpmftsObject *s, PyObject *args, PyObject *kwds)
Definition: rpmfts-py.c:196
#define FTS_SEEDOT
Definition: fts.h:92
#define infoBit(_ix)
Definition: rpmfts-py.c:25
FTSENT * Fts_read(FTS *sp)
Return next node in the file hierarchy traversal.
Definition: fts.c:467
static int rpmfts_traverse(rpmftsObject *s, visitproc visit, void *arg)
Definition: rpmfts-py.c:492
const char const char int arg
Definition: mongo.h:777
const char const bson int mongo_write_concern int flags
Definition: mongo.h:485
#define FTS_DNR
Definition: fts.h:132
static PyObject * rpmfts_iternext(rpmftsObject *s)
Definition: rpmfts-py.c:337
int Fts_set(FTS *sp, FTSENT *p, int instr)
Modify the traversal for a file set member.
Definition: fts.c:688
char fts_name[1]
Definition: fts.h:157
#define FTS_NOCHDIR
Definition: fts.h:89
Definition: fts.h:102
static int rpmfts_init(rpmftsObject *s, PyObject *args, PyObject *kwds)
Definition: rpmfts-py.c:384
#define FTS_WHITEOUT
Definition: fts.h:94
char * stpcpy(char *dest, const char *src)
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:756
#define FTS_NAMEONLY
Definition: fts.h:97
#define RPMFTS_OPEN
Definition: rpmfts-py.c:55
#define FTS_PHYSICAL
Definition: fts.h:91
struct rpmftsObject_s rpmftsObject
#define FTS_LOGICAL
Definition: fts.h:88
int Fts_close(FTS *sp)
Destroy a file hierarchy traversal handle.
Definition: fts.c:380
static int _rpmfts_debug
Definition: rpmfts-py.c:23
static void rpmfts_dealloc(rpmftsObject *s)
Definition: rpmfts-py.c:362
const char char type
Definition: bson.h:908
PyObject_HEAD PyObject * md_dict
Definition: rpmfts-py.h:17
static int indent
Definition: rpmgi.c:47
static const char * name
int(* compare)(const void *, const void *)
Definition: rpmfts-py.h:26
#define FTS_AGAIN
Definition: fts.h:149
#define FTS_F
Definition: fts.h:136
static void rpmfts_free(PyObject *s)
Definition: rpmfts-py.c:350
#define FTS_DP
Definition: fts.h:134
static void rpmfts_debug(const char *msg, rpmftsObject *s)
Definition: rpmfts-py.c:59
const char const bson const bson int int int options
Definition: mongo.h:569
const char ** roots
Definition: rpmfts-py.h:21
#define FTS_NOSTAT
Definition: fts.h:90
#define FTS_ERR
Definition: fts.h:135
#define FTS_ROOTPARENTLEVEL
Definition: fts.h:125
static PyMemberDef rpmfts_members[]
Definition: rpmfts-py.c:313
#define FTS_OPTIONMASK
Definition: fts.h:95
static int nitems
Definition: rpmcache.c:81
#define FTS_STOP
Definition: fts.h:98
PyTypeObject rpmfts_Type
Definition: rpmfts-py.c:526
#define FTS_SKIP
Definition: fts.h:152