file.go 10 KB

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