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
This commit is contained in:
李通洲
2026-10-13 14:16:05 +08:00
committed by Carter Li
parent 73ebe95120
commit f93ffed57a
11 changed files with 68 additions and 44 deletions
+6
View File
@@ -9,6 +9,10 @@ Changes:
* It defaults to `"both"`, so a command that logs to stderr now has that output captured instead of discarded. * It defaults to `"both"`, so a command that logs to stderr now has that output captured instead of discarded.
* Set it to `"stdout"` or `"stderr"` to restore the old single-stream behavior. (Command) * Set it to `"stdout"` or `"stderr"` to restore the old single-stream behavior. (Command)
* The Shell module now reports the shell from the password database (`/etc/passwd`) instead of the `$SHELL` environment variable, which may differ when the login shell was changed after the session started. (Title) * The Shell module now reports the shell from the password database (`/etc/passwd`) instead of the `$SHELL` environment variable, which may differ when the login shell was changed after the session started. (Title)
* The Disk custom format no longer provides `{size-available}`. `{size-free}` now reports whichever of the two the `disk.useAvailable` option selects, and the raw byte counts are available as `{bytes-used}` and `{bytes-total}`. (Disk)
* This also means `{size-free}` now changes with `disk.useAvailable`; it used to always report the file system's free size.
* The Disk JSON output no longer includes `bytes.available` and `bytes.used`. (Disk)
* `bytes.free` and `bytes.total` are unchanged; the used size can be derived as `total - free`.
Features: Features:
* Added Sound detection on Android. (Sound, Android) * Added Sound detection on Android. (Sound, Android)
@@ -34,6 +38,8 @@ Bugfixes:
* Fixed assertion failure when percentage exceeds 100. (Percent) * Fixed assertion failure when percentage exceeds 100. (Percent)
* Fixed a non-existent command being reported as a generic child process error on Windows instead of `command not found`. (Command, Windows) * Fixed a non-existent command being reported as a generic child process error on Windows instead of `command not found`. (Command, Windows)
* Fixed Android display detection on devices running Android 17. (Display, Android) * Fixed Android display detection on devices running Android 17. (Display, Android)
* Fixed Windows volumes with a per-user quota (such as network shares) reporting a wrong total size and a wrapped-around used size, because the total size was quota-limited while the free size was not. (#2651, Disk, Windows)
* On Windows 10 1809 (build 17763) and later, the whole volume's capacity and free space are now reported by default. Set `disk.useAvailable` to `true` to keep reporting the space that is available to the current user, quota included.
Logos: Logos:
* Added filled Artix logo (#2631) * Added filled Artix logo (#2631)
+5 -5
View File
@@ -277,7 +277,7 @@
"batteryFormat": { "batteryFormat": {
"description": "Output format for the `Battery` module. See Wiki for formatting syntax\n 1. {manufacturer}: Battery manufacturer\n 2. {name}: Battery model name *\n 3. {technology}: Battery technology\n 4. {capacity}: Battery capacity (percentage num)\n 5. {status}: Battery status\n 6. {temperature}: Battery temperature (formatted)\n 7. {cycle-count}: Battery cycle count\n 8. {serial}: Battery serial number\n 9. {manufacture-date}: Battery manufacture date\n 10. {capacity-bar}: Battery capacity (percentage bar)\n 11. {time-days}: Battery time remaining days\n 12. {time-hours}: Battery time remaining hours\n 13. {time-minutes}: Battery time remaining minutes\n 14. {time-seconds}: Battery time remaining seconds\n 15. {time-formatted}: Battery time remaining (formatted)", "description": "Output format for the `Battery` module. See Wiki for formatting syntax\n 1. {manufacturer}: Battery manufacturer\n 2. {model-name}: Battery model name *\n 3. {technology}: Battery technology\n 4. {capacity}: Battery capacity (percentage num)\n 5. {status}: Battery status\n 6. {temperature}: Battery temperature (formatted)\n 7. {cycle-count}: Battery cycle count\n 8. {serial}: Battery serial number\n 9. {manufacture-date}: Battery manufacture date\n 10. {capacity-bar}: Battery capacity (percentage bar)\n 11. {time-days}: Battery time remaining days\n 12. {time-hours}: Battery time remaining hours\n 13. {time-minutes}: Battery time remaining minutes\n 14. {time-seconds}: Battery time remaining seconds\n 15. {time-formatted}: Battery time remaining (formatted)",
"type": "string" "type": "string"
}, },
"biosFormat": { "biosFormat": {
@@ -325,7 +325,7 @@
"type": "string" "type": "string"
}, },
"cpuFormat": { "cpuFormat": {
"description": "Output format for the `CPU` module. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count\n 11. {march}: CPU microarchitecture\n 12. {numa-nodes}: NUMA node count\n 13. {code-name}: CPU code name (x86 only)\n 14. {technology}: CPU technology (x86 only)", "description": "Output format for the `CPU` module. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count\n 11. {march}: CPU microarchitecture\n 12. {numa-nodes}: NUMA node count",
"type": "string" "type": "string"
}, },
"cpucacheFormat": { "cpucacheFormat": {
@@ -353,7 +353,7 @@
"type": "string" "type": "string"
}, },
"diskFormat": { "diskFormat": {
"description": "Output format for the `Disk` module. See Wiki for formatting syntax\n 1. {size-used}: Size used\n 2. {size-total}: Size total\n 3. {size-percentage}: Size percentage num\n 4. {files-used}: Files used\n 5. {files-total}: Files total\n 6. {files-percentage}: Files percentage num\n 7. {is-external}: True if external volume\n 8. {is-hidden}: True if hidden volume\n 9. {filesystem}: Filesystem *\n 10. {name}: Label / name *\n 11. {is-readonly}: True if read-only\n 12. {create-time}: Create time in local timezone\n 13. {size-percentage-bar}: Size percentage bar\n 14. {files-percentage-bar}: Files percentage bar\n 15. {days}: Days after creation\n 16. {hours}: Hours after creation\n 17. {minutes}: Minutes after creation\n 18. {seconds}: Seconds after creation\n 19. {milliseconds}: Milliseconds after creation\n 20. {mountpoint}: Mount point / drive letter *\n 21. {mount-from}: Mount from (device path) *\n 22. {years}: Years integer after creation\n 23. {days-of-year}: Days of year after creation\n 24. {years-fraction}: Years fraction after creation\n 25. {size-free}: Size free\n 26. {size-available}: Size available", "description": "Output format for the `Disk` module. See Wiki for formatting syntax\n 1. {size-used}: Size used (formatted)\n 2. {size-total}: Size total (formatted)\n 3. {size-percentage}: Size percentage num\n 4. {files-used}: Files used\n 5. {files-total}: Files total\n 6. {files-percentage}: Files percentage num\n 7. {is-external}: True if external volume\n 8. {is-hidden}: True if hidden volume\n 9. {filesystem}: Filesystem *\n 10. {name}: Label / name *\n 11. {is-readonly}: True if read-only\n 12. {create-time}: Create time in local timezone\n 13. {size-percentage-bar}: Size percentage bar\n 14. {files-percentage-bar}: Files percentage bar\n 15. {days}: Days after creation\n 16. {hours}: Hours after creation\n 17. {minutes}: Minutes after creation\n 18. {seconds}: Seconds after creation\n 19. {milliseconds}: Milliseconds after creation\n 20. {mountpoint}: Mount point / drive letter *\n 21. {mount-from}: Mount from (device path) *\n 22. {years}: Years integer after creation\n 23. {days-of-year}: Days of year after creation\n 24. {years-fraction}: Years fraction after creation\n 25. {size-free}: Size free (formatted)\n 26. {bytes-used}: Size used (in bytes)\n 27. {bytes-total}: Size total (in bytes)",
"type": "string" "type": "string"
}, },
"diskioFormat": { "diskioFormat": {
@@ -465,7 +465,7 @@
"type": "string" "type": "string"
}, },
"poweradapterFormat": { "poweradapterFormat": {
"description": "Output format for the `PowerAdapter` module. See Wiki for formatting syntax\n 1. {watts}: Power adapter watts\n 2. {name}: Power adapter name\n 3. {manufacturer}: Power adapter manufacturer\n 4. {model-name}: Power adapter model\n 5. {description}: Power adapter description\n 6. {serial}: Power adapter serial number", "description": "Output format for the `PowerAdapter` module. See Wiki for formatting syntax\n 1. {watts}: Power adapter watts\n 2. {name}: Power adapter name\n 3. {manufacturer}: Power adapter manufacturer\n 4. {model-name}: Power adapter model name\n 5. {description}: Power adapter description\n 6. {serial}: Power adapter serial number",
"type": "string" "type": "string"
}, },
"processesFormat": { "processesFormat": {
@@ -2716,7 +2716,7 @@
}, },
"useAvailable": { "useAvailable": {
"type": "boolean", "type": "boolean",
"description": "Use f_bavail (lpFreeBytesAvailableToCaller for Windows) instead of f_bfree to calculate used bytes\nMay be required for macOS to display correct results", "description": "Use f_bavail instead of f_bfree to calculate used bytes\nMay be required for macOS to display correct results\nOn Windows, set to true to make fastfetch honors the quota settings",
"default": false "default": false
}, },
"percent": { "percent": {
+24
View File
@@ -719,6 +719,10 @@ static inline bool ffIsSystemBasicProcessInfoAvailable() { // Includes HandleCou
return SharedUserData->NtBuildNumber >= 26200; // MSDN says it was added in 26100.4770; ntdoc says 25H2 return SharedUserData->NtBuildNumber >= 26200; // MSDN says it was added in 26100.4770; ntdoc says 25H2
} }
static inline bool ffIsFileFsFullSizeInformationExAvailable() {
return SharedUserData->NtBuildNumber >= 17763; // Windows 10 October 2018 Update (1809, REDSTONE5)
}
NTSYSAPI NTSTATUS NTAPI NtOpenProcessToken( NTSYSAPI NTSTATUS NTAPI NtOpenProcessToken(
_In_ HANDLE ProcessHandle, _In_ HANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess, _In_ ACCESS_MASK DesiredAccess,
@@ -1419,3 +1423,23 @@ NTSYSAPI NTSTATUS NTAPI NtTerminateProcess(
NTSYSAPI NTSTATUS NTAPI RtlAcquirePebLock(VOID); NTSYSAPI NTSTATUS NTAPI RtlAcquirePebLock(VOID);
NTSYSAPI NTSTATUS NTAPI RtlReleasePebLock(VOID); NTSYSAPI NTSTATUS NTAPI RtlReleasePebLock(VOID);
typedef struct _FILE_FS_FULL_SIZE_INFORMATION_EX {
ULONGLONG ActualTotalAllocationUnits;
ULONGLONG ActualAvailableAllocationUnits;
ULONGLONG ActualPoolUnavailableAllocationUnits;
ULONGLONG CallerTotalAllocationUnits;
ULONGLONG CallerAvailableAllocationUnits;
ULONGLONG CallerPoolUnavailableAllocationUnits;
ULONGLONG UsedAllocationUnits;
ULONGLONG TotalReservedAllocationUnits;
ULONGLONG VolumeStorageReserveAllocationUnits;
ULONGLONG AvailableCommittedAllocationUnits;
ULONGLONG PoolAvailableAllocationUnits;
ULONG SectorsPerAllocationUnit;
ULONG BytesPerSector;
} FILE_FS_FULL_SIZE_INFORMATION_EX, *PFILE_FS_FULL_SIZE_INFORMATION_EX;
enum {
FileFsFullSizeInformationEx = 14
};
-2
View File
@@ -22,8 +22,6 @@ const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks) {
FF_LIST_FOR_EACH (FFDisk, disk, *disks) { FF_LIST_FOR_EACH (FFDisk, disk, *disks) {
if (disk->bytesTotal == 0) { if (disk->bytesTotal == 0) {
disk->type |= FF_DISK_VOLUME_TYPE_UNKNOWN_BIT; disk->type |= FF_DISK_VOLUME_TYPE_UNKNOWN_BIT;
} else {
disk->bytesUsed = disk->bytesTotal - (options->calcType == FF_DISK_CALC_TYPE_FREE ? disk->bytesFree : disk->bytesAvailable);
} }
} }
-2
View File
@@ -16,9 +16,7 @@ typedef struct FFDisk {
FFstrbuf name; FFstrbuf name;
FFDiskVolumeType type; FFDiskVolumeType type;
uint64_t bytesUsed;
uint64_t bytesFree; uint64_t bytesFree;
uint64_t bytesAvailable;
uint64_t bytesTotal; uint64_t bytesTotal;
uint32_t filesUsed; uint32_t filesUsed;
+1 -3
View File
@@ -188,9 +188,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) {
FFDisk* disk = FF_LIST_ADD(FFDisk, *disks); FFDisk* disk = FF_LIST_ADD(FFDisk, *disks);
disk->bytesTotal = (uint64_t) fs->f_blocks * (uint64_t) fs->f_bsize; disk->bytesTotal = (uint64_t) fs->f_blocks * (uint64_t) fs->f_bsize;
disk->bytesFree = (uint64_t) fs->f_bfree * (uint64_t) fs->f_bsize; disk->bytesFree = (uint64_t) (options->calcType == FF_DISK_CALC_TYPE_FREE ? fs->f_bfree : fs->f_bavail) * (uint64_t) fs->f_bsize;
disk->bytesAvailable = (uint64_t) fs->f_bavail * (uint64_t) fs->f_bsize;
disk->bytesUsed = 0; // To be filled in ./disk.c
disk->filesTotal = (uint32_t) fs->f_files; disk->filesTotal = (uint32_t) fs->f_files;
disk->filesUsed = (uint32_t) fs->f_files - (uint32_t) fs->f_ffree; disk->filesUsed = (uint32_t) fs->f_files - (uint32_t) fs->f_ffree;
-2
View File
@@ -44,8 +44,6 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) {
disk->bytesTotal = (uint64_t) fs.total_blocks * (uint64_t) fs.block_size; disk->bytesTotal = (uint64_t) fs.total_blocks * (uint64_t) fs.block_size;
disk->bytesFree = (uint64_t) fs.free_blocks * (uint64_t) fs.block_size; disk->bytesFree = (uint64_t) fs.free_blocks * (uint64_t) fs.block_size;
disk->bytesAvailable = disk->bytesFree;
disk->bytesUsed = 0; // To be filled in ./disk.c
disk->filesTotal = (uint32_t) fs.total_nodes; disk->filesTotal = (uint32_t) fs.total_nodes;
disk->filesUsed = (uint32_t) (fs.total_nodes - fs.free_nodes); disk->filesUsed = (uint32_t) (fs.total_nodes - fs.free_nodes);
+3 -5
View File
@@ -249,16 +249,14 @@ static void detectType(const FFlist* disks, FFDisk* currentDisk, struct mntent*
#endif #endif
static void detectStats(FFDisk* disk) { static void detectStats(FFDiskOptions* options, FFDisk* disk) {
struct statvfs fs; struct statvfs fs;
if (statvfs(disk->mountpoint.chars, &fs) != 0) { if (statvfs(disk->mountpoint.chars, &fs) != 0) {
memset(&fs, 0, sizeof(fs)); // Set all values to 0, so our values get initialized to 0 too memset(&fs, 0, sizeof(fs)); // Set all values to 0, so our values get initialized to 0 too
} }
disk->bytesTotal = fs.f_blocks * (uint64_t) fs.f_frsize; disk->bytesTotal = fs.f_blocks * (uint64_t) fs.f_frsize;
disk->bytesFree = fs.f_bfree * (uint64_t) fs.f_frsize; disk->bytesFree = (options->calcType == FF_DISK_CALC_TYPE_FREE ? fs.f_bfree : fs.f_bavail) * (uint64_t) fs.f_frsize;
disk->bytesAvailable = fs.f_bavail * (uint64_t) fs.f_frsize;
disk->bytesUsed = 0; // To be filled in ./disk.c
if (fs.f_files >= fs.f_ffree) { if (fs.f_files >= fs.f_ffree) {
disk->filesTotal = (uint32_t) fs.f_files; disk->filesTotal = (uint32_t) fs.f_files;
@@ -330,7 +328,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) {
detectType(disks, disk, device); detectType(disks, disk, device);
// Detects stats // Detects stats
detectStats(disk); detectStats(options, disk);
} }
endmntent(mountsFile); endmntent(mountsFile);
+3 -5
View File
@@ -85,16 +85,14 @@ static void detectType(const FFlist* disks, FFDisk* currentDisk, struct mnttab*
} }
} }
static void detectStats(FFDisk* disk) { static void detectStats(FFDiskOptions* options, FFDisk* disk) {
struct statvfs fs; struct statvfs fs;
if (statvfs(disk->mountpoint.chars, &fs) != 0) { if (statvfs(disk->mountpoint.chars, &fs) != 0) {
memset(&fs, 0, sizeof(fs)); memset(&fs, 0, sizeof(fs));
} }
disk->bytesTotal = fs.f_blocks * fs.f_frsize; disk->bytesTotal = fs.f_blocks * fs.f_frsize;
disk->bytesFree = fs.f_bfree * fs.f_frsize; disk->bytesFree = (options->calcType == FF_DISK_CALC_TYPE_FREE ? fs.f_bfree : fs.f_bavail) * fs.f_frsize;
disk->bytesAvailable = fs.f_bavail * fs.f_frsize;
disk->bytesUsed = 0; // To be filled in ./disk.c
disk->filesTotal = (uint32_t) fs.f_files; disk->filesTotal = (uint32_t) fs.f_files;
disk->filesUsed = (uint32_t) (disk->filesTotal - fs.f_ffree); disk->filesUsed = (uint32_t) (disk->filesTotal - fs.f_ffree);
@@ -138,7 +136,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) {
ffStrbufInitS(&disk->filesystem, device.mnt_fstype); ffStrbufInitS(&disk->filesystem, device.mnt_fstype);
ffStrbufInit(&disk->name); ffStrbufInit(&disk->name);
detectType(disks, disk, &device); detectType(disks, disk, &device);
detectStats(disk); detectStats(options, disk);
} }
return nullptr; return nullptr;
+11 -4
View File
@@ -75,8 +75,6 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) {
disk->filesTotal = 0; disk->filesTotal = 0;
disk->bytesTotal = 0; disk->bytesTotal = 0;
disk->bytesFree = 0; disk->bytesFree = 0;
disk->bytesUsed = 0; // To be filled in ./disk.c
disk->bytesAvailable = 0;
disk->createTime = 0; disk->createTime = 0;
ffStrbufInit(&disk->filesystem); ffStrbufInit(&disk->filesystem);
ffStrbufInit(&disk->name); ffStrbufInit(&disk->name);
@@ -118,12 +116,21 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) {
} }
} }
if (options->calcType == FF_DISK_CALC_TYPE_AVAILABLE || !ffIsFileFsFullSizeInformationExAvailable()) {
FILE_FS_FULL_SIZE_INFORMATION fsFullSize; FILE_FS_FULL_SIZE_INFORMATION fsFullSize;
if (NT_SUCCESS(NtQueryVolumeInformationFile(handle, &iosb, &fsFullSize, sizeof(fsFullSize), FileFsFullSizeInformation))) { if (NT_SUCCESS(NtQueryVolumeInformationFile(handle, &iosb, &fsFullSize, sizeof(fsFullSize), FileFsFullSizeInformation))) {
uint64_t units = fsFullSize.BytesPerSector * fsFullSize.SectorsPerAllocationUnit; uint64_t units = fsFullSize.BytesPerSector * fsFullSize.SectorsPerAllocationUnit;
disk->bytesTotal = (uint64_t) fsFullSize.TotalAllocationUnits.QuadPart * units; disk->bytesTotal = (uint64_t) fsFullSize.TotalAllocationUnits.QuadPart * units;
disk->bytesFree = (uint64_t) fsFullSize.ActualAvailableAllocationUnits.QuadPart * units; disk->bytesFree = (uint64_t) fsFullSize.CallerAvailableAllocationUnits.QuadPart * units;
disk->bytesAvailable = (uint64_t) fsFullSize.CallerAvailableAllocationUnits.QuadPart * units; }
} else {
FILE_FS_FULL_SIZE_INFORMATION_EX fsFullSizeEx;
if (NT_SUCCESS(NtQueryVolumeInformationFile(handle, &iosb, &fsFullSizeEx, sizeof(fsFullSizeEx), FileFsFullSizeInformationEx))) {
// Space info without considering the quota setting
uint64_t units = fsFullSizeEx.BytesPerSector * fsFullSizeEx.SectorsPerAllocationUnit;
disk->bytesTotal = (uint64_t) fsFullSizeEx.ActualTotalAllocationUnits * units;
disk->bytesFree = (uint64_t) fsFullSizeEx.ActualAvailableAllocationUnits * units;
}
} }
} }
+11 -12
View File
@@ -15,6 +15,8 @@
static void printDisk(FFDiskOptions* options, const FFDisk* disk, uint32_t index) { static void printDisk(FFDiskOptions* options, const FFDisk* disk, uint32_t index) {
FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY key = ffStrbufCreate();
uint64_t bytesUsed = disk->bytesTotal - disk->bytesFree;
if (options->moduleArgs.key.length == 0) { if (options->moduleArgs.key.length == 0) {
ffStrbufSetF(&key, "%s (%s)", FF_MODULE_GET_DISPLAY_NAME(Disk), disk->mountpoint.chars); ffStrbufSetF(&key, "%s (%s)", FF_MODULE_GET_DISPLAY_NAME(Disk), disk->mountpoint.chars);
} else { } else {
@@ -50,12 +52,12 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk, uint32_t index
} }
FF_STRBUF_AUTO_DESTROY usedPretty = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY usedPretty = ffStrbufCreate();
ffSizeAppendNum(disk->bytesUsed, &usedPretty); ffSizeAppendNum(bytesUsed, &usedPretty);
FF_STRBUF_AUTO_DESTROY totalPretty = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY totalPretty = ffStrbufCreate();
ffSizeAppendNum(disk->bytesTotal, &totalPretty); ffSizeAppendNum(disk->bytesTotal, &totalPretty);
double bytesPercentage = disk->bytesTotal > 0 ? (double) disk->bytesUsed / (double) disk->bytesTotal * 100.0 : 0; double bytesPercentage = disk->bytesTotal > 0 ? (double) bytesUsed / (double) disk->bytesTotal * 100.0 : 0;
FFPercentageTypeFlags percentType = options->percent.type == 0 ? instance.config.display.percentType : options->percent.type; FFPercentageTypeFlags percentType = options->percent.type == 0 ? instance.config.display.percentType : options->percent.type;
if (options->moduleArgs.outputFormat.length == 0) { if (options->moduleArgs.outputFormat.length == 0) {
@@ -136,9 +138,6 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk, uint32_t index
FF_STRBUF_AUTO_DESTROY freePretty = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY freePretty = ffStrbufCreate();
ffSizeAppendNum(disk->bytesFree, &freePretty); ffSizeAppendNum(disk->bytesFree, &freePretty);
FF_STRBUF_AUTO_DESTROY availPretty = ffStrbufCreate();
ffSizeAppendNum(disk->bytesAvailable, &availPretty);
uint64_t now = ffTimeGetNow(); uint64_t now = ffTimeGetNow();
uint64_t duration = now - disk->createTime; uint64_t duration = now - disk->createTime;
uint32_t milliseconds = (uint32_t) (duration % 1000); uint32_t milliseconds = (uint32_t) (duration % 1000);
@@ -178,7 +177,8 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk, uint32_t index
FF_ARG(age.daysOfYear, "days-of-year"), FF_ARG(age.daysOfYear, "days-of-year"),
FF_ARG(age.yearsFraction, "years-fraction"), FF_ARG(age.yearsFraction, "years-fraction"),
FF_ARG(freePretty, "size-free"), FF_ARG(freePretty, "size-free"),
FF_ARG(availPretty, "size-available"), FF_ARG(bytesUsed, "bytes-used"),
FF_ARG(disk->bytesTotal, "bytes-total"),
})); }));
} }
} }
@@ -374,10 +374,8 @@ bool ffGenerateDiskJsonResult(FFDiskOptions* options, yyjson_mut_doc* doc, yyjso
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr); yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_val* bytes = yyjson_mut_obj_add_obj(doc, obj, "bytes"); yyjson_mut_val* bytes = yyjson_mut_obj_add_obj(doc, obj, "bytes");
yyjson_mut_obj_add_uint(doc, bytes, "available", item->bytesAvailable);
yyjson_mut_obj_add_uint(doc, bytes, "free", item->bytesFree); yyjson_mut_obj_add_uint(doc, bytes, "free", item->bytesFree);
yyjson_mut_obj_add_uint(doc, bytes, "total", item->bytesTotal); yyjson_mut_obj_add_uint(doc, bytes, "total", item->bytesTotal);
yyjson_mut_obj_add_uint(doc, bytes, "used", item->bytesUsed);
yyjson_mut_val* files = yyjson_mut_obj_add_obj(doc, obj, "files"); yyjson_mut_val* files = yyjson_mut_obj_add_obj(doc, obj, "files");
if (item->filesTotal == 0 && item->filesUsed == 0) { if (item->filesTotal == 0 && item->filesUsed == 0) {
@@ -487,8 +485,8 @@ FFModuleBaseInfo ffDiskModuleInfo = {
.generateJsonResult = (void*) ffGenerateDiskJsonResult, .generateJsonResult = (void*) ffGenerateDiskJsonResult,
.generateJsonConfig = (void*) ffGenerateDiskJsonConfig, .generateJsonConfig = (void*) ffGenerateDiskJsonConfig,
.formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) { .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
{ "Size used", "size-used" }, { "Size used (formatted)", "size-used" },
{ "Size total", "size-total" }, { "Size total (formatted)", "size-total" },
{ "Size percentage num", "size-percentage" }, { "Size percentage num", "size-percentage" },
{ "Files used", "files-used" }, { "Files used", "files-used" },
{ "Files total", "files-total" }, { "Files total", "files-total" },
@@ -511,8 +509,9 @@ FFModuleBaseInfo ffDiskModuleInfo = {
{ "Years integer after creation", "years" }, { "Years integer after creation", "years" },
{ "Days of year after creation", "days-of-year" }, { "Days of year after creation", "days-of-year" },
{ "Years fraction after creation", "years-fraction" }, { "Years fraction after creation", "years-fraction" },
{ "Size free", "size-free" }, { "Size free (formatted)", "size-free" },
{ "Size available", "size-available" }, { "Size used (in bytes)", "bytes-used" },
{ "Size total (in bytes)", "bytes-total" },
})), })),
.defaultOrder = 42, .defaultOrder = 42,
}; };