file.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. // Copyright 2014 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package webdav
  5. import (
  6. "io"
  7. "net/http"
  8. "os"
  9. "path"
  10. "path/filepath"
  11. "strings"
  12. "sync"
  13. "time"
  14. )
  15. // A FileSystem implements access to a collection of named files. The elements
  16. // in a file path are separated by slash ('/', U+002F) characters, regardless
  17. // of host operating system convention.
  18. //
  19. // Each method has the same semantics as the os package's function of the same
  20. // name.
  21. type FileSystem interface {
  22. Mkdir(name string, perm os.FileMode) error
  23. OpenFile(name string, flag int, perm os.FileMode) (File, error)
  24. RemoveAll(name string) error
  25. Stat(name string) (os.FileInfo, error)
  26. }
  27. // A File is returned by a FileSystem's OpenFile method and can be served by a
  28. // Handler.
  29. type File interface {
  30. http.File
  31. io.Writer
  32. }
  33. // A Dir implements FileSystem using the native file system restricted to a
  34. // specific directory tree.
  35. //
  36. // While the FileSystem.OpenFile method takes '/'-separated paths, a Dir's
  37. // string value is a filename on the native file system, not a URL, so it is
  38. // separated by filepath.Separator, which isn't necessarily '/'.
  39. //
  40. // An empty Dir is treated as ".".
  41. type Dir string
  42. func (d Dir) resolve(name string) string {
  43. // This implementation is based on Dir.Open's code in the standard net/http package.
  44. if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
  45. strings.Contains(name, "\x00") {
  46. return ""
  47. }
  48. dir := string(d)
  49. if dir == "" {
  50. dir = "."
  51. }
  52. return filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))
  53. }
  54. func (d Dir) Mkdir(name string, perm os.FileMode) error {
  55. if name = d.resolve(name); name == "" {
  56. return os.ErrNotExist
  57. }
  58. return os.Mkdir(name, perm)
  59. }
  60. func (d Dir) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
  61. if name = d.resolve(name); name == "" {
  62. return nil, os.ErrNotExist
  63. }
  64. return os.OpenFile(name, flag, perm)
  65. }
  66. func (d Dir) RemoveAll(name string) error {
  67. if name = d.resolve(name); name == "" {
  68. return os.ErrNotExist
  69. }
  70. if name == filepath.Clean(string(d)) {
  71. // Prohibit removing the virtual root directory.
  72. return os.ErrInvalid
  73. }
  74. return os.RemoveAll(name)
  75. }
  76. func (d Dir) Stat(name string) (os.FileInfo, error) {
  77. if name = d.resolve(name); name == "" {
  78. return nil, os.ErrNotExist
  79. }
  80. return os.Stat(name)
  81. }
  82. // NewMemFS returns a new in-memory FileSystem implementation.
  83. func NewMemFS() FileSystem {
  84. return &memFS{
  85. root: memFSNode{
  86. children: make(map[string]*memFSNode),
  87. mode: 0660 | os.ModeDir,
  88. modTime: time.Now(),
  89. },
  90. }
  91. }
  92. // A memFS implements FileSystem, storing all metadata and actual file data
  93. // in-memory. No limits on filesystem size are used, so it is not recommended
  94. // this be used where the clients are untrusted.
  95. //
  96. // Concurrent access is permitted. The tree structure is protected by a mutex,
  97. // and each node's contents and metadata are protected by a per-node mutex.
  98. //
  99. // TODO: Enforce file permissions.
  100. type memFS struct {
  101. mu sync.Mutex
  102. root memFSNode
  103. }
  104. // walk walks the directory tree for the fullname, calling f at each step. If f
  105. // returns an error, the walk will be aborted and return that same error.
  106. //
  107. // Each walk is atomic: fs's mutex is held for the entire operation, including
  108. // all calls to f.
  109. //
  110. // dir is the directory at that step, frag is the name fragment, and final is
  111. // whether it is the final step. For example, walking "/foo/bar/x" will result
  112. // in 3 calls to f:
  113. // - "/", "foo", false
  114. // - "/foo/", "bar", false
  115. // - "/foo/bar/", "x", true
  116. // The frag argument will be empty only if dir is the root node and the walk
  117. // ends at that root node.
  118. func (fs *memFS) walk(op, fullname string, f func(dir *memFSNode, frag string, final bool) error) error {
  119. fs.mu.Lock()
  120. defer fs.mu.Unlock()
  121. original := fullname
  122. fullname = path.Clean("/" + fullname)
  123. // Strip any leading "/"s to make fullname a relative path, as the walk
  124. // starts at fs.root.
  125. if fullname[0] == '/' {
  126. fullname = fullname[1:]
  127. }
  128. dir := &fs.root
  129. for {
  130. frag, remaining := fullname, ""
  131. i := strings.IndexRune(fullname, '/')
  132. final := i < 0
  133. if !final {
  134. frag, remaining = fullname[:i], fullname[i+1:]
  135. }
  136. if frag == "" && dir != &fs.root {
  137. panic("webdav: empty path fragment for a clean path")
  138. }
  139. if err := f(dir, frag, final); err != nil {
  140. return &os.PathError{
  141. Op: op,
  142. Path: original,
  143. Err: err,
  144. }
  145. }
  146. if final {
  147. break
  148. }
  149. child := dir.children[frag]
  150. if child == nil {
  151. return &os.PathError{
  152. Op: op,
  153. Path: original,
  154. Err: os.ErrNotExist,
  155. }
  156. }
  157. if !child.IsDir() {
  158. return &os.PathError{
  159. Op: op,
  160. Path: original,
  161. Err: os.ErrInvalid,
  162. }
  163. }
  164. dir, fullname = child, remaining
  165. }
  166. return nil
  167. }
  168. func (fs *memFS) Mkdir(name string, perm os.FileMode) error {
  169. return fs.walk("mkdir", name, func(dir *memFSNode, frag string, final bool) error {
  170. if !final {
  171. return nil
  172. }
  173. if frag == "" {
  174. return os.ErrInvalid
  175. }
  176. if _, ok := dir.children[frag]; ok {
  177. return os.ErrExist
  178. }
  179. dir.children[frag] = &memFSNode{
  180. name: frag,
  181. children: make(map[string]*memFSNode),
  182. mode: perm.Perm() | os.ModeDir,
  183. modTime: time.Now(),
  184. }
  185. return nil
  186. })
  187. }
  188. func (fs *memFS) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
  189. var ret *memFile
  190. err := fs.walk("open", name, func(dir *memFSNode, frag string, final bool) error {
  191. if !final {
  192. return nil
  193. }
  194. var n *memFSNode
  195. if frag == "" {
  196. if flag&(os.O_WRONLY|os.O_RDWR) != 0 {
  197. return os.ErrPermission
  198. }
  199. n = &fs.root
  200. } else {
  201. n = dir.children[frag]
  202. if flag&(os.O_SYNC|os.O_APPEND) != 0 {
  203. return os.ErrInvalid
  204. }
  205. if flag&os.O_CREATE != 0 {
  206. if flag&os.O_EXCL != 0 && n != nil {
  207. return os.ErrExist
  208. }
  209. if n == nil {
  210. n = &memFSNode{
  211. name: frag,
  212. mode: perm.Perm(),
  213. }
  214. dir.children[frag] = n
  215. }
  216. }
  217. if n == nil {
  218. return os.ErrNotExist
  219. }
  220. if flag&(os.O_WRONLY|os.O_RDWR) != 0 && flag&os.O_TRUNC != 0 {
  221. n.mu.Lock()
  222. n.data = nil
  223. n.mu.Unlock()
  224. }
  225. }
  226. children := make([]os.FileInfo, 0, len(n.children))
  227. for _, c := range n.children {
  228. children = append(children, c)
  229. }
  230. ret = &memFile{
  231. n: n,
  232. children: children,
  233. }
  234. return nil
  235. })
  236. if err != nil {
  237. return nil, err
  238. }
  239. return ret, nil
  240. }
  241. func (fs *memFS) RemoveAll(name string) error {
  242. return fs.walk("remove", name, func(dir *memFSNode, frag string, final bool) error {
  243. if !final {
  244. return nil
  245. }
  246. if frag == "" {
  247. return os.ErrInvalid
  248. }
  249. if _, ok := dir.children[frag]; !ok {
  250. return os.ErrNotExist
  251. }
  252. delete(dir.children, frag)
  253. return nil
  254. })
  255. }
  256. func (fs *memFS) Stat(name string) (os.FileInfo, error) {
  257. var n *memFSNode
  258. err := fs.walk("stat", name, func(dir *memFSNode, frag string, final bool) error {
  259. if !final {
  260. return nil
  261. }
  262. if frag == "" {
  263. n = &fs.root
  264. return nil
  265. }
  266. n = dir.children[frag]
  267. if n == nil {
  268. return os.ErrNotExist
  269. }
  270. return nil
  271. })
  272. if err != nil {
  273. return nil, err
  274. }
  275. return n, nil
  276. }
  277. // A memFSNode represents a single entry in the in-memory filesystem and also
  278. // implements os.FileInfo.
  279. type memFSNode struct {
  280. name string
  281. mu sync.Mutex
  282. modTime time.Time
  283. mode os.FileMode
  284. children map[string]*memFSNode
  285. data []byte
  286. }
  287. func (n *memFSNode) Name() string {
  288. return n.name
  289. }
  290. func (n *memFSNode) Size() int64 {
  291. n.mu.Lock()
  292. defer n.mu.Unlock()
  293. return int64(len(n.data))
  294. }
  295. func (n *memFSNode) Mode() os.FileMode {
  296. n.mu.Lock()
  297. defer n.mu.Unlock()
  298. return n.mode
  299. }
  300. func (n *memFSNode) ModTime() time.Time {
  301. n.mu.Lock()
  302. defer n.mu.Unlock()
  303. return n.modTime
  304. }
  305. func (n *memFSNode) IsDir() bool {
  306. return n.Mode().IsDir()
  307. }
  308. func (n *memFSNode) Sys() interface{} {
  309. return nil
  310. }
  311. // A memFile is a File implementation for a memFSNode. It is a per-file (not
  312. // per-node) read/write position, and if the node is a directory, a snapshot of
  313. // that node's children.
  314. type memFile struct {
  315. n *memFSNode
  316. children []os.FileInfo
  317. // Changes to pos are guarded by n.mu.
  318. pos int
  319. }
  320. func (f *memFile) Close() error {
  321. return nil
  322. }
  323. func (f *memFile) Read(p []byte) (int, error) {
  324. f.n.mu.Lock()
  325. defer f.n.mu.Unlock()
  326. if f.n.mode.IsDir() {
  327. return 0, os.ErrInvalid
  328. }
  329. if f.pos >= len(f.n.data) {
  330. return 0, io.EOF
  331. }
  332. n := copy(p, f.n.data[f.pos:])
  333. f.pos += n
  334. return n, nil
  335. }
  336. func (f *memFile) Readdir(count int) ([]os.FileInfo, error) {
  337. f.n.mu.Lock()
  338. defer f.n.mu.Unlock()
  339. if !f.n.mode.IsDir() {
  340. return nil, os.ErrInvalid
  341. }
  342. old := f.pos
  343. if old >= len(f.children) {
  344. // The os.File Readdir docs say that at the end of a directory,
  345. // the error is io.EOF if count > 0 and nil if count <= 0.
  346. if count > 0 {
  347. return nil, io.EOF
  348. }
  349. return nil, nil
  350. }
  351. if count > 0 {
  352. f.pos += count
  353. if f.pos > len(f.children) {
  354. f.pos = len(f.children)
  355. }
  356. } else {
  357. f.pos = len(f.children)
  358. old = 0
  359. }
  360. return f.children[old:f.pos], nil
  361. }
  362. func (f *memFile) Seek(offset int64, whence int) (int64, error) {
  363. f.n.mu.Lock()
  364. defer f.n.mu.Unlock()
  365. npos := f.pos
  366. // TODO: How to handle offsets greater than the size of system int?
  367. switch whence {
  368. case os.SEEK_SET:
  369. npos = int(offset)
  370. case os.SEEK_CUR:
  371. npos += int(offset)
  372. case os.SEEK_END:
  373. npos = len(f.n.data) + int(offset)
  374. default:
  375. npos = -1
  376. }
  377. if npos < 0 {
  378. return 0, os.ErrInvalid
  379. }
  380. f.pos = npos
  381. return int64(f.pos), nil
  382. }
  383. func (f *memFile) Stat() (os.FileInfo, error) {
  384. return f.n, nil
  385. }
  386. func (f *memFile) Write(p []byte) (int, error) {
  387. lenp := len(p)
  388. f.n.mu.Lock()
  389. defer f.n.mu.Unlock()
  390. if f.n.mode.IsDir() {
  391. return 0, os.ErrInvalid
  392. }
  393. if f.pos < len(f.n.data) {
  394. n := copy(f.n.data[f.pos:], p)
  395. f.pos += n
  396. p = p[n:]
  397. } else if f.pos > len(f.n.data) {
  398. // Write permits the creation of holes, if we've seek'ed past the
  399. // existing end of file.
  400. if f.pos <= cap(f.n.data) {
  401. oldLen := len(f.n.data)
  402. f.n.data = f.n.data[:f.pos]
  403. hole := f.n.data[oldLen:]
  404. for i := range hole {
  405. hole[i] = 0
  406. }
  407. } else {
  408. d := make([]byte, f.pos, f.pos+len(p))
  409. copy(d, f.n.data)
  410. f.n.data = d
  411. }
  412. }
  413. if len(p) > 0 {
  414. // We should only get here if f.pos == len(f.n.data).
  415. f.n.data = append(f.n.data, p...)
  416. f.pos = len(f.n.data)
  417. }
  418. f.n.modTime = time.Now()
  419. return lenp, nil
  420. }