mirror of
https://github.com/versity/versitygw.git
synced 2026-08-18 13:16:31 +00:00
Base import of cutdown version of io/fs/walk.go from golang as walker.go
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package backend
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"path"
|
||||
)
|
||||
|
||||
// WalkDirFunc is the type of the function called by [WalkDir] to visit
|
||||
// each file or directory.
|
||||
//
|
||||
// The path argument contains the argument to [WalkDir] as a prefix.
|
||||
// That is, if WalkDir is called with root argument "dir" and finds a file
|
||||
// named "a" in that directory, the walk function will be called with
|
||||
// argument "dir/a".
|
||||
//
|
||||
// The d argument is the [DirEntry] for the named path.
|
||||
//
|
||||
// The error result returned by the function controls how [WalkDir]
|
||||
// continues. If the function returns the special value [SkipDir], WalkDir
|
||||
// skips the current directory (path if d.IsDir() is true, otherwise
|
||||
// path's parent directory). If the function returns the special value
|
||||
// [SkipAll], WalkDir skips all remaining files and directories. Otherwise,
|
||||
// if the function returns a non-nil error, WalkDir stops entirely and
|
||||
// returns that error.
|
||||
//
|
||||
// The err argument reports an error related to path, signaling that
|
||||
// [WalkDir] will not walk into that directory. The function can decide how
|
||||
// to handle that error; as described earlier, returning the error will
|
||||
// cause WalkDir to stop walking the entire tree.
|
||||
//
|
||||
// [WalkDir] calls the function with a non-nil err argument in two cases.
|
||||
//
|
||||
// First, if the initial [Stat] on the root directory fails, WalkDir
|
||||
// calls the function with path set to root, d set to nil, and err set to
|
||||
// the error from [fs.Stat].
|
||||
//
|
||||
// Second, if a directory's ReadDir method (see [ReadDirFile]) fails, WalkDir calls the
|
||||
// function with path set to the directory's path, d set to an
|
||||
// [DirEntry] describing the directory, and err set to the error from
|
||||
// ReadDir. In this second case, the function is called twice with the
|
||||
// path of the directory: the first call is before the directory read is
|
||||
// attempted and has err set to nil, giving the function a chance to
|
||||
// return [SkipDir] or [SkipAll] and avoid the ReadDir entirely. The second call
|
||||
// is after a failed ReadDir and reports the error from ReadDir.
|
||||
// (If ReadDir succeeds, there is no second call.)
|
||||
//
|
||||
// The differences between WalkDirFunc compared to [path/filepath.WalkFunc] are:
|
||||
//
|
||||
// - The second argument has type [DirEntry] instead of [FileInfo].
|
||||
// - The function is called before reading a directory, to allow [SkipDir]
|
||||
// or [SkipAll] to bypass the directory read entirely or skip all remaining
|
||||
// files and directories respectively.
|
||||
// - If a directory read fails, the function is called a second time
|
||||
// for that directory to report the error.
|
||||
type WalkDirFunc func(path string, d fs.DirEntry, err error) error
|
||||
|
||||
// walkDir recursively descends path, calling walkDirFn.
|
||||
func walkDir(fsys fs.FS, name string, d fs.DirEntry, walkDirFn WalkDirFunc) error {
|
||||
if err := walkDirFn(name, d, nil); err != nil || !d.IsDir() {
|
||||
if err == fs.SkipDir && d.IsDir() {
|
||||
// Successfully skipped directory.
|
||||
err = nil
|
||||
}
|
||||
// return errors.New("hi " + name)
|
||||
return err
|
||||
}
|
||||
|
||||
dirs, err := fs.ReadDir(fsys, name)
|
||||
if err != nil {
|
||||
// Second call, to report ReadDir error.
|
||||
err = walkDirFn(name, d, err)
|
||||
if err != nil {
|
||||
if err == fs.SkipDir && d.IsDir() {
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, d1 := range dirs {
|
||||
name1 := path.Join(name, d1.Name())
|
||||
if err := walkDir(fsys, name1, d1, walkDirFn); err != nil {
|
||||
if err == fs.SkipDir {
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WalkDir walks the file tree rooted at root, calling fn for each file or
|
||||
// directory in the tree, including root.
|
||||
//
|
||||
// All errors that arise visiting files and directories are filtered by fn:
|
||||
// see the [fs.WalkDirFunc] documentation for details.
|
||||
//
|
||||
// The files are walked in lexical order, which makes the output deterministic
|
||||
// but requires WalkDir to read an entire directory into memory before proceeding
|
||||
// to walk that directory.
|
||||
//
|
||||
// WalkDir does not follow symbolic links found in directories,
|
||||
// but if root itself is a symbolic link, its target will be walked.
|
||||
func WalkDir(fsys fs.FS, root string, fn WalkDirFunc) error {
|
||||
info, err := fs.Stat(fsys, root)
|
||||
if err != nil {
|
||||
err = fn(root, nil, err)
|
||||
} else {
|
||||
err = walkDir(fsys, root, fs.FileInfoToDirEntry(info), fn)
|
||||
}
|
||||
if err == fs.SkipDir || err == fs.SkipAll {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user