...

Source file src/github.com/containerd/continuity/fs/du_unix.go

Documentation: github.com/containerd/continuity/fs

     1  //go:build !windows
     2  // +build !windows
     3  
     4  /*
     5     Copyright The containerd Authors.
     6  
     7     Licensed under the Apache License, Version 2.0 (the "License");
     8     you may not use this file except in compliance with the License.
     9     You may obtain a copy of the License at
    10  
    11         http://www.apache.org/licenses/LICENSE-2.0
    12  
    13     Unless required by applicable law or agreed to in writing, software
    14     distributed under the License is distributed on an "AS IS" BASIS,
    15     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16     See the License for the specific language governing permissions and
    17     limitations under the License.
    18  */
    19  
    20  package fs
    21  
    22  import (
    23  	"context"
    24  	"os"
    25  	"path/filepath"
    26  	"syscall"
    27  )
    28  
    29  // blocksUnitSize is the unit used by `st_blocks` in `stat` in bytes.
    30  // See https://man7.org/linux/man-pages/man2/stat.2.html
    31  //
    32  //	st_blocks
    33  //	  This field indicates the number of blocks allocated to the
    34  //	  file, in 512-byte units.  (This may be smaller than
    35  //	  st_size/512 when the file has holes.)
    36  const blocksUnitSize = 512
    37  
    38  type inode struct {
    39  	// TODO(stevvooe): Can probably reduce memory usage by not tracking
    40  	// device, but we can leave this right for now.
    41  	dev, ino uint64
    42  }
    43  
    44  func newInode(stat *syscall.Stat_t) inode {
    45  	return inode{
    46  		dev: uint64(stat.Dev), //nolint: unconvert // dev is uint32 on darwin/bsd, uint64 on linux/solaris/freebsd
    47  		ino: uint64(stat.Ino), //nolint: unconvert // ino is uint32 on bsd, uint64 on darwin/linux/solaris/freebsd
    48  	}
    49  }
    50  
    51  func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
    52  	var (
    53  		size   int64
    54  		inodes = map[inode]struct{}{} // expensive!
    55  	)
    56  
    57  	for _, root := range roots {
    58  		if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
    59  			if err != nil {
    60  				return err
    61  			}
    62  
    63  			select {
    64  			case <-ctx.Done():
    65  				return ctx.Err()
    66  			default:
    67  			}
    68  
    69  			stat := fi.Sys().(*syscall.Stat_t)
    70  			inoKey := newInode(stat)
    71  			if _, ok := inodes[inoKey]; !ok {
    72  				inodes[inoKey] = struct{}{}
    73  				size += stat.Blocks * blocksUnitSize
    74  			}
    75  
    76  			return nil
    77  		}); err != nil {
    78  			return Usage{}, err
    79  		}
    80  	}
    81  
    82  	return Usage{
    83  		Inodes: int64(len(inodes)),
    84  		Size:   size,
    85  	}, nil
    86  }
    87  
    88  func diffUsage(ctx context.Context, a, b string) (Usage, error) {
    89  	var (
    90  		size   int64
    91  		inodes = map[inode]struct{}{} // expensive!
    92  	)
    93  
    94  	if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error {
    95  		if err != nil {
    96  			return err
    97  		}
    98  
    99  		if kind == ChangeKindAdd || kind == ChangeKindModify {
   100  			stat := fi.Sys().(*syscall.Stat_t)
   101  			inoKey := newInode(stat)
   102  			if _, ok := inodes[inoKey]; !ok {
   103  				inodes[inoKey] = struct{}{}
   104  				size += stat.Blocks * blocksUnitSize
   105  			}
   106  
   107  			return nil
   108  
   109  		}
   110  		return nil
   111  	}); err != nil {
   112  		return Usage{}, err
   113  	}
   114  
   115  	return Usage{
   116  		Inodes: int64(len(inodes)),
   117  		Size:   size,
   118  	}, nil
   119  }
   120  

View as plain text