diff --git a/arduino/builder/sketch.go b/arduino/builder/sketch.go index 99cd3b368a4..d9ad4c50385 100644 --- a/arduino/builder/sketch.go +++ b/arduino/builder/sketch.go @@ -25,10 +25,16 @@ import ( "github.com/arduino/arduino-cli/arduino/globals" "github.com/arduino/arduino-cli/arduino/sketch" + "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/cli/feedback" "github.com/pkg/errors" ) +// As currently implemented on Linux, +// the maximum number of symbolic links that will be followed while resolving a pathname is 40 +const maxFileSystemDepth = 40 + var includesArduinoH = regexp.MustCompile(`(?m)^\s*#\s*include\s*[<\"]Arduino\.h[>\"]`) // QuoteCppString returns the given string as a quoted string for use with the C @@ -58,6 +64,39 @@ func SketchSaveItemCpp(item *sketch.Item, destPath string) error { return nil } +// simpleLocalWalk locally replaces filepath.Walk and/but goes through symlinks +func simpleLocalWalk(root string, maxDepth int, walkFn func(path string, info os.FileInfo, err error) error) error { + + info, err := os.Stat(root) + + if err != nil { + return walkFn(root, nil, err) + } + + err = walkFn(root, info, err) + if err == filepath.SkipDir { + return nil + } + + if info.IsDir() { + if maxDepth <= 0 { + return walkFn(root, info, errors.New("Filesystem bottom is too deep (directory recursion or filesystem really deep): "+root)) + } + maxDepth-- + files, err := ioutil.ReadDir(root) + if err == nil { + for _, file := range files { + err = simpleLocalWalk(root+string(os.PathSeparator)+file.Name(), maxDepth, walkFn) + if err == filepath.SkipDir { + return nil + } + } + } + } + + return nil +} + // SketchLoad collects all the files composing a sketch. // The parameter `sketchPath` holds a path pointing to a single sketch file or a sketch folder, // the path must be absolute. @@ -79,6 +118,14 @@ func SketchLoad(sketchPath, buildPath string) (*sketch.Sketch, error) { return nil, errors.Wrap(err, "unable to find the main sketch file") } f.Close() + // ensure it is not a directory + info, err := os.Stat(mainSketchFile) + if err != nil { + return nil, errors.Wrap(err, "unable to check the main sketch file") + } + if info.IsDir() { + return nil, errors.Wrap(errors.New(mainSketchFile), "sketch must not be a directory") + } } else { sketchFolder = filepath.Dir(sketchPath) mainSketchFile = sketchPath @@ -86,7 +133,13 @@ func SketchLoad(sketchPath, buildPath string) (*sketch.Sketch, error) { // collect all the sketch files var files []string - err = filepath.Walk(sketchFolder, func(path string, info os.FileInfo, err error) error { + err = simpleLocalWalk(sketchFolder, maxFileSystemDepth, func(path string, info os.FileInfo, err error) error { + + if err != nil { + feedback.Errorf("Error during sketch processing: %v", err) + os.Exit(errorcodes.ErrGeneric) + } + // ignore hidden files and skip hidden directories if strings.HasPrefix(info.Name(), ".") { if info.IsDir() {