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