[FEATURE] #4489 – Deprecate --nobsdflags option

Replaced by --noflags. In internal data structure the key 'bsdflags' is kept for backwards compatibility.
This commit is contained in:
Thalian 2020-03-18 21:39:48 +01:00
parent e388fabd5b
commit 08a7661e67
10 changed files with 46 additions and 37 deletions

View File

@ -19,7 +19,7 @@ BorgBackup is not run with root privileges.
SSHFS is a FUSE file system and uses the SFTP protocol, so there may be also
other unsupported features that the actual implementations of ssfs, libfuse and
sftp on the backup server do not support, like file name encodings, ACLs, xattrs
or bsdflags. So there is no guarantee that you are able to restore a system
or flags. So there is no guarantee that you are able to restore a system
completely in every aspect from such a backup.
.. warning::

View File

@ -563,7 +563,7 @@ dictionary created by the ``Item`` class that contains:
* mtime, atime, ctime in nanoseconds
* xattrs
* acl (various OS-dependent fields)
* bsdflags
* flags
All items are serialized using msgpack and the resulting byte stream
is fed into the same chunker algorithm as used for regular file data

View File

@ -71,15 +71,15 @@ affect metadata stream deduplication: if only this timestamp changes between
backups and is stored into the metadata stream, the metadata stream chunks
won't deduplicate just because of that.
``--nobsdflags``
~~~~~~~~~~~~~~~~
``--nobsdflags / --noflags``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You can use this to not query and store (or not extract and set) bsdflags -
in case you don't need them or if they are broken somehow for your fs.
You can use this to not query and store (or not extract and set) flags - in case
you don't need them or if they are broken somehow for your fs.
On Linux, dealing with the bsflags needs some additional syscalls.
Especially when dealing with lots of small files, this causes a noticable
overhead, so you can use this option also for speeding up operations.
On Linux, dealing with the flags needs some additional syscalls. Especially when
dealing with lots of small files, this causes a noticable overhead, so you can
use this option also for speeding up operations.
``--umask``
~~~~~~~~~~~

View File

@ -75,10 +75,10 @@ _borg()
local opts="-e --encryption --append-only --storage-quota --make-parent-dirs ${common_opts}"
;;
*' create '*)
local opts="-n --dry-run -s --stats --list --filter --json --no-cache-sync --stdin-name -e --exclude --exclude-from --pattern --patterns-from --exclude-caches --exclude-if-present --keep-exclude-tags --exclude-nodump -x --one-file-system --numeric-owner --noatime --noctime --nobirthtime --nobsdflags --files-cache --read-special --comment --timestamp -c --checkpoint-interval --chunker-params -C --compression ${common_opts}"
local opts="-n --dry-run -s --stats --list --filter --json --no-cache-sync --stdin-name -e --exclude --exclude-from --pattern --patterns-from --exclude-caches --exclude-if-present --keep-exclude-tags --exclude-nodump -x --one-file-system --numeric-owner --noatime --noctime --nobirthtime --nobsdflags --noflags --files-cache --read-special --comment --timestamp -c --checkpoint-interval --chunker-params -C --compression ${common_opts}"
;;
*' extract '*)
local opts="--list -n --dry-run --numeric-owner --nobsdflags --stdout --sparse -e --exclude --exclude-from --pattern --patterns-from --strip-components ${common_opts}"
local opts="--list -n --dry-run --numeric-owner --nobsdflags --noflags --stdout --sparse -e --exclude --exclude-from --pattern --patterns-from --strip-components ${common_opts}"
;;
*' check '*)
local opts="--repository-only --archives-only --verify-data --repair --save-space --max-duration -P --prefix -a --glob-archives --sort-by --first --last ${common_opts}"

View File

