From 7214f2f8b87549bee466f4d425d3f581d38db95d Mon Sep 17 00:00:00 2001 From: nejucomo <nejucomo@gmail.com> Date: Sat, 12 Jan 2008 17:06:39 -0700 Subject: [PATCH] A patch to make tahoe-fuse.py work with 0.7.0 plus a howto README. --- contrib/fuse/README | 90 ++++++++++++++++++++++++++++++++ contrib/{ => fuse}/tahoe-fuse.py | 37 +++++++++---- 2 files changed, 118 insertions(+), 9 deletions(-) create mode 100644 contrib/fuse/README rename contrib/{ => fuse}/tahoe-fuse.py (89%) diff --git a/contrib/fuse/README b/contrib/fuse/README new file mode 100644 index 00000000..f79107cc --- /dev/null +++ b/contrib/fuse/README @@ -0,0 +1,90 @@ + +Welcome to the tahoe fuse interface prototype! + + +Dependencies: + +In addition to a working tahoe installation, this interface depends +on the python-fuse interface. This package is available on Ubuntu +systems as "python-fuse". It is only known to work with ubuntu +package version "2.5-5build1". The latest ubuntu package (version +"1:0.2-pre3-3") appears to not work currently. + +Unfortunately this package appears poorly maintained (notice the wildy +different version strings and changing API semantics), so if you know +of a good replacement pythonic fuse interface, please let tahoe-dev know +about it! + + +Configuration: + +Currently tahoe-fuse.py uses the same ~/.tahoe/private/root_dir.cap +file (which is also the CLI default). This is not configurable yet. +Place a directory cap in this file. (Hint: If you can run "tahoe ls" +and see a directory listing, this file is properly configured.) + + +Commandline: + +The usage is "tahoe-fuse.py <mountpoint>". The mount point needs to +be an existing directory which should be empty. (If it's not empty +the contents will be safe, but unavailable while the tahoe-fuse.py +process is mounted there.) + + +Usage: + +To use the interface, use other programs to poke around the +mountpoint. You should be able to see the same contents as you would +by using the CLI or WUI for the same directory cap. + + +Runtime Behavior Notes: + +Read-only: +Only reading a tahoe grid is supported, which is reflected in +the permission modes. With Tahoe 0.7.0, write access should be easier +to implement, but is not yet present. + +In-Memory File Caching: +Currently requesting a particular file for read causes the entire file to +be retrieved into tahoe-fuse.py memory before the read operation returns! +This caching is reused for subsequent reads. Beware large files. +When transitioning to a finer-grained fuse api, this caching should be +replaced with straight-forward calls to the wapi. In my opinion, the +Tahoe node should do all the caching tricks, so that extensions such as +tahoe-fuse.py can be simple and thin. + +Backgrounding Behavior: +When using the 2.5-5build1 ubuntu package, and no other arguments +besides a mountpoint to tahoe-fuse.py, the process should remain in +the foreground and print debug information. Other python-fuse +versions appear to alter this behavior and may fork the process to +the background and obscure the log output. Bonus points to whomever +discovers the fate of these poor log messages in this case. + +"Investigative Logging": +This prototype is designed to aide in further fuse development, so +currently *every* fuse interface call figures out the process from +which the file system request originates, then it figures out that +processes commandline (this uses the /proc file system). This is handy +for interactive inspection of what kinds of behavior invokes which +file system operations, but may not work for you. To disable this +inspection, edit the source and comment out all of the "@debugcall" +[FIXME: double check python ref name] method decorators by inserting a +'#' so it looks like "#@debugcall" (without quotes). + +Not-to-spec: +The current version was not implemented according to any spec and +makes quite a few dubious "guesses" for what data to pass the fuse +interface. You may see bizarre values, which may potentialy confuse +any processes visiting the files under the mount point. + +Serial, blocking operations: +Most fuse operations result in one or more http calls to the WAPI. +These are serial and blocking (at least for the tested python-fuse +version 2.5-5build1), so access to this file system is quite +inefficient. + + +Good luck! diff --git a/contrib/tahoe-fuse.py b/contrib/fuse/tahoe-fuse.py similarity index 89% rename from contrib/tahoe-fuse.py rename to contrib/fuse/tahoe-fuse.py index 400e7a15..8e352917 100644 --- a/contrib/tahoe-fuse.py +++ b/contrib/fuse/tahoe-fuse.py @@ -58,6 +58,7 @@ fuse.fuse_python_api = (0, 1) # Use the silly path-based api for now. ### Config: TahoeConfigDir = '~/.tahoe' MagicDevNumber = 42 +UnknownSize = -1 def main(args = sys.argv[1:]): @@ -136,12 +137,21 @@ class TahoeFS (fuse.Fuse): 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.rootdir = TahoeDir(self.url, uri) + def _init_rootdir(self): + # For now we just use the same default as the CLI: + rootdirfn = os.path.join(self.confdir, 'private', 'root_dir.cap') + try: + f = open(rootdirfn, 'r') + cap = f.read().strip() + f.close() + except EnvironmentError, le: + # FIXME: This user-friendly help message may be platform-dependent because it checks the exception description. + if le.args[1].find('No such file or directory') != -1: + raise SystemExit('%s requires a directory capability in %s, but it was not found.\nPlease see "The CLI" in "docs/using.html".\n' % (sys.argv[0], rootdirfn)) + else: + raise le + + self.rootdir = TahoeDir(self.url, canonicalize_cap(cap)) def _get_node(self, path): assert path.startswith('/') @@ -335,7 +345,7 @@ class TahoeNode (object): class TahoeFile (TahoeNode): def __init__(self, baseurl, uri): - assert uri.split(':', 2)[1] in ('CHK', 'LIT'), `uri` + #assert uri.split(':', 2)[1] in ('CHK', 'LIT'), `uri` # fails as of 0.7.0 TahoeNode.__init__(self, baseurl, uri) # nonfuse: @@ -346,7 +356,12 @@ class TahoeFile (TahoeNode): return 1 def get_size(self): - return self.get_metadata()[1]['size'] + rawsize = self.get_metadata()[1]['size'] + if type(rawsize) is not int: # FIXME: What about sizes which do not fit in python int? + assert rawsize == u'?', `rawsize` + return UnknownSize + else: + return rawsize def resolve_path(self, path): assert type(path) is list @@ -356,7 +371,6 @@ class TahoeFile (TahoeNode): class TahoeDir (TahoeNode): def __init__(self, baseurl, uri): - #assert uri.split(':', 2)[1] in ('DIR2', 'DIR2-RO'), `uri` TahoeNode.__init__(self, baseurl, uri) self.mode = stat.S_IFDIR | 0500 # Read only directory. @@ -408,6 +422,11 @@ class TahoeDir (TahoeNode): return c +def canonicalize_cap(cap): + i = cap.find('URI:') + assert i != -1, 'A cap must contain "URI:...", but this does not: ' + cap + return cap[i:] + if __name__ == '__main__': main() -- 2.45.2