diff --git a/dvc/system.py b/dvc/system.py index 5348d5867..de73f82a1 100644 --- a/dvc/system.py +++ b/dvc/system.py @@ -1,8 +1,5 @@ import os -if os.name == 'nt': - import ntfsutils.hardlink as winlink - class System(object): @staticmethod @@ -11,10 +8,20 @@ class System(object): @staticmethod def hardlink(source, link_name): + import ctypes if System.is_unix(): - return os.link(source, link_name) + os.link(source, link_name) + return - return winlink.create(source, link_name) + CreateHardLink = ctypes.windll.kernel32.CreateHardLinkW + CreateHardLink.argtypes = [ctypes.c_wchar_p, + ctypes.c_wchar_p, + ctypes.c_void_p] + CreateHardLink.restype = ctypes.wintypes.BOOL + + res = CreateHardLink(link_name, source, None) + if res == 0: + raise ctypes.WinError() @staticmethod def symlink(source, link_name): @@ -102,30 +109,70 @@ class System(object): if ret != 0: raise DvcException('Reflink is not supported') - # FIXME - # Temporary fix while waiting for the PR to be merged and released: - # https://github.com/sunshowers/ntfs/pull/11 @staticmethod def getdirinfo(path): - from ntfsutils.fs import FILE_FLAG_BACKUP_SEMANTICS, FILE_SHARE_READ - from ntfsutils.fs import OPEN_EXISTING, BY_HANDLE_FILE_INFORMATION - from ntfsutils.fs import CreateFile, WinError - from ntfsutils.fs import GetFileInformationByHandle, CloseHandle + import ctypes + from ctypes import c_void_p, c_wchar_p, Structure, WinError + from ctypes.wintypes import DWORD, HANDLE, POINTER, BOOL + + FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 + FILE_SHARE_READ = 0x00000001 + OPEN_EXISTING = 3 + + class FILETIME(Structure): + _fields_ = [("dwLowDateTime", DWORD), + ("dwHighDateTime", DWORD)] + + class BY_HANDLE_FILE_INFORMATION(Structure): + _fields_ = [("dwFileAttributes", DWORD), + ("ftCreationTime", FILETIME), + ("ftLastAccessTime", FILETIME), + ("ftLastWriteTime", FILETIME), + ("dwVolumeSerialNumber", DWORD), + ("nFileSizeHigh", DWORD), + ("nFileSizeLow", DWORD), + ("nNumberOfLinks", DWORD), + ("nFileIndexHigh", DWORD), + ("nFileIndexLow", DWORD)] + flags = FILE_FLAG_BACKUP_SEMANTICS - hfile = CreateFile(path, - 0, - FILE_SHARE_READ, - None, - OPEN_EXISTING, - flags, - None) + + func = ctypes.windll.kernel32.CreateFileW + func.argtypes = [c_wchar_p, + DWORD, + DWORD, + c_void_p, + DWORD, + DWORD, + HANDLE] + func.restype = HANDLE + + hfile = func(path, + 0, + FILE_SHARE_READ, + None, + OPEN_EXISTING, + flags, + None) if hfile is None: raise WinError() + + func = ctypes.windll.kernel32.GetFileInformationByHandle + func.argtypes = [HANDLE, POINTER(BY_HANDLE_FILE_INFORMATION)] + func.restype = BOOL + info = BY_HANDLE_FILE_INFORMATION() - rv = GetFileInformationByHandle(hfile, info) - CloseHandle(hfile) + rv = func(hfile, info) + + func = ctypes.windll.kernel32.CloseHandle + func.argtypes = [HANDLE] + func.restype = BOOL + + func(hfile) + if rv == 0: raise WinError() + return info @staticmethod diff --git a/requirements.txt b/requirements.txt index 13db7a5c4..f5fe48990 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,6 @@ configobj>=5.0.6 networkx>=2.1 pyyaml>=3.12 gitpython>=2.1.8 -ntfsutils>=0.1.4 setuptools>=34.0.0 nanotime>=0.5.2 pyasn1>=0.4.1 diff --git a/setup.py b/setup.py index 98b4889f1..a2612cafb 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,6 @@ install_requires = [ "networkx>=2.1", "pyyaml>=3.12", "gitpython>=2.1.8", - "ntfsutils>=0.1.4", "setuptools>=34.0.0", "nanotime>=0.5.2", "pyasn1>=0.4.1",