[PATCH 2 of 5] osutil: split a utility function to obtain the volume out of getfstype()

Matt Harbison mharbison72 at gmail.com
Sat Dec 30 01:37:31 EST 2017


# HG changeset patch
# User Matt Harbison <matt_harbison at yahoo.com>
# Date 1514603737 18000
#      Fri Dec 29 22:15:37 2017 -0500
# Node ID 32d2484a8565412b23dcb3eda14f5470c9632d13
# Parent  47921e6734f8f9e1536a8bd9e4b33e77baca7337
osutil: split a utility function to obtain the volume out of getfstype()

This is only done on Windows because it's simple enough to call statfs() on
Unix.  The goal is to display this in `hg debugfs`.

diff --git a/mercurial/cext/osutil.c b/mercurial/cext/osutil.c
--- a/mercurial/cext/osutil.c
+++ b/mercurial/cext/osutil.c
@@ -1269,14 +1269,13 @@
 	return file_obj;
 }
 
-static PyObject *getfstype(PyObject *self, PyObject *args)
-/* given a directory path, return filesystem type name (best-effort) */
+static char *getvolumepath(PyObject *args)
+/* given a directory path, return filesystem mount point (best-effort) */
 {
 	const char *path = NULL;
 	char *fullpath = NULL;
 	char *volume = NULL;
 	DWORD size = 0;
-	char fstype[MAX_PATH + 1];
 
 	if (!PyArg_ParseTuple(args, "s", &path))
 		return NULL;
@@ -1306,6 +1305,26 @@
 		goto bail;
 	}
 
+	free(fullpath);
+	return volume;
+
+bail:
+	if (fullpath)
+		free(fullpath);
+	if (volume)
+		free(volume);
+	return NULL;
+}
+
+static PyObject *getfstype(PyObject *self, PyObject *args)
+/* given a directory path, return filesystem type name (best-effort) */
+{
+	char fstype[MAX_PATH + 1];
+	char *volume = getvolumepath(args);
+
+	if (!volume)
+		return NULL;
+
 	/* Even though the documentation says SMB doesn't support volume management
 	 * functions, passing an SMB path to GetVolumeInformation() returns 'NTFS'.
 	 * So bail unless this is known to _not_ be a network drive. */
@@ -1317,14 +1336,12 @@
 		break;
 
 	case DRIVE_REMOTE:
-		free(fullpath);
 		free(volume);
 		return Py_BuildValue("s", "cifs");
 
 	case DRIVE_UNKNOWN:
 	case DRIVE_NO_ROOT_DIR:
 	default:
-		free(fullpath);
 		free(volume);
 		Py_RETURN_NONE;
 	}
@@ -1332,19 +1349,12 @@
 	if (!GetVolumeInformation(volume, NULL, 0, NULL, NULL, NULL, fstype,
 			sizeof(fstype))) {
 		PyErr_SetFromWindowsErrWithFilename(GetLastError(), volume);
-		goto bail;
+		free(volume);
+		return NULL;
 	}
 
-	free(fullpath);
 	free(volume);
 	return Py_BuildValue("s", fstype);
-
-bail:
-	if (fullpath)
-		free(fullpath);
-	if (volume)
-		free(volume);
-	return NULL;
 }
 #endif
 
diff --git a/mercurial/win32.py b/mercurial/win32.py
--- a/mercurial/win32.py
+++ b/mercurial/win32.py
@@ -420,8 +420,9 @@
         raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
     return buf.value
 
-def getfstype(path):
-    """Get the filesystem type name from a directory or file (best-effort)
+def getvolumename(path):
+    """Get the mount point of the filesystem from a directory or file
+    (best-effort)
 
     Returns None if we are unsure. Raises OSError on ENOENT, EPERM, etc.
     """
@@ -434,7 +435,16 @@
     if not _kernel32.GetVolumePathNameA(realpath, ctypes.byref(buf), size):
         raise ctypes.WinError() # Note: WinError is a function
 
-    t = _kernel32.GetDriveTypeA(buf.value)
+    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.
+    """
+    volume = getvolumename(path)
+
+    t = _kernel32.GetDriveTypeA(volume)
 
     if t == 4:  # DRIVE_REMOTE
         return 'cifs'
@@ -447,7 +457,7 @@
     size = 256
     name = ctypes.create_string_buffer(size)
 
-    if not _kernel32.GetVolumeInformationA(buf.value, None, 0, None, None, None,
+    if not _kernel32.GetVolumeInformationA(volume, None, 0, None, None, None,
             ctypes.byref(name), size):
         raise ctypes.WinError() # Note: WinError is a function
 


More information about the Mercurial-devel mailing list