package packed import ( "fmt" "io" "slices" "lindenii.org/go/furgit/errs" "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" "lindenii.org/go/lgo/sync" ) //nolint:gochecknoglobals var deltaHeaderPool = sync.NewPool(func() *[delta.MaxHeaderSizesLen]byte { return new([delta.MaxHeaderSizesLen]byte) }) // deltaNode is a delta entry on a resolution chain. type deltaNode struct { // payload is the entry's compressed delta payload view. payload []byte // size is the entry's declared inflated delta size. size uint64 // baseOffset is the entry's base entry offset. baseOffset int } // unpackEntry reconstructs the object stored at offset in p, // following ref- and ofs-delta chains within the pack. // // A direct base-cache hit returns the shared cache buffer itself, // so the result may alias cache storage and must not be mutated; // delta-applied results are freshly allocated. // // Labels: Life-Parent, Mut-No. func (packed *Packed) unpackEntry(p *pack, offset int) (packfile.EntryType, []byte, error) { var zero packfile.EntryType var ( chain []deltaNode baseType packfile.EntryType base []byte fromCache bool ) // Drill down to the innermost base, // stopping early at any cached base. cur := offset for { if cached, ok := packed.baseCache.Get(baseKey{pack: p, offset: cur}); ok { baseType = cached.entryType base = cached.content fromCache = true break } if len(chain) >= delta.MaxChainDepth { return zero, nil, fmt.Errorf("%w: pack %q: delta chain too deep", ErrMalformedPackedStore, p.name) } header, payload, err := p.entryHeaderAt(cur, packed.objectFormat) if err != nil { return zero, nil, err } if header.Type.IsBase() { base, err = inflate(payload, header.Size) if err != nil { return zero, nil, fmt.Errorf("%w: pack %q: %w", ErrMalformedPackedStore, p.name, err) } baseType = header.Type break } baseOffset, err := packed.deltaBaseOffset(p, cur, header) if err != nil { return zero, nil, err } chain = append(chain, deltaNode{ payload: payload, size: header.Size, baseOffset: baseOffset, }) cur = baseOffset } // A direct cache hit with no deltas to apply // returns the shared cache buffer directly; // callers are contractually Mut-No. if len(chain) == 0 && fromCache { return baseType, base, nil } // Apply deltas back up the chain, caching each consumed base. for i, node := range slices.Backward(chain) { deltaData, err := inflate(node.payload, node.size) if err != nil { return zero, nil, fmt.Errorf("%w: pack %q: %w", ErrMalformedPackedStore, p.name, err) } result, err := delta.Apply(base, deltaData) if err != nil { return zero, nil, fmt.Errorf("%w: pack %q: %w", ErrMalformedPackedStore, p.name, err) } consumedFromCache := fromCache && i == len(chain)-1 if !consumedFromCache { packed.baseCache.Add( baseKey{pack: p, offset: node.baseOffset}, cachedBase{entryType: baseType, content: base}, ) } base = result } return baseType, base, nil } // deltaBaseOffset resolves a delta entry's base entry offset // within the same pack. func (packed *Packed) deltaBaseOffset(p *pack, offset int, header packfile.EntryHeader) (int, error) { switch header.Type { case packfile.EntryTypeOfsDelta: 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 - dist, nil case packfile.EntryTypeRefDelta: refBase := header.RefBase[:packed.objectFormat.Size()] baseOffsetU, found, err := p.idx.Lookup(refBase) if err != nil { return 0, fmt.Errorf("%w: pack %q: %w", ErrMalformedPackedStore, p.name, err) } if !found { baseID, idErr := packed.objectFormat.FromBytes(refBase) if idErr != nil { return 0, fmt.Errorf("%w: pack %q: %w", ErrMalformedPackedStore, p.name, idErr) } return 0, fmt.Errorf( "%w: resolving ref-delta: %w", ErrMalformedPackedStore, &errs.ObjectMissingError{OID: baseID}, ) } 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, packfile.EntryTypeTree, packfile.EntryTypeBlob, packfile.EntryTypeTag, packfile.EntryTypeFuture: } panic("object/store/packed: deltaBaseOffset on non-delta entry") } // resolveType walks one delta chain // to find the chained base object entry type, // without inflating any content. func (packed *Packed) resolveType(p *pack, offset int, entryHeader packfile.EntryHeader) (packfile.EntryType, error) { var zero packfile.EntryType depth := 0 for entryHeader.Type.IsDelta() { if cached, ok := packed.baseCache.Peek(baseKey{pack: p, offset: offset}); ok { return cached.entryType, nil } depth++ if depth > delta.MaxChainDepth { return zero, fmt.Errorf("%w: pack %q: delta chain too deep", ErrMalformedPackedStore, p.name) } baseOffset, err := packed.deltaBaseOffset(p, offset, entryHeader) if err != nil { return zero, err } offset = baseOffset entryHeader, _, err = p.entryHeaderAt(offset, packed.objectFormat) if err != nil { return zero, err } } return entryHeader.Type, nil } // deltaResultSize reads the declared result size // from one compressed delta payload prefix. func deltaResultSize(payload []byte, deltaSize uint64) (int, error) { zr, err := zlib.NewReaderBytes(payload) if err != nil { return 0, fmt.Errorf("reading delta header: %w", err) } defer func() { _ = zr.Close() }() buf := deltaHeaderPool.Get() defer deltaHeaderPool.Put(buf) prefixLen := min(uint64(delta.MaxHeaderSizesLen), deltaSize) prefix := buf[:prefixLen] _, err = io.ReadFull(zr, prefix) if err != nil { return 0, fmt.Errorf("reading delta header: %w", err) } _, resultSize, _, err := delta.ParseHeaderSizes(prefix) if err != nil { return 0, fmt.Errorf("reading delta header: %w", err) } size, err := intconv.Uint64ToInt(resultSize) if err != nil { return 0, fmt.Errorf("reading delta header: result size overflows int: %w", err) } return size, nil }