-
Notifications
You must be signed in to change notification settings - Fork 100
/
hash.go
198 lines (155 loc) · 5.4 KB
/
hash.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
package lib
import (
"crypto/md5"
"encoding/base64"
"fmt"
"hash"
"hash/crc64"
"io"
"os"
"strings"
)
var specChineseHash = SpecText{
synopsisText: "计算本地文件的crc64或md5",
paramText: "file_url [options]",
syntaxText: `
ossutil hash file_url [--type=hashtype]
`,
detailHelpText: `
该命令计算本地文件的crc64值或md5/content-md5值, 可以通过--type选项来控制计算的类型,
可选类型值为crc64或md5, 默认为` + DefaultHashType + `。
注意:oss文件的crc64和content-md5值一般可通过stat命令查看到,参考` + StatCRC64 + `
字段和` + StatContentMD5 + `字段。若文件在oss支持crc64功能之前上传,则stat命令不支持查看crc64值;
对于append和multipart类型的文件,stat命令不支持查看content-md5值。
crc64的计算标准参考ECMA-182标准(http://www.ecma-international.org/publications/standards/Ecma-182.htm)。
计算类型为md5时,会同时输出文件的md5以及content-md5值。content-md5值其实是先计算md5
值获得128比特位数字,然后对该数字进行base64编码得到的值。关于content-md5的更多信息,
请参考https://tools.ietf.org/html/rfc1864。
用法:
ossutil hash file_url [--type=hashtype]
`,
sampleText: `
1) 计算本地文件的crc64:
ossutil hash test.txt 或
ossutil hash test.txt --type=crc64
输出:
CRC64-ECMA : 295992936743767023
2) 计算本地文件的md5:
ossutil hash test.txt --type=md5
输出:
MD5 : 01C3C45C03B2AF225EFAD9F911A33D73
Content-MD5 : AcPEXAOyryJe+tn5EaM9cw==
`,
}
var specEnglishHash = SpecText{
synopsisText: "Get crc64 or md5 of local file",
paramText: "file_url [options]",
syntaxText: `
ossutil hash file_url [--type=hashtype]
`,
detailHelpText: `
The command calculate crc64 or md5/content-md5 value of the specified local file,
specify the hashtype by --type, default hashtype is ` + DefaultHashType + `.
Warning: user can use stat command to check the crc64 or md5/content-md5 value of
normal oss object, see the ` + StatCRC64 + ` and ` + StatContentMD5 + ` field. If the object
was uploaded to oss before oss support crc64 feature, stat result will not show
` + StatCRC64 + `, if the object is append file type or multipart, stat result
will not show ` + StatContentMD5 + `.
Crc64 is calcuated according to ECMA-182(http://www.ecma-international.org/publications/standards/Ecma-182.htm).
When hashtype is md5, it will output both md5 and content-md5 of local file.
Content-md5 is base64 encoded string of md5. For more detial about content-md5,
please refer to https://tools.ietf.org/html/rfc1864.
Usage:
ossutil hash file_url [--type=hashtype]
`,
sampleText: `
1) Get crc64 of local file:
ossutil hash test.txt or
ossutil hash test.txt --type=crc64
output:
CRC64-ECMA : 295992936743767023
2) Get md5 of local file:
ossutil hash test.txt --type=md5
output:
MD5 : 01C3C45C03B2AF225EFAD9F911A33D73
Content-MD5 : AcPEXAOyryJe+tn5EaM9cw==
`,
}
// HashCommand is the command to get crc64/md5 of local file
type HashCommand struct {
command Command
}
var hashCommand = HashCommand{
command: Command{
name: "hash",
nameAlias: []string{""},
minArgc: 1,
maxArgc: 1,
specChinese: specChineseHash,
specEnglish: specEnglishHash,
group: GroupTypeAdditionalCommand,
validOptionNames: []string{
OptionHashType,
OptionLogLevel,
},
},
}
// function for RewriteLoadConfiger interface
func (hc *HashCommand) rewriteLoadConfig(configFile string) error {
// read config file, if error exist, do not print error
var err error
if hc.command.configOptions, err = LoadConfig(configFile); err != nil {
hc.command.configOptions = OptionMapType{}
}
return nil
}
// function for FormatHelper interface
func (hc *HashCommand) formatHelpForWhole() string {
return hc.command.formatHelpForWhole()
}
func (hc *HashCommand) formatIndependHelp() string {
return hc.command.formatIndependHelp()
}
// Init simulate inheritance, and polymorphism
func (hc *HashCommand) Init(args []string, options OptionMapType) error {
return hc.command.Init(args, options, hc)
}
// RunCommand simulate inheritance, and polymorphism
func (hc *HashCommand) RunCommand() error {
hashType, _ := GetString(OptionHashType, hc.command.options)
path := hc.command.args[0]
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
f.Seek(0, os.SEEK_SET)
switch strings.ToLower(hashType) {
case MD5HashType:
return hashMD5(f)
default:
return hashCRC64(f)
}
}
func hashMD5(f io.Reader) error {
md5Ins := md5.New()
w, _ := md5Ins.(hash.Hash)
if _, err := io.Copy(w, f); err != nil {
return err
}
result := md5Ins.Sum(nil)
fmt.Printf("%-28s: %X\n", HashMD5, result)
encoded := base64.StdEncoding.EncodeToString(result)
fmt.Printf("%-28s: %s\n", HashContentMD5, encoded)
return nil
}
func hashCRC64(f io.Reader) error {
crc64Ins := crc64.New(crc64.MakeTable(crc64.ECMA))
w, _ := crc64Ins.(hash.Hash)
if _, err := io.Copy(w, f); err != nil {
return err
}
result := crc64Ins.Sum64()
fmt.Printf("%-28s: %d\n", HashCRC64, result)
return nil
}