From: Brian Warner Date: Sat, 5 Jan 2008 02:51:54 +0000 (-0700) Subject: rename 'extensions' to 'contrib', with the goal of making it clear that contrib/... X-Git-Tag: allmydata-tahoe-0.7.0~29 X-Git-Url: https://git.rkrishnan.org/?a=commitdiff_plain;h=f9e8bd2a9868cb1faaba3c3dbc08c25cc1ee8f00;p=tahoe-lafs%2Ftahoe-lafs.git rename 'extensions' to 'contrib', with the goal of making it clear that contrib/ things might not work --- diff --git a/contrib/tahoe-fuse.py b/contrib/tahoe-fuse.py new file mode 100644 index 00000000..919ec476 --- /dev/null +++ b/contrib/tahoe-fuse.py @@ -0,0 +1,377 @@ +#! /usr/bin/env python +''' +Tahoe thin-client fuse module. + +Goals: +- Delegate to Tahoe webapi as much as possible. +- Thin as possible. +- This is a proof-of-concept, not a usable product. +''' + + +#import bindann +#bindann.install_exception_handler() + +import sys, stat, os, errno, urllib + +import simplejson + +# FIXME: Currently uses the old, silly path-based (non-stateful) interface: +import fuse +fuse.fuse_python_api = (0, 1) # Use the silly path-based api for now. + + +### Config: +TahoeConfigDir = '~/.tahoe' +MagicDevNumber = 42 + + +def main(args = sys.argv[1:]): + fs = TahoeFS(os.path.expanduser(TahoeConfigDir)) + fs.main() + + +### Utilities just for debug: +def debugdeco(m): + def dbmeth(self, *a, **kw): + pid = self.GetContext()['pid'] + print '[%d %r]\n%s%r%r' % (pid, get_cmdline(pid), m.__name__, a, kw) + try: + r = m(self, *a, **kw) + if (type(r) is int) and (r < 0): + print '-> -%s\n' % (errno.errorcode[-r],) + else: + repstr = repr(r)[:256] + print '-> %s\n' % (repstr,) + return r + except: + sys.excepthook(*sys.exc_info()) + + return dbmeth + + +def get_cmdline(pid): + f = open('/proc/%d/cmdline' % pid, 'r') + args = f.read().split('\0') + f.close() + assert args[-1] == '' + return args[:-1] + + +class ErrnoExc (Exception): + def __init__(self, eno): + self.eno = eno + Exception.__init__(self, errno.errorcode[eno]) + + @staticmethod + def wrapped(meth): + def wrapper(*args, **kw): + try: + return meth(*args, **kw) + except ErrnoExc, e: + return -e.eno + wrapper.__name__ = meth.__name__ + return wrapper + + +### Heart of the Matter: +class TahoeFS (fuse.Fuse): + def __init__(self, confdir): + fuse.Fuse.__init__(self) + self.confdir = confdir + + self.flags = 0 # FIXME: What goes here? + self.multithreaded = 0 + + # silly path-based file handles. + self.filecontents = {} # {path -> contents} + + self._init_url() + self._init_bookmarks() + + def _init_url(self): + f = open(os.path.join(self.confdir, 'webport'), 'r') + contents = f.read() + f.close() + + fields = contents.split(':') + proto, port = fields[:2] + assert proto == 'tcp' + port = int(port) + self.url = 'http://localhost:%d' % (port,) + + def _init_bookmarks(self): + f = open(os.path.join(self.confdir, 'fuse-bookmarks.uri'), 'r') + uri = f.read().strip() + f.close() + + self.bookmarks = TahoeDir(self.url, uri) + + def _get_node(self, path): + assert path.startswith('/') + if path == '/': + return self.bookmarks.resolve_path([]) + else: + parts = path.split('/')[1:] + return self.bookmarks.resolve_path(parts) + + def _get_contents(self, path): + node = self._get_node(path) + contents = node.open().read() + self.filecontents[path] = contents + return contents + + @debugdeco + @ErrnoExc.wrapped + def getattr(self, path): + node = self._get_node(path) + return node.getattr() + + @debugdeco + @ErrnoExc.wrapped + def getdir(self, path): + """ + return: [(name, typeflag), ... ] + """ + node = self._get_node(path) + return node.getdir() + + @debugdeco + @ErrnoExc.wrapped + def mythread(self): + return -errno.ENOSYS + + @debugdeco + @ErrnoExc.wrapped + def chmod(self, path, mode): + return -errno.ENOSYS + + @debugdeco + @ErrnoExc.wrapped + def chown(self, path, uid, gid): + return -errno.ENOSYS + + @debugdeco + @ErrnoExc.wrapped + def fsync(self, path, isFsyncFile): + return -errno.ENOSYS + + @debugdeco + @ErrnoExc.wrapped + def link(self, target, link): + return -errno.ENOSYS + + @debugdeco + @ErrnoExc.wrapped + def mkdir(self, path, mode): + return -errno.ENOSYS + + @debugdeco + @ErrnoExc.wrapped + def mknod(self, path, mode, dev_ignored): + return -errno.ENOSYS + + @debugdeco + @ErrnoExc.wrapped + def open(self, path, mode): + IgnoredFlags = os.O_RDONLY | os.O_NONBLOCK | os.O_SYNC | os.O_LARGEFILE + # Note: IgnoredFlags are all ignored! + for fname in dir(os): + if fname.startswith('O_'): + flag = getattr(os, fname) + if flag & IgnoredFlags: + continue + elif mode & flag: + print 'Flag not supported:', fname + raise ErrnoExc(errno.ENOSYS) + + self._get_contents(path) + return 0 + + @debugdeco + @ErrnoExc.wrapped + def read(self, path, length, offset): + return self._get_contents(path)[offset:length] + + @debugdeco + @ErrnoExc.wrapped + def release(self, path): + del self.filecontents[path] + return 0 + + @debugdeco + @ErrnoExc.wrapped + def readlink(self, path): + return -errno.ENOSYS + + @debugdeco + @ErrnoExc.wrapped + def rename(self, oldpath, newpath): + return -errno.ENOSYS + + @debugdeco + @ErrnoExc.wrapped + def rmdir(self, path): + return -errno.ENOSYS + + #@debugdeco + @ErrnoExc.wrapped + def statfs(self): + return -errno.ENOSYS + + @debugdeco + @ErrnoExc.wrapped + def symlink ( self, targetPath, linkPath ): + return -errno.ENOSYS + + @debugdeco + @ErrnoExc.wrapped + def truncate(self, path, size): + return -errno.ENOSYS + + @debugdeco + @ErrnoExc.wrapped + def unlink(self, path): + return -errno.ENOSYS + + @debugdeco + @ErrnoExc.wrapped + def utime(self, path, times): + return -errno.ENOSYS + + +class TahoeNode (object): + NextInode = 0 + + @staticmethod + def make(baseurl, uri): + typefield = uri.split(':', 2)[1] + if typefield.startswith('DIR'): + return TahoeDir(baseurl, uri) + else: + return TahoeFile(baseurl, uri) + + def __init__(self, baseurl, uri): + self.burl = baseurl + self.uri = uri + self.fullurl = '%s/uri/%s' % (self.burl, self.uri) + self.inode = TahoeNode.NextInode + TahoeNode.NextInode += 1 + + def getattr(self): + """ + - st_mode (protection bits) + - st_ino (inode number) + - st_dev (device) + - st_nlink (number of hard links) + - st_uid (user ID of owner) + - st_gid (group ID of owner) + - st_size (size of file, in bytes) + - st_atime (time of most recent access) + - st_mtime (time of most recent content modification) + - st_ctime (platform dependent; time of most recent metadata change on Unix, + or the time of creation on Windows). + """ + # FIXME: Return metadata that isn't completely fabricated. + return (self.get_mode(), + self.inode, + MagicDevNumber, + self.get_linkcount(), + os.getuid(), + os.getgid(), + self.get_size(), + 0, + 0, + 0) + + def get_metadata(self): + f = self.open('?t=json') + json = f.read() + f.close() + return simplejson.loads(json) + + def open(self, postfix=''): + url = self.fullurl + postfix + print '*** Fetching:', `url` + return urllib.urlopen(url) + + +class TahoeFile (TahoeNode): + def __init__(self, baseurl, uri): + assert uri.split(':', 2)[1] in ('CHK', 'LIT'), `uri` + TahoeNode.__init__(self, baseurl, uri) + + # nonfuse: + def get_mode(self): + return stat.S_IFREG | 0400 # Read only regular file. + + def get_linkcount(self): + return 1 + + def get_size(self): + return self.get_metadata()[1]['size'] + + def resolve_path(self, path): + assert type(path) is list + assert path == [] + return self + + +class TahoeDir (TahoeNode): + def __init__(self, baseurl, uri): + assert uri.split(':', 2)[1] in ('DIR', 'DIR-RO'), `uri` + TahoeNode.__init__(self, baseurl, uri) + + self.mode = stat.S_IFDIR | 0500 # Read only directory. + + # FUSE: + def getdir(self): + d = [('.', self.get_mode()), ('..', self.get_mode())] + for name, child in self.get_children().items(): + if name: # Just ignore this crazy case! + d.append((name, child.get_mode())) + return d + + # nonfuse: + def get_mode(self): + return stat.S_IFDIR | 0500 # Read only directory. + + def get_linkcount(self): + return len(self.getdir()) + + def get_size(self): + return 2 ** 12 # FIXME: What do we return here? len(self.get_metadata()) + + def resolve_path(self, path): + assert type(path) is list + + if path: + head = path[0] + child = self.get_child(head) + return child.resolve_path(path[1:]) + else: + return self + + def get_child(self, name): + c = self.get_children() + return c[name] + + def get_children(self): + flag, md = self.get_metadata() + assert flag == 'dirnode' + + c = {} + for name, (childflag, childmd) in md['children'].items(): + if childflag == 'dirnode': + cls = TahoeDir + else: + cls = TahoeFile + + c[str(name)] = cls(self.burl, childmd['ro_uri']) + return c + + + +if __name__ == '__main__': + main() + diff --git a/extensions/tahoe-fuse.py b/extensions/tahoe-fuse.py deleted file mode 100644 index 919ec476..00000000 --- a/extensions/tahoe-fuse.py +++ /dev/null @@ -1,377 +0,0 @@ -#! /usr/bin/env python -''' -Tahoe thin-client fuse module. - -Goals: -- Delegate to Tahoe webapi as much as possible. -- Thin as possible. -- This is a proof-of-concept, not a usable product. -''' - - -#import bindann -#bindann.install_exception_handler() - -import sys, stat, os, errno, urllib - -import simplejson - -# FIXME: Currently uses the old, silly path-based (non-stateful) interface: -import fuse -fuse.fuse_python_api = (0, 1) # Use the silly path-based api for now. - - -### Config: -TahoeConfigDir = '~/.tahoe' -MagicDevNumber = 42 - - -def main(args = sys.argv[1:]): - fs = TahoeFS(os.path.expanduser(TahoeConfigDir)) - fs.main() - - -### Utilities just for debug: -def debugdeco(m): - def dbmeth(self, *a, **kw): - pid = self.GetContext()['pid'] - print '[%d %r]\n%s%r%r' % (pid, get_cmdline(pid), m.__name__, a, kw) - try: - r = m(self, *a, **kw) - if (type(r) is int) and (r < 0): - print '-> -%s\n' % (errno.errorcode[-r],) - else: - repstr = repr(r)[:256] - print '-> %s\n' % (repstr,) - return r - except: - sys.excepthook(*sys.exc_info()) - - return dbmeth - - -def get_cmdline(pid): - f = open('/proc/%d/cmdline' % pid, 'r') - args = f.read().split('\0') - f.close() - assert args[-1] == '' - return args[:-1] - - -class ErrnoExc (Exception): - def __init__(self, eno): - self.eno = eno - Exception.__init__(self, errno.errorcode[eno]) - - @staticmethod - def wrapped(meth): - def wrapper(*args, **kw): - try: - return meth(*args, **kw) - except ErrnoExc, e: - return -e.eno - wrapper.__name__ = meth.__name__ - return wrapper - - -### Heart of the Matter: -class TahoeFS (fuse.Fuse): - def __init__(self, confdir): - fuse.Fuse.__init__(self) - self.confdir = confdir - - self.flags = 0 # FIXME: What goes here? - self.multithreaded = 0 - - # silly path-based file handles. - self.filecontents = {} # {path -> contents} - - self._init_url() - self._init_bookmarks() - - def _init_url(self): - f = open(os.path.join(self.confdir, 'webport'), 'r') - contents = f.read() - f.close() - - fields = contents.split(':') - proto, port = fields[:2] - assert proto == 'tcp' - port = int(port) - self.url = 'http://localhost:%d' % (port,) - - def _init_bookmarks(self): - f = open(os.path.join(self.confdir, 'fuse-bookmarks.uri'), 'r') - uri = f.read().strip() - f.close() - - self.bookmarks = TahoeDir(self.url, uri) - - def _get_node(self, path): - assert path.startswith('/') - if path == '/': - return self.bookmarks.resolve_path([]) - else: - parts = path.split('/')[1:] - return self.bookmarks.resolve_path(parts) - - def _get_contents(self, path): - node = self._get_node(path) - contents = node.open().read() - self.filecontents[path] = contents - return contents - - @debugdeco - @ErrnoExc.wrapped - def getattr(self, path): - node = self._get_node(path) - return node.getattr() - - @debugdeco - @ErrnoExc.wrapped - def getdir(self, path): - """ - return: [(name, typeflag), ... ] - """ - node = self._get_node(path) - return node.getdir() - - @debugdeco - @ErrnoExc.wrapped - def mythread(self): - return -errno.ENOSYS - - @debugdeco - @ErrnoExc.wrapped - def chmod(self, path, mode): - return -errno.ENOSYS - - @debugdeco - @ErrnoExc.wrapped - def chown(self, path, uid, gid): - return -errno.ENOSYS - - @debugdeco - @ErrnoExc.wrapped - def fsync(self, path, isFsyncFile): - return -errno.ENOSYS - - @debugdeco - @ErrnoExc.wrapped - def link(self, target, link): - return -errno.ENOSYS - - @debugdeco - @ErrnoExc.wrapped - def mkdir(self, path, mode): - return -errno.ENOSYS - - @debugdeco - @ErrnoExc.wrapped - def mknod(self, path, mode, dev_ignored): - return -errno.ENOSYS - - @debugdeco - @ErrnoExc.wrapped - def open(self, path, mode): - IgnoredFlags = os.O_RDONLY | os.O_NONBLOCK | os.O_SYNC | os.O_LARGEFILE - # Note: IgnoredFlags are all ignored! - for fname in dir(os): - if fname.startswith('O_'): - flag = getattr(os, fname) - if flag & IgnoredFlags: - continue - elif mode & flag: - print 'Flag not supported:', fname - raise ErrnoExc(errno.ENOSYS) - - self._get_contents(path) - return 0 - - @debugdeco - @ErrnoExc.wrapped - def read(self, path, length, offset): - return self._get_contents(path)[offset:length] - - @debugdeco - @ErrnoExc.wrapped - def release(self, path): - del self.filecontents[path] - return 0 - - @debugdeco - @ErrnoExc.wrapped - def readlink(self, path): - return -errno.ENOSYS - - @debugdeco - @ErrnoExc.wrapped - def rename(self, oldpath, newpath): - return -errno.ENOSYS - - @debugdeco - @ErrnoExc.wrapped - def rmdir(self, path): - return -errno.ENOSYS - - #@debugdeco - @ErrnoExc.wrapped - def statfs(self): - return -errno.ENOSYS - - @debugdeco - @ErrnoExc.wrapped - def symlink ( self, targetPath, linkPath ): - return -errno.ENOSYS - - @debugdeco - @ErrnoExc.wrapped - def truncate(self, path, size): - return -errno.ENOSYS - - @debugdeco - @ErrnoExc.wrapped - def unlink(self, path): - return -errno.ENOSYS - - @debugdeco - @ErrnoExc.wrapped - def utime(self, path, times): - return -errno.ENOSYS - - -class TahoeNode (object): - NextInode = 0 - - @staticmethod - def make(baseurl, uri): - typefield = uri.split(':', 2)[1] - if typefield.startswith('DIR'): - return TahoeDir(baseurl, uri) - else: - return TahoeFile(baseurl, uri) - - def __init__(self, baseurl, uri): - self.burl = baseurl - self.uri = uri - self.fullurl = '%s/uri/%s' % (self.burl, self.uri) - self.inode = TahoeNode.NextInode - TahoeNode.NextInode += 1 - - def getattr(self): - """ - - st_mode (protection bits) - - st_ino (inode number) - - st_dev (device) - - st_nlink (number of hard links) - - st_uid (user ID of owner) - - st_gid (group ID of owner) - - st_size (size of file, in bytes) - - st_atime (time of most recent access) - - st_mtime (time of most recent content modification) - - st_ctime (platform dependent; time of most recent metadata change on Unix, - or the time of creation on Windows). - """ - # FIXME: Return metadata that isn't completely fabricated. - return (self.get_mode(), - self.inode, - MagicDevNumber, - self.get_linkcount(), - os.getuid(), - os.getgid(), - self.get_size(), - 0, - 0, - 0) - - def get_metadata(self): - f = self.open('?t=json') - json = f.read() - f.close() - return simplejson.loads(json) - - def open(self, postfix=''): - url = self.fullurl + postfix - print '*** Fetching:', `url` - return urllib.urlopen(url) - - -class TahoeFile (TahoeNode): - def __init__(self, baseurl, uri): - assert uri.split(':', 2)[1] in ('CHK', 'LIT'), `uri` - TahoeNode.__init__(self, baseurl, uri) - - # nonfuse: - def get_mode(self): - return stat.S_IFREG | 0400 # Read only regular file. - - def get_linkcount(self): - return 1 - - def get_size(self): - return self.get_metadata()[1]['size'] - - def resolve_path(self, path): - assert type(path) is list - assert path == [] - return self - - -class TahoeDir (TahoeNode): - def __init__(self, baseurl, uri): - assert uri.split(':', 2)[1] in ('DIR', 'DIR-RO'), `uri` - TahoeNode.__init__(self, baseurl, uri) - - self.mode = stat.S_IFDIR | 0500 # Read only directory. - - # FUSE: - def getdir(self): - d = [('.', self.get_mode()), ('..', self.get_mode())] - for name, child in self.get_children().items(): - if name: # Just ignore this crazy case! - d.append((name, child.get_mode())) - return d - - # nonfuse: - def get_mode(self): - return stat.S_IFDIR | 0500 # Read only directory. - - def get_linkcount(self): - return len(self.getdir()) - - def get_size(self): - return 2 ** 12 # FIXME: What do we return here? len(self.get_metadata()) - - def resolve_path(self, path): - assert type(path) is list - - if path: - head = path[0] - child = self.get_child(head) - return child.resolve_path(path[1:]) - else: - return self - - def get_child(self, name): - c = self.get_children() - return c[name] - - def get_children(self): - flag, md = self.get_metadata() - assert flag == 'dirnode' - - c = {} - for name, (childflag, childmd) in md['children'].items(): - if childflag == 'dirnode': - cls = TahoeDir - else: - cls = TahoeFile - - c[str(name)] = cls(self.burl, childmd['ro_uri']) - return c - - - -if __name__ == '__main__': - main() -