Mercurial > hg
changeset 35510:2062f7c2ac83
win32: implement util.getfstype()
This will allow NTFS to be added to the hardlink whitelist, and resume creating
hardlinks in transactions (which was disabled globally in 07a92bbd02e5; see also
e5ce49a30146). I opted to report "cifs" for remote volumes because this shows
in `hg debugfs`, which also reports that hardlinks are supported for these
volumes. So being able to distinguish it from "unknown" seems useful.
The documentation [1] seems to indicate that SMB isn't supported by these
functions, but experimenting shows that mapped drives are reported as "NTFS" on
Windows 7. I don't have a second Windows machine, but instead shared a temp
directory on C:\. In this setup, both of the following were detected as 'cifs'
with the explicit GetDriveType() check:
Z:\repo>hg ci -A
C:\>hg -R \\hostname\temp\repo ci -A # (without Z:\ being mapped)
It looks like this is called 6 times to add and commit a single new file, so I'm
a little surprised this isn't cached.
[1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Fri, 29 Dec 2017 21:28:19 -0500 |
parents | beede158ea8a |
children | d8f408d999f9 |
files | mercurial/win32.py mercurial/windows.py |
diffstat | 2 files changed, 50 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/win32.py Sat Dec 30 21:07:03 2017 -0500 +++ b/mercurial/win32.py Fri Dec 29 21:28:19 2017 -0500 @@ -223,6 +223,24 @@ _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD] _kernel32.SetFileAttributesA.restype = _BOOL +_DRIVE_UNKNOWN = 0 +_DRIVE_NO_ROOT_DIR = 1 +_DRIVE_REMOVABLE = 2 +_DRIVE_FIXED = 3 +_DRIVE_REMOTE = 4 +_DRIVE_CDROM = 5 +_DRIVE_RAMDISK = 6 + +_kernel32.GetDriveTypeA.argtypes = [_LPCSTR] +_kernel32.GetDriveTypeA.restype = _UINT + +_kernel32.GetVolumeInformationA.argtypes = [_LPCSTR, ctypes.c_void_p, _DWORD, + ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, _DWORD] +_kernel32.GetVolumeInformationA.restype = _BOOL + +_kernel32.GetVolumePathNameA.argtypes = [_LPCSTR, ctypes.c_void_p, _DWORD] +_kernel32.GetVolumePathNameA.restype = _BOOL + _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD] _kernel32.OpenProcess.restype = _HANDLE @@ -410,6 +428,37 @@ raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER) return buf.value +def getfstype(path): + """Get the filesystem type name from a directory or file (best-effort) + + Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc. + """ + # realpath() calls GetFullPathName() + realpath = os.path.realpath(path) + + size = len(realpath) + 1 + buf = ctypes.create_string_buffer(size) + + if not _kernel32.GetVolumePathNameA(realpath, ctypes.byref(buf), size): + raise ctypes.WinError() # Note: WinError is a function + + t = _kernel32.GetDriveTypeA(buf.value) + + if t == _DRIVE_REMOTE: + return 'cifs' + elif t not in (_DRIVE_REMOVABLE, _DRIVE_FIXED, _DRIVE_CDROM, + _DRIVE_RAMDISK): + return None + + size = 256 + name = ctypes.create_string_buffer(size) + + if not _kernel32.GetVolumeInformationA(buf.value, None, 0, None, None, None, + ctypes.byref(name), size): + raise ctypes.WinError() # Note: WinError is a function + + return name.value + def getuser(): '''return name of current user''' size = _DWORD(300)
--- a/mercurial/windows.py Sat Dec 30 21:07:03 2017 -0500 +++ b/mercurial/windows.py Fri Dec 29 21:28:19 2017 -0500 @@ -32,6 +32,7 @@ osutil = policy.importmod(r'osutil') executablepath = win32.executablepath +getfstype = win32.getfstype getuser = win32.getuser hidewindow = win32.hidewindow makedir = win32.makedir @@ -226,13 +227,6 @@ def checklink(path): return False -def getfstype(dirpath): - '''Get the filesystem type name from a directory (best-effort) - - Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc. - ''' - return None - def setbinary(fd): # When run without console, pipes may expose invalid # fileno(), usually set to -1.