瀏覽代碼

[runtime] Linux support for statfs and improved drive detection

This introduces support for using statfs(2) on Linux as well as moves parsing of
drive information on Linux to the runtime. Three sources of information about drives
are supported: /proc/self/mountinfo, /proc/mounts and /etc/{mtab,mnttab}. The are
tried in the order given. Also, the code will include information about FUSE drives
with the exclusion of the GNOME gvfs (which is of no use to users).
Marek Habersack 14 年之前
父節點
當前提交
a2165c2829
共有 4 個文件被更改,包括 746 次插入109 次删除
  1. 3 91
      mcs/class/corlib/System.IO/DriveInfo.cs
  2. 419 17
      mono/io-layer/io.c
  3. 0 1
      mono/metadata/icall.c
  4. 324 0
      mono/utils/linux_magic.h

+ 3 - 91
mcs/class/corlib/System.IO/DriveInfo.cs

@@ -147,105 +147,17 @@ namespace System.IO {
 			}
 		}
 		
-		static StreamReader TryOpen (string name)
-		{
-			if (File.Exists (name))
-				return new StreamReader (name);
-			return null;
-		}
-
-		static char [] space = { ' ' };
-		static DriveInfo [] LinuxGetDrives ()
-		{
-			using (StreamReader mounts = TryOpen ("/proc/mounts")){
-				var drives = new List<DriveInfo> ();
-				string line;
-				
-				while ((line = mounts.ReadLine ()) != null){
-					if (line.StartsWith ("rootfs"))
-						continue;
-					string [] parts = line.Split (space, 4);
-					if (parts.Length < 3)
-						continue;
-					string path = Unescape (parts [1]);
-					string fstype = parts [2];
-					drives.Add (new DriveInfo (path, fstype));
-				}
-
-				return drives.ToArray ();
-			}
-		}
-
-		static string Unescape (string path)
-		{
-			StringBuilder sb = null;
-			int start = 0;
-			do {
-				int slash = path.IndexOf ('\\', start);
-				if (slash >= 0) {
-					if (sb == null)
-						sb = new StringBuilder ();
-					sb.Append (path.Substring (start, slash - start));
-					char c = (char) ((path [slash + 1] - '0') << 6);
-					c += (char) ((path [slash + 2] - '0') << 3);
-					c += (char) (path [slash + 3] - '0');
-					sb.Append (c);
-					start = slash + 4;
-					continue;
-				}
-				if (start == 0)
-					return path;
-				sb.Append (path.Substring (start));
-				return sb.ToString ();
-			} while (true);
-		}
-		
-		static DriveInfo [] UnixGetDrives ()
-		{
-			DriveInfo [] di = null;
-
-			try {
-				using (StreamReader linux_ostype = TryOpen ("/proc/sys/kernel/ostype")){
-					if (linux_ostype != null){
-						string line = linux_ostype.ReadLine ();
-						if (line == "Linux")
-							di = LinuxGetDrives ();
-					}
-				}
-				
-				if (di != null)
-					return di;
-			} catch (Exception) {
-				// If anything happens.
-			}
-			
-			DriveInfo [] unknown = new DriveInfo [1];
-			unknown [0]= new DriveInfo ("/", "unixfs");
-
-			return unknown;
-		}
-
-		static DriveInfo [] RuntimeGetDrives ()
+		[MonoTODO("In windows, alldrives are 'Fixed'")]
+		public static DriveInfo[] GetDrives ()
 		{
 			var drives = Environment.GetLogicalDrives ();
 			DriveInfo [] infos = new DriveInfo [drives.Length];
 			int i = 0;
-			foreach (string s in drives) {
+			foreach (string s in drives)
 				infos [i++] = new DriveInfo (s, GetDriveFormat (s));
-				Console.WriteLine (infos [i-1].path);
-			}
 
 			return infos;
 		}
-		
-		[MonoTODO("In windows, alldrives are 'Fixed'")]
-		public static DriveInfo[] GetDrives ()
-		{
-			if (!Environment.IsUnix || Environment.IsMacOS)
-				return RuntimeGetDrives ();
-			
-			return UnixGetDrives ();
-		}
 
 		void ISerializable.GetObjectData (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
 		{

+ 419 - 17
mono/io-layer/io.c

@@ -17,7 +17,8 @@
 #include <sys/stat.h>
 #ifdef HAVE_SYS_STATVFS_H
 #include <sys/statvfs.h>
-#elif defined(HAVE_SYS_STATFS_H)
+#endif
+#if defined(HAVE_SYS_STATFS_H)
 #include <sys/statfs.h>
 #endif
 #if defined(HAVE_SYS_PARAM_H) && defined(HAVE_SYS_MOUNT_H)
@@ -32,6 +33,7 @@
 #ifdef __linux__
 #include <sys/ioctl.h>
 #include <linux/fs.h>
+#include <mono/utils/linux_magic.h>
 #endif
 
 #include <mono/io-layer/wapi.h>
@@ -3652,9 +3654,296 @@ unescape_octal (gchar *str)
 	}
 	*wptr = '\0';
 }
