| // 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 fs | 
 |  | 
 | import ( | 
 | 	"errors" | 
 | 	"path" | 
 | ) | 
 |  | 
 | // SkipDir is used as a return value from WalkDirFuncs to indicate that | 
 | // the directory named in the call is to be skipped. It is not returned | 
 | // as an error by any function. | 
 | var SkipDir = errors.New("skip this directory") | 
 |  | 
 | // 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 fs.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). 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 fs.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 fails, WalkDir calls the | 
 | // function with path set to the directory's path, d set to an | 
 | // fs.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 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 filepath.WalkFunc are: | 
 | // | 
 | //   - The second argument has type fs.DirEntry instead of fs.FileInfo. | 
 | //   - The function is called before reading a directory, to allow SkipDir | 
 | //     to bypass the directory read entirely. | 
 | //   - 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 DirEntry, err error) error | 
 |  | 
 | // walkDir recursively descends path, calling walkDirFn. | 
 | func walkDir(fsys FS, name string, d DirEntry, walkDirFn WalkDirFunc) error { | 
 | 	if err := walkDirFn(name, d, nil); err != nil || !d.IsDir() { | 
 | 		if err == SkipDir && d.IsDir() { | 
 | 			// Successfully skipped directory. | 
 | 			err = nil | 
 | 		} | 
 | 		return err | 
 | 	} | 
 |  | 
 | 	dirs, err := ReadDir(fsys, name) | 
 | 	if err != nil { | 
 | 		// Second call, to report ReadDir error. | 
 | 		err = walkDirFn(name, d, err) | 
 | 		if 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 == 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, root string, fn WalkDirFunc) error { | 
 | 	info, err := Stat(fsys, root) | 
 | 	if err != nil { | 
 | 		err = fn(root, nil, err) | 
 | 	} else { | 
 | 		err = walkDir(fsys, root, &statDirEntry{info}, fn) | 
 | 	} | 
 | 	if err == SkipDir { | 
 | 		return nil | 
 | 	} | 
 | 	return err | 
 | } | 
 |  | 
 | type statDirEntry struct { | 
 | 	info FileInfo | 
 | } | 
 |  | 
 | func (d *statDirEntry) Name() string            { return d.info.Name() } | 
 | func (d *statDirEntry) IsDir() bool             { return d.info.IsDir() } | 
 | func (d *statDirEntry) Type() FileMode          { return d.info.Mode().Type() } | 
 | func (d *statDirEntry) Info() (FileInfo, error) { return d.info, nil } |