github.com/Cloud-Foundations/Dominator@v0.3.4/lib/rsync/serveBlocks.go (about)

     1  package rsync
     2  
     3  import (
     4  	"crypto/sha512"
     5  	"io"
     6  
     7  	"github.com/Cloud-Foundations/Dominator/lib/hash"
     8  	proto "github.com/Cloud-Foundations/Dominator/proto/rsync"
     9  )
    10  
    11  func serveBlocks(conn Conn, decoder Decoder, encoder Encoder,
    12  	reader io.ReadSeeker, length uint64) error {
    13  	var request proto.GetBlocksRequest
    14  	if err := decoder.Decode(&request); err != nil {
    15  		return err
    16  	}
    17  	if request.BlockOrder < 9 || request.BlockOrder > 32 {
    18  		return encoder.Encode(proto.Block{Error: "bad block order"})
    19  	}
    20  	blockSize := int64(1) << request.BlockOrder
    21  	var index uint64
    22  	for ; index < request.NumBlocks; index++ {
    23  		hasher := sha512.New()
    24  		if _, err := io.CopyN(hasher, reader, blockSize); err != nil {
    25  			return err
    26  		}
    27  		var localHash, remoteHash hash.Hash
    28  		copy(localHash[:], hasher.Sum(nil))
    29  		if nRead, err := conn.Read(remoteHash[:]); err != nil {
    30  			return encoder.Encode(proto.Block{Error: err.Error()})
    31  		} else if nRead != len(remoteHash) {
    32  			return encoder.Encode(proto.Block{Error: "short read"})
    33  		}
    34  		if remoteHash != localHash {
    35  			if _, err := reader.Seek(-blockSize, io.SeekCurrent); err != nil {
    36  				return encoder.Encode(proto.Block{Error: err.Error()})
    37  			}
    38  			block := proto.Block{Index: index, Size: uint64(blockSize)}
    39  			if err := encoder.Encode(block); err != nil {
    40  				return err
    41  			}
    42  			if _, err := io.CopyN(conn, reader, blockSize); err != nil {
    43  				return encoder.Encode(proto.Block{Error: err.Error()})
    44  			}
    45  		}
    46  	}
    47  	block := proto.Block{
    48  		Index: index,
    49  		Size:  length - index<<request.BlockOrder,
    50  	}
    51  	if err := encoder.Encode(block); err != nil {
    52  		return err
    53  	}
    54  	if block.Size < 1 {
    55  		return nil
    56  	}
    57  	if _, err := io.CopyN(conn, reader, int64(block.Size)); err != nil {
    58  		return err
    59  	}
    60  	return encoder.Encode(proto.Block{})
    61  }