file.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  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. // slashClean is equivalent to but slightly more efficient than
  16. // path.Clean("/" + name).
  17. func slashClean(name string) string {
  18. if name == "" || name[0] != '/' {
  19. name = "/" + name
  20. }
  21. return path.Clean(name)
  22. }
  23. // A FileSystem implements access to a collection of named files. The elements
  24. // in a file path are separated by slash ('/', U+002F) characters, regardless
  25. // of host operating system convention.
  26. //
  27. // Each method has the same semantics as the os package's function of the same
  28. // name.
  29. type FileSystem interface {
  30. Mkdir(name string, perm os.FileMode) error
  31. OpenFile(name string, flag int, perm os.FileMode) (File, error)
  32. RemoveAll(name string) error
  33. Rename(oldName, newName string) error
  34. Stat(name string) (os.FileInfo, error)
  35. }
  36. // A File is returned by a FileSystem's OpenFile method and can be served by a
  37. // Handler.
  38. type File interface {
  39. http.File
  40. io.Writer
  41. }
  42. // A Dir implements FileSystem using the native file system restricted to a
  43. // specific directory tree.
  44. //
  45. // While the FileSystem.OpenFile method takes '/'-separated paths, a Dir's
  46. // string value is a filename on the native file system, not a URL, so it is
  47. // separated by filepath.Separator, which isn't necessarily '/'.
  48. //
  49. // An empty Dir is treated as ".".
  50. type Dir string
  51. func (d Dir) resolve(name string) string {
  52. // This implementation is based on Dir.Open's code in the standard net/http package.
  53. if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
  54. strings.Contains(name, "\x00") {
  55. return ""
  56. }
  57. dir := string(d)
  58. if dir == "" {
  59. dir = "."
  60. }
  61. return filepath.Join(dir, filepath.FromSlash(slashClean(name)))
  62. }
  63. func (d Dir) Mkdir(name string, perm os.FileMode) error {
  64. if name = d.resolve(name); name == "" {
  65. return os.ErrNotExist
  66. }
  67. return os.Mkdir(name, perm)
  68. }
  69. func (d Dir) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
  70. if name = d.resolve(name); name == "" {
  71. return nil, os.ErrNotExist
  72. }
  73. f, err := os.OpenFile(name, flag, perm)
  74. if err != nil {
  75. return nil, err
  76. }
  77. return f, nil
  78. }
  79. func (d Dir) RemoveAll(name string) error {
  80. if name = d.resolve(name); name == "" {
  81. return os.ErrNotExist
  82. }
  83. if name == filepath.Clean(string(d)) {
  84. // Prohibit removing the virtual root directory.
  85. return os.ErrInvalid
  86. }
  87. return os.RemoveAll(name)
  88. }
  89. func (d Dir) Rename(oldName, newName string) error {
  90. if oldName = d.resolve(oldName); oldName == "" {
  91. return os.ErrNotExist
  92. }
  93. if newName = d.resolve(newName); newName == "" {
  94. return os.ErrNotExist
  95. }
  96. if root := filepath.Clean(string(d)); root == oldName || root == newName {
  97. // Prohibit renaming from or to the virtual root directory.
  98. return os.ErrInvalid
  99. }
  100. return os.Rename(oldName, newName)
  101. }
  102. func (d Dir) Stat(name string) (os.FileInfo, error) {
  103. if name = d.resolve(name); name == "" {
  104. return nil, os.ErrNotExist
  105. }
  106. return os.Stat(name)
  107. }
  108. // NewMemFS returns a new in-memory FileSystem implementation.
  109. func NewMemFS() FileSystem {
  110. return &memFS{
  111. root: memFSNode{
  112. children: make(map[string]*memFSNode),
  113. mode: 0660 | os.ModeDir,
  114. modTime: time.Now(),
  115. },
  116. }
  117. }
  118. // A memFS implements FileSystem, storing all metadata and actual file data
  119. // in-memory. No limits on filesystem size are used, so it is not recommended
  120. // this be used where the clients are untrusted.
  121. //
  122. // Concurrent access is permitted. The tree structure is protected by a mutex,
  123. // and each node's contents and metadata are protected by a per-node mutex.
  124. //
  125. // TODO: Enforce file permissions.
  126. type memFS struct {
  127. mu sync.Mutex
  128. root memFSNode
  129. }
  130. // TODO: clean up and rationalize the walk/find code.
  131. // walk walks the directory tree for the fullname, calling f at each step. If f
  132. // returns an error, the walk will be aborted and return that same error.
  133. //
  134. // dir is the directory at that step, frag is the name fragment, and final is
  135. // whether it is the final step. For example, walking "/foo/bar/x" will result
  136. // in 3 calls to f:
  137. // - "/", "foo", false
  138. // - "/foo/", "bar", false
  139. // - "/foo/bar/", "x", true
  140. // The frag argument will be empty only if dir is the root node and the walk
  141. // ends at that root node.
  142. func (fs *memFS) walk(op, fullname string, f func(dir *memFSNode, frag string, final bool) error) error {
  143. original := fullname
  144. fullname = slashClean(fullname)
  145. // Strip any leading "/"s to make fullname a relative path, as the walk
  146. // starts at fs.root.
  147. if fullname[0] == '/' {
  148. fullname = fullname[1:]
  149. }
  150. dir := &fs.root
  151. for {
  152. frag, remaining := fullname, ""
  153. i := strings.IndexRune(fullname, '/')
  154. final := i < 0
  155. if !final {
  156. frag, remaining = fullname[:i], fullname[i+1:]
  157. }
  158. if frag == "" && dir != &fs.root {
  159. panic("webdav: empty path fragment for a clean path")
  160. }
  161. if err := f(dir, frag, final); err != nil {
  162. return &os.PathError{
  163. Op: op,
  164. Path: original,
  165. Err: err,
  166. }
  167. }
  168. if final {
  169. break
  170. }
  171. child := dir.children[frag]
  172. if child == nil {
  173. return &os.PathError{
  174. Op: op,
  175. Path: original,
  176. Err: os.ErrNotExist,
  177. }
  178. }
  179. if !child.mode.IsDir() {
  180. return &os.PathError{
  181. Op: op,
  182. Path: original,
  183. Err: os.ErrInvalid,
  184. }
  185. }
  186. dir, fullname = child, remaining
  187. }
  188. return nil
  189. }
  190. // find returns the parent of the named node and the relative name fragment
  191. // from the parent to the child. For example, if finding "/foo/bar/baz" then
  192. // parent will be the node for "/foo/bar" and frag will be "baz".
  193. //
  194. // If the fullname names the root node, then parent, frag and err will be zero.
  195. //
  196. // find returns an error if the parent does not already exist or the parent
  197. // isn't a directory, but it will not return an error per se if the child does
  198. // not already exist. The error returned is either nil or an *os.PathError
  199. // whose Op is op.
  200. func (fs *memFS) find(op, fullname string) (parent *memFSNode, frag string, err error) {
  201. err = fs.walk(op, fullname, func(parent0 *memFSNode, frag0 string, final bool) error {
  202. if !final {
  203. return nil
  204. }
  205. if frag0 != "" {
  206. parent, frag = parent0, frag0
  207. }
  208. return nil
  209. })
  210. return parent, frag, err
  211. }
  212. func (fs *memFS) Mkdir(name string, perm os.FileMode) error {
  213. fs.mu.Lock()
  214. defer fs.mu.Unlock()
  215. dir, frag, err := fs.find("mkdir", name)
  216. if err != nil {
  217. return err
  218. }
  219. if dir == nil {
  220. // We can't create the root.
  221. return os.ErrInvalid
  222. }
  223. if _, ok := dir.children[frag]; ok {
  224. return os.ErrExist
  225. }
  226. dir.children[frag] = &memFSNode{
  227. children: make(map[string]*memFSNode),
  228. mode: perm.Perm() | os.ModeDir,
  229. modTime: time.Now(),
  230. }
  231. return nil
  232. }
  233. func (fs *memFS) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
  234. fs.mu.Lock()
  235. defer fs.mu.Unlock()
  236. dir, frag, err := fs.find("open", name)
  237. if err != nil {
  238. return nil, err
  239. }
  240. var n *memFSNode
  241. if dir == nil {
  242. // We're opening the root.
  243. if flag&(os.O_WRONLY|os.O_RDWR) != 0 {
  244. return nil, os.ErrPermission
  245. }
  246. n, frag = &fs.root, "/"
  247. } else {
  248. n = dir.children[frag]
  249. if flag&(os.O_SYNC|os.O_APPEND) != 0 {
  250. // memFile doesn't support these flags yet.
  251. return nil, os.ErrInvalid
  252. }
  253. if flag&os.O_CREATE != 0 {
  254. if flag&os.O_EXCL != 0 && n != nil {
  255. return nil, os.ErrExist
  256. }
  257. if n == nil {
  258. n = &memFSNode{
  259. mode: perm.Perm(),
  260. }
  261. dir.children[frag] = n
  262. }
  263. }
  264. if n == nil {
  265. return nil, os.ErrNotExist
  266. }
  267. if flag&(os.O_WRONLY|os.O_RDWR) != 0 && flag&os.O_TRUNC != 0 {
  268. n.mu.Lock()
  269. n.data = nil
  270. n.mu.Unlock()
  271. }
  272. }
  273. children := make([]os.FileInfo, 0, len(n.children))
  274. for cName, c := range n.children {
  275. children = append(children, c.stat(cName))
  276. }
  277. return &memFile{
  278. n: n,
  279. nameSnapshot: frag,
  280. childrenSnapshot: children,
  281. }, nil
  282. }
  283. func (fs *memFS) RemoveAll(name string) error {
  284. fs.mu.Lock()
  285. defer fs.mu.Unlock()
  286. dir, frag, err := fs.find("remove", name)
  287. if err != nil {
  288. return err
  289. }
  290. if dir == nil {
  291. // We can't remove the root.
  292. return os.ErrInvalid
  293. }
  294. delete(dir.children, frag)
  295. return nil
  296. }
  297. func (fs *memFS) Rename(oldName, newName string) error {
  298. fs.mu.Lock()
  299. defer fs.mu.Unlock()
  300. oldName = slashClean(oldName)
  301. newName = slashClean(newName)
  302. if oldName == newName {
  303. return nil
  304. }
  305. if strings.HasPrefix(newName, oldName+"/") {
  306. // We can't rename oldName to be a sub-directory of itself.
  307. return os.ErrInvalid
  308. }
  309. oDir, oFrag, err := fs.find("rename", oldName)
  310. if err != nil {
  311. return err
  312. }
  313. if oDir == nil {
  314. // We can't rename from the root.
  315. return os.ErrInvalid
  316. }
  317. nDir, nFrag, err := fs.find("rename", newName)
  318. if err != nil {
  319. return err
  320. }
  321. if nDir == nil {
  322. // We can't rename to the root.
  323. return os.ErrInvalid
  324. }
  325. oNode, ok := oDir.children[oFrag]
  326. if !ok {
  327. return os.ErrNotExist
  328. }
  329. if oNode.children != nil {
  330. if nNode, ok := nDir.children[nFrag]; ok {
  331. if nNode.children == nil {
  332. return errNotADirectory
  333. }
  334. if len(nNode.children) != 0 {
  335. return errDirectoryNotEmpty
  336. }
  337. }
  338. }
  339. delete(oDir.children, oFrag)
  340. nDir.children[nFrag] = oNode
  341. return nil
  342. }
  343. func (fs *memFS) Stat(name string) (os.FileInfo, error) {
  344. fs.mu.Lock()
  345. defer fs.mu.Unlock()
  346. dir, frag, err := fs.find("stat", name)
  347. if err != nil {
  348. return nil, err
  349. }
  350. if dir == nil {
  351. // We're stat'ting the root.
  352. return fs.root.stat("/"), nil
  353. }
  354. if n, ok := dir.children[frag]; ok {
  355. return n.stat(path.Base(name)), nil
  356. }
  357. return nil, os.ErrNotExist
  358. }
  359. // A memFSNode represents a single entry in the in-memory filesystem and also
  360. // implements os.FileInfo.
  361. type memFSNode struct {
  362. // children is protected by memFS.mu.
  363. children map[string]*memFSNode
  364. mu sync.Mutex
  365. data []byte
  366. mode os.FileMode
  367. modTime time.Time
  368. }
  369. func (n *memFSNode) stat(name string) *memFileInfo {
  370. n.mu.Lock()
  371. defer n.mu.Unlock()
  372. return &memFileInfo{
  373. name: name,
  374. size: int64(len(n.data)),
  375. mode: n.mode,
  376. modTime: n.modTime,
  377. }
  378. }
  379. type memFileInfo struct {
  380. name string
  381. size int64
  382. mode os.FileMode
  383. modTime time.Time
  384. }
  385. func (f *memFileInfo) Name() string { return f.name }
  386. func (f *memFileInfo) Size() int64 { return f.size }
  387. func (f *memFileInfo) Mode() os.FileMode { return f.mode }
  388. func (f *memFileInfo) ModTime() time.Time { return f.modTime }
  389. func (f *memFileInfo) IsDir() bool { return f.mode.IsDir() }
  390. func (f *memFileInfo) Sys() interface{} { return nil }
  391. // A memFile is a File implementation for a memFSNode. It is a per-file (not
  392. // per-node) read/write position, and a snapshot of the memFS' tree structure
  393. // (a node's name and children) for that node.
  394. type memFile struct {
  395. n *memFSNode
  396. nameSnapshot string
  397. childrenSnapshot []os.FileInfo
  398. // pos is protected by n.mu.
  399. pos int
  400. }
  401. func (f *memFile) Close() error {
  402. return nil
  403. }
  404. func (f *memFile) Read(p []byte) (int, error) {
  405. f.n.mu.Lock()
  406. defer f.n.mu.Unlock()
  407. if f.n.mode.IsDir() {
  408. return 0, os.ErrInvalid
  409. }
  410. if f.pos >= len(f.n.data) {
  411. return 0, io.EOF
  412. }
  413. n := copy(p, f.n.data[f.pos:])
  414. f.pos += n
  415. return n, nil
  416. }
  417. func (f *memFile) Readdir(count int) ([]os.FileInfo, error) {
  418. f.n.mu.Lock()
  419. defer f.n.mu.Unlock()
  420. if !f.n.mode.IsDir() {
  421. return nil, os.ErrInvalid
  422. }
  423. old := f.pos
  424. if old >= len(f.childrenSnapshot) {
  425. // The os.File Readdir docs say that at the end of a directory,
  426. // the error is io.EOF if count > 0 and nil if count <= 0.
  427. if count > 0 {
  428. return nil, io.EOF
  429. }
  430. return nil, nil
  431. }
  432. if count > 0 {
  433. f.pos += count
  434. if f.pos > len(f.childrenSnapshot) {
  435. f.pos = len(f.childrenSnapshot)
  436. }
  437. } else {
  438. f.pos = len(f.childrenSnapshot)
  439. old = 0
  440. }
  441. return f.childrenSnapshot[old:f.pos], nil
  442. }
  443. func (f *memFile) Seek(offset int64, whence int) (int64, error) {
  444. f.n.mu.Lock()
  445. defer f.n.mu.Unlock()
  446. npos := f.pos
  447. // TODO: How to handle offsets greater than the size of system int?
  448. switch whence {
  449. case os.SEEK_SET:
  450. npos = int(offset)
  451. case os.SEEK_CUR:
  452. npos += int(offset)
  453. case os.SEEK_END:
  454. npos = len(f.n.data) + int(offset)
  455. default:
  456. npos = -1
  457. }
  458. if npos < 0 {
  459. return 0, os.ErrInvalid
  460. }
  461. f.pos = npos
  462. return int64(f.pos), nil
  463. }
  464. func (f *memFile) Stat() (os.FileInfo, error) {
  465. return f.n.stat(f.nameSnapshot), nil
  466. }
  467. func (f *memFile) Write(p []byte) (int, error) {
  468. lenp := len(p)
  469. f.n.mu.Lock()
  470. defer f.n.mu.Unlock()
  471. if f.n.mode.IsDir() {
  472. return 0, os.ErrInvalid
  473. }
  474. if f.pos < len(f.n.data) {
  475. n := copy(f.n.data[f.pos:], p)
  476. f.pos += n
  477. p = p[n:]
  478. } else if f.pos > len(f.n.data) {
  479. // Write permits the creation of holes, if we've seek'ed past the
  480. // existing end of file.
  481. if f.pos <= cap(f.n.data) {
  482. oldLen := len(f.n.data)
  483. f.n.data = f.n.data[:f.pos]
  484. hole := f.n.data[oldLen:]
  485. for i := range hole {
  486. hole[i] = 0
  487. }
  488. } else {
  489. d := make([]byte, f.pos, f.pos+len(p))
  490. copy(d, f.n.data)
  491. f.n.data = d
  492. }
  493. }
  494. if len(p) > 0 {
  495. // We should only get here if f.pos == len(f.n.data).
  496. f.n.data = append(f.n.data, p...)
  497. f.pos = len(f.n.data)
  498. }
  499. f.n.modTime = time.Now()
  500. return lenp, nil
  501. }
  502. // copyFiles copies files and/or directories from src to dst.
  503. //
  504. // See section 9.8.5 for when various HTTP status codes apply.
  505. func copyFiles(fs FileSystem, src, dst string, overwrite bool, depth int, recursion int) (status int, err error) {
  506. if recursion == 1000 {
  507. return http.StatusInternalServerError, errRecursionTooDeep
  508. }
  509. recursion++
  510. // TODO: section 9.8.3 says that "Note that an infinite-depth COPY of /A/
  511. // into /A/B/ could lead to infinite recursion if not handled correctly."
  512. srcFile, err := fs.OpenFile(src, os.O_RDONLY, 0)
  513. if err != nil {
  514. return http.StatusNotFound, err
  515. }
  516. defer srcFile.Close()
  517. srcStat, err := srcFile.Stat()
  518. if err != nil {
  519. return http.StatusNotFound, err
  520. }
  521. srcPerm := srcStat.Mode() & os.ModePerm
  522. created := false
  523. if _, err := fs.Stat(dst); err != nil {
  524. if os.IsNotExist(err) {
  525. created = true
  526. } else {
  527. return http.StatusForbidden, err
  528. }
  529. } else {
  530. if !overwrite {
  531. return http.StatusPreconditionFailed, os.ErrExist
  532. }
  533. if err := fs.RemoveAll(dst); err != nil && !os.IsNotExist(err) {
  534. return http.StatusForbidden, err
  535. }
  536. }
  537. if srcStat.IsDir() {
  538. if err := fs.Mkdir(dst, srcPerm); err != nil {
  539. return http.StatusForbidden, err
  540. }
  541. if depth == infiniteDepth {
  542. children, err := srcFile.Readdir(-1)
  543. if err != nil {
  544. return http.StatusForbidden, err
  545. }
  546. for _, c := range children {
  547. name := c.Name()
  548. s := path.Join(src, name)
  549. d := path.Join(dst, name)
  550. cStatus, cErr := copyFiles(fs, s, d, overwrite, depth, recursion)
  551. if cErr != nil {
  552. // TODO: MultiStatus.
  553. return cStatus, cErr
  554. }
  555. }
  556. }
  557. } else {
  558. dstFile, err := fs.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, srcPerm)
  559. if err != nil {
  560. if os.IsNotExist(err) {
  561. return http.StatusConflict, err
  562. }
  563. return http.StatusForbidden, err
  564. }
  565. _, copyErr := io.Copy(dstFile, srcFile)
  566. closeErr := dstFile.Close()
  567. if copyErr != nil {
  568. return http.StatusForbidden, copyErr
  569. }
  570. if closeErr != nil {
  571. return http.StatusForbidden, closeErr
  572. }
  573. }
  574. if created {
  575. return http.StatusCreated, nil
  576. }
  577. return http.StatusNoContent, nil
  578. }