-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathload.go
275 lines (215 loc) · 7.87 KB
/
load.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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
// Copyright 2019 Vanessa Sochat. All rights reserved.
// Use of this source code is governed by the Polyform Strict license
// that can be found in the LICENSE file and available at
// https://polyformproject.org/licenses/noncommercial/1.0.0
package main
import (
"encoding/binary"
"bytes"
"fmt"
"syscall/js"
"strings"
"time"
)
// loadBytes loads an imageString from the browser and populates FileImage with data.
func (fimg *FileImage) loadBytes(value js.Value, size int) error {
// We can use CopyBytesToGo, need golang 1.13+
sif := make([]byte, size)
fmt.Println(value)
howmany := js.CopyBytesToGo(sif, value)
fmt.Println("Found", howmany, "bytes")
// Read in the string to bytes, n should equal size
reader := bytes.NewReader(sif)
n, _ := reader.Read(sif)
// Save the data and size to the FileImage
fimg.Filesize = int64(n)
fimg.Filedata = sif
fimg.Reader = bytes.NewReader(fimg.Filedata)
return nil
}
// Read the global header from the container file.
// https://github.com/sylabs/sif/blob/master/pkg/sif/load.go#L20
func (fimg *FileImage) readHeader() error {
if err := binary.Read(fimg.Reader, binary.LittleEndian, &fimg.Header); err != nil {
return fmt.Errorf("reading global header from container file: %s", err)
}
return nil
}
// A valid sif has SIFMAGIC at the top
func (fimg *FileImage) isValidSif() error {
// check various header fields
if trimZeroBytes(fimg.Header.Magic[:]) != HdrMagic {
return fmt.Errorf("invalid SIF file: Magic |%s| want |%s|", fimg.Header.Magic, HdrMagic)
}
if trimZeroBytes(fimg.Header.Version[:]) > HdrVersion {
return fmt.Errorf("invalid SIF file: Version %s want <= %s", fimg.Header.Version, HdrVersion)
}
return nil
}
// Seek to a particular spot in the Reader, exit on error
func (fimg *FileImage) seek(offset int64) error {
_, err := fimg.Reader.Seek(offset, 0);
if err != nil {
return fmt.Errorf("seek() to offset:%s %s", offset, err)
}
return nil
}
// Read descriptors from the SIF
// https://github.com/sylabs/sif/blob/master/pkg/sif/load.go#L29
func (fimg *FileImage) readDescriptors() error {
fmt.Println("fimg.Header.Descroff", fimg.Header.Descroff)
fimg.seek(fimg.Header.Descroff)
fmt.Println("fimg.Header.Dtotal", fimg.Header.Dtotal)
descr, _, err := fimg.GetPartPrimSys()
if err == nil {
fimg.PrimPartID = descr.ID
}
fmt.Println("fimg.PrimPartID", fimg.PrimPartID)
// Initialize descriptor array (slice) and read them all from file
// This seems to be too much for the browser
fimg.DescrArr = make([]Descriptor, DescrNumEntries)// fimg.Header.Dtotal)
if err := binary.Read(fimg.Reader, binary.LittleEndian, &fimg.DescrArr); err != nil {
fimg.DescrArr = nil
return fmt.Errorf("reading descriptor array from container file: %s", err)
}
return nil
}
// getDescriptors in a human friendly map (strings) from the SIF
// The keys are used to map the data to the web interface (div ids)
func (fimg *FileImage) getDescriptors() map[string]string {
descriptors := make(map[string]string)
for _, v := range fimg.DescrArr {
if !v.Used {
continue
} else {
// Data Partition
if v.Datatype == DataPartition {
descriptors["partition"] = fimg.parseDataPartition(v)
// Data Signatures
} else if v.Datatype == DataSignature {
descriptors["signature"] = fimg.parseSignature(v)
// Data Crypto Message
} else if v.Datatype == DataCryptoMessage {
descriptors["crypto"] = fimg.parseCryptoMessage(v)
}
}
}
return descriptors
}
// Parse the data partition to a user friendly string
func (fimg *FileImage) parseDataPartition(v Descriptor) string {
name := strings.TrimRight(string(v.Name[:]), "\000")
var pinfo Partition
var s string
b := bytes.NewReader(v.Extra[:])
if err := binary.Read(b, binary.LittleEndian, &pinfo); err != nil {
fmt.Println("Error reading partition type %s", err)
return ""
}
s += fmt.Sprintln(" Name: ", name)
s += fmt.Sprintln(" Datatype: ", datatypeStr(v.Datatype))
s += fmt.Sprintln(" Fstype: ", fstypeStr(pinfo.Fstype))
s += fmt.Sprintln(" Parttype: ", parttypeStr(pinfo.Parttype))
s += fmt.Sprintln(" Arch: ", GetGoArch(trimZeroBytes(pinfo.Arch[:])))
return s
}
// parse the Signature block from the sif
func (fimg *FileImage) parseSignature(v Descriptor) string {
name := strings.TrimRight(string(v.Name[:]), "\000")
var sinfo Signature
var s string
b := bytes.NewReader(v.Extra[:])
if err := binary.Read(b, binary.LittleEndian, &sinfo); err != nil {
fmt.Println("Error while extracting Signature extra info: %s", err)
return ""
}
s += fmt.Sprintln(" Name: ", name)
s += fmt.Sprintln(" Datatype: ", datatypeStr(v.Datatype))
s += fmt.Sprintln(" Hashtype: ", hashtypeStr(sinfo.Hashtype))
s += fmt.Sprintln(" Entity: ", "%0X", sinfo.Entity[:20])
s += fmt.Sprintln(" Content: ", fimg.readDescriptorContent(v.Fileoff, v.Filelen))
return s
}
// parseCryptoMessage descriptor into a string
func (fimg *FileImage) parseCryptoMessage(v Descriptor) string {
name := strings.TrimRight(string(v.Name[:]), "\000")
var s string
var cinfo CryptoMessage
b := bytes.NewReader(v.Extra[:])
if err := binary.Read(b, binary.LittleEndian, &cinfo); err != nil {
fmt.Println("Error while extracting Crypto extra info: %s", err)
return ""
}
s += fmt.Sprintln(" Name: ", name)
s += fmt.Sprintln(" DataType: ", datatypeStr(v.Datatype))
s += fmt.Sprintln(" Fmttype: ", formattypeStr(cinfo.Formattype))
s += fmt.Sprintln(" Msgtype: ", messagetypeStr(cinfo.Messagetype))
s += fmt.Sprintln(" Content: ", fimg.readDescriptorContent(v.Fileoff, v.Filelen))
return s
}
// Read content based on a seek location and length
func (fimg *FileImage) readDescriptorContent(fileOffset int64, fileLen int64) string {
fimg.seek(fileOffset)
content := make([]byte, fileLen)
fimg.Reader.Read(content)
return string(content)
}
// returnResult back to the browser, in the innerHTML of the result element
func returnResult(output string, divid string) {
js.Global().Get("document").
Call("getElementById", divid).
Set("innerHTML", output)
}
// loadContainer is linked with the JavaScript function of the same name.
// It takes as input the binary data from the SIF image, and attempts
// to read the header. This has to be modified to compile with wasm.
func loadContainer(this js.Value, val []js.Value) interface{} {
fmt.Println("The container binary is:", val[0])
fmt.Println("Size:", val[2].Int())
fmt.Println("ArrayBuffer:", val[1])
fimg := FileImage{}
// read the string of given size to bytes from the SIF file
if err := fimg.loadBytes(val[1], val[2].Int()); err != nil {
returnResult("Error loading bytes.", "header")
return nil
}
// read global header from SIF file
if err := fimg.readHeader(); err != nil {
returnResult("Error reading header.", "header")
return nil
}
// validate global header
if err := fimg.isValidSif(); err != nil {
returnResult("This is not a valid sif", "header")
return nil
}
// read descriptor data
if err := fimg.readDescriptors(); err != nil {
fmt.Println("Skipping reading descriptors: ", err)
}
// parse descriptor data
descriptors := fimg.getDescriptors()
fmt.Println(descriptors)
// header with newlines
header := fimg.FmtHeader()
// Add file info
header = addFileName(val[0].String(), header)
// Print header, and descriptors to console
fmt.Print(header)
// Replace with breaks
header = replaceNewLine(header, "<br>")
fmt.Println("Container id:", fimg.Header.ID)
fmt.Println("Created on: ", time.Unix(fimg.Header.Ctime, 0))
fmt.Println("Modified on: ", time.Unix(fimg.Header.Mtime, 0))
fmt.Println("----------------------------------------------------")
// Send result back to browser, key is div id, content is string
returnResult(header, "header")
for divid, content := range descriptors {
content = replaceNewLine(content, "<br>")
returnResult(content, divid)
}
return nil
}
func trimZeroBytes(str []byte) string {
return string(bytes.TrimRight(str, "\x00"))
}