directory_unix.go 1.2 KB

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