This repository has been archived by the owner on Sep 15, 2020. It is now read-only.
forked from folbricht/desync
-
Notifications
You must be signed in to change notification settings - Fork 0
/
caibx.go
142 lines (127 loc) · 2.75 KB
/
caibx.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
package casync
import (
"fmt"
"github.com/pkg/errors"
"io"
"math"
)
// Caibx represents the content of a caibx file
type Caibx struct {
Index Index
Header Header
Chunks []BlobIndexChunk
}
// Index at the start of the caibx file
type Index struct {
Size uint64
Type uint64
Flags uint64
ChunkSizeMin uint64
ChunkSizeAvg uint64
ChunkSizeMax uint64
}
// Header follows the Index in the caibx file
type Header struct {
Size uint64
Type uint64
}
// BlobIndexChunk is a table entry in a caibx file containing the chunk ID (SHA256)
// as well as the offset within the blob after appending this chunk
type BlobIndexChunk struct {
Start uint64
Size uint64
ID ChunkID
}
// CaibxFromReader parses a caibx structure (from a reader) and returns a populated Caibx
// object
func CaibxFromReader(r io.Reader) (c Caibx, err error) {
cr := reader{r}
// Read the index
c.Index, err = readIndex(cr)
if err != nil {
return c, errors.Wrap(err, "reading index")
}
if c.Index.Type != CaFormatIndex {
return c, errors.New("Only blob indexes are supported")
}
// Read the header
c.Header, err = readHeader(cr)
if err != nil {
return c, errors.Wrap(err, "reading header")
}
if c.Header.Type != CaFormatHeader {
return c, errors.New("Expected table header")
}
if c.Header.Size != math.MaxUint64 {
return c, errors.New("Expected MAX_UINT64 at top of table")
}
// And the chunks
c.Chunks, err = readChunks(cr, c.Index.ChunkSizeMin, c.Index.ChunkSizeMax)
if err != nil {
return c, errors.Wrap(err, "reading table")
}
return
}
func readIndex(r reader) (i Index, err error) {
i.Size, err = r.ReadUint64()
if err != nil {
return
}
i.Type, err = r.ReadUint64()
if err != nil {
return
}
i.Flags, err = r.ReadUint64()
if err != nil {
return
}
i.ChunkSizeMin, err = r.ReadUint64()
if err != nil {
return
}
i.ChunkSizeAvg, err = r.ReadUint64()
if err != nil {
return
}
i.ChunkSizeMax, err = r.ReadUint64()
return
}
func readHeader(r reader) (h Header, err error) {
h.Size, err = r.ReadUint64()
if err != nil {
return
}
h.Type, err = r.ReadUint64()
return
}
func readChunks(r reader, min, max uint64) (chunks []BlobIndexChunk, err error) {
var lastOffset uint64
for {
var (
c BlobIndexChunk
offset uint64
)
offset, err = r.ReadUint64()
if err != nil {
return
}
if offset == 0 { // Last chunk?
break
}
c.Start = lastOffset
c.Size = offset - lastOffset
if c.Size < min {
return chunks, fmt.Errorf("chunk size %d is smaller than minimum %d", c.Size, min)
}
if c.Size > max {
return chunks, fmt.Errorf("chunk size %d is larger than maximum %d", c.Size, max)
}
c.ID, err = r.ReadID()
if err != nil {
return
}
lastOffset = offset
chunks = append(chunks, c)
}
return
}