file.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  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.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. name: frag,
  228. children: make(map[string]*memFSNode),
  229. mode: perm.Perm() | os.ModeDir,
  230. modTime: time.Now(),
  231. }
  232. return nil
  233. }
  234. func (fs *memFS) OpenFile(name string, flag int, perm os.FileMode) (File, error) {
  235. fs.mu.Lock()
  236. defer fs.mu.Unlock()
  237. dir, frag, err := fs.find("open", name)
  238. if err != nil {
  239. return nil, err
  240. }
  241. var n *memFSNode
  242. if dir == nil {
  243. // We're opening the root.
  244. if flag&(os.O_WRONLY|os.O_RDWR) != 0 {
  245. return nil, os.ErrPermission
  246. }
  247. n = &fs.root
  248. } else {
  249. n = dir.children[frag]
  250. if flag&(os.O_SYNC|os.O_APPEND) != 0 {
  251. // memFile doesn't support these flags yet.
  252. return nil, os.ErrInvalid
  253. }
  254. if flag&os.O_CREATE != 0 {
  255. if flag&os.O_EXCL != 0 && n != nil {
  256. return nil, os.ErrExist
  257. }
  258. if n == nil {
  259. n = &memFSNode{
  260. name: frag,
  261. mode: perm.Perm(),
  262. }
  263. dir.children[frag] = n
  264. }
  265. }
  266. if n == nil {
  267. return nil, os.ErrNotExist
  268. }
  269. if flag&(os.O_WRONLY|os.O_RDWR) != 0 && flag&os.O_TRUNC != 0 {
  270. n.mu.Lock()
  271. n.data = nil
  272. n.mu.Unlock()
  273. }
  274. }
  275. children := make([]os.FileInfo, 0, len(n.children))
  276. for _, c := range n.children {
  277. children = append(children, c)
  278. }
  279. return &memFile{
  280. n: n,
  281. childrenSnapshot: children,
  282. }, nil
  283. }
  284. func (fs *memFS) RemoveAll(name string) error {
  285. fs.mu.Lock()
  286. defer fs.mu.Unlock()
  287. dir, frag, err := fs.find("remove", name)
  288. if err != nil {
  289. return err
  290. }
  291. if dir == nil {
  292. // We can't remove the root.
  293. return os.ErrInvalid
  294. }
  295. delete(dir.children, frag)
  296. return nil
  297. }
  298. func (fs *memFS) Rename(oldName, newName string) error {
  299. fs.mu.Lock()
  300. defer fs.mu.Unlock()
  301. oldName = slashClean(oldName)
  302. newName = slashClean(newName)
  303. if oldName == newName {
  304. return nil
  305. }
  306. if strings.HasPrefix(newName, oldName+"/") {
  307. // We can't rename oldName to be a sub-directory of itself.
  308. return os.ErrInvalid
  309. }
  310. oDir, oFrag, err := fs.find("rename", oldName)
  311. if err != nil {
  312. return err
  313. }
  314. if oDir == nil {
  315. // We can't rename from the root.
  316. return os.ErrInvalid
  317. }
  318. nDir, nFrag, err := fs.find("rename", newName)
  319. if err != nil {
  320. return err
  321. }
  322. if nDir == nil {
  323. // We can't rename to the root.
  324. return os.ErrInvalid
  325. }
  326. oNode, ok := oDir.children[oFrag]
  327. if !ok {
  328. return os.ErrNotExist
  329. }
  330. if oNode.IsDir() {
  331. if nNode, ok := nDir.children[nFrag]; ok {
  332. nNode.mu.Lock()
  333. isDir := nNode.mode.IsDir()
  334. nNode.mu.Unlock()
  335. if !isDir {
  336. return errNotADirectory
  337. }
  338. if len(nNode.children) != 0 {
  339. return errDirectoryNotEmpty
  340. }
  341. }
  342. }
  343. delete(oDir.children, oFrag)
  344. nDir.children[nFrag] = oNode
  345. return nil
  346. }
  347. func (fs *memFS) Stat(name string) (os.FileInfo, error) {
  348. fs.mu.Lock()
  349. defer fs.mu.Unlock()
  350. dir, frag, err := fs.find("stat", name)
  351. if err != nil {
  352. return nil, err
  353. }
  354. if dir == nil {
  355. // We're stat'ting the root.
  356. return &fs.root, nil
  357. }
  358. if n, ok := dir.children[frag]; ok {
  359. return n, nil
  360. }
  361. return nil, os.ErrNotExist
  362. }
  363. // A memFSNode represents a single entry in the in-memory filesystem and also
  364. // implements os.FileInfo.
  365. type memFSNode struct {
  366. name string
  367. // children is protected by memFS.mu.
  368. children map[string]*memFSNode
  369. mu sync.Mutex
  370. modTime time.Time
  371. mode os.FileMode
  372. data []byte
  373. }
  374. func (n *memFSNode) Name() string {
  375. return n.name
  376. }
  377. func (n *memFSNode) Size() int64 {
  378. n.mu.Lock()
  379. defer n.mu.Unlock()
  380. return int64(len(n.data))
  381. }
  382. func (n *memFSNode) Mode() os.FileMode {
  383. n.mu.Lock()
  384. defer n.mu.Unlock()
  385. return n.mode
  386. }
  387. func (n *memFSNode) ModTime() time.Time {
  388. n.mu.Lock()
  389. defer n.mu.Unlock()
  390. return n.modTime
  391. }
  392. func (n *memFSNode) IsDir() bool {
  393. return n.Mode().IsDir()
  394. }
  395. func (n *memFSNode) Sys() interface{} {
  396. return nil
  397. }
  398. // A memFile is a File implementation for a memFSNode. It is a per-file (not
  399. // per-node) read/write position, and if the node is a directory, a snapshot of
  400. // that node's children.
  401. type memFile struct {
  402. n *memFSNode
  403. // childrenSnapshot is a snapshot of n.children.
  404. childrenSnapshot []os.FileInfo
  405. // pos is protected by n.mu.
  406. pos int
  407. }
  408. func (f *memFile) Close() error {
  409. return nil
  410. }
  411. func (f *memFile) Read(p []byte) (int, error) {
  412. f.n.mu.Lock()
  413. defer f.n.mu.Unlock()
  414. if f.n.mode.IsDir() {
  415. return 0, os.ErrInvalid
  416. }
  417. if f.pos >= len(f.n.data) {
  418. return 0, io.EOF
  419. }
  420. n := copy(p, f.n.data[f.pos:])
  421. f.pos += n
  422. return n, nil
  423. }
  424. func (f *memFile) Readdir(count int) ([]os.FileInfo, error) {
  425. f.n.mu.Lock()
  426. defer f.n.mu.Unlock()
  427. if !f.n.mode.IsDir() {
  428. return nil, os.ErrInvalid
  429. }
  430. old := f.pos
  431. if old >= len(f.childrenSnapshot) {
  432. // The os.File Readdir docs say that at the end of a directory,
  433. // the error is io.EOF if count > 0 and nil if count <= 0.
  434. if count > 0 {
  435. return nil, io.EOF
  436. }
  437. return nil, nil
  438. }
  439. if count > 0 {
  440. f.pos += count
  441. if f.pos > len(f.childrenSnapshot) {
  442. f.pos = len(f.childrenSnapshot)
  443. }
  444. } else {
  445. f.pos = len(f.childrenSnapshot)
  446. old = 0
  447. }
  448. return f.childrenSnapshot[old:f.pos], nil
  449. }
  450. func (f *memFile) Seek(offset int64, whence int) (int64, error) {
  451. f.n.mu.Lock()
  452. defer f.n.mu.Unlock()
  453. npos := f.pos
  454. // TODO: How to handle offsets greater than the size of system int?
  455. switch whence {
  456. case os.SEEK_SET:
  457. npos = int(offset)
  458. case os.SEEK_CUR:
  459. npos += int(offset)
  460. case os.SEEK_END:
  461. npos = len(f.n.data) + int(offset)
  462. default:
  463. npos = -1
  464. }
  465. if npos < 0 {
  466. return 0, os.ErrInvalid
  467. }
  468. f.pos = npos
  469. return int64(f.pos), nil
  470. }
  471. func (f *memFile) Stat() (os.FileInfo, error) {
  472. return f.n, nil
  473. }
  474. func (f *memFile) Write(p []byte) (int, error) {
  475. lenp := len(p)
  476. f.n.mu.Lock()
  477. defer f.n.mu.Unlock()
  478. if f.n.mode.IsDir() {
  479. return 0, os.ErrInvalid
  480. }
  481. if f.pos < len(f.n.data) {
  482. n := copy(f.n.data[f.pos:], p)
  483. f.pos += n
  484. p = p[n:]
  485. } else if f.pos > len(f.n.data) {
  486. // Write permits the creation of holes, if we've seek'ed past the
  487. // existing end of file.
  488. if f.pos <= cap(f.n.data) {
  489. oldLen := len(f.n.data)
  490. f.n.data = f.n.data[:f.pos]
  491. hole := f.n.data[oldLen:]
  492. for i := range hole {
  493. hole[i] = 0
  494. }
  495. } else {
  496. d := make([]byte, f.pos, f.pos+len(p))
  497. copy(d, f.n.data)
  498. f.n.data = d
  499. }
  500. }
  501. if len(p) > 0 {
  502. // We should only get here if f.pos == len(f.n.data).
  503. f.n.data = append(f.n.data, p...)
  504. f.pos = len(f.n.data)
  505. }
  506. f.n.modTime = time.Now()
  507. return lenp, nil
  508. }