fs.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  1. // Copyright 2017 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package fs
  15. import (
  16. "bytes"
  17. "errors"
  18. "fmt"
  19. "io"
  20. "io/ioutil"
  21. "os"
  22. "os/user"
  23. "path/filepath"
  24. "sync"
  25. "time"
  26. )
  27. var OsFs FileSystem = osFs{}
  28. func NewMockFs(files map[string][]byte) *MockFs {
  29. workDir := "/cwd"
  30. fs := &MockFs{
  31. Clock: NewClock(time.Unix(2, 2)),
  32. workDir: workDir,
  33. }
  34. fs.root = *fs.newDir()
  35. fs.MkDirs(workDir)
  36. for path, bytes := range files {
  37. dir := filepath.Dir(path)
  38. fs.MkDirs(dir)
  39. fs.WriteFile(path, bytes, 0777)
  40. }
  41. return fs
  42. }
  43. type FileSystem interface {
  44. // getting information about files
  45. Open(name string) (file io.ReadCloser, err error)
  46. Lstat(path string) (stats os.FileInfo, err error)
  47. Stat(path string) (stats os.FileInfo, err error)
  48. ReadDir(path string) (contents []DirEntryInfo, err error)
  49. InodeNumber(info os.FileInfo) (number uint64, err error)
  50. DeviceNumber(info os.FileInfo) (number uint64, err error)
  51. PermTime(info os.FileInfo) (time time.Time, err error)
  52. // changing contents of the filesystem
  53. Rename(oldPath string, newPath string) (err error)
  54. WriteFile(path string, data []byte, perm os.FileMode) (err error)
  55. Remove(path string) (err error)
  56. RemoveAll(path string) (err error)
  57. // metadata about the filesystem
  58. ViewId() (id string) // Some unique id of the user accessing the filesystem
  59. }
  60. // DentryInfo is a subset of the functionality available through os.FileInfo that might be able
  61. // to be gleaned through only a syscall.Getdents without requiring a syscall.Lstat of every file.
  62. type DirEntryInfo interface {
  63. Name() string
  64. Mode() os.FileMode // the file type encoded as an os.FileMode
  65. IsDir() bool
  66. }
  67. type dirEntryInfo struct {
  68. name string
  69. mode os.FileMode
  70. modeExists bool
  71. }
  72. var _ DirEntryInfo = os.FileInfo(nil)
  73. func (d *dirEntryInfo) Name() string { return d.name }
  74. func (d *dirEntryInfo) Mode() os.FileMode { return d.mode }
  75. func (d *dirEntryInfo) IsDir() bool { return d.mode.IsDir() }
  76. func (d *dirEntryInfo) String() string { return d.name + ": " + d.mode.String() }
  77. // osFs implements FileSystem using the local disk.
  78. type osFs struct{}
  79. var _ FileSystem = (*osFs)(nil)
  80. func (osFs) Open(name string) (io.ReadCloser, error) { return os.Open(name) }
  81. func (osFs) Lstat(path string) (stats os.FileInfo, err error) {
  82. return os.Lstat(path)
  83. }
  84. func (osFs) Stat(path string) (stats os.FileInfo, err error) {
  85. return os.Stat(path)
  86. }
  87. func (osFs) ReadDir(path string) (contents []DirEntryInfo, err error) {
  88. entries, err := readdir(path)
  89. if err != nil {
  90. return nil, err
  91. }
  92. for _, entry := range entries {
  93. contents = append(contents, entry)
  94. }
  95. return contents, nil
  96. }
  97. func (osFs) Rename(oldPath string, newPath string) error {
  98. return os.Rename(oldPath, newPath)
  99. }
  100. func (osFs) WriteFile(path string, data []byte, perm os.FileMode) error {
  101. return ioutil.WriteFile(path, data, perm)
  102. }
  103. func (osFs) Remove(path string) error {
  104. return os.Remove(path)
  105. }
  106. func (osFs) RemoveAll(path string) error {
  107. return os.RemoveAll(path)
  108. }
  109. func (osFs) ViewId() (id string) {
  110. user, err := user.Current()
  111. if err != nil {
  112. return ""
  113. }
  114. username := user.Username
  115. hostname, err := os.Hostname()
  116. if err != nil {
  117. return ""
  118. }
  119. return username + "@" + hostname
  120. }
  121. type Clock struct {
  122. time time.Time
  123. }
  124. func NewClock(startTime time.Time) *Clock {
  125. return &Clock{time: startTime}
  126. }
  127. func (c *Clock) Tick() {
  128. c.time = c.time.Add(time.Microsecond)
  129. }
  130. func (c *Clock) Time() time.Time {
  131. return c.time
  132. }
  133. // given "/a/b/c/d", pathSplit returns ("/a/b/c", "d")
  134. func pathSplit(path string) (dir string, leaf string) {
  135. dir, leaf = filepath.Split(path)
  136. if dir != "/" && len(dir) > 0 {
  137. dir = dir[:len(dir)-1]
  138. }
  139. return dir, leaf
  140. }
  141. // MockFs supports singlethreaded writes and multithreaded reads
  142. type MockFs struct {
  143. // configuration
  144. viewId string //
  145. deviceNumber uint64
  146. // implementation
  147. root mockDir
  148. Clock *Clock
  149. workDir string
  150. nextInodeNumber uint64
  151. // history of requests, for tests to check
  152. StatCalls []string
  153. ReadDirCalls []string
  154. aggregatesLock sync.Mutex
  155. }
  156. var _ FileSystem = (*MockFs)(nil)
  157. type mockInode struct {
  158. modTime time.Time
  159. permTime time.Time
  160. sys interface{}
  161. inodeNumber uint64
  162. readErr error
  163. }
  164. func (m mockInode) ModTime() time.Time {
  165. return m.modTime
  166. }
  167. func (m mockInode) Sys() interface{} {
  168. return m.sys
  169. }
  170. type mockFile struct {
  171. bytes []byte
  172. mockInode
  173. }
  174. type mockLink struct {
  175. target string
  176. mockInode
  177. }
  178. type mockDir struct {
  179. mockInode
  180. subdirs map[string]*mockDir
  181. files map[string]*mockFile
  182. symlinks map[string]*mockLink
  183. }
  184. func (m *MockFs) resolve(path string, followLastLink bool) (result string, err error) {
  185. if !filepath.IsAbs(path) {
  186. path = filepath.Join(m.workDir, path)
  187. }
  188. path = filepath.Clean(path)
  189. return m.followLinks(path, followLastLink, 10)
  190. }
  191. // note that followLinks can return a file path that doesn't exist
  192. func (m *MockFs) followLinks(path string, followLastLink bool, count int) (canonicalPath string, err error) {
  193. if path == "/" {
  194. return path, nil
  195. }
  196. parentPath, leaf := pathSplit(path)
  197. if parentPath == path {
  198. err = fmt.Errorf("Internal error: %v yields itself as a parent", path)
  199. panic(err.Error())
  200. }
  201. parentPath, err = m.followLinks(parentPath, true, count)
  202. if err != nil {
  203. return "", err
  204. }
  205. parentNode, err := m.getDir(parentPath, false)
  206. if err != nil {
  207. return "", err
  208. }
  209. if parentNode.readErr != nil {
  210. return "", &os.PathError{
  211. Op: "read",
  212. Path: path,
  213. Err: parentNode.readErr,
  214. }
  215. }
  216. link, isLink := parentNode.symlinks[leaf]
  217. if isLink && followLastLink {
  218. if count <= 0 {
  219. // probably a loop
  220. return "", &os.PathError{
  221. Op: "read",
  222. Path: path,
  223. Err: fmt.Errorf("too many levels of symbolic links"),
  224. }
  225. }
  226. if link.readErr != nil {
  227. return "", &os.PathError{
  228. Op: "read",
  229. Path: path,
  230. Err: link.readErr,
  231. }
  232. }
  233. target := m.followLink(link, parentPath)
  234. return m.followLinks(target, followLastLink, count-1)
  235. }
  236. return path, nil
  237. }
  238. func (m *MockFs) followLink(link *mockLink, parentPath string) (result string) {
  239. return filepath.Clean(filepath.Join(parentPath, link.target))
  240. }
  241. func (m *MockFs) getFile(parentDir *mockDir, fileName string) (file *mockFile, err error) {
  242. file, isFile := parentDir.files[fileName]
  243. if !isFile {
  244. _, isDir := parentDir.subdirs[fileName]
  245. _, isLink := parentDir.symlinks[fileName]
  246. if isDir || isLink {
  247. return nil, &os.PathError{
  248. Op: "open",
  249. Path: fileName,
  250. Err: os.ErrInvalid,
  251. }
  252. }
  253. return nil, &os.PathError{
  254. Op: "open",
  255. Path: fileName,
  256. Err: os.ErrNotExist,
  257. }
  258. }
  259. if file.readErr != nil {
  260. return nil, &os.PathError{
  261. Op: "open",
  262. Path: fileName,
  263. Err: file.readErr,
  264. }
  265. }
  266. return file, nil
  267. }
  268. func (m *MockFs) getInode(parentDir *mockDir, name string) (inode *mockInode, err error) {
  269. file, isFile := parentDir.files[name]
  270. if isFile {
  271. return &file.mockInode, nil
  272. }
  273. link, isLink := parentDir.symlinks[name]
  274. if isLink {
  275. return &link.mockInode, nil
  276. }
  277. dir, isDir := parentDir.subdirs[name]
  278. if isDir {
  279. return &dir.mockInode, nil
  280. }
  281. return nil, &os.PathError{
  282. Op: "stat",
  283. Path: name,
  284. Err: os.ErrNotExist,
  285. }
  286. }
  287. func (m *MockFs) Open(path string) (io.ReadCloser, error) {
  288. path, err := m.resolve(path, true)
  289. if err != nil {
  290. return nil, err
  291. }
  292. if err != nil {
  293. return nil, err
  294. }
  295. parentPath, base := pathSplit(path)
  296. parentDir, err := m.getDir(parentPath, false)
  297. if err != nil {
  298. return nil, err
  299. }
  300. file, err := m.getFile(parentDir, base)
  301. if err != nil {
  302. return nil, err
  303. }
  304. return struct {
  305. io.Closer
  306. *bytes.Reader
  307. }{
  308. ioutil.NopCloser(nil),
  309. bytes.NewReader(file.bytes),
  310. }, nil
  311. }
  312. // a mockFileInfo is for exporting file stats in a way that satisfies the FileInfo interface
  313. type mockFileInfo struct {
  314. path string
  315. size int64
  316. modTime time.Time // time at which the inode's contents were modified
  317. permTime time.Time // time at which the inode's permissions were modified
  318. mode os.FileMode
  319. inodeNumber uint64
  320. deviceNumber uint64
  321. }
  322. func (m *mockFileInfo) Name() string {
  323. return m.path
  324. }
  325. func (m *mockFileInfo) Size() int64 {
  326. return m.size
  327. }
  328. func (m *mockFileInfo) Mode() os.FileMode {
  329. return m.mode
  330. }
  331. func (m *mockFileInfo) ModTime() time.Time {
  332. return m.modTime
  333. }
  334. func (m *mockFileInfo) IsDir() bool {
  335. return m.mode&os.ModeDir != 0
  336. }
  337. func (m *mockFileInfo) Sys() interface{} {
  338. return nil
  339. }
  340. func (m *MockFs) dirToFileInfo(d *mockDir, path string) (info *mockFileInfo) {
  341. return &mockFileInfo{
  342. path: filepath.Base(path),
  343. size: 1,
  344. modTime: d.modTime,
  345. permTime: d.permTime,
  346. mode: os.ModeDir,
  347. inodeNumber: d.inodeNumber,
  348. deviceNumber: m.deviceNumber,
  349. }
  350. }
  351. func (m *MockFs) fileToFileInfo(f *mockFile, path string) (info *mockFileInfo) {
  352. return &mockFileInfo{
  353. path: filepath.Base(path),
  354. size: 1,
  355. modTime: f.modTime,
  356. permTime: f.permTime,
  357. mode: 0,
  358. inodeNumber: f.inodeNumber,
  359. deviceNumber: m.deviceNumber,
  360. }
  361. }
  362. func (m *MockFs) linkToFileInfo(l *mockLink, path string) (info *mockFileInfo) {
  363. return &mockFileInfo{
  364. path: filepath.Base(path),
  365. size: 1,
  366. modTime: l.modTime,
  367. permTime: l.permTime,
  368. mode: os.ModeSymlink,
  369. inodeNumber: l.inodeNumber,
  370. deviceNumber: m.deviceNumber,
  371. }
  372. }
  373. func (m *MockFs) Lstat(path string) (stats os.FileInfo, err error) {
  374. // update aggregates
  375. m.aggregatesLock.Lock()
  376. m.StatCalls = append(m.StatCalls, path)
  377. m.aggregatesLock.Unlock()
  378. // resolve symlinks
  379. path, err = m.resolve(path, false)
  380. if err != nil {
  381. return nil, err
  382. }
  383. // special case for root dir
  384. if path == "/" {
  385. return m.dirToFileInfo(&m.root, "/"), nil
  386. }
  387. // determine type and handle appropriately
  388. parentPath, baseName := pathSplit(path)
  389. dir, err := m.getDir(parentPath, false)
  390. if err != nil {
  391. return nil, err
  392. }
  393. subdir, subdirExists := dir.subdirs[baseName]
  394. if subdirExists {
  395. return m.dirToFileInfo(subdir, path), nil
  396. }
  397. file, fileExists := dir.files[baseName]
  398. if fileExists {
  399. return m.fileToFileInfo(file, path), nil
  400. }
  401. link, linkExists := dir.symlinks[baseName]
  402. if linkExists {
  403. return m.linkToFileInfo(link, path), nil
  404. }
  405. // not found
  406. return nil, &os.PathError{
  407. Op: "stat",
  408. Path: path,
  409. Err: os.ErrNotExist,
  410. }
  411. }
  412. func (m *MockFs) Stat(path string) (stats os.FileInfo, err error) {
  413. // resolve symlinks
  414. path, err = m.resolve(path, true)
  415. if err != nil {
  416. return nil, err
  417. }
  418. return m.Lstat(path)
  419. }
  420. func (m *MockFs) InodeNumber(info os.FileInfo) (number uint64, err error) {
  421. mockInfo, ok := info.(*mockFileInfo)
  422. if ok {
  423. return mockInfo.inodeNumber, nil
  424. }
  425. return 0, fmt.Errorf("%v is not a mockFileInfo", info)
  426. }
  427. func (m *MockFs) DeviceNumber(info os.FileInfo) (number uint64, err error) {
  428. mockInfo, ok := info.(*mockFileInfo)
  429. if ok {
  430. return mockInfo.deviceNumber, nil
  431. }
  432. return 0, fmt.Errorf("%v is not a mockFileInfo", info)
  433. }
  434. func (m *MockFs) PermTime(info os.FileInfo) (when time.Time, err error) {
  435. mockInfo, ok := info.(*mockFileInfo)
  436. if ok {
  437. return mockInfo.permTime, nil
  438. }
  439. return time.Date(0, 0, 0, 0, 0, 0, 0, nil),
  440. fmt.Errorf("%v is not a mockFileInfo", info)
  441. }
  442. func (m *MockFs) ReadDir(path string) (contents []DirEntryInfo, err error) {
  443. // update aggregates
  444. m.aggregatesLock.Lock()
  445. m.ReadDirCalls = append(m.ReadDirCalls, path)
  446. m.aggregatesLock.Unlock()
  447. // locate directory
  448. path, err = m.resolve(path, true)
  449. if err != nil {
  450. return nil, err
  451. }
  452. results := []DirEntryInfo{}
  453. dir, err := m.getDir(path, false)
  454. if err != nil {
  455. return nil, err
  456. }
  457. if dir.readErr != nil {
  458. return nil, &os.PathError{
  459. Op: "read",
  460. Path: path,
  461. Err: dir.readErr,
  462. }
  463. }
  464. // describe its contents
  465. for name, subdir := range dir.subdirs {
  466. dirInfo := m.dirToFileInfo(subdir, name)
  467. results = append(results, dirInfo)
  468. }
  469. for name, file := range dir.files {
  470. info := m.fileToFileInfo(file, name)
  471. results = append(results, info)
  472. }
  473. for name, link := range dir.symlinks {
  474. info := m.linkToFileInfo(link, name)
  475. results = append(results, info)
  476. }
  477. return results, nil
  478. }
  479. func (m *MockFs) Rename(sourcePath string, destPath string) error {
  480. // validate source parent exists
  481. sourcePath, err := m.resolve(sourcePath, false)
  482. if err != nil {
  483. return err
  484. }
  485. sourceParentPath := filepath.Dir(sourcePath)
  486. sourceParentDir, err := m.getDir(sourceParentPath, false)
  487. if err != nil {
  488. return err
  489. }
  490. if sourceParentDir == nil {
  491. return &os.PathError{
  492. Op: "move",
  493. Path: sourcePath,
  494. Err: os.ErrNotExist,
  495. }
  496. }
  497. if sourceParentDir.readErr != nil {
  498. return &os.PathError{
  499. Op: "move",
  500. Path: sourcePath,
  501. Err: sourceParentDir.readErr,
  502. }
  503. }
  504. // validate dest parent exists
  505. destPath, err = m.resolve(destPath, false)
  506. destParentPath := filepath.Dir(destPath)
  507. destParentDir, err := m.getDir(destParentPath, false)
  508. if err != nil {
  509. return err
  510. }
  511. if destParentDir == nil {
  512. return &os.PathError{
  513. Op: "move",
  514. Path: destParentPath,
  515. Err: os.ErrNotExist,
  516. }
  517. }
  518. if destParentDir.readErr != nil {
  519. return &os.PathError{
  520. Op: "move",
  521. Path: destParentPath,
  522. Err: destParentDir.readErr,
  523. }
  524. }
  525. // check the source and dest themselves
  526. sourceBase := filepath.Base(sourcePath)
  527. destBase := filepath.Base(destPath)
  528. file, sourceIsFile := sourceParentDir.files[sourceBase]
  529. dir, sourceIsDir := sourceParentDir.subdirs[sourceBase]
  530. link, sourceIsLink := sourceParentDir.symlinks[sourceBase]
  531. // validate that the source exists
  532. if !sourceIsFile && !sourceIsDir && !sourceIsLink {
  533. return &os.PathError{
  534. Op: "move",
  535. Path: sourcePath,
  536. Err: os.ErrNotExist,
  537. }
  538. }
  539. // validate the destination doesn't already exist as an incompatible type
  540. _, destWasFile := destParentDir.files[destBase]
  541. _, destWasDir := destParentDir.subdirs[destBase]
  542. _, destWasLink := destParentDir.symlinks[destBase]
  543. if destWasDir {
  544. return &os.PathError{
  545. Op: "move",
  546. Path: destPath,
  547. Err: errors.New("destination exists as a directory"),
  548. }
  549. }
  550. if sourceIsDir && (destWasFile || destWasLink) {
  551. return &os.PathError{
  552. Op: "move",
  553. Path: destPath,
  554. Err: errors.New("destination exists as a file"),
  555. }
  556. }
  557. if destWasFile {
  558. delete(destParentDir.files, destBase)
  559. }
  560. if destWasDir {
  561. delete(destParentDir.subdirs, destBase)
  562. }
  563. if destWasLink {
  564. delete(destParentDir.symlinks, destBase)
  565. }
  566. if sourceIsFile {
  567. destParentDir.files[destBase] = file
  568. delete(sourceParentDir.files, sourceBase)
  569. }
  570. if sourceIsDir {
  571. destParentDir.subdirs[destBase] = dir
  572. delete(sourceParentDir.subdirs, sourceBase)
  573. }
  574. if sourceIsLink {
  575. destParentDir.symlinks[destBase] = link
  576. delete(destParentDir.symlinks, sourceBase)
  577. }
  578. destParentDir.modTime = m.Clock.Time()
  579. sourceParentDir.modTime = m.Clock.Time()
  580. return nil
  581. }
  582. func (m *MockFs) newInodeNumber() uint64 {
  583. result := m.nextInodeNumber
  584. m.nextInodeNumber++
  585. return result
  586. }
  587. func (m *MockFs) WriteFile(filePath string, data []byte, perm os.FileMode) error {
  588. filePath, err := m.resolve(filePath, true)
  589. if err != nil {
  590. return err
  591. }
  592. parentPath := filepath.Dir(filePath)
  593. parentDir, err := m.getDir(parentPath, false)
  594. if err != nil || parentDir == nil {
  595. return &os.PathError{
  596. Op: "write",
  597. Path: parentPath,
  598. Err: os.ErrNotExist,
  599. }
  600. }
  601. if parentDir.readErr != nil {
  602. return &os.PathError{
  603. Op: "write",
  604. Path: parentPath,
  605. Err: parentDir.readErr,
  606. }
  607. }
  608. baseName := filepath.Base(filePath)
  609. _, exists := parentDir.files[baseName]
  610. if !exists {
  611. parentDir.modTime = m.Clock.Time()
  612. parentDir.files[baseName] = m.newFile()
  613. } else {
  614. readErr := parentDir.files[baseName].readErr
  615. if readErr != nil {
  616. return &os.PathError{
  617. Op: "write",
  618. Path: filePath,
  619. Err: readErr,
  620. }
  621. }
  622. }
  623. file := parentDir.files[baseName]
  624. file.bytes = data
  625. file.modTime = m.Clock.Time()
  626. return nil
  627. }
  628. func (m *MockFs) newFile() *mockFile {
  629. newFile := &mockFile{}
  630. newFile.inodeNumber = m.newInodeNumber()
  631. newFile.modTime = m.Clock.Time()
  632. newFile.permTime = newFile.modTime
  633. return newFile
  634. }
  635. func (m *MockFs) newDir() *mockDir {
  636. newDir := &mockDir{
  637. subdirs: make(map[string]*mockDir, 0),
  638. files: make(map[string]*mockFile, 0),
  639. symlinks: make(map[string]*mockLink, 0),
  640. }
  641. newDir.inodeNumber = m.newInodeNumber()
  642. newDir.modTime = m.Clock.Time()
  643. newDir.permTime = newDir.modTime
  644. return newDir
  645. }
  646. func (m *MockFs) newLink(target string) *mockLink {
  647. newLink := &mockLink{
  648. target: target,
  649. }
  650. newLink.inodeNumber = m.newInodeNumber()
  651. newLink.modTime = m.Clock.Time()
  652. newLink.permTime = newLink.modTime
  653. return newLink
  654. }
  655. func (m *MockFs) MkDirs(path string) error {
  656. _, err := m.getDir(path, true)
  657. return err
  658. }
  659. // getDir doesn't support symlinks
  660. func (m *MockFs) getDir(path string, createIfMissing bool) (dir *mockDir, err error) {
  661. cleanedPath := filepath.Clean(path)
  662. if cleanedPath == "/" {
  663. return &m.root, nil
  664. }
  665. parentPath, leaf := pathSplit(cleanedPath)
  666. if len(parentPath) >= len(path) {
  667. return &m.root, nil
  668. }
  669. parent, err := m.getDir(parentPath, createIfMissing)
  670. if err != nil {
  671. return nil, err
  672. }
  673. if parent.readErr != nil {
  674. return nil, &os.PathError{
  675. Op: "stat",
  676. Path: path,
  677. Err: parent.readErr,
  678. }
  679. }
  680. childDir, dirExists := parent.subdirs[leaf]
  681. if !dirExists {
  682. if createIfMissing {
  683. // confirm that a file with the same name doesn't already exist
  684. _, fileExists := parent.files[leaf]
  685. if fileExists {
  686. return nil, &os.PathError{
  687. Op: "mkdir",
  688. Path: path,
  689. Err: os.ErrExist,
  690. }
  691. }
  692. // create this directory
  693. childDir = m.newDir()
  694. parent.subdirs[leaf] = childDir
  695. parent.modTime = m.Clock.Time()
  696. } else {
  697. return nil, &os.PathError{
  698. Op: "stat",
  699. Path: path,
  700. Err: os.ErrNotExist,
  701. }
  702. }
  703. }
  704. return childDir, nil
  705. }
  706. func (m *MockFs) Remove(path string) (err error) {
  707. path, err = m.resolve(path, false)
  708. parentPath, leaf := pathSplit(path)
  709. if len(leaf) == 0 {
  710. return fmt.Errorf("Cannot remove %v\n", path)
  711. }
  712. parentDir, err := m.getDir(parentPath, false)
  713. if err != nil {
  714. return err
  715. }
  716. if parentDir == nil {
  717. return &os.PathError{
  718. Op: "remove",
  719. Path: path,
  720. Err: os.ErrNotExist,
  721. }
  722. }
  723. if parentDir.readErr != nil {
  724. return &os.PathError{
  725. Op: "remove",
  726. Path: path,
  727. Err: parentDir.readErr,
  728. }
  729. }
  730. _, isDir := parentDir.subdirs[leaf]
  731. if isDir {
  732. return &os.PathError{
  733. Op: "remove",
  734. Path: path,
  735. Err: os.ErrInvalid,
  736. }
  737. }
  738. _, isLink := parentDir.symlinks[leaf]
  739. if isLink {
  740. delete(parentDir.symlinks, leaf)
  741. } else {
  742. _, isFile := parentDir.files[leaf]
  743. if !isFile {
  744. return &os.PathError{
  745. Op: "remove",
  746. Path: path,
  747. Err: os.ErrNotExist,
  748. }
  749. }
  750. delete(parentDir.files, leaf)
  751. }
  752. parentDir.modTime = m.Clock.Time()
  753. return nil
  754. }
  755. func (m *MockFs) Symlink(oldPath string, newPath string) (err error) {
  756. newPath, err = m.resolve(newPath, false)
  757. if err != nil {
  758. return err
  759. }
  760. newParentPath, leaf := pathSplit(newPath)
  761. newParentDir, err := m.getDir(newParentPath, false)
  762. if newParentDir.readErr != nil {
  763. return &os.PathError{
  764. Op: "link",
  765. Path: newPath,
  766. Err: newParentDir.readErr,
  767. }
  768. }
  769. if err != nil {
  770. return err
  771. }
  772. newParentDir.symlinks[leaf] = m.newLink(oldPath)
  773. return nil
  774. }
  775. func (m *MockFs) RemoveAll(path string) (err error) {
  776. path, err = m.resolve(path, false)
  777. if err != nil {
  778. return err
  779. }
  780. parentPath, leaf := pathSplit(path)
  781. if len(leaf) == 0 {
  782. return fmt.Errorf("Cannot remove %v\n", path)
  783. }
  784. parentDir, err := m.getDir(parentPath, false)
  785. if err != nil {
  786. return err
  787. }
  788. if parentDir == nil {
  789. return &os.PathError{
  790. Op: "removeAll",
  791. Path: path,
  792. Err: os.ErrNotExist,
  793. }
  794. }
  795. if parentDir.readErr != nil {
  796. return &os.PathError{
  797. Op: "removeAll",
  798. Path: path,
  799. Err: parentDir.readErr,
  800. }
  801. }
  802. _, isFile := parentDir.files[leaf]
  803. _, isLink := parentDir.symlinks[leaf]
  804. if isFile || isLink {
  805. return m.Remove(path)
  806. }
  807. _, isDir := parentDir.subdirs[leaf]
  808. if !isDir {
  809. if !isDir {
  810. return &os.PathError{
  811. Op: "removeAll",
  812. Path: path,
  813. Err: os.ErrNotExist,
  814. }
  815. }
  816. }
  817. delete(parentDir.subdirs, leaf)
  818. parentDir.modTime = m.Clock.Time()
  819. return nil
  820. }
  821. func (m *MockFs) SetReadable(path string, readable bool) error {
  822. var readErr error
  823. if !readable {
  824. readErr = os.ErrPermission
  825. }
  826. return m.SetReadErr(path, readErr)
  827. }
  828. func (m *MockFs) SetReadErr(path string, readErr error) error {
  829. path, err := m.resolve(path, false)
  830. if err != nil {
  831. return err
  832. }
  833. parentPath, leaf := filepath.Split(path)
  834. parentDir, err := m.getDir(parentPath, false)
  835. if err != nil {
  836. return err
  837. }
  838. if parentDir.readErr != nil {
  839. return &os.PathError{
  840. Op: "chmod",
  841. Path: parentPath,
  842. Err: parentDir.readErr,
  843. }
  844. }
  845. inode, err := m.getInode(parentDir, leaf)
  846. if err != nil {
  847. return err
  848. }
  849. inode.readErr = readErr
  850. inode.permTime = m.Clock.Time()
  851. return nil
  852. }
  853. func (m *MockFs) ClearMetrics() {
  854. m.ReadDirCalls = []string{}
  855. m.StatCalls = []string{}
  856. }
  857. func (m *MockFs) ViewId() (id string) {
  858. return m.viewId
  859. }
  860. func (m *MockFs) SetViewId(id string) {
  861. m.viewId = id
  862. }
  863. func (m *MockFs) SetDeviceNumber(deviceNumber uint64) {
  864. m.deviceNumber = deviceNumber
  865. }