@ -117,6 +117,7 @@ complete -c borg -f -l 'noatime' -d 'Do not store atime'
complete -c borg -f -l 'noctime' -d 'Do not store ctime' -n "__fish_seen_subcommand_from create"
complete -c borg -f -l 'nobirthtime' -d 'Do not store creation date' -n "__fish_seen_subcommand_from create"
complete -c borg -f -l 'nobsdflags' -d 'Do not store bsdflags' -n "__fish_seen_subcommand_from create"
complete -c borg -f -l 'noflags' -d 'Do not store flags' -n "__fish_seen_subcommand_from create"
set -l files_cache_mode "ctime,size,inode mtime,size,inode ctime,size mtime,size rechunk,ctime rechunk,mtime disabled"
complete -c borg -f -l 'files-cache' -d 'Operate files cache in MODE' -a "$files_cache_mode" -n "__fish_seen_subcommand_from create"
complete -c borg -f -l 'read-special' -d 'Open device files like regular files' -n "__fish_seen_subcommand_from create"
@ -134,6 +135,7 @@ complete -c borg -f -l 'list' -d 'Print verbose list of it
complete -c borg -f -s n -l 'dry-run' -d 'Do not actually extract any files' -n "__fish_seen_subcommand_from extract"
complete -c borg -f -l 'numeric-owner' -d 'Only obey numeric user:group identifiers' -n "__fish_seen_subcommand_from extract"
complete -c borg -f -l 'nobsdflags' -d 'Do not extract/set bsdflags' -n "__fish_seen_subcommand_from extract"
complete -c borg -f -l 'noflags' -d 'Do not extract/set flags' -n "__fish_seen_subcommand_from extract"
complete -c borg -f -l 'stdout' -d 'Write all extracted data to stdout' -n "__fish_seen_subcommand_from extract"
complete -c borg -f -l 'sparse' -d 'Create holes in output sparse file' -n "__fish_seen_subcommand_from extract"
# Exclusion options

View File

