Browse Source

Merge pull request #8971 from ThomasWaldmann/files-changed-option-master

create --files-changed=MODE option
TW 23 hours ago
parent
commit
547f7ec338
2 changed files with 46 additions and 11 deletions
  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",