mirror of https://github.com/borgbackup/borg.git
borg delete --force --force to delete severely corrupted archives, fixes #1975
(cherry picked from commit 4d81b186ec
)
This commit is contained in:
parent
bfc745237a
commit
be1227fd1c
|
@ -542,7 +542,7 @@ Number of files: {0.stats.nfiles}'''.format(
|
|||
raise ChunksIndexError(cid)
|
||||
except Repository.ObjectNotFound as e:
|
||||
# object not in repo - strange, but we wanted to delete it anyway.
|
||||
if not forced:
|
||||
if forced == 0:
|
||||
raise
|
||||
error = True
|
||||
|
||||
|
@ -564,14 +564,14 @@ Number of files: {0.stats.nfiles}'''.format(
|
|||
except (TypeError, ValueError):
|
||||
# if items metadata spans multiple chunks and one chunk got dropped somehow,
|
||||
# it could be that unpacker yields bad types
|
||||
if not forced:
|
||||
if forced == 0:
|
||||
raise
|
||||
error = True
|
||||
if progress:
|
||||
pi.finish()
|
||||
except (msgpack.UnpackException, Repository.ObjectNotFound):
|
||||
# items metadata corrupted
|
||||
if not forced:
|
||||
if forced == 0:
|
||||
raise
|
||||
error = True
|
||||
# in forced delete mode, we try hard to delete at least the manifest entry,
|
||||
|
|
|
@ -503,9 +503,23 @@ class Archiver:
|
|||
def do_delete(self, args, repository):
|
||||
"""Delete an existing repository or archive"""
|
||||
if args.location.archive:
|
||||
archive_name = args.location.archive
|
||||
manifest, key = Manifest.load(repository)
|
||||
|
||||
if args.forced == 2:
|
||||
try:
|
||||
del manifest.archives[archive_name]
|
||||
except KeyError:
|
||||
raise Archive.DoesNotExist(archive_name)
|
||||
logger.info('Archive deleted.')
|
||||
manifest.write()
|
||||
# note: might crash in compact() after committing the repo
|
||||
repository.commit()
|
||||
logger.info('Done. Run "borg check --repair" to clean up the mess.')
|
||||
return self.exit_code
|
||||
|
||||
with Cache(repository, key, manifest, lock_wait=self.lock_wait) as cache:
|
||||
archive = Archive(repository, key, manifest, args.location.archive, cache=cache)
|
||||
archive = Archive(repository, key, manifest, archive_name, cache=cache)
|
||||
stats = Statistics()
|
||||
archive.delete(stats, progress=args.progress, forced=args.forced)
|
||||
manifest.write()
|
||||
|
@ -1554,8 +1568,9 @@ class Archiver:
|
|||
action='store_true', default=False,
|
||||
help='delete only the local cache for the given repository')
|
||||
subparser.add_argument('--force', dest='forced',
|
||||
action='store_true', default=False,
|
||||
help='force deletion of corrupted archives')
|
||||
action='count', default=0,
|
||||
help='force deletion of corrupted archives, '
|
||||
'use --force --force in case --force does not work.')
|
||||
subparser.add_argument('--save-space', dest='save_space', action='store_true',
|
||||
default=False,
|
||||
help='work slower, but using less space')
|
||||
|
|
|
@ -914,6 +914,20 @@ class ArchiverTestCase(ArchiverTestCaseBase):
|
|||
# Make sure the repo is gone
|
||||
self.assertFalse(os.path.exists(self.repository_path))
|
||||
|
||||
def test_delete_double_force(self):
|
||||
self.cmd('init', '--encryption=none', self.repository_location)
|
||||
self.create_src_archive('test')
|
||||
with Repository(self.repository_path, exclusive=True) as repository:
|
||||
manifest, key = Manifest.load(repository)
|
||||
archive = Archive(repository, key, manifest, 'test')
|
||||
id = archive.metadata[b'items'][0]
|
||||
repository.put(id, b'corrupted items metadata stream chunk')
|
||||
repository.commit()
|
||||
self.cmd('delete', '--force', '--force', self.repository_location + '::test')
|
||||
self.cmd('check', '--repair', self.repository_location)
|
||||
output = self.cmd('list', self.repository_location)
|
||||
self.assert_not_in('test', output)
|
||||
|
||||
def test_corrupted_repository(self):
|
||||
self.cmd('init', self.repository_location)
|
||||
self.create_src_archive('test')
|
||||
|
|
Loading…
Reference in New Issue