22
33#include <limits.h>
44#include <ctype.h>
5+ #include <dirent.h>
6+ #include <sys/stat.h>
57#include <sys/statvfs.h>
68
7- static void strbufAppendMountPoint (FFstrbuf * mountpoint , const char * source )
9+ #ifdef __USE_LARGEFILE64
10+ #define stat stat64
11+ #define statvfs statvfs64
12+ #define dirent dirent64
13+ #define readdir readdir64
14+ #endif
15+
16+ static bool isPhysicalDevice (const char * device )
817{
9- while (* source != '\0' && !isspace (* source ))
18+ //DrvFs is a filesystem plugin to WSL that was designed to support interop between WSL and the Windows filesystem.
19+ if (strcmp (device , "drvfs" ) == 0 )
20+ return true;
21+
22+ //Pseudo filesystems don't have a device in /dev
23+ const char * devPrefix = "/dev/" ;
24+ if (strncmp (device , devPrefix , strlen (devPrefix )) != 0 )
25+ return false;
26+
27+ //Skip /dev/ prefix
28+ device += strlen (devPrefix );
29+
30+ if (
31+ strncmp (device , "loop" , 4 ) == 0 || //Ignore loop devices
32+ strncmp (device , "ram" , 3 ) == 0 || //Ignore ram devices
33+ strncmp (device , "fd" , 2 ) == 0 //Ignore fd devices
34+ ) return false;
35+
36+ return true;
37+ }
38+
39+ static void appendNextEntry (FFstrbuf * buffer , char * * source )
40+ {
41+ //Read the current entry into the buffer
42+ while (* * source != '\0' && !isspace (* * source ))
1043 {
1144 //After a backslash the next 3 characters are octal ascii codes
12- if (* source == '\\' && strnlen (source , 4 ) == 4 )
45+ if (* * source == '\\' && strnlen (* source , 4 ) == 4 )
1346 {
1447 char octal [4 ] = {0 };
15- strncpy (octal , source + 1 , 3 );
48+ strncpy (octal , * source + 1 , 3 );
1649
1750 long value = strtol (octal , NULL , 8 ); //Returns 0 on error, so no need to check endptr
1851 if (value > 0 && value < CHAR_MAX )
1952 {
20- ffStrbufAppendC (mountpoint , (char ) value );
21- source += 4 ;
53+ ffStrbufAppendC (buffer , (char ) value );
54+ * source += 4 ;
2255 continue ;
2356 }
2457 }
2558
26- ffStrbufAppendC (mountpoint , * source );
27- ++ source ;
59+ ffStrbufAppendC (buffer , * * source );
60+ ++ * source ;
61+ }
62+
63+ //Skip whitespace
64+ while (isspace (* * source ))
65+ ++ * source ;
66+ }
67+
68+ static void detectNameFromPath (FFDisk * disk , const struct stat * deviceStat , FFstrbuf * basePath )
69+ {
70+ DIR * dir = opendir (basePath -> chars );
71+ if (dir == NULL )
72+ return ;
73+
74+ uint32_t basePathLength = basePath -> length ;
75+
76+ struct dirent * entry ;
77+ while ((entry = readdir (dir )) != NULL )
78+ {
79+ if (entry -> d_name [0 ] == '.' )
80+ continue ;
81+
82+ ffStrbufAppendS (basePath , entry -> d_name );
83+
84+ struct stat entryStat ;
85+ bool ret = stat (basePath -> chars , & entryStat ) == 0 ;
86+
87+ ffStrbufSubstrBefore (basePath , basePathLength );
88+
89+ if (!ret || deviceStat -> st_ino != entryStat .st_ino )
90+ continue ;
91+
92+ ffStrbufAppendS (& disk -> name , entry -> d_name );
93+ break ;
2894 }
95+
96+ closedir (dir );
2997}
3098
31- #ifndef __ANDROID__
99+ static void detectName (FFDisk * disk , const FFstrbuf * device )
100+ {
101+ struct stat deviceStat ;
102+ if (stat (device -> chars , & deviceStat ) != 0 )
103+ return ;
104+
105+ FFstrbuf basePath ;
106+ ffStrbufInit (& basePath );
107+
108+ //Try partlabel first
109+ ffStrbufSetS (& basePath , "/dev/disk/by-partlabel/" );
110+ detectNameFromPath (disk , & deviceStat , & basePath );
111+
112+ //Try label second
113+ if (disk -> name .length == 0 )
114+ {
115+ ffStrbufSetS (& basePath , "/dev/disk/by-label/" );
116+ detectNameFromPath (disk , & deviceStat , & basePath );
117+ }
118+
119+ ffStrbufDestroy (& basePath );
120+ }
121+
122+ #ifdef __ANDROID__
123+
124+ static void detectType (const FFlist * allDisks , FFDisk * currentDisk , const char * options )
125+ {
126+ if (ffStrbufEqualS (& disk -> mountpoint , "/" ) || ffStrbufEqualS (& disk -> mountpoint , "/storage/emulated" ))
127+ disk -> type = FF_DISK_TYPE_REGULAR ;
128+ else if (ffStrbufStartsWithS (& disk -> mountpoint , "/mnt/media_rw/" ))
129+ disk -> type = FF_DISK_TYPE_EXTERNAL ;
130+ else
131+ disk -> type = FF_DISK_TYPE_HIDDEN ;
132+ }
133+
134+ #else
135+
32136static bool isSubvolume (const FFlist * allDisks , const FFDisk * currentDisk )
33137{
34138 FF_LIST_FOR_EACH (FFDisk , disk , * allDisks )
@@ -42,8 +146,34 @@ static bool isSubvolume(const FFlist* allDisks, const FFDisk* currentDisk)
42146
43147 return false;
44148}
149+
150+ static void detectType (const FFlist * allDisks , FFDisk * currentDisk , const char * options )
151+ {
152+ if (isSubvolume (allDisks , currentDisk ))
153+ currentDisk -> type = FF_DISK_TYPE_SUBVOLUME ;
154+ else if (strstr (options , "nosuid" ) != NULL || strstr (options , "nodev" ) != NULL )
155+ currentDisk -> type = FF_DISK_TYPE_EXTERNAL ;
156+ else if (ffStrbufStartsWithS (& currentDisk -> mountpoint , "/boot" ) || ffStrbufStartsWithS (& currentDisk -> mountpoint , "/efi" ))
157+ currentDisk -> type = FF_DISK_TYPE_HIDDEN ;
158+ else
159+ currentDisk -> type = FF_DISK_TYPE_REGULAR ;
160+ }
161+
45162#endif
46163
164+ static void detectStats (FFDisk * disk )
165+ {
166+ struct statvfs fs ;
167+ if (statvfs (disk -> mountpoint .chars , & fs ) != 0 )
168+ memset (& fs , 0 , sizeof (struct statvfs )); //Set all values to 0, so our values get initialized to 0 too
169+
170+ disk -> bytesTotal = fs .f_blocks * fs .f_frsize ;
171+ disk -> bytesUsed = disk -> bytesTotal - (fs .f_bavail * fs .f_frsize );
172+
173+ disk -> filesTotal = (uint32_t ) fs .f_files ;
174+ disk -> filesUsed = (uint32_t ) (disk -> filesTotal - fs .f_ffree );
175+ }
176+
47177void ffDetectDisksImpl (FFDiskResult * disks )
48178{
49179 FILE * mountsFile = fopen ("/proc/mounts" , "r" );
@@ -53,90 +183,50 @@ void ffDetectDisksImpl(FFDiskResult* disks)
53183 return ;
54184 }
55185
186+ FFstrbuf device ;
187+ ffStrbufInit (& device );
188+
56189 char * line = NULL ;
57190 size_t len = 0 ;
58191
59192 while (getline (& line , & len , mountsFile ) != EOF )
60193 {
194+ if (!isPhysicalDevice (line ))
195+ continue ;
196+
197+ //We have a valid device, add it to the list
198+ FFDisk * disk = ffListAdd (& disks -> disks );
199+
61200 //Format of the file: "<device> <mountpoint> <filesystem> <options> ..." (Same as fstab)
62201 char * currentPos = line ;
63202
64- //Non pseudo filesystems have their device in /dev/
65- //DrvFs is a filesystem plugin to WSL that was designed to support interop between WSL and the Windows filesystem.
66- if (strncmp (currentPos , "/dev/" , 5 ) != 0 && strncmp (currentPos , "drvfs" , 5 ) != 0 )
67- continue ;
203+ //detect device
204+ ffStrbufClear (& device );
205+ appendNextEntry (& device , & currentPos );
68206
69- //Skip /dev/ or drvfs
70- currentPos += 5 ;
207+ //detect mountpoint
208+ ffStrbufInit (& disk -> mountpoint );
209+ appendNextEntry (& disk -> mountpoint , & currentPos );
71210
72- //Don't show loop file systems
73- if ( strncasecmp ( currentPos , "loop" , 4 ) == 0 )
74- continue ;
211+ //detect filesystem
212+ ffStrbufInit ( & disk -> filesystem );
213+ appendNextEntry ( & disk -> filesystem , & currentPos ) ;
75214
76- FFDisk * disk = ffListAdd (& disks -> disks );
215+ //detect name
216+ ffStrbufInit (& disk -> name );
217+ detectName (disk , & device );
77218
78- //Go to mountpoint
79- while (!isspace (* currentPos ) && * currentPos != '\0' )
80- ++ currentPos ;
81- while (isspace (* currentPos ))
82- ++ currentPos ;
83-
84- ffStrbufInitA (& disk -> mountpoint , 16 );
85- strbufAppendMountPoint (& disk -> mountpoint , currentPos );
86-
87- //Go to filesystem
88- currentPos += disk -> mountpoint .length ;
89- while (isspace (* currentPos ))
90- ++ currentPos ;
91-
92- ffStrbufInitA (& disk -> filesystem , 16 );
93- ffStrbufAppendSUntilC (& disk -> filesystem , currentPos , ' ' );
94-
95- //Go to options, detect type
96- currentPos += disk -> filesystem .length ;
97- while (isspace (* currentPos ))
98- ++ currentPos ;
99-
100- #ifdef __ANDROID__
101- if (ffStrbufEqualS (& disk -> mountpoint , "/" ) || ffStrbufEqualS (& disk -> mountpoint , "/storage/emulated" ))
102- disk -> type = FF_DISK_TYPE_REGULAR ;
103- else if (ffStrbufStartsWithS (& disk -> mountpoint , "/mnt/media_rw/" ))
104- disk -> type = FF_DISK_TYPE_EXTERNAL ;
105- else
106- disk -> type = FF_DISK_TYPE_HIDDEN ;
107- #else
108- if (isSubvolume (& disks -> disks , disk ))
109- disk -> type = FF_DISK_TYPE_SUBVOLUME ;
110- else if (strstr (currentPos , "nosuid" ) != NULL || strstr (currentPos , "nodev" ) != NULL )
111- disk -> type = FF_DISK_TYPE_EXTERNAL ;
112- else if (ffStrbufStartsWithS (& disk -> mountpoint , "/boot" ) || ffStrbufStartsWithS (& disk -> mountpoint , "/efi" ))
113- disk -> type = FF_DISK_TYPE_HIDDEN ;
114- else
115- disk -> type = FF_DISK_TYPE_REGULAR ;
116- #endif
219+ //detect type
220+ detectType (& disks -> disks , disk , currentPos );
117221
118222 //Detects stats
119- #ifdef __USE_LARGEFILE64
120- struct statvfs64 fs ;
121- if (statvfs64 (disk -> mountpoint .chars , & fs ) != 0 )
122- memset (& fs , 0 , sizeof (struct statvfs64 )); //Set all values to 0, so our values get initialized to 0 too
123- #else
124- struct statvfs fs ;
125- if (statvfs (disk -> mountpoint .chars , & fs ) != 0 )
126- memset (& fs , 0 , sizeof (struct statvfs )); //Set all values to 0, so our values get initialized to 0 too
127- #endif
128-
129- disk -> bytesTotal = fs .f_blocks * fs .f_frsize ;
130- disk -> bytesUsed = disk -> bytesTotal - (fs .f_bavail * fs .f_frsize );
131-
132- disk -> filesTotal = (uint32_t ) fs .f_files ;
133- disk -> filesUsed = (uint32_t ) (disk -> filesTotal - fs .f_ffree );
134-
135- ffStrbufInit (& disk -> name ); //TODO: implement this
223+ detectStats (disk );
136224 }
137225
138226 if (line != NULL )
139227 free (line );
140228
229+ ffStrbufDestroy (& device );
230+
141231 fclose (mountsFile );
142232}
0 commit comments