소스 검색

borg mount: support uid= and gid= mount options

also: refactor popping an option, converting an options value
(cherry picked from commit f993f0fd491bf259dfc3d9289a5982360fe95c02)
Thomas Waldmann 7 년 전
부모
커밋
c7d12e3fc0
1개의 변경된 파일36개의 추가작업 그리고 13개의 파일을 삭제
  1. 36 13
      src/borg/fuse.py

+ 36 - 13
src/borg/fuse.py

@@ -230,12 +230,14 @@ class FuseBackend(object):
         self.contents = defaultdict(dict)
         self.default_uid = os.getuid()
         self.default_gid = os.getgid()
-        self.default_dir = Item(mode=0o40755, mtime=int(time.time() * 1e9), uid=self.default_uid, gid=self.default_gid)
+        self.default_dir = None
         # Archives to be loaded when first accessed, mapped by their placeholder inode
         self.pending_archives = {}
         self.cache = ItemCache(decrypted_repository)
         self.allow_damaged_files = False
         self.versions = False
+        self.uid_forced = None
+        self.gid_forced = None
 
     def _create_filesystem(self):
         self._create_dir(parent=1)  # first call, create root dir (inode == 1)
@@ -443,19 +445,40 @@ class FuseOperations(llfuse.Operations, FuseBackend):
 
     def mount(self, mountpoint, mount_options, foreground=False):
         """Mount filesystem on *mountpoint* with *mount_options*."""
+
+        def pop_option(options, key, present, not_present, wanted_type):
+            assert isinstance(options, list)  # we mutate this
+            for idx, option in enumerate(options):
+                if option == key:
+                    options.pop(idx)
+                    return present
+                if option.startswith(key + '='):
+                    options.pop(idx)
+                    value = option.split('=', 1)[1]
+                    if wanted_type is bool:
+                        v = value.lower()
+                        if v in ('y', 'yes', 'true', '1'):
+                            return True
+                        if v in ('n', 'no', 'false', '0'):
+                            return False
+                        raise ValueError('unsupported value in option: %s' % option)
+                    try:
+                        return wanted_type(value)
+                    except ValueError:
+                        raise ValueError('unsupported value in option: %s' % option) from None
+            else:
+                return not_present
+
         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
-        try:
-            options.remove('versions')
-            self.versions = True
-        except ValueError:
-            pass
+        self.allow_damaged_files = pop_option(options, 'allow_damaged_files', True, False, bool)
+        self.versions = pop_option(options, 'versions', True, False, bool)
+        self.uid_forced = pop_option(options, 'uid', None, None, int)
+        self.gid_forced = pop_option(options, 'gid', None, None, int)
+        dir_uid = self.uid_forced if self.uid_forced is not None else self.default_uid
+        dir_gid = self.gid_forced if self.gid_forced is not None else self.default_gid
+        self.default_dir = Item(mode=0o40755, mtime=int(time.time() * 1e9), uid=dir_uid, gid=dir_gid)
         self._create_filesystem()
         llfuse.init(self, mountpoint, options)
         if not foreground:
@@ -500,8 +523,8 @@ class FuseOperations(llfuse.Operations, FuseBackend):
         entry.attr_timeout = 300
         entry.st_mode = item.mode
         entry.st_nlink = item.get('nlink', 1)
-        entry.st_uid = item.uid if item.uid >= 0 else self.default_uid
-        entry.st_gid = item.gid if item.gid >= 0 else self.default_gid
+        entry.st_uid = self.uid_forced if self.uid_forced is not None else item.uid if item.uid >= 0 else self.default_uid
+        entry.st_gid = self.gid_forced if self.gid_forced is not None else item.gid if item.gid >= 0 else self.default_gid
         entry.st_rdev = item.get('rdev', 0)
         entry.st_size = item.get_size()
         entry.st_blksize = 512