From patchwork Sat Dec 30 06:37:30 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [1,of,5] pure: implement osutil.getfstype() on Windows From: Matt Harbison X-Patchwork-Id: 26501 Message-Id: <47921e6734f8f9e1536a.1514615850@Envy> To: mercurial-devel@mercurial-scm.org Date: Sat, 30 Dec 2017 01:37:30 -0500 # HG changeset patch # User Matt Harbison # Date 1514600899 18000 # Fri Dec 29 21:28:19 2017 -0500 # Node ID 47921e6734f8f9e1536a8bd9e4b33e77baca7337 # Parent a210a1a19734a60d52e2b718dfcfccdd5356c03b pure: implement osutil.getfstype() on Windows diff --git a/mercurial/pure/osutil.py b/mercurial/pure/osutil.py --- a/mercurial/pure/osutil.py +++ b/mercurial/pure/osutil.py @@ -154,6 +154,9 @@ else: import msvcrt + from .. import win32 + + getfstype = win32.getfstype _kernel32 = ctypes.windll.kernel32 diff --git a/mercurial/win32.py b/mercurial/win32.py --- a/mercurial/win32.py +++ b/mercurial/win32.py @@ -223,6 +223,16 @@ _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD] _kernel32.SetFileAttributesA.restype = _BOOL +_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 +420,39 @@ 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 == 4: # DRIVE_REMOTE + return 'cifs' + elif t not in (2, 3, 5, 6): + # DRIVE_UNKNOWN, DRIVE_NO_ROOT_DIR, unknown + return None + + # DRIVE_REMOVABLE, DRIVE_FIXED, DRIVE_CDROM, DRIVE_RAMDISK + + 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)