blob: f502a6b31e0afdc6441108bc969d763d7d323d4c [file] [log] [blame]
The Android Open Source Project66339ad2009-01-15 16:12:07 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20// This file is a nearly line-for-line copy of bspatch.c from the
21// bsdiff-4.3 distribution; the primary differences being how the
22// input and output data are read and the error handling. Running
23// applypatch with the -l option will display the bsdiff license
24// notice.
25
26#include <stdio.h>
27#include <sys/stat.h>
28#include <errno.h>
29#include <unistd.h>
30#include <string.h>
31
32#include <bzlib.h>
33
34#include "mincrypt/sha.h"
35
36void ShowBSDiffLicense() {
37 puts("The bsdiff library used herein is:\n"
38 "\n"
39 "Copyright 2003-2005 Colin Percival\n"
40 "All rights reserved\n"
41 "\n"
42 "Redistribution and use in source and binary forms, with or without\n"
43 "modification, are permitted providing that the following conditions\n"
44 "are met:\n"
45 "1. Redistributions of source code must retain the above copyright\n"
46 " notice, this list of conditions and the following disclaimer.\n"
47 "2. Redistributions in binary form must reproduce the above copyright\n"
48 " notice, this list of conditions and the following disclaimer in the\n"
49 " documentation and/or other materials provided with the distribution.\n"
50 "\n"
51 "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
52 "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
53 "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
54 "ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n"
55 "DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"
56 "DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n"
57 "OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"
58 "HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n"
59 "STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n"
60 "IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
61 "POSSIBILITY OF SUCH DAMAGE.\n"
62 "\n------------------\n\n"
63 "This program uses Julian R Seward's \"libbzip2\" library, available\n"
64 "from http://www.bzip.org/.\n"
65 );
66}
67
68static off_t offtin(u_char *buf)
69{
70 off_t y;
71
72 y=buf[7]&0x7F;
73 y=y*256;y+=buf[6];
74 y=y*256;y+=buf[5];
75 y=y*256;y+=buf[4];
76 y=y*256;y+=buf[3];
77 y=y*256;y+=buf[2];
78 y=y*256;y+=buf[1];
79 y=y*256;y+=buf[0];
80
81 if(buf[7]&0x80) y=-y;
82
83 return y;
84}
85
86int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
87 const char* patch_filename,
88 FILE* output, SHA_CTX* ctx) {
89
90 FILE* f;
91 if ((f = fopen(patch_filename, "rb")) == NULL) {
92 fprintf(stderr, "failed to open patch file\n");
93 return 1;
94 }
95
96 // File format:
97 // 0 8 "BSDIFF40"
98 // 8 8 X
99 // 16 8 Y
100 // 24 8 sizeof(newfile)
101 // 32 X bzip2(control block)
102 // 32+X Y bzip2(diff block)
103 // 32+X+Y ??? bzip2(extra block)
104 // with control block a set of triples (x,y,z) meaning "add x bytes
105 // from oldfile to x bytes from the diff block; copy y bytes from the
106 // extra block; seek forwards in oldfile by z bytes".
107
108 unsigned char header[32];
109 if (fread(header, 1, 32, f) < 32) {
110 fprintf(stderr, "failed to read patch file header\n");
111 return 1;
112 }
113
114 if (memcmp(header, "BSDIFF40", 8) != 0) {
115 fprintf(stderr, "corrupt patch file header (magic number)\n");
116 return 1;
117 }
118
119 ssize_t ctrl_len, data_len;
120 ssize_t new_size;
121 ctrl_len = offtin(header+8);
122 data_len = offtin(header+16);
123 new_size = offtin(header+24);
124
125 if (ctrl_len < 0 || data_len < 0 || new_size < 0) {
126 fprintf(stderr, "corrupt patch file header (data lengths)\n");
127 return 1;
128 }
129
130 fclose(f);
131
132 int bzerr;
133
134#define OPEN_AT(f, bzf, offset) \
135 FILE* f; \
136 BZFILE* bzf; \
137 if ((f = fopen(patch_filename, "rb")) == NULL) { \
138 fprintf(stderr, "failed to open patch file\n"); \
139 return 1; \
140 } \
141 if (fseeko(f, offset, SEEK_SET)) { \
142 fprintf(stderr, "failed to seek in patch file\n"); \
143 return 1; \
144 } \
145 if ((bzf = BZ2_bzReadOpen(&bzerr, f, 0, 0, NULL, 0)) == NULL) { \
146 fprintf(stderr, "failed to bzReadOpen in patch file (%d)\n", bzerr); \
147 return 1; \
148 }
149
150 OPEN_AT(cpf, cpfbz2, 32);
151 OPEN_AT(dpf, dpfbz2, 32+ctrl_len);
152 OPEN_AT(epf, epfbz2, 32+ctrl_len+data_len);
153
154#undef OPEN_AT
155
156 unsigned char* new_data = malloc(new_size);
157 if (new_data == NULL) {
158 fprintf(stderr, "failed to allocate memory for output file\n");
159 return 1;
160 }
161
162 off_t oldpos = 0, newpos = 0;
163 off_t ctrl[3];
164 off_t len_read;
165 int i;
166 unsigned char buf[8];
167 while (newpos < new_size) {
168 // Read control data
169 for (i = 0; i < 3; ++i) {
170 len_read = BZ2_bzRead(&bzerr, cpfbz2, buf, 8);
171 if (len_read < 8 || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) {
172 fprintf(stderr, "corrupt patch (read control)\n");
173 return 1;
174 }
175 ctrl[i] = offtin(buf);
176 }
177
178 // Sanity check
179 if (newpos + ctrl[0] > new_size) {
180 fprintf(stderr, "corrupt patch (new file overrun)\n");
181 return 1;
182 }
183
184 // Read diff string
185 len_read = BZ2_bzRead(&bzerr, dpfbz2, new_data + newpos, ctrl[0]);
186 if (len_read < ctrl[0] || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) {
187 fprintf(stderr, "corrupt patch (read diff)\n");
188 return 1;
189 }
190
191 // Add old data to diff string
192 for (i = 0; i < ctrl[0]; ++i) {
193 if ((oldpos+i >= 0) && (oldpos+i < old_size)) {
194 new_data[newpos+i] += old_data[oldpos+i];
195 }
196 }
197
198 // Adjust pointers
199 newpos += ctrl[0];
200 oldpos += ctrl[0];
201
202 // Sanity check
203 if (newpos + ctrl[1] > new_size) {
204 fprintf(stderr, "corrupt patch (new file overrun)\n");
205 return 1;
206 }
207
208 // Read extra string
209 len_read = BZ2_bzRead(&bzerr, epfbz2, new_data + newpos, ctrl[1]);
210 if (len_read < ctrl[1] || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) {
211 fprintf(stderr, "corrupt patch (read extra)\n");
212 return 1;
213 }
214
215 // Adjust pointers
216 newpos += ctrl[1];
217 oldpos += ctrl[2];
218 }
219
220 BZ2_bzReadClose(&bzerr, cpfbz2);
221 BZ2_bzReadClose(&bzerr, dpfbz2);
222 BZ2_bzReadClose(&bzerr, epfbz2);
223 fclose(cpf);
224 fclose(dpf);
225 fclose(epf);
226
227 if (fwrite(new_data, 1, new_size, output) < new_size) {
228 fprintf(stderr, "short write of output: %d (%s)\n", errno, strerror(errno));
229 return 1;
230 }
231 SHA_update(ctx, new_data, new_size);
232 free(new_data);
233
234 return 0;
235}