Jelajahi Sumber

create --files-changed=MODE option

control how borg detects whether a file has changed while it was backed up, valid modes are ctime, mtime or disabled.

ctime is the safest mode and the default.

mtime can be useful if ctime does not work correctly for some reason
(e.g. OneDrive files change their ctime without the user changing the file).

disabled (= disabling change detection) is not recommended as it could lead to
inconsistent backups. Only use if you know what you are doing.
Thomas Waldmann 2 minggu lalu
induk
melakukan
b27df15b36
2 mengubah file dengan 46 tambahan dan 11 penghapusan
  1. 29 11
      src/borg/archive.py
  2. 17 0
      src/borg/archiver/create_cmd.py

+ 29 - 11
src/borg/archive.py

@@ -1215,6 +1215,7 @@ class FilesystemObjectProcessors:
         log_json,
         iec,
         file_status_printer=None,
+        files_changed="ctime",
     ):
         self.metadata_collector = metadata_collector
         self.cache = cache
@@ -1223,6 +1224,7 @@ class FilesystemObjectProcessors:
         self.process_file_chunks = process_file_chunks
         self.show_progress = show_progress
         self.print_file_status = file_status_printer or (lambda *args: None)
+        self.files_changed = files_changed
 
         self.hlm = HardLinkManager(id_type=tuple, info_type=(list, type(None)))  # (dev, ino) -> chunks or None
         self.stats = Statistics(output_json=log_json, iec=iec)  # threading: done by cache (including progress)
@@ -1445,21 +1447,37 @@ class FilesystemObjectProcessors:
                         if not is_win32:  # TODO for win32
                             with backup_io("fstat2"):
                                 st2 = os.fstat(fd)
-                            if is_special_file:
+                            if self.files_changed == "disabled" or is_special_file:
                                 # special files:
                                 # - fifos change naturally, because they are fed from the other side. no problem.
                                 # - blk/chr devices don't change ctime anyway.
                                 pass
-                            elif st.st_ctime_ns != st2.st_ctime_ns:
-                                # ctime was changed, this is either a metadata or a data change.
-                                changed_while_backup = True
-                            elif start_reading - TIME_DIFFERS1_NS < st2.st_ctime_ns < end_reading + TIME_DIFFERS1_NS:
-                                # this is to treat a very special race condition, see #3536.
-                                # - file was changed right before st.ctime was determined.
-                                # - then, shortly afterwards, but already while we read the file, the
-                                #   file was changed again, but st2.ctime is the same due to ctime granularity.
-                                # when comparing file ctime to local clock, widen interval by TIME_DIFFERS1_NS.
-                                changed_while_backup = True
+                            elif self.files_changed == "ctime":
+                                if st.st_ctime_ns != st2.st_ctime_ns:
+                                    # ctime was changed, this is either a metadata or a data change.
+                                    changed_while_backup = True
+                                elif (
+                                    start_reading - TIME_DIFFERS1_NS < st2.st_ctime_ns < end_reading + TIME_DIFFERS1_NS
+                                ):
+                                    # this is to treat a very special race condition, see #3536.
+                                    # - file was changed right before st.ctime was determined.
+                                    # - then, shortly afterwards, but already while we read the file, the
+                                    #   file was changed again, but st2.ctime is the same due to ctime granularity.
+                                    # when comparing file ctime to local clock, widen interval by TIME_DIFFERS1_NS.
+                                    changed_while_backup = True
+                            elif self.files_changed == "mtime":
+                                if st.st_mtime_ns != st2.st_mtime_ns:
+                                    # mtime was changed, this is either a data change.
+                                    changed_while_backup = True
+                                elif (
+                                    start_reading - TIME_DIFFERS1_NS < st2.st_mtime_ns < end_reading + TIME_DIFFERS1_NS
+                                ):
+                                    # this is to treat a very special race condition, see #3536.
+                                    # - file was changed right before st.mtime was determined.
+                                    # - then, shortly afterwards, but already while we read the file, the
+                                    #   file was changed again, but st2.mtime is the same due to mtime granularity.
+                                    # when comparing file mtime to local clock, widen interval by TIME_DIFFERS1_NS.
+                                    changed_while_backup = True
                         if changed_while_backup:
                             # regular file changed while we backed it up, might be inconsistent/corrupt!
                             if last_try:

+ 17 - 0
src/borg/archiver/create_cmd.py

@@ -262,6 +262,7 @@ class CreateMixIn:
                     log_json=args.log_json,
                     iec=args.iec,
                     file_status_printer=self.print_file_status,
+                    files_changed=args.files_changed,
                 )
                 create_inner(archive, cache, fso)
         else:
@@ -611,6 +612,13 @@ class CreateMixIn:
           it had before a content change happened. This can be used maliciously as well as
           well-meant, but in both cases mtime based cache modes can be problematic.
 
+        The ``--files-changed`` option controls how Borg detects if a file has changed during backup:
+         - ctime (default): Use ctime to detect changes. This is the safest option.
+         - mtime: Use mtime to detect changes.
+         - disabled: Disable the "file has changed while we backed it up" detection completely.
+           This is not recommended unless you know what you're doing, as it could lead to
+           inconsistent backups if files change during the backup process.
+
         The mount points of filesystems or filesystem snapshots should be the same for every
         creation of a new archive to ensure fast operation. This is because the file cache that
         is used to determine changed files quickly uses absolute filenames.
@@ -888,6 +896,15 @@ class CreateMixIn:
             default=FILES_CACHE_MODE_UI_DEFAULT,
             help="operate files cache in MODE. default: %s" % FILES_CACHE_MODE_UI_DEFAULT,
         )
+        fs_group.add_argument(
+            "--files-changed",
+            metavar="MODE",
+            dest="files_changed",
+            action=Highlander,
+            choices=["ctime", "mtime", "disabled"],
+            default="ctime",
+            help="specify how to detect if a file has changed during backup (ctime, mtime, disabled). default: ctime",
+        )
         fs_group.add_argument(
             "--read-special",
             dest="read_special",