Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alist-org
GitHub Repository: alist-org/alist
Path: blob/main/internal/archive/rardecode/rardecode.go
2369 views
1
package rardecode
2
3
import (
4
"fmt"
5
"io"
6
"os"
7
stdpath "path"
8
"path/filepath"
9
"strings"
10
11
"github.com/alist-org/alist/v3/internal/archive/tool"
12
"github.com/alist-org/alist/v3/internal/errs"
13
"github.com/alist-org/alist/v3/internal/model"
14
"github.com/alist-org/alist/v3/internal/stream"
15
"github.com/nwaples/rardecode/v2"
16
)
17
18
type RarDecoder struct{}
19
20
func (RarDecoder) AcceptedExtensions() []string {
21
return []string{".rar"}
22
}
23
24
func (RarDecoder) AcceptedMultipartExtensions() map[string]tool.MultipartExtension {
25
return map[string]tool.MultipartExtension{
26
".part1.rar": {".part%d.rar", 2},
27
}
28
}
29
30
func (RarDecoder) GetMeta(ss []*stream.SeekableStream, args model.ArchiveArgs) (model.ArchiveMeta, error) {
31
l, err := list(ss, args.Password)
32
if err != nil {
33
return nil, err
34
}
35
_, tree := tool.GenerateMetaTreeFromFolderTraversal(l)
36
return &model.ArchiveMetaInfo{
37
Comment: "",
38
Encrypted: false,
39
Tree: tree,
40
}, nil
41
}
42
43
func (RarDecoder) List(ss []*stream.SeekableStream, args model.ArchiveInnerArgs) ([]model.Obj, error) {
44
return nil, errs.NotSupport
45
}
46
47
func (RarDecoder) Extract(ss []*stream.SeekableStream, args model.ArchiveInnerArgs) (io.ReadCloser, int64, error) {
48
reader, err := getReader(ss, args.Password)
49
if err != nil {
50
return nil, 0, err
51
}
52
innerPath := strings.TrimPrefix(args.InnerPath, "/")
53
for {
54
var header *rardecode.FileHeader
55
header, err = reader.Next()
56
if err == io.EOF {
57
break
58
}
59
if err != nil {
60
return nil, 0, err
61
}
62
if header.Name == innerPath {
63
if header.IsDir {
64
break
65
}
66
return io.NopCloser(reader), header.UnPackedSize, nil
67
}
68
}
69
return nil, 0, errs.ObjectNotFound
70
}
71
72
func (RarDecoder) Decompress(ss []*stream.SeekableStream, outputPath string, args model.ArchiveInnerArgs, up model.UpdateProgress) error {
73
reader, err := getReader(ss, args.Password)
74
if err != nil {
75
return err
76
}
77
if args.InnerPath == "/" {
78
for {
79
var header *rardecode.FileHeader
80
header, err = reader.Next()
81
if err == io.EOF {
82
break
83
}
84
if err != nil {
85
return err
86
}
87
name := header.Name
88
if header.IsDir {
89
name = name + "/"
90
}
91
dstPath, e := tool.SecureJoin(outputPath, name)
92
if e != nil {
93
return e
94
}
95
err = decompress(reader, header, dstPath)
96
if err != nil {
97
return err
98
}
99
}
100
} else {
101
innerPath := strings.TrimPrefix(args.InnerPath, "/")
102
innerBase := stdpath.Base(innerPath)
103
createdBaseDir := false
104
var baseDirPath string
105
for {
106
var header *rardecode.FileHeader
107
header, err = reader.Next()
108
if err == io.EOF {
109
break
110
}
111
if err != nil {
112
return err
113
}
114
name := header.Name
115
if header.IsDir {
116
name = name + "/"
117
}
118
if name == innerPath {
119
if header.IsDir {
120
if !createdBaseDir {
121
baseDirPath, err = tool.SecureJoin(outputPath, innerBase)
122
if err != nil {
123
return err
124
}
125
if err = os.MkdirAll(baseDirPath, 0700); err != nil {
126
return err
127
}
128
createdBaseDir = true
129
}
130
continue
131
}
132
if !header.Mode().IsRegular() {
133
return fmt.Errorf("%w: %s", tool.ErrArchiveIllegalPath, header.Name)
134
}
135
dstPath, e := tool.SecureJoin(outputPath, stdpath.Base(innerPath))
136
if e != nil {
137
return e
138
}
139
if err = os.MkdirAll(filepath.Dir(dstPath), 0700); err != nil {
140
return err
141
}
142
err = _decompress(reader, header, dstPath, up)
143
if err != nil {
144
return err
145
}
146
break
147
} else if strings.HasPrefix(name, innerPath+"/") {
148
if !createdBaseDir {
149
baseDirPath, err = tool.SecureJoin(outputPath, innerBase)
150
if err != nil {
151
return err
152
}
153
err = os.MkdirAll(baseDirPath, 0700)
154
if err != nil {
155
return err
156
}
157
createdBaseDir = true
158
}
159
restPath := strings.TrimPrefix(name, innerPath+"/")
160
if restPath == "" || restPath == "." {
161
continue
162
}
163
dstPath, e := tool.SecureJoin(baseDirPath, restPath)
164
if e != nil {
165
return e
166
}
167
err = decompress(reader, header, dstPath)
168
if err != nil {
169
return err
170
}
171
}
172
}
173
}
174
return nil
175
}
176
177
var _ tool.Tool = (*RarDecoder)(nil)
178
179
func init() {
180
tool.RegisterTool(RarDecoder{})
181
}
182
183