mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-12-09 19:29:26 +00:00
vendor: cadvisor v0.38.4
This commit is contained in:
272
vendor/github.com/karrick/godirwalk/walk.go
generated
vendored
272
vendor/github.com/karrick/godirwalk/walk.go
generated
vendored
@@ -1,31 +1,12 @@
|
||||
package godirwalk
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// DefaultScratchBufferSize specifies the size of the scratch buffer that will
|
||||
// be allocated by Walk, ReadDirents, or ReadDirnames when a scratch buffer is
|
||||
// not provided or the scratch buffer that is provided is smaller than
|
||||
// MinimumScratchBufferSize bytes. This may seem like a large value; however,
|
||||
// when a program intends to enumerate large directories, having a larger
|
||||
// scratch buffer results in fewer operating system calls.
|
||||
const DefaultScratchBufferSize = 64 * 1024
|
||||
|
||||
// MinimumScratchBufferSize specifies the minimum size of the scratch buffer
|
||||
// that Walk, ReadDirents, and ReadDirnames will use when reading file entries
|
||||
// from the operating system. It is initialized to the result from calling
|
||||
// `os.Getpagesize()` during program startup.
|
||||
var MinimumScratchBufferSize int
|
||||
|
||||
func init() {
|
||||
MinimumScratchBufferSize = os.Getpagesize()
|
||||
}
|
||||
|
||||
// Options provide parameters for how the Walk function operates.
|
||||
type Options struct {
|
||||
// ErrorCallback specifies a function to be invoked in the case of an error
|
||||
@@ -84,9 +65,16 @@ type Options struct {
|
||||
// Walk to use when reading directory entries, to reduce amount of garbage
|
||||
// generation. Not all architectures take advantage of the scratch
|
||||
// buffer. If omitted or the provided buffer has fewer bytes than
|
||||
// MinimumScratchBufferSize, then a buffer with DefaultScratchBufferSize
|
||||
// MinimumScratchBufferSize, then a buffer with MinimumScratchBufferSize
|
||||
// bytes will be created and used once per Walk invocation.
|
||||
ScratchBuffer []byte
|
||||
|
||||
// AllowNonDirectory causes Walk to bypass the check that ensures it is
|
||||
// being called on a directory node, or when FollowSymbolicLinks is true, a
|
||||
// symbolic link that points to a directory. Leave this value false to have
|
||||
// Walk return an error when called on a non-directory. Set this true to
|
||||
// have Walk run even when called on a non-directory node.
|
||||
AllowNonDirectory bool
|
||||
}
|
||||
|
||||
// ErrorAction defines a set of actions the Walk function could take based on
|
||||
@@ -108,6 +96,11 @@ const (
|
||||
SkipNode
|
||||
)
|
||||
|
||||
// SkipThis is used as a return value from WalkFuncs to indicate that the file
|
||||
// system entry named in the call is to be skipped. It is not returned as an
|
||||
// error by any function.
|
||||
var SkipThis = errors.New("skip this directory entry")
|
||||
|
||||
// WalkFunc is the type of the function called for each file system node visited
|
||||
// by Walk. The pathname argument will contain the argument to Walk as a prefix;
|
||||
// that is, if Walk is called with "dir", which is a directory containing the
|
||||
@@ -131,13 +124,60 @@ const (
|
||||
// Walk skips the remaining files in the containing directory. Note that any
|
||||
// supplied ErrorCallback function is not invoked with filepath.SkipDir when the
|
||||
// Callback or PostChildrenCallback functions return that special value.
|
||||
//
|
||||
// One arguably confusing aspect of the filepath.WalkFunc API that this library
|
||||
// must emulate is how a caller tells Walk to skip file system entries or
|
||||
// directories. With both filepath.Walk and this Walk, when a callback function
|
||||
// wants to skip a directory and not descend into its children, it returns
|
||||
// filepath.SkipDir. If the callback function returns filepath.SkipDir for a
|
||||
// non-directory, filepath.Walk and this library will stop processing any more
|
||||
// entries in the current directory, which is what many people do not want. If
|
||||
// you want to simply skip a particular non-directory entry but continue
|
||||
// processing entries in the directory, a callback function must return nil. The
|
||||
// implications of this API is when you want to walk a file system hierarchy and
|
||||
// skip an entry, when the entry is a directory, you must return one value,
|
||||
// namely filepath.SkipDir, but when the entry is a non-directory, you must
|
||||
// return a different value, namely nil. In other words, to get identical
|
||||
// behavior for two file system entry types you need to send different token
|
||||
// values.
|
||||
//
|
||||
// Here is an example callback function that adheres to filepath.Walk API to
|
||||
// have it skip any file system entry whose full pathname includes a particular
|
||||
// substring, optSkip:
|
||||
//
|
||||
// func callback1(osPathname string, de *godirwalk.Dirent) error {
|
||||
// if optSkip != "" && strings.Contains(osPathname, optSkip) {
|
||||
// if b, err := de.IsDirOrSymlinkToDir(); b == true && err == nil {
|
||||
// return filepath.SkipDir
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
// // Process file like normal...
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// This library attempts to eliminate some of that logic boilerplate by
|
||||
// providing a new token error value, SkipThis, which a callback function may
|
||||
// return to skip the current file system entry regardless of what type of entry
|
||||
// it is. If the current entry is a directory, its children will not be
|
||||
// enumerated, exactly as if the callback returned filepath.SkipDir. If the
|
||||
// current entry is a non-directory, the next file system entry in the current
|
||||
// directory will be enumerated, exactly as if the callback returned nil. The
|
||||
// following example callback function has identical behavior as the previous,
|
||||
// but has less boilerplate, and admittedly more simple logic.
|
||||
//
|
||||
// func callback2(osPathname string, de *godirwalk.Dirent) error {
|
||||
// if optSkip != "" && strings.Contains(osPathname, optSkip) {
|
||||
// return godirwalk.SkipThis
|
||||
// }
|
||||
// // Process file like normal...
|
||||
// return nil
|
||||
// }
|
||||
type WalkFunc func(osPathname string, directoryEntry *Dirent) error
|
||||
|
||||
// Walk walks the file tree rooted at the specified directory, calling the
|
||||
// specified callback function for each file system node in the tree, including
|
||||
// root, symbolic links, and other node types. The nodes are walked in lexical
|
||||
// order, which makes the output deterministic but means that for very large
|
||||
// directories this function can be inefficient.
|
||||
// root, symbolic links, and other node types.
|
||||
//
|
||||
// This function is often much faster than filepath.Walk because it does not
|
||||
// invoke os.Stat for every node it encounters, but rather obtains the file
|
||||
@@ -175,6 +215,10 @@ type WalkFunc func(osPathname string, directoryEntry *Dirent) error
|
||||
// }
|
||||
// }
|
||||
func Walk(pathname string, options *Options) error {
|
||||
if options == nil || options.Callback == nil {
|
||||
return errors.New("cannot walk without non-nil options and Callback function")
|
||||
}
|
||||
|
||||
pathname = filepath.Clean(pathname)
|
||||
|
||||
var fi os.FileInfo
|
||||
@@ -182,26 +226,28 @@ func Walk(pathname string, options *Options) error {
|
||||
|
||||
if options.FollowSymbolicLinks {
|
||||
fi, err = os.Stat(pathname)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot Stat")
|
||||
}
|
||||
} else {
|
||||
fi, err = os.Lstat(pathname)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cannot Lstat")
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mode := fi.Mode()
|
||||
if mode&os.ModeDir == 0 {
|
||||
return errors.Errorf("cannot Walk non-directory: %s", pathname)
|
||||
if !options.AllowNonDirectory && mode&os.ModeDir == 0 {
|
||||
return fmt.Errorf("cannot Walk non-directory: %s", pathname)
|
||||
}
|
||||
|
||||
dirent := &Dirent{
|
||||
name: filepath.Base(pathname),
|
||||
path: filepath.Dir(pathname),
|
||||
modeType: mode & os.ModeType,
|
||||
}
|
||||
|
||||
if len(options.ScratchBuffer) < MinimumScratchBufferSize {
|
||||
options.ScratchBuffer = newScratchBuffer()
|
||||
}
|
||||
|
||||
// If ErrorCallback is nil, set to a default value that halts the walk
|
||||
// process on all operating system errors. This is done to allow error
|
||||
// handling to be more succinct in the walk code.
|
||||
@@ -209,15 +255,15 @@ func Walk(pathname string, options *Options) error {
|
||||
options.ErrorCallback = defaultErrorCallback
|
||||
}
|
||||
|
||||
if len(options.ScratchBuffer) < MinimumScratchBufferSize {
|
||||
options.ScratchBuffer = make([]byte, DefaultScratchBufferSize)
|
||||
}
|
||||
|
||||
err = walk(pathname, dirent, options)
|
||||
if err == filepath.SkipDir {
|
||||
return nil // silence SkipDir for top level
|
||||
switch err {
|
||||
case nil, SkipThis, filepath.SkipDir:
|
||||
// silence SkipThis and filepath.SkipDir for top level
|
||||
debug("no error of significance: %v\n", err)
|
||||
return nil
|
||||
default:
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// defaultErrorCallback always returns Halt because if the upstream code did not
|
||||
@@ -230,124 +276,91 @@ func defaultErrorCallback(_ string, _ error) ErrorAction { return Halt }
|
||||
func walk(osPathname string, dirent *Dirent, options *Options) error {
|
||||
err := options.Callback(osPathname, dirent)
|
||||
if err != nil {
|
||||
if err == filepath.SkipDir {
|
||||
if err == SkipThis || err == filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
err = errors.Wrap(err, "Callback") // wrap potential errors returned by callback
|
||||
if action := options.ErrorCallback(osPathname, err); action == SkipNode {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// On some platforms, an entry can have more than one mode type bit set.
|
||||
// For instance, it could have both the symlink bit and the directory bit
|
||||
// set indicating it's a symlink to a directory.
|
||||
if dirent.IsSymlink() {
|
||||
if !options.FollowSymbolicLinks {
|
||||
return nil
|
||||
}
|
||||
// Only need to Stat entry if platform did not already have os.ModeDir
|
||||
// set, such as would be the case for unix like operating systems. (This
|
||||
// guard eliminates extra os.Stat check on Windows.)
|
||||
if !dirent.IsDir() {
|
||||
referent, err := os.Readlink(osPathname)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "cannot Readlink")
|
||||
if action := options.ErrorCallback(osPathname, err); action == SkipNode {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
// Does this symlink point to a directory?
|
||||
info, err := os.Stat(osPathname)
|
||||
if err != nil {
|
||||
if action := options.ErrorCallback(osPathname, err); action == SkipNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
var osp string
|
||||
if filepath.IsAbs(referent) {
|
||||
osp = referent
|
||||
} else {
|
||||
osp = filepath.Join(filepath.Dir(osPathname), referent)
|
||||
}
|
||||
|
||||
fi, err := os.Stat(osp)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "cannot Stat")
|
||||
if action := options.ErrorCallback(osp, err); action == SkipNode {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
dirent.modeType = fi.Mode() & os.ModeType
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !dirent.IsDir() {
|
||||
if !info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
} else if !dirent.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If get here, then specified pathname refers to a directory.
|
||||
deChildren, err := ReadDirents(osPathname, options.ScratchBuffer)
|
||||
// If get here, then specified pathname refers to a directory or a
|
||||
// symbolic link to a directory.
|
||||
|
||||
var ds scanner
|
||||
|
||||
if options.Unsorted {
|
||||
// When upstream does not request a sorted iteration, it's more memory
|
||||
// efficient to read a single child at a time from the file system.
|
||||
ds, err = NewScanner(osPathname)
|
||||
} else {
|
||||
// When upstream wants a sorted iteration, we must read the entire
|
||||
// directory and sort through the child names, and then iterate on each
|
||||
// child.
|
||||
ds, err = newSortedScanner(osPathname, options.ScratchBuffer)
|
||||
}
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "cannot ReadDirents")
|
||||
if action := options.ErrorCallback(osPathname, err); action == SkipNode {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if !options.Unsorted {
|
||||
sort.Sort(deChildren) // sort children entries unless upstream says to leave unsorted
|
||||
}
|
||||
|
||||
for _, deChild := range deChildren {
|
||||
for ds.Scan() {
|
||||
deChild, err := ds.Dirent()
|
||||
osChildname := filepath.Join(osPathname, deChild.name)
|
||||
err = walk(osChildname, deChild, options)
|
||||
if err != nil {
|
||||
if err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
// If received skipdir on a directory, stop processing that
|
||||
// directory, but continue to its siblings. If received skipdir on a
|
||||
// non-directory, stop processing remaining siblings.
|
||||
if deChild.IsSymlink() {
|
||||
// Only need to Stat entry if platform did not already have
|
||||
// os.ModeDir set, such as would be the case for unix like
|
||||
// operating systems. (This guard eliminates extra os.Stat check
|
||||
// on Windows.)
|
||||
if !deChild.IsDir() {
|
||||
// Resolve symbolic link referent to determine whether node
|
||||
// is directory or not.
|
||||
referent, err := os.Readlink(osChildname)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "cannot Readlink")
|
||||
if action := options.ErrorCallback(osChildname, err); action == SkipNode {
|
||||
continue // with next child
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var osp string
|
||||
if filepath.IsAbs(referent) {
|
||||
osp = referent
|
||||
} else {
|
||||
osp = filepath.Join(osPathname, referent)
|
||||
}
|
||||
|
||||
fi, err := os.Stat(osp)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "cannot Stat")
|
||||
if action := options.ErrorCallback(osp, err); action == SkipNode {
|
||||
continue // with next child
|
||||
}
|
||||
return err
|
||||
}
|
||||
deChild.modeType = fi.Mode() & os.ModeType
|
||||
}
|
||||
}
|
||||
if !deChild.IsDir() {
|
||||
// If not directory, return immediately, thus skipping remainder
|
||||
// of siblings.
|
||||
if action := options.ErrorCallback(osChildname, err); action == SkipNode {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
err = walk(osChildname, deChild, options)
|
||||
debug("osChildname: %q; error: %v\n", osChildname, err)
|
||||
if err == nil || err == SkipThis {
|
||||
continue
|
||||
}
|
||||
if err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
// When received SkipDir on a directory or a symbolic link to a
|
||||
// directory, stop processing that directory but continue processing
|
||||
// siblings. When received on a non-directory, stop processing
|
||||
// remaining siblings.
|
||||
isDir, err := deChild.IsDirOrSymlinkToDir()
|
||||
if err != nil {
|
||||
if action := options.ErrorCallback(osChildname, err); action == SkipNode {
|
||||
continue // ignore and continue with next sibling
|
||||
}
|
||||
return err // caller does not approve of this error
|
||||
}
|
||||
if !isDir {
|
||||
break // stop processing remaining siblings, but allow post children callback
|
||||
}
|
||||
// continue processing remaining siblings
|
||||
}
|
||||
if err = ds.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.PostChildrenCallback == nil {
|
||||
@@ -359,7 +372,6 @@ func walk(osPathname string, dirent *Dirent, options *Options) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = errors.Wrap(err, "PostChildrenCallback") // wrap potential errors returned by callback
|
||||
if action := options.ErrorCallback(osPathname, err); action == SkipNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user