def to_bytes(self) -> bytes: return bytes(ffi.buffer(ffi.new('struct msghdr*', { "msg_name": ffi.cast('void*', int(self.name.near)) if self.name else ffi.NULL, "msg_namelen": self.name.size() if self.name else 0, "msg_iov": ffi.cast('void*', int(self.iov.near)), "msg_iovlen": len(self.iov.value), "msg_control": ffi.cast('void*', int(self.control.near)) if self.control else ffi.NULL, "msg_controllen": self.control.size() if self.control else 0, "msg_flags": 0, })))
def to_bytes(self) -> bytes: return bytes( ffi.buffer( ffi.new( 'struct kernel_sigaction const*', { "ksa_handler": ffi.cast('sighandler_t', int(self.handler)), "ksa_flags": self.flags, "ksa_restorer": ffi.cast('sigrestore_t', int(self.restorer or 0)), "ksa_mask": self.mask.to_cffi()[0], })))
def from_bytes(cls: t.Type[T], data: bytes) -> T: if len(data) < cls.sizeof(): raise Exception("data too small", data) struct = ffi.cast('struct sockaddr_in6*', ffi.from_buffer(data)) cls.check_family(AF(struct.sin6_family)) return cls(socket.ntohs(struct.sin6_port), ipaddress.IPv6Address(bytes(struct.sin6_addr.s6_addr)), struct.sin6_flowinfo, struct.sin6_scope_id)
def from_bytes(cls: t.Type[T], data: bytes) -> T: if len(data) < cls.sizeof(): raise Exception("data too small", data) struct = ffi.cast('struct sockaddr_in*', ffi.from_buffer(data)) cls.check_family(AF(struct.sin_family)) return cls(socket.ntohs(struct.sin_port), socket.ntohl(struct.sin_addr.s_addr))
def from_bytes(self, data: bytes) -> T_socketpair: struct = ffi.cast('struct fdpair const*', ffi.from_buffer(data)) def make(n: int) -> FileDescriptor: return self.task.make_fd_handle(near.FileDescriptor(int(n))) return self.cls(make(struct.first), make(struct.second))
def from_bytes(self, data: bytes) -> Sockbuf[T]: struct = ffi.cast('socklen_t*', ffi.from_buffer(data)) socklen = struct[0] if socklen > self.buf.size(): raise Exception("not enough buffer space to read socket, need", socklen) valid, rest = self.buf.split(socklen) return Sockbuf(valid, rest)
def from_bytes(cls: t.Type[T], data: bytes) -> T: struct = ffi.cast('struct kernel_sigaction const*', ffi.from_buffer(data)) handler: t.Union[Sighandler, near.Address] int_handler = int(ffi.cast('long int', struct.ksa_handler)) try: handler = Sighandler(int_handler) except ValueError: handler = near.Address(int_handler) int_restorer = int(ffi.cast('long int', struct.ksa_restorer)) return cls( handler=handler, flags=SA(struct.ksa_flags), mask=Sigset.from_cffi(struct.ksa_mask), restorer=near.Address(int_restorer) if int_restorer else None, )
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 )
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 to_bytes(self) -> bytes: ret = b"" for ptr in self: ret += bytes(ffi.buffer(ffi.new('struct iovec const*', { "iov_base": ffi.cast('void*', int(ptr.near)), "iov_len": ptr.size(), }))) return ret
def from_bytes(cls: t.Type[T], data: bytes) -> T: struct = ffi.cast('struct siginfo const*', ffi.from_buffer(data)) return cls( code=struct.si_code, pid=struct.si_pid, uid=struct.si_uid, status=struct.si_status, )
def from_bytes(cls: t.Type[T], data: bytes) -> T: struct = ffi.cast('cpu_set_t*', ffi.from_buffer(data)) ret: t.List[int] = [] for i, val in enumerate(getattr(struct, '__bits')): inc = (64 * i) for bit in bits(val, one_indexed=False): ret.append(bit) return cls(ret)
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_release_in*', ffi.from_buffer(data)) return cls( fh=struct.fh, flags=O(struct.flags), release_flags=FUSE_RELEASE(struct.release_flags), lock_owner=struct.lock_owner, )
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_handle(cffi_ptr) -> Pointer[NativeFunction]: pointer_int = int(ffi.cast('ssize_t', cffi_ptr)) # TODO we're just making up a memory mapping that this pointer is inside; # we should figure out the actual mapping, and the size for that matter. mapping = MemoryMapping(task, near.MemoryMapping(pointer_int, 0, 1), far.File()) return Pointer(mapping, NullGateway(), NativeFunctionSerializer(), StaticAllocation())
def from_bytes(cls: t.Type[T], data: bytes) -> T: struct = ffi.cast('struct fuse_read_in*', ffi.from_buffer(data)) return cls( fh=struct.fh, offset=struct.offset, size=struct.size, read_flags=FUSE_READ(struct.read_flags), flags=O(struct.flags), )
def from_bytes(cls: t.Type[T], data: bytes) -> T: struct = ffi.cast('struct fuse_init_in*', ffi.from_buffer(data)) value = cls( major=struct.major, minor=struct.minor, max_readahead=struct.max_readahead, flags=FUSE_INIT(struct.flags), ) return value
def to_bytes(self) -> bytes: struct = ffi.new( 'struct robust_list_head*', { 'list': (ffi.cast('struct robust_list*', int(self.first.near)), ), 'futex_offset': ffi.offsetof('struct futex_node', 'futex'), 'list_op_pending': ffi.NULL, }) return bytes(ffi.buffer(struct))
async def batch_read(self, ops: t.List[Pointer]) -> t.List[bytes]: ret: t.List[bytes] = [] for src in ops: if src.mapping.task.address_space != self.local_task.address_space: raise Exception("trying to read from pointer", src, "not in local address space") buf = ffi.buffer(ffi.cast('void*', int(src.near)), src.size()) ret.append(bytes(buf)) return ret
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: struct = ffi.cast('struct __user_cap_data_struct[2]', ffi.from_buffer(data)) capset_names = ['effective', 'permitted', 'inheritable'] capsets: t.List[t.Set[CAP]] = [] for name in capset_names: one, two = getattr(struct[0], name), getattr(struct[1], name) capset = from_uint32s(one, two) capsets.append(capset) return cls(*capsets)
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: entries = [] while len(data) > 0: record = ffi.cast('struct linux_dirent64*', ffi.from_buffer(data)) name_len = record.d_reclen - _d_name_offset # the name is padded with null bytes to make the dirent aligned, # so we have to use strlen to find the end name = ffi.string(record.d_name, name_len).decode() entries.append(Dirent(inode=record.d_ino, offset=record.d_off, type=DT(record.d_type), name=name)) data = data[record.d_reclen:] return cls(entries)
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_bytes(self, data: bytes) -> T_cmsglist: entries = [] while len(data) > 0: record = ffi.cast('struct cmsghdr*', ffi.from_buffer(data)) record_data = data[:record.cmsg_len] level = SOL(record.cmsg_level) if level == SOL.SOCKET and record.cmsg_type == int(SCM.RIGHTS): entries.append(CmsgSCMRights.get_serializer(self.task).from_bytes(record_data)) else: raise Exception("unknown cmsg level/type sorry", level, type) data = data[record.cmsg_len:] return self.cls(entries)
def from_bytes(cls: t.Type[T], data: bytes) -> T: struct = ffi.cast('struct fuse_init_out*', ffi.from_buffer(data)) return cls( major=struct.major, minor=struct.minor, max_readahead=struct.max_readahead, flags=FUSE_INIT(struct.flags), max_background=struct.max_background, congestion_threshold=struct.congestion_threshold, max_write=struct.max_write, time_gran=struct.time_gran, )
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 from_bytes(cls: t.Type[T], 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. record = ffi.cast('struct linux_dirent64*', ffi.from_buffer(data)) name_len = record.d_reclen - _d_name_offset # the name is padded with null bytes to make the dirent aligned, # so we have to use strlen to find the end name = ffi.string(record.d_name, name_len).decode() entries.append(Dirent(inode=record.d_ino, offset=record.d_off, type=DT(record.d_type), name=name)) data = data[record.d_reclen:] return cls(entries)
def from_bytes(self, data: bytes) -> RecvMsghdrOut: struct = ffi.cast('struct msghdr*', ffi.from_buffer(data)) if self.name is None: name: t.Optional[Pointer[Address]] = None name_rest: t.Optional[Pointer[Address]] = None else: name, name_rest = self.name.split(struct.msg_namelen) if self.control is None: control: t.Optional[Pointer[CmsgList]] = None control_rest: t.Optional[Pointer[CmsgList]] = None else: control, control_rest = self.control.split(struct.msg_controllen) flags = MsghdrFlags(struct.msg_flags) return RecvMsghdrOut(name, control, flags, name_rest, control_rest)