diff options
| author | 2026-06-13 03:32:21 +0000 | |
|---|---|---|
| committer | 2026-06-13 04:59:51 +0000 | |
| commit | be63ecd9711b46135bbff1769c2e4c3642255ef1 (patch) | |
| tree | d5581c8b2e438af2b8ae82dd8f200393b2dbc5d3 /object/store/packed | |
| parent | TODO: Update (diff) | |
Unify lengths
Diffstat (limited to 'object/store/packed')
| -rw-r--r-- | object/store/packed/basecache.go | 2 | ||||
| -rw-r--r-- | object/store/packed/delta.go | 30 | ||||
| -rw-r--r-- | object/store/packed/entry.go | 6 | ||||
| -rw-r--r-- | object/store/packed/internal/ingest/finalize.go | 7 | ||||
| -rw-r--r-- | object/store/packed/internal/ingest/ingest.go | 10 | ||||
| -rw-r--r-- | object/store/packed/internal/ingest/record.go | 12 | ||||
| -rw-r--r-- | object/store/packed/internal/ingest/resolve.go | 28 | ||||
| -rw-r--r-- | object/store/packed/internal/ingest/scan.go | 52 | ||||
| -rw-r--r-- | object/store/packed/internal/ingest/thin.go | 39 | ||||
| -rw-r--r-- | object/store/packed/lookup.go | 10 | ||||
| -rw-r--r-- | object/store/packed/read_test.go | 6 | ||||
| -rw-r--r-- | object/store/packed/reader.go | 34 |
12 files changed, 123 insertions, 113 deletions
diff --git a/object/store/packed/basecache.go b/object/store/packed/basecache.go index 7de4ec7b..88597404 100644 --- a/object/store/packed/basecache.go +++ b/object/store/packed/basecache.go @@ -12,7 +12,7 @@ const baseCacheMaxWeight = 96 << 20 // as a delta base cache key. type baseKey struct { pack *pack - offset uint64 + offset int } // cachedBase is a cached delta base, i.e., diff --git a/object/store/packed/delta.go b/object/store/packed/delta.go index c20a3eb5..567fd679 100644 --- a/object/store/packed/delta.go +++ b/object/store/packed/delta.go @@ -10,6 +10,7 @@ import ( "lindenii.org/go/furgit/internal/compress/zlib" "lindenii.org/go/furgit/internal/format/packfile" "lindenii.org/go/furgit/internal/format/packfile/delta" + "lindenii.org/go/lgo/intconv" ) // deltaNode is a delta entry on a resolution chain. @@ -21,14 +22,14 @@ type deltaNode struct { size uint64 // baseOffset is the entry's base entry offset. - baseOffset uint64 + baseOffset int } // unpackEntry reconstructs the object stored at offset in p, // following ref- and ofs-delta chains within the pack. // // Labels: Life-Independent. -func (packed *Packed) unpackEntry(p *pack, offset uint64) (packfile.EntryType, []byte, error) { +func (packed *Packed) unpackEntry(p *pack, offset int) (packfile.EntryType, []byte, error) { var zero packfile.EntryType var ( @@ -118,18 +119,19 @@ func (packed *Packed) unpackEntry(p *pack, offset uint64) (packfile.EntryType, [ // deltaBaseOffset resolves a delta entry's base entry offset // within the same pack. -func (packed *Packed) deltaBaseOffset(p *pack, offset uint64, header packfile.EntryHeader) (uint64, error) { +func (packed *Packed) deltaBaseOffset(p *pack, offset int, header packfile.EntryHeader) (int, error) { switch header.Type { case packfile.EntryTypeOfsDelta: - if header.OfsDistance == 0 || header.OfsDistance > offset { + dist, err := intconv.Uint64ToInt(header.OfsDistance) + if err != nil || dist == 0 || dist > offset { return 0, fmt.Errorf("%w: pack %q: invalid ofs-delta distance", ErrMalformedPackedStore, p.name) } - return offset - header.OfsDistance, nil + return offset - dist, nil case packfile.EntryTypeRefDelta: refBase := header.RefBase[:packed.objectFormat.Size()] - baseOffset, found, err := p.idx.Lookup(refBase) + baseOffsetU, found, err := p.idx.Lookup(refBase) if err != nil { return 0, fmt.Errorf("%w: pack %q: %w", ErrMalformedPackedStore, p.name, err) } @@ -146,6 +148,11 @@ func (packed *Packed) deltaBaseOffset(p *pack, offset uint64, header packfile.En ) } + baseOffset, err := intconv.Uint64ToInt(baseOffsetU) + if err != nil { + return 0, fmt.Errorf("%w: pack %q: ref-delta base offset overflows int: %w", ErrMalformedPackedStore, p.name, err) + } + return baseOffset, nil case packfile.EntryTypeInvalid, packfile.EntryTypeCommit, @@ -161,7 +168,7 @@ func (packed *Packed) deltaBaseOffset(p *pack, offset uint64, header packfile.En // resolveType walks one delta chain // to find the chained base object entry type, // without inflating any content. -func (packed *Packed) resolveType(p *pack, offset uint64, entryHeader packfile.EntryHeader) (packfile.EntryType, error) { +func (packed *Packed) resolveType(p *pack, offset int, entryHeader packfile.EntryHeader) (packfile.EntryType, error) { var zero packfile.EntryType depth := 0 @@ -194,7 +201,7 @@ func (packed *Packed) resolveType(p *pack, offset uint64, entryHeader packfile.E // deltaResultSize reads the declared result size // from one compressed delta payload prefix. -func deltaResultSize(payload []byte, deltaSize uint64) (uint64, error) { +func deltaResultSize(payload []byte, deltaSize uint64) (int, error) { zr, err := zlib.NewReader(bytes.NewReader(payload)) if err != nil { return 0, fmt.Errorf("reading delta header: %w", err) @@ -216,5 +223,10 @@ func deltaResultSize(payload []byte, deltaSize uint64) (uint64, error) { return 0, fmt.Errorf("reading delta header: %w", err) } - return resultSize, nil + size, err := intconv.Uint64ToInt(resultSize) + if err != nil { + return 0, fmt.Errorf("reading delta header: result size overflows int: %w", err) + } + + return size, nil } diff --git a/object/store/packed/entry.go b/object/store/packed/entry.go index 23f389a3..e9d45bb4 100644 --- a/object/store/packed/entry.go +++ b/object/store/packed/entry.go @@ -23,11 +23,11 @@ var errPayloadOverlong = errors.New("entry payload longer than declared") // not the slice length. // // Labels: Life-Parent, Mut-No. -func (pack *pack) entryHeaderAt(offset uint64, objectFormat id.ObjectFormat) (packfile.EntryHeader, []byte, error) { +func (pack *pack) entryHeaderAt(offset int, objectFormat id.ObjectFormat) (packfile.EntryHeader, []byte, error) { var zero packfile.EntryHeader - pos, err := intconv.Uint64ToInt(offset) - if err != nil || pos >= len(pack.data) { + 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) } diff --git a/object/store/packed/internal/ingest/finalize.go b/object/store/packed/internal/ingest/finalize.go index 7dca131a..f0ab6622 100644 --- a/object/store/packed/internal/ingest/finalize.go +++ b/object/store/packed/internal/ingest/finalize.go @@ -96,9 +96,14 @@ func (ingestion *ingestion) indexEntries() ([]packidx.Entry, []uint32, error) { var oidBytes [id.MaxObjectIDSize]byte copy(oidBytes[:], rec.oid.RawBytes()) + offset, err := intconv.IntToUint64(rec.offset) + if err != nil { + return nil, nil, fmt.Errorf("object/store/packed/internal/ingest: %w", err) + } + entries[indexPosition] = packidx.Entry{ OID: oidBytes, - Offset: rec.offset, + Offset: offset, CRC32: rec.crc32, } diff --git a/object/store/packed/internal/ingest/ingest.go b/object/store/packed/internal/ingest/ingest.go index 324ed8ce..5422b4af 100644 --- a/object/store/packed/internal/ingest/ingest.go +++ b/object/store/packed/internal/ingest/ingest.go @@ -46,17 +46,17 @@ type ingestion struct { // byOffset maps an entry offset to its record index, // and byOID maps a resolved object ID to its record index. - byOffset map[uint64]int + byOffset map[int]int byOID map[id.ObjectID]int // headerCount is the object count declared by the pack header. - headerCount uint32 + headerCount int // deltaCount counts delta records, accumulated during scanning. - deltaCount uint64 + deltaCount int // deltasResolved counts resolved delta records, for progress. - deltasResolved uint64 + deltasResolved int // packHash is the final pack trailer hash. packHash id.ObjectID @@ -101,7 +101,7 @@ func WritePack(root *os.Root, objectFormat id.ObjectFormat, src io.Reader, opts temps: nil, scanner: nil, records: nil, - byOffset: make(map[uint64]int), + byOffset: make(map[int]int), byOID: make(map[id.ObjectID]int), headerCount: count, deltaCount: 0, diff --git a/object/store/packed/internal/ingest/record.go b/object/store/packed/internal/ingest/record.go index 460365fd..69101293 100644 --- a/object/store/packed/internal/ingest/record.go +++ b/object/store/packed/internal/ingest/record.go @@ -12,15 +12,15 @@ import ( // so a record's index in the slice is also its pack order. type record struct { // offset is the entry's start offset in the pack. - offset uint64 + offset int // headerLen is the entry header length in bytes, // so the zlib payload begins at offset+headerLen. - headerLen uint64 + headerLen int // packedLen is the total on-disk entry length in bytes, // covering the header and the compressed payload. - packedLen uint64 + packedLen int // crc32 is the CRC32 of the entry's packed bytes. crc32 uint32 @@ -29,10 +29,10 @@ type record struct { packedType packfile.EntryType // declaredSize is the declared inflated payload size. - declaredSize uint64 + declaredSize int // baseOffset is the base entry offset for an ofs-delta. - baseOffset uint64 + baseOffset int // baseOID is the base object ID for a ref-delta. baseOID id.ObjectID @@ -50,6 +50,6 @@ type record struct { } // dataOffset returns the entry's compressed payload start offset. -func (record *record) dataOffset() uint64 { +func (record *record) dataOffset() int { return record.offset + record.headerLen } diff --git a/object/store/packed/internal/ingest/resolve.go b/object/store/packed/internal/ingest/resolve.go index 7e163f2d..8595d366 100644 --- a/object/store/packed/internal/ingest/resolve.go +++ b/object/store/packed/internal/ingest/resolve.go @@ -10,13 +10,12 @@ import ( "lindenii.org/go/furgit/internal/progress" "lindenii.org/go/furgit/object/header" "lindenii.org/go/furgit/object/id" - "lindenii.org/go/lgo/intconv" ) // adjacency maps each resolvable base to its delta children: // ofs-deltas keyed by base offset, ref-deltas keyed by base object ID. type adjacency struct { - byOffset map[uint64][]int + byOffset map[int][]int byOID map[id.ObjectID][]int } @@ -60,7 +59,7 @@ func (ingestion *ingestion) resolveDeltas() error { // so a resolved base can find the children that delta against it. func (ingestion *ingestion) buildAdjacency() adjacency { out := adjacency{ - byOffset: make(map[uint64][]int), + byOffset: make(map[int][]int), byOID: make(map[id.ObjectID][]int), } @@ -192,20 +191,9 @@ func (ingestion *ingestion) resolveChild( func (ingestion *ingestion) inflateRecord(index int) ([]byte, error) { rec := &ingestion.records[index] - offset, err := intconv.Uint64ToInt64(rec.dataOffset()) - if err != nil { - return nil, fmt.Errorf("object/store/packed/internal/ingest: %w", err) - } - - compressedLen, err := intconv.Uint64ToInt64(rec.packedLen - rec.headerLen) - if err != nil { - return nil, fmt.Errorf("object/store/packed/internal/ingest: %w", err) - } - - size, err := intconv.Uint64ToInt(rec.declaredSize) - if err != nil { - return nil, fmt.Errorf("object/store/packed/internal/ingest: %w", err) - } + offset := int64(rec.dataOffset()) + compressedLen := int64(rec.packedLen - rec.headerLen) + size := rec.declaredSize zr, err := zlib.NewReader(io.NewSectionReader(ingestion.packFile, offset, compressedLen)) if err != nil { @@ -238,7 +226,7 @@ func (ingestion *ingestion) hashObject(objectType packfile.EntryType, content [] return zero, fmt.Errorf("object/store/packed/internal/ingest: %w", err) } - _, _ = hashImpl.Write(header.Append(nil, ty, uint64(len(content)))) + _, _ = hashImpl.Write(header.Append(nil, ty, len(content))) _, _ = hashImpl.Write(content) oid, err := ingestion.objectFormat.FromBytes(hashImpl.Sum(nil)) @@ -263,7 +251,7 @@ func (ingestion *ingestion) resolvedRoots() []int { } // countDeltas returns the number of delta records. -func (ingestion *ingestion) countDeltas() uint64 { +func (ingestion *ingestion) countDeltas() int { return ingestion.deltaCount } @@ -272,7 +260,7 @@ func (ingestion *ingestion) countDeltas() uint64 { // Every base is resolved during scanning or thin completion, // so the unresolved records are exactly the unresolved deltas: // the delta records minus those already resolved. -func (ingestion *ingestion) countUnresolved() uint64 { +func (ingestion *ingestion) countUnresolved() int { return ingestion.deltaCount - ingestion.deltasResolved } diff --git a/object/store/packed/internal/ingest/scan.go b/object/store/packed/internal/ingest/scan.go index 56e42cea..6b3b73b7 100644 --- a/object/store/packed/internal/ingest/scan.go +++ b/object/store/packed/internal/ingest/scan.go @@ -36,7 +36,7 @@ type scanner struct { n int // consumed counts stream bytes consumed so far. - consumed uint64 + consumed int // hash accumulates the pack hash over consumed bytes // while hashing is true. @@ -66,7 +66,7 @@ func newScanner(src io.Reader, dst io.Writer, packHash hash.Hash) *scanner { // readPackHeader reads and validates the pack header from src, // returning the raw header and its declared object count. -func readPackHeader(src io.Reader) ([packfile.HeaderLen]byte, uint32, error) { +func readPackHeader(src io.Reader) ([packfile.HeaderLen]byte, int, error) { var raw [packfile.HeaderLen]byte _, err := io.ReadFull(src, raw[:]) @@ -79,7 +79,12 @@ func readPackHeader(src io.Reader) ([packfile.HeaderLen]byte, uint32, error) { return raw, 0, fmt.Errorf("%w: %w", ErrMalformedPack, err) } - return raw, packHeader.ObjectCount, nil + count, err := intconv.Uint32ToInt(packHeader.ObjectCount) + if err != nil { + return raw, 0, fmt.Errorf("%w: object count: %w", ErrMalformedPack, err) + } + + return raw, count, nil } // Read implements [io.Reader]. @@ -205,7 +210,7 @@ func (scanner *scanner) use(n int) error { } scanner.off += n - scanner.consumed += uint64(n) //nolint:gosec + scanner.consumed += n return nil } @@ -283,7 +288,7 @@ func (ingestion *ingestion) streamAndScan() error { meter := progress.New(progress.Options{ Writer: ingestion.opts.Progress, Title: "receiving objects", - Total: uint64(ingestion.headerCount), + Total: ingestion.headerCount, Delay: 0, Sparse: false, Throughput: true, @@ -295,7 +300,7 @@ func (ingestion *ingestion) streamAndScan() error { return err } - meter.Set(uint64(done)+1, ingestion.scanner.consumed) + meter.Set(done+1, ingestion.scanner.consumed) } meter.Stop("done") @@ -316,7 +321,7 @@ func (ingestion *ingestion) streamAndScan() error { } // scanEntry scans the entry beginning at start into one record. -func (ingestion *ingestion) scanEntry(start uint64) error { +func (ingestion *ingestion) scanEntry(start int) error { ingestion.scanner.beginCRC() rec, err := ingestion.scanHeader(start) @@ -329,7 +334,7 @@ func (ingestion *ingestion) scanEntry(start uint64) error { return err } - if inflated != rec.declaredSize { + if inflated != int64(rec.declaredSize) { return fmt.Errorf( "%w: entry at %d: inflated size %d differs from declared %d", ErrMalformedPack, start, inflated, rec.declaredSize, @@ -359,7 +364,7 @@ func (ingestion *ingestion) scanEntry(start uint64) error { } // scanHeader parses and consumes the entry header at start. -func (ingestion *ingestion) scanHeader(start uint64) (record, error) { +func (ingestion *ingestion) scanHeader(start int) (record, error) { var rec record rec.offset = start @@ -374,23 +379,24 @@ func (ingestion *ingestion) scanHeader(start uint64) (record, error) { return rec, fmt.Errorf("%w: entry at %d: %w", ErrMalformedPack, start, err) } - headerLen, err := intconv.IntToUint64(entryHeader.HeaderLen) + declaredSize, err := intconv.Uint64ToInt(entryHeader.Size) if err != nil { - return rec, fmt.Errorf("object/store/packed/internal/ingest: %w", err) + return rec, fmt.Errorf("%w: entry at %d: declared size overflows int: %w", ErrMalformedPack, start, err) } rec.packedType = entryHeader.Type - rec.declaredSize = entryHeader.Size - rec.headerLen = headerLen + rec.declaredSize = declaredSize + rec.headerLen = entryHeader.HeaderLen switch entryHeader.Type { case packfile.EntryTypeCommit, packfile.EntryTypeTree, packfile.EntryTypeBlob, packfile.EntryTypeTag: case packfile.EntryTypeOfsDelta: - if entryHeader.OfsDistance == 0 || entryHeader.OfsDistance > start { + dist, err := intconv.Uint64ToInt(entryHeader.OfsDistance) + if err != nil || dist == 0 || dist > start { return rec, fmt.Errorf("%w: entry at %d: ofs-delta base out of bounds", ErrMalformedPack, start) } - rec.baseOffset = start - entryHeader.OfsDistance + rec.baseOffset = start - dist case packfile.EntryTypeRefDelta: baseID, err := ingestion.objectFormat.FromBytes(entryHeader.RefBase[:ingestion.objectFormat.Size()]) if err != nil { @@ -412,7 +418,7 @@ func (ingestion *ingestion) scanHeader(start uint64) (record, error) { // drainPayload consumes one entry's compressed payload from the stream, // returning its inflated length and, for base entries, its object ID. -func (ingestion *ingestion) drainPayload(rec *record) (uint64, id.ObjectID, error) { +func (ingestion *ingestion) drainPayload(rec *record) (int64, id.ObjectID, error) { var zero id.ObjectID zr, err := zlib.NewReader(ingestion.scanner) @@ -428,12 +434,7 @@ func (ingestion *ingestion) drainPayload(rec *record) (uint64, id.ObjectID, erro return 0, zero, fmt.Errorf("%w: entry at %d: %w", ErrMalformedPack, rec.offset, err) } - inflated, err := intconv.Int64ToUint64(read) - if err != nil { - return 0, zero, fmt.Errorf("object/store/packed/internal/ingest: %w", err) - } - - return inflated, zero, nil + return read, zero, nil } objectType, err := rec.packedType.ObjectType() @@ -458,10 +459,5 @@ func (ingestion *ingestion) drainPayload(rec *record) (uint64, id.ObjectID, erro return 0, zero, fmt.Errorf("object/store/packed/internal/ingest: %w", err) } - inflated, err := intconv.Int64ToUint64(read) - if err != nil { - return 0, zero, fmt.Errorf("object/store/packed/internal/ingest: %w", err) - } - - return inflated, oid, nil + return read, oid, nil } diff --git a/object/store/packed/internal/ingest/thin.go b/object/store/packed/internal/ingest/thin.go index e96846cb..8d1566e0 100644 --- a/object/store/packed/internal/ingest/thin.go +++ b/object/store/packed/internal/ingest/thin.go @@ -25,8 +25,8 @@ func (ingestion *ingestion) fixThin(external []id.ObjectID, adjacency adjacency, return ErrThinPackNotPermitted } - hashSize := uint64(ingestion.objectFormat.Size()) //nolint:gosec - if ingestion.scanner.consumed < uint64(packfile.HeaderLen)+hashSize { + hashSize := ingestion.objectFormat.Size() + if ingestion.scanner.consumed < packfile.HeaderLen+hashSize { return fmt.Errorf("%w: pack shorter than trailer", ErrMalformedPack) } @@ -96,11 +96,7 @@ func (ingestion *ingestion) appendBaseObject(objectID id.ObjectID, objectType ty } start := ingestion.scanner.consumed - - startOffset, err := intconv.Uint64ToInt64(start) - if err != nil { - return 0, fmt.Errorf("object/store/packed/internal/ingest: %w", err) - } + startOffset := int64(start) headerBytes := packfile.AppendTypeSize(nil, entryType, uint64(len(content))) @@ -129,17 +125,8 @@ func (ingestion *ingestion) appendBaseObject(objectID id.ObjectID, objectType ty return 0, fmt.Errorf("object/store/packed/internal/ingest: compressing thin base: %w", err) } - compressedLen, err := intconv.Int64ToUint64(writer.offset - dataOffset) - if err != nil { - return 0, fmt.Errorf("object/store/packed/internal/ingest: %w", err) - } - - headerLen, err := intconv.IntToUint64(len(headerBytes)) - if err != nil { - return 0, fmt.Errorf("object/store/packed/internal/ingest: %w", err) - } - - packedLen := headerLen + compressedLen + headerLen := len(headerBytes) + packedLen := headerLen + writer.written ingestion.scanner.consumed = start + packedLen rec := record{ @@ -148,7 +135,7 @@ func (ingestion *ingestion) appendBaseObject(objectID id.ObjectID, objectType ty packedLen: packedLen, crc32: crc.Sum32(), packedType: entryType, - declaredSize: uint64(len(content)), + declaredSize: len(content), baseOffset: 0, baseOID: id.ObjectID{}, objectType: entryType, @@ -178,10 +165,7 @@ func (ingestion *ingestion) rewriteHeaderTrailer() error { return fmt.Errorf("object/store/packed/internal/ingest: rewriting header: %w", err) } - bodyEnd, err := intconv.Uint64ToInt64(ingestion.scanner.consumed) - if err != nil { - return fmt.Errorf("object/store/packed/internal/ingest: %w", err) - } + bodyEnd := int64(ingestion.scanner.consumed) hashImpl, err := ingestion.objectFormat.New() if err != nil { @@ -211,16 +195,19 @@ func (ingestion *ingestion) rewriteHeaderTrailer() error { } // offsetWriter writes to a file via WriteAt, -// advancing sequentially from a base offset. +// advancing sequentially from a base offset +// and counting the bytes written. type offsetWriter struct { - file *os.File - offset int64 + file *os.File + offset int64 + written int } // Write implements [io.Writer]. func (writer *offsetWriter) Write(p []byte) (int, error) { n, err := writer.file.WriteAt(p, writer.offset) writer.offset += int64(n) + writer.written += n return n, err //nolint:wrapcheck } diff --git a/object/store/packed/lookup.go b/object/store/packed/lookup.go index 74087072..e54d34b2 100644 --- a/object/store/packed/lookup.go +++ b/object/store/packed/lookup.go @@ -5,6 +5,7 @@ import ( "lindenii.org/go/furgit/object/id" "lindenii.org/go/furgit/object/store" + "lindenii.org/go/lgo/intconv" ) // lookup finds the pack containing objectID @@ -12,7 +13,7 @@ import ( // probing packs in most-recently-used-ish order. // // Labels: Life-Parent. -func (packed *Packed) lookup(objectID id.ObjectID) (*pack, uint64, error) { +func (packed *Packed) lookup(objectID id.ObjectID) (*pack, int, error) { if objectID.ObjectFormat() != packed.objectFormat { return nil, 0, fmt.Errorf( "%w: got %s want %s", @@ -23,7 +24,7 @@ func (packed *Packed) lookup(objectID id.ObjectID) (*pack, uint64, error) { oid := objectID.RawBytes() for _, p := range packed.order.Keys() { - offset, found, err := p.idx.Lookup(oid) + offsetU, found, err := p.idx.Lookup(oid) if err != nil { return nil, 0, fmt.Errorf("%w: pack %q: %w", ErrMalformedPackedStore, p.name, err) } @@ -32,6 +33,11 @@ func (packed *Packed) lookup(objectID id.ObjectID) (*pack, uint64, error) { continue } + offset, err := intconv.Uint64ToInt(offsetU) + if err != nil { + return nil, 0, fmt.Errorf("%w: pack %q: entry offset overflows int: %w", ErrMalformedPackedStore, p.name, err) + } + packed.order.Touch(p) return p, offset, nil diff --git a/object/store/packed/read_test.go b/object/store/packed/read_test.go index 02a3a5b0..64faaf5b 100644 --- a/object/store/packed/read_test.go +++ b/object/store/packed/read_test.go @@ -70,7 +70,7 @@ func TestReadGitPack(t *testing.T) { t.Fatalf("ReadHeader(%s) type = %v, want %v", oid, ty, group.ty) } - if size != uint64(len(wantContent)) { + if size != len(wantContent) { t.Fatalf("ReadHeader(%s) size = %d, want %d", oid, size, len(wantContent)) } @@ -79,7 +79,7 @@ func TestReadGitPack(t *testing.T) { t.Fatalf("ReadSize(%s): %v", oid, err) } - if size != uint64(len(wantContent)) { + if size != len(wantContent) { t.Fatalf("ReadSize(%s) = %d, want %d", oid, size, len(wantContent)) } @@ -105,7 +105,7 @@ func checkReaderContent(t *testing.T, packedStore *packed.Packed, oid id.ObjectI t.Fatalf("ReadReaderContent(%s) type = %v, want %v", oid, ty, wantType) } - if size != uint64(len(wantContent)) { + if size != len(wantContent) { t.Fatalf("ReadReaderContent(%s) size = %d, want %d", oid, size, len(wantContent)) } diff --git a/object/store/packed/reader.go b/object/store/packed/reader.go index 9c183575..bfc82eff 100644 --- a/object/store/packed/reader.go +++ b/object/store/packed/reader.go @@ -11,6 +11,7 @@ import ( "lindenii.org/go/furgit/object/header" "lindenii.org/go/furgit/object/id" "lindenii.org/go/furgit/object/typ" + "lindenii.org/go/lgo/intconv" ) // ReadBytesContent reads an object's type and content bytes, @@ -42,7 +43,7 @@ func (packed *Packed) ReadBytesFull(objectID id.ObjectID) ([]byte, error) { return nil, err } - raw := header.Append(make([]byte, 0, len(content)+32), ty, uint64(len(content))) + raw := header.Append(make([]byte, 0, len(content)+32), ty, len(content)) return append(raw, content...), nil } @@ -52,7 +53,7 @@ func (packed *Packed) ReadBytesFull(objectID id.ObjectID) ([]byte, error) { // For delta entries this resolves the chained base type // and the declared delta result size, // without reconstructing content. -func (packed *Packed) ReadHeader(objectID id.ObjectID) (typ.Type, uint64, error) { +func (packed *Packed) ReadHeader(objectID id.ObjectID) (typ.Type, int, error) { p, offset, err := packed.lookup(objectID) if err != nil { return typ.Unknown, 0, err @@ -63,13 +64,18 @@ func (packed *Packed) ReadHeader(objectID id.ObjectID) (typ.Type, uint64, error) return typ.Unknown, 0, err } - size := entryHeader.Size + var size int if entryHeader.Type.IsDelta() { size, err = deltaResultSize(payload, entryHeader.Size) if err != nil { return typ.Unknown, 0, fmt.Errorf("%w: pack %q: %w", ErrMalformedPackedStore, p.name, err) } + } else { + size, err = intconv.Uint64ToInt(entryHeader.Size) + if err != nil { + return typ.Unknown, 0, fmt.Errorf("%w: pack %q: object size overflows int: %w", ErrMalformedPackedStore, p.name, err) + } } entryType, err := packed.resolveType(p, offset, entryHeader) @@ -89,7 +95,7 @@ func (packed *Packed) ReadHeader(objectID id.ObjectID) (typ.Type, uint64, error) // // Unlike ReadHeader, // this never walks delta chains. -func (packed *Packed) ReadSize(objectID id.ObjectID) (uint64, error) { +func (packed *Packed) ReadSize(objectID id.ObjectID) (int, error) { p, offset, err := packed.lookup(objectID) if err != nil { return 0, err @@ -101,7 +107,12 @@ func (packed *Packed) ReadSize(objectID id.ObjectID) (uint64, error) { } if !entryHeader.Type.IsDelta() { - return entryHeader.Size, nil + size, err := intconv.Uint64ToInt(entryHeader.Size) + if err != nil { + return 0, fmt.Errorf("%w: pack %q: object size overflows int: %w", ErrMalformedPackedStore, p.name, err) + } + + return size, nil } size, err := deltaResultSize(payload, entryHeader.Size) @@ -119,7 +130,7 @@ func (packed *Packed) ReadSize(objectID id.ObjectID) (uint64, error) { // delta entries are fully resolved in memory first. // Close releases resources only // and does not drain unread data for additional validation. -func (packed *Packed) ReadReaderContent(objectID id.ObjectID) (typ.Type, uint64, io.ReadCloser, error) { +func (packed *Packed) ReadReaderContent(objectID id.ObjectID) (typ.Type, int, io.ReadCloser, error) { p, offset, err := packed.lookup(objectID) if err != nil { return typ.Unknown, 0, nil, err @@ -141,7 +152,7 @@ func (packed *Packed) ReadReaderContent(objectID id.ObjectID) (typ.Type, uint64, return typ.Unknown, 0, nil, err } - return ty, uint64(len(content)), io.NopCloser(bytes.NewReader(content)), nil + return ty, len(content), io.NopCloser(bytes.NewReader(content)), nil } ty, err := objectTypeOf(entryHeader.Type) @@ -149,13 +160,18 @@ func (packed *Packed) ReadReaderContent(objectID id.ObjectID) (typ.Type, uint64, return typ.Unknown, 0, nil, err } + size, err := intconv.Uint64ToInt(entryHeader.Size) + if err != nil { + return typ.Unknown, 0, nil, fmt.Errorf("%w: pack %q: object size overflows int: %w", ErrMalformedPackedStore, p.name, err) + } + zr, err := zlib.NewReader(bytes.NewReader(payload)) if err != nil { return typ.Unknown, 0, nil, fmt.Errorf("%w: pack %q: %w", ErrMalformedPackedStore, p.name, err) } - return ty, entryHeader.Size, &objectReader{ - reader: iolimit.ExpectLengthReader(zr, entryHeader.Size), + return ty, size, &objectReader{ + reader: iolimit.ExpectLengthReader(zr, size), zr: zr, }, nil } |
