...

Source file src/io/fs/walk.go

Documentation: io/fs

		 1  // Copyright 2020 The Go Authors. All rights reserved.
		 2  // Use of this source code is governed by a BSD-style
		 3  // license that can be found in the LICENSE file.
		 4  
		 5  package fs
		 6  
		 7  import (
		 8  	"errors"
		 9  	"path"
		10  )
		11  
		12  // SkipDir is used as a return value from WalkDirFuncs to indicate that
		13  // the directory named in the call is to be skipped. It is not returned
		14  // as an error by any function.
		15  var SkipDir = errors.New("skip this directory")
		16  
		17  // WalkDirFunc is the type of the function called by WalkDir to visit
		18  // each file or directory.
		19  //
		20  // The path argument contains the argument to WalkDir as a prefix.
		21  // That is, if WalkDir is called with root argument "dir" and finds a file
		22  // named "a" in that directory, the walk function will be called with
		23  // argument "dir/a".
		24  //
		25  // The d argument is the fs.DirEntry for the named path.
		26  //
		27  // The error result returned by the function controls how WalkDir
		28  // continues. If the function returns the special value SkipDir, WalkDir
		29  // skips the current directory (path if d.IsDir() is true, otherwise
		30  // path's parent directory). Otherwise, if the function returns a non-nil
		31  // error, WalkDir stops entirely and returns that error.
		32  //
		33  // The err argument reports an error related to path, signaling that
		34  // WalkDir will not walk into that directory. The function can decide how
		35  // to handle that error; as described earlier, returning the error will
		36  // cause WalkDir to stop walking the entire tree.
		37  //
		38  // WalkDir calls the function with a non-nil err argument in two cases.
		39  //
		40  // First, if the initial fs.Stat on the root directory fails, WalkDir
		41  // calls the function with path set to root, d set to nil, and err set to
		42  // the error from fs.Stat.
		43  //
		44  // Second, if a directory's ReadDir method fails, WalkDir calls the
		45  // function with path set to the directory's path, d set to an
		46  // fs.DirEntry describing the directory, and err set to the error from
		47  // ReadDir. In this second case, the function is called twice with the
		48  // path of the directory: the first call is before the directory read is
		49  // attempted and has err set to nil, giving the function a chance to
		50  // return SkipDir and avoid the ReadDir entirely. The second call is
		51  // after a failed ReadDir and reports the error from ReadDir.
		52  // (If ReadDir succeeds, there is no second call.)
		53  //
		54  // The differences between WalkDirFunc compared to filepath.WalkFunc are:
		55  //
		56  //	 - The second argument has type fs.DirEntry instead of fs.FileInfo.
		57  //	 - The function is called before reading a directory, to allow SkipDir
		58  //		 to bypass the directory read entirely.
		59  //	 - If a directory read fails, the function is called a second time
		60  //		 for that directory to report the error.
		61  //
		62  type WalkDirFunc func(path string, d DirEntry, err error) error
		63  
		64  // walkDir recursively descends path, calling walkDirFn.
		65  func walkDir(fsys FS, name string, d DirEntry, walkDirFn WalkDirFunc) error {
		66  	if err := walkDirFn(name, d, nil); err != nil || !d.IsDir() {
		67  		if err == SkipDir && d.IsDir() {
		68  			// Successfully skipped directory.
		69  			err = nil
		70  		}
		71  		return err
		72  	}
		73  
		74  	dirs, err := ReadDir(fsys, name)
		75  	if err != nil {
		76  		// Second call, to report ReadDir error.
		77  		err = walkDirFn(name, d, err)
		78  		if err != nil {
		79  			return err
		80  		}
		81  	}
		82  
		83  	for _, d1 := range dirs {
		84  		name1 := path.Join(name, d1.Name())
		85  		if err := walkDir(fsys, name1, d1, walkDirFn); err != nil {
		86  			if err == SkipDir {
		87  				break
		88  			}
		89  			return err
		90  		}
		91  	}
		92  	return nil
		93  }
		94  
		95  // WalkDir walks the file tree rooted at root, calling fn for each file or
		96  // directory in the tree, including root.
		97  //
		98  // All errors that arise visiting files and directories are filtered by fn:
		99  // see the fs.WalkDirFunc documentation for details.
	 100  //
	 101  // The files are walked in lexical order, which makes the output deterministic
	 102  // but requires WalkDir to read an entire directory into memory before proceeding
	 103  // to walk that directory.
	 104  //
	 105  // WalkDir does not follow symbolic links found in directories,
	 106  // but if root itself is a symbolic link, its target will be walked.
	 107  func WalkDir(fsys FS, root string, fn WalkDirFunc) error {
	 108  	info, err := Stat(fsys, root)
	 109  	if err != nil {
	 110  		err = fn(root, nil, err)
	 111  	} else {
	 112  		err = walkDir(fsys, root, &statDirEntry{info}, fn)
	 113  	}
	 114  	if err == SkipDir {
	 115  		return nil
	 116  	}
	 117  	return err
	 118  }
	 119  
	 120  type statDirEntry struct {
	 121  	info FileInfo
	 122  }
	 123  
	 124  func (d *statDirEntry) Name() string						{ return d.info.Name() }
	 125  func (d *statDirEntry) IsDir() bool						 { return d.info.IsDir() }
	 126  func (d *statDirEntry) Type() FileMode					{ return d.info.Mode().Type() }
	 127  func (d *statDirEntry) Info() (FileInfo, error) { return d.info, nil }
	 128  

View as plain text