aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2026-01-05 12:25:12 +0100
committerDmitry Vyukov <dvyukov@google.com>2026-01-09 12:51:45 +0000
commitce25ef79a77633ecbd0042eb35c9432dd582d448 (patch)
tree7b34a5c4988d6927e4d468a553ac5a125da4cd00 /pkg
parent56f8805780da7b6cf7aa8b6f104db4b2e1d57d70 (diff)
pkg/osutil: add DiskUsage function
DiskUsage returns total recursive disk usage of the dir (similar to du -s).
Diffstat (limited to 'pkg')
-rw-r--r--pkg/osutil/osutil.go18
-rw-r--r--pkg/osutil/osutil_darwin.go39
-rw-r--r--pkg/osutil/osutil_fuchsia.go31
-rw-r--r--pkg/osutil/osutil_linux.go6
-rw-r--r--pkg/osutil/osutil_nonlinux.go (renamed from pkg/osutil/osutil_bsd.go)9
-rw-r--r--pkg/osutil/osutil_test.go42
-rw-r--r--pkg/osutil/osutil_windows.go31
7 files changed, 73 insertions, 103 deletions
diff --git a/pkg/osutil/osutil.go b/pkg/osutil/osutil.go
index 936465ee7..fa963a3fb 100644
--- a/pkg/osutil/osutil.go
+++ b/pkg/osutil/osutil.go
@@ -11,6 +11,7 @@ import (
"errors"
"fmt"
"io"
+ "io/fs"
"os"
"os/exec"
"path/filepath"
@@ -366,3 +367,20 @@ func CreationTime(fi os.FileInfo) time.Time {
//
//go:linkname MonotonicNano runtime.nanotime
func MonotonicNano() time.Duration
+
+// DiskUsage returns total recursive disk usage of the dir (similar to du -s).
+func DiskUsage(dir string) (uint64, error) {
+ var total uint64
+ err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ return err
+ }
+ info, err := d.Info()
+ if err != nil {
+ return err
+ }
+ total += sysDiskUsage(info)
+ return nil
+ })
+ return total, err
+}
diff --git a/pkg/osutil/osutil_darwin.go b/pkg/osutil/osutil_darwin.go
deleted file mode 100644
index 0b1f30711..000000000
--- a/pkg/osutil/osutil_darwin.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2017 syzkaller project authors. All rights reserved.
-// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
-
-package osutil
-
-import (
- "os"
- "os/exec"
- "time"
-)
-
-func creationTime(fi os.FileInfo) time.Time {
- return time.Time{}
-}
-
-func RemoveAll(dir string) error {
- return os.RemoveAll(dir)
-}
-
-func SystemMemorySize() uint64 {
- return 0
-}
-
-func prolongPipe(r, w *os.File) {
-}
-
-func Sandbox(cmd *exec.Cmd, user, net bool) error {
- return nil
-}
-
-func SandboxChown(file string) error {
- return nil
-}
-
-func setPdeathsig(cmd *exec.Cmd, hardKill bool) {
-}
-
-func killPgroup(cmd *exec.Cmd) {
-}
diff --git a/pkg/osutil/osutil_fuchsia.go b/pkg/osutil/osutil_fuchsia.go
index fce4e38ba..a4a8c22b2 100644
--- a/pkg/osutil/osutil_fuchsia.go
+++ b/pkg/osutil/osutil_fuchsia.go
@@ -7,43 +7,12 @@ package osutil
import (
"os"
- "os/exec"
- "time"
)
-func creationTime(fi os.FileInfo) time.Time {
- return time.Time{}
-}
-
func HandleInterrupts(shutdown chan struct{}) {
}
-func RemoveAll(dir string) error {
- return os.RemoveAll(dir)
-}
-
-func SystemMemorySize() uint64 {
- return 0
-}
-
func ProcessExitStatus(ps *os.ProcessState) int {
// TODO: can be extracted from ExitStatus string.
return 0
}
-
-func prolongPipe(r, w *os.File) {
-}
-
-func Sandbox(cmd *exec.Cmd, user, net bool) error {
- return nil
-}
-
-func SandboxChown(file string) error {
- return nil
-}
-
-func setPdeathsig(cmd *exec.Cmd, hardKill bool) {
-}
-
-func killPgroup(cmd *exec.Cmd) {
-}
diff --git a/pkg/osutil/osutil_linux.go b/pkg/osutil/osutil_linux.go
index 63743a5f2..50be9b047 100644
--- a/pkg/osutil/osutil_linux.go
+++ b/pkg/osutil/osutil_linux.go
@@ -5,6 +5,7 @@ package osutil
import (
"fmt"
+ "io/fs"
"os"
"os/exec"
"path/filepath"
@@ -150,3 +151,8 @@ func prolongPipe(r, w *os.File) {
syscall.Syscall(syscall.SYS_FCNTL, w.Fd(), syscall.F_SETPIPE_SZ, uintptr(sz))
}
}
+
+func sysDiskUsage(info fs.FileInfo) uint64 {
+ stat := info.Sys().(*syscall.Stat_t)
+ return uint64(max(0, stat.Size, stat.Blocks*512))
+}
diff --git a/pkg/osutil/osutil_bsd.go b/pkg/osutil/osutil_nonlinux.go
index b26c91ff7..1d3ee8b82 100644
--- a/pkg/osutil/osutil_bsd.go
+++ b/pkg/osutil/osutil_nonlinux.go
@@ -1,11 +1,12 @@
-// Copyright 2017 syzkaller project authors. All rights reserved.
+// Copyright 2026 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
-//go:build freebsd || netbsd || openbsd
+//go:build !linux
package osutil
import (
+ "io/fs"
"os"
"os/exec"
"time"
@@ -39,3 +40,7 @@ func setPdeathsig(cmd *exec.Cmd, hardKill bool) {
func killPgroup(cmd *exec.Cmd) {
}
+
+func sysDiskUsage(info fs.FileInfo) uint64 {
+ return uint64(max(0, info.Size()))
+}
diff --git a/pkg/osutil/osutil_test.go b/pkg/osutil/osutil_test.go
index 4d9bf4cf8..460cc85ca 100644
--- a/pkg/osutil/osutil_test.go
+++ b/pkg/osutil/osutil_test.go
@@ -4,6 +4,7 @@
package osutil
import (
+ "bytes"
"fmt"
"os"
"path/filepath"
@@ -150,3 +151,44 @@ func TestReadWriteJSON(t *testing.T) {
t.Fatal(diff)
}
}
+
+func TestDiskUsage(t *testing.T) {
+ dir := t.TempDir()
+ var currentUsage uint64
+ expectUsage := func(minIncrease, maxIncrease uint64) {
+ usage, err := DiskUsage(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expectMin := currentUsage + minIncrease
+ expectMax := currentUsage + maxIncrease
+ t.Logf("got usage %v when expected (%v, %v)", usage, expectMin, expectMax)
+ if usage <= expectMin || usage >= expectMax {
+ t.Fatalf("bad usage %v, expect (%v, %v)", usage, expectMin, expectMax)
+ }
+ currentUsage = usage
+ }
+ expectUsage(1, 5<<10)
+ if err := MkdirAll(filepath.Join(dir, "nested")); err != nil {
+ t.Fatal(err)
+ }
+ expectUsage(1, 5<<10)
+ if err := WriteFile(filepath.Join(dir, "nested", "foo"), bytes.Repeat([]byte{'a'}, 1<<10)); err != nil {
+ t.Fatal(err)
+ }
+ expectUsage(1<<10, 5<<10)
+ if err := WriteFile(filepath.Join(dir, "nested", "bar"), bytes.Repeat([]byte{'a'}, 10<<10)); err != nil {
+ t.Fatal(err)
+ }
+ expectUsage(10<<10, 14<<10)
+ // Symlinks must not be counted twice.
+ if err := os.Symlink(filepath.Join(dir, "nested"), filepath.Join(dir, "dirlink")); err != nil {
+ t.Fatal(err)
+ }
+ expectUsage(1, 1<<10)
+
+ if err := os.Symlink(filepath.Join(dir, "nested", "bar"), filepath.Join(dir, "filelink")); err != nil {
+ t.Fatal(err)
+ }
+ expectUsage(1, 1<<10)
+}
diff --git a/pkg/osutil/osutil_windows.go b/pkg/osutil/osutil_windows.go
index 03e729e83..db9f56efa 100644
--- a/pkg/osutil/osutil_windows.go
+++ b/pkg/osutil/osutil_windows.go
@@ -5,43 +5,12 @@ package osutil
import (
"os"
- "os/exec"
"syscall"
- "time"
)
-func creationTime(fi os.FileInfo) time.Time {
- return time.Time{}
-}
-
func HandleInterrupts(shutdown chan struct{}) {
}
-func RemoveAll(dir string) error {
- return os.RemoveAll(dir)
-}
-
-func SystemMemorySize() uint64 {
- return 0
-}
-
-func prolongPipe(r, w *os.File) {
-}
-
func ProcessExitStatus(ps *os.ProcessState) int {
return ps.Sys().(syscall.WaitStatus).ExitStatus()
}
-
-func Sandbox(cmd *exec.Cmd, user, net bool) error {
- return nil
-}
-
-func SandboxChown(file string) error {
- return nil
-}
-
-func setPdeathsig(cmd *exec.Cmd, hardKill bool) {
-}
-
-func killPgroup(cmd *exec.Cmd) {
-}