From bff97a99e16f992203c8af0df5550b4def02218b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Rast?= Date: Thu, 8 Aug 2019 23:48:23 +0200 Subject: [PATCH] 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. --- src/borg/archive.py | 4 +++- src/borg/archiver.py | 6 ++++-- src/borg/helpers/fs.py | 4 ++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/borg/archive.py b/src/borg/archive.py index 212fd3bfa..86e8a62e0 100644 --- a/src/borg/archive.py +++ b/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: diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 8fb6439d5..55ef22cde 100644 --- a/src/borg/archiver.py +++ b/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: diff --git a/src/borg/helpers/fs.py b/src/borg/helpers/fs.py index cb3f0ba8e..eecff277a 100644 --- a/src/borg/helpers/fs.py +++ b/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')