diff options
Diffstat (limited to 'src/borg/fuse.py')
-rw-r--r-- | src/borg/fuse.py | 70 |
1 files changed, 49 insertions, 21 deletions
diff --git a/src/borg/fuse.py b/src/borg/fuse.py index eeb4c7f80..93530f892 100644 --- a/src/borg/fuse.py +++ b/src/borg/fuse.py @@ -14,7 +14,7 @@ from .logger import create_logger logger = create_logger() from .archive import Archive -from .helpers import daemonize +from .helpers import daemonize, safe_encode from .item import Item from .lrucache import LRUCache @@ -50,6 +50,9 @@ class ItemCache: class FuseOperations(llfuse.Operations): """Export archive as a fuse filesystem """ + + allow_damaged_files = False + def __init__(self, key, repository, manifest, archive, cached_repo): super().__init__() self._inode_count = 0 @@ -79,6 +82,32 @@ class FuseOperations(llfuse.Operations): self.contents[1][os.fsencode(archive_name)] = archive_inode self.pending_archives[archive_inode] = Archive(repository, key, manifest, archive_name) + def mount(self, mountpoint, mount_options, foreground=False): + """Mount filesystem on *mountpoint* with *mount_options*.""" + options = ['fsname=borgfs', 'ro'] + if mount_options: + options.extend(mount_options.split(',')) + try: + options.remove('allow_damaged_files') + self.allow_damaged_files = True + except ValueError: + pass + llfuse.init(self, mountpoint, options) + if not foreground: + daemonize() + + # If the file system crashes, we do not want to umount because in that + # case the mountpoint suddenly appears to become empty. This can have + # nasty consequences, imagine the user has e.g. an active rsync mirror + # job - seeing the mountpoint empty, rsync would delete everything in the + # mirror. + umount = False + try: + signal = fuse_main() + umount = (signal is None) # no crash and no signal -> umount request + finally: + llfuse.close(umount) + def process_archive(self, archive, prefix=[]): """Build fuse inode hierarchy from archive metadata """ @@ -88,6 +117,16 @@ class FuseOperations(llfuse.Operations): unpacker.feed(data) for item in unpacker: item = Item(internal_dict=item) + try: + # This can happen if an archive was created with a command line like + # $ borg create ... dir1/file dir1 + # In this case the code below will have created a default_dir inode for dir1 already. + inode = self._find_inode(safe_encode(item.path), prefix) + except KeyError: + pass + else: + self.items[inode] = item + continue segments = prefix + os.fsencode(os.path.normpath(item.path)).split(b'/') del item.path num_segments = len(segments) @@ -214,6 +253,15 @@ class FuseOperations(llfuse.Operations): return self.getattr(inode) def open(self, inode, flags, ctx=None): + if not self.allow_damaged_files: + item = self.get_item(inode) + if 'chunks_healthy' in item: + # Processed archive items don't carry the path anymore; for converting the inode + # to the path we'd either have to store the inverse of the current structure, + # or search the entire archive. So we just don't print it. It's easy to correlate anyway. + logger.warning('File has damaged (all-zero) chunks. Try running borg check --repair. ' + 'Mount with allow_damaged_files to read damaged files.') + raise llfuse.FUSEError(errno.EIO) return inode def opendir(self, inode, ctx=None): @@ -254,23 +302,3 @@ class FuseOperations(llfuse.Operations): def readlink(self, inode, ctx=None): item = self.get_item(inode) return os.fsencode(item.source) - - def mount(self, mountpoint, extra_options, foreground=False): - options = ['fsname=borgfs', 'ro'] - if extra_options: - options.extend(extra_options.split(',')) - llfuse.init(self, mountpoint, options) - if not foreground: - daemonize() - - # If the file system crashes, we do not want to umount because in that - # case the mountpoint suddenly appears to become empty. This can have - # nasty consequences, imagine the user has e.g. an active rsync mirror - # job - seeing the mountpoint empty, rsync would delete everything in the - # mirror. - umount = False - try: - signal = fuse_main() - umount = (signal is None) # no crash and no signal -> umount request - finally: - llfuse.close(umount) |