various updates to improve the functionality of the mac fuse plugin
1. caching
previously, the experimental tahoefuse plugin pre-loaded the whole
structure of the specified mount into memory at launch time. changes
which were made through that fuse plugin would be remembered, but any
changes made through other tahoe clients would not be reflected.
now directory contents are only loaded when needed, and the data is
cached for a limited time. any use of Directory objects should first
call maybe_refresh() which will check the time since the cache was last
loaded, and if the data is older than some validity period (currently
26s) then the directory's contents will be refetched and reloaded.
this replaces the 'load_dir()' method of TFS
whenever a local change is made to a Directory object, or when the
aforementioned cache reloading notices a change in directory data, the
mtime of the directory is automatically updated.
2. stat / metadata
the retrieval of 'stat' information for getattr(), and the way that
metadata is handled, has been refactored to better reflect the fact that
metadata in tahoe is only represented by 'edges' (i.e entries in
directories) not on 'nodes' (files or directories themselves) hence a
stat lookup should be a query to the parent directory (specifically the
parent specified by the path being queried in the case that a node has
multiple parents) for details known by that directory for the given
child, rather than a query to the child itself.
the TStat utility class for returning stat information to the python-
fuse layer has been extended to accept a 'metadata' argument in its
constructor. any fields found in the metadata dict which match the
names of the stat attributes are loaded into the TStat object. the
'ctime' and 'mtime' attributes are translated to st_ctime and st_mtime
to mesh with the existing timestamp handling code. any fields specified
by kwargs to the constructor override things that might be loaded from
the metadata dict.
Directory objects now track their children as a dict mapping name to
(child_obj, metadata) tuples. This is because the metadata in tahoe
will be stored exclusively on the edges of the graph. each Directory
maintains its own mtime however, and get_stat() calls will report the
mtime of a directory based on the last modification of the Directory
object, not based on any mtime records from the parent directory's
metadata for that child. This addresses the fact that since directories
may be shared, a given parent may or may not reflect the latest changes,
however one of the Finder's behaviours is to examine the stat of a
directory, and not to bother doing a readdir() if the stat is unchanged.
i.e. unless directories report their changes in their stat info, the
Finder will not show changes within that directory.
3. refactoring
reporting of many error codes has been refactored to raise IOError
subclasses with the appropriate errno. this exploits python-fuse's
built-in mechanism for catching IOError and reporting the errno
embedded within it automatically, while simplifying the code within
the plugin.
the add_child() method on TFS was removed in favour of simply having an
add_child() method on Directory objects. this provides a more OO
approach in that Directory is responsible for maintaining its own in
memory state and also writing changes back to the node. similarly for
remove_child()
these changes, along with the new tfs.compose_url() method,
significantly simplify and improve readability of mkdir, rename methods
along with the newer link and unlink. these also get improved error
reporting.
various operations (chmod, chown, truncate, utime) are now ignored.
previously they would report an unsupported operation (EOPNOTSUPP)
but now are simply logged and ignored. this surpresses errors caused
by some client programs which try to use these operations, but at the
moment those operations are meaningless to the tahoe filesystem anyway.
4. link / unlink / rmdir
link, symlink calls are now supported, though with semantics differing
from posix, both equivalent. unlink, rmdir calls are now supported,
also equivalent.
link or symlink calls duplicate the uri of the named source and adds it
as a child of another directory according to the destination path. for
directories, this creates a 'hard' link, i.e. the same directory will
appear in multiple locations within the filesystem, and changes in
any place will be reflected everywhere. for files, by contrast, since
the uri being duplicated is an immutable CHK uri, link/symlink for files
is equivalent to a copy - though significantly cheaper. (a file copy
with the fuse plugin is likely to cause a new file to be written and
uploaded, the link command simply adds an entry referring to an
existing uri)
in testing, the 'ln' command is unable to make hard links (i.e. call
link()) for directories, though symlink ('ln -s') is supported.
either forms works equivalently for files.
unlink and rmdir both remove the specified entry from its parent
directory.
5. logging
the 'tfuse.log' file now only reports launches of the fuse plugin. once
the plugin has parsed the options, it reopens the log file with the
name of the mount, e.g. tfuse.root_dir.log, so that multiple instances
running concurrently will not interfere with each others' logging.
6. bug fixes
the tmp_file in the cache dir backing files opened for write was
intermittently failing to open the file. added O_CREAT to the os.open
call so that files will be created if missing, not throw errors.
a failure to correctly parse arguments if no mount (dir_cap) name was
given but also no fuse options were given has been fixed. now the
command 'tahoe fuse mountpoint' will correctly default to root_dir
also when running from source, arguments to tahoefuse were not handled
to correctly match the 'tahoe fuse ...' behaviour.
Unfinished bits: doc in webapi.txt, test handling of badly formed JSON, return reasonable HTTP response, examination of the effect of this patch on code coverage -- but I'm committing it anyway because MikeB can use it and I'm being called to dinner...
oops. I screwed up the makefile syntax further. buildslave would spend a
lot of fruitless time trawling the entire drive. this fixes that. and a
stray -n. ahem. [looks down sheepishly]
blah $( foo ) is more explicit than blah ` foo ` in a bash-like context
unfortunately it doesn't translate very well to makefiles, for which $(
means something else entirely
rather than trying to build a single .app with both 10.4 and 10.5 fuse
libraries embedded within it, for the time being, we're just going to
have independant 10.4 and 10.5 builds.
this provides a 10.5 _fusemodule.so, and build changes to copy the
appropriate versions of files for 10.4 or 10.5 from sub dirs of mac/
into the build tree before triggering py2app
the existing environment on otto requires a few build hints in order for
xml parsing to work properly. these hints are unnecessary, and moreover
their import by depends.py is broken, in the 10.5 environment in which
zandr's buildslave is running.
the make mac-upload target now requires an UPLOAD_DEST argument to be given,
which is the rsync destination (including trailing '/') to which the version
stamped directory containing the .dmg should be placed. the account the
build is running as (e.g. 'buildslave') should have ssh access to the account
specified in that dest. one might also consider locking the key down to the
target directory by adding something like
command="rsync --server -vlogDtpr . /home/amduser/public_html/dist/mac-blah/"
to the corresponding authorized_key entry on the target machine.
the name 'tahoe' is in the process of being removed from the windows
installer and binaries. this changes the name of the smb service the
confwiz tries to start to 'Allmydata SMB'
this adds an action to the dock menu and to the file menu (when visible)
"Mount Filesystem". This action opens a windows offering the user an
opportunity to select from any of the named *.cap files in their
.tahoe/private directory, and choose a corresponding mount point to mount
that at.
it launches the .app binary as a subprocess with the corresponding command
line arguments to launch the 'tahoe fuse' functionality to mount that file
system. if a NAME.icns file is present in .tahoe/private alonside the
chosen NAME.cap, then that icon will be used when the filesystem is mounted.
this is highly unlikely to work when running from source, since it uses
introspection on sys.executable to find the relavent binary to launch in
order to get the right built .app's 'tahoe fuse' functionality.
it is also relatively likely that the code currently checked in, hence
linked into the build, will have as yet unresolved library dependencies.
it's quite unlikely to work on 10.5 with macfuse 1.3.1 at the moment.
the mac/macfuse subdirectory needed to be added to the pythonpath in order
to build a binary incorporating the mac fuse system. this change should
make those modules accessible relative to the mac/ directory which is
implicitly included in the .app build process.
this provides a variety of changes to the macfuse 'tahoefuse' implementation.
most notably it extends the 'tahoe' command available through the mac build
to provide a 'fuse' subcommand, which invokes tahoefuse. this addresses
various aspects of main(argv) handling, sys.argv manipulation to provide an
appropriate command line syntax that meshes with the fuse library's built-
in command line parsing.
this provides a "tahoe fuse [dir_cap_name] [fuse_options] mountpoint"
command, where dir_cap_name is an optional name of a .cap file to be found
in ~/.tahoe/private defaulting to the standard root_dir.cap. fuse_options
if given are passed into the fuse system as its normal command line options
and the mountpoint is checked for existence before launching fuse.
the tahoe 'fuse' command is provided as an additional_command to the tahoe
runner in the case that it's launched from the mac .app binary.
this also includes a tweak to the TFS class which incorporates the ctime
and mtime of files into the tahoe fs model, if available.
runner provides the main point of entry for the 'tahoe' command, and
provides various subcommands by default. this provides a hook whereby
additional subcommands can be added in in other contexts, providing a
simple way to extend the (sub)commands space available through 'tahoe'