12 // The BasePathFs restricts all operations to a given path within an Fs.
13 // The given file name to the operations on this Fs will be prepended with
14 // the base path before calling the base Fs.
15 // Any file name (after filepath.Clean()) outside this base path will be
16 // treated as non existing file.
18 // Note that it does not clean the error messages on return, so you may
19 // reveal the real path on errors.
20 type BasePathFs struct {
25 func NewBasePathFs(source Fs, path string) Fs {
26 return &BasePathFs{source: source, path: path}
29 // on a file outside the base path it returns the given file name and an error,
30 // else the given file with the base path prepended
31 func (b *BasePathFs) RealPath(name string) (path string, err error) {
32 if err := validateBasePathName(name); err != nil {
36 bpath := filepath.Clean(b.path)
37 path = filepath.Clean(filepath.Join(bpath, name))
38 if !strings.HasPrefix(path, bpath) {
39 return name, os.ErrNotExist
45 func validateBasePathName(name string) error {
46 if runtime.GOOS != "windows" {
47 // Not much to do here;
48 // the virtual file paths all look absolute on *nix.
52 // On Windows a common mistake would be to provide an absolute OS path
53 // We could strip out the base part, but that would not be very portable.
54 if filepath.IsAbs(name) {
55 return &os.PathError{Op: "realPath", Path: name, Err: errors.New("got a real OS path instead of a virtual")}
61 func (b *BasePathFs) Chtimes(name string, atime, mtime time.Time) (err error) {
62 if name, err = b.RealPath(name); err != nil {
63 return &os.PathError{Op: "chtimes", Path: name, Err: err}
65 return b.source.Chtimes(name, atime, mtime)
68 func (b *BasePathFs) Chmod(name string, mode os.FileMode) (err error) {
69 if name, err = b.RealPath(name); err != nil {
70 return &os.PathError{Op: "chmod", Path: name, Err: err}
72 return b.source.Chmod(name, mode)
75 func (b *BasePathFs) Name() string {
79 func (b *BasePathFs) Stat(name string) (fi os.FileInfo, err error) {
80 if name, err = b.RealPath(name); err != nil {
81 return nil, &os.PathError{Op: "stat", Path: name, Err: err}
83 return b.source.Stat(name)
86 func (b *BasePathFs) Rename(oldname, newname string) (err error) {
87 if oldname, err = b.RealPath(oldname); err != nil {
88 return &os.PathError{Op: "rename", Path: oldname, Err: err}
90 if newname, err = b.RealPath(newname); err != nil {
91 return &os.PathError{Op: "rename", Path: newname, Err: err}
93 return b.source.Rename(oldname, newname)
96 func (b *BasePathFs) RemoveAll(name string) (err error) {
97 if name, err = b.RealPath(name); err != nil {
98 return &os.PathError{Op: "remove_all", Path: name, Err: err}
100 return b.source.RemoveAll(name)
103 func (b *BasePathFs) Remove(name string) (err error) {
104 if name, err = b.RealPath(name); err != nil {
105 return &os.PathError{Op: "remove", Path: name, Err: err}
107 return b.source.Remove(name)
110 func (b *BasePathFs) OpenFile(name string, flag int, mode os.FileMode) (f File, err error) {
111 if name, err = b.RealPath(name); err != nil {
112 return nil, &os.PathError{Op: "openfile", Path: name, Err: err}
114 return b.source.OpenFile(name, flag, mode)
117 func (b *BasePathFs) Open(name string) (f File, err error) {
118 if name, err = b.RealPath(name); err != nil {
119 return nil, &os.PathError{Op: "open", Path: name, Err: err}
121 return b.source.Open(name)
124 func (b *BasePathFs) Mkdir(name string, mode os.FileMode) (err error) {
125 if name, err = b.RealPath(name); err != nil {
126 return &os.PathError{Op: "mkdir", Path: name, Err: err}
128 return b.source.Mkdir(name, mode)
131 func (b *BasePathFs) MkdirAll(name string, mode os.FileMode) (err error) {
132 if name, err = b.RealPath(name); err != nil {
133 return &os.PathError{Op: "mkdir", Path: name, Err: err}
135 return b.source.MkdirAll(name, mode)
138 func (b *BasePathFs) Create(name string) (f File, err error) {
139 if name, err = b.RealPath(name); err != nil {
140 return nil, &os.PathError{Op: "create", Path: name, Err: err}
142 return b.source.Create(name)
145 // vim: ts=4 sw=4 noexpandtab nolist syn=go