@ -101,6 +101,7 @@ _borg() {
--noatime'[do not store atime into archive]'\
--nobirthtime'[do not store birthtime (creation date) into archive]'\
--nobsdflags'[do not read and store bsdflags (e.g. NODUMP, IMMUTABLE) into archive]'\
--noflags'[do not read and store flags (e.g. NODUMP, IMMUTABLE) into archive]'\
--files-cache'[operate files cache in MODE. default: ctime,size,inode]:mode:(ctime,size,inode mtime,size,inode ctime,size mtime,size rechunk,ctime rechunk,mtime disabled)'\
--read-special'[open and read block and char device files as well as FIFOs as if they were regular files.]'\
--comment'[add a comment text to the archive]:COMMENT'\
@ -119,6 +120,7 @@ _borg() {
{-n,--dry-run}'[do not actually change any files]'\
--numeric-owner'[only obey numeric user and group identifiers]'\
--nobsdflags'[do not extract/set bsdflags (e.g. NODUMP, IMMUTABLE)]'\
--noflags'[do not extract/set flags (e.g. NODUMP, IMMUTABLE)]'\
--stdout'[write all extracted data to stdout]'\
--sparse'[create holes in output sparse file from all-zero chunks]'\
{-e,--exclude}'[exclude paths matching PATTERN]:PATTERN'\

View File

@ -375,7 +375,7 @@ class Archive:
"""Failed to encode filename "{}" into file system encoding "{}". Consider configuring the LANG environment variable."""
def __init__(self, repository, key, manifest, name, cache=None, create=False,
checkpoint_interval=1800, numeric_owner=False, noatime=False, noctime=False, nobsdflags=False,
checkpoint_interval=1800, numeric_owner=False, noatime=False, noctime=False, noflags=False,
progress=False, chunker_params=CHUNKER_PARAMS, start=None, start_monotonic=None, end=None,
consider_part_files=False, log_json=False):
self.cwd = os.getcwd()
@ -393,7 +393,7 @@ class Archive:
self.numeric_owner = numeric_owner
self.noatime = noatime
self.noctime = noctime
self.nobsdflags = nobsdflags
self.noflags = noflags
assert (start is None) == (start_monotonic is None), 'Logic error: if start is given, start_monotonic must be given as well and vice versa.'
if start is None:
start = datetime.utcnow()
@ -846,7 +846,7 @@ Utilization of max. archive size: {csize_max:.0%}
if warning:
set_ec(EXIT_WARNING)
# bsdflags include the immutable flag and need to be set last:
if not self.nobsdflags and 'bsdflags' in item:
if not self.noflags and 'bsdflags' in item:
try:
set_flags(path, item.bsdflags, fd=fd)
except OSError:
@ -1025,11 +1025,11 @@ Utilization of max. archive size: {csize_max:.0%}
class MetadataCollector:
def __init__(self, *, noatime, noctime, numeric_owner, nobsdflags, nobirthtime):
def __init__(self, *, noatime, noctime, numeric_owner, noflags, nobirthtime):
self.noatime = noatime
self.noctime = noctime
self.numeric_owner = numeric_owner
self.nobsdflags = nobsdflags
self.noflags = noflags
self.nobirthtime = nobirthtime
def stat_simple_attrs(self, st):
@ -1058,16 +1058,16 @@ class MetadataCollector:
def stat_ext_attrs(self, st, path, fd=None):
attrs = {}
bsdflags = 0
flags = 0
with backup_io('extended stat'):
if not self.nobsdflags:
bsdflags = get_flags(path, st, fd=fd)
if not self.noflags:
flags = get_flags(path, st, fd=fd)
xattrs = xattr.get_all(fd or path, follow_symlinks=False)
acl_get(path, attrs, st, self.numeric_owner, fd=fd)
if xattrs:
attrs['xattrs'] = StableDict(xattrs)
if bsdflags:
attrs['bsdflags'] = bsdflags
if flags:
attrs['bsdflags'] = flags
return attrs
def stat_attrs(self, st, path, fd=None):

View File

@ -175,7 +175,7 @@ def with_archive(method):
def wrapper(self, args, repository, key, manifest, **kwargs):
archive = Archive(repository, key, manifest, args.location.archive,
numeric_owner=getattr(args, 'numeric_owner', False),
nobsdflags=getattr(args, 'nobsdflags', False),
noflags=getattr(args, 'nobsdflags', False) or getattr(args, 'noflags', False),
cache=kwargs.get('cache'),
consider_part_files=args.consider_part_files, log_json=args.log_json)
return method(self, args, repository=repository, manifest=manifest, key=key, archive=archive, **kwargs)
@ -557,7 +557,7 @@ class Archiver:
self.output_filter = args.output_filter
self.output_list = args.output_list
self.nobsdflags = args.nobsdflags
self.noflags = args.nobsdflags or args.noflags
self.exclude_nodump = args.exclude_nodump
dry_run = args.dry_run
t0 = datetime.utcnow()
@ -574,7 +574,7 @@ class Archiver:
chunker_params=args.chunker_params, start=t0, start_monotonic=t0_monotonic,
log_json=args.log_json)
metadata_collector = MetadataCollector(noatime=not args.atime, noctime=args.noctime,
nobsdflags=args.nobsdflags, numeric_owner=args.numeric_owner, nobirthtime=args.nobirthtime)
noflags=args.nobsdflags or args.noflags, numeric_owner=args.numeric_owner, nobirthtime=args.nobirthtime)
cp = ChunksProcessor(cache=cache, key=key,
add_item=archive.add_item, write_checkpoint=archive.write_checkpoint,
checkpoint_interval=args.checkpoint_interval, rechunkify=False)
@ -2370,7 +2370,8 @@ class Archiver:
def preprocess_args(self, args):
deprecations = [
# ('--old', '--new' or None, 'Warning: "--old" has been deprecated. Use "--new" instead.'),
('--noatime', None, 'Warning: "--noatime" has been deprecated because it is the default now.')
('--noatime', None, 'Warning: "--noatime" has been deprecated because it is the default now.'),
('--nobsdflags', None, 'Warning: "--nobsdflags" has been deprecated. Use --noflags instead.')
]
for i, arg in enumerate(args[:]):
for old_name, new_name, warning in deprecations:
@ -3133,7 +3134,9 @@ class Archiver:
fs_group.add_argument('--nobirthtime', dest='nobirthtime', action='store_true',
help='do not store birthtime (creation date) into archive')
fs_group.add_argument('--nobsdflags', dest='nobsdflags', action='store_true',
help='do not read and store bsdflags (e.g. NODUMP, IMMUTABLE) into archive')
help='deprecated, use ``--noflags`` instead')
fs_group.add_argument('--noflags', dest='noflags', action='store_true',
help='do not read and store flags (e.g. NODUMP, IMMUTABLE) into archive')
fs_group.add_argument('--files-cache', metavar='MODE', dest='files_cache_mode',
type=FilesCacheMode, default=DEFAULT_FILES_CACHE_MODE_UI,
help='operate files cache in MODE. default: %s' % DEFAULT_FILES_CACHE_MODE_UI)
@ -3526,7 +3529,9 @@ class Archiver:
subparser.add_argument('--numeric-owner', dest='numeric_owner', action='store_true',
help='only obey numeric user and group identifiers')
subparser.add_argument('--nobsdflags', dest='nobsdflags', action='store_true',
help='do not extract/set bsdflags (e.g. NODUMP, IMMUTABLE)')
help='deprecated, use ``--noflags`` instead')
subparser.add_argument('--noflags', dest='noflags', action='store_true',
help='do not extract/set flags (e.g. NODUMP, IMMUTABLE)')
subparser.add_argument('--stdout', dest='stdout', action='store_true',
help='write all extracted data to stdout')
subparser.add_argument('--sparse', dest='sparse', action='store_true',

View File

@ -186,7 +186,7 @@ class BaseTestCase(unittest.TestCase):
diff = filecmp.dircmp(dir1, dir2)
self._assert_dirs_equal_cmp(diff, **kwargs)
def _assert_dirs_equal_cmp(self, diff, ignore_bsdflags=False, ignore_xattrs=False, ignore_ns=False):
def _assert_dirs_equal_cmp(self, diff, ignore_flags=False, ignore_xattrs=False, ignore_ns=False):
self.assert_equal(diff.left_only, [])
self.assert_equal(diff.right_only, [])
self.assert_equal(diff.diff_files, [])
@ -206,7 +206,7 @@ class BaseTestCase(unittest.TestCase):
d2 = [filename] + [getattr(s2, a) for a in attrs]
d1.insert(1, oct(s1.st_mode))
d2.insert(1, oct(s2.st_mode))
if not ignore_bsdflags:
if not ignore_flags:
d1.append(get_flags(path1, s1))
d2.append(get_flags(path2, s2))
# ignore st_rdev if file is not a block/char device, fixes #203
@ -232,7 +232,7 @@ class BaseTestCase(unittest.TestCase):
d2.append(no_selinux(get_all(path2, follow_symlinks=False)))
self.assert_equal(d1, d2)
for sub_diff in diff.subdirs.values():
self._assert_dirs_equal_cmp(sub_diff, ignore_bsdflags=ignore_bsdflags, ignore_xattrs=ignore_xattrs, ignore_ns=ignore_ns)
self._assert_dirs_equal_cmp(sub_diff, ignore_flags=ignore_flags, ignore_xattrs=ignore_xattrs, ignore_ns=ignore_ns)
@contextmanager
def fuse_mount(self, location, mountpoint, *options):

View File

@ -2182,16 +2182,16 @@ class ArchiverTestCase(ArchiverTestCaseBase):
mountpoint = os.path.join(self.tmpdir, 'mountpoint')
# mount the whole repository, archive contents shall show up in archivename subdirs of mountpoint:
with self.fuse_mount(self.repository_location, mountpoint):
# bsdflags are not supported by the FUSE mount
# flags are not supported by the FUSE mount
# we also ignore xattrs here, they are tested separately
self.assert_dirs_equal(self.input_path, os.path.join(mountpoint, 'archive', 'input'),
ignore_bsdflags=True, ignore_xattrs=True)
ignore_flags=True, ignore_xattrs=True)
self.assert_dirs_equal(self.input_path, os.path.join(mountpoint, 'archive2', 'input'),
ignore_bsdflags=True, ignore_xattrs=True)
ignore_flags=True, ignore_xattrs=True)
# mount only 1 archive, its contents shall show up directly in mountpoint:
with self.fuse_mount(self.repository_location + '::archive', mountpoint):
self.assert_dirs_equal(self.input_path, os.path.join(mountpoint, 'input'),
ignore_bsdflags=True, ignore_xattrs=True)
ignore_flags=True, ignore_xattrs=True)
# regular file
in_fn = 'input/file1'
out_fn = os.path.join(mountpoint, 'input', 'file1')
@ -2896,7 +2896,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02
with changedir('output'):
# This probably assumes GNU tar. Note -p switch to extract permissions regardless of umask.
subprocess.check_call(['tar', 'xpf', '../simple.tar', '--warning=no-timestamp'])
self.assert_dirs_equal('input', 'output/input', ignore_bsdflags=True, ignore_xattrs=True, ignore_ns=True)
self.assert_dirs_equal('input', 'output/input', ignore_flags=True, ignore_xattrs=True, ignore_ns=True)
@requires_gnutar
@requires_gzip
@ -2912,7 +2912,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02
assert 'input/dir2\n' in list
with changedir('output'):
subprocess.check_call(['tar', 'xpf', '../simple.tar.gz', '--warning=no-timestamp'])
self.assert_dirs_equal('input', 'output/input', ignore_bsdflags=True, ignore_xattrs=True, ignore_ns=True)
self.assert_dirs_equal('input', 'output/input', ignore_flags=True, ignore_xattrs=True, ignore_ns=True)
@requires_gnutar
def test_export_tar_strip_components(self):
@ -2928,7 +2928,7 @@ id: 2 / e29442 3506da 4e1ea7 / 25f62a 5a3d41 - 02
assert 'input/dir2\n' in list
with changedir('output'):
subprocess.check_call(['tar', 'xpf', '../simple.tar', '--warning=no-timestamp'])
self.assert_dirs_equal('input', 'output/', ignore_bsdflags=True, ignore_xattrs=True, ignore_ns=True)
self.assert_dirs_equal('input', 'output/', ignore_flags=True, ignore_xattrs=True, ignore_ns=True)
@requires_hardlinks
@requires_gnutar