// This file is part of arduino-cli. // // Copyright 2020 ARDUINO SA (http://www.arduino.cc/) // // This software is released under the GNU General Public License version 3, // which covers the main part of arduino-cli. // The terms of this license can be found at: // https://www.gnu.org/licenses/gpl-3.0.en.html // // You can be released from the requirements of the above licenses by purchasing // a commercial license. Buying such a license is mandatory if you want to // modify or otherwise use the software for commercial activities involving the // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. package gohasissues import ( "io/ioutil" "os" "path/filepath" "sort" ) func Walk(root string, walkFn filepath.WalkFunc) error { info, err := os.Stat(root) if err != nil { return walkFn(root, nil, err) } return walk(root, info, walkFn) } func walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error { err := walkFn(path, info, nil) if err != nil { if info.IsDir() && err == filepath.SkipDir { return nil } return err } if !info.IsDir() { return nil } names, err := readDirNames(path) if err != nil { return walkFn(path, info, err) } for _, name := range names { filename := filepath.Join(path, name) fileInfo, err := os.Stat(filename) if err != nil { if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { return err } } else { err = walk(filename, fileInfo, walkFn) if err != nil { if !fileInfo.IsDir() || err != filepath.SkipDir { return err } } } } return nil } // readDirNames reads the directory named by dirname and returns // a sorted list of directory entries. func readDirNames(dirname string) ([]string, error) { f, err := os.Open(dirname) if err != nil { return nil, err } names, err := f.Readdirnames(-1) f.Close() if err != nil { return nil, err } sort.Strings(names) return names, nil } func ReadDir(dirname string) ([]os.FileInfo, error) { infos, err := ioutil.ReadDir(dirname) if err != nil { return nil, err } for idx, info := range infos { info, err := resolveSymlink(dirname, info) if err != nil { // unresolvable symlinks should be skipped silently continue } infos[idx] = info } return infos, nil } func resolveSymlink(parentFolder string, info os.FileInfo) (os.FileInfo, error) { if !isSymlink(info) { return info, nil } return os.Stat(filepath.Join(parentFolder, info.Name())) } func isSymlink(info os.FileInfo) bool { return info.Mode()&os.ModeSymlink != 0 }