github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/pkg/directory/directory_unix.go (about)

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