...
1
2
3
4
19
20 package fs
21
22 import (
23 "context"
24 "os"
25 "path/filepath"
26 "syscall"
27 )
28
29
30
31
32
33
34
35
36 const blocksUnitSize = 512
37
38 type inode struct {
39
40
41 dev, ino uint64
42 }
43
44 func newInode(stat *syscall.Stat_t) inode {
45 return inode{
46 dev: uint64(stat.Dev),
47 ino: uint64(stat.Ino),
48 }
49 }
50
51 func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
52 var (
53 size int64
54 inodes = map[inode]struct{}{}
55 )
56
57 for _, root := range roots {
58 if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
59 if err != nil {
60 return err
61 }
62
63 select {
64 case <-ctx.Done():
65 return ctx.Err()
66 default:
67 }
68
69 stat := fi.Sys().(*syscall.Stat_t)
70 inoKey := newInode(stat)
71 if _, ok := inodes[inoKey]; !ok {
72 inodes[inoKey] = struct{}{}
73 size += stat.Blocks * blocksUnitSize
74 }
75
76 return nil
77 }); err != nil {
78 return Usage{}, err
79 }
80 }
81
82 return Usage{
83 Inodes: int64(len(inodes)),
84 Size: size,
85 }, nil
86 }
87
88 func diffUsage(ctx context.Context, a, b string) (Usage, error) {
89 var (
90 size int64
91 inodes = map[inode]struct{}{}
92 )
93
94 if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error {
95 if err != nil {
96 return err
97 }
98
99 if kind == ChangeKindAdd || kind == ChangeKindModify {
100 stat := fi.Sys().(*syscall.Stat_t)
101 inoKey := newInode(stat)
102 if _, ok := inodes[inoKey]; !ok {
103 inodes[inoKey] = struct{}{}
104 size += stat.Blocks * blocksUnitSize
105 }
106
107 return nil
108
109 }
110 return nil
111 }); err != nil {
112 return Usage{}, err
113 }
114
115 return Usage{
116 Inodes: int64(len(inodes)),
117 Size: size,
118 }, nil
119 }
120
View as plain text