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
|
package packed
import (
"fmt"
"io"
"codeberg.org/lindenii/furgit/objecttype"
)
// deltaFrame describes one delta payload to apply during reconstruction.
type deltaFrame struct {
// packName identifies where the delta payload lives.
packName string
// dataOffset points to the start of the delta zlib payload in pack.
dataOffset int
}
// deltaPlan describes how to reconstruct one requested object.
type deltaPlan struct {
// declaredSize is the target object's declared content size.
declaredSize int64
// baseLoc points to the innermost base object.
baseLoc location
// baseType is the canonical object type resolved from baseLoc.
baseType objecttype.Type
// frames contains deltas from target down toward base.
frames []deltaFrame
}
// deltaPlanFor walks one object's chain and builds a delta reconstruction plan.
func (store *Store) deltaPlanFor(start location) (deltaPlan, error) {
visited := make(map[location]struct{})
current := start
var plan deltaPlan
plan.declaredSize = -1
for {
if _, ok := visited[current]; ok {
return deltaPlan{}, fmt.Errorf("objectstore/packed: delta cycle while resolving object")
}
visited[current] = struct{}{}
pack, meta, err := store.entryMetaAt(current)
if err != nil {
return deltaPlan{}, err
}
if plan.declaredSize < 0 {
if isBaseObjectType(meta.ty) {
plan.declaredSize = meta.size
} else {
declaredSize, err := deltaDeclaredSizeAt(pack, meta.dataOffset)
if err != nil {
return deltaPlan{}, err
}
plan.declaredSize = declaredSize
}
}
if isBaseObjectType(meta.ty) {
plan.baseLoc = current
plan.baseType = meta.ty
return plan, nil
}
switch meta.ty {
case objecttype.TypeRefDelta:
plan.frames = append(plan.frames, deltaFrame{
packName: current.packName,
dataOffset: meta.dataOffset,
})
next, err := store.lookup(meta.baseRefID)
if err != nil {
return deltaPlan{}, err
}
current = next
case objecttype.TypeOfsDelta:
plan.frames = append(plan.frames, deltaFrame{
packName: current.packName,
dataOffset: meta.dataOffset,
})
current = location{
packName: current.packName,
offset: meta.baseOfs,
}
case objecttype.TypeCommit, objecttype.TypeTree, objecttype.TypeBlob, objecttype.TypeTag:
return deltaPlan{}, fmt.Errorf("objectstore/packed: internal invariant violation for base type %d", meta.ty)
case objecttype.TypeInvalid, objecttype.TypeFuture:
return deltaPlan{}, fmt.Errorf("objectstore/packed: unsupported pack type %d", meta.ty)
default:
return deltaPlan{}, fmt.Errorf("objectstore/packed: unsupported pack type %d", meta.ty)
}
}
}
// deltaDeclaredSizeAt returns the resolved object size declared by one delta
// stream header at dataOffset.
func deltaDeclaredSizeAt(pack *packFile, dataOffset int) (int64, error) {
reader, err := zlibReaderAt(pack, dataOffset)
if err != nil {
return 0, err
}
defer func() { _ = reader.Close() }()
_, size, err := readDeltaHeaderSizes(reader)
if err != nil {
return 0, err
}
return int64(size), nil
}
// readDeltaHeaderSizes reads the first two varints in one inflated delta stream.
func readDeltaHeaderSizes(reader io.Reader) (int, int, error) {
// Two Git varints are read here. Each can take up to 10 bytes.
var buf [20]byte
n := 0
for {
if n >= len(buf) {
return 0, 0, fmt.Errorf("objectstore/packed: malformed delta varint")
}
if _, err := io.ReadFull(reader, buf[n:n+1]); err != nil {
return 0, 0, fmt.Errorf("objectstore/packed: malformed delta varint: %w", err)
}
n++
if buf[n-1]&0x80 == 0 {
break
}
}
pos := 0
srcSize, err := readDeltaVarint(buf[:n], &pos)
if err != nil {
return 0, 0, err
}
for {
if n >= len(buf) {
return 0, 0, fmt.Errorf("objectstore/packed: malformed delta varint")
}
if _, err := io.ReadFull(reader, buf[n:n+1]); err != nil {
return 0, 0, fmt.Errorf("objectstore/packed: malformed delta varint: %w", err)
}
n++
if buf[n-1]&0x80 == 0 {
break
}
}
dstSize, err := readDeltaVarint(buf[:n], &pos)
if err != nil {
return 0, 0, err
}
return srcSize, dstSize, nil
}
|