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 }