fs_sys.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. package projection //import "github.com/kpmy/mipfs/dav_ipfs/projection"
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/kpmy/mipfs/dav_ipfs"
  6. "github.com/kpmy/mipfs/ipfs_api"
  7. "github.com/streamrail/concurrent-map"
  8. "golang.org/x/net/webdav"
  9. "io"
  10. "log"
  11. "os"
  12. "strings"
  13. "time"
  14. )
  15. const Active = true
  16. const Passive = false
  17. const ProjectionRoot = ".fs"
  18. type Extension interface {
  19. ConnectTo(root string)
  20. Open(chain []string) (webdav.File, error)
  21. os.FileInfo
  22. webdav.File
  23. }
  24. type item struct {
  25. name string
  26. }
  27. func (i *item) Size() int64 {
  28. return 0
  29. }
  30. func (i *item) Mode() os.FileMode {
  31. return 0
  32. }
  33. func (i *item) ModTime() time.Time {
  34. return time.Now()
  35. }
  36. func (i *item) IsDir() bool {
  37. return false
  38. }
  39. func (i *item) Sys() interface{} {
  40. return nil
  41. }
  42. func (i *item) Close() error {
  43. return nil
  44. }
  45. func (i *item) Read(p []byte) (n int, err error) {
  46. return 0, io.EOF
  47. }
  48. func (i *item) Seek(offset int64, whence int) (int64, error) {
  49. log.Println("seek")
  50. return 0, nil
  51. }
  52. func (i *item) Write(p []byte) (n int, err error) {
  53. return 0, webdav.ErrForbidden
  54. }
  55. func (i *item) Readdir(count int) (ret []os.FileInfo, err error) {
  56. return nil, webdav.ErrForbidden
  57. }
  58. func (i *item) Stat() (os.FileInfo, error) {
  59. return i, nil
  60. }
  61. func (i *item) Name() string {
  62. return i.name
  63. }
  64. type locator struct {
  65. }
  66. func (l *locator) Size() int64 {
  67. return 0
  68. }
  69. func (l *locator) Mode() os.FileMode {
  70. return os.ModeDir
  71. }
  72. func (l *locator) ModTime() time.Time {
  73. return time.Now()
  74. }
  75. func (l *locator) IsDir() bool {
  76. return true
  77. }
  78. func (l *locator) Sys() interface{} {
  79. return nil
  80. }
  81. func (l *locator) Close() error {
  82. return nil
  83. }
  84. func (l *locator) Read(p []byte) (n int, err error) {
  85. return 0, webdav.ErrForbidden
  86. }
  87. func (l *locator) Seek(offset int64, whence int) (int64, error) {
  88. return 0, webdav.ErrForbidden
  89. }
  90. func (l *locator) Write(p []byte) (n int, err error) {
  91. return 0, webdav.ErrForbidden
  92. }
  93. type ext struct {
  94. locator
  95. root string
  96. name string
  97. }
  98. func (e *ext) Name() string {
  99. return e.name
  100. }
  101. func (e *ext) Readdir(count int) (ret []os.FileInfo, err error) {
  102. log.Println(e.root)
  103. var ch <-chan string
  104. if ch, err = ipfs_api.Shell().Refs(e.root, true); err == nil {
  105. for s := range ch {
  106. ret = append(ret, &item{name: s})
  107. }
  108. }
  109. return
  110. }
  111. func (e *ext) Stat() (os.FileInfo, error) {
  112. return e, nil
  113. }
  114. func (e *ext) Open(chain []string) (ret webdav.File, err error) {
  115. if len(chain) == 1 {
  116. i := &item{name: chain[0]}
  117. ret = i
  118. } else {
  119. err = os.ErrPermission
  120. }
  121. return
  122. }
  123. func (e *ext) ConnectTo(root string) {
  124. e.root = root
  125. }
  126. type cat struct {
  127. locator
  128. pl map[string]Extension
  129. }
  130. func (c *cat) Name() string {
  131. return ProjectionRoot
  132. }
  133. func (c *cat) Readdir(count int) (ret []os.FileInfo, err error) {
  134. for _, v := range c.pl {
  135. ret = append(ret, v)
  136. }
  137. return
  138. }
  139. func (c *cat) Stat() (os.FileInfo, error) {
  140. return c, nil
  141. }
  142. type projection struct {
  143. inner webdav.FileSystem
  144. root string
  145. cache cmap.ConcurrentMap
  146. all *cat
  147. set func(string)
  148. get func() string
  149. }
  150. func isProjection(split []string) bool {
  151. return strings.ToLower(split[0]) == ProjectionRoot
  152. }
  153. func (p *projection) Mkdir(ctx context.Context, name string, perm os.FileMode) (err error) {
  154. ls := splitPath(name)
  155. switch {
  156. case len(ls) > 1 && isProjection(ls):
  157. err = os.ErrPermission
  158. case len(ls) == 1 && isProjection(ls):
  159. err = p.inner.Mkdir(ctx, strings.ToLower(name), perm)
  160. default:
  161. err = p.inner.Mkdir(ctx, name, perm)
  162. }
  163. return
  164. }
  165. func (p *projection) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (ret webdav.File, err error) {
  166. log.Println("open", name)
  167. ls := splitPath(name)
  168. switch {
  169. case isProjection(ls) && len(ls) == 1:
  170. ret = p.all
  171. case isProjection(ls) && len(ls) > 1:
  172. if e, ok := p.all.pl[ls[1]]; ok {
  173. e.ConnectTo(p.root)
  174. if len(ls) > 2 {
  175. ret, err = e.Open(ls[2:])
  176. } else {
  177. ret = e
  178. }
  179. } else {
  180. err = os.ErrNotExist
  181. }
  182. default:
  183. ret, err = p.inner.OpenFile(ctx, name, flag, perm)
  184. }
  185. return
  186. }
  187. func (p *projection) RemoveAll(ctx context.Context, name string) (err error) {
  188. ls := splitPath(name)
  189. switch {
  190. case isProjection(ls):
  191. err = os.ErrPermission
  192. default:
  193. err = p.inner.RemoveAll(ctx, name)
  194. }
  195. return
  196. }
  197. func (p *projection) Rename(ctx context.Context, oldName, newName string) (err error) {
  198. ls := splitPath(oldName)
  199. switch {
  200. case isProjection(ls):
  201. err = os.ErrPermission
  202. default:
  203. err = p.inner.Rename(ctx, oldName, newName)
  204. }
  205. return
  206. }
  207. func (p *projection) Stat(ctx context.Context, name string) (fi os.FileInfo, err error) {
  208. log.Println("stat", name)
  209. ls := splitPath(name)
  210. switch {
  211. case isProjection(ls):
  212. fi = &cat{}
  213. default:
  214. fi, err = p.inner.Stat(ctx, name)
  215. }
  216. return
  217. }
  218. func (p *projection) String() string {
  219. return fmt.Sprint(p.inner)
  220. }
  221. func NewPS(get func() string, set func(string), active bool) (fs webdav.FileSystem, ls webdav.LockSystem) {
  222. var pr *projection
  223. if active {
  224. pr = &projection{get: get}
  225. pr.set = func(hash string) {
  226. pr.root = hash
  227. set(hash)
  228. }
  229. xs := dav_ipfs.NewFS(pr.get, pr.set)
  230. ls = dav_ipfs.NewLS(xs)
  231. pr.inner = xs
  232. pr.cache = cmap.New()
  233. pr.all = &cat{}
  234. pr.all.pl = map[string]Extension{"all": &ext{name: "all"}}
  235. fs = pr
  236. } else {
  237. xs := dav_ipfs.NewFS(get, set)
  238. ls = dav_ipfs.NewLS(xs)
  239. fs = xs
  240. }
  241. return
  242. }