Files
fastfetch/src/detection/disk/disk_sunos.c
T
李通洲 f93ffed57a Disk: fix Windows quota affecting free space and unify disk size calculation
- Windows: use FILE_FS_FULL_SIZE_INFORMATION_EX on Windows 10 1809+ (Build >= 17763) when calcType != AVAILABLE to get ActualTotalAllocationUnits/ActualAvailableAllocationUnits (ignoring per-user disk quotas). Fall back to legacy FILE_FS_FULL_SIZE_INFORMATION with CallerAvailableAllocationUnits when calcType is AVAILABLE or EX is unavailable.
- Unix-like: respect --disk-calc-type. Use f_bfree for FREE, f_bavail for AVAILABLE (Linux/BSD/SunOS). Haiku currently always uses free_blocks.
- Refactor FFDisk: remove bytesUsed and bytesAvailable; compute used = total - free in disk module.
- Disk module: update custom format (remove `size-available`, add `bytes-used` and `bytes-total`); update JSON output (remove `bytes.available`, `bytes.used`).
- Disk detection: stop computing used in common path; let each platform set bytesFree by chosen semantics.

Fixes #2651
2026-10-13 15:35:12 +08:00

144 lines
4.4 KiB
C

#include "disk.h"
#include "common/io.h"
#include "common/strutil.h"
#include <sys/mntent.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/mount.h>
#include <sys/mnttab.h>
static bool isPhysicalDevice(const struct mnttab* device) {
// Always show the root path
if (ffStrEquals(device->mnt_mountp, "/")) {
return true;
}
if (ffStrEquals(device->mnt_special, "none")) {
return false;
}
// ZFS pool
if (ffStrEquals(device->mnt_fstype, "zfs")) {
return true;
}
// Pseudo filesystems don't have a device in /dev
if (!ffStrStartsWith(device->mnt_special, "/dev/")) {
return false;
}
struct stat deviceStat;
if (stat(device->mnt_special, &deviceStat) != 0) {
return false;
}
// Ignore all devices that are not block devices
if (!S_ISBLK(deviceStat.st_mode)) {
return false;
}
return true;
}
static bool isSubvolume(const FFlist* disks, FFDisk* currentDisk) {
if (ffStrbufEqualS(&currentDisk->filesystem, "zfs")) {
// ZFS subvolumes
uint32_t index = ffStrbufFirstIndexC(&currentDisk->mountFrom, '/');
if (index == currentDisk->mountFrom.length) {
return false;
}
FF_STRBUF_AUTO_DESTROY zpoolName = ffStrbufCreateNS(index, currentDisk->mountFrom.chars);
for (uint32_t i = 0; i < disks->length - 1; i++) {
const FFDisk* otherDevice = FF_LIST_GET(FFDisk, *disks, i);
if (ffStrbufEqualS(&otherDevice->filesystem, "zfs") && ffStrbufStartsWith(&otherDevice->mountFrom, &zpoolName)) {
return true;
}
}
return false;
} else {
// Filter all disks which device was already found. This catches BTRFS subvolumes.
for (uint32_t i = 0; i < disks->length - 1; i++) {
const FFDisk* otherDevice = FF_LIST_GET(FFDisk, *disks, i);
if (ffStrbufEqual(&currentDisk->mountFrom, &otherDevice->mountFrom)) {
return true;
}
}
}
return false;
}
static void detectType(const FFlist* disks, FFDisk* currentDisk, struct mnttab* device) {
if (hasmntopt(device, MNTOPT_NOBROWSE)) {
currentDisk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
} else if (isSubvolume(disks, currentDisk)) {
currentDisk->type = FF_DISK_VOLUME_TYPE_SUBVOLUME_BIT;
} else {
currentDisk->type = FF_DISK_VOLUME_TYPE_REGULAR_BIT;
}
if (hasmntopt(device, MNTOPT_RO)) {
currentDisk->type |= FF_DISK_VOLUME_TYPE_READONLY_BIT;
}
}
static void detectStats(FFDiskOptions* options, FFDisk* disk) {
struct statvfs fs;
if (statvfs(disk->mountpoint.chars, &fs) != 0) {
memset(&fs, 0, sizeof(fs));
}
disk->bytesTotal = fs.f_blocks * fs.f_frsize;
disk->bytesFree = (options->calcType == FF_DISK_CALC_TYPE_FREE ? fs.f_bfree : fs.f_bavail) * fs.f_frsize;
disk->filesTotal = (uint32_t) fs.f_files;
disk->filesUsed = (uint32_t) (disk->filesTotal - fs.f_ffree);
ffStrbufSetS(&disk->name, fs.f_fstr);
ffStrbufTrimRightSpace(&disk->name);
disk->createTime = 0;
}
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) {
FF_AUTO_CLOSE_FILE FILE* mountsFile = fopen(MNTTAB, "r");
if (mountsFile == nullptr) {
return "fopen(\"" MNTTAB "\", \"r\") == nullptr";
}
struct mnttab device;
while (getmntent(mountsFile, &device) == 0) {
if (__builtin_expect(options->folders.length, 0)) {
if (!ffStrbufSeparatedContainS(&options->folders, device.mnt_mountp, FF_DISK_FOLDER_SEPARATOR)) {
continue;
}
} else if (!isPhysicalDevice(&device)) {
continue;
}
if (options->hideFolders.length && ffDiskMatchesFolderPatterns(&options->hideFolders, device.mnt_mountp, FF_DISK_FOLDER_SEPARATOR)) {
continue;
}
if (options->hideFS.length && ffStrbufSeparatedContainS(&options->hideFS, device.mnt_fstype, ':')) {
continue;
}
// We have a valid device, add it to the list
FFDisk* disk = FF_LIST_ADD(FFDisk, *disks);
disk->type = FF_DISK_VOLUME_TYPE_NONE;
ffStrbufInitS(&disk->mountFrom, device.mnt_special);
ffStrbufInitS(&disk->mountpoint, device.mnt_mountp);
ffStrbufInitS(&disk->filesystem, device.mnt_fstype);
ffStrbufInit(&disk->name);
detectType(disks, disk, &device);
detectStats(options, disk);
}
return nullptr;
}