feat(archive): archive manage (#7817)

* feat(archive): archive management

* fix(ftp-server): remove duplicate ReadAtSeeker realization

* fix(archive): bad seeking of SeekableStream

* fix(archive): split internal and driver extraction api

* feat(archive): patch

* fix(shutdown): clear decompress upload tasks

* chore

* feat(archive): support .iso format

* chore
This commit is contained in:
KirCute_ECT
2025-01-18 23:28:12 +08:00
committed by GitHub
parent ab22cf8233
commit bb40e2e2cd
36 changed files with 2854 additions and 127 deletions

View File

@ -0,0 +1,96 @@
package iso9660
import (
"github.com/alist-org/alist/v3/internal/archive/tool"
"github.com/alist-org/alist/v3/internal/errs"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/stream"
"github.com/kdomanski/iso9660"
"io"
"os"
stdpath "path"
)
type ISO9660 struct {
}
func (t *ISO9660) AcceptedExtensions() []string {
return []string{".iso"}
}
func (t *ISO9660) GetMeta(ss *stream.SeekableStream, args model.ArchiveArgs) (model.ArchiveMeta, error) {
return &model.ArchiveMetaInfo{
Comment: "",
Encrypted: false,
}, nil
}
func (t *ISO9660) List(ss *stream.SeekableStream, args model.ArchiveInnerArgs) ([]model.Obj, error) {
img, err := getImage(ss)
if err != nil {
return nil, err
}
dir, err := getObj(img, args.InnerPath)
if err != nil {
return nil, err
}
if !dir.IsDir() {
return nil, errs.NotFolder
}
children, err := dir.GetChildren()
if err != nil {
return nil, err
}
ret := make([]model.Obj, 0, len(children))
for _, child := range children {
ret = append(ret, toModelObj(child))
}
return ret, nil
}
func (t *ISO9660) Extract(ss *stream.SeekableStream, args model.ArchiveInnerArgs) (io.ReadCloser, int64, error) {
img, err := getImage(ss)
if err != nil {
return nil, 0, err
}
obj, err := getObj(img, args.InnerPath)
if err != nil {
return nil, 0, err
}
if obj.IsDir() {
return nil, 0, errs.NotFile
}
return io.NopCloser(obj.Reader()), obj.Size(), nil
}
func (t *ISO9660) Decompress(ss *stream.SeekableStream, outputPath string, args model.ArchiveInnerArgs, up model.UpdateProgress) error {
img, err := getImage(ss)
if err != nil {
return err
}
obj, err := getObj(img, args.InnerPath)
if err != nil {
return err
}
if obj.IsDir() {
if args.InnerPath != "/" {
outputPath = stdpath.Join(outputPath, obj.Name())
if err = os.MkdirAll(outputPath, 0700); err != nil {
return err
}
}
var children []*iso9660.File
if children, err = obj.GetChildren(); err == nil {
err = decompressAll(children, outputPath)
}
} else {
err = decompress(obj, outputPath, up)
}
return err
}
var _ tool.Tool = (*ISO9660)(nil)
func init() {
tool.RegisterTool(&ISO9660{})
}

View File

@ -0,0 +1,100 @@
package iso9660
import (
"github.com/alist-org/alist/v3/internal/errs"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/stream"
"github.com/kdomanski/iso9660"
"io"
"os"
stdpath "path"
"strings"
)
func getImage(ss *stream.SeekableStream) (*iso9660.Image, error) {
reader, err := stream.NewReadAtSeeker(ss, 0)
if err != nil {
return nil, err
}
return iso9660.OpenImage(reader)
}
func getObj(img *iso9660.Image, path string) (*iso9660.File, error) {
obj, err := img.RootDir()
if err != nil {
return nil, err
}
if path == "/" {
return obj, nil
}
paths := strings.Split(strings.TrimPrefix(path, "/"), "/")
for _, p := range paths {
if !obj.IsDir() {
return nil, errs.ObjectNotFound
}
children, err := obj.GetChildren()
if err != nil {
return nil, err
}
exist := false
for _, child := range children {
if child.Name() == p {
obj = child
exist = true
break
}
}
if !exist {
return nil, errs.ObjectNotFound
}
}
return obj, nil
}
func toModelObj(file *iso9660.File) model.Obj {
return &model.Object{
Name: file.Name(),
Size: file.Size(),
Modified: file.ModTime(),
IsFolder: file.IsDir(),
}
}
func decompress(f *iso9660.File, path string, up model.UpdateProgress) error {
file, err := os.OpenFile(stdpath.Join(path, f.Name()), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
if err != nil {
return err
}
defer file.Close()
_, err = io.Copy(file, &stream.ReaderUpdatingProgress{
Reader: &stream.SimpleReaderWithSize{
Reader: f.Reader(),
Size: f.Size(),
},
UpdateProgress: up,
})
return err
}
func decompressAll(children []*iso9660.File, path string) error {
for _, child := range children {
if child.IsDir() {
nextChildren, err := child.GetChildren()
if err != nil {
return err
}
nextPath := stdpath.Join(path, child.Name())
if err = os.MkdirAll(nextPath, 0700); err != nil {
return err
}
if err = decompressAll(nextChildren, nextPath); err != nil {
return err
}
} else {
if err := decompress(child, path, func(_ float64) {}); err != nil {
return err
}
}
}
return nil
}