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