github.com/3JoB/vfs@v1.0.0/filesystem.go (about) 1 package vfs 2 3 import ( 4 "errors" 5 "io" 6 "os" 7 "strings" 8 ) 9 10 var ( 11 // ErrIsDirectory is returned if a file is a directory 12 ErrIsDirectory = errors.New("is directory") 13 14 // ErrNotDirectory is returned if a file is not a directory 15 ErrNotDirectory = errors.New("is not a directory") 16 ) 17 18 // Filesystem represents an abstract filesystem 19 type Filesystem interface { 20 PathSeparator() uint8 21 OpenFile(name string, flag int, perm os.FileMode) (File, error) 22 Remove(name string) error 23 24 // RemoveAll(path string) error 25 Rename(oldpath, newpath string) error 26 27 Mkdir(name string, perm os.FileMode) error 28 29 Symlink(oldname, newname string) error 30 31 // TempDir() string 32 // Chmod(name string, mode FileMode) error 33 // Chown(name string, uid, gid int) error 34 Stat(name string) (os.FileInfo, error) 35 36 Lstat(name string) (os.FileInfo, error) 37 ReadDir(path string) ([]os.FileInfo, error) 38 } 39 40 // File represents a File with common operations. 41 // It differs from os.File so e.g. Stat() needs to be called from the Filesystem instead. 42 // 43 // osfile.Stat() -> filesystem.Stat(file.Name()) 44 type File interface { 45 Name() string 46 Sync() error 47 48 // Truncate shrinks or extends the size of the File to the specified size. 49 Truncate(int64) error 50 51 io.Reader 52 io.ReaderAt 53 io.Writer 54 io.Seeker 55 io.Closer 56 } 57 58 // Create creates the named file mode 0666 (before umask) on the given Filesystem, 59 // truncating it if it already exists. 60 // The associated file descriptor has mode os.O_RDWR. 61 // If there is an error, it will be of type *os.PathError. 62 func Create(fs Filesystem, name string) (File, error) { 63 return fs.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) 64 } 65 66 // Open opens the named file on the given Filesystem for reading. 67 // If successful, methods on the returned file can be used for reading. 68 // The associated file descriptor has mode os.O_RDONLY. 69 // If there is an error, it will be of type *PathError. 70 func Open(fs Filesystem, name string) (File, error) { 71 return fs.OpenFile(name, os.O_RDONLY, 0) 72 } 73 74 // MkdirAll creates a directory named path on the given Filesystem, 75 // along with any necessary parents, and returns nil, 76 // or else returns an error. 77 // The permission bits perm are used for all 78 // directories that MkdirAll creates. 79 // If path is already a directory, MkdirAll does nothing 80 // and returns nil. 81 func MkdirAll(fs Filesystem, path string, perm os.FileMode) error { 82 if dir, err := fs.Stat(path); err == nil { 83 if dir.IsDir() { 84 return nil 85 } 86 return &os.PathError{Op: "mkdir", Path: path, Err: ErrNotDirectory} 87 } 88 89 parts := SplitPath(path, string(fs.PathSeparator())) 90 if len(parts) > 1 { 91 // Create parent 92 err := MkdirAll(fs, strings.Join(parts[0:len(parts)-1], string(fs.PathSeparator())), perm) 93 if err != nil { 94 return err 95 } 96 } 97 98 // Parent now exists; invoke Mkdir and use its result. 99 err := fs.Mkdir(path, perm) 100 if err != nil { 101 // Handle arguments like "foo/." by 102 // double-checking that directory doesn't exist. 103 dir, err1 := fs.Lstat(path) 104 if err1 == nil && dir.IsDir() { 105 return nil 106 } 107 return err 108 } 109 return nil 110 } 111 112 // RemoveAll removes path and any children it contains. 113 // It removes everything it can but returns the first error 114 // it encounters. If the path does not exist, RemoveAll 115 // returns nil. 116 func RemoveAll(fs Filesystem, path string) error { 117 if err := fs.Remove(path); err == nil || os.IsNotExist(err) { 118 return nil 119 } 120 121 // We could not delete it, so might be a directory 122 fis, err := fs.ReadDir(path) 123 if err != nil { 124 if os.IsNotExist(err) { 125 return nil 126 } 127 return err 128 } 129 130 // Remove contents & return first error. 131 err = nil 132 for _, fi := range fis { 133 err1 := RemoveAll(fs, path+string(fs.PathSeparator())+fi.Name()) 134 if err == nil { 135 err = err1 136 } 137 } 138 139 // Remove directory itself. 140 err1 := fs.Remove(path) 141 if err1 == nil || os.IsNotExist(err1) { 142 return nil 143 } 144 if err == nil { 145 err = err1 146 } 147 return err 148 }