Finalize writes the header for all added blobs and finalizes the pack.
()
| 90 | |
| 91 | // Finalize writes the header for all added blobs and finalizes the pack. |
| 92 | func (p *Packer) Finalize() error { |
| 93 | p.m.Lock() |
| 94 | defer p.m.Unlock() |
| 95 | |
| 96 | if p.err != nil { |
| 97 | return errors.Join(ErrBroken, p.err) |
| 98 | } |
| 99 | |
| 100 | header, err := makeHeader(p.blobs) |
| 101 | if err != nil { |
| 102 | return err |
| 103 | } |
| 104 | |
| 105 | encryptedHeader := make([]byte, 0, crypto.CiphertextLength(len(header))) |
| 106 | nonce := crypto.NewRandomNonce() |
| 107 | encryptedHeader = append(encryptedHeader, nonce...) |
| 108 | encryptedHeader = p.k.Seal(encryptedHeader, nonce, header, nil) |
| 109 | encryptedHeader = binary.LittleEndian.AppendUint32(encryptedHeader, uint32(len(encryptedHeader))) |
| 110 | |
| 111 | if err := verifyHeader(p.k, encryptedHeader, p.blobs); err != nil { |
| 112 | //nolint:revive,staticcheck // ignore linter warnings about error message spelling |
| 113 | return fmt.Errorf("Detected data corruption while writing pack-file header: %w\nCorrupted data is either caused by hardware issues or software bugs. Please open an issue at https://github.com/restic/restic/issues/new/choose for further troubleshooting.", err) |
| 114 | } |
| 115 | |
| 116 | // append the header |
| 117 | n, err := p.wr.Write(encryptedHeader) |
| 118 | if err != nil { |
| 119 | p.err = errors.Wrap(err, "Write") |
| 120 | return p.err |
| 121 | } |
| 122 | |
| 123 | if n != len(encryptedHeader) { |
| 124 | p.err = errors.New("wrong number of bytes written") |
| 125 | return p.err |
| 126 | } |
| 127 | p.bytes += uint(len(encryptedHeader)) |
| 128 | |
| 129 | return nil |
| 130 | } |
| 131 | |
| 132 | func verifyHeader(k *crypto.Key, header []byte, expected restic.Blobs) error { |
| 133 | // do not offer a way to skip the pack header verification, as pack headers are usually small enough |