summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbtimby <btimby@67cdc799-7952-0410-af00-57a81ceafa0f>2012-12-04 21:14:53 +0000
committerbtimby <btimby@67cdc799-7952-0410-af00-57a81ceafa0f>2012-12-04 21:14:53 +0000
commitb568e62918a82a6c21e0ecf00b31c3a28af1a17c (patch)
treedd7bc39b330533aae9d79e04e1dd0b7e2fe1a327
parent1fd025edd27f3eda1418d9e5231ff7e26acef4ec (diff)
downloadpyfilesystem-b568e62918a82a6c21e0ecf00b31c3a28af1a17c.tar.gz
Whitespace fix.
unmount now closes the filesystem after unmounting it. Use 'r' in mode since mode might be 'rb'. Rename needs to handle renaming archives (don't redirect through an ArchiveFS). git-svn-id: http://pyfilesystem.googlecode.com/svn/trunk@839 67cdc799-7952-0410-af00-57a81ceafa0f
-rw-r--r--fs/contrib/archivefs.py40
1 files changed, 39 insertions, 1 deletions
diff --git a/fs/contrib/archivefs.py b/fs/contrib/archivefs.py
index cb3b4af..428c680 100644
--- a/fs/contrib/archivefs.py
+++ b/fs/contrib/archivefs.py
@@ -70,7 +70,7 @@ class ArchiveFS(FS):
self.root_path = getattr(f, 'name', None)
self.contents = PathMap()
self.archive = libarchive.SeekableArchive(f, format=format, mode=mode)
- if mode == 'r':
+ if 'r' in mode:
for item in self.archive:
for part in recursepath(item.pathname)[1:]:
part = relpath(part)
@@ -198,6 +198,22 @@ class ArchiveMountFS(mountfs.MountFS):
return False
return isinstance(object, mountfs.MountFS.DirMount)
+ def unmount(self, path):
+ """Unmounts a path.
+
+ :param path: Path to unmount
+
+ """
+ # This might raise a KeyError, but that is what MountFS will do, so
+ # shall we.
+ fs = self.mount_tree.pop(path)
+ # TODO: it may be necessary to remember what paths were auto-mounted,
+ # so we can close those here. It may not be safe to close a file system
+ # that the user provided. However, it is definitely NOT safe to leave
+ # one open.
+ if callable(getattr(fs, 'close', None)):
+ fs.close()
+
def _delegate(self, path, auto_mount=True):
"""A _delegate() override that will automatically mount archives that are
encountered in the path. For example, the path /foo/bar.zip/baz.txt contains
@@ -356,6 +372,27 @@ class ArchiveMountFS(mountfs.MountFS):
self.copy(src, dst, overwrite=overwrite, chunk_size=chunk_size)
self.remove(src)
+ def rename(self, src, dst):
+ """An rename() implementation that ensures the rename does not span
+ file systems. It also ensures that an archive can be renamed (without
+ trying to mount either the src or destination paths)."""
+ src_is_archive = libarchive.is_archive_name(src)
+ # If src path is a mounted archive, unmount it.
+ if src_is_archive and self.ismount(src):
+ self.unmount(src)
+ # Now delegate the path, if the path is an archive, don't remount it.
+ srcfs, _ignored, src = self._delegate(src, auto_mount=(not src_is_archive))
+ # Follow the same steps for dst.
+ dst_is_archive = libarchive.is_archive_name(dst)
+ if dst_is_archive and self.ismount(dst):
+ self.unmount(dst)
+ dstfs, _ignored, dst = self._delegate(dst, auto_mount=(not dst_is_archive))
+ # srcfs, src and dstfs, dst are now the file system and path for our src and dst.
+ if srcfs is dstfs and srcfs is not self:
+ # Both src and dst are on the same fs, let it do the copy.
+ return srcfs.rename(src, dst)
+ raise OperationFailedError("rename resource", path=src)
+
def walk(self,
path="/",
wildcard=None,
@@ -466,6 +503,7 @@ class ArchiveMountFS(mountfs.MountFS):
def main():
ArchiveFS()
+
if __name__ == '__main__':
main()