file.go 19 KB

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