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
|
package packed
import (
"errors"
"fmt"
"io"
"lindenii.org/go/furgit/internal/compress/zlib"
"lindenii.org/go/furgit/internal/format/packfile"
"lindenii.org/go/furgit/object/id"
"lindenii.org/go/lgo/intconv"
)
var errPayloadOverlong = errors.New("entry payload longer than declared")
// entryHeaderAt parses the entry header at offset,
// returning it together with the entry's compressed payload view.
//
// The entry header only contains the inflated length,
// so payload slice extends to the end of the pack;
// the compressed data length is determined by the zlib stream end,
// not the slice length.
//
// Labels: Life-Parent, Mut-No.
func (pack *pack) entryHeaderAt(offset int, objectFormat id.ObjectFormat) (packfile.EntryHeader, []byte, error) {
var zero packfile.EntryHeader
pos := offset
if pos < 0 || pos >= len(pack.data) {
return zero, nil, fmt.Errorf("%w: pack %q: entry offset out of bounds", ErrMalformedPackedStore, pack.name)
}
header, err := packfile.ParseEntryHeader(pack.data[pos:], objectFormat.Size())
if err != nil {
return zero, nil, fmt.Errorf("%w: pack %q: %w", ErrMalformedPackedStore, pack.name, err)
}
return header, pack.data[pos+header.HeaderLen:], nil
}
// inflate decompresses one entry payload of expectedSize bytes,
// rejecting payloads whose inflated size differs.
//
// Labels: Life-Independent.
func inflate(payload []byte, expectedSize uint64) ([]byte, error) {
size, err := intconv.Uint64ToInt(expectedSize)
if err != nil {
return nil, fmt.Errorf("declared size: %w", err)
}
zr, err := zlib.NewReaderBytes(payload)
if err != nil {
return nil, fmt.Errorf("inflating entry payload: %w", err)
}
defer func() { _ = zr.Close() }()
out := make([]byte, size)
_, err = io.ReadFull(zr, out)
if err != nil {
return nil, fmt.Errorf("inflating entry payload: %w", err)
}
var probe [1]byte
n, err := zr.Read(probe[:])
if n != 0 || !errors.Is(err, io.EOF) {
return nil, errPayloadOverlong
}
return out, nil
}
|