Skip to content

libfile: fix free space reporting and 32-bit block count truncation - #294

Merged
AltraMayor merged 2 commits into
masterfrom
issue-231
Oct 26, 2026
Merged

AltraMayor merged 2 commits into
masterfrom
issue-231

Conversation

@AltraMayor

Copy link
Copy Markdown
Owner

This pull request addresses the two issues reported in #231:

  1. macOS statvfs(3) 32-bit block count truncation: On macOS, statvfs(3) casts 64-bit block counts from statfs(2) into 32-bit fsblkcnt_t. On file systems with 512-byte blocks such as exFAT, free space of 2 TiB or more wraps modulo $2^{32}$ blocks, causing f3write to stop writing early. Calling statfs(2) directly on macOS and defining _FILE_OFFSET_BITS 64 in src/libfile.c ensures 64-bit block counts are used.
  2. Root-reserved blocks (f_bfree vs. f_bavail): File systems such as ext4 reserve a percentage of blocks (5% by default) for root. Returning fs.f_bavail in get_free_blocks() when running as an unprivileged user (geteuid() != 0) avoids overestimating writable space and avoids reporting root-reserved blocks as remaining free space after hitting ENOSPC.

This pull request closes #231.

On macOS, statvfs(3) is a wrapper around statfs(2) that casts the
64-bit block counts of struct statfs to 32-bit fsblkcnt_t. On file
systems with 512-byte blocks such as exFAT, free space of 2 TiB or
more overflows 32 bits in get_free_blocks(), causing f3write to stop
writing early.

This commit fixes the truncation by:
1. Calling statfs(2) in get_block_order() and get_free_blocks() on
   macOS.
2. Defining _FILE_OFFSET_BITS to 64 in libfile.c so statvfs(3) uses
   64-bit block counts on 32-bit architectures.
3. Removing the unused #include <sys/statvfs.h> directive from
   f3write.c.

This commit addresses issue #231.
File systems such as ext4 reserve a percentage of blocks for root.
Because get_free_blocks() always returned f_bfree, running f3write as
an unprivileged user overestimated the initial writable space and
reported the reserved blocks as remaining free space after hitting
ENOSPC.

This commit makes get_free_blocks() return f_bavail when geteuid(2) is
non-zero, and f_bfree when running as root.

This commit closes #231
@AltraMayor AltraMayor mentioned this pull request Oct 26, 2026
@AltraMayor
AltraMayor merged commit 3ad3d47 into master Oct 26, 2026
26 checks passed
@AltraMayor
AltraMayor deleted the issue-231 branch October 26, 2026 22:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Not fully testing 8TB

1 participant