vendor/github.com/spf13/afero/basepath.go
changeset 242 2a9ec03fe5a1
child 256 6d9efbef00a9
equal deleted inserted replaced
241:e77dad242f4c 242:2a9ec03fe5a1
       
     1 package afero
       
     2 
       
     3 import (
       
     4 	"os"
       
     5 	"path/filepath"
       
     6 	"runtime"
       
     7 	"strings"
       
     8 	"time"
       
     9 )
       
    10 
       
    11 var _ Lstater = (*BasePathFs)(nil)
       
    12 
       
    13 // The BasePathFs restricts all operations to a given path within an Fs.
       
    14 // The given file name to the operations on this Fs will be prepended with
       
    15 // the base path before calling the base Fs.
       
    16 // Any file name (after filepath.Clean()) outside this base path will be
       
    17 // treated as non existing file.
       
    18 //
       
    19 // Note that it does not clean the error messages on return, so you may
       
    20 // reveal the real path on errors.
       
    21 type BasePathFs struct {
       
    22 	source Fs
       
    23 	path   string
       
    24 }
       
    25 
       
    26 type BasePathFile struct {
       
    27 	File
       
    28 	path string
       
    29 }
       
    30 
       
    31 func (f *BasePathFile) Name() string {
       
    32 	sourcename := f.File.Name()
       
    33 	return strings.TrimPrefix(sourcename, filepath.Clean(f.path))
       
    34 }
       
    35 
       
    36 func NewBasePathFs(source Fs, path string) Fs {
       
    37 	return &BasePathFs{source: source, path: path}
       
    38 }
       
    39 
       
    40 // on a file outside the base path it returns the given file name and an error,
       
    41 // else the given file with the base path prepended
       
    42 func (b *BasePathFs) RealPath(name string) (path string, err error) {
       
    43 	if err := validateBasePathName(name); err != nil {
       
    44 		return name, err
       
    45 	}
       
    46 
       
    47 	bpath := filepath.Clean(b.path)
       
    48 	path = filepath.Clean(filepath.Join(bpath, name))
       
    49 	if !strings.HasPrefix(path, bpath) {
       
    50 		return name, os.ErrNotExist
       
    51 	}
       
    52 
       
    53 	return path, nil
       
    54 }
       
    55 
       
    56 func validateBasePathName(name string) error {
       
    57 	if runtime.GOOS != "windows" {
       
    58 		// Not much to do here;
       
    59 		// the virtual file paths all look absolute on *nix.
       
    60 		return nil
       
    61 	}
       
    62 
       
    63 	// On Windows a common mistake would be to provide an absolute OS path
       
    64 	// We could strip out the base part, but that would not be very portable.
       
    65 	if filepath.IsAbs(name) {
       
    66 		return os.ErrNotExist
       
    67 	}
       
    68 
       
    69 	return nil
       
    70 }
       
    71 
       
    72 func (b *BasePathFs) Chtimes(name string, atime, mtime time.Time) (err error) {
       
    73 	if name, err = b.RealPath(name); err != nil {
       
    74 		return &os.PathError{Op: "chtimes", Path: name, Err: err}
       
    75 	}
       
    76 	return b.source.Chtimes(name, atime, mtime)
       
    77 }
       
    78 
       
    79 func (b *BasePathFs) Chmod(name string, mode os.FileMode) (err error) {
       
    80 	if name, err = b.RealPath(name); err != nil {
       
    81 		return &os.PathError{Op: "chmod", Path: name, Err: err}
       
    82 	}
       
    83 	return b.source.Chmod(name, mode)
       
    84 }
       
    85 
       
    86 func (b *BasePathFs) Name() string {
       
    87 	return "BasePathFs"
       
    88 }
       
    89 
       
    90 func (b *BasePathFs) Stat(name string) (fi os.FileInfo, err error) {
       
    91 	if name, err = b.RealPath(name); err != nil {
       
    92 		return nil, &os.PathError{Op: "stat", Path: name, Err: err}
       
    93 	}
       
    94 	return b.source.Stat(name)
       
    95 }
       
    96 
       
    97 func (b *BasePathFs) Rename(oldname, newname string) (err error) {
       
    98 	if oldname, err = b.RealPath(oldname); err != nil {
       
    99 		return &os.PathError{Op: "rename", Path: oldname, Err: err}
       
   100 	}
       
   101 	if newname, err = b.RealPath(newname); err != nil {
       
   102 		return &os.PathError{Op: "rename", Path: newname, Err: err}
       
   103 	}
       
   104 	return b.source.Rename(oldname, newname)
       
   105 }
       
   106 
       
   107 func (b *BasePathFs) RemoveAll(name string) (err error) {
       
   108 	if name, err = b.RealPath(name); err != nil {
       
   109 		return &os.PathError{Op: "remove_all", Path: name, Err: err}
       
   110 	}
       
   111 	return b.source.RemoveAll(name)
       
   112 }
       
   113 
       
   114 func (b *BasePathFs) Remove(name string) (err error) {
       
   115 	if name, err = b.RealPath(name); err != nil {
       
   116 		return &os.PathError{Op: "remove", Path: name, Err: err}
       
   117 	}
       
   118 	return b.source.Remove(name)
       
   119 }
       
   120 
       
   121 func (b *BasePathFs) OpenFile(name string, flag int, mode os.FileMode) (f File, err error) {
       
   122 	if name, err = b.RealPath(name); err != nil {
       
   123 		return nil, &os.PathError{Op: "openfile", Path: name, Err: err}
       
   124 	}
       
   125 	sourcef, err := b.source.OpenFile(name, flag, mode)
       
   126 	if err != nil {
       
   127 		return nil, err
       
   128 	}
       
   129 	return &BasePathFile{sourcef, b.path}, nil
       
   130 }
       
   131 
       
   132 func (b *BasePathFs) Open(name string) (f File, err error) {
       
   133 	if name, err = b.RealPath(name); err != nil {
       
   134 		return nil, &os.PathError{Op: "open", Path: name, Err: err}
       
   135 	}
       
   136 	sourcef, err := b.source.Open(name)
       
   137 	if err != nil {
       
   138 		return nil, err
       
   139 	}
       
   140 	return &BasePathFile{File: sourcef, path: b.path}, nil
       
   141 }
       
   142 
       
   143 func (b *BasePathFs) Mkdir(name string, mode os.FileMode) (err error) {
       
   144 	if name, err = b.RealPath(name); err != nil {
       
   145 		return &os.PathError{Op: "mkdir", Path: name, Err: err}
       
   146 	}
       
   147 	return b.source.Mkdir(name, mode)
       
   148 }
       
   149 
       
   150 func (b *BasePathFs) MkdirAll(name string, mode os.FileMode) (err error) {
       
   151 	if name, err = b.RealPath(name); err != nil {
       
   152 		return &os.PathError{Op: "mkdir", Path: name, Err: err}
       
   153 	}
       
   154 	return b.source.MkdirAll(name, mode)
       
   155 }
       
   156 
       
   157 func (b *BasePathFs) Create(name string) (f File, err error) {
       
   158 	if name, err = b.RealPath(name); err != nil {
       
   159 		return nil, &os.PathError{Op: "create", Path: name, Err: err}
       
   160 	}
       
   161 	sourcef, err := b.source.Create(name)
       
   162 	if err != nil {
       
   163 		return nil, err
       
   164 	}
       
   165 	return &BasePathFile{File: sourcef, path: b.path}, nil
       
   166 }
       
   167 
       
   168 func (b *BasePathFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
       
   169 	name, err := b.RealPath(name)
       
   170 	if err != nil {
       
   171 		return nil, false, &os.PathError{Op: "lstat", Path: name, Err: err}
       
   172 	}
       
   173 	if lstater, ok := b.source.(Lstater); ok {
       
   174 		return lstater.LstatIfPossible(name)
       
   175 	}
       
   176 	fi, err := b.source.Stat(name)
       
   177 	return fi, false, err
       
   178 }
       
   179 
       
   180 // vim: ts=4 sw=4 noexpandtab nolist syn=go