Преглед на файлове

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

create --files-changed=MODE option
TW преди 1 ден
родител
ревизия
547f7ec338
променени са 2 файла, в които са добавени 46 реда и са изтрити 11 реда
  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,
         log_json,
         iec,
         iec,
         file_status_printer=None,
         file_status_printer=None,
+        files_changed="ctime",
     ):
     ):
         self.metadata_collector = metadata_collector
         self.metadata_collector = metadata_collector
         self.cache = cache
         self.cache = cache
@@ -1223,6 +1224,7 @@ class FilesystemObjectProcessors:
         self.process_file_chunks = process_file_chunks
         self.process_file_chunks = process_file_chunks
         self.show_progress = show_progress
         self.show_progress = show_progress
         self.print_file_status = file_status_printer or (lambda *args: None)
         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.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)
         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
                         if not is_win32:  # TODO for win32
                             with backup_io("fstat2"):
                             with backup_io("fstat2"):
                                 st2 = os.fstat(fd)
                                 st2 = os.fstat(fd)
-                            if is_special_file:
+                            if self.files_changed == "disabled" or is_special_file:
                                 # special files:
                                 # special files:
                                 # - fifos change naturally, because they are fed from the other side. no problem.
                                 # - fifos change naturally, because they are fed from the other side. no problem.
                                 # - blk/chr devices don't change ctime anyway.
                                 # - blk/chr devices don't change ctime anyway.
                                 pass
                                 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:
                         if changed_while_backup:
                             # regular file changed while we backed it up, might be inconsistent/corrupt!
                             # regular file changed while we backed it up, might be inconsistent/corrupt!
                             if last_try:
                             if last_try:

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

@@ -262,6 +262,7 @@ class CreateMixIn:
                     log_json=args.log_json,
                     log_json=args.log_json,
                     iec=args.iec,
                     iec=args.iec,
                     file_status_printer=self.print_file_status,
                     file_status_printer=self.print_file_status,
+                    files_changed=args.files_changed,
                 )
                 )
                 create_inner(archive, cache, fso)
                 create_inner(archive, cache, fso)
         else:
         else:
@@ -611,6 +612,13 @@ class CreateMixIn:
           it had before a content change happened. This can be used maliciously as well as
           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.
           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
         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
         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.
         is used to determine changed files quickly uses absolute filenames.
@@ -888,6 +896,15 @@ class CreateMixIn:
             default=FILES_CACHE_MODE_UI_DEFAULT,
             default=FILES_CACHE_MODE_UI_DEFAULT,
             help="operate files cache in MODE. default: %s" % 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(
         fs_group.add_argument(
             "--read-special",
             "--read-special",
             dest="read_special",
             dest="read_special",