github.com/keygen-sh/go-update@v1.0.0/internal/binarydist/patch.go (about) 1 package binarydist 2 3 import ( 4 "bytes" 5 "compress/bzip2" 6 "encoding/binary" 7 "errors" 8 "io" 9 "io/ioutil" 10 ) 11 12 var ErrCorrupt = errors.New("corrupt patch") 13 14 // Patch applies patch to old, according to the bspatch algorithm, 15 // and writes the result to new. 16 func Patch(old io.Reader, new io.Writer, patch io.Reader) error { 17 var hdr header 18 err := binary.Read(patch, signMagLittleEndian{}, &hdr) 19 if err != nil { 20 return err 21 } 22 if hdr.Magic != magic { 23 return ErrCorrupt 24 } 25 if hdr.CtrlLen < 0 || hdr.DiffLen < 0 || hdr.NewSize < 0 { 26 return ErrCorrupt 27 } 28 29 ctrlbuf := make([]byte, hdr.CtrlLen) 30 _, err = io.ReadFull(patch, ctrlbuf) 31 if err != nil { 32 return err 33 } 34 cpfbz2 := bzip2.NewReader(bytes.NewReader(ctrlbuf)) 35 36 diffbuf := make([]byte, hdr.DiffLen) 37 _, err = io.ReadFull(patch, diffbuf) 38 if err != nil { 39 return err 40 } 41 dpfbz2 := bzip2.NewReader(bytes.NewReader(diffbuf)) 42 43 // The entire rest of the file is the extra block. 44 epfbz2 := bzip2.NewReader(patch) 45 46 obuf, err := ioutil.ReadAll(old) 47 if err != nil { 48 return err 49 } 50 51 nbuf := make([]byte, hdr.NewSize) 52 53 var oldpos, newpos int64 54 for newpos < hdr.NewSize { 55 var ctrl struct{ Add, Copy, Seek int64 } 56 err = binary.Read(cpfbz2, signMagLittleEndian{}, &ctrl) 57 if err != nil { 58 return err 59 } 60 61 // Sanity-check 62 if newpos+ctrl.Add > hdr.NewSize { 63 return ErrCorrupt 64 } 65 66 // Read diff string 67 _, err = io.ReadFull(dpfbz2, nbuf[newpos:newpos+ctrl.Add]) 68 if err != nil { 69 return ErrCorrupt 70 } 71 72 // Add old data to diff string 73 for i := int64(0); i < ctrl.Add; i++ { 74 if oldpos+i >= 0 && oldpos+i < int64(len(obuf)) { 75 nbuf[newpos+i] += obuf[oldpos+i] 76 } 77 } 78 79 // Adjust pointers 80 newpos += ctrl.Add 81 oldpos += ctrl.Add 82 83 // Sanity-check 84 if newpos+ctrl.Copy > hdr.NewSize { 85 return ErrCorrupt 86 } 87 88 // Read extra string 89 _, err = io.ReadFull(epfbz2, nbuf[newpos:newpos+ctrl.Copy]) 90 if err != nil { 91 return ErrCorrupt 92 } 93 94 // Adjust pointers 95 newpos += ctrl.Copy 96 oldpos += ctrl.Seek 97 } 98 99 // Write the new file 100 for len(nbuf) > 0 { 101 n, err := new.Write(nbuf) 102 if err != nil { 103 return err 104 } 105 nbuf = nbuf[n:] 106 } 107 108 return nil 109 }