package convert import ( "archive/zip" "errors" "io" "io/fs" "os" "path/filepath" ) type ZipReader struct { r *zip.Reader p string // limit is the maximum size of a file that can be read directly // from the zip archive. Files larger than this size will be extracted limit int64 } func NewZipReader(r *zip.Reader, p string, limit int64) fs.FS { return &ZipReader{r, p, limit} } func (z *ZipReader) Open(name string) (fs.File, error) { r, err := z.r.Open(name) if err != nil { return nil, err } defer r.Close() if fi, err := r.Stat(); err != nil { return nil, err } else if fi.Size() < z.limit { return r, nil } if !filepath.IsLocal(name) { return nil, zip.ErrInsecurePath } n := filepath.Join(z.p, name) if _, err := os.Stat(n); errors.Is(err, os.ErrNotExist) { w, err := os.Create(n) if err != nil { return nil, err } defer w.Close() if _, err := io.Copy(w, r); err != nil { return nil, err } } else if err != nil { return nil, err } return os.Open(n) }