filesys.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. package wdfs
  2. import (
  3. "fmt"
  4. "github.com/ipfs/go-ipfs-api"
  5. "github.com/kpmy/mipfs/ipfs_api"
  6. "github.com/kpmy/ypk/dom"
  7. "github.com/kpmy/ypk/fn"
  8. . "github.com/kpmy/ypk/tc"
  9. "golang.org/x/net/webdav"
  10. "log"
  11. "os"
  12. "strings"
  13. "time"
  14. )
  15. type filesystem struct {
  16. webdav.FileSystem
  17. nodeId *shell.IdOutput
  18. root *chain
  19. }
  20. func (f *filesystem) Mkdir(name string, perm os.FileMode) (err error) {
  21. chain := newChain(f.root.mirror(), f.root.Hash+"/"+strings.Trim(name, "/"))
  22. if tail := chain.tail(); !tail.exists() {
  23. onlyOne := true
  24. for tail != nil {
  25. if !tail.exists() {
  26. if onlyOne {
  27. tail.Hash, _ = ipfs_api.Shell().NewObject("unixfs-dir")
  28. prop := newPropsModel()
  29. prop.Attr("modified", fmt.Sprint(time.Now().Unix()))
  30. propHash, _ := ipfs_api.Shell().Add(dom.EncodeWithHeader(prop))
  31. if tail.Hash, err = ipfs_api.Shell().PatchLink(tail.Hash, "*", propHash, false); err != nil {
  32. log.Fatal(err)
  33. return
  34. }
  35. onlyOne = false
  36. } else {
  37. err = os.ErrNotExist
  38. return
  39. }
  40. }
  41. if tail.down != nil {
  42. tail.Hash, _ = ipfs_api.Shell().PatchLink(tail.Hash, tail.down.name, tail.down.Hash, false)
  43. }
  44. tail = tail.up
  45. }
  46. chain.link.update(chain.Hash)
  47. } else {
  48. err = os.ErrExist
  49. }
  50. return
  51. }
  52. func (f *filesystem) OpenFile(name string, flag int, perm os.FileMode) (ret webdav.File, err error) {
  53. log.Println("open", name, flag, perm)
  54. path := newChain(f.root.mirror(), f.root.Hash+"/"+strings.Trim(name, "/"))
  55. switch tail := path.tail(); {
  56. case tail.exists() && tail.IsDir():
  57. _l := &loc{ch: tail}
  58. _l.readPropsModel()
  59. ret = _l
  60. case tail.exists() && !tail.IsDir():
  61. _f := &file{ch: tail}
  62. _f.readPropsModel()
  63. ret = _f
  64. case !tail.exists() && flag&os.O_CREATE != 0:
  65. var edir *chain
  66. for edir = tail.up; edir != nil && edir.exists() && edir.IsDir(); edir = edir.up {
  67. }
  68. if fn.IsNil(edir) {
  69. ret = &file{ch: tail}
  70. } else {
  71. err = os.ErrNotExist
  72. }
  73. default:
  74. log.Println("open error", name, flag, perm)
  75. err = os.ErrNotExist
  76. }
  77. return
  78. }
  79. func (f *filesystem) RemoveAll(name string) (err error) {
  80. chain := newChain(f.root.mirror(), f.root.Hash+"/"+strings.Trim(name, "/"))
  81. if tail := chain.tail(); tail.exists() {
  82. tail = tail.up
  83. tail.Hash, _ = ipfs_api.Shell().Patch(tail.Hash, "rm-link", tail.down.name)
  84. if !tail.down.IsDir() {
  85. //удалим пропы
  86. if th, err := ipfs_api.Shell().Patch(tail.Hash, "rm-link", "*"+tail.down.name); err == nil {
  87. tail.Hash = th
  88. }
  89. }
  90. tail = tail.up
  91. for tail != nil {
  92. tail.Hash, _ = ipfs_api.Shell().PatchLink(tail.Hash, tail.down.name, tail.down.Hash, false)
  93. tail = tail.up
  94. }
  95. chain.link.update(chain.Hash)
  96. }
  97. return
  98. }
  99. func (f *filesystem) Rename(oldName, newName string) (err error) {
  100. //log.Println("rename", oldName, newName)
  101. on := newChain(f.root.mirror(), f.root.Hash+"/"+strings.Trim(oldName, "/"))
  102. var op *chain
  103. if !on.tail().IsDir() {
  104. propPath := ""
  105. for x := on; x != nil; x = x.down {
  106. if x.down == nil {
  107. propPath = propPath + "/" + "*" + x.name
  108. } else {
  109. propPath = propPath + "/" + x.name
  110. }
  111. }
  112. op = newChain(f.root.mirror(), propPath)
  113. }
  114. nn := newChain(f.root.mirror(), f.root.Hash+"/"+strings.Trim(newName, "/"))
  115. if ot := on.tail(); ot.exists() {
  116. if nt := nn.tail(); !nt.exists() {
  117. Assert(ot.depth() == nt.depth(), 40)
  118. tail := ot.up
  119. tail.Hash, _ = ipfs_api.Shell().Patch(tail.Hash, "rm-link", ot.name)
  120. if op != nil {
  121. tail.Hash, _ = ipfs_api.Shell().Patch(tail.Hash, "rm-link", op.tail().name)
  122. }
  123. tail.Hash, _ = ipfs_api.Shell().PatchLink(tail.Hash, nt.name, ot.Hash, false)
  124. if op != nil {
  125. tail.Hash, _ = ipfs_api.Shell().PatchLink(tail.Hash, "*"+nt.name, op.tail().Hash, false)
  126. }
  127. tail = tail.up
  128. for tail != nil {
  129. tail.Hash, _ = ipfs_api.Shell().PatchLink(tail.Hash, tail.down.name, tail.down.Hash, false)
  130. tail = tail.up
  131. }
  132. on.link.update(on.Hash)
  133. } else {
  134. err = os.ErrExist
  135. }
  136. } else {
  137. err = os.ErrNotExist
  138. }
  139. return
  140. }
  141. func (f *filesystem) Stat(name string) (fi os.FileInfo, err error) {
  142. //log.Println("stat", name)
  143. chain := newChain(f.root.mirror(), f.root.Hash+"/"+strings.Trim(name, "/"))
  144. tail := chain.tail()
  145. if !tail.exists() {
  146. err = os.ErrNotExist
  147. } else if tail.IsDir() {
  148. _l := &loc{ch: tail}
  149. _l.readPropsModel()
  150. fi = _l
  151. } else {
  152. _f := &file{ch: tail}
  153. _f.readPropsModel()
  154. fi = _f
  155. }
  156. return
  157. }
  158. func (f *filesystem) String() string {
  159. return f.root.Hash
  160. }
  161. func (f *filesystem) ETag(name string) (ret string, err error) {
  162. var fi os.FileInfo
  163. if fi, err = f.Stat(name); err == nil {
  164. ret = fmt.Sprintf(`"%x%x"`, fi.ModTime().UnixNano(), fi.Size())
  165. }
  166. return
  167. }
  168. func NewFS(id *shell.IdOutput, root string) *filesystem {
  169. ch := &chain{}
  170. ch.Hash = root
  171. ch.name = root
  172. ch.Type = "Directory"
  173. return &filesystem{nodeId: id, root: ch}
  174. }