Browse Source

Merge pull request #5034 from fantasya-pbem/docs/3428_Restore-after-corruption

docs: borg repo restore instructions needed, fixes #3428
TW 5 years ago
parent
commit
54df299604
3 changed files with 33 additions and 6 deletions
  1. 20 0
      docs/faq.rst
  2. 2 0
      docs/internals/security.rst
  3. 11 6
      src/borg/archiver.py

+ 20 - 0
docs/faq.rst

@@ -187,6 +187,26 @@ all the part files and manually concatenate them together.
 
 
 For more details, see :ref:`checkpoints_parts`.
 For more details, see :ref:`checkpoints_parts`.
 
 
+My repository is corrupt, how can I restore from an older copy of it?
+---------------------------------------------------------------------
+
+If your repositories are encrypted and have the same ID, the recommended method
+is to delete the corrupted repository, but keep its security info, and then copy
+the working repository to the same location:
+
+::
+
+    borg delete --keep-security-info /path/to/repo
+    rsync -aH /path/to/repo-working/ /path/to/repo  # Note the trailing slash.
+
+A plain delete command would remove the security info in
+``~/.config/borg/security``, including the nonce value. In BorgBackup
+:ref:`security_encryption` is AES-CTR, where the nonce is a counter. When the
+working repo was used later for creating new archives, Borg would re-use nonce
+values due to starting from a lower counter value given by the older copy of the
+repository. To prevent this, the ``keep-security-info`` option is applied so
+that the client-side nonce counter is kept.
+
 Can Borg add redundancy to the backup data to deal with hardware malfunction?
 Can Borg add redundancy to the backup data to deal with hardware malfunction?
 -----------------------------------------------------------------------------
 -----------------------------------------------------------------------------
 
 

+ 2 - 0
docs/internals/security.rst

@@ -118,6 +118,8 @@ prompt is a set BORG_PASSPHRASE. See issue :issue:`2169` for details.
        manifest this way, while a changed layout would have broken
        manifest this way, while a changed layout would have broken
        compatibility.
        compatibility.
 
 
+.. _security_encryption:
+
 Encryption
 Encryption
 ----------
 ----------
 
 

+ 11 - 6
src/borg/archiver.py

@@ -1184,6 +1184,7 @@ class Archiver:
     def _delete_repository(self, args, repository):
     def _delete_repository(self, args, repository):
         """Delete a repository"""
         """Delete a repository"""
         dry_run = args.dry_run
         dry_run = args.dry_run
+        keep_security_info = args.keep_security_info
 
 
         if not args.cache_only:
         if not args.cache_only:
             msg = []
             msg = []
@@ -1208,9 +1209,11 @@ class Archiver:
             if not dry_run:
             if not dry_run:
                 repository.destroy()
                 repository.destroy()
                 logger.info("Repository deleted.")
                 logger.info("Repository deleted.")
-                SecurityManager.destroy(repository)
+                if not keep_security_info:
+                    SecurityManager.destroy(repository)
             else:
             else:
                 logger.info("Would delete repository.")
                 logger.info("Would delete repository.")
+                logger.info("Would %s security info." % ("keep" if keep_security_info else "delete"))
         if not dry_run:
         if not dry_run:
             Cache.destroy(repository)
             Cache.destroy(repository)
             logger.info("Cache deleted.")
             logger.info("Cache deleted.")
@@ -3360,9 +3363,10 @@ class Archiver:
         Important: When deleting archives, repository disk space is **not** freed until
         Important: When deleting archives, repository disk space is **not** freed until
         you run ``borg compact``.
         you run ``borg compact``.
 
 
-        If you delete the complete repository, the local cache for it (if any) is
-        also deleted. Alternatively, you can delete just the local cache with the
-        ``--cache-only`` option.
+        When you delete a complete repository, the security info and local cache for it
+        (if any) are also deleted. Alternatively, you can delete just the local cache
+        with the ``--cache-only`` option, or keep the security info with the
+        ``--keep-security-info`` option.
 
 
         When using ``--stats``, you will get some statistics about how much data was
         When using ``--stats``, you will get some statistics about how much data was
         deleted - the "Deleted data" deduplicated size there is most interesting as
         deleted - the "Deleted data" deduplicated size there is most interesting as
@@ -3391,10 +3395,11 @@ class Archiver:
                                help='print statistics for the deleted archive')
                                help='print statistics for the deleted archive')
         subparser.add_argument('--cache-only', dest='cache_only', action='store_true',
         subparser.add_argument('--cache-only', dest='cache_only', action='store_true',
                                help='delete only the local cache for the given repository')
                                help='delete only the local cache for the given repository')
-        subparser.add_argument('--force', dest='forced',
-                               action='count', default=0,
+        subparser.add_argument('--force', dest='forced', action='count', default=0,
                                help='force deletion of corrupted archives, '
                                help='force deletion of corrupted archives, '
                                     'use ``--force --force`` in case ``--force`` does not work.')
                                     'use ``--force --force`` in case ``--force`` does not work.')
+        subparser.add_argument('--keep-security-info', dest='keep_security_info', action='store_true',
+                               help='keep the local security info when deleting a repository')
         subparser.add_argument('--save-space', dest='save_space', action='store_true',
         subparser.add_argument('--save-space', dest='save_space', action='store_true',
                                help='work slower, but using less space')
                                help='work slower, but using less space')
         subparser.add_argument('location', metavar='REPOSITORY_OR_ARCHIVE', nargs='?', default='',
         subparser.add_argument('location', metavar='REPOSITORY_OR_ARCHIVE', nargs='?', default='',