mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
#2834 - follow symlink
This commit is contained in:
@@ -5,10 +5,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/log"
|
"github.com/grafana/grafana/pkg/log"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PluginMeta struct {
|
type PluginMeta struct {
|
||||||
@@ -36,7 +36,7 @@ func scan(pluginDir string) error {
|
|||||||
pluginPath: pluginDir,
|
pluginPath: pluginDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := filepath.Walk(pluginDir, scanner.walker); err != nil {
|
if err := util.Walk(pluginDir, true, true, scanner.walker); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
98
pkg/util/filepath.go
Normal file
98
pkg/util/filepath.go
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
//WalkSkipDir is the Error returned when we want to skip descending into a directory
|
||||||
|
var WalkSkipDir = errors.New("skip this directory")
|
||||||
|
|
||||||
|
//WalkFunc is a callback function called for each path as a directory is walked
|
||||||
|
//If resolvedPath != "", then we are following symbolic links.
|
||||||
|
type WalkFunc func(resolvedPath string, info os.FileInfo, err error) error
|
||||||
|
|
||||||
|
//Walk walks a path, optionally following symbolic links, and for each path,
|
||||||
|
//it calls the walkFn passed.
|
||||||
|
//
|
||||||
|
//It is similar to filepath.Walk, except that it supports symbolic links and
|
||||||
|
//can detect infinite loops while following sym links.
|
||||||
|
//It solves the issue where your WalkFunc needs a path relative to the symbolic link
|
||||||
|
//(resolving links within walkfunc loses the path to the symbolic link for each traversal).
|
||||||
|
func Walk(path string, followSymlinks bool, detectSymlinkInfiniteLoop bool, walkFn WalkFunc) error {
|
||||||
|
info, err := os.Lstat(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var symlinkPathsFollowed map[string]bool
|
||||||
|
var resolvedPath string
|
||||||
|
if followSymlinks {
|
||||||
|
resolvedPath = path
|
||||||
|
if detectSymlinkInfiniteLoop {
|
||||||
|
symlinkPathsFollowed = make(map[string]bool, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return walk(path, info, resolvedPath, symlinkPathsFollowed, walkFn)
|
||||||
|
}
|
||||||
|
|
||||||
|
//walk walks the path. It is a helper/sibling function to Walk.
|
||||||
|
//It takes a resolvedPath into consideration. This way, paths being walked are
|
||||||
|
//always relative to the path argument, even if symbolic links were resolved).
|
||||||
|
//
|
||||||
|
//If resolvedPath is "", then we are not following symbolic links.
|
||||||
|
//If symlinkPathsFollowed is not nil, then we need to detect infinite loop.
|
||||||
|
func walk(path string, info os.FileInfo, resolvedPath string,
|
||||||
|
symlinkPathsFollowed map[string]bool, walkFn WalkFunc) error {
|
||||||
|
if info == nil {
|
||||||
|
return errors.New("Walk: Nil FileInfo passed")
|
||||||
|
}
|
||||||
|
err := walkFn(resolvedPath, info, nil)
|
||||||
|
if err != nil {
|
||||||
|
if info.IsDir() && err == WalkSkipDir {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resolvedPath != "" && info.Mode()&os.ModeSymlink == os.ModeSymlink {
|
||||||
|
path2, err := os.Readlink(resolvedPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//vout("SymLink Path: %v, links to: %v", resolvedPath, path2)
|
||||||
|
if symlinkPathsFollowed != nil {
|
||||||
|
if _, ok := symlinkPathsFollowed[path2]; ok {
|
||||||
|
errMsg := "Potential SymLink Infinite Loop. Path: %v, Link To: %v"
|
||||||
|
return fmt.Errorf(errMsg, resolvedPath, path2)
|
||||||
|
} else {
|
||||||
|
symlinkPathsFollowed[path2] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info2, err := os.Lstat(path2)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return walk(path, info2, path2, symlinkPathsFollowed, walkFn)
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
list, err := ioutil.ReadDir(path)
|
||||||
|
if err != nil {
|
||||||
|
return walkFn(resolvedPath, info, err)
|
||||||
|
}
|
||||||
|
for _, fileInfo := range list {
|
||||||
|
path2 := filepath.Join(path, fileInfo.Name())
|
||||||
|
var resolvedPath2 string
|
||||||
|
if resolvedPath != "" {
|
||||||
|
resolvedPath2 = filepath.Join(resolvedPath, fileInfo.Name())
|
||||||
|
}
|
||||||
|
err = walk(path2, fileInfo, resolvedPath2, symlinkPathsFollowed, walkFn)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user