Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

_inotify.py 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. # -*- test-case-name: twisted.internet.test.test_inotify -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. Very low-level ctypes-based interface to Linux inotify(7).
  6. ctypes and a version of libc which supports inotify system calls are
  7. required.
  8. """
  9. import ctypes
  10. import ctypes.util
  11. from typing import cast
  12. from twisted.python.filepath import FilePath
  13. class INotifyError(Exception):
  14. """
  15. Unify all the possible exceptions that can be raised by the INotify API.
  16. """
  17. def init() -> int:
  18. """
  19. Create an inotify instance and return the associated file descriptor.
  20. """
  21. fd = cast(int, libc.inotify_init())
  22. if fd < 0:
  23. raise INotifyError("INotify initialization error.")
  24. return fd
  25. def add(fd: int, path: FilePath, mask: int) -> int:
  26. """
  27. Add a watch for the given path to the inotify file descriptor, and return
  28. the watch descriptor.
  29. @param fd: The file descriptor returned by C{libc.inotify_init}.
  30. @param path: The path to watch via inotify.
  31. @param mask: Bitmask specifying the events that inotify should monitor.
  32. """
  33. wd = cast(int, libc.inotify_add_watch(fd, path.asBytesMode().path, mask))
  34. if wd < 0:
  35. raise INotifyError(f"Failed to add watch on '{path!r}' - ({wd!r})")
  36. return wd
  37. def remove(fd: int, wd: int) -> None:
  38. """
  39. Remove the given watch descriptor from the inotify file descriptor.
  40. """
  41. # When inotify_rm_watch returns -1 there's an error:
  42. # The errno for this call can be either one of the following:
  43. # EBADF: fd is not a valid file descriptor.
  44. # EINVAL: The watch descriptor wd is not valid; or fd is
  45. # not an inotify file descriptor.
  46. #
  47. # if we can't access the errno here we cannot even raise
  48. # an exception and we need to ignore the problem, one of
  49. # the most common cases is when you remove a directory from
  50. # the filesystem and that directory is observed. When inotify
  51. # tries to call inotify_rm_watch with a non existing directory
  52. # either of the 2 errors might come up because the files inside
  53. # it might have events generated way before they were handled.
  54. # Unfortunately only ctypes in Python 2.6 supports accessing errno:
  55. # http://bugs.python.org/issue1798 and in order to solve
  56. # the problem for previous versions we need to introduce
  57. # code that is quite complex:
  58. # http://stackoverflow.com/questions/661017/access-to-errno-from-python
  59. #
  60. # See #4310 for future resolution of this issue.
  61. libc.inotify_rm_watch(fd, wd)
  62. def initializeModule(libc: ctypes.CDLL) -> None:
  63. """
  64. Initialize the module, checking if the expected APIs exist and setting the
  65. argtypes and restype for C{inotify_init}, C{inotify_add_watch}, and
  66. C{inotify_rm_watch}.
  67. """
  68. for function in ("inotify_add_watch", "inotify_init", "inotify_rm_watch"):
  69. if getattr(libc, function, None) is None:
  70. raise ImportError("libc6 2.4 or higher needed")
  71. libc.inotify_init.argtypes = []
  72. libc.inotify_init.restype = ctypes.c_int
  73. libc.inotify_rm_watch.argtypes = [ctypes.c_int, ctypes.c_int]
  74. libc.inotify_rm_watch.restype = ctypes.c_int
  75. libc.inotify_add_watch.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_uint32]
  76. libc.inotify_add_watch.restype = ctypes.c_int
  77. name = ctypes.util.find_library("c")
  78. if not name:
  79. raise ImportError("Can't find C library.")
  80. libc = ctypes.cdll.LoadLibrary(name)
  81. initializeModule(libc)