Commit 4d237495 by btimby

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).
parent 59b5cfdc
...@@ -70,7 +70,7 @@ class ArchiveFS(FS): ...@@ -70,7 +70,7 @@ class ArchiveFS(FS):
self.root_path = getattr(f, 'name', None) self.root_path = getattr(f, 'name', None)
self.contents = PathMap() self.contents = PathMap()
self.archive = libarchive.SeekableArchive(f, format=format, mode=mode) self.archive = libarchive.SeekableArchive(f, format=format, mode=mode)
if mode == 'r': if 'r' in mode:
for item in self.archive: for item in self.archive:
for part in recursepath(item.pathname)[1:]: for part in recursepath(item.pathname)[1:]:
part = relpath(part) part = relpath(part)
...@@ -198,6 +198,22 @@ class ArchiveMountFS(mountfs.MountFS): ...@@ -198,6 +198,22 @@ class ArchiveMountFS(mountfs.MountFS):
return False return False
return isinstance(object, mountfs.MountFS.DirMount) 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): def _delegate(self, path, auto_mount=True):
"""A _delegate() override that will automatically mount archives that are """A _delegate() override that will automatically mount archives that are
encountered in the path. For example, the path /foo/bar.zip/baz.txt contains encountered in the path. For example, the path /foo/bar.zip/baz.txt contains
...@@ -356,6 +372,27 @@ class ArchiveMountFS(mountfs.MountFS): ...@@ -356,6 +372,27 @@ class ArchiveMountFS(mountfs.MountFS):
self.copy(src, dst, overwrite=overwrite, chunk_size=chunk_size) self.copy(src, dst, overwrite=overwrite, chunk_size=chunk_size)
self.remove(src) 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, def walk(self,
path="/", path="/",
wildcard=None, wildcard=None,
...@@ -466,6 +503,7 @@ class ArchiveMountFS(mountfs.MountFS): ...@@ -466,6 +503,7 @@ class ArchiveMountFS(mountfs.MountFS):
def main(): def main():
ArchiveFS() ArchiveFS()
if __name__ == '__main__': if __name__ == '__main__':
main() main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment