// fillHeader fills in the header for the pending chunk. func (w *Writer) fillHeader(last bool) { if w.i+headerSize > w.j || w.j > blockSize { panic("leveldb/journal: bad writer state") } if last { if w.first { w.buf[w.i+6] = fullChunkType } else { w.buf[w.i+6] = lastChunkType } } else { if w.first { w.buf[w.i+6] = firstChunkType } else { w.buf[w.i+6] = middleChunkType } } binary.LittleEndian.PutUint32(w.buf[w.i+0:w.i+4], util.NewCRC(w.buf[w.i+6:w.j]).Value()) binary.LittleEndian.PutUint16(w.buf[w.i+4:w.i+6], uint16(w.j-w.i-headerSize)) }
func (r *Reader) readRawBlock(bh blockHandle, verifyChecksum bool) ([]byte, error) { data := r.bpool.Get(int(bh.length + blockTrailerLen)) if _, err := r.reader.ReadAt(data, int64(bh.offset)); err != nil && err != io.EOF { return nil, err } if verifyChecksum { n := bh.length + 1 checksum0 := binary.LittleEndian.Uint32(data[n:]) checksum1 := util.NewCRC(data[:n]).Value() if checksum0 != checksum1 { r.bpool.Put(data) return nil, r.newErrCorruptedBH(bh, fmt.Sprintf("checksum mismatch, want=%#x got=%#x", checksum0, checksum1)) } } switch data[bh.length] { case blockTypeNoCompression: data = data[:bh.length] case blockTypeSnappyCompression: decLen, err := snappy.DecodedLen(data[:bh.length]) if err != nil { return nil, r.newErrCorruptedBH(bh, err.Error()) } decData := r.bpool.Get(decLen) decData, err = snappy.Decode(decData, data[:bh.length]) r.bpool.Put(data) if err != nil { r.bpool.Put(decData) return nil, r.newErrCorruptedBH(bh, err.Error()) } data = decData default: r.bpool.Put(data) return nil, r.newErrCorruptedBH(bh, fmt.Sprintf("unknown compression type %#x", data[bh.length])) } return data, nil }
// nextChunk sets r.buf[r.i:r.j] to hold the next chunk's payload, reading the // next block into the buffer if necessary. func (r *Reader) nextChunk(first bool) error { for { if r.j+headerSize <= r.n { checksum := binary.LittleEndian.Uint32(r.buf[r.j+0 : r.j+4]) length := binary.LittleEndian.Uint16(r.buf[r.j+4 : r.j+6]) chunkType := r.buf[r.j+6] if checksum == 0 && length == 0 && chunkType == 0 { // Drop entire block. m := r.n - r.j r.i = r.n r.j = r.n return r.corrupt(m, "zero header", false) } else { m := r.n - r.j r.i = r.j + headerSize r.j = r.j + headerSize + int(length) if r.j > r.n { // Drop entire block. r.i = r.n r.j = r.n return r.corrupt(m, "chunk length overflows block", false) } else if r.checksum && checksum != util.NewCRC(r.buf[r.i-1:r.j]).Value() { // Drop entire block. r.i = r.n r.j = r.n return r.corrupt(m, "checksum mismatch", false) } } if first && chunkType != fullChunkType && chunkType != firstChunkType { m := r.j - r.i r.i = r.j // Report the error, but skip it. return r.corrupt(m+headerSize, "orphan chunk", true) } r.last = chunkType == fullChunkType || chunkType == lastChunkType return nil } // The last block. if r.n < blockSize && r.n > 0 { if !first { return r.corrupt(0, "missing chunk part", false) } r.err = io.EOF return r.err } // Read block. n, err := io.ReadFull(r.r, r.buf[:]) if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF { return err } if n == 0 { if !first { return r.corrupt(0, "missing chunk part", false) } r.err = io.EOF return r.err } r.i, r.j, r.n = 0, 0, n } }