diff options
Diffstat (limited to 'format/pack/ingest/thin_fix.go')
| -rw-r--r-- | format/pack/ingest/thin_fix.go | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/format/pack/ingest/thin_fix.go b/format/pack/ingest/thin_fix.go index 249fe136..15fe7674 100644 --- a/format/pack/ingest/thin_fix.go +++ b/format/pack/ingest/thin_fix.go @@ -17,26 +17,32 @@ func maybeFixThin(state *ingestState) error { if len(state.unresolvedRefDeltas) == 0 { return nil } + if !state.fixThin { return &ErrThinPackUnresolved{Count: len(state.unresolvedRefDeltas)} } + if state.base == nil { return &ErrThinPackUnresolved{Count: len(state.unresolvedRefDeltas)} } hashSize := int64(state.algo.Size()) + info, err := state.packFile.Stat() if err != nil { return err } + size := info.Size() if size < hashSize { return fmt.Errorf("format/pack/ingest: pack too short to trim trailer") } + newEnd := size - hashSize if err := state.packFile.Truncate(newEnd); err != nil { return err } + state.stream.consumed = uint64(newEnd) baseIDs := unresolvedThinBaseIDs(state) @@ -45,9 +51,11 @@ func maybeFixThin(state *ingestState) error { if err != nil { continue } + if _, err := appendBaseObject(state, id, ty, content); err != nil { return err } + state.thinFixed = true } @@ -61,6 +69,7 @@ func maybeFixThin(state *ingestState) error { // appendBaseObject appends one base object as a new packed non-delta entry. func appendBaseObject(state *ingestState, id objectid.ObjectID, realType objecttype.Type, content []byte) (int, error) { start := state.stream.consumed + header := encodePackEntryHeader(realType, int64(len(content))) if _, err := state.packFile.WriteAt(header, int64(start)); err != nil { return 0, err @@ -70,10 +79,12 @@ func appendBaseObject(state *ingestState, id objectid.ObjectID, realType objectt crc := crc32.NewIEEE() _, _ = crc.Write(header) counting := &countingWriter{dst: section} + zw := zlib.NewWriter(io.MultiWriter(counting, crc)) if _, err := zw.Write(content); err != nil { return 0, err } + if err := zw.Close(); err != nil { return 0, err } @@ -116,6 +127,7 @@ func (writer *fileSectionWriter) Write(src []byte) (int, error) { if len(src) == 0 { return 0, nil } + n, err := writer.file.WriteAt(src, writer.off+writer.pos) writer.pos += int64(n) @@ -140,6 +152,7 @@ func (writer *countingWriter) Write(src []byte) (int, error) { func rewritePackHeaderAndTrailer(state *ingestState) error { var countRaw [4]byte binary.BigEndian.PutUint32(countRaw[:], uint32(len(state.records))) + if _, err := state.packFile.WriteAt(countRaw[:], 8); err != nil { return err } @@ -148,29 +161,35 @@ func rewritePackHeaderAndTrailer(state *ingestState) error { if err != nil { return err } + endWithoutTrailer := info.Size() hashImpl, err := state.algo.New() if err != nil { return err } + var ( buf [128 << 10]byte pos int64 ) for pos < endWithoutTrailer { want := int64(len(buf)) + remaining := endWithoutTrailer - pos if remaining < want { want = remaining } + n, err := state.packFile.ReadAt(buf[:want], pos) if err != nil && err != io.EOF { return err } + if n == 0 { return io.ErrUnexpectedEOF } + _, _ = hashImpl.Write(buf[:n]) pos += int64(n) } @@ -184,6 +203,7 @@ func rewritePackHeaderAndTrailer(state *ingestState) error { if err != nil { return err } + state.packHash = packHash state.objectCountHeader = uint32(len(state.records)) state.stream.consumed = uint64(endWithoutTrailer + int64(len(sum))) @@ -194,9 +214,11 @@ func rewritePackHeaderAndTrailer(state *ingestState) error { // encodePackEntryHeader encodes one non-delta packed entry header. func encodePackEntryHeader(ty objecttype.Type, size int64) []byte { var out [16]byte + n := 0 s := uint64(size) c := byte((uint8(ty) << 4) | byte(s&0x0f)) + s >>= 4 for s != 0 { out[n] = c | 0x80 @@ -204,6 +226,7 @@ func encodePackEntryHeader(ty objecttype.Type, size int64) []byte { c = byte(s & 0x7f) s >>= 7 } + out[n] = c n++ |
