http_fs.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package vessel
  2. import (
  3. "archive/zip"
  4. "fmt"
  5. "net/http"
  6. "os"
  7. "path"
  8. "path/filepath"
  9. "strings"
  10. "time"
  11. )
  12. // FileSystem implements an http filesystem access to the bundle
  13. type FileSystem struct {
  14. cacheTime time.Time
  15. b *Bundle
  16. files map[string]os.FileInfo
  17. }
  18. // verify we implement the http.FileSystem interface
  19. var _ http.FileSystem = (*FileSystem)(nil)
  20. func (f *FileSystem) get(name string) (*zip.File, error) {
  21. zr, err := zip.NewReader(f.b, f.b.Size())
  22. if err != nil {
  23. return nil, os.ErrNotExist
  24. }
  25. for idx := range zr.File {
  26. z := zr.File[idx]
  27. if z.Name == name {
  28. return z, nil
  29. }
  30. }
  31. return nil, os.ErrNotExist
  32. }
  33. // Open opens a file in the filesystem
  34. func (f *FileSystem) Open(name string) (http.File, error) {
  35. log.Log("vessel.FileSystem Open: %s|%s\n", name, filepath.Dir(name))
  36. v, ok := f.files[name]
  37. if !ok {
  38. return nil, os.ErrNotExist
  39. }
  40. if v.IsDir() {
  41. return &Dir{
  42. name: name,
  43. mode: os.ModeDir,
  44. fs: f,
  45. }, nil
  46. }
  47. z, err := f.get(name)
  48. if err != nil {
  49. return nil, err
  50. }
  51. if !z.FileInfo().IsDir() {
  52. z.Modified = v.ModTime()
  53. return newFile(z)
  54. }
  55. return nil, os.ErrNotExist
  56. }
  57. // Stat returns file info for a file in the bundle filesystem
  58. func (f *FileSystem) Stat(name string) (os.FileInfo, error) {
  59. v, ok := f.files[name]
  60. if !ok {
  61. return nil, os.ErrNotExist
  62. }
  63. return v, nil
  64. }
  65. func (f *FileSystem) isDir(path string) bool {
  66. if path == string(os.PathSeparator) {
  67. return true
  68. }
  69. v, ok := f.files[path]
  70. if !ok {
  71. return false
  72. }
  73. return v.IsDir()
  74. }
  75. // Dir return a list of files contained in a subdirectory of our bundle
  76. func (f *FileSystem) Dir(path string) ([]os.FileInfo, error) {
  77. if f.isDir(path) == false {
  78. return nil, os.ErrNotExist
  79. }
  80. ls := make([]os.FileInfo, 0)
  81. for k := range f.files {
  82. if k == path {
  83. continue
  84. }
  85. d := filepath.Dir(k)
  86. if d == path {
  87. fmt.Printf("+%s\n", k)
  88. ls = append(ls, f.files[k])
  89. }
  90. }
  91. return ls, nil
  92. }
  93. func (f *FileSystem) initCaches(cacheTime time.Time) error {
  94. zr, err := zip.NewReader(f.b, f.b.Size())
  95. if err != nil {
  96. return os.ErrNotExist
  97. }
  98. f.cacheTime = cacheTime
  99. files := make(map[string]os.FileInfo)
  100. for idx := range zr.File {
  101. z := zr.File[idx]
  102. if !f.cacheTime.IsZero() {
  103. z.Modified = f.cacheTime
  104. }
  105. files[z.Name] = z.FileInfo()
  106. }
  107. // zip files don't contain directories
  108. for k, v := range files {
  109. if v.IsDir() {
  110. continue
  111. }
  112. dir := filepath.Dir(k)
  113. chunks := strings.Split(dir, string(os.PathSeparator))
  114. for i := 2; i <= len(chunks); i++ {
  115. dir := fmt.Sprintf("/%s", path.Join(chunks[:i]...))
  116. if _, ok := files[dir]; !ok {
  117. files[dir] = &Dir{
  118. name: dir,
  119. mode: os.ModeDir,
  120. fs: f,
  121. }
  122. }
  123. }
  124. }
  125. f.files = files
  126. return nil
  127. }