blocks.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at http://mozilla.org/MPL/2.0/.
  6. package scanner
  7. import (
  8. "bytes"
  9. "crypto/sha256"
  10. "fmt"
  11. "io"
  12. "github.com/syncthing/syncthing/lib/protocol"
  13. )
  14. var SHA256OfNothing = []uint8{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}
  15. type Counter interface {
  16. Update(bytes int64)
  17. }
  18. // Blocks returns the blockwise hash of the reader.
  19. func Blocks(r io.Reader, blocksize int, sizehint int64, counter Counter) ([]protocol.BlockInfo, error) {
  20. hf := sha256.New()
  21. hashLength := hf.Size()
  22. var blocks []protocol.BlockInfo
  23. var hashes, thisHash []byte
  24. if sizehint >= 0 {
  25. // Allocate contiguous blocks for the BlockInfo structures and their
  26. // hashes once and for all, and stick to the specified size.
  27. r = io.LimitReader(r, sizehint)
  28. numBlocks := int(sizehint / int64(blocksize))
  29. blocks = make([]protocol.BlockInfo, 0, numBlocks)
  30. hashes = make([]byte, 0, hashLength*numBlocks)
  31. }
  32. // A 32k buffer is used for copying into the hash function.
  33. buf := make([]byte, 32<<10)
  34. var offset int64
  35. for {
  36. lr := io.LimitReader(r, int64(blocksize))
  37. n, err := copyBuffer(hf, lr, buf)
  38. if err != nil {
  39. return nil, err
  40. }
  41. if n == 0 {
  42. break
  43. }
  44. if counter != nil {
  45. counter.Update(int64(n))
  46. }
  47. // Carve out a hash-sized chunk of "hashes" to store the hash for this
  48. // block.
  49. hashes = hf.Sum(hashes)
  50. thisHash, hashes = hashes[:hashLength], hashes[hashLength:]
  51. b := protocol.BlockInfo{
  52. Size: int32(n),
  53. Offset: offset,
  54. Hash: thisHash,
  55. }
  56. blocks = append(blocks, b)
  57. offset += int64(n)
  58. hf.Reset()
  59. }
  60. if len(blocks) == 0 {
  61. // Empty file
  62. blocks = append(blocks, protocol.BlockInfo{
  63. Offset: 0,
  64. Size: 0,
  65. Hash: SHA256OfNothing,
  66. })
  67. }
  68. return blocks, nil
  69. }
  70. // PopulateOffsets sets the Offset field on each block
  71. func PopulateOffsets(blocks []protocol.BlockInfo) {
  72. var offset int64
  73. for i := range blocks {
  74. blocks[i].Offset = offset
  75. offset += int64(blocks[i].Size)
  76. }
  77. }
  78. // BlockDiff returns lists of common and missing (to transform src into tgt)
  79. // blocks. Both block lists must have been created with the same block size.
  80. func BlockDiff(src, tgt []protocol.BlockInfo) (have, need []protocol.BlockInfo) {
  81. if len(tgt) == 0 && len(src) != 0 {
  82. return nil, nil
  83. }
  84. if len(tgt) != 0 && len(src) == 0 {
  85. // Copy the entire file
  86. return nil, tgt
  87. }
  88. for i := range tgt {
  89. if i >= len(src) || !bytes.Equal(tgt[i].Hash, src[i].Hash) {
  90. // Copy differing block
  91. need = append(need, tgt[i])
  92. } else {
  93. have = append(have, tgt[i])
  94. }
  95. }
  96. return have, need
  97. }
  98. // Verify returns nil or an error describing the mismatch between the block
  99. // list and actual reader contents
  100. func Verify(r io.Reader, blocksize int, blocks []protocol.BlockInfo) error {
  101. hf := sha256.New()
  102. for i, block := range blocks {
  103. lr := &io.LimitedReader{R: r, N: int64(blocksize)}
  104. _, err := io.Copy(hf, lr)
  105. if err != nil {
  106. return err
  107. }
  108. hash := hf.Sum(nil)
  109. hf.Reset()
  110. if !bytes.Equal(hash, block.Hash) {
  111. return fmt.Errorf("hash mismatch %x != %x for block %d", hash, block.Hash, i)
  112. }
  113. }
  114. // We should have reached the end now
  115. bs := make([]byte, 1)
  116. n, err := r.Read(bs)
  117. if n != 0 || err != io.EOF {
  118. return fmt.Errorf("file continues past end of blocks")
  119. }
  120. return nil
  121. }
  122. func VerifyBuffer(buf []byte, block protocol.BlockInfo) ([]byte, error) {
  123. if len(buf) != int(block.Size) {
  124. return nil, fmt.Errorf("length mismatch %d != %d", len(buf), block.Size)
  125. }
  126. hf := sha256.New()
  127. _, err := hf.Write(buf)
  128. if err != nil {
  129. return nil, err
  130. }
  131. hash := hf.Sum(nil)
  132. if !bytes.Equal(hash, block.Hash) {
  133. return hash, fmt.Errorf("hash mismatch %x != %x", hash, block.Hash)
  134. }
  135. return hash, nil
  136. }
  137. // BlocksEqual returns whether two slices of blocks are exactly the same hash
  138. // and index pair wise.
  139. func BlocksEqual(src, tgt []protocol.BlockInfo) bool {
  140. if len(tgt) != len(src) {
  141. return false
  142. }
  143. for i, sblk := range src {
  144. if !bytes.Equal(sblk.Hash, tgt[i].Hash) {
  145. return false
  146. }
  147. }
  148. return true
  149. }
  150. // This is a copy & paste of io.copyBuffer from the Go 1.5 standard library,
  151. // as we want this but also want to build with Go 1.3+.
  152. // copyBuffer is the actual implementation of Copy and CopyBuffer.
  153. // if buf is nil, one is allocated.
  154. func copyBuffer(dst io.Writer, src io.Reader, buf []byte) (written int64, err error) {
  155. // If the reader has a WriteTo method, use it to do the copy.
  156. // Avoids an allocation and a copy.
  157. if wt, ok := src.(io.WriterTo); ok {
  158. return wt.WriteTo(dst)
  159. }
  160. // Similarly, if the writer has a ReadFrom method, use it to do the copy.
  161. if rt, ok := dst.(io.ReaderFrom); ok {
  162. return rt.ReadFrom(src)
  163. }
  164. if buf == nil {
  165. buf = make([]byte, 32*1024)
  166. }
  167. for {
  168. nr, er := src.Read(buf)
  169. if nr > 0 {
  170. nw, ew := dst.Write(buf[0:nr])
  171. if nw > 0 {
  172. written += int64(nw)
  173. }
  174. if ew != nil {
  175. err = ew
  176. break
  177. }
  178. if nr != nw {
  179. err = io.ErrShortWrite
  180. break
  181. }
  182. }
  183. if er == io.EOF {
  184. break
  185. }
  186. if er != nil {
  187. err = er
  188. break
  189. }
  190. }
  191. return written, err
  192. }