blob: eb45e9ce924033a0db9c9c4e250dc62afbc935ea [file] [log] [blame]
Doug Zongker512536a2010-02-17 16:11:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// This file is a nearly line-for-line copy of bspatch.c from the
18// bsdiff-4.3 distribution; the primary differences being how the
19// input and output data are read and the error handling. Running
20// applypatch with the -l option will display the bsdiff license
21// notice.
22
23#include <stdio.h>
24#include <sys/stat.h>
Sen Jiang0cce9cd2016-01-22 20:49:07 +080025#include <sys/types.h>
Doug Zongker512536a2010-02-17 16:11:44 -080026#include <errno.h>
27#include <unistd.h>
28#include <string.h>
29
30#include <bzlib.h>
31
Sen Jiangc48cb5e2016-02-04 16:23:21 +080032#include "openssl/sha.h"
Tao Baod80a9982016-03-03 11:43:47 -080033#include "applypatch/applypatch.h"
Doug Zongker512536a2010-02-17 16:11:44 -080034
35void ShowBSDiffLicense() {
Doug Zongkerc4351c72010-02-22 14:46:32 -080036 puts("The bsdiff library used herein is:\n"
37 "\n"
38 "Copyright 2003-2005 Colin Percival\n"
39 "All rights reserved\n"
40 "\n"
41 "Redistribution and use in source and binary forms, with or without\n"
42 "modification, are permitted providing that the following conditions\n"
43 "are met:\n"
44 "1. Redistributions of source code must retain the above copyright\n"
45 " notice, this list of conditions and the following disclaimer.\n"
46 "2. Redistributions in binary form must reproduce the above copyright\n"
47 " notice, this list of conditions and the following disclaimer in the\n"
48 " documentation and/or other materials provided with the distribution.\n"
49 "\n"
50 "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
51 "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
52 "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
53 "ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n"
54 "DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"
55 "DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n"
56 "OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"
57 "HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n"
58 "STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n"
59 "IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
60 "POSSIBILITY OF SUCH DAMAGE.\n"
61 "\n------------------\n\n"
62 "This program uses Julian R Seward's \"libbzip2\" library, available\n"
63 "from http://www.bzip.org/.\n"
64 );
Doug Zongker512536a2010-02-17 16:11:44 -080065}
66
Tianjie Xuaced5d92016-10-12 10:55:04 -070067static off_t offtin(const u_char *buf)
Doug Zongker512536a2010-02-17 16:11:44 -080068{
Doug Zongkerc4351c72010-02-22 14:46:32 -080069 off_t y;
Doug Zongker512536a2010-02-17 16:11:44 -080070
Doug Zongkerc4351c72010-02-22 14:46:32 -080071 y=buf[7]&0x7F;
72 y=y*256;y+=buf[6];
73 y=y*256;y+=buf[5];
74 y=y*256;y+=buf[4];
75 y=y*256;y+=buf[3];
76 y=y*256;y+=buf[2];
77 y=y*256;y+=buf[1];
78 y=y*256;y+=buf[0];
Doug Zongker512536a2010-02-17 16:11:44 -080079
Doug Zongkerc4351c72010-02-22 14:46:32 -080080 if(buf[7]&0x80) y=-y;
Doug Zongker512536a2010-02-17 16:11:44 -080081
Doug Zongkerc4351c72010-02-22 14:46:32 -080082 return y;
Doug Zongker512536a2010-02-17 16:11:44 -080083}
84
Doug Zongkerc4351c72010-02-22 14:46:32 -080085int FillBuffer(unsigned char* buffer, int size, bz_stream* stream) {
86 stream->next_out = (char*)buffer;
87 stream->avail_out = size;
88 while (stream->avail_out > 0) {
89 int bzerr = BZ2_bzDecompress(stream);
90 if (bzerr != BZ_OK && bzerr != BZ_STREAM_END) {
91 printf("bz error %d decompressing\n", bzerr);
92 return -1;
93 }
94 if (stream->avail_out > 0) {
95 printf("need %d more bytes\n", stream->avail_out);
96 }
97 }
98 return 0;
99}
Doug Zongker512536a2010-02-17 16:11:44 -0800100
101int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
Doug Zongkerc4351c72010-02-22 14:46:32 -0800102 const Value* patch, ssize_t patch_offset,
Doug Zongker512536a2010-02-17 16:11:44 -0800103 SinkFn sink, void* token, SHA_CTX* ctx) {
104
Yabin Cuid483c202016-02-03 17:08:52 -0800105 std::vector<unsigned char> new_data;
106 if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset, &new_data) != 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800107 return -1;
108 }
Doug Zongker512536a2010-02-17 16:11:44 -0800109
Yabin Cuid483c202016-02-03 17:08:52 -0800110 if (sink(new_data.data(), new_data.size(), token) < static_cast<ssize_t>(new_data.size())) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800111 printf("short write of output: %d (%s)\n", errno, strerror(errno));
112 return 1;
113 }
Yabin Cuid483c202016-02-03 17:08:52 -0800114 if (ctx) SHA1_Update(ctx, new_data.data(), new_data.size());
Doug Zongkerc4351c72010-02-22 14:46:32 -0800115 return 0;
Doug Zongker512536a2010-02-17 16:11:44 -0800116}
117
118int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
Doug Zongkerc4351c72010-02-22 14:46:32 -0800119 const Value* patch, ssize_t patch_offset,
Yabin Cuid483c202016-02-03 17:08:52 -0800120 std::vector<unsigned char>* new_data) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800121 // Patch data format:
122 // 0 8 "BSDIFF40"
123 // 8 8 X
124 // 16 8 Y
125 // 24 8 sizeof(newfile)
126 // 32 X bzip2(control block)
127 // 32+X Y bzip2(diff block)
128 // 32+X+Y ??? bzip2(extra block)
129 // with control block a set of triples (x,y,z) meaning "add x bytes
130 // from oldfile to x bytes from the diff block; copy y bytes from the
131 // extra block; seek forwards in oldfile by z bytes".
Doug Zongker512536a2010-02-17 16:11:44 -0800132
Tianjie Xuaced5d92016-10-12 10:55:04 -0700133 const unsigned char* header = reinterpret_cast<const unsigned char*>(&patch->data[patch_offset]);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800134 if (memcmp(header, "BSDIFF40", 8) != 0) {
135 printf("corrupt bsdiff patch file header (magic number)\n");
Doug Zongker512536a2010-02-17 16:11:44 -0800136 return 1;
Doug Zongker512536a2010-02-17 16:11:44 -0800137 }
138
Yabin Cuid483c202016-02-03 17:08:52 -0800139 ssize_t ctrl_len, data_len, new_size;
Doug Zongkerc4351c72010-02-22 14:46:32 -0800140 ctrl_len = offtin(header+8);
141 data_len = offtin(header+16);
Yabin Cuid483c202016-02-03 17:08:52 -0800142 new_size = offtin(header+24);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800143
Yabin Cuid483c202016-02-03 17:08:52 -0800144 if (ctrl_len < 0 || data_len < 0 || new_size < 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800145 printf("corrupt patch file header (data lengths)\n");
146 return 1;
Doug Zongker512536a2010-02-17 16:11:44 -0800147 }
148
Doug Zongkerc4351c72010-02-22 14:46:32 -0800149 int bzerr;
150
151 bz_stream cstream;
Tianjie Xuaced5d92016-10-12 10:55:04 -0700152 cstream.next_in = const_cast<char*>(&patch->data[patch_offset + 32]);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800153 cstream.avail_in = ctrl_len;
154 cstream.bzalloc = NULL;
155 cstream.bzfree = NULL;
156 cstream.opaque = NULL;
157 if ((bzerr = BZ2_bzDecompressInit(&cstream, 0, 0)) != BZ_OK) {
158 printf("failed to bzinit control stream (%d)\n", bzerr);
Doug Zongker512536a2010-02-17 16:11:44 -0800159 }
160
Doug Zongkerc4351c72010-02-22 14:46:32 -0800161 bz_stream dstream;
Tianjie Xuaced5d92016-10-12 10:55:04 -0700162 dstream.next_in = const_cast<char*>(&patch->data[patch_offset + 32 + ctrl_len]);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800163 dstream.avail_in = data_len;
164 dstream.bzalloc = NULL;
165 dstream.bzfree = NULL;
166 dstream.opaque = NULL;
167 if ((bzerr = BZ2_bzDecompressInit(&dstream, 0, 0)) != BZ_OK) {
168 printf("failed to bzinit diff stream (%d)\n", bzerr);
Doug Zongker512536a2010-02-17 16:11:44 -0800169 }
170
Doug Zongkerc4351c72010-02-22 14:46:32 -0800171 bz_stream estream;
Tianjie Xuaced5d92016-10-12 10:55:04 -0700172 estream.next_in = const_cast<char*>(&patch->data[patch_offset + 32 + ctrl_len + data_len]);
173 estream.avail_in = patch->data.size() - (patch_offset + 32 + ctrl_len + data_len);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800174 estream.bzalloc = NULL;
175 estream.bzfree = NULL;
176 estream.opaque = NULL;
177 if ((bzerr = BZ2_bzDecompressInit(&estream, 0, 0)) != BZ_OK) {
178 printf("failed to bzinit extra stream (%d)\n", bzerr);
Doug Zongker512536a2010-02-17 16:11:44 -0800179 }
180
Yabin Cuid483c202016-02-03 17:08:52 -0800181 new_data->resize(new_size);
Doug Zongker512536a2010-02-17 16:11:44 -0800182
Doug Zongkerc4351c72010-02-22 14:46:32 -0800183 off_t oldpos = 0, newpos = 0;
184 off_t ctrl[3];
Doug Zongkerc4351c72010-02-22 14:46:32 -0800185 int i;
186 unsigned char buf[24];
Yabin Cuid483c202016-02-03 17:08:52 -0800187 while (newpos < new_size) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800188 // Read control data
189 if (FillBuffer(buf, 24, &cstream) != 0) {
190 printf("error while reading control stream\n");
191 return 1;
192 }
193 ctrl[0] = offtin(buf);
194 ctrl[1] = offtin(buf+8);
195 ctrl[2] = offtin(buf+16);
Doug Zongker512536a2010-02-17 16:11:44 -0800196
Doug Zongker4aa12dd2014-05-13 08:40:49 -0700197 if (ctrl[0] < 0 || ctrl[1] < 0) {
198 printf("corrupt patch (negative byte counts)\n");
199 return 1;
200 }
201
Doug Zongkerc4351c72010-02-22 14:46:32 -0800202 // Sanity check
Yabin Cuid483c202016-02-03 17:08:52 -0800203 if (newpos + ctrl[0] > new_size) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800204 printf("corrupt patch (new file overrun)\n");
205 return 1;
206 }
Doug Zongker512536a2010-02-17 16:11:44 -0800207
Doug Zongkerc4351c72010-02-22 14:46:32 -0800208 // Read diff string
Yabin Cuid483c202016-02-03 17:08:52 -0800209 if (FillBuffer(new_data->data() + newpos, ctrl[0], &dstream) != 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800210 printf("error while reading diff stream\n");
211 return 1;
212 }
213
214 // Add old data to diff string
215 for (i = 0; i < ctrl[0]; ++i) {
216 if ((oldpos+i >= 0) && (oldpos+i < old_size)) {
217 (*new_data)[newpos+i] += old_data[oldpos+i];
218 }
219 }
220
221 // Adjust pointers
222 newpos += ctrl[0];
223 oldpos += ctrl[0];
224
225 // Sanity check
Yabin Cuid483c202016-02-03 17:08:52 -0800226 if (newpos + ctrl[1] > new_size) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800227 printf("corrupt patch (new file overrun)\n");
228 return 1;
229 }
230
231 // Read extra string
Yabin Cuid483c202016-02-03 17:08:52 -0800232 if (FillBuffer(new_data->data() + newpos, ctrl[1], &estream) != 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800233 printf("error while reading extra stream\n");
234 return 1;
235 }
236
237 // Adjust pointers
238 newpos += ctrl[1];
239 oldpos += ctrl[2];
240 }
241
242 BZ2_bzDecompressEnd(&cstream);
243 BZ2_bzDecompressEnd(&dstream);
244 BZ2_bzDecompressEnd(&estream);
245 return 0;
Doug Zongker512536a2010-02-17 16:11:44 -0800246}