du_unix.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // +build !windows
  2. package fs
  3. import (
  4. "context"
  5. "os"
  6. "path/filepath"
  7. "syscall"
  8. )
  9. type inode struct {
  10. // TODO(stevvooe): Can probably reduce memory usage by not tracking
  11. // device, but we can leave this right for now.
  12. dev, ino uint64
  13. }
  14. func newInode(stat *syscall.Stat_t) inode {
  15. return inode{
  16. // Dev is uint32 on darwin/bsd, uint64 on linux/solaris
  17. dev: uint64(stat.Dev), // nolint: unconvert
  18. // Ino is uint32 on bsd, uint64 on darwin/linux/solaris
  19. ino: uint64(stat.Ino), // nolint: unconvert
  20. }
  21. }
  22. func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
  23. var (
  24. size int64
  25. inodes = map[inode]struct{}{} // expensive!
  26. )
  27. for _, root := range roots {
  28. if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
  29. if err != nil {
  30. return err
  31. }
  32. select {
  33. case <-ctx.Done():
  34. return ctx.Err()
  35. default:
  36. }
  37. inoKey := newInode(fi.Sys().(*syscall.Stat_t))
  38. if _, ok := inodes[inoKey]; !ok {
  39. inodes[inoKey] = struct{}{}
  40. size += fi.Size()
  41. }
  42. return nil
  43. }); err != nil {
  44. return Usage{}, err
  45. }
  46. }
  47. return Usage{
  48. Inodes: int64(len(inodes)),
  49. Size: size,
  50. }, nil
  51. }
  52. func diffUsage(ctx context.Context, a, b string) (Usage, error) {
  53. var (
  54. size int64
  55. inodes = map[inode]struct{}{} // expensive!
  56. )
  57. if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error {
  58. if err != nil {
  59. return err
  60. }
  61. if kind == ChangeKindAdd || kind == ChangeKindModify {
  62. inoKey := newInode(fi.Sys().(*syscall.Stat_t))
  63. if _, ok := inodes[inoKey]; !ok {
  64. inodes[inoKey] = struct{}{}
  65. size += fi.Size()
  66. }
  67. return nil
  68. }
  69. return nil
  70. }); err != nil {
  71. return Usage{}, err
  72. }
  73. return Usage{
  74. Inodes: int64(len(inodes)),
  75. Size: size,
  76. }, nil
  77. }