Beispiel #1
0
func (vs *ValidatingSink) Store(loc BlockLocation, data []byte) error {
	vs.log("validating %+v (%d bytes)", loc, len(data))

	if vs.hashGroups == nil {
		vs.log("making hash groups")
		err := vs.makeHashGroups()
		if err != nil {
			return errors.Wrap(err, 1)
		}

		vs.blockBuf = make([]byte, pwr.BlockSize)
		vs.split = splitfunc.New(int(pwr.BlockSize))
		vs.sctx = wsync.NewContext(int(pwr.BlockSize))
	}

	hashGroup := vs.hashGroups[loc]

	// see also wsync.CreateSignature
	s := bufio.NewScanner(bytes.NewReader(data))
	s.Buffer(vs.blockBuf, 0)
	s.Split(vs.split)

	hashIndex := 0

	for ; s.Scan(); hashIndex++ {
		smallBlock := s.Bytes()
		vs.log("validating sub #%d of %+v (%d bytes)", hashIndex, loc, len(smallBlock))

		weakHash, strongHash := vs.sctx.HashBlock(smallBlock)
		bh := hashGroup[hashIndex]

		if bh.WeakHash != weakHash {
			err := fmt.Errorf("at %+v, expected weak hash %x, got %x", loc, bh.WeakHash, weakHash)
			return errors.Wrap(err, 1)
		}

		if !bytes.Equal(bh.StrongHash, strongHash) {
			err := fmt.Errorf("at %+v, expected strong hash %x, got %x", loc, bh.StrongHash, strongHash)
			return errors.Wrap(err, 1)
		}
	}

	return vs.Sink.Store(loc, data)
}
Beispiel #2
0
// GetWriter returns a writer that checks hashes before writing to the underlying
// pool's writer. It tries really hard to be transparent, but does buffer some data,
// which means some writing is only done when the returned writer is closed.
func (vp *ValidatingPool) GetWriter(fileIndex int64) (io.WriteCloser, error) {
	if vp.hashGroups == nil {
		err := vp.makeHashGroups()
		if err != nil {
			return nil, errors.Wrap(err, 1)
		}
		vp.sctx = wsync.NewContext(int(BlockSize))
	}

	w, err := vp.Pool.GetWriter(fileIndex)
	if err != nil {
		return nil, errors.Wrap(err, 1)
	}

	hashGroup := vp.hashGroups[fileIndex]
	blockIndex := int64(0)
	fileSize := vp.Container.Files[fileIndex].Size

	validate := func(data []byte) error {
		bh := hashGroup[blockIndex]

		weakHash, strongHash := vp.sctx.HashBlock(data)
		start := blockIndex * BlockSize
		size := ComputeBlockSize(fileSize, blockIndex)

		if bh.WeakHash != weakHash {
			if vp.Wounds == nil {
				err := fmt.Errorf("at %d/%d, expected weak hash %x, got %x", fileIndex, blockIndex, bh.WeakHash, weakHash)
				return errors.Wrap(err, 1)
			}

			vp.Wounds <- &Wound{
				Kind:  WoundKind_FILE,
				Index: fileIndex,
				Start: start,
				End:   start + size,
			}
		} else if !bytes.Equal(bh.StrongHash, strongHash) {
			if vp.Wounds == nil {
				err := fmt.Errorf("at %d/%d, expected strong hash %x, got %x", fileIndex, blockIndex, bh.StrongHash, strongHash)
				return errors.Wrap(err, 1)
			}

			vp.Wounds <- &Wound{
				Kind:  WoundKind_FILE,
				Index: fileIndex,
				Start: start,
				End:   start + size,
			}
		}

		if vp.Wounds != nil {
			vp.Wounds <- &Wound{
				Kind:  WoundKind_CLOSED_FILE,
				Index: fileIndex,
				Start: start,
				End:   start + size,
			}
		}

		blockIndex++
		return nil
	}

	dw := &drip.Writer{
		Writer:   w,
		Buffer:   make([]byte, BlockSize),
		Validate: validate,
	}

	return dw, nil
}
Beispiel #3
0
func mksync() *wsync.Context {
	return wsync.NewContext(int(BlockSize))
}