From 2d9ec1005b1fb5dbaabfb1779ad18d4ba05adcb8 Mon Sep 17 00:00:00 2001 From: Ruslan Kuprieiev Date: Tue, 4 Dec 2018 10:46:10 +0200 Subject: [PATCH] unprotect: only process symlinks and hardlinks Fixes #1373 Signed-off-by: Ruslan Kuprieiev --- dvc/project.py | 15 ++++++++++----- dvc/system.py | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/dvc/project.py b/dvc/project.py index 84d7ddf58..0ce183565 100644 --- a/dvc/project.py +++ b/dvc/project.py @@ -325,16 +325,21 @@ class Project(object): def _unprotect_file(self, path): import stat import uuid + from dvc.system import System from dvc.utils import copyfile, move, remove - self.logger.debug("Unprotecting '{}'".format(path)) + if System.is_symlink(path) or System.is_hardlink(path): + self.logger.debug("Unprotecting '{}'".format(path)) - tmp = os.path.join(os.path.dirname(path), '.' + str(uuid.uuid4())) - move(path, tmp) + tmp = os.path.join(os.path.dirname(path), '.' + str(uuid.uuid4())) + move(path, tmp) - copyfile(tmp, path) + copyfile(tmp, path) - remove(tmp) + remove(tmp) + else: + self.logger.debug("Skipping copying for '{}', since it is not " + "a symlink or a hardlink.".format(path)) os.chmod(path, os.stat(path).st_mode | stat.S_IWRITE) diff --git a/dvc/system.py b/dvc/system.py index bba11fa1e..6c3c3fca8 100644 --- a/dvc/system.py +++ b/dvc/system.py @@ -240,3 +240,22 @@ class System(object): return System._wait_for_input_posix(timeout) else: return System._wait_for_input_windows(timeout) + + @staticmethod + def is_symlink(path): + if System.is_unix(): + return os.path.islink(path) + + # https://docs.microsoft.com/en-us/windows/desktop/fileio/ + # file-attribute-constants + FILE_ATTRIBUTE_REPARSE_POINT = 0x400 + info = System.getdirinfo(path) + return info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT + + @staticmethod + def is_hardlink(path): + if System.is_unix(): + return os.stat(path).st_nlink > 1 + + info = System.getdirinfo(path) + return info.nNumberOfLinks > 1