Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alist-org
GitHub Repository: alist-org/alist
Path: blob/main/internal/archive/archives/archives.go
2368 views
1
package archives
2
3
import (
4
"fmt"
5
"io"
6
"io/fs"
7
"os"
8
stdpath "path"
9
"path/filepath"
10
"strings"
11
12
"github.com/alist-org/alist/v3/internal/archive/tool"
13
"github.com/alist-org/alist/v3/internal/model"
14
"github.com/alist-org/alist/v3/internal/stream"
15
"github.com/alist-org/alist/v3/pkg/utils"
16
)
17
18
type Archives struct {
19
}
20
21
func (Archives) AcceptedExtensions() []string {
22
return []string{
23
".br", ".bz2", ".gz", ".lz4", ".lz", ".sz", ".s2", ".xz", ".zz", ".zst", ".tar",
24
}
25
}
26
27
func (Archives) AcceptedMultipartExtensions() map[string]tool.MultipartExtension {
28
return map[string]tool.MultipartExtension{}
29
}
30
31
func (Archives) GetMeta(ss []*stream.SeekableStream, args model.ArchiveArgs) (model.ArchiveMeta, error) {
32
fsys, err := getFs(ss[0], args)
33
if err != nil {
34
return nil, err
35
}
36
files, err := fsys.ReadDir(".")
37
if err != nil {
38
return nil, filterPassword(err)
39
}
40
41
tree := make([]model.ObjTree, 0, len(files))
42
for _, file := range files {
43
info, err := file.Info()
44
if err != nil {
45
continue
46
}
47
tree = append(tree, &model.ObjectTree{Object: *toModelObj(info)})
48
}
49
return &model.ArchiveMetaInfo{
50
Comment: "",
51
Encrypted: false,
52
Tree: tree,
53
}, nil
54
}
55
56
func (Archives) List(ss []*stream.SeekableStream, args model.ArchiveInnerArgs) ([]model.Obj, error) {
57
fsys, err := getFs(ss[0], args.ArchiveArgs)
58
if err != nil {
59
return nil, err
60
}
61
innerPath := strings.TrimPrefix(args.InnerPath, "/")
62
if innerPath == "" {
63
innerPath = "."
64
}
65
obj, err := fsys.ReadDir(innerPath)
66
if err != nil {
67
return nil, filterPassword(err)
68
}
69
return utils.SliceConvert(obj, func(src os.DirEntry) (model.Obj, error) {
70
info, err := src.Info()
71
if err != nil {
72
return nil, err
73
}
74
return toModelObj(info), nil
75
})
76
}
77
78
func (Archives) Extract(ss []*stream.SeekableStream, args model.ArchiveInnerArgs) (io.ReadCloser, int64, error) {
79
fsys, err := getFs(ss[0], args.ArchiveArgs)
80
if err != nil {
81
return nil, 0, err
82
}
83
file, err := fsys.Open(strings.TrimPrefix(args.InnerPath, "/"))
84
if err != nil {
85
return nil, 0, filterPassword(err)
86
}
87
stat, err := file.Stat()
88
if err != nil {
89
return nil, 0, filterPassword(err)
90
}
91
return file, stat.Size(), nil
92
}
93
94
func (Archives) Decompress(ss []*stream.SeekableStream, outputPath string, args model.ArchiveInnerArgs, up model.UpdateProgress) error {
95
fsys, err := getFs(ss[0], args.ArchiveArgs)
96
if err != nil {
97
return err
98
}
99
isDir := false
100
path := strings.TrimPrefix(args.InnerPath, "/")
101
if path == "" {
102
isDir = true
103
path = "."
104
} else {
105
stat, err := fsys.Stat(path)
106
if err != nil {
107
return filterPassword(err)
108
}
109
if stat.IsDir() {
110
isDir = true
111
outputPath = filepath.Join(outputPath, stat.Name())
112
err = os.Mkdir(outputPath, 0700)
113
if err != nil {
114
return filterPassword(err)
115
}
116
}
117
}
118
if isDir {
119
err = fs.WalkDir(fsys, path, func(p string, d fs.DirEntry, err error) error {
120
if err != nil {
121
return err
122
}
123
if p == path {
124
if d.IsDir() {
125
return nil
126
}
127
}
128
relPath := strings.TrimPrefix(p, path+"/")
129
if relPath == "" || relPath == "." {
130
if d.IsDir() {
131
return nil
132
}
133
}
134
dstPath, err := tool.SecureJoin(outputPath, relPath)
135
if err != nil {
136
return err
137
}
138
if d.IsDir() {
139
return os.MkdirAll(dstPath, 0700)
140
}
141
info, err := d.Info()
142
if err != nil {
143
return err
144
}
145
if !info.Mode().IsRegular() {
146
return fmt.Errorf("%w: %s", tool.ErrArchiveIllegalPath, p)
147
}
148
if err := os.MkdirAll(filepath.Dir(dstPath), 0700); err != nil {
149
return err
150
}
151
return decompress(fsys, p, dstPath, func(_ float64) {})
152
})
153
} else {
154
entryName := stdpath.Base(path)
155
dstPath, e := tool.SecureJoin(outputPath, entryName)
156
if e != nil {
157
return e
158
}
159
if err = os.MkdirAll(filepath.Dir(dstPath), 0700); err != nil {
160
return err
161
}
162
err = decompress(fsys, path, dstPath, up)
163
}
164
return filterPassword(err)
165
}
166
167
var _ tool.Tool = (*Archives)(nil)
168
169
func init() {
170
tool.RegisterTool(Archives{})
171
}
172
173