def from_bytes(cls: t.Type[T], data: bytes) -> T: # As with to_bytes, we can't just cast the bytes to a struct sockaddr_storage and read its data field, # because that would pad the data with a bunch of null bytes, # and would not preserve the length of the valid data family = ffi.cast('sa_family_t*', ffi.from_buffer(data)) rest = data[ffi.sizeof('sa_family_t'):] return cls(family=AF(family[0]), data=rest)
def from_bytes(cls: t.Type[T], data: bytes) -> T: # type: ignore family = ffi.cast('sa_family_t*', ffi.from_buffer(data)) rest = data[ffi.sizeof('sa_family_t'):] return cls( family=AF(family[0]), data=rest )
class InotifyEvent: wd: WatchDescriptor mask: IN cookie: int name: t.Optional[str] MINIMUM_SIZE_TO_READ_ONE_EVENT = ffi.sizeof('struct inotify_event') + NAME_MAX + 1 def to_bytes(self) -> bytes: if self.name is not None: name = self.name.encode() name_len = len(name) else: name = b"" name_len = 0 return bytes(ffi.buffer(ffi.new('struct inotify_event*', { "wd": self.wd, "mask": self.mask, "cookie": self.cookie, "len": name_len, "name": name, }))) T = t.TypeVar('T', bound='InotifyEvent') @classmethod def from_bytes(cls: t.Type[T], data: bytes) -> t.Tuple[T, int]: struct = ffi.cast('struct inotify_event*', ffi.from_buffer(data)) value = cls( wd=WatchDescriptor(struct.wd), mask=IN(struct.mask), cookie=struct.cookie, name=ffi.string(struct.name, struct.len).decode() if struct.len else None, ) size = ffi.sizeof("struct inotify_event") + struct.len return value, size
def from_bytes(cls: t.Type[T], data: bytes) -> T: struct = ffi.cast('struct fuse_getxattr_out*', ffi.from_buffer(data)) variable = data[ffi.sizeof('struct fuse_getxattr_out'):] if len(variable) < struct.size: raise Exception("partial fuse_getxattr_out packet, received size", len(variable), "expected size", struct.size) # -1 to strip null byte return cls(os.fsdecode(variable[:struct.size - 1]))
def from_bytes(cls: t.Type[T], data: bytes) -> T: struct = ffi.cast('struct fuse_out_header*', ffi.from_buffer(data)) if struct.len > len(data): raise Exception( "only part of the FUSE out packet was passed to from_bytes", "length field in header is", struct.len, "but passed buffer is only", len(data)) msg_data = data[ffi.sizeof('struct fuse_out_header'):struct.len] return cls.from_header(FuseOutHeader.from_cffi(struct), msg_data)
def to_bytes(self) -> bytes: namebytes = self.name.encode() + b'\0' length = ffi.sizeof('struct fuse_dirent') + len(namebytes) padding = align(length, 8) - length namebytes = namebytes + bytes(padding) return bytes( ffi.buffer( ffi.new('struct fuse_dirent*', self._to_cffi_dict(namebytes)))) + namebytes
def from_bytes(self, data: bytes) -> T_cmsg: record = ffi.cast('struct cmsghdr*', ffi.from_buffer(data)) if record.cmsg_level != self.cls.level(): raise Exception("serializer for level", self.cls.level(), "got message for level", record.cmsg_level) if record.cmsg_type != self.cls.type(): raise Exception("serializer for type", self.cls.type(), "got message for type", record.cmsg_type) return self.cls.from_data(self.task, data[ffi.sizeof('struct cmsghdr'):record.cmsg_len])
def from_bytes(cls: t.Type[T], data: bytes) -> t.Tuple[T, int]: struct = ffi.cast('struct inotify_event*', ffi.from_buffer(data)) value = cls( wd=WatchDescriptor(struct.wd), mask=IN(struct.mask), cookie=struct.cookie, name=ffi.string(struct.name, struct.len).decode() if struct.len else None, ) size = ffi.sizeof("struct inotify_event") + struct.len return value, size
def to_bytes(self) -> bytes: msg_data = self.msg_to_bytes() return bytes( ffi.buffer( ffi.new( 'struct fuse_out_header*', { 'len': ffi.sizeof('struct fuse_out_header') + len(msg_data), 'error': self.hdr.error, 'unique': self.hdr.unique, }))) + msg_data
def to_bytes(self, val: T_cmsg) -> bytes: if not isinstance(val, self.cls): raise Exception("Serializer for", self.cls, "had to_bytes called on different type", val) data = val.to_data() header = bytes(ffi.buffer(ffi.new('struct cmsghdr*', { "cmsg_len": ffi.sizeof('struct cmsghdr') + len(data), "cmsg_level": val.level(), "cmsg_type": val.type(), }))) return header + data
def to_bytes(self) -> bytes: namebytes = self.dirent.name.encode() + b'\0' length = ffi.sizeof('struct fuse_direntplus') + len(namebytes) padding = align(length, 8) - length namebytes = namebytes + bytes(padding) return bytes( ffi.buffer( ffi.new( 'struct fuse_direntplus*', { "entry_out": self.entry_out._to_cffi_dict(), "dirent": self.dirent._to_cffi_dict(namebytes), }))) + namebytes
async def read_cffi(self, name: str) -> t.Any: "Read, parse, and return this fixed-size cffi type." size = ffi.sizeof(name) data = await self.read_length(size) if data is None: raise EOFException("got EOF while expecting to read a", name) nameptr = name + '*' dest = ffi.new(nameptr) # ffi.cast drops the reference to the backing buffer, so we have to copy it src = ffi.cast(nameptr, ffi.from_buffer(data)) ffi.memmove(dest, src, size) return dest[0]
def from_header(cls: t.Type[T], hdr: FuseOutHeader, data: bytes) -> T: entries = [] while len(data) > 0: # We do the work of from_bytes in this class instead of in Dirent because we need the # raw length field from the struct; merely doing len(name) will exclude padding. struct = ffi.cast('struct fuse_dirent*', ffi.from_buffer(data)) record_length = ffi.sizeof('struct fuse_dirent') + struct.namelen if len(data) < record_length: raise Exception( "partial packet passed to FuseDirent.from_bytes") entries.append(FuseDirent.from_cffi(struct)) data = data[record_length:] return cls(hdr=hdr, msg=entries)
def split_iovec(iov: WrittenPointer[IovecList], ret: int ) -> t.Tuple[WrittenPointer[IovecList], t.Optional[t.Tuple[Pointer, Pointer]], WrittenPointer[IovecList]]: first, middle, last = iov.value.split_with_middle(ret) if middle is None: first_count = len(first) else: # we include the partially-consumed middle pointer in the first WP[IovecList] returned; # I think this is the most ergonomic choice, since in the normal case, I'll want to # operate on middle separately, then on second. first_count = len(first) + 1 # TODO this is fairly ad-hoc, splitting on a WrittenPointer should really call into the # Serializer to determine validity. (And then I suppose we would have .degrade to degrade a # WrittenPointer back into a Pointer so we can split it??? Hmm, seems awkward...) first_ptr, last_ptr = iov.split(first_count * ffi.sizeof('struct iovec')) return first_ptr._wrote(first), middle, last_ptr._wrote(last)
def from_bytes(cls: t.Type[T], data: bytes) -> T: header = ffi.sizeof('sa_family_t') if len(data) < header: raise Exception("data too smalllll", data) struct = ffi.cast('struct sockaddr_un*', ffi.from_buffer(data)) cls.check_family(AF(struct.sun_family)) if len(data) == header: # unnamed socket, name is empty length = 0 elif struct.sun_path[0] == b'\0': # abstract socket, entire buffer is part of path length = len(data) - header else: # TODO handle the case where there's no null terminator # pathname socket, path is null-terminated length = lib.strlen(struct.sun_path) return cls(bytes(ffi.buffer(struct.sun_path, length)))
def sizeof(cls) -> int: return ffi.sizeof('struct ifreq')
def sizeof(cls) -> int: return ffi.sizeof('struct timespec')
def sizeof(cls) -> int: return ffi.sizeof('struct signalfd_siginfo')
def sizeof(cls) -> int: return ffi.sizeof('struct kernel_sigset')
def to_bytes(self) -> bytes: addr = ffi.new('struct sockaddr_un*', (AF.UNIX, self.path)) real_length = ffi.sizeof('sa_family_t') + len(self.path) + 1 return bytes(ffi.buffer(addr))[:real_length]
events = await self.wait() for event in events: if event.mask & mask and (event.name == name if name else True): return event async def remove(self) -> None: "Remove this watch from inotify" await self.inotify.asyncfd.handle.inotify_rm_watch(self.wd) # we'll mark this Watch as removed once we get the IN_IGNORED event; # only after that do we know for sure that there are no more events # coming for this Watch. _inotify_read_size = 4096 _inotify_minimum_size_to_read_one_event = (ffi.sizeof('struct inotify_event') + NAME_MAX + 1) assert _inotify_read_size > _inotify_minimum_size_to_read_one_event class Inotify: "An inotify file descriptor, which allows monitoring filesystem paths for events." def __init__(self, asyncfd: AsyncFileDescriptor, ram: RAM) -> None: "Private; use Inotify.make instead." self.asyncfd = asyncfd self.ram = ram self.wd_to_watch: t.Dict[WatchDescriptor, Watch] = {} self.running_wait = OneAtATime() @staticmethod
def sizeof(cls) -> int: return ffi.sizeof('struct file_clone_range')
def sizeof(cls) -> int: # this is the maximum size of a sockaddr return ffi.sizeof('struct sockaddr_storage')
def sizeof(cls) -> int: return ffi.sizeof('struct kernel_sigaction')
def sizeof(cls) -> int: return ffi.sizeof('struct sockaddr_storage')
def sizeof(cls) -> int: return ffi.sizeof('cpu_set_t')
def sizeof(cls) -> int: return ffi.sizeof('struct fdpair')
def sizeof(cls) -> int: return ffi.sizeof('struct epoll_event')
def sizeof(cls) -> int: return ffi.sizeof('struct sockaddr_un')
def sizeof(cls) -> int: return ffi.sizeof('struct rlimit')