diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 0dd91bcee..356ae2427 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -2290,7 +2290,7 @@ class Archiver: key = key_factory(repository, cdata) break i = 0 - for id, cdata, tag, segment, offset in repository.scan_low_level(): + for id, cdata, tag, segment, offset in repository.scan_low_level(segment=args.segment, offset=args.offset): if tag == TAG_PUT: decrypt_dump(i, id, cdata, tag='put', segment=segment, offset=offset) elif tag == TAG_DELETE: @@ -3917,6 +3917,10 @@ class Archiver: help='repository to dump') subparser.add_argument('--ghost', dest='ghost', action='store_true', help='dump all segment file contents, including deleted/uncommitted objects and commits.') + subparser.add_argument('--segment', metavar='SEG', dest='segment', default=None, type=positive_int_validator, + help='used together with --ghost: limit processing to given segment.') + subparser.add_argument('--offset', metavar='OFFS', dest='offset', default=None, type=positive_int_validator, + help='used together with --ghost: limit processing to given offset.') debug_search_repo_objs_epilog = process_epilog(""" This command searches raw (but decrypted and decompressed) repo objects for a specific bytes sequence. diff --git a/src/borg/repository.py b/src/borg/repository.py index 9267fe0e6..c6565cdaa 100644 --- a/src/borg/repository.py +++ b/src/borg/repository.py @@ -1102,7 +1102,7 @@ class Repository: logger.info('Finished %s repository check, no problems found.', mode) return not error_found or repair - def scan_low_level(self): + def scan_low_level(self, segment=None, offset=None): """Very low level scan over all segment file entries. It does NOT care about what's committed and what not. @@ -1111,13 +1111,21 @@ class Repository: This is intended as a last-resort way to get access to all repo contents of damaged repos, when there is uncommitted, but valuable data in there... + + When segment or segment+offset is given, limit processing to this location only. """ - for segment, filename in self.io.segment_iterator(): + for current_segment, filename in self.io.segment_iterator(segment=segment): + if segment is not None and current_segment > segment: + break try: - for tag, key, offset, data in self.io.iter_objects(segment, include_data=True): - yield key, data, tag, segment, offset + for tag, key, current_offset, data in self.io.iter_objects(segment=current_segment, + offset=offset or 0, include_data=True): + if offset is not None and current_offset > offset: + break + yield key, data, tag, current_segment, current_offset except IntegrityError as err: - logger.error('Segment %d (%s) has IntegrityError(s) [%s] - skipping.' % (segment, filename, str(err))) + logger.error('Segment %d (%s) has IntegrityError(s) [%s] - skipping.' % ( + current_segment, filename, str(err))) def _rollback(self, *, cleanup): """