From 23eeded7c5bc56c46d7bf7966c4062d98a476c28 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Wed, 20 Feb 2019 10:13:09 +0100 Subject: [PATCH] fix --read-special behaviour: follow symlinks pointing to special files also: added a test for this. --- src/borg/archive.py | 4 ++-- src/borg/archiver.py | 6 +++--- src/borg/helpers/fs.py | 5 +++-- src/borg/testsuite/archiver.py | 14 ++++++++++++++ 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/borg/archive.py b/src/borg/archive.py index 6083c8d82..21ed7b0cd 100644 --- a/src/borg/archive.py +++ b/src/borg/archive.py @@ -1153,9 +1153,9 @@ def process_stdin(self, *, path, cache): self.add_item(item, stats=self.stats) 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 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'): st = stat_update_check(st, os.fstat(fd)) is_special_file = is_special(st.st_mode) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 116907c4d..e7111c2a4 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -66,7 +66,7 @@ from .helpers import popen_with_error_handling, prepare_subprocess_env from .helpers import dash_open 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 .nanorst import rst_to_terminal from .patterns import ArgparsePatternAction, ArgparseExcludeFileAction, ArgparsePatternFileAction, parse_exclude_pattern @@ -639,8 +639,8 @@ def _process(self, *, path, parent_fd=None, name=None, else: special = is_special(st_target.st_mode) 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: status = fso.process_symlink(path=path, parent_fd=parent_fd, name=name, st=st) elif stat.S_ISFIFO(st.st_mode): diff --git a/src/borg/helpers/fs.py b/src/borg/helpers/fs.py index 1f39d58df..7e747e756 100644 --- a/src/borg/helpers/fs.py +++ b/src/borg/helpers/fs.py @@ -202,8 +202,9 @@ def O_(*flags): 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_root = O_('RDONLY') flags_dir = O_('DIRECTORY', 'RDONLY', 'NOFOLLOW') diff --git a/src/borg/testsuite/archiver.py b/src/borg/testsuite/archiver.py index 7c1316db2..cc828adb4 100644 --- a/src/borg/testsuite/archiver.py +++ b/src/borg/testsuite/archiver.py @@ -1780,6 +1780,20 @@ def test_create_topical(self): output = self.cmd('create', '--list', '--filter=AM', self.repository_location + '::test3', 'input') 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): os.symlink('somewhere doesnt exist', os.path.join(self.input_path, 'link')) self.cmd('init', '--encryption=repokey', self.repository_location)