1// +build !windows 2 3/* 4 Copyright The containerd Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17*/ 18 19package fs 20 21import ( 22 "context" 23 "os" 24 "path/filepath" 25 "syscall" 26) 27 28type inode struct { 29 // TODO(stevvooe): Can probably reduce memory usage by not tracking 30 // device, but we can leave this right for now. 31 dev, ino uint64 32} 33 34func newInode(stat *syscall.Stat_t) inode { 35 return inode{ 36 // Dev is uint32 on darwin/bsd, uint64 on linux/solaris 37 dev: uint64(stat.Dev), // nolint: unconvert 38 // Ino is uint32 on bsd, uint64 on darwin/linux/solaris 39 ino: uint64(stat.Ino), // nolint: unconvert 40 } 41} 42 43func diskUsage(ctx context.Context, roots ...string) (Usage, error) { 44 45 var ( 46 size int64 47 inodes = map[inode]struct{}{} // expensive! 48 ) 49 50 for _, root := range roots { 51 if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { 52 if err != nil { 53 return err 54 } 55 56 select { 57 case <-ctx.Done(): 58 return ctx.Err() 59 default: 60 } 61 62 inoKey := newInode(fi.Sys().(*syscall.Stat_t)) 63 if _, ok := inodes[inoKey]; !ok { 64 inodes[inoKey] = struct{}{} 65 size += fi.Size() 66 } 67 68 return nil 69 }); err != nil { 70 return Usage{}, err 71 } 72 } 73 74 return Usage{ 75 Inodes: int64(len(inodes)), 76 Size: size, 77 }, nil 78} 79 80func diffUsage(ctx context.Context, a, b string) (Usage, error) { 81 var ( 82 size int64 83 inodes = map[inode]struct{}{} // expensive! 84 ) 85 86 if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error { 87 if err != nil { 88 return err 89 } 90 91 if kind == ChangeKindAdd || kind == ChangeKindModify { 92 inoKey := newInode(fi.Sys().(*syscall.Stat_t)) 93 if _, ok := inodes[inoKey]; !ok { 94 inodes[inoKey] = struct{}{} 95 size += fi.Size() 96 } 97 98 return nil 99 100 } 101 return nil 102 }); err != nil { 103 return Usage{}, err 104 } 105 106 return Usage{ 107 Inodes: int64(len(inodes)), 108 Size: size, 109 }, nil 110} 111