-
Notifications
You must be signed in to change notification settings - Fork 255
/
filefmt.go
111 lines (102 loc) · 2.93 KB
/
filefmt.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
package image
import (
"bytes"
"encoding/hex"
"strconv"
"github.com/pkg/errors"
"k8s.io/klog/v2"
)
// MaxExpectedHdrSize defines the Size of buffer used to read file headers.
// Note: this is the size of tar's header. If a larger number is used the tar unarchive operation
// creates the destination file too large, by the difference between this const and 512.
const MaxExpectedHdrSize = 512
// Headers provides a map for header info, key is file format, eg. "gz" or "tar", value is metadata describing the layout for this hdr
type Headers map[string]Header
var knownHeaders = Headers{
"gz": Header{
Format: "gz",
magicNumber: []byte{0x1F, 0x8B},
// TODO: size not in hdr
SizeOff: 0,
SizeLen: 0,
},
"qcow2": Header{
Format: "qcow2",
magicNumber: []byte{'Q', 'F', 'I', 0xfb},
mgOffset: 0,
SizeOff: 24,
SizeLen: 8,
},
"tar": Header{
Format: "tar",
magicNumber: []byte{0x75, 0x73, 0x74, 0x61, 0x72},
mgOffset: 0x101,
SizeOff: 124,
SizeLen: 8,
},
"xz": Header{
Format: "xz",
magicNumber: []byte{0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00},
// TODO: size not in hdr
SizeOff: 0,
SizeLen: 0,
},
"vmdk": Header{
Format: "vmdk",
magicNumber: []byte("KDMV"),
SizeOff: 0,
SizeLen: 0,
},
"vdi": Header{
Format: "vdi",
magicNumber: []byte("<<< Oracle VM"),
SizeOff: 0,
SizeLen: 0,
},
"vhd": Header{
Format: "vhd",
magicNumber: []byte("connectix"),
SizeOff: 0,
SizeLen: 0,
},
"vhdx": Header{
Format: "vhdx",
magicNumber: []byte("vhdxfile"),
SizeOff: 0,
SizeLen: 0,
},
}
// Header represents our parameters for a file format header
type Header struct {
Format string
magicNumber []byte
mgOffset int
SizeOff int // in bytes
SizeLen int // in bytes
}
// CopyKnownHdrs performs a simple map copy since := assignment copies the reference to the map, not contents.
func CopyKnownHdrs() Headers {
m := make(Headers)
for k, v := range knownHeaders {
m[k] = v
}
return m
}
// Match performs a check to see if the provided byte slice matches the bytes in our header data
func (h Header) Match(b []byte) bool {
return bytes.Equal(b[h.mgOffset:h.mgOffset+len(h.magicNumber)], h.magicNumber)
}
// Size uses the Header receiver offset and length fields to extract, from the passed-in file header slice (b),
// the size of the original file. It is not guaranteed that the header is known to cdi and thus 0 may be returned as the size.
func (h Header) Size(b []byte) (int64, error) {
if h.SizeLen == 0 { // no size is supported in this format's header
return 0, nil
}
s := hex.EncodeToString(b[h.SizeOff : h.SizeOff+h.SizeLen])
size, err := strconv.ParseInt(s, 16, 64)
if err != nil {
return 0, errors.Wrapf(err, "unable to determine original file size from %+v", s)
}
klog.V(3).Infof("Size: %q size in bytes (at off %d:%d): %d", h.Format, h.SizeOff, h.SizeOff+h.SizeLen, size)
return size, nil
}