mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-02 07:18:25 +01:00
188 lines
5.2 KiB
Python
188 lines
5.2 KiB
Python
import os
|
|
|
|
|
|
class System(object):
|
|
@staticmethod
|
|
def is_unix():
|
|
return os.name != 'nt'
|
|
|
|
@staticmethod
|
|
def hardlink(source, link_name):
|
|
import ctypes
|
|
if System.is_unix():
|
|
os.link(source, link_name)
|
|
return
|
|
|
|
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):
|
|
import ctypes
|
|
if System.is_unix():
|
|
return os.symlink(source, link_name)
|
|
|
|
flags = 0
|
|
if source is not None and os.path.isdir(source):
|
|
flags = 1
|
|
|
|
func = ctypes.windll.kernel32.CreateSymbolicLinkW
|
|
func.argtypes = (ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32)
|
|
func.restype = ctypes.c_ubyte
|
|
|
|
if func(link_name, source, flags) == 0:
|
|
raise ctypes.WinError()
|
|
|
|
@staticmethod
|
|
def _reflink_darwin(src, dst):
|
|
import ctypes
|
|
|
|
clib = ctypes.CDLL('libc.dylib')
|
|
if not hasattr(clib, 'clonefile'):
|
|
return -1
|
|
|
|
clonefile = clib.clonefile
|
|
clonefile.argtypes = [ctypes.c_char_p,
|
|
ctypes.c_char_p,
|
|
ctypes.c_int]
|
|
clonefile.restype = ctypes.c_int
|
|
|
|
return clonefile(ctypes.c_char_p(src.encode('utf-8')),
|
|
ctypes.c_char_p(src.encode('utf-8')),
|
|
ctypes.c_int(0))
|
|
|
|
@staticmethod
|
|
def _reflink_windows(src, dst):
|
|
return -1
|
|
|
|
@staticmethod
|
|
def _reflink_linux(src, dst):
|
|
import os
|
|
import fcntl
|
|
|
|
FICLONE = 0x40049409
|
|
|
|
s = open(src, 'r')
|
|
d = open(dst, 'w+')
|
|
|
|
try:
|
|
ret = fcntl.ioctl(d.fileno(), FICLONE, s.fileno())
|
|
except IOError:
|
|
s.close()
|
|
d.close()
|
|
os.unlink(dst)
|
|
raise
|
|
|
|
s.close()
|
|
d.close()
|
|
|
|
if ret != 0:
|
|
os.unlink(dst)
|
|
|
|
return ret
|
|
|
|
@staticmethod
|
|
def reflink(source, link_name):
|
|
import platform
|
|
from dvc.exceptions import DvcException
|
|
|
|
system = platform.system()
|
|
try:
|
|
if system == 'Windows':
|
|
ret = System._reflink_windows(source, link_name)
|
|
elif system == 'Darwin':
|
|
ret = System._reflink_darwin(source, link_name)
|
|
elif system == 'Linux':
|
|
ret = System._reflink_linux(source, link_name)
|
|
else:
|
|
ret = -1
|
|
except IOError:
|
|
ret = -1
|
|
|
|
if ret != 0:
|
|
raise DvcException('Reflink is not supported')
|
|
|
|
@staticmethod
|
|
def getdirinfo(path):
|
|
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
|
|
|
|
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 = func(hfile, info)
|
|
|
|
func = ctypes.windll.kernel32.CloseHandle
|
|
func.argtypes = [HANDLE]
|
|
func.restype = BOOL
|
|
|
|
func(hfile)
|
|
|
|
if rv == 0:
|
|
raise WinError()
|
|
|
|
return info
|
|
|
|
@staticmethod
|
|
def inode(path):
|
|
if System.is_unix():
|
|
return os.lstat(path).st_ino
|
|
|
|
# getdirinfo from ntfsutils works on both files and dirs
|
|
info = System.getdirinfo(path)
|
|
return hash((info.dwVolumeSerialNumber,
|
|
info.nFileIndexHigh,
|
|
info.nFileIndexLow))
|