blob: ebb55f1d194337c079a3c2c7070b938a7e85734b [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"
Doug Zongker512536a2010-02-17 16:11:44 -080033#include "applypatch.h"
34
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
67static off_t offtin(u_char *buf)
68{
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
Doug Zongkerc4351c72010-02-22 14:46:32 -0800133 unsigned char* header = (unsigned char*) patch->data + patch_offset;
134 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;
152 cstream.next_in = patch->data + patch_offset + 32;
153 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;
162 dstream.next_in = patch->data + patch_offset + 32 + ctrl_len;
163 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;
172 estream.next_in = patch->data + patch_offset + 32 + ctrl_len + data_len;
173 estream.avail_in = patch->size - (patch_offset + 32 + ctrl_len + data_len);
174 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];
185 off_t len_read;
186 int i;
187 unsigned char buf[24];
Yabin Cuid483c202016-02-03 17:08:52 -0800188 while (newpos < new_size) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800189 // Read control data
190 if (FillBuffer(buf, 24, &cstream) != 0) {
191 printf("error while reading control stream\n");
192 return 1;
193 }
194 ctrl[0] = offtin(buf);
195 ctrl[1] = offtin(buf+8);
196 ctrl[2] = offtin(buf+16);
Doug Zongker512536a2010-02-17 16:11:44 -0800197
Doug Zongker4aa12dd2014-05-13 08:40:49 -0700198 if (ctrl[0] < 0 || ctrl[1] < 0) {
199 printf("corrupt patch (negative byte counts)\n");
200 return 1;
201 }
202
Doug Zongkerc4351c72010-02-22 14:46:32 -0800203 // Sanity check
Yabin Cuid483c202016-02-03 17:08:52 -0800204 if (newpos + ctrl[0] > new_size) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800205 printf("corrupt patch (new file overrun)\n");
206 return 1;
207 }
Doug Zongker512536a2010-02-17 16:11:44 -0800208
Doug Zongkerc4351c72010-02-22 14:46:32 -0800209 // Read diff string
Yabin Cuid483c202016-02-03 17:08:52 -0800210 if (FillBuffer(new_data->data() + newpos, ctrl[0], &dstream) != 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800211 printf("error while reading diff stream\n");
212 return 1;
213 }
214
215 // Add old data to diff string
216 for (i = 0; i < ctrl[0]; ++i) {
217 if ((oldpos+i >= 0) && (oldpos+i < old_size)) {
218 (*new_data)[newpos+i] += old_data[oldpos+i];
219 }
220 }
221
222 // Adjust pointers
223 newpos += ctrl[0];
224 oldpos += ctrl[0];
225
226 // Sanity check
Yabin Cuid483c202016-02-03 17:08:52 -0800227 if (newpos + ctrl[1] > new_size) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800228 printf("corrupt patch (new file overrun)\n");
229 return 1;
230 }
231
232 // Read extra string
Yabin Cuid483c202016-02-03 17:08:52 -0800233 if (FillBuffer(new_data->data() + newpos, ctrl[1], &estream) != 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800234 printf("error while reading extra stream\n");
235 return 1;
236 }
237
238 // Adjust pointers
239 newpos += ctrl[1];
240 oldpos += ctrl[2];
241 }
242
243 BZ2_bzDecompressEnd(&cstream);
244 BZ2_bzDecompressEnd(&dstream);
245 BZ2_bzDecompressEnd(&estream);
246 return 0;
Doug Zongker512536a2010-02-17 16:11:44 -0800247}