diff --git a/borg/archiver.py b/borg/archiver.py index 3f4876943..166050dcd 100644 --- a/borg/archiver.py +++ b/borg/archiver.py @@ -337,34 +337,38 @@ Type "Yes I am sure" if you understand this and want to continue.\n""") repository = self.open_repository(args.src) manifest, key = Manifest.load(repository) if args.src.archive: - tmap = {1: 'p', 2: 'c', 4: 'd', 6: 'b', 0o10: '-', 0o12: 'l', 0o14: 's'} archive = Archive(repository, key, manifest, args.src.archive) - for item in archive.iter_items(): - type = tmap.get(item[b'mode'] // 4096, '?') - mode = format_file_mode(item[b'mode']) - size = 0 - if type == '-': + if args.short: + for item in archive.iter_items(): + print(remove_surrogates(item[b'path'])) + else: + tmap = {1: 'p', 2: 'c', 4: 'd', 6: 'b', 0o10: '-', 0o12: 'l', 0o14: 's'} + for item in archive.iter_items(): + type = tmap.get(item[b'mode'] // 4096, '?') + mode = format_file_mode(item[b'mode']) + size = 0 + if type == '-': + try: + size = sum(size for _, size, _ in item[b'chunks']) + except KeyError: + pass try: - size = sum(size for _, size, _ in item[b'chunks']) - except KeyError: - pass - try: - mtime = datetime.fromtimestamp(bigint_to_int(item[b'mtime']) / 1e9) - except ValueError: - # likely a broken mtime and datetime did not want to go beyond year 9999 - mtime = datetime(9999, 12, 31, 23, 59, 59) - if b'source' in item: - if type == 'l': - extra = ' -> %s' % item[b'source'] + mtime = datetime.fromtimestamp(bigint_to_int(item[b'mtime']) / 1e9) + except ValueError: + # likely a broken mtime and datetime did not want to go beyond year 9999 + mtime = datetime(9999, 12, 31, 23, 59, 59) + if b'source' in item: + if type == 'l': + extra = ' -> %s' % item[b'source'] + else: + type = 'h' + extra = ' link to %s' % item[b'source'] else: - type = 'h' - extra = ' link to %s' % item[b'source'] - else: - extra = '' - print('%s%s %-6s %-6s %8d %s %s%s' % ( - type, mode, item[b'user'] or item[b'uid'], - item[b'group'] or item[b'gid'], size, format_time(mtime), - remove_surrogates(item[b'path']), extra)) + extra = '' + print('%s%s %-6s %-6s %8d %s %s%s' % ( + type, mode, item[b'user'] or item[b'uid'], + item[b'group'] or item[b'gid'], size, format_time(mtime), + remove_surrogates(item[b'path']), extra)) else: for archive_info in manifest.list_archive_infos(sort_by='ts'): print(format_archive(archive_info)) @@ -766,6 +770,9 @@ Type "Yes I am sure" if you understand this and want to continue.\n""") epilog=list_epilog, formatter_class=argparse.RawDescriptionHelpFormatter) subparser.set_defaults(func=self.do_list) + subparser.add_argument('--short', dest='short', + action='store_true', default=False, + help='only print file/directory names, nothing else') subparser.add_argument('src', metavar='REPOSITORY_OR_ARCHIVE', type=location_validator(), help='repository/archive to list contents of') mount_epilog = textwrap.dedent(""" diff --git a/borg/testsuite/archiver.py b/borg/testsuite/archiver.py index 1f1be2bf0..e635d1b0c 100644 --- a/borg/testsuite/archiver.py +++ b/borg/testsuite/archiver.py @@ -12,6 +12,7 @@ import unittest from hashlib import sha256 from mock import patch +import pytest from .. import xattr from ..archive import Archive, ChunkBuffer, CHUNK_MAX_EXP @@ -33,6 +34,12 @@ has_lchflags = hasattr(os, 'lchflags') src_dir = os.path.join(os.getcwd(), os.path.dirname(__file__), '..') +# Python <= 3.2 raises OSError instead of PermissionError (See #164) +try: + PermissionError = PermissionError +except NameError: + PermissionError = OSError + class changedir: def __init__(self, dir): @@ -154,15 +161,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): self.create_regular_file('flagfile', size=1024) # Directory self.create_regular_file('dir2/file2', size=1024 * 80) - # File owner - os.chown('input/file1', 100, 200) # File mode os.chmod('input/file1', 0o7755) - os.chmod('input/dir2', 0o555) - # Block device - os.mknod('input/bdev', 0o600 | stat.S_IFBLK, os.makedev(10, 20)) - # Char device - os.mknod('input/cdev', 0o600 | stat.S_IFCHR, os.makedev(30, 40)) # Hard link os.link(os.path.join(self.input_path, 'file1'), os.path.join(self.input_path, 'hardlink')) @@ -180,20 +180,50 @@ class ArchiverTestCase(ArchiverTestCaseBase): os.mkfifo(os.path.join(self.input_path, 'fifo1')) if has_lchflags: os.lchflags(os.path.join(self.input_path, 'flagfile'), stat.UF_NODUMP) + try: + # Block device + os.mknod('input/bdev', 0o600 | stat.S_IFBLK, os.makedev(10, 20)) + # Char device + os.mknod('input/cdev', 0o600 | stat.S_IFCHR, os.makedev(30, 40)) + # File mode + os.chmod('input/dir2', 0o555) # if we take away write perms, we need root to remove contents + # File owner + os.chown('input/file1', 100, 200) + have_root = True # we have (fake)root + except PermissionError: + have_root = False + return have_root def test_basic_functionality(self): - self.create_test_files() + have_root = self.create_test_files() self.cmd('init', self.repository_location) self.cmd('create', self.repository_location + '::test', 'input') self.cmd('create', '--stats', self.repository_location + '::test.2', 'input') with changedir('output'): self.cmd('extract', self.repository_location + '::test') self.assert_equal(len(self.cmd('list', self.repository_location).splitlines()), 2) - item_count = 10 if has_lchflags else 11 # one file is UF_NODUMP - self.assert_equal(len(self.cmd('list', self.repository_location + '::test').splitlines()), item_count) + expected = [ + 'input', + 'input/bdev', + 'input/cdev', + 'input/dir2', + 'input/dir2/file2', + 'input/empty', + 'input/fifo1', + 'input/file1', + 'input/flagfile', + 'input/hardlink', + 'input/link1', + ] + if not have_root: + # we could not create these device files without (fake)root + expected.remove('input/bdev') + expected.remove('input/cdev') if has_lchflags: # remove the file we did not backup, so input and output become equal + expected.remove('input/flagfile') # this file is UF_NODUMP os.remove(os.path.join('input', 'flagfile')) + self.assert_equal(self.cmd('list', '--short', self.repository_location + '::test').splitlines(), expected) self.assert_dirs_equal('input', 'output/input') info_output = self.cmd('info', self.repository_location + '::test') item_count = 3 if has_lchflags else 4 # one file is UF_NODUMP @@ -436,6 +466,8 @@ class ArchiverTestCase(ArchiverTestCaseBase): fd.write(b'XXXX') self.cmd('check', self.repository_location, exit_code=1) + # we currently need to be able to create a lock directory inside the repo: + @pytest.mark.xfail(reason="we need to be able to create the lock directory inside the repo") def test_readonly_repository(self): self.cmd('init', self.repository_location) self.create_src_archive('test')