##// END OF EJS Templates
inotify: make proper use of Python API to get object size....
Renato Cunha -
r11547:36a6aeb6 default
parent child Browse files
Show More
@@ -1,601 +1,601 b''
1 1 /*
2 2 * _inotify.c - Python extension interfacing to the Linux inotify subsystem
3 3 *
4 4 * Copyright 2006 Bryan O'Sullivan <bos@serpentine.com>
5 5 *
6 6 * This library is free software; you can redistribute it and/or
7 7 * modify it under the terms of version 2.1 of the GNU Lesser General
8 8 * Public License or any later version.
9 9 */
10 10
11 11 #include <Python.h>
12 12 #include <alloca.h>
13 13 #include <sys/inotify.h>
14 14 #include <stdint.h>
15 15 #include <sys/ioctl.h>
16 16 #include <unistd.h>
17 17
18 18 static PyObject *init(PyObject *self, PyObject *args)
19 19 {
20 20 PyObject *ret = NULL;
21 21 int fd = -1;
22 22
23 23 if (!PyArg_ParseTuple(args, ":init"))
24 24 goto bail;
25 25
26 26 Py_BEGIN_ALLOW_THREADS;
27 27 fd = inotify_init();
28 28 Py_END_ALLOW_THREADS;
29 29
30 30 if (fd == -1) {
31 31 PyErr_SetFromErrno(PyExc_OSError);
32 32 goto bail;
33 33 }
34 34
35 35 ret = PyInt_FromLong(fd);
36 36 if (ret == NULL)
37 37 goto bail;
38 38
39 39 goto done;
40 40
41 41 bail:
42 42 if (fd != -1)
43 43 close(fd);
44 44
45 45 Py_CLEAR(ret);
46 46
47 47 done:
48 48 return ret;
49 49 }
50 50
51 51 PyDoc_STRVAR(
52 52 init_doc,
53 53 "init() -> fd\n"
54 54 "\n"
55 55 "Initialise an inotify instance.\n"
56 56 "Return a file descriptor associated with a new inotify event queue.");
57 57
58 58 static PyObject *add_watch(PyObject *self, PyObject *args)
59 59 {
60 60 PyObject *ret = NULL;
61 61 uint32_t mask;
62 62 int wd = -1;
63 63 char *path;
64 64 int fd;
65 65
66 66 if (!PyArg_ParseTuple(args, "isI:add_watch", &fd, &path, &mask))
67 67 goto bail;
68 68
69 69 Py_BEGIN_ALLOW_THREADS;
70 70 wd = inotify_add_watch(fd, path, mask);
71 71 Py_END_ALLOW_THREADS;
72 72
73 73 if (wd == -1) {
74 74 PyErr_SetFromErrnoWithFilename(PyExc_OSError, path);
75 75 goto bail;
76 76 }
77 77
78 78 ret = PyInt_FromLong(wd);
79 79 if (ret == NULL)
80 80 goto bail;
81 81
82 82 goto done;
83 83
84 84 bail:
85 85 if (wd != -1)
86 86 inotify_rm_watch(fd, wd);
87 87
88 88 Py_CLEAR(ret);
89 89
90 90 done:
91 91 return ret;
92 92 }
93 93
94 94 PyDoc_STRVAR(
95 95 add_watch_doc,
96 96 "add_watch(fd, path, mask) -> wd\n"
97 97 "\n"
98 98 "Add a watch to an inotify instance, or modify an existing watch.\n"
99 99 "\n"
100 100 " fd: file descriptor returned by init()\n"
101 101 " path: path to watch\n"
102 102 " mask: mask of events to watch for\n"
103 103 "\n"
104 104 "Return a unique numeric watch descriptor for the inotify instance\n"
105 105 "mapped by the file descriptor.");
106 106
107 107 static PyObject *remove_watch(PyObject *self, PyObject *args)
108 108 {
109 109 uint32_t wd;
110 110 int fd;
111 111 int r;
112 112
113 113 if (!PyArg_ParseTuple(args, "iI:remove_watch", &fd, &wd))
114 114 return NULL;
115 115
116 116 Py_BEGIN_ALLOW_THREADS;
117 117 r = inotify_rm_watch(fd, wd);
118 118 Py_END_ALLOW_THREADS;
119 119
120 120 if (r == -1) {
121 121 PyErr_SetFromErrno(PyExc_OSError);
122 122 return NULL;
123 123 }
124 124
125 125 Py_INCREF(Py_None);
126 126 return Py_None;
127 127 }
128 128
129 129 PyDoc_STRVAR(
130 130 remove_watch_doc,
131 131 "remove_watch(fd, wd)\n"
132 132 "\n"
133 133 " fd: file descriptor returned by init()\n"
134 134 " wd: watch descriptor returned by add_watch()\n"
135 135 "\n"
136 136 "Remove a watch associated with the watch descriptor wd from the\n"
137 137 "inotify instance associated with the file descriptor fd.\n"
138 138 "\n"
139 139 "Removing a watch causes an IN_IGNORED event to be generated for this\n"
140 140 "watch descriptor.");
141 141
142 142 #define bit_name(x) {x, #x}
143 143
144 144 static struct {
145 145 int bit;
146 146 const char *name;
147 147 PyObject *pyname;
148 148 } bit_names[] = {
149 149 bit_name(IN_ACCESS),
150 150 bit_name(IN_MODIFY),
151 151 bit_name(IN_ATTRIB),
152 152 bit_name(IN_CLOSE_WRITE),
153 153 bit_name(IN_CLOSE_NOWRITE),
154 154 bit_name(IN_OPEN),
155 155 bit_name(IN_MOVED_FROM),
156 156 bit_name(IN_MOVED_TO),
157 157 bit_name(IN_CREATE),
158 158 bit_name(IN_DELETE),
159 159 bit_name(IN_DELETE_SELF),
160 160 bit_name(IN_MOVE_SELF),
161 161 bit_name(IN_UNMOUNT),
162 162 bit_name(IN_Q_OVERFLOW),
163 163 bit_name(IN_IGNORED),
164 164 bit_name(IN_ONLYDIR),
165 165 bit_name(IN_DONT_FOLLOW),
166 166 bit_name(IN_MASK_ADD),
167 167 bit_name(IN_ISDIR),
168 168 bit_name(IN_ONESHOT),
169 169 {0}
170 170 };
171 171
172 172 static PyObject *decode_mask(int mask)
173 173 {
174 174 PyObject *ret = PyList_New(0);
175 175 int i;
176 176
177 177 if (ret == NULL)
178 178 goto bail;
179 179
180 180 for (i = 0; bit_names[i].bit; i++) {
181 181 if (mask & bit_names[i].bit) {
182 182 if (bit_names[i].pyname == NULL) {
183 183 bit_names[i].pyname = PyString_FromString(bit_names[i].name);
184 184 if (bit_names[i].pyname == NULL)
185 185 goto bail;
186 186 }
187 187 Py_INCREF(bit_names[i].pyname);
188 188 if (PyList_Append(ret, bit_names[i].pyname) == -1)
189 189 goto bail;
190 190 }
191 191 }
192 192
193 193 goto done;
194 194
195 195 bail:
196 196 Py_CLEAR(ret);
197 197
198 198 done:
199 199 return ret;
200 200 }
201 201
202 202 static PyObject *pydecode_mask(PyObject *self, PyObject *args)
203 203 {
204 204 int mask;
205 205
206 206 if (!PyArg_ParseTuple(args, "i:decode_mask", &mask))
207 207 return NULL;
208 208
209 209 return decode_mask(mask);
210 210 }
211 211
212 212 PyDoc_STRVAR(
213 213 decode_mask_doc,
214 214 "decode_mask(mask) -> list_of_strings\n"
215 215 "\n"
216 216 "Decode an inotify mask value into a list of strings that give the\n"
217 217 "name of each bit set in the mask.");
218 218
219 219 static char doc[] = "Low-level inotify interface wrappers.";
220 220
221 221 static void define_const(PyObject *dict, const char *name, uint32_t val)
222 222 {
223 223 PyObject *pyval = PyInt_FromLong(val);
224 224 PyObject *pyname = PyString_FromString(name);
225 225
226 226 if (!pyname || !pyval)
227 227 goto bail;
228 228
229 229 PyDict_SetItem(dict, pyname, pyval);
230 230
231 231 bail:
232 232 Py_XDECREF(pyname);
233 233 Py_XDECREF(pyval);
234 234 }
235 235
236 236 static void define_consts(PyObject *dict)
237 237 {
238 238 define_const(dict, "IN_ACCESS", IN_ACCESS);
239 239 define_const(dict, "IN_MODIFY", IN_MODIFY);
240 240 define_const(dict, "IN_ATTRIB", IN_ATTRIB);
241 241 define_const(dict, "IN_CLOSE_WRITE", IN_CLOSE_WRITE);
242 242 define_const(dict, "IN_CLOSE_NOWRITE", IN_CLOSE_NOWRITE);
243 243 define_const(dict, "IN_OPEN", IN_OPEN);
244 244 define_const(dict, "IN_MOVED_FROM", IN_MOVED_FROM);
245 245 define_const(dict, "IN_MOVED_TO", IN_MOVED_TO);
246 246
247 247 define_const(dict, "IN_CLOSE", IN_CLOSE);
248 248 define_const(dict, "IN_MOVE", IN_MOVE);
249 249
250 250 define_const(dict, "IN_CREATE", IN_CREATE);
251 251 define_const(dict, "IN_DELETE", IN_DELETE);
252 252 define_const(dict, "IN_DELETE_SELF", IN_DELETE_SELF);
253 253 define_const(dict, "IN_MOVE_SELF", IN_MOVE_SELF);
254 254 define_const(dict, "IN_UNMOUNT", IN_UNMOUNT);
255 255 define_const(dict, "IN_Q_OVERFLOW", IN_Q_OVERFLOW);
256 256 define_const(dict, "IN_IGNORED", IN_IGNORED);
257 257
258 258 define_const(dict, "IN_ONLYDIR", IN_ONLYDIR);
259 259 define_const(dict, "IN_DONT_FOLLOW", IN_DONT_FOLLOW);
260 260 define_const(dict, "IN_MASK_ADD", IN_MASK_ADD);
261 261 define_const(dict, "IN_ISDIR", IN_ISDIR);
262 262 define_const(dict, "IN_ONESHOT", IN_ONESHOT);
263 263 define_const(dict, "IN_ALL_EVENTS", IN_ALL_EVENTS);
264 264 }
265 265
266 266 struct event {
267 267 PyObject_HEAD
268 268 PyObject *wd;
269 269 PyObject *mask;
270 270 PyObject *cookie;
271 271 PyObject *name;
272 272 };
273 273
274 274 static PyObject *event_wd(PyObject *self, void *x)
275 275 {
276 276 struct event *evt = (struct event *)self;
277 277 Py_INCREF(evt->wd);
278 278 return evt->wd;
279 279 }
280 280
281 281 static PyObject *event_mask(PyObject *self, void *x)
282 282 {
283 283 struct event *evt = (struct event *)self;
284 284 Py_INCREF(evt->mask);
285 285 return evt->mask;
286 286 }
287 287
288 288 static PyObject *event_cookie(PyObject *self, void *x)
289 289 {
290 290 struct event *evt = (struct event *)self;
291 291 Py_INCREF(evt->cookie);
292 292 return evt->cookie;
293 293 }
294 294
295 295 static PyObject *event_name(PyObject *self, void *x)
296 296 {
297 297 struct event *evt = (struct event *)self;
298 298 Py_INCREF(evt->name);
299 299 return evt->name;
300 300 }
301 301
302 302 static struct PyGetSetDef event_getsets[] = {
303 303 {"wd", event_wd, NULL,
304 304 "watch descriptor"},
305 305 {"mask", event_mask, NULL,
306 306 "event mask"},
307 307 {"cookie", event_cookie, NULL,
308 308 "rename cookie, if rename-related event"},
309 309 {"name", event_name, NULL,
310 310 "file name"},
311 311 {NULL}
312 312 };
313 313
314 314 PyDoc_STRVAR(
315 315 event_doc,
316 316 "event: Structure describing an inotify event.");
317 317
318 318 static PyObject *event_new(PyTypeObject *t, PyObject *a, PyObject *k)
319 319 {
320 320 return (*t->tp_alloc)(t, 0);
321 321 }
322 322
323 323 static void event_dealloc(struct event *evt)
324 324 {
325 325 Py_XDECREF(evt->wd);
326 326 Py_XDECREF(evt->mask);
327 327 Py_XDECREF(evt->cookie);
328 328 Py_XDECREF(evt->name);
329 329
330 (*evt->ob_type->tp_free)(evt);
330 Py_TYPE(evt)->tp_free(evt);
331 331 }
332 332
333 333 static PyObject *event_repr(struct event *evt)
334 334 {
335 335 int wd = PyInt_AsLong(evt->wd);
336 336 int cookie = evt->cookie == Py_None ? -1 : PyInt_AsLong(evt->cookie);
337 337 PyObject *ret = NULL, *pymasks = NULL, *pymask = NULL;
338 338 PyObject *join = NULL;
339 339 char *maskstr;
340 340
341 341 join = PyString_FromString("|");
342 342 if (join == NULL)
343 343 goto bail;
344 344
345 345 pymasks = decode_mask(PyInt_AsLong(evt->mask));
346 346 if (pymasks == NULL)
347 347 goto bail;
348 348
349 349 pymask = _PyString_Join(join, pymasks);
350 350 if (pymask == NULL)
351 351 goto bail;
352 352
353 353 maskstr = PyString_AsString(pymask);
354 354
355 355 if (evt->name != Py_None) {
356 356 PyObject *pyname = PyString_Repr(evt->name, 1);
357 357 char *name = pyname ? PyString_AsString(pyname) : "???";
358 358
359 359 if (cookie == -1)
360 360 ret = PyString_FromFormat(
361 361 "event(wd=%d, mask=%s, name=%s)",
362 362 wd, maskstr, name);
363 363 else
364 364 ret = PyString_FromFormat("event(wd=%d, mask=%s, "
365 365 "cookie=0x%x, name=%s)",
366 366 wd, maskstr, cookie, name);
367 367
368 368 Py_XDECREF(pyname);
369 369 } else {
370 370 if (cookie == -1)
371 371 ret = PyString_FromFormat("event(wd=%d, mask=%s)",
372 372 wd, maskstr);
373 373 else {
374 374 ret = PyString_FromFormat(
375 375 "event(wd=%d, mask=%s, cookie=0x%x)",
376 376 wd, maskstr, cookie);
377 377 }
378 378 }
379 379
380 380 goto done;
381 381 bail:
382 382 Py_CLEAR(ret);
383 383
384 384 done:
385 385 Py_XDECREF(pymask);
386 386 Py_XDECREF(pymasks);
387 387 Py_XDECREF(join);
388 388
389 389 return ret;
390 390 }
391 391
392 392 static PyTypeObject event_type = {
393 393 PyObject_HEAD_INIT(NULL)
394 394 0, /*ob_size*/
395 395 "_inotify.event", /*tp_name*/
396 396 sizeof(struct event), /*tp_basicsize*/
397 397 0, /*tp_itemsize*/
398 398 (destructor)event_dealloc, /*tp_dealloc*/
399 399 0, /*tp_print*/
400 400 0, /*tp_getattr*/
401 401 0, /*tp_setattr*/
402 402 0, /*tp_compare*/
403 403 (reprfunc)event_repr, /*tp_repr*/
404 404 0, /*tp_as_number*/
405 405 0, /*tp_as_sequence*/
406 406 0, /*tp_as_mapping*/
407 407 0, /*tp_hash */
408 408 0, /*tp_call*/
409 409 0, /*tp_str*/
410 410 0, /*tp_getattro*/
411 411 0, /*tp_setattro*/
412 412 0, /*tp_as_buffer*/
413 413 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
414 414 event_doc, /* tp_doc */
415 415 0, /* tp_traverse */
416 416 0, /* tp_clear */
417 417 0, /* tp_richcompare */
418 418 0, /* tp_weaklistoffset */
419 419 0, /* tp_iter */
420 420 0, /* tp_iternext */
421 421 0, /* tp_methods */
422 422 0, /* tp_members */
423 423 event_getsets, /* tp_getset */
424 424 0, /* tp_base */
425 425 0, /* tp_dict */
426 426 0, /* tp_descr_get */
427 427 0, /* tp_descr_set */
428 428 0, /* tp_dictoffset */
429 429 0, /* tp_init */
430 430 0, /* tp_alloc */
431 431 event_new, /* tp_new */
432 432 };
433 433
434 434 PyObject *read_events(PyObject *self, PyObject *args)
435 435 {
436 436 PyObject *ctor_args = NULL;
437 437 PyObject *pybufsize = NULL;
438 438 PyObject *ret = NULL;
439 439 int bufsize = 65536;
440 440 char *buf = NULL;
441 441 int nread, pos;
442 442 int fd;
443 443
444 444 if (!PyArg_ParseTuple(args, "i|O:read", &fd, &pybufsize))
445 445 goto bail;
446 446
447 447 if (pybufsize && pybufsize != Py_None)
448 448 bufsize = PyInt_AsLong(pybufsize);
449 449
450 450 ret = PyList_New(0);
451 451 if (ret == NULL)
452 452 goto bail;
453 453
454 454 if (bufsize <= 0) {
455 455 int r;
456 456
457 457 Py_BEGIN_ALLOW_THREADS;
458 458 r = ioctl(fd, FIONREAD, &bufsize);
459 459 Py_END_ALLOW_THREADS;
460 460
461 461 if (r == -1) {
462 462 PyErr_SetFromErrno(PyExc_OSError);
463 463 goto bail;
464 464 }
465 465 if (bufsize == 0)
466 466 goto done;
467 467 }
468 468 else {
469 469 static long name_max;
470 470 static long name_fd = -1;
471 471 long min;
472 472
473 473 if (name_fd != fd) {
474 474 name_fd = fd;
475 475 Py_BEGIN_ALLOW_THREADS;
476 476 name_max = fpathconf(fd, _PC_NAME_MAX);
477 477 Py_END_ALLOW_THREADS;
478 478 }
479 479
480 480 min = sizeof(struct inotify_event) + name_max + 1;
481 481
482 482 if (bufsize < min) {
483 483 PyErr_Format(PyExc_ValueError,
484 484 "bufsize must be at least %d", (int)min);
485 485 goto bail;
486 486 }
487 487 }
488 488
489 489 buf = alloca(bufsize);
490 490
491 491 Py_BEGIN_ALLOW_THREADS;
492 492 nread = read(fd, buf, bufsize);
493 493 Py_END_ALLOW_THREADS;
494 494
495 495 if (nread == -1) {
496 496 PyErr_SetFromErrno(PyExc_OSError);
497 497 goto bail;
498 498 }
499 499
500 500 ctor_args = PyTuple_New(0);
501 501
502 502 if (ctor_args == NULL)
503 503 goto bail;
504 504
505 505 pos = 0;
506 506
507 507 while (pos < nread) {
508 508 struct inotify_event *in = (struct inotify_event *)(buf + pos);
509 509 struct event *evt;
510 510 PyObject *obj;
511 511
512 512 obj = PyObject_CallObject((PyObject *)&event_type, ctor_args);
513 513
514 514 if (obj == NULL)
515 515 goto bail;
516 516
517 517 evt = (struct event *)obj;
518 518
519 519 evt->wd = PyInt_FromLong(in->wd);
520 520 evt->mask = PyInt_FromLong(in->mask);
521 521 if (in->mask & IN_MOVE)
522 522 evt->cookie = PyInt_FromLong(in->cookie);
523 523 else {
524 524 Py_INCREF(Py_None);
525 525 evt->cookie = Py_None;
526 526 }
527 527 if (in->len)
528 528 evt->name = PyString_FromString(in->name);
529 529 else {
530 530 Py_INCREF(Py_None);
531 531 evt->name = Py_None;
532 532 }
533 533
534 534 if (!evt->wd || !evt->mask || !evt->cookie || !evt->name)
535 535 goto mybail;
536 536
537 537 if (PyList_Append(ret, obj) == -1)
538 538 goto mybail;
539 539
540 540 pos += sizeof(struct inotify_event) + in->len;
541 541 continue;
542 542
543 543 mybail:
544 544 Py_CLEAR(evt->wd);
545 545 Py_CLEAR(evt->mask);
546 546 Py_CLEAR(evt->cookie);
547 547 Py_CLEAR(evt->name);
548 548 Py_DECREF(obj);
549 549
550 550 goto bail;
551 551 }
552 552
553 553 goto done;
554 554
555 555 bail:
556 556 Py_CLEAR(ret);
557 557
558 558 done:
559 559 Py_XDECREF(ctor_args);
560 560
561 561 return ret;
562 562 }
563 563
564 564 PyDoc_STRVAR(
565 565 read_doc,
566 566 "read(fd, bufsize[=65536]) -> list_of_events\n"
567 567 "\n"
568 568 "\nRead inotify events from a file descriptor.\n"
569 569 "\n"
570 570 " fd: file descriptor returned by init()\n"
571 571 " bufsize: size of buffer to read into, in bytes\n"
572 572 "\n"
573 573 "Return a list of event objects.\n"
574 574 "\n"
575 575 "If bufsize is > 0, block until events are available to be read.\n"
576 576 "Otherwise, immediately return all events that can be read without\n"
577 577 "blocking.");
578 578
579 579 static PyMethodDef methods[] = {
580 580 {"init", init, METH_VARARGS, init_doc},
581 581 {"add_watch", add_watch, METH_VARARGS, add_watch_doc},
582 582 {"remove_watch", remove_watch, METH_VARARGS, remove_watch_doc},
583 583 {"read", read_events, METH_VARARGS, read_doc},
584 584 {"decode_mask", pydecode_mask, METH_VARARGS, decode_mask_doc},
585 585 {NULL},
586 586 };
587 587
588 588 void init_inotify(void)
589 589 {
590 590 PyObject *mod, *dict;
591 591
592 592 if (PyType_Ready(&event_type) == -1)
593 593 return;
594 594
595 595 mod = Py_InitModule3("_inotify", methods, doc);
596 596
597 597 dict = PyModule_GetDict(mod);
598 598
599 599 if (dict)
600 600 define_consts(dict);
601 601 }
General Comments 0
You need to be logged in to leave comments. Login now