directory_unix.go 1.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. // +build linux freebsd solaris
  2. package directory
  3. import (
  4. "os"
  5. "path/filepath"
  6. "syscall"
  7. )
  8. // Size walks a directory tree and returns its total size in bytes.
  9. func Size(dir string) (size int64, err error) {
  10. data := make(map[uint64]struct{})
  11. err = filepath.Walk(dir, func(d string, fileInfo os.FileInfo, err error) error {
  12. if err != nil {
  13. // if dir does not exist, Size() returns the error.
  14. // if dir/x disappeared while walking, Size() ignores dir/x.
  15. if os.IsNotExist(err) && d != dir {
  16. return nil
  17. }
  18. return err
  19. }
  20. // Ignore directory sizes
  21. if fileInfo == nil {
  22. return nil
  23. }
  24. s := fileInfo.Size()
  25. if fileInfo.IsDir() || s == 0 {
  26. return nil
  27. }
  28. // Check inode to handle hard links correctly
  29. inode := fileInfo.Sys().(*syscall.Stat_t).Ino
  30. // inode is not a uint64 on all platforms. Cast it to avoid issues.
  31. if _, exists := data[uint64(inode)]; exists {
  32. return nil
  33. }
  34. // inode is not a uint64 on all platforms. Cast it to avoid issues.
  35. data[uint64(inode)] = struct{}{}
  36. size += s
  37. return nil
  38. })
  39. return
  40. }