From eefcc554c0d3e0b025f01488c9909407ef731bc2 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Mon, 3 Sep 2018 14:26:46 -0500 Subject: [PATCH] inotify: Correctly handle multi-struct reads When reading from the *inotify* file descriptor, multiple structs can be returned. Because the read loop was incorrectly calculating offsets, messages would frequently get lost in this way. This commit simplifies the logic of the read loop, using only a single position indicator and correctly calculating all offsets from that on each iteration. The result is that no more messages are incorrectly skipped. --- src/linuxapi/inotify.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/linuxapi/inotify.py b/src/linuxapi/inotify.py index 485837b..6da79ca 100644 --- a/src/linuxapi/inotify.py +++ b/src/linuxapi/inotify.py @@ -119,9 +119,9 @@ class InotifyError(OSError): class Inotify(object): '''Wrapper class for Linux inotify capabilities''' - BUFSIZE = 4096 STRUCT_FMT = '@iIII' STRUCT_SIZE = struct.calcsize(STRUCT_FMT) + BUFSIZE = STRUCT_SIZE + 256 def __init__(self): fd = _libc.inotify_init() @@ -173,21 +173,19 @@ class Inotify(object): buf = memoryview(os.read(self.__fd, self.BUFSIZE)) nread = len(buf) - i = begin = 0 - end = self.STRUCT_SIZE - while i < nread: - wd, mask, cookie, sz = self._unpack(buf[begin:end]) - begin = end - end += sz - x = begin - while buf[x:x + 1] != b'\x00': - x += 1 - name = buf[begin:x].tobytes() + pos = 0 + while pos < nread: + packed = buf[pos:pos + self.STRUCT_SIZE] + pos += self.STRUCT_SIZE + wd, mask, cookie, sz = self._unpack(packed) + if sz: + name = buf[pos:pos + sz].tobytes() + name = name[:name.index(b'\x00')] + pos += sz + else: + name = None pathname = self.__watches[wd] - i += end yield Event(wd, mask, cookie, name, pathname) - begin = end - end += self.STRUCT_SIZE def close(self): '''Close all watch descriptors and the inotify descriptor'''