Example #1
0
 def copy(self, src, dst, overwrite=False, chunk_size=1024*64):
     """An optimized copy() that will skip mounting an archive if one is involved
     as either the src or dst. This allows the file containing the archive to be
     copied."""
     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.
         srcfs.copy(src, dst, overwrite=overwrite, chunk_size=chunk_size)
     else:
         # Src and dst are on different file systems. Just do the copy...
         srcfd = None
         try:
             srcfd = srcfs.open(src, 'rb')
             dstfs.setcontents(dst, srcfd, chunk_size=chunk_size)
         except ResourceNotFoundError:
             if srcfs.exists(src) and not dstfs.exists(dirname(dst)):
                 raise ParentDirectoryMissingError(dst)
         finally:
             if srcfd:
                 srcfd.close()
Example #2
0
 def test_formats(self):
     self.assertEqual(is_archive_name('foo'), None)
     self.assertEqual(is_archive_name('foo.txt'), None)
     self.assertEqual(is_archive_name('foo.txt.gz'), None)
     self.assertEqual(is_archive_name('foo.tar.gz'), 'tar')
     self.assertEqual(is_archive_name('foo.tar.bz2'), 'tar')
     self.assertEqual(is_archive_name('foo.zip'), 'zip')
     self.assertEqual(is_archive_name('foo.rar'), 'rar')
     self.assertEqual(is_archive_name('foo.iso'), 'iso')
     self.assertEqual(is_archive_name('foo.rpm'), 'cpio')
 def test_formats(self):
     self.assertEqual(is_archive_name('foo'), None)
     self.assertEqual(is_archive_name('foo.txt'), None)
     self.assertEqual(is_archive_name('foo.txt.gz'), None)
     self.assertEqual(is_archive_name('foo.tar.gz'), 'tar')
     self.assertEqual(is_archive_name('foo.tar.bz2'), 'tar')
     self.assertEqual(is_archive_name('foo.zip'), 'zip')
     self.assertEqual(is_archive_name('foo.rar'), 'rar')
     self.assertEqual(is_archive_name('foo.iso'), 'iso')
     self.assertEqual(is_archive_name('foo.rpm'), 'cpio')
Example #4
0
 def remove(self, path, **kwargs):
     """A remove() override that deletes an archive directly. It is not fooled
     by a mounted archive. If the path is not an archive, the call is delegated."""
     if libarchive.is_archive_name(path) and self.ismount(path):
         self.unmount(path)
     fs, _mount_path, delegate_path = self._delegate(path, auto_mount=False)
     return fs.remove(delegate_path)
Example #5
0
 def open(self, path, *args, **kwargs):
     """An open() override that opens an archive. It is not fooled by mounted
     archives. If the path is a mounted archive, it is unmounted and the archive
     file is opened and returned."""
     if libarchive.is_archive_name(path) and self.ismount(path):
         self.unmount(path)
     fs, _mount_path, delegate_path = self._delegate(path, auto_mount=False)
     return fs.open(delegate_path, *args, **kwargs)
Example #6
0
 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)
Example #7
0
 def remove(self, path):
     # In case one of our mounted file systems backing archive is being
     # deleted, unmout it before continuing. Once unmounted, the archive
     # can be deleted by root fs, otherwise, the ArchiveFS will be asked
     # to remove itself, which it cannot do.
     if self.ismount(path) and libarchive.is_archive_name(path):
         self.unmount(path)
         # Send the delete directoy to the root filesystem. This avoids
         # being delegated, and the fs we just unmounted being remounted.
         return self.rootfs.remove(path)
     # Otherwise, just delegate to the responsible fs.
     return super(ArchiveMountFS, self).remove(path)
Example #8
0
 def _delegate(self, path):
     for ppath in recursepath(path)[1:]:
         # Don't mount again...
         if self.ismount(ppath):
             break
         if libarchive.is_archive_name(ppath):
             # It looks like an archive, try mounting it.
             full_path = self.mount_tree['/'].fs.getsyspath(ppath)
             try:
                 self.mountdir(ppath, ArchiveFS(full_path, 'r'))
             except:
                 pass # Must NOT have been an archive after all
             # Stop recursing path, we support just one archive per path!
             # No nested archives yet!
             break
     return super(ArchiveMountFS, self)._delegate(path)
Example #9
0
    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
        the archive path /foo/bar.zip. If this archive can be mounted by ArchiveFS,
        it will be. Then the file system call will be delegated to that mounted file
        system, which will act upon /baz.txt within the archive. This is lazy
        initialization which means users of this class need not crawl the file system
        for archives and mount them all up-front.

        This behavior can be overridden by self.auto_mount=False or by passing the
        auto_mount=False keyword argument.
        """
        if self.auto_mount and auto_mount:
            for ppath in recursepath(path)[1:]:
                if self.ismount(ppath):
                    # If something is already mounted here, no need to continue.
                    break
                if libarchive.is_archive_name(ppath):
                    # It looks like an archive, we might mount it.
                    # First check that the size is acceptable.
                    if self.max_size:
                        if self.rootfs.exists(ppath) and \
                           self.rootfs.getsize(ppath) > self.max_size:
                            break
                    # Looks good, the proof is in the pudding, so let's try to
                    # mount this *supposed* archive...
                    full_path = self.rootfs.getsyspath(ppath)
                    try:
                        # TODO: it would be really nice if we could open the path using
                        # self.rootfs.open(), that way we could support archives on a file
                        # system other than osfs (even nested archives). However, the libarchive
                        # wrapper is not sophisticated enough to handle a Python file-like object,
                        # it uses an actual fd.
                        self.mountdir(ppath, ArchiveFS(full_path, 'r'))
                        # That worked!! Stop recursing path, we support just one archive per path!
                        break
                    except:
                        # Must NOT have been an archive after all, but maybe
                        # there is one deeper in the directory...
                        continue
        return super(ArchiveMountFS, self)._delegate(path)
Example #10
0
 def isarchive(path):
     try:
         return libarchive.is_archive(path)
     except:
         return libarchive.is_archive_name(path)
Example #11
0
 def isarchive(path):
     try:
         return libarchive.is_archive(path)
     except:
         return libarchive.is_archive_name(path)