file.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. package http
  2. import (
  3. "io/fs"
  4. "net/http"
  5. "os"
  6. "path"
  7. "strings"
  8. "time"
  9. )
  10. type (
  11. FS struct {
  12. fs http.FileSystem
  13. modtime time.Time
  14. prefix string
  15. indexFile string
  16. denyDirectory bool
  17. }
  18. File struct {
  19. fp http.File
  20. modtime time.Time
  21. }
  22. FileInfo struct {
  23. name string
  24. size int64
  25. mode fs.FileMode
  26. isDir bool
  27. modtime time.Time
  28. }
  29. )
  30. func (fi *FileInfo) Name() string {
  31. return fi.name
  32. }
  33. func (fi *FileInfo) Size() int64 {
  34. return fi.size
  35. }
  36. func (fi *FileInfo) Mode() fs.FileMode {
  37. return fi.mode
  38. }
  39. func (fi *FileInfo) ModTime() time.Time {
  40. return fi.modtime
  41. }
  42. func (fi *FileInfo) IsDir() bool {
  43. return fi.isDir
  44. }
  45. func (fi *FileInfo) Sys() any {
  46. return nil
  47. }
  48. func (file *File) Close() error {
  49. return file.fp.Close()
  50. }
  51. func (file *File) Read(p []byte) (n int, err error) {
  52. return file.fp.Read(p)
  53. }
  54. func (file *File) Seek(offset int64, whence int) (int64, error) {
  55. return file.fp.Seek(offset, whence)
  56. }
  57. func (file *File) Readdir(count int) ([]fs.FileInfo, error) {
  58. return file.fp.Readdir(count)
  59. }
  60. func (file *File) Stat() (fs.FileInfo, error) {
  61. fi, err := file.fp.Stat()
  62. if err != nil {
  63. return nil, err
  64. }
  65. return newFileInfo(fi, file.modtime), nil
  66. }
  67. func (fs *FS) DenyAccessDirectory() {
  68. fs.denyDirectory = true
  69. }
  70. func (fs *FS) SetPrefix(prefix string) {
  71. if prefix != "" {
  72. if prefix[0] != '/' {
  73. prefix = "/" + prefix
  74. }
  75. prefix = strings.TrimRight(prefix, "/")
  76. fs.prefix = prefix
  77. }
  78. }
  79. func (fs *FS) SetIndexFile(indexFile string) {
  80. fs.indexFile = indexFile
  81. }
  82. func (fs *FS) Open(name string) (http.File, error) {
  83. var (
  84. needRetry bool
  85. )
  86. if name == "" || name == "/" {
  87. needRetry = true
  88. }
  89. if fs.prefix != "" {
  90. if !strings.HasPrefix(name, fs.prefix) {
  91. name = path.Join(fs.prefix, name)
  92. }
  93. }
  94. fp, err := fs.fs.Open(name)
  95. if err != nil {
  96. return nil, err
  97. }
  98. if fs.denyDirectory {
  99. state, err := fp.Stat()
  100. if err != nil {
  101. return nil, err
  102. }
  103. if state.IsDir() {
  104. if needRetry {
  105. if fs.indexFile != "" {
  106. return fs.Open(path.Join(name, fs.indexFile))
  107. }
  108. }
  109. return nil, os.ErrPermission
  110. }
  111. }
  112. return &File{fp: fp, modtime: fs.modtime}, nil
  113. }
  114. func newFS(modtime time.Time, fs http.FileSystem) *FS {
  115. return &FS{
  116. fs: fs,
  117. modtime: modtime,
  118. }
  119. }
  120. func newFileInfo(fi fs.FileInfo, modtime time.Time) *FileInfo {
  121. return &FileInfo{
  122. name: fi.Name(),
  123. size: fi.Size(),
  124. mode: fi.Mode(),
  125. isDir: fi.IsDir(),
  126. modtime: modtime,
  127. }
  128. }