github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/pkg/directory/directory_unix.go (about) 1 // +build linux freebsd darwin 2 3 package directory // import "github.com/demonoid81/moby/pkg/directory" 4 5 import ( 6 "context" 7 "os" 8 "path/filepath" 9 "syscall" 10 ) 11 12 // Size walks a directory tree and returns its total size in bytes. 13 func Size(ctx context.Context, dir string) (size int64, err error) { 14 data := make(map[uint64]struct{}) 15 err = filepath.Walk(dir, func(d string, fileInfo os.FileInfo, err error) error { 16 if err != nil { 17 // if dir does not exist, Size() returns the error. 18 // if dir/x disappeared while walking, Size() ignores dir/x. 19 if os.IsNotExist(err) && d != dir { 20 return nil 21 } 22 return err 23 } 24 select { 25 case <-ctx.Done(): 26 return ctx.Err() 27 default: 28 } 29 30 // Ignore directory sizes 31 if fileInfo == nil { 32 return nil 33 } 34 35 s := fileInfo.Size() 36 if fileInfo.IsDir() || s == 0 { 37 return nil 38 } 39 40 // Check inode to handle hard links correctly 41 inode := fileInfo.Sys().(*syscall.Stat_t).Ino 42 // inode is not a uint64 on all platforms. Cast it to avoid issues. 43 if _, exists := data[inode]; exists { 44 return nil 45 } 46 // inode is not a uint64 on all platforms. Cast it to avoid issues. 47 data[inode] = struct{}{} 48 49 size += s 50 51 return nil 52 }) 53 return 54 }