瀏覽代碼

fix --read-special behaviour: follow symlinks pointing to special files

also: added a test for this.
Thomas Waldmann 6 年之前
父節點
當前提交
23eeded7c5
共有 4 個文件被更改,包括 22 次插入7 次删除
  1. 2 2
      src/borg/archive.py
  2. 3 3
      src/borg/archiver.py
  3. 3 2
      src/borg/helpers/fs.py
  4. 14 0
      src/borg/testsuite/archiver.py

+ 2 - 2
src/borg/archive.py

@@ -1153,9 +1153,9 @@ class FilesystemObjectProcessors:
         self.add_item(item, stats=self.stats)
         self.add_item(item, stats=self.stats)
         return 'i'  # stdin
         return 'i'  # stdin
 
 
-    def process_file(self, *, path, parent_fd, name, st, cache):
+    def process_file(self, *, path, parent_fd, name, st, cache, flags=flags_normal):
         with self.create_helper(path, st, None) as (item, status, hardlinked, hardlink_master):  # no status yet
         with self.create_helper(path, st, None) as (item, status, hardlinked, hardlink_master):  # no status yet
-            with OsOpen(path=path, parent_fd=parent_fd, name=name, flags=flags_normal, noatime=True) as fd:
+            with OsOpen(path=path, parent_fd=parent_fd, name=name, flags=flags, noatime=True) as fd:
                 with backup_io('fstat'):
                 with backup_io('fstat'):
                     st = stat_update_check(st, os.fstat(fd))
                     st = stat_update_check(st, os.fstat(fd))
                 is_special_file = is_special(st.st_mode)
                 is_special_file = is_special(st.st_mode)

+ 3 - 3
src/borg/archiver.py

@@ -66,7 +66,7 @@ from .helpers import ChunkIteratorFileWrapper
 from .helpers import popen_with_error_handling, prepare_subprocess_env
 from .helpers import popen_with_error_handling, prepare_subprocess_env
 from .helpers import dash_open
 from .helpers import dash_open
 from .helpers import umount
 from .helpers import umount
-from .helpers import flags_root, flags_dir
+from .helpers import flags_root, flags_dir, flags_follow
 from .helpers import msgpack
 from .helpers import msgpack
 from .nanorst import rst_to_terminal
 from .nanorst import rst_to_terminal
 from .patterns import ArgparsePatternAction, ArgparseExcludeFileAction, ArgparsePatternFileAction, parse_exclude_pattern
 from .patterns import ArgparsePatternAction, ArgparseExcludeFileAction, ArgparsePatternFileAction, parse_exclude_pattern
@@ -639,8 +639,8 @@ class Archiver:
                         else:
                         else:
                             special = is_special(st_target.st_mode)
                             special = is_special(st_target.st_mode)
                         if special:
                         if special:
-                            # XXX must FOLLOW symlinks!
-                            status = fso.process_file(path=path, parent_fd=parent_fd, name=name, st=st_target, cache=cache)
+                            status = fso.process_file(path=path, parent_fd=parent_fd, name=name, st=st_target,
+                                                      cache=cache, flags=flags_follow)
                         else:
                         else:
                             status = fso.process_symlink(path=path, parent_fd=parent_fd, name=name, st=st)
                             status = fso.process_symlink(path=path, parent_fd=parent_fd, name=name, st=st)
             elif stat.S_ISFIFO(st.st_mode):
             elif stat.S_ISFIFO(st.st_mode):

+ 3 - 2
src/borg/helpers/fs.py

@@ -202,8 +202,9 @@ def O_(*flags):
     return result
     return result
 
 
 
 
-flags_base = O_('BINARY', 'NONBLOCK', 'NOCTTY', 'NOFOLLOW')
-flags_normal = flags_base | O_('RDONLY')
+flags_base = O_('BINARY', 'NONBLOCK', 'NOCTTY')
+flags_follow = flags_base | O_('RDONLY')
+flags_normal = flags_base | O_('RDONLY', 'NOFOLLOW')
 flags_noatime = flags_normal | O_('NOATIME')
 flags_noatime = flags_normal | O_('NOATIME')
 flags_root = O_('RDONLY')
 flags_root = O_('RDONLY')
 flags_dir = O_('DIRECTORY', 'RDONLY', 'NOFOLLOW')
 flags_dir = O_('DIRECTORY', 'RDONLY', 'NOFOLLOW')

+ 14 - 0
src/borg/testsuite/archiver.py

@@ -1780,6 +1780,20 @@ class ArchiverTestCase(ArchiverTestCaseBase):
         output = self.cmd('create', '--list', '--filter=AM', self.repository_location + '::test3', 'input')
         output = self.cmd('create', '--list', '--filter=AM', self.repository_location + '::test3', 'input')
         self.assert_in('file1', output)
         self.assert_in('file1', output)
 
 
+    def test_create_read_special(self):
+        self.create_regular_file('regular', size=1024)
+        os.symlink(os.path.join(self.input_path, 'file'), os.path.join(self.input_path, 'link_regular'))
+        if are_fifos_supported():
+            os.mkfifo(os.path.join(self.input_path, 'fifo'))
+            os.symlink(os.path.join(self.input_path, 'fifo'), os.path.join(self.input_path, 'link_fifo'))
+        self.cmd('init', '--encryption=repokey', self.repository_location)
+        archive = self.repository_location + '::test'
+        self.cmd('create', '--read-special', archive, 'input')
+        output = self.cmd('list', archive)
+        assert 'input/link_regular -> ' in output  # not pointing to special file: archived as symlink
+        if are_fifos_supported():
+            assert 'input/link_fifo\n' in output  # pointing to a special file: archived following symlink
+
     def test_create_read_special_broken_symlink(self):
     def test_create_read_special_broken_symlink(self):
         os.symlink('somewhere doesnt exist', os.path.join(self.input_path, 'link'))
         os.symlink('somewhere doesnt exist', os.path.join(self.input_path, 'link'))
         self.cmd('init', '--encryption=repokey', self.repository_location)
         self.cmd('init', '--encryption=repokey', self.repository_location)