forked from koron-go/zipx
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdest.go
141 lines (116 loc) · 3.16 KB
/
dest.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package zipx
import (
"io"
"io/ioutil"
"os"
"path/filepath"
"time"
)
// DirInfo describes meta information of a dir.
type DirInfo struct {
// NonUTF8 indicates name would be non UTF-8 encoding.
NonUTF8 bool
// Mode represents directory's mode and permission bits.
Mode os.FileMode
}
// FileInfo describes meta information of a file.
type FileInfo struct {
// NonUTF8 indicates name would be non UTF-8 encoding.
NonUTF8 bool
// Size is estimated size to write.
Size uint64
// Modified is last updated time of file.
Modified time.Time
// Mode represents file's mode and permission bits.
Mode os.FileMode
}
// Destination provides destination for extraction.
type Destination interface {
// CreateDir creates a new directory in destination.
CreateDir(name string, info DirInfo) error
// CreateFile creates a new file in destination.
//
// This can return io.WriteCloser as 1st return parameter, in that case
// zipx close it automatically after have finished to use.
CreateFile(name string, info FileInfo) (io.Writer, error)
}
// Dir creates simple directory Destination.
func Dir(name string) Destination {
return dir(name)
}
type dir string
func (d dir) CreateDir(name string, info DirInfo) error {
// re-interpret name as different encoding.
if info.NonUTF8 {
n, err := DefaultReinterpreter.Reinterpret(name)
if err != nil {
return err
}
name = n
}
return os.MkdirAll(filepath.Join(string(d), name), info.Mode.Perm())
}
func (d dir) CreateFile(name string, info FileInfo) (io.Writer, error) {
// re-interpret name as different encoding.
if info.NonUTF8 {
n, err := DefaultReinterpreter.Reinterpret(name)
if err != nil {
return nil, err
}
name = n
}
name = filepath.Join(string(d), name)
err := os.MkdirAll(filepath.Dir(name), 0777)
if err != nil {
return nil, err
}
f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, info.Mode)
if err != nil {
return nil, err
}
return &file{
File: f,
mtime: info.Modified,
}, nil
}
type file struct {
*os.File
mtime time.Time
}
func (f file) Write(b []byte) (int, error) {
return f.File.Write(b)
}
func (f file) Close() error {
err := f.File.Close()
if err != nil {
return err
}
return os.Chtimes(f.File.Name(), f.mtime, f.mtime)
}
// Discard is a destination which discard all extracted files and dirs.
var Discard Destination = &discard{}
type discard struct{}
func (*discard) CreateDir(name string, info DirInfo) error {
// nothing to do.
return nil
}
func (*discard) CreateFile(name string, info FileInfo) (io.Writer, error) {
// nothing to do.
return ioutil.Discard, nil
}
// Reinterpreter provides correction of encoding of names for files and dirs.
type Reinterpreter interface {
Reinterpret(string) (string, error)
}
// ReinterpretFunc is used to implement Reinterpreter with function.
type ReinterpretFunc func(string) (string, error)
// Reinterpret re-interprets string with another encoding.
func (f ReinterpretFunc) Reinterpret(s string) (string, error) {
return f(s)
}
func noReinterpret(s string) (string, error) {
// nothing to do.
return s, nil
}
// DefaultReinterpreter is used by Dir (Destination)
var DefaultReinterpreter = ReinterpretFunc(noReinterpret)