Skip to content

Commit 75b1f22

Browse files
authored
zstd: Allow to ignore checksum checking (#572)
Fixes #571
1 parent 595e86d commit 75b1f22

File tree

4 files changed

+99
-17
lines changed

4 files changed

+99
-17
lines changed

zstd/decoder.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ func (d *Decoder) nextBlock(blocking bool) (ok bool) {
439439
println("got", len(d.current.b), "bytes, error:", d.current.err, "data crc:", tmp)
440440
}
441441

442-
if len(next.b) > 0 {
442+
if !d.o.ignoreChecksum && len(next.b) > 0 {
443443
n, err := d.current.crc.Write(next.b)
444444
if err == nil {
445445
if n != len(next.b) {
@@ -451,7 +451,7 @@ func (d *Decoder) nextBlock(blocking bool) (ok bool) {
451451
got := d.current.crc.Sum64()
452452
var tmp [4]byte
453453
binary.LittleEndian.PutUint32(tmp[:], uint32(got))
454-
if !bytes.Equal(tmp[:], next.d.checkCRC) && !ignoreCRC {
454+
if !d.o.ignoreChecksum && !bytes.Equal(tmp[:], next.d.checkCRC) && !ignoreCRC {
455455
if debugDecoder {
456456
println("CRC Check Failed:", tmp[:], " (got) !=", next.d.checkCRC, "(on stream)")
457457
}
@@ -534,7 +534,7 @@ func (d *Decoder) nextBlockSync() (ok bool) {
534534
}
535535

536536
// Update/Check CRC
537-
if d.frame.HasCheckSum {
537+
if !d.o.ignoreChecksum && d.frame.HasCheckSum {
538538
d.frame.crc.Write(d.current.b)
539539
if d.current.d.Last {
540540
d.current.err = d.frame.checkCRC()

zstd/decoder_options.go

+9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type decoderOptions struct {
1919
maxDecodedSize uint64
2020
maxWindowSize uint64
2121
dicts []dict
22+
ignoreChecksum bool
2223
}
2324

2425
func (o *decoderOptions) setDefault() {
@@ -112,3 +113,11 @@ func WithDecoderMaxWindow(size uint64) DOption {
112113
return nil
113114
}
114115
}
116+
117+
// IgnoreChecksum allows to forcibly ignore checksum checking.
118+
func IgnoreChecksum(b bool) DOption {
119+
return func(o *decoderOptions) error {
120+
o.ignoreChecksum = b
121+
return nil
122+
}
123+
}

zstd/decoder_test.go

+51
Original file line numberDiff line numberDiff line change
@@ -1737,6 +1737,57 @@ func TestResetNil(t *testing.T) {
17371737
}
17381738
}
17391739

1740+
func TestIgnoreChecksum(t *testing.T) {
1741+
// zstd file containing text "compress\n" and has a xxhash checksum
1742+
zstdBlob := []byte{0x28, 0xb5, 0x2f, 0xfd, 0x24, 0x09, 0x49, 0x00, 0x00, 'C', 'o', 'm', 'p', 'r', 'e', 's', 's', '\n', 0x79, 0x6e, 0xe0, 0xd2}
1743+
1744+
// replace letter 'c' with 'C', so decoding should fail.
1745+
zstdBlob[9] = 'C'
1746+
1747+
{
1748+
// Check if the file is indeed incorrect
1749+
dec, err := NewReader(nil)
1750+
if err != nil {
1751+
t.Fatal(err)
1752+
}
1753+
defer dec.Close()
1754+
1755+
dec.Reset(bytes.NewBuffer(zstdBlob))
1756+
1757+
_, err = ioutil.ReadAll(dec)
1758+
if err == nil {
1759+
t.Fatal("Expected decoding error")
1760+
}
1761+
1762+
if !errors.Is(err, ErrCRCMismatch) {
1763+
t.Fatalf("Expected checksum error, got '%s'", err)
1764+
}
1765+
}
1766+
1767+
{
1768+
// Ignore CRC error and decompress the content
1769+
dec, err := NewReader(nil, IgnoreChecksum(true))
1770+
if err != nil {
1771+
t.Fatal(err)
1772+
}
1773+
defer dec.Close()
1774+
1775+
dec.Reset(bytes.NewBuffer(zstdBlob))
1776+
1777+
res, err := ioutil.ReadAll(dec)
1778+
if err != nil {
1779+
t.Fatalf("Unexpected error: '%s'", err)
1780+
}
1781+
1782+
want := []byte{'C', 'o', 'm', 'p', 'r', 'e', 's', 's', '\n'}
1783+
if !bytes.Equal(res, want) {
1784+
t.Logf("want: %s", want)
1785+
t.Logf("got: %s", res)
1786+
t.Fatalf("Wrong output")
1787+
}
1788+
}
1789+
}
1790+
17401791
func timeout(after time.Duration) (cancel func()) {
17411792
if isRaceTest {
17421793
return func() {}

zstd/framedec.go

+36-14
Original file line numberDiff line numberDiff line change
@@ -290,13 +290,6 @@ func (d *frameDec) checkCRC() error {
290290
if !d.HasCheckSum {
291291
return nil
292292
}
293-
var tmp [4]byte
294-
got := d.crc.Sum64()
295-
// Flip to match file order.
296-
tmp[0] = byte(got >> 0)
297-
tmp[1] = byte(got >> 8)
298-
tmp[2] = byte(got >> 16)
299-
tmp[3] = byte(got >> 24)
300293

301294
// We can overwrite upper tmp now
302295
want, err := d.rawInput.readSmall(4)
@@ -305,6 +298,18 @@ func (d *frameDec) checkCRC() error {
305298
return err
306299
}
307300

301+
if d.o.ignoreChecksum {
302+
return nil
303+
}
304+
305+
var tmp [4]byte
306+
got := d.crc.Sum64()
307+
// Flip to match file order.
308+
tmp[0] = byte(got >> 0)
309+
tmp[1] = byte(got >> 8)
310+
tmp[2] = byte(got >> 16)
311+
tmp[3] = byte(got >> 24)
312+
308313
if !bytes.Equal(tmp[:], want) && !ignoreCRC {
309314
if debugDecoder {
310315
println("CRC Check Failed:", tmp[:], "!=", want)
@@ -317,6 +322,19 @@ func (d *frameDec) checkCRC() error {
317322
return nil
318323
}
319324

325+
// consumeCRC reads the checksum data if the frame has one.
326+
func (d *frameDec) consumeCRC() error {
327+
if d.HasCheckSum {
328+
_, err := d.rawInput.readSmall(4)
329+
if err != nil {
330+
println("CRC missing?", err)
331+
return err
332+
}
333+
}
334+
335+
return nil
336+
}
337+
320338
// runDecoder will create a sync decoder that will decode a block of data.
321339
func (d *frameDec) runDecoder(dst []byte, dec *blockDec) ([]byte, error) {
322340
saved := d.history.b
@@ -373,13 +391,17 @@ func (d *frameDec) runDecoder(dst []byte, dec *blockDec) ([]byte, error) {
373391
if d.FrameContentSize != fcsUnknown && uint64(len(d.history.b)-crcStart) != d.FrameContentSize {
374392
err = ErrFrameSizeMismatch
375393
} else if d.HasCheckSum {
376-
var n int
377-
n, err = d.crc.Write(dst[crcStart:])
378-
if err == nil {
379-
if n != len(dst)-crcStart {
380-
err = io.ErrShortWrite
381-
} else {
382-
err = d.checkCRC()
394+
if d.o.ignoreChecksum {
395+
err = d.consumeCRC()
396+
} else {
397+
var n int
398+
n, err = d.crc.Write(dst[crcStart:])
399+
if err == nil {
400+
if n != len(dst)-crcStart {
401+
err = io.ErrShortWrite
402+
} else {
403+
err = d.checkCRC()
404+
}
383405
}
384406
}
385407
}

0 commit comments

Comments
 (0)