package partition import ( "fmt" "syscall" ) // FreeBytes returns the number of free bytes available on the filesystem // containing `path`. Uses statfs(2); path must exist and be readable. func FreeBytes(path string) (uint64, error) { var stat syscall.Statfs_t if err := syscall.Statfs(path, &stat); err != nil { return 0, fmt.Errorf("statfs %s: %w", path, err) } // Bavail is the count of free blocks available to non-root users — // matches what `df` reports. Bsize is the block size in bytes. //nolint:unconvert // Bavail is uint64 on most platforms but int64 on darwin/freebsd return uint64(stat.Bavail) * uint64(stat.Bsize), nil } // HasFreeSpaceFor reports whether `path`'s filesystem has at least `wantBytes` // of free space, with `headroomPct` reserved (e.g. 10 = require 110% of want). // Returns the available bytes alongside, so callers can render a useful error. func HasFreeSpaceFor(path string, wantBytes int64, headroomPct int) (avail uint64, ok bool, err error) { avail, err = FreeBytes(path) if err != nil { return 0, false, err } if wantBytes < 0 { return avail, false, fmt.Errorf("invalid wantBytes %d", wantBytes) } required := uint64(wantBytes) * uint64(100+headroomPct) / 100 return avail, avail >= required, nil }