2020-09-01 20:12:57 -06:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"runtime"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/spf13/afero"
|
|
|
|
)
|
|
|
|
|
2020-09-04 13:00:23 -06:00
|
|
|
// RecursiveBasePathFs is an overloaded afero.BasePathFs that has a recursive RealPath().
|
|
|
|
type RecursiveBasePathFs struct {
|
2020-09-01 20:12:57 -06:00
|
|
|
afero.Fs
|
|
|
|
source afero.Fs
|
|
|
|
path string
|
|
|
|
}
|
|
|
|
|
2020-09-04 13:00:23 -06:00
|
|
|
// NewRecursiveBasePathFs returns a new RecursiveBasePathFs.
|
|
|
|
func NewRecursiveBasePathFs(source afero.Fs, path string) *RecursiveBasePathFs {
|
|
|
|
return &RecursiveBasePathFs{
|
2020-09-01 20:12:57 -06:00
|
|
|
Fs: afero.NewBasePathFs(source, path),
|
|
|
|
source: source,
|
|
|
|
path: path,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-04 13:00:23 -06:00
|
|
|
// RealPath returns the real path to a file, "breaking out" of the RecursiveBasePathFs.
|
|
|
|
func (b *RecursiveBasePathFs) RealPath(name string) (path string, err error) {
|
2020-09-01 20:12:57 -06:00
|
|
|
if err := validateBasePathName(name); err != nil {
|
|
|
|
return name, err
|
|
|
|
}
|
|
|
|
|
|
|
|
bpath := filepath.Clean(b.path)
|
|
|
|
path = filepath.Clean(filepath.Join(bpath, name))
|
|
|
|
|
2020-09-04 13:00:23 -06:00
|
|
|
if parentRecursiveBasePathFs, ok := b.source.(*RecursiveBasePathFs); ok {
|
|
|
|
return parentRecursiveBasePathFs.RealPath(path)
|
|
|
|
} else if parentRecursiveBasePathFs, ok := b.source.(*afero.BasePathFs); ok {
|
|
|
|
return parentRecursiveBasePathFs.RealPath(path)
|
2020-09-01 20:12:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if !strings.HasPrefix(path, bpath) {
|
|
|
|
return name, os.ErrNotExist
|
|
|
|
}
|
|
|
|
|
|
|
|
return path, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func validateBasePathName(name string) error {
|
|
|
|
if runtime.GOOS != "windows" {
|
|
|
|
// Not much to do here;
|
|
|
|
// the virtual file paths all look absolute on *nix.
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// On Windows a common mistake would be to provide an absolute OS path
|
|
|
|
// We could strip out the base part, but that would not be very portable.
|
|
|
|
if filepath.IsAbs(name) {
|
|
|
|
return os.ErrNotExist
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|