| // Copyright 2014 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package webdav |
| |
| import ( |
| "io" |
| "net/http" |
| "os" |
| "path" |
| "path/filepath" |
| "strings" |
| ) |
| |
| // A FileSystem implements access to a collection of named files. The elements |
| // in a file path are separated by slash ('/', U+002F) characters, regardless |
| // of host operating system convention. |
| // |
| // Each method has the same semantics as the os package's function of the same |
| // name. |
| type FileSystem interface { |
| Mkdir(name string, perm os.FileMode) error |
| OpenFile(name string, flag int, perm os.FileMode) (File, error) |
| RemoveAll(name string) error |
| Stat(name string) (os.FileInfo, error) |
| } |
| |
| // A File is returned by a FileSystem's OpenFile method and can be served by a |
| // Handler. |
| type File interface { |
| http.File |
| io.Writer |
| } |
| |
| // A Dir implements FileSystem using the native file system restricted to a |
| // specific directory tree. |
| // |
| // While the FileSystem.OpenFile method takes '/'-separated paths, a Dir's |
| // string value is a filename on the native file system, not a URL, so it is |
| // separated by filepath.Separator, which isn't necessarily '/'. |
| // |
| // An empty Dir is treated as ".". |
| type Dir string |
| |
| func (d Dir) resolve(name string) string { |
| // This implementation is based on Dir.Open's code in the standard net/http package. |
| if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 || |
| strings.Contains(name, "\x00") { |
| return "" |
| } |
| dir := string(d) |
| if dir == "" { |
| dir = "." |
| } |
| return filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name))) |
| } |
| |
| func (d Dir) Mkdir(name string, perm os.FileMode) error { |
| if name = d.resolve(name); name == "" { |
| return os.ErrNotExist |
| } |
| return os.Mkdir(name, perm) |
| } |
| |
| func (d Dir) OpenFile(name string, flag int, perm os.FileMode) (File, error) { |
| if name = d.resolve(name); name == "" { |
| return nil, os.ErrNotExist |
| } |
| return os.OpenFile(name, flag, perm) |
| } |
| |
| func (d Dir) RemoveAll(name string) error { |
| if name = d.resolve(name); name == "" { |
| return os.ErrNotExist |
| } |
| if name == filepath.Clean(string(d)) { |
| // Prohibit removing the virtual root directory. |
| return os.ErrInvalid |
| } |
| return os.RemoveAll(name) |
| } |
| |
| func (d Dir) Stat(name string) (os.FileInfo, error) { |
| if name = d.resolve(name); name == "" { |
| return nil, os.ErrNotExist |
| } |
| return os.Stat(name) |
| } |
| |
| // TODO: a MemFS implementation. |