Path: blob/main/internal/archive/rardecode/rardecode.go
2369 views
package rardecode12import (3"fmt"4"io"5"os"6stdpath "path"7"path/filepath"8"strings"910"github.com/alist-org/alist/v3/internal/archive/tool"11"github.com/alist-org/alist/v3/internal/errs"12"github.com/alist-org/alist/v3/internal/model"13"github.com/alist-org/alist/v3/internal/stream"14"github.com/nwaples/rardecode/v2"15)1617type RarDecoder struct{}1819func (RarDecoder) AcceptedExtensions() []string {20return []string{".rar"}21}2223func (RarDecoder) AcceptedMultipartExtensions() map[string]tool.MultipartExtension {24return map[string]tool.MultipartExtension{25".part1.rar": {".part%d.rar", 2},26}27}2829func (RarDecoder) GetMeta(ss []*stream.SeekableStream, args model.ArchiveArgs) (model.ArchiveMeta, error) {30l, err := list(ss, args.Password)31if err != nil {32return nil, err33}34_, tree := tool.GenerateMetaTreeFromFolderTraversal(l)35return &model.ArchiveMetaInfo{36Comment: "",37Encrypted: false,38Tree: tree,39}, nil40}4142func (RarDecoder) List(ss []*stream.SeekableStream, args model.ArchiveInnerArgs) ([]model.Obj, error) {43return nil, errs.NotSupport44}4546func (RarDecoder) Extract(ss []*stream.SeekableStream, args model.ArchiveInnerArgs) (io.ReadCloser, int64, error) {47reader, err := getReader(ss, args.Password)48if err != nil {49return nil, 0, err50}51innerPath := strings.TrimPrefix(args.InnerPath, "/")52for {53var header *rardecode.FileHeader54header, err = reader.Next()55if err == io.EOF {56break57}58if err != nil {59return nil, 0, err60}61if header.Name == innerPath {62if header.IsDir {63break64}65return io.NopCloser(reader), header.UnPackedSize, nil66}67}68return nil, 0, errs.ObjectNotFound69}7071func (RarDecoder) Decompress(ss []*stream.SeekableStream, outputPath string, args model.ArchiveInnerArgs, up model.UpdateProgress) error {72reader, err := getReader(ss, args.Password)73if err != nil {74return err75}76if args.InnerPath == "/" {77for {78var header *rardecode.FileHeader79header, err = reader.Next()80if err == io.EOF {81break82}83if err != nil {84return err85}86name := header.Name87if header.IsDir {88name = name + "/"89}90dstPath, e := tool.SecureJoin(outputPath, name)91if e != nil {92return e93}94err = decompress(reader, header, dstPath)95if err != nil {96return err97}98}99} else {100innerPath := strings.TrimPrefix(args.InnerPath, "/")101innerBase := stdpath.Base(innerPath)102createdBaseDir := false103var baseDirPath string104for {105var header *rardecode.FileHeader106header, err = reader.Next()107if err == io.EOF {108break109}110if err != nil {111return err112}113name := header.Name114if header.IsDir {115name = name + "/"116}117if name == innerPath {118if header.IsDir {119if !createdBaseDir {120baseDirPath, err = tool.SecureJoin(outputPath, innerBase)121if err != nil {122return err123}124if err = os.MkdirAll(baseDirPath, 0700); err != nil {125return err126}127createdBaseDir = true128}129continue130}131if !header.Mode().IsRegular() {132return fmt.Errorf("%w: %s", tool.ErrArchiveIllegalPath, header.Name)133}134dstPath, e := tool.SecureJoin(outputPath, stdpath.Base(innerPath))135if e != nil {136return e137}138if err = os.MkdirAll(filepath.Dir(dstPath), 0700); err != nil {139return err140}141err = _decompress(reader, header, dstPath, up)142if err != nil {143return err144}145break146} else if strings.HasPrefix(name, innerPath+"/") {147if !createdBaseDir {148baseDirPath, err = tool.SecureJoin(outputPath, innerBase)149if err != nil {150return err151}152err = os.MkdirAll(baseDirPath, 0700)153if err != nil {154return err155}156createdBaseDir = true157}158restPath := strings.TrimPrefix(name, innerPath+"/")159if restPath == "" || restPath == "." {160continue161}162dstPath, e := tool.SecureJoin(baseDirPath, restPath)163if e != nil {164return e165}166err = decompress(reader, header, dstPath)167if err != nil {168return err169}170}171}172}173return nil174}175176var _ tool.Tool = (*RarDecoder)(nil)177178func init() {179tool.RegisterTool(RarDecoder{})180}181182183