Skip to content

Commit 734ee38

Browse files
Disk (Linux): partition name impl & general refactor
1 parent e651633 commit 734ee38

File tree

1 file changed

+165
-75
lines changed

1 file changed

+165
-75
lines changed

src/detection/disk/disk_linux.c

Lines changed: 165 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,137 @@
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+
32136
static 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+
47177
void 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

Comments
 (0)