from message import * from socket import error import traceback import fsctl REQ_READDIR_LEN = struct.calcsize("H") REQ_RW_LEN = struct.calcsize("qL") FATTR_LEN = struct.calcsize("LLLLLqLLLLL") REQ_MODE_LEN = struct.calcsize("i") class SilentFSError(Exception): pass class FileSystem(object): def mount(cls, mount_point, *args, **kwds): fsctl.mount(lambda: cls(*args, **kwds), mount_point) mount = classmethod(mount) def handle(self, sock): self._handle_READDIR_cache = {} handlers = [getattr(self, 'handle_'+name) for name in MESSAGES] try: while True: msgtype, msgdata = recvmsg(sock) try: msgdata = handlers[msgtype](msgdata) rep = OK except SilentFSError: msgdata = '' rep = ERROR except: traceback.print_exc() msgdata = '' rep = ERROR sendmsg(sock, rep, msgdata) except EOFError: print "disconnected" handle_OK = None handle_MOUNT = None handle_UMOUNT = None def handle_READDIR(self, msg): offset, = struct.unpack("H", msg[:REQ_READDIR_LEN]) assert msg.endswith('\x00') dirname = msg[REQ_READDIR_LEN:-1] if offset == 2: filenames = [fn for fn in self.readdir(dirname) if fn != '.' and fn != '..'] self._handle_READDIR_cache[dirname] = filenames else: assert offset > 2 try: filenames = self._handle_READDIR_cache[dirname][offset-2:] except KeyError: return '\x00' if not filenames: del self._handle_READDIR_cache[dirname] return '\x00' n = 0 result = [] for fn in filenames: n += len(fn)+1 if n >= LU_MAXDATA: break result.append(fn) result.append('\x00') return '\n'.join(result) def handle_READ(self, msg): offset, count = struct.unpack("qL", msg[:REQ_RW_LEN]) assert msg.endswith('\x00') filename = msg[REQ_RW_LEN:-1] buffer = [] while count > 0: moredata = self.read(filename, offset, count) if not moredata: moredata = '\x00' * count count -= len(moredata) offset += len(moredata) buffer.append(moredata) assert count == 0 return ''.join(buffer) def handle_WRITE(self, msg): offset, count = struct.unpack("qL", msg[:REQ_RW_LEN]) i = len(msg) - count assert msg[i-1] == '\x00' filename = msg[REQ_RW_LEN:i-1] buffer = msg[i:] while buffer: count = self.write(filename, offset, buffer) offset += count buffer = buffer[count:] return '' def handle_STAT(self, msg): assert msg.endswith('\x00') filename = msg[:-1] return self._parse_STAT(self.stat(filename)) def _parse_STAT(self, st): if len(st) == 10: # os.stat() result: ignore dev mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime = st else: mode, nlink, uid, gid, size, atime, mtime, ctime = st ino = 0 return struct.pack("LLLLLqLLLLL", ino, mode, nlink, uid, gid, size, atime, mtime, ctime, 0, 0) def handle_MKDIR(self, msg): mode, = struct.unpack("i", msg[:REQ_MODE_LEN]) assert msg.endswith('\x00') dirname = msg[REQ_MODE_LEN:-1] self.mkdir(dirname, mode) return '' def handle_RMDIR(self, msg): assert msg.endswith('\x00') dirname = msg[:-1] self.rmdir(dirname) return '' def handle_CREATE(self, msg): mode, = struct.unpack("i", msg[:REQ_MODE_LEN]) assert msg.endswith('\x00') filename = msg[REQ_MODE_LEN:-1] self.create(filename, mode) return '' def handle_UNLINK(self, msg): assert msg.endswith('\x00') filename = msg[:-1] self.unlink(filename) return '' def handle_RENAME(self, msg): fromname, toname, empty = msg.split('\x00') assert empty == '' self.rename(fromname, toname) return '' def handle_OPEN(self, msg): mode, = struct.unpack("i", msg[:REQ_MODE_LEN]) assert msg.endswith('\x00') filename = msg[REQ_MODE_LEN:-1] self.open(filename, mode) return '' def handle_RELEASE(self, msg): assert msg.endswith('\x00') filename = msg[:-1] self.release(filename) return '' def handle_READLINK(self, msg): assert msg.endswith('\x00') filename = msg[:-1] buffer = self.readlink(filename) return buffer + '\x00' def handle_LINK(self, msg): link, target, empty = msg.split('\x00') assert empty == '' self.link(target, link) return '' def handle_SYMLINK(self, msg): link, target, empty = msg.split('\x00') assert empty == '' self.symlink(target, link) return '' def handle_SETATTR(self, msg): st = struct.unpack("LLLLLqLLLLL", msg[:FATTR_LEN]) assert msg.endswith('\x00') filename = msg[FATTR_LEN:-1] self.setattr(filename, st[1:9]) return ''