+#if __linux__
+#define GET_LOGICAL_DRIVE_STRINGS_BUFFER 512
+#define GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER 512
+#define GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER 64
+
+typedef struct 
+{
+	glong total;
+	guint32 buffer_index;
+	guint32 mountpoint_index;
+	guint32 field_number;
+	guint32 allocated_size;
+	guint32 fsname_index;
+	guint32 fstype_index;
+	gchar mountpoint [GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER + 1];
+	gchar *mountpoint_allocated;
+	gchar buffer [GET_LOGICAL_DRIVE_STRINGS_BUFFER];
+	gchar fsname [GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER + 1];
+	gchar fstype [GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER + 1];
+	ssize_t nbytes;
+	gchar delimiter;
+	gboolean check_mount_source;
+} LinuxMountInfoParseState;
+
+static gboolean GetLogicalDriveStrings_Mounts (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state);
+static gboolean GetLogicalDriveStrings_MountInfo (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state);
+static gint32 GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf);
+static void append_to_mountpoint (LinuxMountInfoParseState *state);
+static gboolean add_drive_string (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state);
+
+gint32 GetLogicalDriveStrings (guint32 len, gunichar2 *buf)
+{
+	int fd;
+	gint32 ret = 0;
+	LinuxMountInfoParseState state;
+	gboolean (*parser)(guint32, gunichar2*, LinuxMountInfoParseState*) = NULL;
+
+	memset (buf, 0, len * sizeof (gunichar2));
+	fd = open ("/proc/self/mountinfo", O_RDONLY);
+	if (fd != -1)
+		parser = GetLogicalDriveStrings_MountInfo;
+	else {
+		fd = open ("/proc/mounts", O_RDONLY);
+		if (fd != -1)
+			parser = GetLogicalDriveStrings_Mounts;
+	}
+
+	if (!parser) {
+		ret = GetLogicalDriveStrings_Mtab (len, buf);
+		goto done_and_out;
+	}
+
+	memset (&state, 0, sizeof (LinuxMountInfoParseState));
+	state.field_number = 1;
+	state.delimiter = ' ';
+
+	while ((state.nbytes = read (fd, state.buffer, GET_LOGICAL_DRIVE_STRINGS_BUFFER)) > 0) {
+		state.buffer_index = 0;
+
+		while ((*parser)(len, buf, &state)) {
+			if (state.buffer [state.buffer_index] == '\n') {
+				gboolean quit = add_drive_string (len, buf, &state);
+				state.field_number = 1;
+				state.buffer_index++;
+				if (state.mountpoint_allocated) {
+					g_free (state.mountpoint_allocated);
+					state.mountpoint_allocated = NULL;
+				}
+				if (quit) {
+					ret = state.total;
+					goto done_and_out;
+				}
+			}
+		}
+	};
+	ret = state.total;
+
+  done_and_out:
+	if (fd != -1)
+		close (fd);
+	return ret;
+}
+
+static gboolean GetLogicalDriveStrings_Mounts (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state)
+{
+	gchar *ptr;
+
+	if (state->field_number == 1)
+		state->check_mount_source = TRUE;
+
+	while (state->buffer_index < (guint32)state->nbytes) {
+		if (state->buffer [state->buffer_index] == state->delimiter) {
+			state->field_number++;
+			switch (state->field_number) {
+				case 2:
+					state->mountpoint_index = 0;
+					break;
+
+				case 3:
+					if (state->mountpoint_allocated)
+						state->mountpoint_allocated [state->mountpoint_index] = 0;
+					else
+						state->mountpoint [state->mountpoint_index] = 0;
+					break;
+
+				default:
+					ptr = (gchar*)memchr (state->buffer + state->buffer_index, '\n', GET_LOGICAL_DRIVE_STRINGS_BUFFER - state->buffer_index);
+					if (ptr)
+						state->buffer_index = (ptr - (gchar*)state->buffer) - 1;
+					else
+						state->buffer_index = state->nbytes;
+					return TRUE;
+			}
+			state->buffer_index++;
+			continue;
+		} else if (state->buffer [state->buffer_index] == '\n')
+			return TRUE;
+
+		switch (state->field_number) {
+			case 1:
+				if (state->check_mount_source) {
+					if (state->fsname_index == 0 && state->buffer [state->buffer_index] == '/') {
+						/* We can ignore the rest, it's a device
+						 * path */
+						state->check_mount_source = FALSE;
+						state->fsname [state->fsname_index++] = '/';
+						break;
+					}
+					if (state->fsname_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
+						state->fsname [state->fsname_index++] = state->buffer [state->buffer_index];
+				}
+				break;
+
+			case 2:
+				append_to_mountpoint (state);
+				break;
+
+			case 3:
+				if (state->fstype_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
+					state->fstype [state->fstype_index++] = state->buffer [state->buffer_index];
+				break;
+		}
+
+		state->buffer_index++;
+	}
+
+	return FALSE;
+}
+
+static gboolean GetLogicalDriveStrings_MountInfo (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state)
+{
+	while (state->buffer_index < (guint32)state->nbytes) {
+		if (state->buffer [state->buffer_index] == state->delimiter) {
+			state->field_number++;
+			switch (state->field_number) {
+				case 5:
+					state->mountpoint_index = 0;
+					break;
+
+				case 6:
+					if (state->mountpoint_allocated)
+						state->mountpoint_allocated [state->mountpoint_index] = 0;
+					else
+						state->mountpoint [state->mountpoint_index] = 0;
+					break;
+
+				case 7:
+					state->delimiter = '-';
+					break;
+
+				case 8:
+					state->delimiter = ' ';
+					break;
+
+				case 10:
+					state->check_mount_source = TRUE;
+					break;
+			}
+			state->buffer_index++;
+			continue;
+		} else if (state->buffer [state->buffer_index] == '\n')
+			return TRUE;
+
+		switch (state->field_number) {
+			case 5:
+				append_to_mountpoint (state);
+				break;
+
+			case 9:
+				if (state->fstype_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
+					state->fstype [state->fstype_index++] = state->buffer [state->buffer_index];
+				break;
+
+			case 10:
+				if (state->check_mount_source) {
+					if (state->fsname_index == 0 && state->buffer [state->buffer_index] == '/') {
+						/* We can ignore the rest, it's a device
+						 * path */
+						state->check_mount_source = FALSE;
+						state->fsname [state->fsname_index++] = '/';
+						break;
+					}
+					if (state->fsname_index < GET_LOGICAL_DRIVE_STRINGS_FSNAME_BUFFER)
+						state->fsname [state->fsname_index++] = state->buffer [state->buffer_index];
+				}
+				break;
+		}
+
+		state->buffer_index++;
+	}
+
+	return FALSE;
+}
+
+static void
+append_to_mountpoint (LinuxMountInfoParseState *state)
+{
+	gchar ch = state->buffer [state->buffer_index];
+	if (state->mountpoint_allocated) {
+		if (state->mountpoint_index >= state->allocated_size) {
+			guint32 newsize = (state->allocated_size << 1) + 1;
+			gchar *newbuf = g_malloc0 (newsize * sizeof (gchar));
+
+			memcpy (newbuf, state->mountpoint_allocated, state->mountpoint_index);
+			g_free (state->mountpoint_allocated);
+			state->mountpoint_allocated = newbuf;
+			state->allocated_size = newsize;
+		}
+		state->mountpoint_allocated [state->mountpoint_index++] = ch;
+	} else {
+		if (state->mountpoint_index >= GET_LOGICAL_DRIVE_STRINGS_MOUNTPOINT_BUFFER) {
+			state->allocated_size = (state->mountpoint_index << 1) + 1;
+			state->mountpoint_allocated = g_malloc0 (state->allocated_size * sizeof (gchar));
+			memcpy (state->mountpoint_allocated, state->mountpoint, state->mountpoint_index);
+			state->mountpoint_allocated [state->mountpoint_index++] = ch;
+		} else
+			state->mountpoint [state->mountpoint_index++] = ch;
+	}
+}
+
+static gboolean
+add_drive_string (guint32 len, gunichar2 *buf, LinuxMountInfoParseState *state)
+{
+	gboolean quit = FALSE;
+	gboolean ignore_entry;
+
+	if (state->fsname_index == 1 && state->fsname [0] == '/')
+		ignore_entry = FALSE;
+	else if (state->fsname_index == 0 || memcmp ("none", state->fsname, state->fsname_index) == 0)
+		ignore_entry = TRUE;
+	else if (state->fstype_index >= 5 && memcmp ("fuse.", state->fstype, 5) == 0) {
+		/* Ignore GNOME's gvfs */
+		if (state->fstype_index == 21 && memcmp ("fuse.gvfs-fuse-daemon", state->fstype, state->fstype_index) == 0)
+			ignore_entry = TRUE;
+		else
+			ignore_entry = FALSE;
+	} else
+		ignore_entry = TRUE;
+
+	if (!ignore_entry) {
+		gunichar2 *dir;
+		glong length;
+		gchar *mountpoint = state->mountpoint_allocated ? state->mountpoint_allocated : state->mountpoint;
+
+		unescape_octal (mountpoint);
+		dir = g_utf8_to_utf16 (mountpoint, -1, NULL, &length, NULL);
+		if (state->total + length + 1 > len) {
+			quit = TRUE;
+			state->total = len * 2;
+		} else {
+			length++;
+			memcpy (buf + state->total, dir, sizeof (gunichar2) * length);
+			state->total += length;
+		}
+		g_free (dir);
+	}
+	state->fsname_index = 0;
+	state->fstype_index = 0;
 
+	return quit;
+}
+#else
 gint32
 GetLogicalDriveStrings (guint32 len, gunichar2 *buf)
+{
+	return GetLogicalDriveStrings_Mtab (len, buf);
+}
+#endif
+static gint32
+GetLogicalDriveStrings_Mtab (guint32 len, gunichar2 *buf)
 {
 	FILE *fp;
 	gunichar2 *ptr, *dir;
@@ -3849,6 +4138,9 @@ gboolean GetDiskFreeSpaceEx(const gunichar2 *path_name, WapiULargeInteger *free_
  */
 typedef struct {
 	guint32 drive_type;
+#if __linux__
+	const long fstypeid;
+#endif
 	const gchar* fstype;
 } _wapi_drive_type;
 
@@ -3869,6 +4161,80 @@ static _wapi_drive_type _wapi_drive_types[] = {
 	{ DRIVE_REMOTE, "smbfs" },
 	{ DRIVE_FIXED, "udf" },
 	{ DRIVE_REMOTE, "webdav" },
+	{ DRIVE_UNKNOWN, NULL }
+#elif __linux__
+	{ DRIVE_FIXED, ADFS_SUPER_MAGIC, "adfs"},
+	{ DRIVE_FIXED, AFFS_SUPER_MAGIC, "affs"},
+	{ DRIVE_REMOTE, AFS_SUPER_MAGIC, "afs"},
+	{ DRIVE_RAMDISK, AUTOFS_SUPER_MAGIC, "autofs"},
+	{ DRIVE_RAMDISK, AUTOFS_SBI_MAGIC, "autofs4"},
+	{ DRIVE_REMOTE, CODA_SUPER_MAGIC, "coda" },
+	{ DRIVE_RAMDISK, CRAMFS_MAGIC, "cramfs"},
+	{ DRIVE_RAMDISK, CRAMFS_MAGIC_WEND, "cramfs"},
+	{ DRIVE_REMOTE, CIFS_MAGIC_NUMBER, "cifs"},
+	{ DRIVE_RAMDISK, DEBUGFS_MAGIC, "debugfs"},
+	{ DRIVE_RAMDISK, SYSFS_MAGIC, "sysfs"},
+	{ DRIVE_RAMDISK, SECURITYFS_MAGIC, "securityfs"},
+	{ DRIVE_RAMDISK, SELINUX_MAGIC, "selinuxfs"},
+	{ DRIVE_RAMDISK, RAMFS_MAGIC, "ramfs"},
+	{ DRIVE_FIXED, SQUASHFS_MAGIC, "squashfs"},
+	{ DRIVE_FIXED, EFS_SUPER_MAGIC, "efs"},
+	{ DRIVE_FIXED, EXT2_SUPER_MAGIC, "ext"},
+	{ DRIVE_FIXED, EXT3_SUPER_MAGIC, "ext"},
+	{ DRIVE_FIXED, EXT4_SUPER_MAGIC, "ext"},
+	{ DRIVE_REMOTE, XENFS_SUPER_MAGIC, "xenfs"},
+	{ DRIVE_FIXED, BTRFS_SUPER_MAGIC, "btrfs"},
+	{ DRIVE_FIXED, HFS_SUPER_MAGIC, "hfs"},
+	{ DRIVE_FIXED, HFSPLUS_SUPER_MAGIC, "hfsplus"},
+	{ DRIVE_FIXED, HPFS_SUPER_MAGIC, "hpfs"},
+	{ DRIVE_RAMDISK, HUGETLBFS_MAGIC, "hugetlbfs"},
+	{ DRIVE_CDROM, ISOFS_SUPER_MAGIC, "iso"},
+	{ DRIVE_FIXED, JFFS2_SUPER_MAGIC, "jffs2"},
+	{ DRIVE_RAMDISK, ANON_INODE_FS_MAGIC, "anon_inode"},
+	{ DRIVE_FIXED, JFS_SUPER_MAGIC, "jfs"},
+	{ DRIVE_FIXED, MINIX_SUPER_MAGIC, "minix"},
+	{ DRIVE_FIXED, MINIX_SUPER_MAGIC2, "minix v2"},
+	{ DRIVE_FIXED, MINIX2_SUPER_MAGIC, "minix2"},
+	{ DRIVE_FIXED, MINIX2_SUPER_MAGIC2, "minix2 v2"},
+	{ DRIVE_FIXED, MINIX3_SUPER_MAGIC, "minix3"},
+	{ DRIVE_FIXED, MSDOS_SUPER_MAGIC, "msdos"},
+	{ DRIVE_REMOTE, NCP_SUPER_MAGIC, "ncp"},
+	{ DRIVE_REMOTE, NFS_SUPER_MAGIC, "nfs"},
+	{ DRIVE_FIXED, NTFS_SB_MAGIC, "ntfs"},
+	{ DRIVE_RAMDISK, OPENPROM_SUPER_MAGIC, "openpromfs"},
+	{ DRIVE_RAMDISK, PROC_SUPER_MAGIC, "proc"},
+	{ DRIVE_FIXED, QNX4_SUPER_MAGIC, "qnx4"},
+	{ DRIVE_FIXED, REISERFS_SUPER_MAGIC, "reiserfs"},
+	{ DRIVE_RAMDISK, ROMFS_MAGIC, "romfs"},
+	{ DRIVE_REMOTE, SMB_SUPER_MAGIC, "samba"},
+	{ DRIVE_RAMDISK, CGROUP_SUPER_MAGIC, "cgroupfs"},
+	{ DRIVE_RAMDISK, FUTEXFS_SUPER_MAGIC, "futexfs"},
+	{ DRIVE_FIXED, SYSV2_SUPER_MAGIC, "sysv2"},
+	{ DRIVE_FIXED, SYSV4_SUPER_MAGIC, "sysv4"},
+	{ DRIVE_RAMDISK, TMPFS_MAGIC, "tmpfs"},
+	{ DRIVE_RAMDISK, DEVPTS_SUPER_MAGIC, "devpts"},
+	{ DRIVE_CDROM, UDF_SUPER_MAGIC, "udf"},
+	{ DRIVE_FIXED, UFS_MAGIC, "ufs"},
+	{ DRIVE_FIXED, UFS_MAGIC_BW, "ufs"},
+	{ DRIVE_FIXED, UFS2_MAGIC, "ufs2"},
+	{ DRIVE_FIXED, UFS_CIGAM, "ufs"},
+	{ DRIVE_RAMDISK, USBDEVICE_SUPER_MAGIC, "usbdev"},
+	{ DRIVE_FIXED, XENIX_SUPER_MAGIC, "xenix"},
+	{ DRIVE_FIXED, XFS_SB_MAGIC, "xfs"},
+	{ DRIVE_RAMDISK, FUSE_SUPER_MAGIC, "fuse"},
+	{ DRIVE_FIXED, V9FS_MAGIC, "9p"},
+	{ DRIVE_REMOTE, CEPH_SUPER_MAGIC, "ceph"},
+	{ DRIVE_RAMDISK, CONFIGFS_MAGIC, "configfs"},
+	{ DRIVE_RAMDISK, ECRYPTFS_SUPER_MAGIC, "eCryptfs"},
+	{ DRIVE_FIXED, EXOFS_SUPER_MAGIC, "exofs"},
+	{ DRIVE_FIXED, VXFS_SUPER_MAGIC, "vxfs"},
+	{ DRIVE_FIXED, VXFS_OLT_MAGIC, "vxfs_olt"},
+	{ DRIVE_REMOTE, GFS2_MAGIC, "gfs2"},
+	{ DRIVE_FIXED, LOGFS_MAGIC_U32, "logfs"},
+	{ DRIVE_FIXED, OCFS2_SUPER_MAGIC, "ocfs2"},
+	{ DRIVE_FIXED, OMFS_MAGIC, "omfs"},
+	{ DRIVE_FIXED, UBIFS_SUPER_MAGIC, "ubifs"},
+	{ DRIVE_UNKNOWN, 0, NULL}
 #else
 	{ DRIVE_RAMDISK, "ramfs"      },
 	{ DRIVE_RAMDISK, "tmpfs"      },
@@ -3900,10 +4266,25 @@ static _wapi_drive_type _wapi_drive_types[] = {
 	{ DRIVE_REMOTE,  "ncpfs"      },
 	{ DRIVE_REMOTE,  "coda"       },
 	{ DRIVE_REMOTE,  "afs"        },
-#endif
 	{ DRIVE_UNKNOWN, NULL         }
+#endif
 };
 
+#if __linux__
+static guint32 _wapi_get_drive_type(long f_type)
+{
+	_wapi_drive_type *current;
+
+	current = &_wapi_drive_types[0];
+	while (current->drive_type != DRIVE_UNKNOWN) {
+		if (current->fstypeid == f_type)
+			return current->drive_type;
+		current++;
+	}
+
+	return DRIVE_UNKNOWN;
+}
+#else
 static guint32 _wapi_get_drive_type(const gchar* fstype)
 {
 	_wapi_drive_type *current;
@@ -3918,8 +4299,9 @@ static guint32 _wapi_get_drive_type(const gchar* fstype)
 	
 	return current->drive_type;
 }
+#endif
 
-#if PLATFORM_MACOSX
+#if defined (PLATFORM_MACOSX) || defined (__linux__)
 static guint32
 GetDriveTypeFromPath (const char *utf8_root_path_name)
 {
@@ -3927,7 +4309,11 @@ GetDriveTypeFromPath (const char *utf8_root_path_name)
 	
 	if (statfs (utf8_root_path_name, &buf) == -1)
 		return DRIVE_UNKNOWN;
+#if PLATFORM_MACOSX
 	return _wapi_get_drive_type (buf.f_fstypename);
+#else
+	return _wapi_get_drive_type (buf.f_type);
+#endif
 }
 #else
 static guint32
@@ -4001,13 +4387,39 @@ guint32 GetDriveType(const gunichar2 *root_path_name)
 	return (drive_type);
 }
 
-/* Linux has struct statfs which has a different layout */
+static const gchar*
+get_fstypename (gchar *utfpath)
+{
+#if defined (PLATFORM_MACOSX) || defined (__linux__)
+	struct statfs stat;
+#if __linux__
+	_wapi_drive_type *current;
+#endif
+	if (statfs (utfpath, &stat) == -1)
+		return NULL;
 #if PLATFORM_MACOSX
+	return stat.f_fstypename;
+#else
+	current = &_wapi_drive_types[0];
+	while (current->drive_type != DRIVE_UNKNOWN) {
+		if (stat.f_type == current->fstypeid)
+			return current->fstype;
+		current++;
+	}
+	return NULL;
+#endif
+#else
+	return NULL;
+#endif
+}
+
+/* Linux has struct statfs which has a different layout */
+#if defined (PLATFORM_MACOSX) || defined (__linux__)
 gboolean
 GetVolumeInformation (const gunichar2 *path, gunichar2 *volumename, int volumesize, int *outserial, int *maxcomp, int *fsflags, gunichar2 *fsbuffer, int fsbuffersize)
 {
 	gchar *utfpath;
-	struct statfs stat;
+	const gchar *fstypename;
 	gboolean status = FALSE;
 	glong len;
 	
@@ -4016,8 +4428,8 @@ GetVolumeInformation (const gunichar2 *path, gunichar2 *volumename, int volumesi
 		return 0;
 	
 	utfpath = mono_unicode_to_external (path);
-	if (statfs (utfpath, &stat) != -1){
-		gunichar2 *ret = g_utf8_to_utf16 (stat.f_fstypename, -1, NULL, &len, NULL);
+	if ((fstypename = get_fstypename (utfpath)) != NULL){
+		gunichar2 *ret = g_utf8_to_utf16 (fstypename, -1, NULL, &len, NULL);
 		if (ret != NULL && len < fsbuffersize){
 			memcpy (fsbuffer, ret, len * sizeof (gunichar2));
 			fsbuffer [len] = 0;
@@ -4029,14 +4441,4 @@ GetVolumeInformation (const gunichar2 *path, gunichar2 *volumename, int volumesi
 	g_free (utfpath);
 	return status;
 }
-/* Windows has its own GetVolumeInformation */
-#elif !HOST_WIN32 
-/*
- * Linux does not this case, as the processing is done in managed code, by parsing /etc/mtab
- */
-gboolean
-GetVolumeInformation (const gunichar2 *path, gunichar2 *volumename, int volumesize, int *outserial, int *maxcomp, int *fsflags, gunichar2 *fsbuffer, int fsbuffersize)
-{
-	return FALSE;
-}
 #endif

+ 0 - 1
mono/metadata/icall.c

@@ -6628,7 +6628,6 @@ ves_icall_System_IO_DriveInfo_GetDriveFormat (MonoString *path)
 	
 	if (GetVolumeInformation (mono_string_chars (path), NULL, 0, NULL, NULL, NULL, volume_name, MAX_PATH + 1) == FALSE)
 		return NULL;
-	/* Not sure using wcslen here is safe */
 	return mono_string_from_utf16 (volume_name);
 }
 

+ 324 - 0
mono/utils/linux_magic.h

@@ -0,0 +1,324 @@
+#ifndef __LINUX_MAGIC_H
+#define __LINUX_MAGIC_H
+
+#if __linux__
+#include <linux/magic.h>
+
+#ifndef ADFS_SUPER_MAGIC
+#define ADFS_SUPER_MAGIC        0xadf5
+#endif
+
+#ifndef AFFS_SUPER_MAGIC
+#define AFFS_SUPER_MAGIC        0xadff
+#endif
+
+#ifndef AFS_SUPER_MAGIC
+#define AFS_SUPER_MAGIC         0x5346414F
+#endif
+
+#ifndef AUTOFS_SUPER_MAGIC
+#define AUTOFS_SUPER_MAGIC      0x0187
+#endif
+
+#ifndef AUTOFS_SBI_MAGIC
+#define AUTOFS_SBI_MAGIC        0x6d4a556d
+#endif
+
+#ifndef CODA_SUPER_MAGIC
+#define CODA_SUPER_MAGIC        0x73757245
+#endif
+
+#ifndef CRAMFS_MAGIC
+#define CRAMFS_MAGIC            0x28cd3d45
+#endif
+
+#ifndef CRAMFS_MAGIC_WEND
+#define CRAMFS_MAGIC_WEND       0x453dcd28
+#endif
+
+#ifndef DEBUGFS_MAGIC
+#define DEBUGFS_MAGIC          0x64626720
+#endif
+
+#ifndef SYSFS_MAGIC
+#define SYSFS_MAGIC             0x62656572
+#endif
+
+#ifndef SECURITYFS_MAGIC
+#define SECURITYFS_MAGIC        0x73636673
+#endif
+
+#ifndef SELINUX_MAGIC
+#define SELINUX_MAGIC           0xf97cff8c
+#endif
+
+#ifndef RAMFS_MAGIC
+#define RAMFS_MAGIC             0x858458f6
+#endif
+
+#ifndef TMPFS_MAGIC
+#define TMPFS_MAGIC             0x01021994
+#endif
+
+#ifndef HUGETLBFS_MAGIC
+#define HUGETLBFS_MAGIC         0x958458f6
+#endif
+
+#ifndef SQUASHFS_MAGIC
+#define SQUASHFS_MAGIC          0x73717368
+#endif
+
+#ifndef EFS_SUPER_MAGIC
+#define EFS_SUPER_MAGIC         0x414A53
+#endif
+
+#ifndef EXT2_SUPER_MAGIC
+#define EXT2_SUPER_MAGIC        0xEF53
+#endif
+
+#ifndef EXT3_SUPER_MAGIC
+#define EXT3_SUPER_MAGIC        0xEF53
+#endif
+
+#ifndef XENFS_SUPER_MAGIC
+#define XENFS_SUPER_MAGIC       0xabba1974
+#endif
+
+#ifndef EXT4_SUPER_MAGIC
+#define EXT4_SUPER_MAGIC        0xEF53
+#endif
+
+#ifndef BTRFS_SUPER_MAGIC
+#define BTRFS_SUPER_MAGIC       0x9123683E
+#endif
+
+#ifndef HPFS_SUPER_MAGIC
+#define HPFS_SUPER_MAGIC        0xf995e849
+#endif
+
+#ifndef ISOFS_SUPER_MAGIC
+#define ISOFS_SUPER_MAGIC       0x9660
+#endif
+
+#ifndef JFFS2_SUPER_MAGIC
+#define JFFS2_SUPER_MAGIC       0x72b6
+#endif
+
+#ifndef JFS_SUPER_MAGIC
+#define JFS_SUPER_MAGIC         0x3153464a
+#endif
+
+#ifndef ANON_INODE_FS_MAGIC
+#define ANON_INODE_FS_MAGIC     0x09041934
+#endif
+
+#ifndef MINIX_SUPER_MAGIC
+#define MINIX_SUPER_MAGIC       0x137F
+#endif
+
+#ifndef MINIX_SUPER_MAGIC2
+#define MINIX_SUPER_MAGIC2      0x138F
+#endif
+
+#ifndef MINIX2_SUPER_MAGIC
+#define MINIX2_SUPER_MAGIC      0x2468
+#endif
+
+#ifndef MINIX2_SUPER_MAGIC2
+#define MINIX2_SUPER_MAGIC2     0x2478
+#endif
+
+#ifndef MINIX3_SUPER_MAGIC
+#define MINIX3_SUPER_MAGIC      0x4d5a
+#endif
+
+#ifndef MSDOS_SUPER_MAGIC
+#define MSDOS_SUPER_MAGIC       0x4d44
+#endif
+
+#ifndef NCP_SUPER_MAGIC
+#define NCP_SUPER_MAGIC         0x564c
+#endif
+
+#ifndef NFS_SUPER_MAGIC
+#define NFS_SUPER_MAGIC         0x6969
+#endif
+
+#ifndef OPENPROM_SUPER_MAGIC
+#define OPENPROM_SUPER_MAGIC    0x9fa1
+#endif
+
+#ifndef PROC_SUPER_MAGIC
+#define PROC_SUPER_MAGIC        0x9fa0
+#endif
+
+#ifndef QNX4_SUPER_MAGIC
+#define QNX4_SUPER_MAGIC        0x002f
+#endif
+
+#ifndef REISERFS_SUPER_MAGIC
+#define REISERFS_SUPER_MAGIC    0x52654973
+#endif
+
+#ifndef SMB_SUPER_MAGIC
+#define SMB_SUPER_MAGIC         0x517B
+#endif
+
+#ifndef USBDEVICE_SUPER_MAGIC
+#define USBDEVICE_SUPER_MAGIC   0x9fa2
+#endif
+
+#ifndef CGROUP_SUPER_MAGIC
+#define CGROUP_SUPER_MAGIC      0x27e0eb
+#endif
+
+#ifndef FUTEXFS_SUPER_MAGIC
+#define FUTEXFS_SUPER_MAGIC     0xBAD1DEA
+#endif
+
+#ifndef DEVPTS_SUPER_MAGIC
+#define DEVPTS_SUPER_MAGIC      0x1cd1
+#endif
+
+#ifndef CIFS_MAGIC_NUMBER
+#define CIFS_MAGIC_NUMBER       0xFF534D42
+#endif
+
+#ifndef BEFS_SUPER_MAGIC1
+#define BEFS_SUPER_MAGIC1       0x42465331
+#endif
+
+#ifndef BEFS_SUPER_MAGIC2
+#define BEFS_SUPER_MAGIC2       0xdd121031
+#endif
+
+#ifndef BEFS_SUPER_MAGIC3
+#define BEFS_SUPER_MAGIC3       0x15b6830e
+#endif
+
+#ifndef BFS_MAGIC
+#define BFS_MAGIC               0x1BADFACE
+#endif
+
+#ifndef NTFS_SB_MAGIC
+#define NTFS_SB_MAGIC           0x5346544e
+#endif
+
+enum {
+        MONO_SYSV_FSTYPE_NONE = 0,
+        MONO_SYSV_FSTYPE_XENIX,
+        MONO_SYSV_FSTYPE_SYSV4,
+        MONO_SYSV_FSTYPE_SYSV2,
+        MONO_SYSV_FSTYPE_COH,
+};
+
+#ifndef SYSV_MAGIC_BASE
+#define SYSV_MAGIC_BASE         0x012FF7B3
+#endif
+
+#ifndef XENIX_SUPER_MAGIC
+#define XENIX_SUPER_MAGIC       (SYSV_MAGIC_BASE+MONO_SYSV_FSTYPE_XENIX)
+#endif
+
+#ifndef SYSV4_SUPER_MAGIC
+#define SYSV4_SUPER_MAGIC       (SYSV_MAGIC_BASE+MONO_SYSV_FSTYPE_SYSV4)
+#endif
+
+#ifndef SYSV2_SUPER_MAGIC
+#define SYSV2_SUPER_MAGIC       (SYSV_MAGIC_BASE+MONO_SYSV_FSTYPE_SYSV2)
+#endif
+
+#ifndef COH_SUPER_MAGIC
+#define COH_SUPER_MAGIC         (SYSV_MAGIC_BASE+MONO_SYSV_FSTYPE_COH)
+#endif
+
+#ifndef UFS_MAGIC
+#define UFS_MAGIC               0x00011954
+#endif
+
+#ifndef UFS_MAGIC_BW
+#define UFS_MAGIC_BW            0x0f242697
+#endif
+
+#ifndef UFS2_MAGIC
+#define UFS2_MAGIC              0x19540119
+#endif
+
+#ifndef UFS_CIGAM
+#define UFS_CIGAM               0x54190100
+#endif
+
+#ifndef UDF_SUPER_MAGIC
+#define UDF_SUPER_MAGIC         0x15013346
+#endif
+
+#ifndef XFS_SB_MAGIC
+#define XFS_SB_MAGIC            0x58465342
+#endif
+
+#ifndef FUSE_SUPER_MAGIC
+#define FUSE_SUPER_MAGIC        0x65735546
+#endif
+
+#ifndef V9FS_MAGIC
+#define V9FS_MAGIC              0x01021997
+#endif
+
+#ifndef CEPH_SUPER_MAGIC
+#define CEPH_SUPER_MAGIC        0x00c36400
+#endif
+
+#ifndef CONFIGFS_MAGIC
+#define CONFIGFS_MAGIC          0x62656570
+#endif
+
+#ifndef ECRYPTFS_SUPER_MAGIC
+#define ECRYPTFS_SUPER_MAGIC    0xf15f
+#endif
+
+#ifndef EXOFS_SUPER_MAGIC
+#define EXOFS_SUPER_MAGIC       0x5df5
+#endif
+
+#ifndef VXFS_SUPER_MAGIC
+#define VXFS_SUPER_MAGIC        0xa501fcf5
+#endif
+
+#ifndef VXFS_OLT_MAGIC
+#define VXFS_OLT_MAGIC          0xa504fcf5
+#endif
+
+#ifndef GFS2_MAGIC
+#define GFS2_MAGIC              0x01161970
+#endif
+
+#ifndef HFS_SUPER_MAGIC
+#define HFS_SUPER_MAGIC         0x4244
+#endif
+
+#ifndef HFSPLUS_SUPER_MAGIC
+#define HFSPLUS_SUPER_MAGIC     0x482b
+#endif
+
+#ifndef LOGFS_MAGIC_U32
+#define LOGFS_MAGIC_U32         0xc97e8168
+#endif
+
+#ifndef OCFS2_SUPER_MAGIC
+#define OCFS2_SUPER_MAGIC       0x7461636f
+#endif
+
+#ifndef OMFS_MAGIC
+#define OMFS_MAGIC              0xc2993d87
+#endif
+
+#ifndef UBIFS_SUPER_MAGIC
+#define UBIFS_SUPER_MAGIC       0x24051905
+#endif
+
+#ifndef ROMFS_MAGIC
+#define ROMFS_MAGIC             0x7275
+#endif
+
+#endif
+#endif