Neale Pickett
·
2021-03-26
basepath.go
1package transpile
2
3import (
4 "os"
5 "path/filepath"
6 "runtime"
7 "strings"
8
9 "github.com/spf13/afero"
10)
11
12// RecursiveBasePathFs is an overloaded afero.BasePathFs that has a recursive RealPath().
13type RecursiveBasePathFs struct {
14 afero.Fs
15 source afero.Fs
16 path string
17}
18
19// NewRecursiveBasePathFs returns a new RecursiveBasePathFs.
20func NewRecursiveBasePathFs(source afero.Fs, path string) *RecursiveBasePathFs {
21 ret := &RecursiveBasePathFs{
22 source: source,
23 path: path,
24 }
25 if path == "" {
26 ret.Fs = source
27 } else {
28 ret.Fs = afero.NewBasePathFs(source, path)
29 }
30 return ret
31}
32
33// RealPath returns the real path to a file, "breaking out" of the RecursiveBasePathFs.
34func (b *RecursiveBasePathFs) RealPath(name string) (path string, err error) {
35 if err := validateBasePathName(name); err != nil {
36 return name, err
37 }
38
39 bpath := filepath.Clean(b.path)
40 path = filepath.Clean(filepath.Join(bpath, name))
41
42 switch pfs := b.source.(type) {
43 case *RecursiveBasePathFs:
44 return pfs.RealPath(path)
45 case *afero.BasePathFs:
46 return pfs.RealPath(path)
47 case *afero.OsFs:
48 return path, nil
49 }
50
51 if !strings.HasPrefix(path, bpath) {
52 return name, os.ErrNotExist
53 }
54
55 return path, nil
56}
57
58func validateBasePathName(name string) error {
59 if runtime.GOOS != "windows" {
60 // Not much to do here;
61 // the virtual file paths all look absolute on *nix.
62 return nil
63 }
64
65 // On Windows a common mistake would be to provide an absolute OS path
66 // We could strip out the base part, but that would not be very portable.
67 if filepath.IsAbs(name) {
68 return os.ErrNotExist
69 }
70
71 return nil
72}