You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

patch_delta.go 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. package packfile
  2. import (
  3. "bytes"
  4. "errors"
  5. "io"
  6. "github.com/go-git/go-git/v5/plumbing"
  7. "github.com/go-git/go-git/v5/utils/ioutil"
  8. )
  9. // See https://github.com/git/git/blob/49fa3dc76179e04b0833542fa52d0f287a4955ac/delta.h
  10. // https://github.com/git/git/blob/c2c5f6b1e479f2c38e0e01345350620944e3527f/patch-delta.c,
  11. // and https://github.com/tarruda/node-git-core/blob/master/src/js/delta.js
  12. // for details about the delta format.
  13. const deltaSizeMin = 4
  14. // ApplyDelta writes to target the result of applying the modification deltas in delta to base.
  15. func ApplyDelta(target, base plumbing.EncodedObject, delta []byte) (err error) {
  16. r, err := base.Reader()
  17. if err != nil {
  18. return err
  19. }
  20. defer ioutil.CheckClose(r, &err)
  21. w, err := target.Writer()
  22. if err != nil {
  23. return err
  24. }
  25. defer ioutil.CheckClose(w, &err)
  26. buf := bufPool.Get().(*bytes.Buffer)
  27. defer bufPool.Put(buf)
  28. buf.Reset()
  29. _, err = buf.ReadFrom(r)
  30. if err != nil {
  31. return err
  32. }
  33. src := buf.Bytes()
  34. dst := bufPool.Get().(*bytes.Buffer)
  35. defer bufPool.Put(dst)
  36. dst.Reset()
  37. err = patchDelta(dst, src, delta)
  38. if err != nil {
  39. return err
  40. }
  41. target.SetSize(int64(dst.Len()))
  42. b := byteSlicePool.Get().([]byte)
  43. _, err = io.CopyBuffer(w, dst, b)
  44. byteSlicePool.Put(b)
  45. return err
  46. }
  47. var (
  48. ErrInvalidDelta = errors.New("invalid delta")
  49. ErrDeltaCmd = errors.New("wrong delta command")
  50. )
  51. // PatchDelta returns the result of applying the modification deltas in delta to src.
  52. // An error will be returned if delta is corrupted (ErrDeltaLen) or an action command
  53. // is not copy from source or copy from delta (ErrDeltaCmd).
  54. func PatchDelta(src, delta []byte) ([]byte, error) {
  55. b := &bytes.Buffer{}
  56. if err := patchDelta(b, src, delta); err != nil {
  57. return nil, err
  58. }
  59. return b.Bytes(), nil
  60. }
  61. func patchDelta(dst *bytes.Buffer, src, delta []byte) error {
  62. if len(delta) < deltaSizeMin {
  63. return ErrInvalidDelta
  64. }
  65. srcSz, delta := decodeLEB128(delta)
  66. if srcSz != uint(len(src)) {
  67. return ErrInvalidDelta
  68. }
  69. targetSz, delta := decodeLEB128(delta)
  70. remainingTargetSz := targetSz
  71. var cmd byte
  72. dst.Grow(int(targetSz))
  73. for {
  74. if len(delta) == 0 {
  75. return ErrInvalidDelta
  76. }
  77. cmd = delta[0]
  78. delta = delta[1:]
  79. if isCopyFromSrc(cmd) {
  80. var offset, sz uint
  81. var err error
  82. offset, delta, err = decodeOffset(cmd, delta)
  83. if err != nil {
  84. return err
  85. }
  86. sz, delta, err = decodeSize(cmd, delta)
  87. if err != nil {
  88. return err
  89. }
  90. if invalidSize(sz, targetSz) ||
  91. invalidOffsetSize(offset, sz, srcSz) {
  92. break
  93. }
  94. dst.Write(src[offset:offset+sz])
  95. remainingTargetSz -= sz
  96. } else if isCopyFromDelta(cmd) {
  97. sz := uint(cmd) // cmd is the size itself
  98. if invalidSize(sz, targetSz) {
  99. return ErrInvalidDelta
  100. }
  101. if uint(len(delta)) < sz {
  102. return ErrInvalidDelta
  103. }
  104. dst.Write(delta[0:sz])
  105. remainingTargetSz -= sz
  106. delta = delta[sz:]
  107. } else {
  108. return ErrDeltaCmd
  109. }
  110. if remainingTargetSz <= 0 {
  111. break
  112. }
  113. }
  114. return nil
  115. }
  116. // Decodes a number encoded as an unsigned LEB128 at the start of some
  117. // binary data and returns the decoded number and the rest of the
  118. // stream.
  119. //
  120. // This must be called twice on the delta data buffer, first to get the
  121. // expected source buffer size, and again to get the target buffer size.
  122. func decodeLEB128(input []byte) (uint, []byte) {
  123. var num, sz uint
  124. var b byte
  125. for {
  126. b = input[sz]
  127. num |= (uint(b) & payload) << (sz * 7) // concats 7 bits chunks
  128. sz++
  129. if uint(b)&continuation == 0 || sz == uint(len(input)) {
  130. break
  131. }
  132. }
  133. return num, input[sz:]
  134. }
  135. const (
  136. payload = 0x7f // 0111 1111
  137. continuation = 0x80 // 1000 0000
  138. )
  139. func isCopyFromSrc(cmd byte) bool {
  140. return (cmd & 0x80) != 0
  141. }
  142. func isCopyFromDelta(cmd byte) bool {
  143. return (cmd&0x80) == 0 && cmd != 0
  144. }
  145. func decodeOffset(cmd byte, delta []byte) (uint, []byte, error) {
  146. var offset uint
  147. if (cmd & 0x01) != 0 {
  148. if len(delta) == 0 {
  149. return 0, nil, ErrInvalidDelta
  150. }
  151. offset = uint(delta[0])
  152. delta = delta[1:]
  153. }
  154. if (cmd & 0x02) != 0 {
  155. if len(delta) == 0 {
  156. return 0, nil, ErrInvalidDelta
  157. }
  158. offset |= uint(delta[0]) << 8
  159. delta = delta[1:]
  160. }
  161. if (cmd & 0x04) != 0 {
  162. if len(delta) == 0 {
  163. return 0, nil, ErrInvalidDelta
  164. }
  165. offset |= uint(delta[0]) << 16
  166. delta = delta[1:]
  167. }
  168. if (cmd & 0x08) != 0 {
  169. if len(delta) == 0 {
  170. return 0, nil, ErrInvalidDelta
  171. }
  172. offset |= uint(delta[0]) << 24
  173. delta = delta[1:]
  174. }
  175. return offset, delta, nil
  176. }
  177. func decodeSize(cmd byte, delta []byte) (uint, []byte, error) {
  178. var sz uint
  179. if (cmd & 0x10) != 0 {
  180. if len(delta) == 0 {
  181. return 0, nil, ErrInvalidDelta
  182. }
  183. sz = uint(delta[0])
  184. delta = delta[1:]
  185. }
  186. if (cmd & 0x20) != 0 {
  187. if len(delta) == 0 {
  188. return 0, nil, ErrInvalidDelta
  189. }
  190. sz |= uint(delta[0]) << 8
  191. delta = delta[1:]
  192. }
  193. if (cmd & 0x40) != 0 {
  194. if len(delta) == 0 {
  195. return 0, nil, ErrInvalidDelta
  196. }
  197. sz |= uint(delta[0]) << 16
  198. delta = delta[1:]
  199. }
  200. if sz == 0 {
  201. sz = 0x10000
  202. }
  203. return sz, delta, nil
  204. }
  205. func invalidSize(sz, targetSz uint) bool {
  206. return sz > targetSz
  207. }
  208. func invalidOffsetSize(offset, sz, srcSz uint) bool {
  209. return sumOverflows(offset, sz) ||
  210. offset+sz > srcSz
  211. }
  212. func sumOverflows(a, b uint) bool {
  213. return a+b < a
  214. }