#! /usr/bin/env python import py, lufs, os, time from lufs import FileSystem import localfs bootstrapcode = py.code.Source( "import os, thread, time", lufs.ALL_SOURCE_CODE(), localfs.Filesystem, """ def DO_CONNECT(): res = len(instances) instances.append(Filesystem()) return res, os.getuid(), os.getgid(), time.time() instances = [] global_op = globals() for n, name, args in channel: try: if n is None: meth = global_op['DO_'+name] else: meth = getattr(instances[n], name) res = 0, meth(*args) except Exception, e: res = -1, (e.__class__.__name__, str(e)) channel.send(res) """) # ____________________________________________________________ UID = os.getuid() GID = os.getgid() class ExecNetFS(FileSystem): def __init__(self, factory): self.channel = factory.channel localtime = time.time() self.n, self.remote_uid, self.remote_gid, remotetime = ( self.rmi_call(None, 'CONNECT')) # # The timediff is the difference of the local clocks: # remotehost.time() - localhost.time(). # # The difference is only computed once, and it is "emacs-conservative": # indeed, to make emacs/xemacs happy, it is necessary that when emacs # writes a file, it doesn't get a time that appears to be the future # (which occurs if remotehost.time() > localhost.time()). # To avoid this, we subtract 'timediff' to each file time obtained # from the remote host. For emacs we have to guarantee that # # remotehost.time() - timediff <= localhost.time() # # i.e. timediff >= remotehost.time() - localhost.time() # # so we add 1 second to be on the safe side, and we round up. # if factory.timediff is None: inttimediff = int(remotetime - localtime + 2.0) factory.timediff = inttimediff self.inttimediff = factory.timediff def rmi_call(self, n, name, *args): self.channel.send((n, name, args)) err, res = self.channel.receive() if err: raise RMIError(name, *res) else: return res def stat(self, filename): st = list(self.rmi_call(self.n, 'stat', filename)) if len(st) == 8: st[1:1] = [0, 0] # ino, dev if st[4] == self.remote_uid: st[4] = UID else: st[4] = 0 if st[5] == self.remote_gid: st[5] = GID else: st[5] = 0 st[7] -= self.inttimediff st[8] -= self.inttimediff st[9] -= self.inttimediff #print 'STAT:', filename, '->', st #print 'time.time() =', time.time() return tuple(st) def setattr(self, filename, attribs): mode, nlink, uid, gid, size, atime, mtime, ctime = attribs if uid != UID: raise OSError, "cannot change uid" if gid != GID: raise OSError, "cannot change gid" atime += self.inttimediff mtime += self.inttimediff ctime += self.inttimediff attribs = (mode, nlink, self.remote_uid, self.remote_gid, size, atime, mtime, ctime) return self.rmi_call(self.n, 'setattr', filename, attribs) class ExecNetFSFactory: def __init__(self, gateway): self.channel = gateway.remote_exec(bootstrapcode) self.timediff = None def __call__(self): return ExecNetFS(self) # ____________________________________________________________ # # Default Remote Method Invocation implementation for operations class RMIError(Exception): pass def RMI(name): def wrapper(self, *args): print 'DOING', self.n, name, args res = self.rmi_call(self.n, name, *args) print 'DOING', self.n, name, args, 'GOT', res return res return wrapper for _name in ["readdir", "stat", "mkdir", "rmdir", "create", "unlink", "rename", "open", "release", "read", "write", "readlink", "link", "symlink", "setattr"]: if not hasattr(ExecNetFS, _name): setattr(ExecNetFS, _name, RMI(_name)) del _name ##class NoOwnerExecNetFS(ExecNetFS): ## def setattr(self, filename, attribs): ## mode, nlink, uid, gid, size, atime, mtime, ctime = attribs ## attribs = mode, nlink, None, None, size, atime, mtime, ctime ## ExecNetFS.setattr(self, filename, attribs) # ____________________________________________________________ if __name__ == '__main__': import sys hostname = sys.argv[1] gw = py.execnet.SshGateway(hostname) lufs.mount(ExecNetFSFactory(gw), sys.argv[2])