Explorar el Código

Merge pull request #6940 from ThomasWaldmann/mkstemp_mode-1.1

use a custom mkstemp with mode support, fixes #6933, fixes #6400
TW hace 2 años
padre
commit
9e22b27dad
Se han modificado 2 ficheros con 71 adiciones y 11 borrados
  1. 68 0
      src/borg/helpers.py
  2. 3 11
      src/borg/platform/base.py

+ 68 - 0
src/borg/helpers.py

@@ -2533,3 +2533,71 @@ def umount(mountpoint):
         return subprocess.call(['fusermount', '-u', mountpoint], env=env)
     except FileNotFoundError:
         return subprocess.call(['umount', mountpoint], env=env)
+
+# below is a slightly modified tempfile.mkstemp that has an additional mode parameter.
+# see https://github.com/borgbackup/borg/issues/6933 and https://github.com/borgbackup/borg/issues/6400
+
+import os as _os  # NOQA
+import sys as _sys  # NOQA
+import errno as _errno  # NOQA
+from tempfile import _sanitize_params, _get_candidate_names, TMP_MAX, _text_openflags, _bin_openflags  # NOQA
+
+
+def _mkstemp_inner(dir, pre, suf, flags, output_type, mode=0o600):
+    """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile."""
+
+    dir = _os.path.abspath(dir)
+    names = _get_candidate_names()
+    if output_type is bytes:
+        names = map(_os.fsencode, names)
+
+    for seq in range(TMP_MAX):
+        name = next(names)
+        file = _os.path.join(dir, pre + name + suf)
+        # _sys.audit("tempfile.mkstemp", file)  # no .audit in sys module of python 3.5
+        try:
+            fd = _os.open(file, flags, mode)
+        except FileExistsError:
+            continue  # try again
+        except PermissionError:
+            # This exception is thrown when a directory with the chosen name
+            # already exists on windows.
+            if _os.name == "nt" and _os.path.isdir(dir) and _os.access(dir, _os.W_OK):
+                continue
+            else:
+                raise
+        return fd, file
+
+    raise FileExistsError(_errno.EEXIST, "No usable temporary file name found")
+
+
+def mkstemp_mode(suffix=None, prefix=None, dir=None, text=False, mode=0o600):
+    """User-callable function to create and return a unique temporary
+    file.  The return value is a pair (fd, name) where fd is the
+    file descriptor returned by os.open, and name is the filename.
+    If 'suffix' is not None, the file name will end with that suffix,
+    otherwise there will be no suffix.
+    If 'prefix' is not None, the file name will begin with that prefix,
+    otherwise a default prefix is used.
+    If 'dir' is not None, the file will be created in that directory,
+    otherwise a default directory is used.
+    If 'text' is specified and true, the file is opened in text
+    mode.  Else (the default) the file is opened in binary mode.
+    If any of 'suffix', 'prefix' and 'dir' are not None, they must be the
+    same type.  If they are bytes, the returned name will be bytes; str
+    otherwise.
+    The file is readable and writable only by the creating user ID.
+    If the operating system uses permission bits to indicate whether a
+    file is executable, the file is executable by no one. The file
+    descriptor is not inherited by children of this process.
+    Caller is responsible for deleting the file when done with it.
+    """
+
+    prefix, suffix, dir, output_type = _sanitize_params(prefix, suffix, dir)
+
+    if text:
+        flags = _text_openflags
+    else:
+        flags = _bin_openflags
+
+    return _mkstemp_inner(dir, prefix, suffix, flags, output_type, mode)

+ 3 - 11
src/borg/platform/base.py

@@ -1,10 +1,8 @@
 import errno
 import os
 import socket
-import tempfile
 import uuid
 
-from borg.constants import UMASK_DEFAULT
 from borg.helpers import safe_unlink
 
 """
@@ -183,7 +181,9 @@ class SaveFile:
 
     def __enter__(self):
         from .. import platform
-        self.tmp_fd, self.tmp_fname = tempfile.mkstemp(prefix=self.tmp_prefix, suffix='.tmp', dir=self.dir)
+        from ..helpers import mkstemp_mode
+
+        self.tmp_fd, self.tmp_fname = mkstemp_mode(prefix=self.tmp_prefix, suffix='.tmp', dir=self.dir, mode=0o666)
         self.f = platform.SyncFile(self.tmp_fname, fd=self.tmp_fd, binary=self.binary)
         return self.f
 
@@ -195,14 +195,6 @@ class SaveFile:
             safe_unlink(self.tmp_fname)  # with-body has failed, clean up tmp file
             return  # continue processing the exception normally
 
-        # tempfile.mkstemp always uses owner-only file permissions for the temp file,
-        # but as we'll rename it to the non-temp permanent file now, we need to respect
-        # the umask and change the file mode to what a normally created file would have.
-        # thanks to the crappy os.umask api, we can't query the umask without setting it. :-(
-        umask = os.umask(UMASK_DEFAULT)
-        os.umask(umask)
-        os.chmod(self.tmp_fname, mode=0o666 & ~ umask)
-
         try:
             os.replace(self.tmp_fname, self.path)  # POSIX: atomic rename
         except OSError: