Преглед изворни кода

Merge pull request #7452 from snsmac/fix/no_perm_retry

Do not retry on permission errors
TW пре 2 година
родитељ
комит
c187d7c8e6
2 измењених фајлова са 38 додато и 0 уклоњено
  1. 5 0
      src/borg/archiver/create_cmd.py
  2. 33 0
      src/borg/testsuite/archiver/create_cmd.py

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

@@ -1,3 +1,4 @@
+import errno
 import sys
 import sys
 import argparse
 import argparse
 import logging
 import logging
@@ -370,6 +371,10 @@ class CreateMixIn:
                     self.print_warning("Unknown file type: %s", path)
                     self.print_warning("Unknown file type: %s", path)
                     return
                     return
             except (BackupError, BackupOSError) as err:
             except (BackupError, BackupOSError) as err:
+                if isinstance(err, BackupOSError):
+                    if err.errno in (errno.EPERM, errno.EACCES):
+                        # Do not try again, such errors can not be fixed by retrying.
+                        raise
                 # sleep a bit, so temporary problems might go away...
                 # sleep a bit, so temporary problems might go away...
                 sleep_s = 1000.0 / 1e6 * 10 ** (retry / 2)  # retry 0: 1ms, retry 6: 1s, ...
                 sleep_s = 1000.0 / 1e6 * 10 ** (retry / 2)  # retry 0: 1ms, retry 6: 1s, ...
                 time.sleep(sleep_s)
                 time.sleep(sleep_s)

+ 33 - 0
src/borg/testsuite/archiver/create_cmd.py

@@ -5,6 +5,7 @@ from random import randbytes
 import shutil
 import shutil
 import socket
 import socket
 import stat
 import stat
+import subprocess
 import time
 import time
 import unittest
 import unittest
 
 
@@ -208,6 +209,7 @@ class ArchiverTestCase(ArchiverTestCaseBase):
             input=flist.encode(),
             input=flist.encode(),
             exit_code=0,
             exit_code=0,
         )
         )
+        assert "retry: 3 of " in out
         assert "E input/file2" not in out  # we managed to read it in the 3rd retry (after 3 failed reads)
         assert "E input/file2" not in out  # we managed to read it in the 3rd retry (after 3 failed reads)
         # repo looking good overall? checks for rc == 0.
         # repo looking good overall? checks for rc == 0.
         self.cmd(f"--repo={self.repository_location}", "check", "--debug")
         self.cmd(f"--repo={self.repository_location}", "check", "--debug")
@@ -217,6 +219,37 @@ class ArchiverTestCase(ArchiverTestCaseBase):
         assert "input/file2" in out
         assert "input/file2" in out
         assert "input/file3" in out
         assert "input/file3" in out
 
 
+    def test_create_no_permission_file(self):
+        file_path = os.path.join(self.input_path, "file")
+        self.create_regular_file(file_path + "1", size=1000)
+        self.create_regular_file(file_path + "2", size=1000)
+        self.create_regular_file(file_path + "3", size=1000)
+        # revoke read permissions on file2 for everybody, including us:
+        if is_win32:
+            subprocess.run(["icacls.exe", file_path + "2", "/deny", "everyone:(R)"])
+        else:
+            os.chmod(file_path + "2", 0o000)
+        self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION)
+        flist = "".join(f"input/file{n}\n" for n in range(1, 4))
+        out = self.cmd(
+            f"--repo={self.repository_location}",
+            "create",
+            "--paths-from-stdin",
+            "--list",
+            "test",
+            input=flist.encode(),
+            exit_code=1,  # WARNING status: could not back up file2.
+        )
+        assert "retry: 1 of " not in out  # retries were NOT attempted!
+        assert "E input/file2" in out  # no permissions!
+        # repo looking good overall? checks for rc == 0.
+        self.cmd(f"--repo={self.repository_location}", "check", "--debug")
+        # check files in created archive
+        out = self.cmd(f"--repo={self.repository_location}", "list", "test")
+        assert "input/file1" in out
+        assert "input/file2" not in out  # it skipped file2
+        assert "input/file3" in out
+
     def test_create_content_from_command(self):
     def test_create_content_from_command(self):
         self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION)
         self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION)
         input_data = "some test content"
         input_data = "some test content"