github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/pkg/directory/directory_unix.go (about)

     1  //go:build linux || freebsd || darwin
     2  // +build linux freebsd darwin
     3  
     4  package directory // import "github.com/docker/docker/pkg/directory"
     5  
     6  import (
     7  	"context"
     8  	"os"
     9  	"path/filepath"
    10  	"syscall"
    11  )
    12  
    13  // Size walks a directory tree and returns its total size in bytes.
    14  func Size(ctx context.Context, dir string) (size int64, err error) {
    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 does not exist, Size() returns the error.
    19  			// if dir/x disappeared while walking, Size() ignores dir/x.
    20  			if os.IsNotExist(err) && d != dir {
    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  		// inode is not a uint64 on all platforms. Cast it to avoid issues.
    44  		if _, exists := data[inode]; exists {
    45  			return nil
    46  		}
    47  		// inode is not a uint64 on all platforms. Cast it to avoid issues.
    48  		data[inode] = struct{}{}
    49  
    50  		size += s
    51  
    52  		return nil
    53  	})
    54  	return
    55  }