vendor: cadvisor v0.38.4

This commit is contained in:
David Porter
2020-11-13 19:52:57 +00:00
parent ec734aced7
commit 8af7405f17
396 changed files with 73154 additions and 18510 deletions

View File

@@ -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
}