| // Copyright 2024 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 fsys |
| |
| import ( |
| "io/fs" |
| "path/filepath" |
| ) |
| |
| // Copied from path/filepath. |
| |
| // WalkDir is like filepath.WalkDir but over the virtual file system. |
| func WalkDir(root string, fn fs.WalkDirFunc) error { |
| info, err := Lstat(root) |
| if err != nil { |
| err = fn(root, nil, err) |
| } else { |
| err = walkDir(root, fs.FileInfoToDirEntry(info), fn) |
| } |
| if err == filepath.SkipDir || err == filepath.SkipAll { |
| return nil |
| } |
| return err |
| } |
| |
| // walkDir recursively descends path, calling walkDirFn. |
| func walkDir(path string, d fs.DirEntry, walkDirFn fs.WalkDirFunc) error { |
| if err := walkDirFn(path, d, nil); err != nil || !d.IsDir() { |
| if err == filepath.SkipDir && d.IsDir() { |
| // Successfully skipped directory. |
| err = nil |
| } |
| return err |
| } |
| |
| dirs, err := ReadDir(path) |
| if err != nil { |
| // Second call, to report ReadDir error. |
| err = walkDirFn(path, d, err) |
| if err != nil { |
| if err == filepath.SkipDir && d.IsDir() { |
| err = nil |
| } |
| return err |
| } |
| } |
| |
| for _, d1 := range dirs { |
| path1 := filepath.Join(path, d1.Name()) |
| if err := walkDir(path1, d1, walkDirFn); err != nil { |
| if err == filepath.SkipDir { |
| break |
| } |
| return err |
| } |
| } |
| return nil |
| } |