files.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. package wdfs
  2. import (
  3. "encoding/xml"
  4. "github.com/ipfs/go-ipfs-api"
  5. "github.com/kpmy/mipfs/ipfs_api"
  6. "github.com/kpmy/ypk/fn"
  7. "github.com/mattetti/filebuffer"
  8. "io/ioutil"
  9. "os"
  10. "sync"
  11. "time"
  12. "fmt"
  13. "github.com/kpmy/ypk/dom"
  14. . "github.com/kpmy/ypk/tc"
  15. "golang.org/x/net/webdav"
  16. "io"
  17. "strconv"
  18. "strings"
  19. )
  20. type block struct {
  21. pos int64
  22. data *filebuffer.Buffer
  23. }
  24. type file struct {
  25. ch *chain
  26. pos int64
  27. links []*shell.LsLink
  28. buf *filebuffer.Buffer
  29. wr chan *block
  30. wg *sync.WaitGroup
  31. props dom.Element
  32. }
  33. func (f *file) Name() string {
  34. return f.ch.name
  35. }
  36. func (f *file) Size() int64 {
  37. return int64(f.ch.UnixLsObject.Size)
  38. }
  39. func (f *file) Mode() os.FileMode {
  40. return 0
  41. }
  42. func (f *file) ModTime() (ret time.Time) {
  43. ret = time.Now()
  44. if !fn.IsNil(f.props) {
  45. if ts := f.props.Attr("modified"); ts != "" {
  46. if sec, err := strconv.ParseInt(ts, 10, 64); err == nil {
  47. ret = time.Unix(sec, 0)
  48. }
  49. }
  50. }
  51. return
  52. }
  53. func (f *file) IsDir() bool {
  54. return false
  55. }
  56. func (f *file) Sys() interface{} {
  57. Halt(100)
  58. return nil
  59. }
  60. func (f *file) Close() error {
  61. if f.wr != nil {
  62. close(f.wr)
  63. f.wg.Wait()
  64. } else if !f.ch.exists() {
  65. f.update(nil)
  66. }
  67. return nil
  68. }
  69. func (f *file) Read(p []byte) (n int, err error) {
  70. if f.links == nil {
  71. f.links, _ = ipfs_api.Shell().List(f.ch.Hash)
  72. }
  73. if len(f.links) == 0 {
  74. if fn.IsNil(f.buf) {
  75. f.buf = filebuffer.New(nil)
  76. rd, _ := ipfs_api.Shell().Cat(f.ch.Hash)
  77. io.Copy(f.buf, rd)
  78. }
  79. f.buf.Seek(f.pos, io.SeekStart)
  80. n, err = f.buf.Read(p)
  81. f.pos = f.pos + int64(n)
  82. return n, err
  83. } else {
  84. var end int64 = 0
  85. for _, l := range f.links {
  86. begin := end
  87. end = begin + int64(l.Size)
  88. if begin <= f.pos && f.pos < end {
  89. if f.buf == nil {
  90. rd, _ := ipfs_api.Shell().Cat(l.Hash)
  91. f.buf = filebuffer.New(nil)
  92. io.Copy(f.buf, rd)
  93. l.Size = uint64(f.buf.Buff.Len())
  94. }
  95. f.buf.Seek(f.pos-begin, io.SeekStart)
  96. n, err = f.buf.Read(p)
  97. f.pos = f.pos + int64(n)
  98. if f.buf.Index == int64(l.Size) {
  99. f.buf = nil
  100. }
  101. return
  102. }
  103. }
  104. panic(100)
  105. }
  106. }
  107. func (f *file) Seek(offset int64, whence int) (seek int64, err error) {
  108. switch whence {
  109. case io.SeekStart:
  110. f.pos = offset
  111. case io.SeekCurrent:
  112. f.pos = f.pos + offset
  113. case io.SeekEnd:
  114. f.pos = f.Size() + offset
  115. default:
  116. Halt(100)
  117. }
  118. Assert(f.pos >= 0, 60)
  119. seek = f.pos
  120. return
  121. }
  122. func (f *file) Readdir(count int) (ret []os.FileInfo, err error) {
  123. return nil, webdav.ErrForbidden
  124. }
  125. func (f *file) Stat() (os.FileInfo, error) {
  126. return f, nil
  127. }
  128. const emptyFileHash = "QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH"
  129. func (f *file) update(data io.ReadCloser) {
  130. if !fn.IsNil(data) {
  131. f.ch.Hash, _ = ipfs_api.Shell().Add(data)
  132. } else {
  133. f.ch.Hash = emptyFileHash
  134. }
  135. for tail := f.ch.up; tail != nil; tail = tail.up {
  136. tail.Hash, _ = ipfs_api.Shell().PatchLink(tail.Hash, tail.down.name, tail.down.Hash, false)
  137. if tail.down.Hash == f.ch.Hash {
  138. //создадим пропы
  139. f.props = newPropsModel()
  140. f.props.Attr("modified", fmt.Sprint(time.Now().Unix()))
  141. propHash, _ := ipfs_api.Shell().Add(dom.EncodeWithHeader(f.props))
  142. tail.Hash, _ = ipfs_api.Shell().PatchLink(tail.Hash, "*"+f.ch.name, propHash, false)
  143. }
  144. }
  145. head := f.ch.head()
  146. head.link.update(head.Hash)
  147. }
  148. func (f *file) Write(p []byte) (n int, err error) {
  149. if f.wr == nil {
  150. f.wr = make(chan *block, 16)
  151. f.wg = new(sync.WaitGroup)
  152. f.wg.Add(1)
  153. go func(f *file) {
  154. tmp, _ := ioutil.TempFile(os.TempDir(), "mipfs")
  155. for w := range f.wr {
  156. tmp.Seek(w.pos, io.SeekStart)
  157. w.data.Seek(0, io.SeekStart)
  158. io.Copy(tmp, w.data)
  159. }
  160. tmp.Seek(0, io.SeekStart)
  161. f.update(tmp)
  162. f.wg.Done()
  163. }(f)
  164. }
  165. b := &block{pos: f.pos}
  166. b.data = filebuffer.New(nil)
  167. n, err = b.data.Write(p)
  168. f.wr <- b
  169. f.pos = f.pos + int64(n)
  170. return n, nil
  171. }
  172. func (f *file) readPropsModel() {
  173. if !strings.HasPrefix(f.ch.name, "*") {
  174. ls, _ := ipfs_api.Shell().FileList(f.ch.up.Hash)
  175. pm := propLinksMap(ls)
  176. if p, ok := pm[f.ch.name]; ok {
  177. rd, _ := ipfs_api.Shell().Cat(p.Hash)
  178. if el, err := dom.Decode(rd); err == nil {
  179. f.props = el.Model()
  180. } else {
  181. Halt(99, f.ch.name, f.ch.Hash)
  182. }
  183. } else {
  184. f.props = newPropsModel()
  185. }
  186. }
  187. }
  188. func (f *file) readPropsObject() (props map[xml.Name]dom.Element, err error) {
  189. props = make(map[xml.Name]dom.Element)
  190. f.readPropsModel()
  191. props = readProps(f.props)
  192. return
  193. }
  194. func (f *file) writePropsObject(props map[xml.Name]dom.Element) {
  195. if !strings.HasPrefix(f.ch.name, "*") {
  196. el := writeProps(props)
  197. propHash, _ := ipfs_api.Shell().Add(dom.EncodeWithHeader(el))
  198. for tail := f.ch.up; tail != nil; tail = tail.up {
  199. if tail.down.Hash == f.ch.Hash {
  200. tail.Hash, _ = ipfs_api.Shell().PatchLink(tail.Hash, "*"+f.ch.name, propHash, false)
  201. } else {
  202. tail.Hash, _ = ipfs_api.Shell().PatchLink(tail.Hash, tail.down.name, tail.down.Hash, false)
  203. }
  204. }
  205. head := f.ch.head()
  206. head.link.update(head.Hash)
  207. }
  208. }
  209. func (f *file) DeadProps() (ret map[xml.Name]webdav.Property, err error) {
  210. //log.Println("file prop get")
  211. pm, _ := f.readPropsObject()
  212. ret = props2webdav(pm)
  213. //log.Println("read file props", ret)
  214. return
  215. }
  216. func (f *file) Patch(patch []webdav.Proppatch) (ret []webdav.Propstat, err error) {
  217. //log.Println("file prop patch", patch)
  218. pe, _ := f.readPropsObject()
  219. ret = propsPatch(pe, patch)
  220. //log.Println("write file props", pe)
  221. f.writePropsObject(pe)
  222. return
  223. }