tstor/src/export/httpfs/httpfs.go

114 lines
1.9 KiB
Go
Raw Normal View History

2023-10-08 16:46:03 +00:00
package httpfs
2021-11-23 12:05:49 +00:00
import (
"io"
"io/fs"
"net/http"
"os"
"sync"
2023-10-16 09:18:40 +00:00
"git.kmsign.ru/royalcat/tstor/src/host/vfs"
2023-10-08 16:46:03 +00:00
"git.kmsign.ru/royalcat/tstor/src/iio"
2021-11-23 12:05:49 +00:00
)
var _ http.FileSystem = &HTTPFS{}
type HTTPFS struct {
2023-10-16 09:18:40 +00:00
fs vfs.Filesystem
2021-11-23 12:05:49 +00:00
}
2023-10-16 09:18:40 +00:00
func NewHTTPFS(fs vfs.Filesystem) *HTTPFS {
2021-11-23 12:05:49 +00:00
return &HTTPFS{fs: fs}
}
2023-12-21 23:15:39 +00:00
func (hfs *HTTPFS) Open(name string) (http.File, error) {
f, err := hfs.fs.Open(name)
2021-11-23 12:05:49 +00:00
if err != nil {
return nil, err
}
2023-12-21 23:15:39 +00:00
var fis []fs.FileInfo
if f.IsDir() {
// TODO make this lazy
fis, err = hfs.filesToFileInfo(name)
if err != nil {
return nil, err
}
2021-11-23 12:05:49 +00:00
}
2023-12-21 23:15:39 +00:00
return newHTTPFile(f, fis), nil
2021-11-23 12:05:49 +00:00
}
2023-12-21 23:15:39 +00:00
func (hfs *HTTPFS) filesToFileInfo(name string) ([]fs.FileInfo, error) {
files, err := hfs.fs.ReadDir(name)
2021-11-23 12:05:49 +00:00
if err != nil {
return nil, err
}
2023-12-21 23:15:39 +00:00
out := make([]os.FileInfo, 0, len(files))
for _, f := range files {
info, err := f.Info()
if err != nil {
return nil, err
}
out = append(out, info)
2021-11-23 12:05:49 +00:00
}
return out, nil
}
var _ http.File = &httpFile{}
type httpFile struct {
2023-12-21 23:15:39 +00:00
f vfs.File
2021-11-23 12:05:49 +00:00
iio.ReaderSeeker
mu sync.Mutex
// dirPos is protected by mu.
dirPos int
dirContent []os.FileInfo
}
2023-12-21 23:15:39 +00:00
func newHTTPFile(f vfs.File, dirContent []os.FileInfo) *httpFile {
2021-11-23 12:05:49 +00:00
return &httpFile{
2023-12-21 23:15:39 +00:00
f: f,
dirContent: dirContent,
2021-11-23 12:05:49 +00:00
ReaderSeeker: iio.NewSeekerWrapper(f, f.Size()),
}
}
func (f *httpFile) Readdir(count int) ([]fs.FileInfo, error) {
2023-12-21 23:15:39 +00:00
if !f.f.IsDir() {
2021-11-23 12:05:49 +00:00
return nil, os.ErrInvalid
}
2023-12-21 23:15:39 +00:00
f.mu.Lock()
defer f.mu.Unlock()
2021-11-23 12:05:49 +00:00
old := f.dirPos
if old >= len(f.dirContent) {
// The os.File Readdir docs say that at the end of a directory,
// the error is io.EOF if count > 0 and nil if count <= 0.
if count > 0 {
return nil, io.EOF
}
return nil, nil
}
if count > 0 {
f.dirPos += count
if f.dirPos > len(f.dirContent) {
f.dirPos = len(f.dirContent)
}
} else {
f.dirPos = len(f.dirContent)
old = 0
}
return f.dirContent[old:f.dirPos], nil
}
func (f *httpFile) Stat() (fs.FileInfo, error) {
2023-12-21 23:15:39 +00:00
return f.f.Stat()
2021-11-23 12:05:49 +00:00
}