github.com/moby/docker@v26.1.3+incompatible/pkg/directory/directory_unix.go (about)

     1  //go: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  // calcSize walks a directory tree and returns its total size in bytes.
    13  func calcSize(ctx context.Context, dir string) (int64, error) {
    14  	var size int64
    15  	data := make(map[uint64]struct{})
    16  	err := filepath.Walk(dir, func(d string, fileInfo os.FileInfo, err error) error {
    17  		if err != nil {
    18  			// if dir/x disappeared while walking, Size() ignores dir/x.
    19  			// if dir does not exist, Size() returns the error.
    20  			if d != dir && os.IsNotExist(err) {
    21  				return nil
    22  			}
    23  			return err
    24  		}
    25  		select {
    26  		case <-ctx.Done():
    27  			return ctx.Err()
    28  		default:
    29  		}
    30  
    31  		// Ignore directory sizes
    32  		if fileInfo == nil {
    33  			return nil
    34  		}
    35  
    36  		s := fileInfo.Size()
    37  		if fileInfo.IsDir() || s == 0 {
    38  			return nil
    39  		}
    40  
    41  		// Check inode to handle hard links correctly
    42  		inode := fileInfo.Sys().(*syscall.Stat_t).Ino
    43  		//nolint:unconvert // inode is not an uint64 on all platforms.
    44  		if _, exists := data[uint64(inode)]; exists {
    45  			return nil
    46  		}
    47  
    48  		data[uint64(inode)] = struct{}{} //nolint:unconvert // inode is not an uint64 on all platforms.
    49  
    50  		size += s
    51  
    52  		return nil
    53  	})
    54  	return size, err
    55  }