1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.IO;
7 using System.Collections.Generic;
8 using System.Runtime.InteropServices;
9 
10 internal static partial class Interop
11 {
12     internal static partial class Sys
13     {
14         private const int MountPointFormatBufferSizeInBytes = 32;
15 
16         /// <summary>
17         /// Internal FileSystem names and magic numbers taken from man(2) statfs
18         /// </summary>
19         /// <remarks>
20         /// These value names MUST be kept in sync with those in GetDriveType below
21         /// </remarks>
22         internal enum UnixFileSystemTypes : long
23         {
24             adfs = 0xADF5,
25             affs = 0xADFF,
26             afs = 0x5346414F,
27             anoninode = 0x09041934,
28             aufs = 0x61756673,
29             autofs = 0x0187,
30             befs = 0x42465331,
31             bdevfs = 0x62646576,
32             bfs = 0x1BADFACE,
33             binfmt_misc = 0x42494E4D,
34             btrfs = 0x9123683E,
35             ceph = 0x00C36400,
36             cgroupfs = 0x0027E0EB,
37             cifs = 0xFF534D42,
38             coda = 0x73757245,
39             coherent = 0x012FF7B7,
40             cramfs = 0x28CD3D45,
41             debugfs = 0x64626720,
42             devfs = 0x1373,
43             devpts = 0x1CD1,
44             ecryptfs = 0xF15F,
45             efs = 0x00414A53,
46             ext = 0x137D,
47             ext2_old = 0xEF51,
48             ext2 = 0xEF53,
49             ext3 = 0xEF53,
50             ext4 = 0xEF53,
51             fat = 0x4006,
52             fhgfs = 0x19830326,
53             fuseblk = 0x65735546,
54             fusectl = 0x65735543,
55             futexfs = 0x0BAD1DEA,
56             gfsgfs2 = 0x1161970,
57             gpfs = 0x47504653,
58             hfs = 0x4244,
59             hpfs = 0xF995E849,
60             hugetlbfs = 0x958458F6,
61             inodefs = 0x11307854,
62             inotifyfs = 0x2BAD1DEA,
63             isofs = 0x9660,
64             // isofs = 0x4004, // R_WIN
65             // isofs = 0x4000, // WIN
66             jffs = 0x07C0,
67             jffs2 = 0x72B6,
68             jfs = 0x3153464A,
69             kafs = 0x6B414653,
70             lustre = 0x0BD00BD0,
71             minix_old = 0x137F, /* orig. minix */
72             minix = 0x138F, /* 30 char minix */
73             minix2 = 0x2468, /* minix V2 */
74             minix2v2 = 0x2478, /* MINIX V2, 30 char names */
75             minix3 = 0x4D5A,
76             mqueue = 0x19800202,
77             msdos = 0x4D44,
78             nfs = 0x6969,
79             nfsd = 0x6E667364,
80             nilfs = 0x3434,
81             novell = 0x564C,
82             ntfs = 0x5346544E,
83             openprom = 0x9FA1,
84             ocfs2 = 0x7461636F,
85             overlay = 0x794C7630,
86             overlayfs = 0x794C764F,
87             panfs = 0xAAD7AAEA,
88             pipefs = 0x50495045,
89             proc = 0x9FA0,
90             pstorefs = 0x6165676C,
91             qnx4 = 0x002F,
92             qnx6 = 0x68191122,
93             ramfs = 0x858458F6,
94             reiserfs = 0x52654973,
95             romfs = 0x7275,
96             rpc_pipefs = 0x67596969,
97             securityfs = 0x73636673,
98             selinux = 0xF97CFF8C,
99             smb = 0x517B,
100             sockfs = 0x534F434B,
101             squashfs = 0x73717368,
102             sysfs = 0x62656572,
103             sysv2 = 0x012FF7B6,
104             sysv4 = 0x012FF7B5,
105             tmpfs = 0x01021994,
106             udf = 0x15013346,
107             ufs = 0x00011954,
108             // ufs = 0x54190100, // byteswapped
109             usbdevice = 0x9FA2,
110             v9fs = 0x01021997,
111             vmhgfs = 0xBACBACBC,
112             vxfs = 0xA501FCF5,
113             vzfs = 0x565A4653,
114             xenfs = 0xABBA1974,
115             xenix = 0x012FF7B4,
116             xfs = 0x58465342,
117             xia = 0x012FD16D,
118             zfs = 0x2FC12FC1,
119         }
120 
121         [StructLayout(LayoutKind.Sequential)]
122         internal struct MountPointInformation
123         {
124             internal ulong AvailableFreeSpace;
125             internal ulong TotalFreeSpace;
126             internal ulong TotalSize;
127         }
128 
129         [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetSpaceInfoForMountPoint", SetLastError = true)]
GetSpaceInfoForMountPoint([MarshalAs(UnmanagedType.LPStr)]string name, out MountPointInformation mpi)130         internal static extern int GetSpaceInfoForMountPoint([MarshalAs(UnmanagedType.LPStr)]string name, out MountPointInformation mpi);
131 
132         [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetFormatInfoForMountPoint", SetLastError = true)]
GetFormatInfoForMountPoint( [MarshalAs(UnmanagedType.LPStr)]string name, byte* formatNameBuffer, int bufferLength, long* formatType)133         private static extern unsafe int GetFormatInfoForMountPoint(
134             [MarshalAs(UnmanagedType.LPStr)]string name,
135             byte* formatNameBuffer,
136             int bufferLength,
137             long* formatType);
138 
GetFormatInfoForMountPoint(string name, out string format)139         internal static int GetFormatInfoForMountPoint(string name, out string format)
140         {
141             DriveType temp;
142             return GetFormatInfoForMountPoint(name, out format, out temp);
143         }
144 
GetFormatInfoForMountPoint(string name, out DriveType type)145         internal static int GetFormatInfoForMountPoint(string name, out DriveType type)
146         {
147             string temp;
148             return GetFormatInfoForMountPoint(name, out temp, out type);
149         }
150 
GetFormatInfoForMountPoint(string name, out string format, out DriveType type)151         private static int GetFormatInfoForMountPoint(string name, out string format, out DriveType type)
152         {
153             unsafe
154             {
155                 byte* formatBuffer = stackalloc byte[MountPointFormatBufferSizeInBytes];    // format names should be small
156                 long numericFormat;
157                 int result = GetFormatInfoForMountPoint(name, formatBuffer, MountPointFormatBufferSizeInBytes, &numericFormat);
158                 if (result == 0)
159                 {
160                     // Check if we have a numeric answer or string
161                     format = numericFormat != -1 ?
162                         Enum.GetName(typeof(UnixFileSystemTypes), numericFormat) :
163                         Marshal.PtrToStringAnsi((IntPtr)formatBuffer);
164                     type = GetDriveType(format);
165                 }
166                 else
167                 {
168                     format = string.Empty;
169                     type = DriveType.Unknown;
170                 }
171 
172                 return result;
173             }
174         }
175 
176         /// <summary>Categorizes a file system name into a drive type.</summary>
177         /// <param name="fileSystemName">The name to categorize.</param>
178         /// <returns>The recognized drive type.</returns>
GetDriveType(string fileSystemName)179         private static DriveType GetDriveType(string fileSystemName)
180         {
181             // This list is based primarily on "man fs", "man mount", "mntent.h", "/proc/filesystems", coreutils "stat.c",
182             // and "wiki.debian.org/FileSystem". It can be extended over time as we
183             // find additional file systems that should be recognized as a particular drive type.
184             switch (fileSystemName)
185             {
186                 case "iso":
187                 case "isofs":
188                 case "iso9660":
189                 case "fuseiso":
190                 case "fuseiso9660":
191                 case "umview-mod-umfuseiso9660":
192                     return DriveType.CDRom;
193 
194                 case "aafs":
195                 case "adfs":
196                 case "affs":
197                 case "anoninode":
198                 case "anon-inode FS":
199                 case "apfs":
200                 case "autofs":
201                 case "balloon-kvm-fs":
202                 case "bdevfs":
203                 case "befs":
204                 case "bfs":
205                 case "bpf_fs":
206                 case "btrfs":
207                 case "btrfs_test":
208                 case "cgroup2fs":
209                 case "cgroupfs":
210                 case "coh":
211                 case "cramfs":
212                 case "cramfs-wend":
213                 case "daxfs":
214                 case "drvfs":
215                 case "ecryptfs":
216                 case "efivarfs":
217                 case "efs":
218                 case "exofs":
219                 case "ext":
220                 case "ext2":
221                 case "ext2_old":
222                 case "ext3":
223                 case "ext2/ext3":
224                 case "ext4":
225                 case "ext4dev":
226                 case "f2fs":
227                 case "fat":
228                 case "fuseext2":
229                 case "fusefat":
230                 case "futexfs":
231                 case "hfs":
232                 case "hfs+":
233                 case "hfsplus":
234                 case "hfsx":
235                 case "hostfs":
236                 case "hpfs":
237                 case "inodefs":
238                 case "inotifyfs":
239                 case "jbd":
240                 case "jbd2":
241                 case "jffs":
242                 case "jffs2":
243                 case "jfs":
244                 case "logfs":
245                 case "lxfs":
246                 case "minix (30 char.)":
247                 case "minix v2 (30 char.)":
248                 case "minix v2":
249                 case "minix":
250                 case "minix_old":
251                 case "minix2":
252                 case "minix2v2":
253                 case "minix3":
254                 case "mlfs":
255                 case "msdos":
256                 case "nilfs":
257                 case "nsfs":
258                 case "ntfs":
259                 case "ocfs2":
260                 case "omfs":
261                 case "openprom":
262                 case "overlay":
263                 case "overlayfs":
264                 case "pstorefs":
265                 case "qnx4":
266                 case "qnx6":
267                 case "reiserfs":
268                 case "rpc_pipefs":
269                 case "selinux":
270                 case "smackfs":
271                 case "squashfs":
272                 case "swap":
273                 case "sysfs":
274                 case "sysv":
275                 case "sysv2":
276                 case "sysv4":
277                 case "tracefs":
278                 case "ubifs":
279                 case "udf":
280                 case "ufs":
281                 case "umsdos":
282                 case "umview-mod-umfuseext2":
283                 case "usbdevfs":
284                 case "v9fs":
285                 case "vzfs":
286                 case "wslfs":
287                 case "xenfs":
288                 case "xenix":
289                 case "xfs":
290                 case "xia":
291                 case "xiafs":
292                 case "xmount":
293                 case "zfs":
294                 case "zfs-fuse":
295                 case "zsmallocfs":
296                     return DriveType.Fixed;
297 
298                 case "9p":
299                 case "acfs":
300                 case "afs":
301                 case "aufs":
302                 case "autofs4":
303                 case "beaglefs":
304                 case "ceph":
305                 case "cifs":
306                 case "coda":
307                 case "coherent":
308                 case "curlftpfs":
309                 case "davfs2":
310                 case "dlm":
311                 case "fhgfs":
312                 case "flickrfs":
313                 case "fuseblk":
314                 case "fusedav":
315                 case "fusesmb":
316                 case "gfsgfs2":
317                 case "gfs/gfs2":
318                 case "gfs2":
319                 case "glusterfs-client":
320                 case "gmailfs":
321                 case "gpfs":
322                 case "ibrix":
323                 case "k-afs":
324                 case "kafs":
325                 case "ltspfs":
326                 case "lustre":
327                 case "ncpfs":
328                 case "nfs":
329                 case "nfs4":
330                 case "nfsd":
331                 case "novell":
332                 case "obexfs":
333                 case "panfs":
334                 case "prl_fs":
335                 case "s3ql":
336                 case "smb":
337                 case "smb2":
338                 case "smbfs":
339                 case "snfs":
340                 case "sshfs":
341                 case "vmhgfs":
342                 case "vxfs":
343                 case "wikipediafs":
344                     return DriveType.Network;
345 
346                 case "anon_inodefs":
347                 case "aptfs":
348                 case "avfs":
349                 case "bdev":
350                 case "binfmt_misc":
351                 case "cgroup":
352                 case "configfs":
353                 case "cryptkeeper":
354                 case "cpuset":
355                 case "debugfs":
356                 case "devfs":
357                 case "devpts":
358                 case "devtmpfs":
359                 case "encfs":
360                 case "fuse":
361                 case "fuse.gvfsd-fuse":
362                 case "fusectl":
363                 case "hugetlbfs":
364                 case "libpam-encfs":
365                 case "ibpam-mount":
366                 case "mtpfs":
367                 case "mythtvfs":
368                 case "mqueue":
369                 case "pipefs":
370                 case "plptools":
371                 case "proc":
372                 case "pstore":
373                 case "pytagsfs":
374                 case "ramfs":
375                 case "rofs":
376                 case "romfs":
377                 case "rootfs":
378                 case "securityfs":
379                 case "sockfs":
380                 case "tmpfs":
381                     return DriveType.Ram;
382 
383                 case "gphotofs":
384                 case "usbfs":
385                 case "usbdevice":
386                 case "vfat":
387                     return DriveType.Removable;
388 
389                     // Categorize as "Unknown" everything else not explicitly
390                     // recognized as a particular drive type.
391                 default:
392                     return DriveType.Unknown;
393             }
394         }
395     }
396 }
397