Quellcode durchsuchen

Merge pull request #11064 from delftswa2014/10970-treesize

Move directory size calculation to pkg/ (fixes #10970)
Michael Crosby vor 10 Jahren
Ursprung
Commit
92e632c84e

+ 2 - 1
daemon/container.go

@@ -26,6 +26,7 @@ import (
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/broadcastwriter"
 	"github.com/docker/docker/pkg/common"
+	"github.com/docker/docker/pkg/directory"
 	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/docker/pkg/networkfs/etchosts"
 	"github.com/docker/docker/pkg/networkfs/resolvconf"
@@ -909,7 +910,7 @@ func (container *Container) GetSize() (int64, int64) {
 	}
 
 	if _, err = os.Stat(container.basefs); err != nil {
-		if sizeRootfs, err = utils.TreeSize(container.basefs); err != nil {
+		if sizeRootfs, err = directory.Size(container.basefs); err != nil {
 			sizeRootfs = -1
 		}
 	}

+ 2 - 2
daemon/graphdriver/aufs/aufs.go

@@ -35,8 +35,8 @@ import (
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/common"
+	"github.com/docker/docker/pkg/directory"
 	mountpk "github.com/docker/docker/pkg/mount"
-	"github.com/docker/docker/utils"
 	"github.com/docker/libcontainer/label"
 )
 
@@ -320,7 +320,7 @@ func (a *Driver) applyDiff(id string, diff archive.ArchiveReader) error {
 // relative to its base filesystem directory.
 func (a *Driver) DiffSize(id, parent string) (size int64, err error) {
 	// AUFS doesn't need the parent layer to calculate the diff size.
-	return utils.TreeSize(path.Join(a.rootPath(), "diff", id))
+	return directory.Size(path.Join(a.rootPath(), "diff", id))
 }
 
 // ApplyDiff extracts the changeset from the given diff into the

+ 39 - 0
pkg/directory/directory.go

@@ -0,0 +1,39 @@
+// +build linux
+
+package directory
+
+import (
+	"os"
+	"path/filepath"
+	"syscall"
+)
+
+// Size walks a directory tree and returns its total size in bytes.
+func Size(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
+}

+ 120 - 0
pkg/directory/directory_test.go

@@ -0,0 +1,120 @@
+package directory
+
+import (
+	"os"
+	"testing"
+)
+
+// Size of an empty directory should be 0
+func TestSizeEmpty(t *testing.T) {
+	var err error
+	if err = os.Mkdir("/tmp/testSizeEmptyDirectory", 0777); err != nil {
+		t.Fatalf("failed to create directory: %s", err)
+	}
+
+	var size int64
+	if size, _ = Size("/tmp/testSizeEmptyDirectory"); size != 0 {
+		t.Fatalf("empty directory has size: %d", size)
+	}
+}
+
+// Size of a directory with one empty file should be 0
+func TestSizeEmptyFile(t *testing.T) {
+	var err error
+	if err = os.Mkdir("/tmp/testSizeEmptyFile", 0777); err != nil {
+		t.Fatalf("failed to create directory: %s", err)
+	}
+
+	if _, err = os.Create("/tmp/testSizeEmptyFile/file"); err != nil {
+		t.Fatalf("failed to create file: %s", err)
+	}
+
+	var size int64
+	if size, _ = Size("/tmp/testSizeEmptyFile"); size != 0 {
+		t.Fatalf("directory with one file has size: %d", size)
+	}
+}
+
+// Size of a directory with one 5-byte file should be 5
+func TestSizeNonemptyFile(t *testing.T) {
+	var err error
+	if err = os.Mkdir("/tmp/testSizeNonemptyFile", 0777); err != nil {
+		t.Fatalf("failed to create directory: %s", err)
+	}
+
+	var file *os.File
+	if file, err = os.Create("/tmp/testSizeNonemptyFile/file"); err != nil {
+		t.Fatalf("failed to create file: %s", err)
+	}
+
+	d := []byte{97, 98, 99, 100, 101}
+	file.Write(d)
+
+	var size int64
+	if size, _ = Size("/tmp/testSizeNonemptyFile"); size != 5 {
+		t.Fatalf("directory with one 5-byte file has size: %d", size)
+	}
+}
+
+// Size of a directory with one empty directory should be 0
+func TestSizeNestedDirectoryEmpty(t *testing.T) {
+	var err error
+	if err = os.MkdirAll("/tmp/testSizeNestedDirectoryEmpty/nested", 0777); err != nil {
+		t.Fatalf("failed to create directory: %s", err)
+	}
+
+	var size int64
+	if size, _ = Size("/tmp/testSizeNestedDirectoryEmpty"); size != 0 {
+		t.Fatalf("directory with one empty directory has size: %d", size)
+	}
+}
+
+// Test directory with 1 file and 1 empty directory
+func TestSizeFileAndNestedDirectoryEmpty(t *testing.T) {
+	var err error
+	if err = os.MkdirAll("/tmp/testSizeFileAndNestedDirectoryEmpty/nested", 0777); err != nil {
+		t.Fatalf("failed to create directory: %s", err)
+	}
+
+	var file *os.File
+	if file, err = os.Create("/tmp/testSizeFileAndNestedDirectoryEmpty/file"); err != nil {
+		t.Fatalf("failed to create file: %s", err)
+	}
+
+	d := []byte{100, 111, 99, 107, 101, 114}
+	file.Write(d)
+
+	var size int64
+	if size, _ = Size("/tmp/testSizeFileAndNestedDirectoryEmpty"); size != 6 {
+		t.Fatalf("directory with 6-byte file and empty directory has size: %d", size)
+	}
+}
+
+// Test directory with 1 file and 1 non-empty directory
+func TestSizeFileAndNestedDirectoryNonempty(t *testing.T) {
+	var err error
+	if err = os.MkdirAll("/tmp/testSizeFileAndNestedDirectoryEmpty/nested", 0777); err != nil {
+		t.Fatalf("failed to create directory: %s", err)
+	}
+
+	var file *os.File
+	if file, err = os.Create("/tmp/testSizeFileAndNestedDirectoryEmpty/file"); err != nil {
+		t.Fatalf("failed to create file: %s", err)
+	}
+
+	data := []byte{100, 111, 99, 107, 101, 114}
+	file.Write(data)
+
+	var nestedFile *os.File
+	if nestedFile, err = os.Create("/tmp/testSizeFileAndNestedDirectoryEmpty/nested/file"); err != nil {
+		t.Fatalf("failed to create file: %s", err)
+	}
+
+	nestedData := []byte{100, 111, 99, 107, 101, 114}
+	nestedFile.Write(nestedData)
+
+	var size int64
+	if size, _ = Size("/tmp/testSizeFileAndNestedDirectoryEmpty"); size != 12 {
+		t.Fatalf("directory with 6-byte file and empty directory has size: %d", size)
+	}
+}

+ 0 - 31
utils/utils_daemon.go

@@ -4,40 +4,9 @@ package utils
 
 import (
 	"os"
-	"path/filepath"
 	"syscall"
 )
 
-// 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
-}
-
 // IsFileOwner checks whether the current user is the owner of the given file.
 func IsFileOwner(f string) bool {
 	if fileInfo, err := os.Stat(f); err == nil && fileInfo != nil {