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.
master
Dustin 2018-09-03 14:26:46 -05:00
parent b7070876e5
commit eefcc554c0
1 changed files with 12 additions and 14 deletions

View File

@ -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'''