From c9c77e9f8a00d936e7f085c8878a0e000d81cf97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E7=99=BD-=E7=99=BD?= Date: Thu, 5 May 2022 14:56:10 +0800 Subject: [PATCH] make zip contents seekable Fix "seeker can't seek" error --- main.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index ed7a409a..4b7fcf38 100644 --- a/main.go +++ b/main.go @@ -2,9 +2,11 @@ package main import ( _ "embed" + "bytes" "flag" "io" "io/fs" + "io/ioutil" "strings" "github.com/cloudreve/Cloudreve/v3/bootstrap" @@ -32,10 +34,10 @@ func init() { flag.StringVar(&scriptName, "database-script", "", "运行内置数据库助手脚本") flag.Parse() - staticFS = archiver.ArchiveFS{ + staticFS = &seekableFS{archiver.ArchiveFS{ Stream: io.NewSectionReader(strings.NewReader(staticZip), 0, int64(len(staticZip))), Format: archiver.Zip{}, - } + }} bootstrap.Init(confPath, staticFS) } @@ -79,3 +81,48 @@ func main() { util.Log().Error("无法监听[%s],%s", conf.SystemConfig.Listen, err) } } + +// https://github.com/golang/go/issues/46809 +// A seekableFS is an FS wrapper that makes every file seekable +// by reading it entirely into memory when it is opened and then +// serving read operations (including seek) from the memory copy. +type seekableFS struct { + fs fs.FS +} + +func (s *seekableFS) Open(name string) (fs.File, error) { + f, err := s.fs.Open(name) + if err != nil { + return nil, err + } + info, err := f.Stat() + if err != nil { + f.Close() + return nil, err + } + if info.IsDir() { + return f, nil + } + data, err := ioutil.ReadAll(f) + if err != nil { + f.Close() + return nil, err + } + var sf seekableFile + sf.File = f + sf.Reset(data) + return &sf, nil +} + +// A seekableFile is a fs.File augmented by an in-memory copy of the file data to allow use of Seek. +type seekableFile struct { + bytes.Reader + fs.File +} + +// Read calls f.Reader.Read. +// Both f.Reader and f.File have Read methods - a conflict - so f inherits neither. +// This method calls the one we want. +func (f *seekableFile) Read(b []byte) (int, error) { + return f.Reader.Read(b) +} \ No newline at end of file