|
@@ -21,6 +21,7 @@ import (
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"sync"
|
|
|
+ "syscall"
|
|
|
"time"
|
|
|
|
|
|
"github.com/dotcloud/docker/dockerversion"
|
|
@@ -1091,3 +1092,33 @@ func ParseKeyValueOpt(opt string) (string, string, error) {
|
|
|
}
|
|
|
return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil
|
|
|
}
|
|
|
+
|
|
|
+// TreeSize walks a directory tree and returns its total size in bytes.
|
|
|
+func TreeSize(dir string) (size int64, err error) {
|
|
|
+ data := make(map[uint64]struct{})
|
|
|
+ err = filepath.Walk(dir, func(d string, fileInfo os.FileInfo, e error) error {
|
|
|
+ // Ignore directory sizes
|
|
|
+ if fileInfo == nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ s := fileInfo.Size()
|
|
|
+ if fileInfo.IsDir() || s == 0 {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check inode to handle hard links correctly
|
|
|
+ inode := fileInfo.Sys().(*syscall.Stat_t).Ino
|
|
|
+ // inode is not a uint64 on all platforms. Cast it to avoid issues.
|
|
|
+ if _, exists := data[uint64(inode)]; exists {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ // inode is not a uint64 on all platforms. Cast it to avoid issues.
|
|
|
+ data[uint64(inode)] = struct{}{}
|
|
|
+
|
|
|
+ size += s
|
|
|
+
|
|
|
+ return nil
|
|
|
+ })
|
|
|
+ return
|
|
|
+}
|