Implement GetLogicalDrives for Unix
authorJeremy Kuhne <jeremy.kuhne@microsoft.com>
Wed, 29 Jun 2016 05:27:39 +0000 (22:27 -0700)
committerJeremy Kuhne <jeremy.kuhne@microsoft.com>
Thu, 30 Jun 2016 20:49:53 +0000 (13:49 -0700)
Implement and unify code for getting drives/mount points

Commit migrated from https://github.com/dotnet/corefx/commit/20ddbef76e857901e9c2baac1c0723cf9951324a

17 files changed:
src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs [new file with mode: 0644]
src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs
src/libraries/Common/src/System/IO/DriveInfoInternal.Unix.cs [new file with mode: 0644]
src/libraries/Common/src/System/IO/DriveInfoInternal.Win32.cs [moved from src/libraries/System.IO.FileSystem/src/System/IO/Directory.Win32.cs with 67% similarity]
src/libraries/Common/src/System/IO/DriveInfoInternal.WinRT.cs [new file with mode: 0644]
src/libraries/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj
src/libraries/System.IO.FileSystem.DriveInfo/src/System/IO/DriveInfo.Windows.cs
src/libraries/System.IO.FileSystem/src/System.IO.FileSystem.csproj
src/libraries/System.IO.FileSystem/src/System/IO/Directory.Unix.cs [deleted file]
src/libraries/System.IO.FileSystem/src/System/IO/Directory.WinRT.cs [deleted file]
src/libraries/System.IO.FileSystem/src/System/IO/Directory.cs
src/libraries/System.IO.FileSystem/src/System/IO/FileSystem.cs
src/libraries/System.IO.FileSystem/src/System/IO/MultiplexingWin32WinRTFileSystem.cs
src/libraries/System.IO.FileSystem/src/System/IO/UnixFileSystem.cs
src/libraries/System.IO.FileSystem/src/System/IO/Win32FileSystem.cs
src/libraries/System.IO.FileSystem/src/System/IO/WinRTFileSystem.cs
src/libraries/System.IO.FileSystem/tests/Directory/GetLogicalDrives.cs

diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs
new file mode 100644 (file)
index 0000000..3a0a829
--- /dev/null
@@ -0,0 +1,281 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+internal static partial class Interop
+{
+    internal static partial class Sys
+    {
+        private const int MountPointFormatBufferSizeInBytes = 32;
+
+        /// <summary>
+        /// Internal FileSystem names and magic numbers taken from man(2) statfs
+        /// </summary>
+        /// <remarks>
+        /// These value names MUST be kept in sync with those in GetDriveType below
+        /// </remarks>
+        internal enum UnixFileSystemTypes : long
+        {
+            adfs = 0xadf5,
+            affs = 0xADFF,
+            befs = 0x42465331,
+            bfs = 0x1BADFACE,
+            cifs = 0xFF534D42,
+            coda = 0x73757245,
+            coherent = 0x012FF7B7,
+            cramfs = 0x28cd3d45,
+            devfs = 0x1373,
+            efs = 0x00414A53,
+            ext = 0x137D,
+            ext2_old = 0xEF51,
+            ext2 = 0xEF53,
+            ext3 = 0xEF53,
+            ext4 = 0xEF53,
+            hfs = 0x4244,
+            hpfs = 0xF995E849,
+            hugetlbfs = 0x958458f6,
+            isofs = 0x9660,
+            jffs2 = 0x72b6,
+            jfs = 0x3153464a,
+            minix_old = 0x137F, /* orig. minix */
+            minix = 0x138F, /* 30 char minix */
+            minix2 = 0x2468, /* minix V2 */
+            minix2v2 = 0x2478, /* minix V2, 30 char names */
+            msdos = 0x4d44,
+            ncpfs = 0x564c,
+            nfs = 0x6969,
+            ntfs = 0x5346544e,
+            openprom = 0x9fa1,
+            proc = 0x9fa0,
+            qnx4 = 0x002f,
+            reiserfs = 0x52654973,
+            romfs = 0x7275,
+            smb = 0x517B,
+            sysv2 = 0x012FF7B6,
+            sysv4 = 0x012FF7B5,
+            tmpfs = 0x01021994,
+            udf = 0x15013346,
+            ufs = 0x00011954,
+            usbdevice = 0x9fa2,
+            vxfs = 0xa501FCF5,
+            xenix = 0x012FF7B4,
+            xfs = 0x58465342,
+            xiafs = 0x012FD16D,
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        internal struct MountPointInformation
+        {
+            internal ulong AvailableFreeSpace;
+            internal ulong TotalFreeSpace;
+            internal ulong TotalSize;
+        }
+
+        [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetSpaceInfoForMountPoint", SetLastError = true)]
+        internal static extern int GetSpaceInfoForMountPoint([MarshalAs(UnmanagedType.LPStr)]string name, out MountPointInformation mpi);
+
+        [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetFormatInfoForMountPoint", SetLastError = true)]
+        private unsafe static extern int GetFormatInfoForMountPoint(
+            [MarshalAs(UnmanagedType.LPStr)]string name,
+            byte* formatNameBuffer,
+            int bufferLength,
+            long* formatType);
+
+        internal static int GetFormatInfoForMountPoint(string name, out string format)
+        {
+            DriveType temp;
+            return GetFormatInfoForMountPoint(name, out format, out temp);
+        }
+
+        internal static int GetFormatInfoForMountPoint(string name, out DriveType type)
+        {
+            string temp;
+            return GetFormatInfoForMountPoint(name, out temp, out type);
+        }
+
+        private static int GetFormatInfoForMountPoint(string name, out string format, out DriveType type)
+        {
+            unsafe
+            {
+                byte* formatBuffer = stackalloc byte[MountPointFormatBufferSizeInBytes];    // format names should be small
+                long numericFormat;
+                int result = GetFormatInfoForMountPoint(name, formatBuffer, MountPointFormatBufferSizeInBytes, &numericFormat);
+                if (result == 0)
+                {
+                    // Check if we have a numeric answer or string
+                    format = numericFormat != -1 ?
+                        Enum.GetName(typeof(UnixFileSystemTypes), numericFormat) :
+                        Marshal.PtrToStringAnsi((IntPtr)formatBuffer);
+                    type = GetDriveType(format);
+                }
+                else
+                {
+                    format = string.Empty;
+                    type = DriveType.Unknown;
+                }
+
+                return result;
+            }
+        }
+
+        /// <summary>Categorizes a file system name into a drive type.</summary>
+        /// <param name="fileSystemName">The name to categorize.</param>
+        /// <returns>The recognized drive type.</returns>
+        private static DriveType GetDriveType(string fileSystemName)
+        {
+            // This list is based primarily on "man fs", "man mount", "mntent.h", "/proc/filesystems",
+            // and "wiki.debian.org/FileSystem". It can be extended over time as we 
+            // find additional file systems that should be recognized as a particular drive type.
+            switch (fileSystemName)
+            {
+                case "iso":
+                case "isofs":
+                case "iso9660":
+                case "fuseiso":
+                case "fuseiso9660":
+                case "umview-mod-umfuseiso9660":
+                    return DriveType.CDRom;
+
+                case "adfs":
+                case "affs":
+                case "befs":
+                case "bfs":
+                case "btrfs":
+                case "ecryptfs":
+                case "efs":
+                case "ext":
+                case "ext2":
+                case "ext2_old":
+                case "ext3":
+                case "ext4":
+                case "ext4dev":
+                case "fat":
+                case "fuseblk":
+                case "fuseext2":
+                case "fusefat":
+                case "hfs":
+                case "hfsplus":
+                case "hpfs":
+                case "jbd":
+                case "jbd2":
+                case "jfs":
+                case "jffs":
+                case "jffs2":
+                case "minix":
+                case "minix_old":
+                case "minix2":
+                case "minix2v2":
+                case "msdos":
+                case "ocfs2":
+                case "omfs":
+                case "openprom":
+                case "ntfs":
+                case "qnx4":
+                case "reiserfs":
+                case "squashfs":
+                case "swap":
+                case "sysv":
+                case "ubifs":
+                case "udf":
+                case "ufs":
+                case "umsdos":
+                case "umview-mod-umfuseext2":
+                case "xenix":
+                case "xfs":
+                case "xiafs":
+                case "xmount":
+                case "zfs-fuse":
+                    return DriveType.Fixed;
+
+                case "9p":
+                case "autofs":
+                case "autofs4":
+                case "beaglefs":
+                case "cifs":
+                case "coda":
+                case "coherent":
+                case "curlftpfs":
+                case "davfs2":
+                case "dlm":
+                case "flickrfs":
+                case "fusedav":
+                case "fusesmb":
+                case "gfs2":
+                case "glusterfs-client":
+                case "gmailfs":
+                case "kafs":
+                case "ltspfs":
+                case "ncpfs":
+                case "nfs":
+                case "nfs4":
+                case "obexfs":
+                case "s3ql":
+                case "smb":
+                case "smbfs":
+                case "sshfs":
+                case "sysfs":
+                case "sysv2":
+                case "sysv4":
+                case "vxfs":
+                case "wikipediafs":
+                    return DriveType.Network;
+
+                case "anon_inodefs":
+                case "aptfs":
+                case "avfs":
+                case "bdev":
+                case "binfmt_misc":
+                case "cgroup":
+                case "configfs":
+                case "cramfs":
+                case "cryptkeeper":
+                case "cpuset":
+                case "debugfs":
+                case "devfs":
+                case "devpts":
+                case "devtmpfs":
+                case "encfs":
+                case "fuse":
+                case "fuse.gvfsd-fuse":
+                case "fusectl":
+                case "hugetlbfs":
+                case "libpam-encfs":
+                case "ibpam-mount":
+                case "mtpfs":
+                case "mythtvfs":
+                case "mqueue":
+                case "pipefs":
+                case "plptools":
+                case "proc":
+                case "pstore":
+                case "pytagsfs":
+                case "ramfs":
+                case "rofs":
+                case "romfs":
+                case "rootfs":
+                case "securityfs":
+                case "sockfs":
+                case "tmpfs":
+                    return DriveType.Ram;
+
+                case "gphotofs":
+                case "usbfs":
+                case "usbdevice":
+                case "vfat":
+                    return DriveType.Removable;
+
+                case "aufs": // marking all unions as unknown
+                case "funionfs":
+                case "unionfs-fuse":
+                case "mhddfs":
+                default:
+                    return DriveType.Unknown;
+            }
+        }
+    }
+}
index 448250f..4e6552c 100644 (file)
@@ -3,7 +3,6 @@
 // See the LICENSE file in the project root for more information.
 
 using System;
-using System.IO;
 using System.Collections.Generic;
 using System.Runtime.InteropServices;
 
@@ -11,124 +10,12 @@ internal static partial class Interop
 {
     internal static partial class Sys
     {
-        private const int MountPointFormatBufferSizeInBytes = 32;
-
-        /// <summary>
-        /// Internal FileSystem names and magic numbers taken from man(2) statfs
-        /// </summary>
-        /// <remarks>
-        /// These value names MUST be kept in sync with those in GetDriveType below
-        /// </remarks>
-        internal enum UnixFileSystemTypes : long
-        {
-            adfs = 0xadf5,
-            affs = 0xADFF,
-            befs = 0x42465331,
-            bfs = 0x1BADFACE,
-            cifs = 0xFF534D42,
-            coda = 0x73757245,
-            coherent = 0x012FF7B7,
-            cramfs = 0x28cd3d45,
-            devfs = 0x1373,
-            efs = 0x00414A53,
-            ext = 0x137D,
-            ext2_old = 0xEF51,
-            ext2 = 0xEF53,
-            ext3 = 0xEF53,
-            ext4 = 0xEF53,
-            hfs = 0x4244,
-            hpfs = 0xF995E849,
-            hugetlbfs = 0x958458f6,
-            isofs = 0x9660,
-            jffs2 = 0x72b6,
-            jfs = 0x3153464a,
-            minix_old = 0x137F, /* orig. minix */
-            minix = 0x138F, /* 30 char minix */
-            minix2 = 0x2468, /* minix V2 */
-            minix2v2 = 0x2478, /* minix V2, 30 char names */
-            msdos = 0x4d44,
-            ncpfs = 0x564c,
-            nfs = 0x6969,
-            ntfs = 0x5346544e,
-            openprom = 0x9fa1,
-            proc = 0x9fa0,
-            qnx4 = 0x002f,
-            reiserfs = 0x52654973,
-            romfs = 0x7275,
-            smb = 0x517B,
-            sysv2 = 0x012FF7B6,
-            sysv4 = 0x012FF7B5,
-            tmpfs = 0x01021994,
-            udf = 0x15013346,
-            ufs = 0x00011954,
-            usbdevice = 0x9fa2,
-            vxfs = 0xa501FCF5,
-            xenix = 0x012FF7B4,
-            xfs = 0x58465342,
-            xiafs = 0x012FD16D,
-        }
-
-        [StructLayout(LayoutKind.Sequential)]
-        internal struct MountPointInformation
-        {
-            internal ulong AvailableFreeSpace;
-            internal ulong TotalFreeSpace;
-            internal ulong TotalSize;
-        }
-
         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
         private unsafe delegate void MountPointFound(byte* name);
 
         [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetAllMountPoints", SetLastError = true)]
         private static extern int GetAllMountPoints(MountPointFound mpf);
 
-        [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetSpaceInfoForMountPoint", SetLastError = true)]
-        internal static extern int GetSpaceInfoForMountPoint([MarshalAs(UnmanagedType.LPStr)]string name, out MountPointInformation mpi);
-
-        [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetFormatInfoForMountPoint", SetLastError = true)]
-        private unsafe static extern int GetFormatInfoForMountPoint(
-            [MarshalAs(UnmanagedType.LPStr)]string name,
-            byte* formatNameBuffer,
-            int bufferLength,
-            long* formatType);
-
-        internal static int GetFormatInfoForMountPoint(string name, out string format)
-        {
-            DriveType temp;
-            return GetFormatInfoForMountPoint(name, out format, out temp);
-        }
-
-        internal static int GetFormatInfoForMountPoint(string name, out DriveType type)
-        {
-            string temp;
-            return GetFormatInfoForMountPoint(name, out temp, out type);
-        }
-
-        private static int GetFormatInfoForMountPoint(string name, out string format, out DriveType type)
-        {
-            unsafe
-            {
-                byte* formatBuffer = stackalloc byte[MountPointFormatBufferSizeInBytes];    // format names should be small
-                long numericFormat;
-                int result = GetFormatInfoForMountPoint(name, formatBuffer, MountPointFormatBufferSizeInBytes, &numericFormat);
-                if (result == 0)
-                {
-                    // Check if we have a numeric answer or string
-                    format = numericFormat != -1 ?
-                        Enum.GetName(typeof(UnixFileSystemTypes), numericFormat) :
-                        Marshal.PtrToStringAnsi((IntPtr)formatBuffer);
-                    type = GetDriveType(format);
-                }
-                else
-                {
-                    format = string.Empty;
-                    type = DriveType.Unknown;
-                }
-
-                return result;
-            }
-        }
-
         internal static List<string> GetAllMountPoints()
         {
             List<string> lst = new List<string>();
@@ -142,160 +29,5 @@ internal static partial class Interop
 
             return lst;
         }
-
-        /// <summary>Categorizes a file system name into a drive type.</summary>
-        /// <param name="fileSystemName">The name to categorize.</param>
-        /// <returns>The recognized drive type.</returns>
-        private static DriveType GetDriveType(string fileSystemName)
-        {
-            // This list is based primarily on "man fs", "man mount", "mntent.h", "/proc/filesystems",
-            // and "wiki.debian.org/FileSystem". It can be extended over time as we 
-            // find additional file systems that should be recognized as a particular drive type.
-            switch (fileSystemName)
-            {
-                case "iso":
-                case "isofs":
-                case "iso9660":
-                case "fuseiso":
-                case "fuseiso9660":
-                case "umview-mod-umfuseiso9660":
-                    return DriveType.CDRom;
-
-                case "adfs":
-                case "affs":
-                case "befs":
-                case "bfs":
-                case "btrfs":
-                case "ecryptfs":
-                case "efs":
-                case "ext":
-                case "ext2":
-                case "ext2_old":
-                case "ext3":
-                case "ext4":
-                case "ext4dev":
-                case "fat":
-                case "fuseblk":
-                case "fuseext2":
-                case "fusefat":
-                case "hfs":
-                case "hfsplus":
-                case "hpfs":
-                case "jbd":
-                case "jbd2":
-                case "jfs":
-                case "jffs":
-                case "jffs2":
-                case "minix":
-                case "minix_old":
-                case "minix2":
-                case "minix2v2":
-                case "msdos":
-                case "ocfs2":
-                case "omfs":
-                case "openprom":
-                case "ntfs":
-                case "qnx4":
-                case "reiserfs":
-                case "squashfs":
-                case "swap":
-                case "sysv":
-                case "ubifs":
-                case "udf":
-                case "ufs":
-                case "umsdos":
-                case "umview-mod-umfuseext2":
-                case "xenix":
-                case "xfs":
-                case "xiafs":
-                case "xmount":
-                case "zfs-fuse":
-                    return DriveType.Fixed;
-
-                case "9p":
-                case "autofs":
-                case "autofs4":
-                case "beaglefs":
-                case "cifs":
-                case "coda":
-                case "coherent":
-                case "curlftpfs":
-                case "davfs2":
-                case "dlm":
-                case "flickrfs":
-                case "fusedav":
-                case "fusesmb":
-                case "gfs2":
-                case "glusterfs-client":
-                case "gmailfs":
-                case "kafs":
-                case "ltspfs":
-                case "ncpfs":
-                case "nfs":
-                case "nfs4":
-                case "obexfs":
-                case "s3ql":
-                case "smb":
-                case "smbfs":
-                case "sshfs":
-                case "sysfs":
-                case "sysv2":
-                case "sysv4":
-                case "vxfs":
-                case "wikipediafs":
-                    return DriveType.Network;
-
-                case "anon_inodefs":
-                case "aptfs":
-                case "avfs":
-                case "bdev":
-                case "binfmt_misc":
-                case "cgroup":
-                case "configfs":
-                case "cramfs":
-                case "cryptkeeper":
-                case "cpuset":
-                case "debugfs":
-                case "devfs":
-                case "devpts":
-                case "devtmpfs":
-                case "encfs":
-                case "fuse":
-                case "fuse.gvfsd-fuse":
-                case "fusectl":
-                case "hugetlbfs":
-                case "libpam-encfs":
-                case "ibpam-mount":
-                case "mtpfs":
-                case "mythtvfs":
-                case "mqueue":
-                case "pipefs":
-                case "plptools":
-                case "proc":
-                case "pstore":
-                case "pytagsfs":
-                case "ramfs":
-                case "rofs":
-                case "romfs":
-                case "rootfs":
-                case "securityfs":
-                case "sockfs":
-                case "tmpfs":
-                    return DriveType.Ram;
-
-                case "gphotofs":
-                case "usbfs":
-                case "usbdevice":
-                case "vfat":
-                    return DriveType.Removable;
-
-                case "aufs": // marking all unions as unknown
-                case "funionfs":
-                case "unionfs-fuse":
-                case "mhddfs":
-                default:
-                    return DriveType.Unknown;
-            }
-        }
     }
 }
diff --git a/src/libraries/Common/src/System/IO/DriveInfoInternal.Unix.cs b/src/libraries/Common/src/System/IO/DriveInfoInternal.Unix.cs
new file mode 100644 (file)
index 0000000..cdeb762
--- /dev/null
@@ -0,0 +1,18 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Text;
+
+namespace System.IO
+{
+    /// <summary>Contains internal volume helpers that are shared between many projects.</summary>
+    internal static partial class DriveInfoInternal
+    {
+        internal static string[] GetLogicalDrives()
+        {
+            return Interop.Sys.GetAllMountPoints().ToArray();
+        }
+    }
+}
@@ -1,10 +1,14 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Diagnostics;
+using System.Text;
+
 namespace System.IO
 {
-    public static partial class Directory
+    /// <summary>Contains internal volume helpers that are shared between many projects.</summary>
+    internal static partial class DriveInfoInternal
     {
         public static string[] GetLogicalDrives()
         {
@@ -12,6 +16,11 @@ namespace System.IO
             if (drives == 0)
                 throw Win32Marshal.GetExceptionForLastWin32Error();
 
+            // GetLogicalDrives returns a bitmask starting from 
+            // position 0 "A" indicating whether a drive is present.
+            // Loop over each bit, creating a string for each one
+            // that is set.
+
             uint d = (uint)drives;
             int count = 0;
             while (d != 0)
@@ -19,6 +28,7 @@ namespace System.IO
                 if (((int)d & 1) != 0) count++;
                 d >>= 1;
             }
+
             string[] result = new string[count];
             char[] root = new char[] { 'A', ':', '\\' };
             d = (uint)drives;
diff --git a/src/libraries/Common/src/System/IO/DriveInfoInternal.WinRT.cs b/src/libraries/Common/src/System/IO/DriveInfoInternal.WinRT.cs
new file mode 100644 (file)
index 0000000..93460b8
--- /dev/null
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Text;
+
+namespace System.IO
+{
+    /// <summary>Contains internal volume helpers that are shared between many projects.</summary>
+    internal static partial class DriveInfoInternal
+    {
+        internal static string[] GetLogicalDrives()
+        {
+            // Getting volume information isn't supported on WinRT
+            throw new PlatformNotSupportedException();
+        }
+    }
+}
index c1110ba..aafb9de 100644 (file)
@@ -74,6 +74,9 @@
     <Compile Include="$(CommonPath)\System\IO\Win32Marshal.cs">
       <Link>Common\System\IO\Win32Marshal.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)\System\IO\DriveInfoInternal.Win32.cs">
+      <Link>Common\System\IO\DriveInfoInternal.Win32.cs</Link>
+    </Compile>
     <Compile Include="$(CommonPath)\System\IO\PathInternal.Windows.cs">
       <Link>Common\System\IO\PathInternal.Windows.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.MountPoints.cs">
       <Link>Common\Interop\Unix\Interop.MountPoints.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.MountPoints.FormatInfo.cs">
+      <Link>Common\Interop\Unix\Interop.MountPoints.FormatInfo.cs</Link>
+    </Compile>
   </ItemGroup>
   <ItemGroup Condition="'$(TargetGroup)' == 'net46'">
     <TargetingPackReference Include="mscorlib" />
index 84aa4ba..d77317a 100644 (file)
@@ -152,35 +152,11 @@ namespace System.IO
 
         public static DriveInfo[] GetDrives()
         {
-            int drives = Interop.mincore.GetLogicalDrives();
-            if (drives == 0)
-                throw Win32Marshal.GetExceptionForLastWin32Error();
-
-            // GetLogicalDrives returns a bitmask starting from 
-            // position 0 "A" indicating whether a drive is present.
-            // Loop over each bit, creating a DriveInfo for each one
-            // that is set.
-
-            uint d = (uint)drives;
-            int count = 0;
-            while (d != 0)
+            string[] drives = DriveInfoInternal.GetLogicalDrives();
+            DriveInfo[] result = new DriveInfo[drives.Length];
+            for (int i = 0; i < drives.Length; i++)
             {
-                if (((int)d & 1) != 0) count++;
-                d >>= 1;
-            }
-
-            DriveInfo[] result = new DriveInfo[count];
-            char[] root = new char[] { 'A', ':', '\\' };
-            d = (uint)drives;
-            count = 0;
-            while (d != 0)
-            {
-                if (((int)d & 1) != 0)
-                {
-                    result[count++] = new DriveInfo(new String(root));
-                }
-                d >>= 1;
-                root[0]++;
+                result[i] = new DriveInfo(drives[i]);
             }
             return result;
         }
index 5d2bed6..fedf64b 100644 (file)
     <Compile Include="$(CommonPath)\Interop\Windows\mincore\Interop.GetLogicalDrive.cs">
       <Link>Common\Interop\Windows\Interop.GetLogicalDrive.cs</Link>
     </Compile>
-    <Compile Include="System\IO\Directory.Win32.cs" />
+    <Compile Include="$(CommonPath)\System\IO\DriveInfoInternal.Win32.cs">
+      <Link>Common\System\IO\DriveInfoInternal.Win32.cs</Link>
+    </Compile>
     <Compile Include="System\IO\FileSystem.Current.Win32.cs" />
     <Compile Include="System\IO\FileSystemInfo.Win32.cs" />
     <Compile Include="$(CommonPath)\Interop\Windows\mincore\Interop.CreateFile.cs">
     <Compile Include="$(CommonPath)\Interop\Windows\mincore\WinRT\Interop.SetErrorMode.cs">
       <Link>Common\Interop\Windows\WinRT\Interop.SetErrorMode.cs</Link>
     </Compile>
-    <Compile Include="System\IO\Directory.WinRT.cs" />
+    <Compile Include="$(CommonPath)\System\IO\DriveInfoInternal.WinRT.cs">
+      <Link>Common\System\IO\DriveInfoInternal.WinRT.cs</Link>
+    </Compile>
     <Compile Include="System\IO\FileSystem.Current.MuxWin32WinRT.cs" />
     <Compile Include="System\IO\FileSystemInfo.WinRT.cs" />
     <Compile Include="System\IO\MultiplexingWin32WinRTFileSystem.cs" />
   <!-- Unix -->
   <ItemGroup Condition="'$(TargetsUnix)' == 'true'">
     <Compile Include="Microsoft\Win32\SafeHandles\SafeFileHandle.Unix.cs" />
-    <Compile Include="System\IO\Directory.Unix.cs" />
     <Compile Include="System\IO\FileStream.Unix.cs" />
     <Compile Include="System\IO\FileSystem.Current.Unix.cs" />
     <Compile Include="System\IO\FileSystemInfo.Unix.cs" />
     <Compile Include="System\IO\PathHelpers.Unix.cs" />
     <Compile Include="System\IO\UnixFileStream.cs" />
     <Compile Include="System\IO\UnixFileSystem.cs" />
-    <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeFileHandle.Unix.cs">
-      <Link>Common\Microsoft\Win32\SafeHandles\SafeFileHandle.Unix.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\Interop\Unix\Interop.Libraries.cs">
       <Link>Common\Interop\Unix\Interop.Libraries.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Stat.cs">
       <Link>Common\Interop\Unix\Interop.Stat.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\IO\PathInternal.Unix.cs">
-      <Link>Common\System\IO\PathInternal.Unix.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.ReadDir.cs">
       <Link>Common\Interop\Unix\Interop.ReadDir.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.Link.cs">
       <Link>Common\Interop\Unix\Interop.Link.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.MountPoints.cs">
+      <Link>Common\Interop\Unix\Interop.MountPoints.cs</Link>
+    </Compile>
     <Compile Include="$(CommonPath)\Interop\Unix\System.Native\Interop.PosixFAdvise.cs">
       <Link>Common\Interop\Unix\Interop.PosixFAdvise.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeDirectoryHandle.Unix.cs">
       <Link>Common\Microsoft\Win32\SafeHandles\SafeDirectoryHandle.Unix.cs</Link>
     </Compile>
+    <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeFileHandle.Unix.cs">
+      <Link>Common\Microsoft\Win32\SafeHandles\SafeFileHandle.Unix.cs</Link>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\IO\PathInternal.Unix.cs">
+      <Link>Common\System\IO\PathInternal.Unix.cs</Link>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\IO\DriveInfoInternal.Unix.cs">
+      <Link>Common\System\IO\DriveInfoInternal.Unix.cs</Link>
+    </Compile>
   </ItemGroup>
   <ItemGroup Condition="'$(TargetGroup)' == 'net46'">
     <TargetingPackReference Include="mscorlib" />
diff --git a/src/libraries/System.IO.FileSystem/src/System/IO/Directory.Unix.cs b/src/libraries/System.IO.FileSystem/src/System/IO/Directory.Unix.cs
deleted file mode 100644 (file)
index f387838..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.IO
-{
-    public static partial class Directory
-    {
-        public static string[] GetLogicalDrives()
-        {
-            throw new PlatformNotSupportedException();
-        }
-    }
-}
diff --git a/src/libraries/System.IO.FileSystem/src/System/IO/Directory.WinRT.cs b/src/libraries/System.IO.FileSystem/src/System/IO/Directory.WinRT.cs
deleted file mode 100644 (file)
index f387838..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-namespace System.IO
-{
-    public static partial class Directory
-    {
-        public static string[] GetLogicalDrives()
-        {
-            throw new PlatformNotSupportedException();
-        }
-    }
-}
index 2eac0f1..7cbcc4c 100644 (file)
@@ -579,6 +579,11 @@ namespace System.IO
             String fullPath = Path.GetFullPath(path);
             FileSystem.Current.RemoveDirectory(fullPath, recursive);
         }
+
+        public static string[] GetLogicalDrives()
+        {
+            return FileSystem.Current.GetLogicalDrives();
+        }
     }
 }
 
index 8724811..8a651bd 100644 (file)
@@ -43,5 +43,8 @@ namespace System.IO
         public abstract void SetCurrentDirectory(string fullPath);
         public abstract int MaxPath { get; }
         public abstract int MaxDirectoryPath { get; }
+
+        // Volume
+        public abstract string[] GetLogicalDrives();
     }
 }
index 48dacc0..526338e 100644 (file)
@@ -149,6 +149,12 @@ namespace System.IO
             return (ShouldUseWinRT(sourceFullPath, isCreate: false) || ShouldUseWinRT(destFullPath, isCreate: true)) ? _winRTFileSystem : _win32FileSystem;
         }
 
+        public override string[] GetLogicalDrives()
+        {
+            // This API is always blocked on WinRT, don't use Win32
+            return _winRTFileSystem.GetLogicalDrives();
+        }
+
         private static bool ShouldUseWinRT(string fullPath, bool isCreate)
         {
             // The purpose of this method is to determine if we can access a path
index f404f4c..8e55d3b 100644 (file)
@@ -653,5 +653,10 @@ namespace System.IO
                 (IFileSystemObject)new DirectoryInfo(fullPath, null) :
                 (IFileSystemObject)new FileInfo(fullPath, null);
         }
+
+        public override string[] GetLogicalDrives()
+        {
+            return DriveInfoInternal.GetLogicalDrives();
+        }
     }
 }
