Browse Source

Windows specific directory handling

On windows os.open does not work for directories.
If borg tries to open an directory on windows, None is returned
as file descriptor. The archive and archiver where adjusted to
handle the case if a file descriptor is None.
Jürg Rast 5 years ago
parent
commit
bff97a99e1
3 changed files with 11 additions and 3 deletions
  1. 3 1
      src/borg/archive.py
  2. 4 2
      src/borg/archiver.py
  3. 4 0
      src/borg/helpers/fs.py

+ 3 - 1
src/borg/archive.py

@@ -239,7 +239,9 @@ def OsOpen(*, flags, path=None, parent_fd=None, name=None, noatime=False, op='op
     try:
         yield fd
     finally:
-        os.close(fd)
+        # On windows fd is None for directories.
+        if fd is not None:
+            os.close(fd)
 
 
 class DownloadPipeline:

+ 4 - 2
src/borg/archiver.py

@@ -625,8 +625,10 @@ class Archiver:
             elif stat.S_ISDIR(st.st_mode):
                 with OsOpen(path=path, parent_fd=parent_fd, name=name, flags=flags_dir,
                             noatime=True, op='dir_open') as child_fd:
-                    with backup_io('fstat'):
-                        st = stat_update_check(st, os.fstat(child_fd))
+                    # child_fd is None for directories on windows, in that case a race condition check is not possible.
+                    if child_fd is not None:
+                        with backup_io('fstat'):
+                            st = stat_update_check(st, os.fstat(child_fd))
                     if recurse:
                         tag_names = dir_is_tagged(path, exclude_caches, exclude_if_present)
                         if tag_names:

+ 4 - 0
src/borg/helpers/fs.py

@@ -8,6 +8,7 @@ import sys
 import textwrap
 
 from .process import prepare_subprocess_env
+from ..platformflags import is_win32
 
 from ..constants import *  # NOQA
 
@@ -230,6 +231,9 @@ def os_open(*, flags, path=None, parent_fd=None, name=None, noatime=False):
         fname = name  # use name relative to parent_fd
     else:
         fname, parent_fd = path, None  # just use the path
+    if is_win32 and os.path.isdir(fname):
+        # Directories can not be opened on Windows.
+        return None
     _flags_normal = flags
     if noatime:
         _flags_noatime = _flags_normal | O_('NOATIME')