diff options
| author | 2026-02-21 17:13:06 +0800 | |
|---|---|---|
| committer | 2026-02-21 17:13:06 +0800 | |
| commit | 1fdcdc4d8a160f4b2b48be10f6eef2235b99f8f6 (patch) | |
| tree | 0941ffb77b0fe406924cf29b3f14c83675284ebc | |
| parent | objectstore/packed: Add test for mismatched verify-pick -v size (diff) | |
| signature | No signature | |
objectstore/packed: Fix ReadHeader to return resolved delta object size v0.1.21
| -rw-r--r-- | objectstore/packed/delta_plan.go | 72 |
1 files changed, 70 insertions, 2 deletions
diff --git a/objectstore/packed/delta_plan.go b/objectstore/packed/delta_plan.go index 5a989c62..2fca7c0e 100644 --- a/objectstore/packed/delta_plan.go +++ b/objectstore/packed/delta_plan.go @@ -2,6 +2,7 @@ package packed import ( "fmt" + "io" "codeberg.org/lindenii/furgit/objecttype" ) @@ -40,12 +41,20 @@ func (store *Store) deltaPlanFor(start location) (deltaPlan, error) { } visited[current] = struct{}{} - _, meta, err := store.entryMetaAt(current) + pack, meta, err := store.entryMetaAt(current) if err != nil { return deltaPlan{}, err } if plan.declaredSize < 0 { - plan.declaredSize = meta.size + 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) { @@ -83,3 +92,62 @@ func (store *Store) deltaPlanFor(start location) (deltaPlan, error) { } } } + +// 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 +} |