index b2004b0..5954202 100644 (file)
@@ -729,5 +729,10 @@ namespace System.IO
                 }
             }
         }
+
+        public override string[] GetLogicalDrives()
+        {
+            return DriveInfoInternal.GetLogicalDrives();
+        }
     }
 }
index 076f5a9..c12361d 100644 (file)
@@ -725,6 +725,11 @@ namespace System.IO
             // "System.DateModified" property is readonly
         }
 
+        public override string[] GetLogicalDrives()
+        {
+            return DriveInfoInternal.GetLogicalDrives();
+        }
+
         #region Task Utility
         private static void EnsureBackgroundThread()
         {
index 67eeab6..8e68ccb 100644 (file)
@@ -12,9 +12,12 @@ namespace System.IO.Tests
     {
         [Fact]
         [PlatformSpecific(PlatformID.AnyUnix)]
-        public void ThrowsPlatformNotSupported_Unix()
+        public void GetsValidDriveStrings_Unix()
         {
-            Assert.Throws<PlatformNotSupportedException>(() => Directory.GetLogicalDrives());
+            string[] drives = Directory.GetLogicalDrives();
+            Assert.NotEmpty(drives);
+            Assert.All(drives, d => Assert.NotNull(d));
+            Assert.Contains(drives, d => d == "/");
         }
 
         [Fact]