aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDoug Zongker2010-02-22 16:46:32 -0600
committerDoug Zongker2010-02-22 17:30:33 -0600
commitc4351c791052ad529a4e83c600b1aa6e6420ea86 (patch)
treecdc534868eb58ea980bcca2fbc8e04b68fd9936c
parent583fc12c3dbe09e3a9b759b9466c505b006e6a39 (diff)
downloadplatform-bootable-recovery-c4351c791052ad529a4e83c600b1aa6e6420ea86.tar.gz
platform-bootable-recovery-c4351c791052ad529a4e83c600b1aa6e6420ea86.tar.xz
platform-bootable-recovery-c4351c791052ad529a4e83c600b1aa6e6420ea86.zip
refactor applypatch and friends
Change the applypatch function to take meaningful arguments instead of argc and argv. Move all the parsing of arguments into main.c (for the standalone binary) and into install.c (for the updater function). applypatch() takes patches as Value objects, so we can pass in blobs extracted from the package without ever writing them to temp files. The patching code is changed to read the patch from memory instead of a file. A bunch of compiler warnings (mostly about signed vs unsigned types) are fixed. Support for the IMGDIFF1 format is dropped. (We've been generating IMGDIFF2 packages for some time now.) Change-Id: I217563c500012750f27110db821928a06211323f
-rw-r--r--applypatch/Android.mk2
-rw-r--r--applypatch/applypatch.c1359
-rw-r--r--applypatch/applypatch.h22
-rwxr-xr-xapplypatch/applypatch.sh11
-rw-r--r--applypatch/bspatch.c372
-rw-r--r--applypatch/imgpatch.c485
-rw-r--r--applypatch/main.c147
-rw-r--r--applypatch/utils.c37
-rw-r--r--applypatch/utils.h6
-rw-r--r--edify/main.c3
-rw-r--r--edify/yydefs.h2
-rw-r--r--updater/install.c172
12 files changed, 1296 insertions, 1322 deletions
diff --git a/applypatch/Android.mk b/applypatch/Android.mk
index d20d6c8f..bb024f66 100644
--- a/applypatch/Android.mk
+++ b/applypatch/Android.mk
@@ -29,6 +29,7 @@ include $(CLEAR_VARS)
29 29
30LOCAL_SRC_FILES := main.c 30LOCAL_SRC_FILES := main.c
31LOCAL_MODULE := applypatch 31LOCAL_MODULE := applypatch
32LOCAL_C_INCLUDES += bootable/recovery
32LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz 33LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz
33LOCAL_SHARED_LIBRARIES += libz libcutils libstdc++ libc 34LOCAL_SHARED_LIBRARIES += libz libcutils libstdc++ libc
34 35
@@ -40,6 +41,7 @@ LOCAL_SRC_FILES := main.c
40LOCAL_MODULE := applypatch_static 41LOCAL_MODULE := applypatch_static
41LOCAL_FORCE_STATIC_EXECUTABLE := true 42LOCAL_FORCE_STATIC_EXECUTABLE := true
42LOCAL_MODULE_TAGS := eng 43LOCAL_MODULE_TAGS := eng
44LOCAL_C_INCLUDES += bootable/recovery
43LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz 45LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz
44LOCAL_STATIC_LIBRARIES += libz libcutils libstdc++ libc 46LOCAL_STATIC_LIBRARIES += libz libcutils libstdc++ libc
45 47
diff --git a/applypatch/applypatch.c b/applypatch/applypatch.c
index daf37290..99d36616 100644
--- a/applypatch/applypatch.c
+++ b/applypatch/applypatch.c
@@ -28,6 +28,7 @@
28#include "mincrypt/sha.h" 28#include "mincrypt/sha.h"
29#include "applypatch.h" 29#include "applypatch.h"
30#include "mtdutils/mtdutils.h" 30#include "mtdutils/mtdutils.h"
31#include "edify/expr.h"
31 32
32int SaveFileContents(const char* filename, FileContents file); 33int SaveFileContents(const char* filename, FileContents file);
33int LoadMTDContents(const char* filename, FileContents* file); 34int LoadMTDContents(const char* filename, FileContents* file);
@@ -39,57 +40,57 @@ static int mtd_partitions_scanned = 0;
39// Read a file into memory; store it and its associated metadata in 40// Read a file into memory; store it and its associated metadata in
40// *file. Return 0 on success. 41// *file. Return 0 on success.
41int LoadFileContents(const char* filename, FileContents* file) { 42int LoadFileContents(const char* filename, FileContents* file) {
42 file->data = NULL; 43 file->data = NULL;
43 44
44 // A special 'filename' beginning with "MTD:" means to load the 45 // A special 'filename' beginning with "MTD:" means to load the
45 // contents of an MTD partition. 46 // contents of an MTD partition.
46 if (strncmp(filename, "MTD:", 4) == 0) { 47 if (strncmp(filename, "MTD:", 4) == 0) {
47 return LoadMTDContents(filename, file); 48 return LoadMTDContents(filename, file);
48 } 49 }
49 50
50 if (stat(filename, &file->st) != 0) { 51 if (stat(filename, &file->st) != 0) {
51 printf("failed to stat \"%s\": %s\n", filename, strerror(errno)); 52 printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
52 return -1; 53 return -1;
53 } 54 }
54 55
55 file->size = file->st.st_size; 56 file->size = file->st.st_size;
56 file->data = malloc(file->size); 57 file->data = malloc(file->size);
57 58
58 FILE* f = fopen(filename, "rb"); 59 FILE* f = fopen(filename, "rb");
59 if (f == NULL) { 60 if (f == NULL) {
60 printf("failed to open \"%s\": %s\n", filename, strerror(errno)); 61 printf("failed to open \"%s\": %s\n", filename, strerror(errno));
61 free(file->data); 62 free(file->data);
62 file->data = NULL; 63 file->data = NULL;
63 return -1; 64 return -1;
64 } 65 }
65 66
66 size_t bytes_read = fread(file->data, 1, file->size, f); 67 ssize_t bytes_read = fread(file->data, 1, file->size, f);
67 if (bytes_read != file->size) { 68 if (bytes_read != file->size) {
68 printf("short read of \"%s\" (%d bytes of %d)\n", 69 printf("short read of \"%s\" (%ld bytes of %ld)\n",
69 filename, bytes_read, file->size); 70 filename, (long)bytes_read, (long)file->size);
70 free(file->data); 71 free(file->data);
71 file->data = NULL; 72 file->data = NULL;
72 return -1; 73 return -1;
73 } 74 }
74 fclose(f); 75 fclose(f);
75 76
76 SHA(file->data, file->size, file->sha1); 77 SHA(file->data, file->size, file->sha1);
77 return 0; 78 return 0;
78} 79}
79 80
80static size_t* size_array; 81static size_t* size_array;
81// comparison function for qsort()ing an int array of indexes into 82// comparison function for qsort()ing an int array of indexes into
82// size_array[]. 83// size_array[].
83static int compare_size_indices(const void* a, const void* b) { 84static int compare_size_indices(const void* a, const void* b) {
84 int aa = *(int*)a; 85 int aa = *(int*)a;
85 int bb = *(int*)b; 86 int bb = *(int*)b;
86 if (size_array[aa] < size_array[bb]) { 87 if (size_array[aa] < size_array[bb]) {
87 return -1; 88 return -1;
88 } else if (size_array[aa] > size_array[bb]) { 89 } else if (size_array[aa] > size_array[bb]) {
89 return 1; 90 return 1;
90 } else { 91 } else {
91 return 0; 92 return 0;
92 } 93 }
93} 94}
94 95
95void FreeFileContents(FileContents* file) { 96void FreeFileContents(FileContents* file) {
@@ -113,239 +114,240 @@ void FreeFileContents(FileContents* file) {
113// hash of the data, and we'll do the load expecting to find one of 114// hash of the data, and we'll do the load expecting to find one of
114// those hashes. 115// those hashes.
115int LoadMTDContents(const char* filename, FileContents* file) { 116int LoadMTDContents(const char* filename, FileContents* file) {
116 char* copy = strdup(filename); 117 char* copy = strdup(filename);
117 const char* magic = strtok(copy, ":"); 118 const char* magic = strtok(copy, ":");
118 if (strcmp(magic, "MTD") != 0) { 119 if (strcmp(magic, "MTD") != 0) {
119 printf("LoadMTDContents called with bad filename (%s)\n", 120 printf("LoadMTDContents called with bad filename (%s)\n",
120 filename); 121 filename);
121 return -1;
122 }
123 const char* partition = strtok(NULL, ":");
124
125 int i;
126 int colons = 0;
127 for (i = 0; filename[i] != '\0'; ++i) {
128 if (filename[i] == ':') {
129 ++colons;
130 }
131 }
132 if (colons < 3 || colons%2 == 0) {
133 printf("LoadMTDContents called with bad filename (%s)\n",
134 filename);
135 }
136
137 int pairs = (colons-1)/2; // # of (size,sha1) pairs in filename
138 int* index = malloc(pairs * sizeof(int));
139 size_t* size = malloc(pairs * sizeof(size_t));
140 char** sha1sum = malloc(pairs * sizeof(char*));
141
142 for (i = 0; i < pairs; ++i) {
143 const char* size_str = strtok(NULL, ":");
144 size[i] = strtol(size_str, NULL, 10);
145 if (size[i] == 0) {
146 printf("LoadMTDContents called with bad size (%s)\n", filename);
147 return -1;
148 }
149 sha1sum[i] = strtok(NULL, ":");
150 index[i] = i;
151 }
152
153 // sort the index[] array so it indexes the pairs in order of
154 // increasing size.
155 size_array = size;
156 qsort(index, pairs, sizeof(int), compare_size_indices);
157
158 if (!mtd_partitions_scanned) {
159 mtd_scan_partitions();
160 mtd_partitions_scanned = 1;
161 }
162
163 const MtdPartition* mtd = mtd_find_partition_by_name(partition);
164 if (mtd == NULL) {
165 printf("mtd partition \"%s\" not found (loading %s)\n",
166 partition, filename);
167 return -1;
168 }
169
170 MtdReadContext* ctx = mtd_read_partition(mtd);
171 if (ctx == NULL) {
172 printf("failed to initialize read of mtd partition \"%s\"\n",
173 partition);
174 return -1;
175 }
176
177 SHA_CTX sha_ctx;
178 SHA_init(&sha_ctx);
179 uint8_t parsed_sha[SHA_DIGEST_SIZE];
180
181 // allocate enough memory to hold the largest size.
182 file->data = malloc(size[index[pairs-1]]);
183 char* p = (char*)file->data;
184 file->size = 0; // # bytes read so far
185
186 for (i = 0; i < pairs; ++i) {
187 // Read enough additional bytes to get us up to the next size
188 // (again, we're trying the possibilities in order of increasing
189 // size).
190 size_t next = size[index[i]] - file->size;
191 size_t read = 0;
192 if (next > 0) {
193 read = mtd_read_data(ctx, p, next);
194 if (next != read) {
195 printf("short read (%d bytes of %d) for partition \"%s\"\n",
196 read, next, partition);
197 free(file->data);
198 file->data = NULL;
199 return -1; 122 return -1;
200 }
201 SHA_update(&sha_ctx, p, read);
202 file->size += read;
203 } 123 }
124 const char* partition = strtok(NULL, ":");
204 125
205 // Duplicate the SHA context and finalize the duplicate so we can 126 int i;
206 // check it against this pair's expected hash. 127 int colons = 0;
207 SHA_CTX temp_ctx; 128 for (i = 0; filename[i] != '\0'; ++i) {
208 memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX)); 129 if (filename[i] == ':') {
209 const uint8_t* sha_so_far = SHA_final(&temp_ctx); 130 ++colons;
131 }
132 }
133 if (colons < 3 || colons%2 == 0) {
134 printf("LoadMTDContents called with bad filename (%s)\n",
135 filename);
136 }
210 137
211 if (ParseSha1(sha1sum[index[i]], parsed_sha) != 0) { 138 int pairs = (colons-1)/2; // # of (size,sha1) pairs in filename
212 printf("failed to parse sha1 %s in %s\n", 139 int* index = malloc(pairs * sizeof(int));
213 sha1sum[index[i]], filename); 140 size_t* size = malloc(pairs * sizeof(size_t));
214 free(file->data); 141 char** sha1sum = malloc(pairs * sizeof(char*));
215 file->data = NULL; 142
216 return -1; 143 for (i = 0; i < pairs; ++i) {
144 const char* size_str = strtok(NULL, ":");
145 size[i] = strtol(size_str, NULL, 10);
146 if (size[i] == 0) {
147 printf("LoadMTDContents called with bad size (%s)\n", filename);
148 return -1;
149 }
150 sha1sum[i] = strtok(NULL, ":");
151 index[i] = i;
217 } 152 }
218 153
219 if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_SIZE) == 0) { 154 // sort the index[] array so it indexes the pairs in order of
220 // we have a match. stop reading the partition; we'll return 155 // increasing size.
221 // the data we've read so far. 156 size_array = size;
222 printf("mtd read matched size %d sha %s\n", 157 qsort(index, pairs, sizeof(int), compare_size_indices);
223 size[index[i]], sha1sum[index[i]]); 158
224 break; 159 if (!mtd_partitions_scanned) {
160 mtd_scan_partitions();
161 mtd_partitions_scanned = 1;
225 } 162 }
226 163
227 p += read; 164 const MtdPartition* mtd = mtd_find_partition_by_name(partition);
228 } 165 if (mtd == NULL) {
166 printf("mtd partition \"%s\" not found (loading %s)\n",
167 partition, filename);
168 return -1;
169 }
229 170
230 mtd_read_close(ctx); 171 MtdReadContext* ctx = mtd_read_partition(mtd);
172 if (ctx == NULL) {
173 printf("failed to initialize read of mtd partition \"%s\"\n",
174 partition);
175 return -1;
176 }
231 177
232 if (i == pairs) { 178 SHA_CTX sha_ctx;
233 // Ran off the end of the list of (size,sha1) pairs without 179 SHA_init(&sha_ctx);
234 // finding a match. 180 uint8_t parsed_sha[SHA_DIGEST_SIZE];
235 printf("contents of MTD partition \"%s\" didn't match %s\n", 181
236 partition, filename); 182 // allocate enough memory to hold the largest size.
237 free(file->data); 183 file->data = malloc(size[index[pairs-1]]);
238 file->data = NULL; 184 char* p = (char*)file->data;
239 return -1; 185 file->size = 0; // # bytes read so far
240 } 186
187 for (i = 0; i < pairs; ++i) {
188 // Read enough additional bytes to get us up to the next size
189 // (again, we're trying the possibilities in order of increasing
190 // size).
191 size_t next = size[index[i]] - file->size;
192 size_t read = 0;
193 if (next > 0) {
194 read = mtd_read_data(ctx, p, next);
195 if (next != read) {
196 printf("short read (%d bytes of %d) for partition \"%s\"\n",
197 read, next, partition);
198 free(file->data);
199 file->data = NULL;
200 return -1;
201 }
202 SHA_update(&sha_ctx, p, read);
203 file->size += read;
204 }
205
206 // Duplicate the SHA context and finalize the duplicate so we can
207 // check it against this pair's expected hash.
208 SHA_CTX temp_ctx;
209 memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX));
210 const uint8_t* sha_so_far = SHA_final(&temp_ctx);
211
212 if (ParseSha1(sha1sum[index[i]], parsed_sha) != 0) {
213 printf("failed to parse sha1 %s in %s\n",
214 sha1sum[index[i]], filename);
215 free(file->data);
216 file->data = NULL;
217 return -1;
218 }
219
220 if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_SIZE) == 0) {
221 // we have a match. stop reading the partition; we'll return
222 // the data we've read so far.
223 printf("mtd read matched size %d sha %s\n",
224 size[index[i]], sha1sum[index[i]]);
225 break;
226 }
241 227
242 const uint8_t* sha_final = SHA_final(&sha_ctx); 228 p += read;
243 for (i = 0; i < SHA_DIGEST_SIZE; ++i) { 229 }
244 file->sha1[i] = sha_final[i]; 230
245 } 231 mtd_read_close(ctx);
232
233 if (i == pairs) {
234 // Ran off the end of the list of (size,sha1) pairs without
235 // finding a match.
236 printf("contents of MTD partition \"%s\" didn't match %s\n",
237 partition, filename);
238 free(file->data);
239 file->data = NULL;
240 return -1;
241 }
242
243 const uint8_t* sha_final = SHA_final(&sha_ctx);
244 for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
245 file->sha1[i] = sha_final[i];
246 }
246 247
247 // Fake some stat() info. 248 // Fake some stat() info.
248 file->st.st_mode = 0644; 249 file->st.st_mode = 0644;
249 file->st.st_uid = 0; 250 file->st.st_uid = 0;
250 file->st.st_gid = 0; 251 file->st.st_gid = 0;
251 252
252 free(copy); 253 free(copy);
253 free(index); 254 free(index);
254 free(size); 255 free(size);
255 free(sha1sum); 256 free(sha1sum);
256 257
257 return 0; 258 return 0;
258} 259}
259 260
260 261
261// Save the contents of the given FileContents object under the given 262// Save the contents of the given FileContents object under the given
262// filename. Return 0 on success. 263// filename. Return 0 on success.
263int SaveFileContents(const char* filename, FileContents file) { 264int SaveFileContents(const char* filename, FileContents file) {
264 int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC); 265 int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
265 if (fd < 0) { 266 if (fd < 0) {
266 printf("failed to open \"%s\" for write: %s\n", 267 printf("failed to open \"%s\" for write: %s\n",
267 filename, strerror(errno)); 268 filename, strerror(errno));
268 return -1; 269 return -1;
269 } 270 }
270 271
271 size_t bytes_written = FileSink(file.data, file.size, &fd); 272 ssize_t bytes_written = FileSink(file.data, file.size, &fd);
272 if (bytes_written != file.size) { 273 if (bytes_written != file.size) {
273 printf("short write of \"%s\" (%d bytes of %d) (%s)\n", 274 printf("short write of \"%s\" (%ld bytes of %ld) (%s)\n",
274 filename, bytes_written, file.size, strerror(errno)); 275 filename, (long)bytes_written, (long)file.size,
276 strerror(errno));
277 close(fd);
278 return -1;
279 }
280 fsync(fd);
275 close(fd); 281 close(fd);
276 return -1;
277 }
278 fsync(fd);
279 close(fd);
280 282
281 if (chmod(filename, file.st.st_mode) != 0) { 283 if (chmod(filename, file.st.st_mode) != 0) {
282 printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno)); 284 printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno));
283 return -1; 285 return -1;
284 } 286 }
285 if (chown(filename, file.st.st_uid, file.st.st_gid) != 0) { 287 if (chown(filename, file.st.st_uid, file.st.st_gid) != 0) {
286 printf("chown of \"%s\" failed: %s\n", filename, strerror(errno)); 288 printf("chown of \"%s\" failed: %s\n", filename, strerror(errno));
287 return -1; 289 return -1;
288 } 290 }
289 291
290 return 0; 292 return 0;
291} 293}
292 294
293// Write a memory buffer to target_mtd partition, a string of the form 295// Write a memory buffer to target_mtd partition, a string of the form
294// "MTD:<partition>[:...]". Return 0 on success. 296// "MTD:<partition>[:...]". Return 0 on success.
295int WriteToMTDPartition(unsigned char* data, size_t len, 297int WriteToMTDPartition(unsigned char* data, size_t len,
296 const char* target_mtd) { 298 const char* target_mtd) {
297 char* partition = strchr(target_mtd, ':'); 299 char* partition = strchr(target_mtd, ':');
298 if (partition == NULL) { 300 if (partition == NULL) {
299 printf("bad MTD target name \"%s\"\n", target_mtd); 301 printf("bad MTD target name \"%s\"\n", target_mtd);
300 return -1; 302 return -1;
301 } 303 }
302 ++partition; 304 ++partition;
303 // Trim off anything after a colon, eg "MTD:boot:blah:blah:blah...". 305 // Trim off anything after a colon, eg "MTD:boot:blah:blah:blah...".
304 // We want just the partition name "boot". 306 // We want just the partition name "boot".
305 partition = strdup(partition); 307 partition = strdup(partition);
306 char* end = strchr(partition, ':'); 308 char* end = strchr(partition, ':');
307 if (end != NULL) 309 if (end != NULL)
308 *end = '\0'; 310 *end = '\0';
309 311
310 if (!mtd_partitions_scanned) { 312 if (!mtd_partitions_scanned) {
311 mtd_scan_partitions(); 313 mtd_scan_partitions();
312 mtd_partitions_scanned = 1; 314 mtd_partitions_scanned = 1;
313 } 315 }
314
315 const MtdPartition* mtd = mtd_find_partition_by_name(partition);
316 if (mtd == NULL) {
317 printf("mtd partition \"%s\" not found for writing\n", partition);
318 return -1;
319 }
320 316
321 MtdWriteContext* ctx = mtd_write_partition(mtd); 317 const MtdPartition* mtd = mtd_find_partition_by_name(partition);
322 if (ctx == NULL) { 318 if (mtd == NULL) {
323 printf("failed to init mtd partition \"%s\" for writing\n", 319 printf("mtd partition \"%s\" not found for writing\n", partition);
324 partition); 320 return -1;
325 return -1; 321 }
326 }
327 322
328 size_t written = mtd_write_data(ctx, (char*)data, len); 323 MtdWriteContext* ctx = mtd_write_partition(mtd);
329 if (written != len) { 324 if (ctx == NULL) {
330 printf("only wrote %d of %d bytes to MTD %s\n", 325 printf("failed to init mtd partition \"%s\" for writing\n",
331 written, len, partition); 326 partition);
332 mtd_write_close(ctx); 327 return -1;
333 return -1; 328 }
334 }
335 329
336 if (mtd_erase_blocks(ctx, -1) < 0) { 330 size_t written = mtd_write_data(ctx, (char*)data, len);
337 printf("error finishing mtd write of %s\n", partition); 331 if (written != len) {
338 mtd_write_close(ctx); 332 printf("only wrote %d of %d bytes to MTD %s\n",
339 return -1; 333 written, len, partition);
340 } 334 mtd_write_close(ctx);
335 return -1;
336 }
341 337
342 if (mtd_write_close(ctx)) { 338 if (mtd_erase_blocks(ctx, -1) < 0) {
343 printf("error closing mtd write of %s\n", partition); 339 printf("error finishing mtd write of %s\n", partition);
344 return -1; 340 mtd_write_close(ctx);
345 } 341 return -1;
342 }
346 343
347 free(partition); 344 if (mtd_write_close(ctx)) {
348 return 0; 345 printf("error closing mtd write of %s\n", partition);
346 return -1;
347 }
348
349 free(partition);
350 return 0;
349} 351}
350 352
351 353
@@ -354,547 +356,460 @@ int WriteToMTDPartition(unsigned char* data, size_t len,
354// the form "<digest>:<anything>". Return 0 on success, -1 on any 356// the form "<digest>:<anything>". Return 0 on success, -1 on any
355// error. 357// error.
356int ParseSha1(const char* str, uint8_t* digest) { 358int ParseSha1(const char* str, uint8_t* digest) {
357 int i; 359 int i;
358 const char* ps = str; 360 const char* ps = str;
359 uint8_t* pd = digest; 361 uint8_t* pd = digest;
360 for (i = 0; i < SHA_DIGEST_SIZE * 2; ++i, ++ps) { 362 for (i = 0; i < SHA_DIGEST_SIZE * 2; ++i, ++ps) {
361 int digit; 363 int digit;
362 if (*ps >= '0' && *ps <= '9') { 364 if (*ps >= '0' && *ps <= '9') {
363 digit = *ps - '0'; 365 digit = *ps - '0';
364 } else if (*ps >= 'a' && *ps <= 'f') { 366 } else if (*ps >= 'a' && *ps <= 'f') {
365 digit = *ps - 'a' + 10; 367 digit = *ps - 'a' + 10;
366 } else if (*ps >= 'A' && *ps <= 'F') { 368 } else if (*ps >= 'A' && *ps <= 'F') {
367 digit = *ps - 'A' + 10; 369 digit = *ps - 'A' + 10;
368 } else { 370 } else {
369 return -1; 371 return -1;
370 } 372 }
371 if (i % 2 == 0) { 373 if (i % 2 == 0) {
372 *pd = digit << 4; 374 *pd = digit << 4;
373 } else { 375 } else {
374 *pd |= digit; 376 *pd |= digit;
375 ++pd; 377 ++pd;
376 } 378 }
377 }
378 if (*ps != '\0' && *ps != ':') return -1;
379 return 0;
380}
381
382// Parse arguments (which should be of the form "<sha1>" or
383// "<sha1>:<filename>" into the array *patches, returning the number
384// of Patch objects in *num_patches. Return 0 on success.
385int ParseShaArgs(int argc, char** argv, Patch** patches, int* num_patches) {
386 *num_patches = argc;
387 *patches = malloc(*num_patches * sizeof(Patch));
388
389 int i;
390 for (i = 0; i < *num_patches; ++i) {
391 if (ParseSha1(argv[i], (*patches)[i].sha1) != 0) {
392 printf("failed to parse sha1 \"%s\"\n", argv[i]);
393 return -1;
394 }
395 if (argv[i][SHA_DIGEST_SIZE*2] == '\0') {
396 (*patches)[i].patch_filename = NULL;
397 } else if (argv[i][SHA_DIGEST_SIZE*2] == ':') {
398 (*patches)[i].patch_filename = argv[i] + (SHA_DIGEST_SIZE*2+1);
399 } else {
400 printf("failed to parse filename \"%s\"\n", argv[i]);
401 return -1;
402 } 379 }
403 } 380 if (*ps != '\0') return -1;
404 381 return 0;
405 return 0;
406} 382}
407 383
408// Search an array of Patch objects for one matching the given sha1. 384// Search an array of sha1 strings for one matching the given sha1.
409// Return the Patch object on success, or NULL if no match is found. 385// Return the index of the match on success, or -1 if no match is
410const Patch* FindMatchingPatch(uint8_t* sha1, Patch* patches, int num_patches) { 386// found.
411 int i; 387int FindMatchingPatch(uint8_t* sha1, char** const patch_sha1_str,
412 for (i = 0; i < num_patches; ++i) { 388 int num_patches) {
413 if (memcmp(patches[i].sha1, sha1, SHA_DIGEST_SIZE) == 0) { 389 int i;
414 return patches+i; 390 uint8_t patch_sha1[SHA_DIGEST_SIZE];
391 for (i = 0; i < num_patches; ++i) {
392 if (ParseSha1(patch_sha1_str[i], patch_sha1) == 0 &&
393 memcmp(patch_sha1, sha1, SHA_DIGEST_SIZE) == 0) {
394 return i;
395 }
415 } 396 }
416 } 397 return -1;
417 return NULL;
418} 398}
419 399
420// Returns 0 if the contents of the file (argv[2]) or the cached file 400// Returns 0 if the contents of the file (argv[2]) or the cached file
421// match any of the sha1's on the command line (argv[3:]). Returns 401// match any of the sha1's on the command line (argv[3:]). Returns
422// nonzero otherwise. 402// nonzero otherwise.
423int CheckMode(int argc, char** argv) { 403int applypatch_check(const char* filename,
424 if (argc < 3) { 404 int num_patches, char** const patch_sha1_str) {
425 printf("no filename given\n"); 405 FileContents file;
426 return 2; 406 file.data = NULL;
427 } 407
428 408 // It's okay to specify no sha1s; the check will pass if the
429 int num_patches; 409 // LoadFileContents is successful. (Useful for reading MTD
430 Patch* patches; 410 // partitions, where the filename encodes the sha1s; no need to
431 if (ParseShaArgs(argc-3, argv+3, &patches, &num_patches) != 0) { return 1; } 411 // check them twice.)
432 412 if (LoadFileContents(filename, &file) != 0 ||
433 FileContents file; 413 (num_patches > 0 &&
434 file.data = NULL; 414 FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0)) {
435 415 printf("file \"%s\" doesn't have any of expected "
436 // It's okay to specify no sha1s; the check will pass if the 416 "sha1 sums; checking cache\n", filename);
437 // LoadFileContents is successful. (Useful for reading MTD 417
438 // partitions, where the filename encodes the sha1s; no need to 418 free(file.data);
439 // check them twice.) 419
440 if (LoadFileContents(argv[2], &file) != 0 || 420 // If the source file is missing or corrupted, it might be because
441 (num_patches > 0 && 421 // we were killed in the middle of patching it. A copy of it
442 FindMatchingPatch(file.sha1, patches, num_patches) == NULL)) { 422 // should have been made in CACHE_TEMP_SOURCE. If that file
443 printf("file \"%s\" doesn't have any of expected " 423 // exists and matches the sha1 we're looking for, the check still
444 "sha1 sums; checking cache\n", argv[2]); 424 // passes.
445 425
446 free(file.data); 426 if (LoadFileContents(CACHE_TEMP_SOURCE, &file) != 0) {
447 427 printf("failed to load cache file\n");
448 // If the source file is missing or corrupted, it might be because 428 return 1;
449 // we were killed in the middle of patching it. A copy of it 429 }
450 // should have been made in CACHE_TEMP_SOURCE. If that file
451 // exists and matches the sha1 we're looking for, the check still
452 // passes.
453
454 if (LoadFileContents(CACHE_TEMP_SOURCE, &file) != 0) {
455 printf("failed to load cache file\n");
456 return 1;
457 }
458 430
459 if (FindMatchingPatch(file.sha1, patches, num_patches) == NULL) { 431 if (FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0) {
460 printf("cache bits don't match any sha1 for \"%s\"\n", 432 printf("cache bits don't match any sha1 for \"%s\"\n", filename);
461 argv[2]); 433 free(file.data);
462 return 1; 434 return 1;
435 }
463 } 436 }
464 }
465 437
466 free(file.data); 438 free(file.data);
467 return 0; 439 return 0;
468} 440}
469 441
470int ShowLicenses() { 442int ShowLicenses() {
471 ShowBSDiffLicense(); 443 ShowBSDiffLicense();
472 return 0; 444 return 0;
473} 445}
474 446
475ssize_t FileSink(unsigned char* data, ssize_t len, void* token) { 447ssize_t FileSink(unsigned char* data, ssize_t len, void* token) {
476 int fd = *(int *)token; 448 int fd = *(int *)token;
477 ssize_t done = 0; 449 ssize_t done = 0;
478 ssize_t wrote; 450 ssize_t wrote;
479 while (done < (ssize_t) len) { 451 while (done < (ssize_t) len) {
480 wrote = write(fd, data+done, len-done); 452 wrote = write(fd, data+done, len-done);
481 if (wrote <= 0) { 453 if (wrote <= 0) {
482 printf("error writing %d bytes: %s\n", (int)(len-done), strerror(errno)); 454 printf("error writing %d bytes: %s\n", (int)(len-done), strerror(errno));
483 return done; 455 return done;
484 } 456 }
485 done += wrote; 457 done += wrote;
486 } 458 }
487 printf("wrote %d bytes to output\n", (int)done); 459 return done;
488 return done;
489} 460}
490 461
491typedef struct { 462typedef struct {
492 unsigned char* buffer; 463 unsigned char* buffer;
493 ssize_t size; 464 ssize_t size;
494 ssize_t pos; 465 ssize_t pos;
495} MemorySinkInfo; 466} MemorySinkInfo;
496 467
497ssize_t MemorySink(unsigned char* data, ssize_t len, void* token) { 468ssize_t MemorySink(unsigned char* data, ssize_t len, void* token) {
498 MemorySinkInfo* msi = (MemorySinkInfo*)token; 469 MemorySinkInfo* msi = (MemorySinkInfo*)token;
499 if (msi->size - msi->pos < len) { 470 if (msi->size - msi->pos < len) {
500 return -1; 471 return -1;
501 } 472 }
502 memcpy(msi->buffer + msi->pos, data, len); 473 memcpy(msi->buffer + msi->pos, data, len);
503 msi->pos += len; 474 msi->pos += len;
504 return len; 475 return len;
505} 476}
506 477
507// Return the amount of free space (in bytes) on the filesystem 478// Return the amount of free space (in bytes) on the filesystem
508// containing filename. filename must exist. Return -1 on error. 479// containing filename. filename must exist. Return -1 on error.
509size_t FreeSpaceForFile(const char* filename) { 480size_t FreeSpaceForFile(const char* filename) {
510 struct statfs sf; 481 struct statfs sf;
511 if (statfs(filename, &sf) != 0) { 482 if (statfs(filename, &sf) != 0) {
512 printf("failed to statfs %s: %s\n", filename, strerror(errno)); 483 printf("failed to statfs %s: %s\n", filename, strerror(errno));
513 return -1; 484 return -1;
514 } 485 }
515 return sf.f_bsize * sf.f_bfree; 486 return sf.f_bsize * sf.f_bfree;
487}
488
489int CacheSizeCheck(size_t bytes) {
490 if (MakeFreeSpaceOnCache(bytes) < 0) {
491 printf("unable to make %ld bytes available on /cache\n", (long)bytes);
492 return 1;
493 } else {
494 return 0;
495 }
516} 496}
517 497
518// This program applies binary patches to files in a way that is safe 498
499// This function applies binary patches to files in a way that is safe
519// (the original file is not touched until we have the desired 500// (the original file is not touched until we have the desired
520// replacement for it) and idempotent (it's okay to run this program 501// replacement for it) and idempotent (it's okay to run this program
521// multiple times). 502// multiple times).
522// 503//
523// - if the sha1 hash of <tgt-file> is <tgt-sha1>, does nothing and exits 504// - if the sha1 hash of <target_filename> is <target_sha1_string>,
524// successfully. 505// does nothing and exits successfully.
525// 506//
526// - otherwise, if the sha1 hash of <src-file> is <src-sha1>, applies the 507// - otherwise, if the sha1 hash of <source_filename> is one of the
527// bsdiff <patch> to <src-file> to produce a new file (the type of patch 508// entries in <patch_sha1_str>, the corresponding patch from
528// is automatically detected from the file header). If that new 509// <patch_data> (which must be a VAL_BLOB) is applied to produce a
529// file has sha1 hash <tgt-sha1>, moves it to replace <tgt-file>, and 510// new file (the type of patch is automatically detected from the
530// exits successfully. Note that if <src-file> and <tgt-file> are 511// blob daat). If that new file has sha1 hash <target_sha1_str>,
531// not the same, <src-file> is NOT deleted on success. <tgt-file> 512// moves it to replace <target_filename>, and exits successfully.
532// may be the string "-" to mean "the same as src-file". 513// Note that if <source_filename> and <target_filename> are not the
514// same, <source_filename> is NOT deleted on success.
515// <target_filename> may be the string "-" to mean "the same as
516// source_filename".
533// 517//
534// - otherwise, or if any error is encountered, exits with non-zero 518// - otherwise, or if any error is encountered, exits with non-zero
535// status. 519// status.
536// 520//
537// <src-file> (or <file> in check mode) may refer to an MTD partition 521// <source_filename> may refer to an MTD partition to read the source
538// to read the source data. See the comments for the 522// data. See the comments for the LoadMTDContents() function above
539// LoadMTDContents() function above for the format of such a filename. 523// for the format of such a filename.
540// 524
541// 525int applypatch(const char* source_filename,
542// As you might guess from the arguments, this function used to be 526 const char* target_filename,
543// main(); it was split out this way so applypatch could be built as a 527 const char* target_sha1_str,
544// static library and linked into other executables as well. In the 528 size_t target_size,
545// future only the library form will exist; we will not need to build 529 int num_patches,
546// this as a standalone executable. 530 char** const patch_sha1_str,
547// 531 Value** patch_data) {
548// The arguments to this function are just the command-line of the 532 printf("\napplying patch to %s\n", source_filename);
549// standalone executable: 533
550// 534 if (target_filename[0] == '-' &&
551// <src-file> <tgt-file> <tgt-sha1> <tgt-size> [<src-sha1>:<patch> ...] 535 target_filename[1] == '\0') {
552// to apply a patch. Returns 0 on success, 1 on failure. 536 target_filename = source_filename;
553// 537 }
554// "-c" <file> [<sha1> ...]
555// to check a file's contents against zero or more sha1s. Returns
556// 0 if it matches any of them, 1 if it doesn't.
557//
558// "-s" <bytes>
559// returns 0 if enough free space is available on /cache; 1 if it
560// does not.
561//
562// "-l"
563// shows open-source license information and returns 0.
564//
565// This function returns 2 if the arguments are not understood (in the
566// standalone executable, this causes the usage message to be
567// printed).
568//
569// TODO: make the interface more sensible for use as a library.
570
571int applypatch(int argc, char** argv) {
572 if (argc < 2) {
573 return 2;
574 }
575 538
576 if (strncmp(argv[1], "-l", 3) == 0) { 539 uint8_t target_sha1[SHA_DIGEST_SIZE];
577 return ShowLicenses(); 540 if (ParseSha1(target_sha1_str, target_sha1) != 0) {
578 } 541 printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str);
542 return 1;
543 }
579 544
580 if (strncmp(argv[1], "-c", 3) == 0) { 545 FileContents copy_file;
581 return CheckMode(argc, argv); 546 FileContents source_file;
582 } 547 const Value* source_patch_value = NULL;
548 const Value* copy_patch_value = NULL;
549 int made_copy = 0;
550
551 // We try to load the target file into the source_file object.
552 if (LoadFileContents(target_filename, &source_file) == 0) {
553 if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) {
554 // The early-exit case: the patch was already applied, this file
555 // has the desired hash, nothing for us to do.
556 printf("\"%s\" is already target; no patch needed\n",
557 target_filename);
558 return 0;
559 }
560 }
583 561
584 if (strncmp(argv[1], "-s", 3) == 0) { 562 if (source_file.data == NULL ||
585 if (argc != 3) { 563 (target_filename != source_filename &&
586 return 2; 564 strcmp(target_filename, source_filename) != 0)) {
565 // Need to load the source file: either we failed to load the
566 // target file, or we did but it's different from the source file.
567 free(source_file.data);
568 LoadFileContents(source_filename, &source_file);
587 } 569 }
588 size_t bytes = strtol(argv[2], NULL, 10); 570
589 if (MakeFreeSpaceOnCache(bytes) < 0) { 571 if (source_file.data != NULL) {
590 printf("unable to make %ld bytes available on /cache\n", (long)bytes); 572 int to_use = FindMatchingPatch(source_file.sha1,
591 return 1; 573 patch_sha1_str, num_patches);
592 } else { 574 if (to_use >= 0) {
593 return 0; 575 source_patch_value = patch_data[to_use];
594 }
595 }
596
597 uint8_t target_sha1[SHA_DIGEST_SIZE];
598
599 const char* source_filename = argv[1];
600 const char* target_filename = argv[2];
601 if (target_filename[0] == '-' &&
602 target_filename[1] == '\0') {
603 target_filename = source_filename;
604 }
605
606 printf("\napplying patch to %s\n", source_filename);
607
608 if (ParseSha1(argv[3], target_sha1) != 0) {
609 printf("failed to parse tgt-sha1 \"%s\"\n", argv[3]);
610 return 1;
611 }
612
613 unsigned long target_size = strtoul(argv[4], NULL, 0);
614
615 int num_patches;
616 Patch* patches;
617 if (ParseShaArgs(argc-5, argv+5, &patches, &num_patches) < 0) { return 1; }
618
619 FileContents copy_file;
620 FileContents source_file;
621 const char* source_patch_filename = NULL;
622 const char* copy_patch_filename = NULL;
623 int made_copy = 0;
624
625 // We try to load the target file into the source_file object.
626 if (LoadFileContents(target_filename, &source_file) == 0) {
627 if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) {
628 // The early-exit case: the patch was already applied, this file
629 // has the desired hash, nothing for us to do.
630 printf("\"%s\" is already target; no patch needed\n",
631 target_filename);
632 return 0;
633 }
634 }
635
636 if (source_file.data == NULL ||
637 (target_filename != source_filename &&
638 strcmp(target_filename, source_filename) != 0)) {
639 // Need to load the source file: either we failed to load the
640 // target file, or we did but it's different from the source file.
641 free(source_file.data);
642 LoadFileContents(source_filename, &source_file);
643 }
644
645 if (source_file.data != NULL) {
646 const Patch* to_use =
647 FindMatchingPatch(source_file.sha1, patches, num_patches);
648 if (to_use != NULL) {
649 source_patch_filename = to_use->patch_filename;
650 }
651 }
652
653 if (source_patch_filename == NULL) {
654 free(source_file.data);
655 printf("source file is bad; trying copy\n");
656
657 if (LoadFileContents(CACHE_TEMP_SOURCE, &copy_file) < 0) {
658 // fail.
659 printf("failed to read copy file\n");
660 return 1;
661 }
662
663 const Patch* to_use =
664 FindMatchingPatch(copy_file.sha1, patches, num_patches);
665 if (to_use != NULL) {
666 copy_patch_filename = to_use->patch_filename;
667 }
668
669 if (copy_patch_filename == NULL) {
670 // fail.
671 printf("copy file doesn't match source SHA-1s either\n");
672 return 1;
673 }
674 }
675
676 int retry = 1;
677 SHA_CTX ctx;
678 int output;
679 MemorySinkInfo msi;
680 FileContents* source_to_use;
681 char* outname;
682
683 // assume that target_filename (eg "/system/app/Foo.apk") is located
684 // on the same filesystem as its top-level directory ("/system").
685 // We need something that exists for calling statfs().
686 char target_fs[strlen(target_filename)+1];
687 char* slash = strchr(target_filename+1, '/');
688 if (slash != NULL) {
689 int count = slash - target_filename;
690 strncpy(target_fs, target_filename, count);
691 target_fs[count] = '\0';
692 } else {
693 strcpy(target_fs, target_filename);
694 }
695
696 do {
697 // Is there enough room in the target filesystem to hold the patched
698 // file?
699
700 if (strncmp(target_filename, "MTD:", 4) == 0) {
701 // If the target is an MTD partition, we're actually going to
702 // write the output to /tmp and then copy it to the partition.
703 // statfs() always returns 0 blocks free for /tmp, so instead
704 // we'll just assume that /tmp has enough space to hold the file.
705
706 // We still write the original source to cache, in case the MTD
707 // write is interrupted.
708 if (MakeFreeSpaceOnCache(source_file.size) < 0) {
709 printf("not enough free space on /cache\n");
710 return 1;
711 }
712 if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
713 printf("failed to back up source file\n");
714 return 1;
715 }
716 made_copy = 1;
717 retry = 0;
718 } else {
719 int enough_space = 0;
720 if (retry > 0) {
721 size_t free_space = FreeSpaceForFile(target_fs);
722 int enough_space =
723 (free_space > (target_size * 3 / 2)); // 50% margin of error
724 printf("target %ld bytes; free space %ld bytes; retry %d; enough %d\n",
725 (long)target_size, (long)free_space, retry, enough_space);
726 }
727
728 if (!enough_space) {
729 retry = 0;
730 }
731
732 if (!enough_space && source_patch_filename != NULL) {
733 // Using the original source, but not enough free space. First
734 // copy the source file to cache, then delete it from the original
735 // location.
736
737 if (strncmp(source_filename, "MTD:", 4) == 0) {
738 // It's impossible to free space on the target filesystem by
739 // deleting the source if the source is an MTD partition. If
740 // we're ever in a state where we need to do this, fail.
741 printf("not enough free space for target but source is MTD\n");
742 return 1;
743 } 576 }
577 }
744 578
745 if (MakeFreeSpaceOnCache(source_file.size) < 0) { 579 if (source_patch_value == NULL) {
746 printf("not enough free space on /cache\n"); 580 free(source_file.data);
747 return 1; 581 printf("source file is bad; trying copy\n");
582
583 if (LoadFileContents(CACHE_TEMP_SOURCE, &copy_file) < 0) {
584 // fail.
585 printf("failed to read copy file\n");
586 return 1;
748 } 587 }
749 588
750 if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) { 589 int to_use = FindMatchingPatch(copy_file.sha1,
751 printf("failed to back up source file\n"); 590 patch_sha1_str, num_patches);
752 return 1; 591 if (to_use > 0) {
592 copy_patch_value = patch_data[to_use];
753 } 593 }
754 made_copy = 1;
755 unlink(source_filename);
756 594
757 size_t free_space = FreeSpaceForFile(target_fs); 595 if (copy_patch_value == NULL) {
758 printf("(now %ld bytes free for target)\n", (long)free_space); 596 // fail.
759 } 597 printf("copy file doesn't match source SHA-1s either\n");
598 return 1;
599 }
760 } 600 }
761 601
762 const char* patch_filename; 602 int retry = 1;
763 if (source_patch_filename != NULL) { 603 SHA_CTX ctx;
764 source_to_use = &source_file; 604 int output;
765 patch_filename = source_patch_filename; 605 MemorySinkInfo msi;
766 } else { 606 FileContents* source_to_use;
767 source_to_use = &copy_file; 607 char* outname;
768 patch_filename = copy_patch_filename; 608
769 } 609 // assume that target_filename (eg "/system/app/Foo.apk") is located
770 610 // on the same filesystem as its top-level directory ("/system").
771 SinkFn sink = NULL; 611 // We need something that exists for calling statfs().
772 void* token = NULL; 612 char target_fs[strlen(target_filename)+1];
773 output = -1; 613 char* slash = strchr(target_filename+1, '/');
774 outname = NULL; 614 if (slash != NULL) {
775 if (strncmp(target_filename, "MTD:", 4) == 0) { 615 int count = slash - target_filename;
776 // We store the decoded output in memory. 616 strncpy(target_fs, target_filename, count);
777 msi.buffer = malloc(target_size); 617 target_fs[count] = '\0';
778 if (msi.buffer == NULL) {
779 printf("failed to alloc %ld bytes for output\n",
780 (long)target_size);
781 return 1;
782 }
783 msi.pos = 0;
784 msi.size = target_size;
785 sink = MemorySink;
786 token = &msi;
787 } else {
788 // We write the decoded output to "<tgt-file>.patch".
789 outname = (char*)malloc(strlen(target_filename) + 10);
790 strcpy(outname, target_filename);
791 strcat(outname, ".patch");
792
793 output = open(outname, O_WRONLY | O_CREAT | O_TRUNC);
794 if (output < 0) {
795 printf("failed to open output file %s: %s\n",
796 outname, strerror(errno));
797 return 1;
798 }
799 sink = FileSink;
800 token = &output;
801 }
802
803#define MAX_HEADER_LENGTH 8
804 unsigned char header[MAX_HEADER_LENGTH];
805 FILE* patchf = fopen(patch_filename, "rb");
806 if (patchf == NULL) {
807 printf("failed to open patch file %s: %s\n",
808 patch_filename, strerror(errno));
809 return 1;
810 }
811 int header_bytes_read = fread(header, 1, MAX_HEADER_LENGTH, patchf);
812 fclose(patchf);
813
814 SHA_init(&ctx);
815
816 int result;
817
818 if (header_bytes_read >= 4 &&
819 header[0] == 0xd6 && header[1] == 0xc3 &&
820 header[2] == 0xc4 && header[3] == 0) {
821 // xdelta3 patches begin "VCD" (with the high bits set) followed
822 // by a zero byte (the version number).
823 printf("error: xdelta3 patches no longer supported\n");
824 return 1;
825 } else if (header_bytes_read >= 8 &&
826 memcmp(header, "BSDIFF40", 8) == 0) {
827 result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size,
828 patch_filename, 0, sink, token, &ctx);
829 } else if (header_bytes_read >= 8 &&
830 memcmp(header, "IMGDIFF", 7) == 0 &&
831 (header[7] == '1' || header[7] == '2')) {
832 result = ApplyImagePatch(source_to_use->data, source_to_use->size,
833 patch_filename, sink, token, &ctx);
834 } else { 618 } else {
835 printf("Unknown patch file format\n"); 619 strcpy(target_fs, target_filename);
836 return 1;
837 } 620 }
838 621
839 if (output >= 0) { 622 do {
840 fsync(output); 623 // Is there enough room in the target filesystem to hold the patched
841 close(output); 624 // file?
625
626 if (strncmp(target_filename, "MTD:", 4) == 0) {
627 // If the target is an MTD partition, we're actually going to
628 // write the output to /tmp and then copy it to the partition.
629 // statfs() always returns 0 blocks free for /tmp, so instead
630 // we'll just assume that /tmp has enough space to hold the file.
631
632 // We still write the original source to cache, in case the MTD
633 // write is interrupted.
634 if (MakeFreeSpaceOnCache(source_file.size) < 0) {
635 printf("not enough free space on /cache\n");
636 return 1;
637 }
638 if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
639 printf("failed to back up source file\n");
640 return 1;
641 }
642 made_copy = 1;
643 retry = 0;
644 } else {
645 int enough_space = 0;
646 if (retry > 0) {
647 size_t free_space = FreeSpaceForFile(target_fs);
648 int enough_space =
649 (free_space > (target_size * 3 / 2)); // 50% margin of error
650 printf("target %ld bytes; free space %ld bytes; retry %d; enough %d\n",
651 (long)target_size, (long)free_space, retry, enough_space);
652 }
653
654 if (!enough_space) {
655 retry = 0;
656 }
657
658 if (!enough_space && source_patch_value != NULL) {
659 // Using the original source, but not enough free space. First
660 // copy the source file to cache, then delete it from the original
661 // location.
662
663 if (strncmp(source_filename, "MTD:", 4) == 0) {
664 // It's impossible to free space on the target filesystem by
665 // deleting the source if the source is an MTD partition. If
666 // we're ever in a state where we need to do this, fail.
667 printf("not enough free space for target but source is MTD\n");
668 return 1;
669 }
670
671 if (MakeFreeSpaceOnCache(source_file.size) < 0) {
672 printf("not enough free space on /cache\n");
673 return 1;
674 }
675
676 if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
677 printf("failed to back up source file\n");
678 return 1;
679 }
680 made_copy = 1;
681 unlink(source_filename);
682
683 size_t free_space = FreeSpaceForFile(target_fs);
684 printf("(now %ld bytes free for target)\n", (long)free_space);
685 }
686 }
687
688 const Value* patch;
689 if (source_patch_value != NULL) {
690 source_to_use = &source_file;
691 patch = source_patch_value;
692 } else {
693 source_to_use = &copy_file;
694 patch = copy_patch_value;
695 }
696
697 if (patch->type != VAL_BLOB) {
698 printf("patch is not a blob\n");
699 return 1;
700 }
701
702 SinkFn sink = NULL;
703 void* token = NULL;
704 output = -1;
705 outname = NULL;
706 if (strncmp(target_filename, "MTD:", 4) == 0) {
707 // We store the decoded output in memory.
708 msi.buffer = malloc(target_size);
709 if (msi.buffer == NULL) {
710 printf("failed to alloc %ld bytes for output\n",
711 (long)target_size);
712 return 1;
713 }
714 msi.pos = 0;
715 msi.size = target_size;
716 sink = MemorySink;
717 token = &msi;
718 } else {
719 // We write the decoded output to "<tgt-file>.patch".
720 outname = (char*)malloc(strlen(target_filename) + 10);
721 strcpy(outname, target_filename);
722 strcat(outname, ".patch");
723
724 output = open(outname, O_WRONLY | O_CREAT | O_TRUNC);
725 if (output < 0) {
726 printf("failed to open output file %s: %s\n",
727 outname, strerror(errno));
728 return 1;
729 }
730 sink = FileSink;
731 token = &output;
732 }
733
734 char* header = patch->data;
735 ssize_t header_bytes_read = patch->size;
736
737 SHA_init(&ctx);
738
739 int result;
740
741 if (header_bytes_read >= 8 &&
742 memcmp(header, "BSDIFF40", 8) == 0) {
743 result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size,
744 patch, 0, sink, token, &ctx);
745 } else if (header_bytes_read >= 8 &&
746 memcmp(header, "IMGDIFF2", 8) == 0) {
747 result = ApplyImagePatch(source_to_use->data, source_to_use->size,
748 patch, sink, token, &ctx);
749 } else {
750 printf("Unknown patch file format\n");
751 return 1;
752 }
753
754 if (output >= 0) {
755 fsync(output);
756 close(output);
757 }
758
759 if (result != 0) {
760 if (retry == 0) {
761 printf("applying patch failed\n");
762 return result != 0;
763 } else {
764 printf("applying patch failed; retrying\n");
765 }
766 if (outname != NULL) {
767 unlink(outname);
768 }
769 } else {
770 // succeeded; no need to retry
771 break;
772 }
773 } while (retry-- > 0);
774
775 const uint8_t* current_target_sha1 = SHA_final(&ctx);
776 if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 0) {
777 printf("patch did not produce expected sha1\n");
778 return 1;
842 } 779 }
843 780
844 if (result != 0) { 781 if (output < 0) {
845 if (retry == 0) { 782 // Copy the temp file to the MTD partition.
846 printf("applying patch failed\n"); 783 if (WriteToMTDPartition(msi.buffer, msi.pos, target_filename) != 0) {
847 return result != 0; 784 printf("write of patched data to %s failed\n", target_filename);
848 } else { 785 return 1;
849 printf("applying patch failed; retrying\n"); 786 }
850 } 787 free(msi.buffer);
851 if (outname != NULL) {
852 unlink(outname);
853 }
854 } else { 788 } else {
855 // succeeded; no need to retry 789 // Give the .patch file the same owner, group, and mode of the
856 break; 790 // original source file.
857 } 791 if (chmod(outname, source_to_use->st.st_mode) != 0) {
858 } while (retry-- > 0); 792 printf("chmod of \"%s\" failed: %s\n", outname, strerror(errno));
859 793 return 1;
860 const uint8_t* current_target_sha1 = SHA_final(&ctx); 794 }
861 if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 0) { 795 if (chown(outname, source_to_use->st.st_uid,
862 printf("patch did not produce expected sha1\n"); 796 source_to_use->st.st_gid) != 0) {
863 return 1; 797 printf("chown of \"%s\" failed: %s\n", outname, strerror(errno));
864 } 798 return 1;
865 799 }
866 if (output < 0) { 800
867 // Copy the temp file to the MTD partition. 801 // Finally, rename the .patch file to replace the target file.
868 if (WriteToMTDPartition(msi.buffer, msi.pos, target_filename) != 0) { 802 if (rename(outname, target_filename) != 0) {
869 printf("write of patched data to %s failed\n", target_filename); 803 printf("rename of .patch to \"%s\" failed: %s\n",
870 return 1; 804 target_filename, strerror(errno));
871 } 805 return 1;
872 free(msi.buffer); 806 }
873 } else { 807 }
874 // Give the .patch file the same owner, group, and mode of the 808
875 // original source file. 809 // If this run of applypatch created the copy, and we're here, we
876 if (chmod(outname, source_to_use->st.st_mode) != 0) { 810 // can delete it.
877 printf("chmod of \"%s\" failed: %s\n", outname, strerror(errno)); 811 if (made_copy) unlink(CACHE_TEMP_SOURCE);
878 return 1; 812
879 } 813 // Success!
880 if (chown(outname, source_to_use->st.st_uid, 814 return 0;
881 source_to_use->st.st_gid) != 0) {
882 printf("chown of \"%s\" failed: %s\n", outname, strerror(errno));
883 return 1;
884 }
885
886 // Finally, rename the .patch file to replace the target file.
887 if (rename(outname, target_filename) != 0) {
888 printf("rename of .patch to \"%s\" failed: %s\n",
889 target_filename, strerror(errno));
890 return 1;
891 }
892 }
893
894 // If this run of applypatch created the copy, and we're here, we
895 // can delete it.
896 if (made_copy) unlink(CACHE_TEMP_SOURCE);
897
898 // Success!
899 return 0;
900} 815}
diff --git a/applypatch/applypatch.h b/applypatch/applypatch.h
index 3cb80216..10c01259 100644
--- a/applypatch/applypatch.h
+++ b/applypatch/applypatch.h
@@ -19,6 +19,7 @@
19 19
20#include <sys/stat.h> 20#include <sys/stat.h>
21#include "mincrypt/sha.h" 21#include "mincrypt/sha.h"
22#include "edify/expr.h"
22 23
23typedef struct _Patch { 24typedef struct _Patch {
24 uint8_t sha1[SHA_DIGEST_SIZE]; 25 uint8_t sha1[SHA_DIGEST_SIZE];
@@ -42,8 +43,21 @@ typedef struct _FileContents {
42typedef ssize_t (*SinkFn)(unsigned char*, ssize_t, void*); 43typedef ssize_t (*SinkFn)(unsigned char*, ssize_t, void*);
43 44
44// applypatch.c 45// applypatch.c
46int ShowLicenses();
45size_t FreeSpaceForFile(const char* filename); 47size_t FreeSpaceForFile(const char* filename);
46int applypatch(int argc, char** argv); 48int CacheSizeCheck(size_t bytes);
49int ParseSha1(const char* str, uint8_t* digest);
50
51int applypatch(const char* source_filename,
52 const char* target_filename,
53 const char* target_sha1_str,
54 size_t target_size,
55 int num_patches,
56 char** const patch_sha1_str,
57 Value** patch_data);
58int applypatch_check(const char* filename,
59 int num_patches,
60 char** const patch_sha1_str);
47 61
48// Read a file into memory; store it and its associated metadata in 62// Read a file into memory; store it and its associated metadata in
49// *file. Return 0 on success. 63// *file. Return 0 on success.
@@ -53,15 +67,15 @@ void FreeFileContents(FileContents* file);
53// bsdiff.c 67// bsdiff.c
54void ShowBSDiffLicense(); 68void ShowBSDiffLicense();
55int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, 69int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
56 const char* patch_filename, ssize_t offset, 70 const Value* patch, ssize_t patch_offset,
57 SinkFn sink, void* token, SHA_CTX* ctx); 71 SinkFn sink, void* token, SHA_CTX* ctx);
58int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, 72int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
59 const char* patch_filename, ssize_t patch_offset, 73 const Value* patch, ssize_t patch_offset,
60 unsigned char** new_data, ssize_t* new_size); 74 unsigned char** new_data, ssize_t* new_size);
61 75
62// imgpatch.c 76// imgpatch.c
63int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, 77int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
64 const char* patch_filename, 78 const Value* patch,
65 SinkFn sink, void* token, SHA_CTX* ctx); 79 SinkFn sink, void* token, SHA_CTX* ctx);
66 80
67// freecache.c 81// freecache.c
diff --git a/applypatch/applypatch.sh b/applypatch/applypatch.sh
index 88f3025f..8ea68a1a 100755
--- a/applypatch/applypatch.sh
+++ b/applypatch/applypatch.sh
@@ -11,7 +11,7 @@
11# the tests. 11# the tests.
12 12
13EMULATOR_PORT=5580 13EMULATOR_PORT=5580
14DATA_DIR=$ANDROID_BUILD_TOP/build/tools/applypatch/testdata 14DATA_DIR=$ANDROID_BUILD_TOP/bootable/recovery/applypatch/testdata
15 15
16# This must be the filename that applypatch uses for its copies. 16# This must be the filename that applypatch uses for its copies.
17CACHE_TEMP_SOURCE=/cache/saved.file 17CACHE_TEMP_SOURCE=/cache/saved.file
@@ -81,6 +81,7 @@ cleanup() {
81 testname "removing test files" 81 testname "removing test files"
82 run_command rm $WORK_DIR/bloat.dat 82 run_command rm $WORK_DIR/bloat.dat
83 run_command rm $WORK_DIR/old.file 83 run_command rm $WORK_DIR/old.file
84 run_command rm $WORK_DIR/foo
84 run_command rm $WORK_DIR/patch.bsdiff 85 run_command rm $WORK_DIR/patch.bsdiff
85 run_command rm $WORK_DIR/applypatch 86 run_command rm $WORK_DIR/applypatch
86 run_command rm $CACHE_TEMP_SOURCE 87 run_command rm $CACHE_TEMP_SOURCE
@@ -88,10 +89,12 @@ cleanup() {
88 89
89 [ "$pid_emulator" == "" ] || kill $pid_emulator 90 [ "$pid_emulator" == "" ] || kill $pid_emulator
90 91
91 rm -rf $tmpdir 92 if [ $# == 0 ]; then
93 rm -rf $tmpdir
94 fi
92} 95}
93 96
94cleanup 97cleanup leave_tmp
95 98
96$ADB push $ANDROID_PRODUCT_OUT/system/bin/applypatch $WORK_DIR/applypatch 99$ADB push $ANDROID_PRODUCT_OUT/system/bin/applypatch $WORK_DIR/applypatch
97 100
@@ -153,6 +156,8 @@ run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 &&
153 156
154$ADB push $DATA_DIR/old.file $WORK_DIR 157$ADB push $DATA_DIR/old.file $WORK_DIR
155$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR 158$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR
159echo hello > $tmpdir/foo
160$ADB push $tmpdir/foo $WORK_DIR
156 161
157# Check that the partition has enough space to apply the patch without 162# Check that the partition has enough space to apply the patch without
158# copying. If it doesn't, we'll be testing the low-space condition 163# copying. If it doesn't, we'll be testing the low-space condition
diff --git a/applypatch/bspatch.c b/applypatch/bspatch.c
index d5cd6174..2e80f81d 100644
--- a/applypatch/bspatch.c
+++ b/applypatch/bspatch.c
@@ -32,221 +32,221 @@
32#include "applypatch.h" 32#include "applypatch.h"
33 33
34void ShowBSDiffLicense() { 34void ShowBSDiffLicense() {
35 puts("The bsdiff library used herein is:\n" 35 puts("The bsdiff library used herein is:\n"
36 "\n" 36 "\n"
37 "Copyright 2003-2005 Colin Percival\n" 37 "Copyright 2003-2005 Colin Percival\n"
38 "All rights reserved\n" 38 "All rights reserved\n"
39 "\n" 39 "\n"
40 "Redistribution and use in source and binary forms, with or without\n" 40 "Redistribution and use in source and binary forms, with or without\n"
41 "modification, are permitted providing that the following conditions\n" 41 "modification, are permitted providing that the following conditions\n"
42 "are met:\n" 42 "are met:\n"
43 "1. Redistributions of source code must retain the above copyright\n" 43 "1. Redistributions of source code must retain the above copyright\n"
44 " notice, this list of conditions and the following disclaimer.\n" 44 " notice, this list of conditions and the following disclaimer.\n"
45 "2. Redistributions in binary form must reproduce the above copyright\n" 45 "2. Redistributions in binary form must reproduce the above copyright\n"
46 " notice, this list of conditions and the following disclaimer in the\n" 46 " notice, this list of conditions and the following disclaimer in the\n"
47 " documentation and/or other materials provided with the distribution.\n" 47 " documentation and/or other materials provided with the distribution.\n"
48 "\n" 48 "\n"
49 "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n" 49 "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
50 "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n" 50 "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
51 "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n" 51 "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
52 "ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n" 52 "ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n"
53 "DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n" 53 "DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"
54 "DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n" 54 "DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n"
55 "OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n" 55 "OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"
56 "HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n" 56 "HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n"
57 "STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n" 57 "STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n"
58 "IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n" 58 "IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
59 "POSSIBILITY OF SUCH DAMAGE.\n" 59 "POSSIBILITY OF SUCH DAMAGE.\n"
60 "\n------------------\n\n" 60 "\n------------------\n\n"
61 "This program uses Julian R Seward's \"libbzip2\" library, available\n" 61 "This program uses Julian R Seward's \"libbzip2\" library, available\n"
62 "from http://www.bzip.org/.\n" 62 "from http://www.bzip.org/.\n"
63 ); 63 );
64} 64}
65 65
66static off_t offtin(u_char *buf) 66static off_t offtin(u_char *buf)
67{ 67{
68 off_t y; 68 off_t y;
69 69
70 y=buf[7]&0x7F; 70 y=buf[7]&0x7F;
71 y=y*256;y+=buf[6]; 71 y=y*256;y+=buf[6];
72 y=y*256;y+=buf[5]; 72 y=y*256;y+=buf[5];
73 y=y*256;y+=buf[4]; 73 y=y*256;y+=buf[4];
74 y=y*256;y+=buf[3]; 74 y=y*256;y+=buf[3];
75 y=y*256;y+=buf[2]; 75 y=y*256;y+=buf[2];
76 y=y*256;y+=buf[1]; 76 y=y*256;y+=buf[1];
77 y=y*256;y+=buf[0]; 77 y=y*256;y+=buf[0];
78 78
79 if(buf[7]&0x80) y=-y; 79 if(buf[7]&0x80) y=-y;
80 80
81 return y; 81 return y;
82} 82}
83 83
84int FillBuffer(unsigned char* buffer, int size, bz_stream* stream) {
85 stream->next_out = (char*)buffer;
86 stream->avail_out = size;
87 while (stream->avail_out > 0) {
88 int bzerr = BZ2_bzDecompress(stream);
89 if (bzerr != BZ_OK && bzerr != BZ_STREAM_END) {
90 printf("bz error %d decompressing\n", bzerr);
91 return -1;
92 }
93 if (stream->avail_out > 0) {
94 printf("need %d more bytes\n", stream->avail_out);
95 }
96 }
97 return 0;
98}
84 99
85int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, 100int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
86 const char* patch_filename, ssize_t patch_offset, 101 const Value* patch, ssize_t patch_offset,
87 SinkFn sink, void* token, SHA_CTX* ctx) { 102 SinkFn sink, void* token, SHA_CTX* ctx) {
88 103
89 unsigned char* new_data; 104 unsigned char* new_data;
90 ssize_t new_size; 105 ssize_t new_size;
91 if (ApplyBSDiffPatchMem(old_data, old_size, patch_filename, patch_offset, 106 if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset,
92 &new_data, &new_size) != 0) { 107 &new_data, &new_size) != 0) {
93 return -1; 108 return -1;
94 } 109 }
95 110
96 if (sink(new_data, new_size, token) < new_size) { 111 if (sink(new_data, new_size, token) < new_size) {
97 fprintf(stderr, "short write of output: %d (%s)\n", errno, strerror(errno)); 112 printf("short write of output: %d (%s)\n", errno, strerror(errno));
98 return 1; 113 return 1;
99 } 114 }
100 if (ctx) { 115 if (ctx) {
101 SHA_update(ctx, new_data, new_size); 116 SHA_update(ctx, new_data, new_size);
102 } 117 }
103 free(new_data); 118 free(new_data);
104 119
105 return 0; 120 return 0;
106} 121}
107 122
108int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, 123int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
109 const char* patch_filename, ssize_t patch_offset, 124 const Value* patch, ssize_t patch_offset,
110 unsigned char** new_data, ssize_t* new_size) { 125 unsigned char** new_data, ssize_t* new_size) {
111 126 // Patch data format:
112 FILE* f; 127 // 0 8 "BSDIFF40"
113 if ((f = fopen(patch_filename, "rb")) == NULL) { 128 // 8 8 X
114 fprintf(stderr, "failed to open patch file\n"); 129 // 16 8 Y
115 return 1; 130 // 24 8 sizeof(newfile)
116 } 131 // 32 X bzip2(control block)
117 132 // 32+X Y bzip2(diff block)
118 // File format: 133 // 32+X+Y ??? bzip2(extra block)
119 // 0 8 "BSDIFF40" 134 // with control block a set of triples (x,y,z) meaning "add x bytes
120 // 8 8 X 135 // from oldfile to x bytes from the diff block; copy y bytes from the
121 // 16 8 Y 136 // extra block; seek forwards in oldfile by z bytes".
122 // 24 8 sizeof(newfile) 137
123 // 32 X bzip2(control block) 138 unsigned char* header = (unsigned char*) patch->data + patch_offset;
124 // 32+X Y bzip2(diff block) 139 if (memcmp(header, "BSDIFF40", 8) != 0) {
125 // 32+X+Y ??? bzip2(extra block) 140 printf("corrupt bsdiff patch file header (magic number)\n");
126 // with control block a set of triples (x,y,z) meaning "add x bytes
127 // from oldfile to x bytes from the diff block; copy y bytes from the
128 // extra block; seek forwards in oldfile by z bytes".
129
130 fseek(f, patch_offset, SEEK_SET);
131
132 unsigned char header[32];
133 if (fread(header, 1, 32, f) < 32) {
134 fprintf(stderr, "failed to read patch file header\n");
135 return 1;
136 }
137
138 if (memcmp(header, "BSDIFF40", 8) != 0) {
139 fprintf(stderr, "corrupt bsdiff patch file header (magic number)\n");
140 return 1;
141 }
142
143 ssize_t ctrl_len, data_len;
144 ctrl_len = offtin(header+8);
145 data_len = offtin(header+16);
146 *new_size = offtin(header+24);
147
148 if (ctrl_len < 0 || data_len < 0 || *new_size < 0) {
149 fprintf(stderr, "corrupt patch file header (data lengths)\n");
150 return 1;
151 }
152
153 fclose(f);
154
155 int bzerr;
156
157#define OPEN_AT(f, bzf, offset) \
158 FILE* f; \
159 BZFILE* bzf; \
160 if ((f = fopen(patch_filename, "rb")) == NULL) { \
161 fprintf(stderr, "failed to open patch file\n"); \
162 return 1; \
163 } \
164 if (fseeko(f, offset+patch_offset, SEEK_SET)) { \
165 fprintf(stderr, "failed to seek in patch file\n"); \
166 return 1; \
167 } \
168 if ((bzf = BZ2_bzReadOpen(&bzerr, f, 0, 0, NULL, 0)) == NULL) { \
169 fprintf(stderr, "failed to bzReadOpen in patch file (%d)\n", bzerr); \
170 return 1; \
171 }
172
173 OPEN_AT(cpf, cpfbz2, 32);
174 OPEN_AT(dpf, dpfbz2, 32+ctrl_len);
175 OPEN_AT(epf, epfbz2, 32+ctrl_len+data_len);
176
177#undef OPEN_AT
178
179 *new_data = malloc(*new_size);
180 if (*new_data == NULL) {
181 fprintf(stderr, "failed to allocate %d bytes of memory for output file\n",
182 (int)*new_size);
183 return 1;
184 }
185
186 off_t oldpos = 0, newpos = 0;
187 off_t ctrl[3];
188 off_t len_read;
189 int i;
190 unsigned char buf[8];
191 while (newpos < *new_size) {
192 // Read control data
193 for (i = 0; i < 3; ++i) {
194 len_read = BZ2_bzRead(&bzerr, cpfbz2, buf, 8);
195 if (len_read < 8 || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) {
196 fprintf(stderr, "corrupt patch (read control)\n");
197 return 1; 141 return 1;
198 }
199 ctrl[i] = offtin(buf);
200 } 142 }
201 143
202 // Sanity check 144 ssize_t ctrl_len, data_len;
203 if (newpos + ctrl[0] > *new_size) { 145 ctrl_len = offtin(header+8);
204 fprintf(stderr, "corrupt patch (new file overrun)\n"); 146 data_len = offtin(header+16);
205 return 1; 147 *new_size = offtin(header+24);
206 }
207 148
208 // Read diff string 149 if (ctrl_len < 0 || data_len < 0 || *new_size < 0) {
209 len_read = BZ2_bzRead(&bzerr, dpfbz2, *new_data + newpos, ctrl[0]); 150 printf("corrupt patch file header (data lengths)\n");
210 if (len_read < ctrl[0] || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) { 151 return 1;
211 fprintf(stderr, "corrupt patch (read diff)\n");
212 return 1;
213 } 152 }
214 153
215 // Add old data to diff string 154 int bzerr;
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 155
222 // Adjust pointers 156 bz_stream cstream;
223 newpos += ctrl[0]; 157 cstream.next_in = patch->data + patch_offset + 32;
224 oldpos += ctrl[0]; 158 cstream.avail_in = ctrl_len;
159 cstream.bzalloc = NULL;
160 cstream.bzfree = NULL;
161 cstream.opaque = NULL;
162 if ((bzerr = BZ2_bzDecompressInit(&cstream, 0, 0)) != BZ_OK) {
163 printf("failed to bzinit control stream (%d)\n", bzerr);
164 }
225 165
226 // Sanity check 166 bz_stream dstream;
227 if (newpos + ctrl[1] > *new_size) { 167 dstream.next_in = patch->data + patch_offset + 32 + ctrl_len;
228 fprintf(stderr, "corrupt patch (new file overrun)\n"); 168 dstream.avail_in = data_len;
229 return 1; 169 dstream.bzalloc = NULL;
170 dstream.bzfree = NULL;
171 dstream.opaque = NULL;
172 if ((bzerr = BZ2_bzDecompressInit(&dstream, 0, 0)) != BZ_OK) {
173 printf("failed to bzinit diff stream (%d)\n", bzerr);
230 } 174 }
231 175
232 // Read extra string 176 bz_stream estream;
233 len_read = BZ2_bzRead(&bzerr, epfbz2, *new_data + newpos, ctrl[1]); 177 estream.next_in = patch->data + patch_offset + 32 + ctrl_len + data_len;
234 if (len_read < ctrl[1] || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) { 178 estream.avail_in = patch->size - (patch_offset + 32 + ctrl_len + data_len);
235 fprintf(stderr, "corrupt patch (read extra)\n"); 179 estream.bzalloc = NULL;
236 return 1; 180 estream.bzfree = NULL;
181 estream.opaque = NULL;
182 if ((bzerr = BZ2_bzDecompressInit(&estream, 0, 0)) != BZ_OK) {
183 printf("failed to bzinit extra stream (%d)\n", bzerr);
237 } 184 }
238 185
239 // Adjust pointers 186 *new_data = malloc(*new_size);
240 newpos += ctrl[1]; 187 if (*new_data == NULL) {
241 oldpos += ctrl[2]; 188 printf("failed to allocate %ld bytes of memory for output file\n",
242 } 189 (long)*new_size);
190 return 1;
191 }
243 192
244 BZ2_bzReadClose(&bzerr, cpfbz2); 193 off_t oldpos = 0, newpos = 0;
245 BZ2_bzReadClose(&bzerr, dpfbz2); 194 off_t ctrl[3];
246 BZ2_bzReadClose(&bzerr, epfbz2); 195 off_t len_read;
247 fclose(cpf); 196 int i;
248 fclose(dpf); 197 unsigned char buf[24];
249 fclose(epf); 198 while (newpos < *new_size) {
199 // Read control data
200 if (FillBuffer(buf, 24, &cstream) != 0) {
201 printf("error while reading control stream\n");
202 return 1;
203 }
204 ctrl[0] = offtin(buf);
205 ctrl[1] = offtin(buf+8);
206 ctrl[2] = offtin(buf+16);
207
208 // Sanity check
209 if (newpos + ctrl[0] > *new_size) {
210 printf("corrupt patch (new file overrun)\n");
211 return 1;
212 }
213
214 // Read diff string
215 if (FillBuffer(*new_data + newpos, ctrl[0], &dstream) != 0) {
216 printf("error while reading diff stream\n");
217 return 1;
218 }
219
220 // Add old data to diff string
221 for (i = 0; i < ctrl[0]; ++i) {
222 if ((oldpos+i >= 0) && (oldpos+i < old_size)) {
223 (*new_data)[newpos+i] += old_data[oldpos+i];
224 }
225 }
226
227 // Adjust pointers
228 newpos += ctrl[0];
229 oldpos += ctrl[0];
230
231 // Sanity check
232 if (newpos + ctrl[1] > *new_size) {
233 printf("corrupt patch (new file overrun)\n");
234 return 1;
235 }
236
237 // Read extra string
238 if (FillBuffer(*new_data + newpos, ctrl[1], &estream) != 0) {
239 printf("error while reading extra stream\n");
240 return 1;
241 }
242
243 // Adjust pointers
244 newpos += ctrl[1];
245 oldpos += ctrl[2];
246 }
250 247
251 return 0; 248 BZ2_bzDecompressEnd(&cstream);
249 BZ2_bzDecompressEnd(&dstream);
250 BZ2_bzDecompressEnd(&estream);
251 return 0;
252} 252}
diff --git a/applypatch/imgpatch.c b/applypatch/imgpatch.c
index 53228174..e3ee80ac 100644
--- a/applypatch/imgpatch.c
+++ b/applypatch/imgpatch.c
@@ -36,329 +36,184 @@
36 * Return 0 on success. 36 * Return 0 on success.
37 */ 37 */
38int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, 38int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
39 const char* patch_filename, 39 const Value* patch,
40 SinkFn sink, void* token, SHA_CTX* ctx) { 40 SinkFn sink, void* token, SHA_CTX* ctx) {
41 FILE* f; 41 ssize_t pos = 12;
42 if ((f = fopen(patch_filename, "rb")) == NULL) { 42 char* header = patch->data;
43 printf("failed to open patch file\n"); 43 if (patch->size < 12) {
44 return -1; 44 printf("patch too short to contain header\n");
45 }
46
47 unsigned char header[12];
48 if (fread(header, 1, 12, f) != 12) {
49 printf("failed to read patch file header\n");
50 return -1;
51 }
52
53 // IMGDIFF1 uses CHUNK_NORMAL and CHUNK_GZIP.
54 // IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW.
55 if (memcmp(header, "IMGDIFF", 7) != 0 ||
56 (header[7] != '1' && header[7] != '2')) {
57 printf("corrupt patch file header (magic number)\n");
58 return -1;
59 }
60
61 int num_chunks = Read4(header+8);
62
63 int i;
64 for (i = 0; i < num_chunks; ++i) {
65 // each chunk's header record starts with 4 bytes.
66 unsigned char chunk[4];
67 if (fread(chunk, 1, 4, f) != 4) {
68 printf("failed to read chunk %d record\n", i);
69 return -1;
70 }
71
72 int type = Read4(chunk);
73
74 if (type == CHUNK_NORMAL) {
75 unsigned char normal_header[24];
76 if (fread(normal_header, 1, 24, f) != 24) {
77 printf("failed to read chunk %d normal header data\n", i);
78 return -1;
79 }
80
81 size_t src_start = Read8(normal_header);
82 size_t src_len = Read8(normal_header+8);
83 size_t patch_offset = Read8(normal_header+16);
84
85 printf("CHUNK %d: normal patch offset %d\n", i, patch_offset);
86
87 ApplyBSDiffPatch(old_data + src_start, src_len,
88 patch_filename, patch_offset,
89 sink, token, ctx);
90 } else if (type == CHUNK_GZIP) {
91 // This branch is basically a duplicate of the CHUNK_DEFLATE
92 // branch, with a bit of extra processing for the gzip header
93 // and footer. I've avoided factoring the common code out since
94 // this branch will just be deleted when we drop support for
95 // IMGDIFF1.
96
97 // gzip chunks have an additional 64 + gzip_header_len + 8 bytes
98 // in their chunk header.
99 unsigned char* gzip = malloc(64);
100 if (fread(gzip, 1, 64, f) != 64) {
101 printf("failed to read chunk %d initial gzip header data\n",
102 i);
103 return -1;
104 }
105 size_t gzip_header_len = Read4(gzip+60);
106 gzip = realloc(gzip, 64 + gzip_header_len + 8);
107 if (fread(gzip+64, 1, gzip_header_len+8, f) != gzip_header_len+8) {
108 printf("failed to read chunk %d remaining gzip header data\n",
109 i);
110 return -1;
111 }
112
113 size_t src_start = Read8(gzip);
114 size_t src_len = Read8(gzip+8);
115 size_t patch_offset = Read8(gzip+16);
116
117 size_t expanded_len = Read8(gzip+24);
118 size_t target_len = Read8(gzip+32);
119 int gz_level = Read4(gzip+40);
120 int gz_method = Read4(gzip+44);
121 int gz_windowBits = Read4(gzip+48);
122 int gz_memLevel = Read4(gzip+52);
123 int gz_strategy = Read4(gzip+56);
124
125 printf("CHUNK %d: gzip patch offset %d\n", i, patch_offset);
126
127 // Decompress the source data; the chunk header tells us exactly
128 // how big we expect it to be when decompressed.
129
130 unsigned char* expanded_source = malloc(expanded_len);
131 if (expanded_source == NULL) {
132 printf("failed to allocate %d bytes for expanded_source\n",
133 expanded_len);
134 return -1;
135 }
136
137 z_stream strm;
138 strm.zalloc = Z_NULL;
139 strm.zfree = Z_NULL;
140 strm.opaque = Z_NULL;
141 strm.avail_in = src_len - (gzip_header_len + 8);
142 strm.next_in = (unsigned char*)(old_data + src_start + gzip_header_len);
143 strm.avail_out = expanded_len;
144 strm.next_out = expanded_source;
145
146 int ret;
147 ret = inflateInit2(&strm, -15);
148 if (ret != Z_OK) {
149 printf("failed to init source inflation: %d\n", ret);
150 return -1;
151 }
152
153 // Because we've provided enough room to accommodate the output
154 // data, we expect one call to inflate() to suffice.
155 ret = inflate(&strm, Z_SYNC_FLUSH);
156 if (ret != Z_STREAM_END) {
157 printf("source inflation returned %d\n", ret);
158 return -1;
159 }
160 // We should have filled the output buffer exactly.
161 if (strm.avail_out != 0) {
162 printf("source inflation short by %d bytes\n", strm.avail_out);
163 return -1; 45 return -1;
164 } 46 }
165 inflateEnd(&strm);
166 47
167 // Next, apply the bsdiff patch (in memory) to the uncompressed 48 // IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW.
168 // data. 49 // (IMGDIFF1, which is no longer supported, used CHUNK_NORMAL and
169 unsigned char* uncompressed_target_data; 50 // CHUNK_GZIP.)
170 ssize_t uncompressed_target_size; 51 if (memcmp(header, "IMGDIFF2", 8) != 0) {
171 if (ApplyBSDiffPatchMem(expanded_source, expanded_len, 52 printf("corrupt patch file header (magic number)\n");
172 patch_filename, patch_offset,
173 &uncompressed_target_data,
174 &uncompressed_target_size) != 0) {
175 return -1; 53 return -1;
176 } 54 }
177
178 // Now compress the target data and append it to the output.
179
180 // start with the gzip header.
181 sink(gzip+64, gzip_header_len, token);
182 SHA_update(ctx, gzip+64, gzip_header_len);
183
184 // we're done with the expanded_source data buffer, so we'll
185 // reuse that memory to receive the output of deflate.
186 unsigned char* temp_data = expanded_source;
187 ssize_t temp_size = expanded_len;
188 if (temp_size < 32768) {
189 // ... unless the buffer is too small, in which case we'll
190 // allocate a fresh one.
191 free(temp_data);
192 temp_data = malloc(32768);
193 temp_size = 32768;
194 }
195 55
196 // now the deflate stream 56 int num_chunks = Read4(header+8);
197 strm.zalloc = Z_NULL;
198 strm.zfree = Z_NULL;
199 strm.opaque = Z_NULL;
200 strm.avail_in = uncompressed_target_size;
201 strm.next_in = uncompressed_target_data;
202 ret = deflateInit2(&strm, gz_level, gz_method, gz_windowBits,
203 gz_memLevel, gz_strategy);
204 do {
205 strm.avail_out = temp_size;
206 strm.next_out = temp_data;
207 ret = deflate(&strm, Z_FINISH);
208 size_t have = temp_size - strm.avail_out;
209 57
210 if (sink(temp_data, have, token) != have) { 58 int i;
211 printf("failed to write %d compressed bytes to output\n", 59 for (i = 0; i < num_chunks; ++i) {
212 have); 60 // each chunk's header record starts with 4 bytes.
213 return -1; 61 if (pos + 4 > patch->size) {
62 printf("failed to read chunk %d record\n", i);
63 return -1;
214 } 64 }
215 SHA_update(ctx, temp_data, have); 65 int type = Read4(patch->data + pos);
216 } while (ret != Z_STREAM_END); 66 pos += 4;
217 deflateEnd(&strm); 67
218 68 if (type == CHUNK_NORMAL) {
219 // lastly, the gzip footer. 69 char* normal_header = patch->data + pos;
220 sink(gzip+64+gzip_header_len, 8, token); 70 pos += 24;
221 SHA_update(ctx, gzip+64+gzip_header_len, 8); 71 if (pos > patch->size) {
222 72 printf("failed to read chunk %d normal header data\n", i);
223 free(temp_data); 73 return -1;
224 free(uncompressed_target_data); 74 }
225 free(gzip); 75
226 } else if (type == CHUNK_RAW) { 76 size_t src_start = Read8(normal_header);
227 unsigned char raw_header[4]; 77 size_t src_len = Read8(normal_header+8);
228 if (fread(raw_header, 1, 4, f) != 4) { 78 size_t patch_offset = Read8(normal_header+16);
229 printf("failed to read chunk %d raw header data\n", i); 79
230 return -1; 80 ApplyBSDiffPatch(old_data + src_start, src_len,
231 } 81 patch, patch_offset, sink, token, ctx);
232 82 } else if (type == CHUNK_RAW) {
233 size_t data_len = Read4(raw_header); 83 char* raw_header = patch->data + pos;
234 84 pos += 4;
235 printf("CHUNK %d: raw data %d\n", i, data_len); 85 if (pos > patch->size) {
236 86 printf("failed to read chunk %d raw header data\n", i);
237 unsigned char* temp = malloc(data_len); 87 return -1;
238 if (fread(temp, 1, data_len, f) != data_len) { 88 }
239 printf("failed to read chunk %d raw data\n", i); 89
240 return -1; 90 ssize_t data_len = Read4(raw_header);
241 } 91
242 SHA_update(ctx, temp, data_len); 92 if (pos + data_len > patch->size) {
243 if (sink(temp, data_len, token) != data_len) { 93 printf("failed to read chunk %d raw data\n", i);
244 printf("failed to write chunk %d raw data\n", i); 94 return -1;
245 return -1; 95 }
246 } 96 SHA_update(ctx, patch->data + pos, data_len);
247 } else if (type == CHUNK_DEFLATE) { 97 if (sink((unsigned char*)patch->data + pos,
248 // deflate chunks have an additional 60 bytes in their chunk header. 98 data_len, token) != data_len) {
249 unsigned char deflate_header[60]; 99 printf("failed to write chunk %d raw data\n", i);
250 if (fread(deflate_header, 1, 60, f) != 60) { 100 return -1;
251 printf("failed to read chunk %d deflate header data\n", i); 101 }
252 return -1; 102 pos += data_len;
253 } 103 } else if (type == CHUNK_DEFLATE) {
254 104 // deflate chunks have an additional 60 bytes in their chunk header.
255 size_t src_start = Read8(deflate_header); 105 char* deflate_header = patch->data + pos;
256 size_t src_len = Read8(deflate_header+8); 106 pos += 60;
257 size_t patch_offset = Read8(deflate_header+16); 107 if (pos > patch->size) {
258 size_t expanded_len = Read8(deflate_header+24); 108 printf("failed to read chunk %d deflate header data\n", i);
259 size_t target_len = Read8(deflate_header+32); 109 return -1;
260 int level = Read4(deflate_header+40); 110 }
261 int method = Read4(deflate_header+44); 111
262 int windowBits = Read4(deflate_header+48); 112 size_t src_start = Read8(deflate_header);
263 int memLevel = Read4(deflate_header+52); 113 size_t src_len = Read8(deflate_header+8);
264 int strategy = Read4(deflate_header+56); 114 size_t patch_offset = Read8(deflate_header+16);
265 115 size_t expanded_len = Read8(deflate_header+24);
266 printf("CHUNK %d: deflate patch offset %d\n", i, patch_offset); 116 size_t target_len = Read8(deflate_header+32);
267 117 int level = Read4(deflate_header+40);
268 // Decompress the source data; the chunk header tells us exactly 118 int method = Read4(deflate_header+44);
269 // how big we expect it to be when decompressed. 119 int windowBits = Read4(deflate_header+48);
270 120 int memLevel = Read4(deflate_header+52);
271 unsigned char* expanded_source = malloc(expanded_len); 121 int strategy = Read4(deflate_header+56);
272 if (expanded_source == NULL) { 122
273 printf("failed to allocate %d bytes for expanded_source\n", 123 // Decompress the source data; the chunk header tells us exactly
274 expanded_len); 124 // how big we expect it to be when decompressed.
275 return -1; 125
276 } 126 unsigned char* expanded_source = malloc(expanded_len);
277 127 if (expanded_source == NULL) {
278 z_stream strm; 128 printf("failed to allocate %d bytes for expanded_source\n",
279 strm.zalloc = Z_NULL; 129 expanded_len);
280 strm.zfree = Z_NULL; 130 return -1;
281 strm.opaque = Z_NULL; 131 }
282 strm.avail_in = src_len; 132
283 strm.next_in = (unsigned char*)(old_data + src_start); 133 z_stream strm;
284 strm.avail_out = expanded_len; 134 strm.zalloc = Z_NULL;
285 strm.next_out = expanded_source; 135 strm.zfree = Z_NULL;
286 136 strm.opaque = Z_NULL;
287 int ret; 137 strm.avail_in = src_len;
288 ret = inflateInit2(&strm, -15); 138 strm.next_in = (unsigned char*)(old_data + src_start);
289 if (ret != Z_OK) { 139 strm.avail_out = expanded_len;
290 printf("failed to init source inflation: %d\n", ret); 140 strm.next_out = expanded_source;
291 return -1; 141
292 } 142 int ret;
293 143 ret = inflateInit2(&strm, -15);
294 // Because we've provided enough room to accommodate the output 144 if (ret != Z_OK) {
295 // data, we expect one call to inflate() to suffice. 145 printf("failed to init source inflation: %d\n", ret);
296 ret = inflate(&strm, Z_SYNC_FLUSH); 146 return -1;
297 if (ret != Z_STREAM_END) { 147 }
298 printf("source inflation returned %d\n", ret); 148
299 return -1; 149 // Because we've provided enough room to accommodate the output
300 } 150 // data, we expect one call to inflate() to suffice.
301 // We should have filled the output buffer exactly. 151 ret = inflate(&strm, Z_SYNC_FLUSH);
302 if (strm.avail_out != 0) { 152 if (ret != Z_STREAM_END) {
303 printf("source inflation short by %d bytes\n", strm.avail_out); 153 printf("source inflation returned %d\n", ret);
304 return -1; 154 return -1;
305 } 155 }
306 inflateEnd(&strm); 156 // We should have filled the output buffer exactly.
307 157 if (strm.avail_out != 0) {
308 // Next, apply the bsdiff patch (in memory) to the uncompressed 158 printf("source inflation short by %d bytes\n", strm.avail_out);
309 // data. 159 return -1;
310 unsigned char* uncompressed_target_data; 160 }
311 ssize_t uncompressed_target_size; 161 inflateEnd(&strm);
312 if (ApplyBSDiffPatchMem(expanded_source, expanded_len, 162
313 patch_filename, patch_offset, 163 // Next, apply the bsdiff patch (in memory) to the uncompressed
314 &uncompressed_target_data, 164 // data.
315 &uncompressed_target_size) != 0) { 165 unsigned char* uncompressed_target_data;
316 return -1; 166 ssize_t uncompressed_target_size;
317 } 167 if (ApplyBSDiffPatchMem(expanded_source, expanded_len,
318 168 patch, patch_offset,
319 // Now compress the target data and append it to the output. 169 &uncompressed_target_data,
320 170 &uncompressed_target_size) != 0) {
321 // we're done with the expanded_source data buffer, so we'll 171 return -1;
322 // reuse that memory to receive the output of deflate. 172 }
323 unsigned char* temp_data = expanded_source; 173
324 ssize_t temp_size = expanded_len; 174 // Now compress the target data and append it to the output.
325 if (temp_size < 32768) { 175
326 // ... unless the buffer is too small, in which case we'll 176 // we're done with the expanded_source data buffer, so we'll
327 // allocate a fresh one. 177 // reuse that memory to receive the output of deflate.
328 free(temp_data); 178 unsigned char* temp_data = expanded_source;
329 temp_data = malloc(32768); 179 ssize_t temp_size = expanded_len;
330 temp_size = 32768; 180 if (temp_size < 32768) {
331 } 181 // ... unless the buffer is too small, in which case we'll
332 182 // allocate a fresh one.
333 // now the deflate stream 183 free(temp_data);
334 strm.zalloc = Z_NULL; 184 temp_data = malloc(32768);
335 strm.zfree = Z_NULL; 185 temp_size = 32768;
336 strm.opaque = Z_NULL; 186 }
337 strm.avail_in = uncompressed_target_size; 187
338 strm.next_in = uncompressed_target_data; 188 // now the deflate stream
339 ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy); 189 strm.zalloc = Z_NULL;
340 do { 190 strm.zfree = Z_NULL;
341 strm.avail_out = temp_size; 191 strm.opaque = Z_NULL;
342 strm.next_out = temp_data; 192 strm.avail_in = uncompressed_target_size;
343 ret = deflate(&strm, Z_FINISH); 193 strm.next_in = uncompressed_target_data;
344 size_t have = temp_size - strm.avail_out; 194 ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy);
345 195 do {
346 if (sink(temp_data, have, token) != have) { 196 strm.avail_out = temp_size;
347 printf("failed to write %d compressed bytes to output\n", 197 strm.next_out = temp_data;
348 have); 198 ret = deflate(&strm, Z_FINISH);
349 return -1; 199 ssize_t have = temp_size - strm.avail_out;
200
201 if (sink(temp_data, have, token) != have) {
202 printf("failed to write %ld compressed bytes to output\n",
203 (long)have);
204 return -1;
205 }
206 SHA_update(ctx, temp_data, have);
207 } while (ret != Z_STREAM_END);
208 deflateEnd(&strm);
209
210 free(temp_data);
211 free(uncompressed_target_data);
212 } else {
213 printf("patch chunk %d is unknown type %d\n", i, type);
214 return -1;
350 } 215 }
351 SHA_update(ctx, temp_data, have);
352 } while (ret != Z_STREAM_END);
353 deflateEnd(&strm);
354
355 free(temp_data);
356 free(uncompressed_target_data);
357 } else {
358 printf("patch chunk %d is unknown type %d\n", i, type);
359 return -1;
360 } 216 }
361 }
362 217
363 return 0; 218 return 0;
364} 219}
diff --git a/applypatch/main.c b/applypatch/main.c
index e08f5c1e..3917f86e 100644
--- a/applypatch/main.c
+++ b/applypatch/main.c
@@ -15,8 +15,126 @@
15 */ 15 */
16 16
17#include <stdio.h> 17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
18 21
19extern int applypatch(int argc, char** argv); 22#include "applypatch.h"
23#include "edify/expr.h"
24#include "mincrypt/sha.h"
25
26int CheckMode(int argc, char** argv) {
27 if (argc < 3) {
28 return 2;
29 }
30 return applypatch_check(argv[2], argc-3, argv+3);
31}
32
33int SpaceMode(int argc, char** argv) {
34 if (argc != 3) {
35 return 2;
36 }
37 char* endptr;
38 size_t bytes = strtol(argv[2], &endptr, 10);
39 if (bytes == 0 && endptr == argv[2]) {
40 printf("can't parse \"%s\" as byte count\n\n", argv[2]);
41 return 1;
42 }
43 return CacheSizeCheck(bytes);
44}
45
46// Parse arguments (which should be of the form "<sha1>" or
47// "<sha1>:<filename>" into the new parallel arrays *sha1s and
48// *patches (loading file contents into the patches). Returns 0 on
49// success.
50static int ParsePatchArgs(int argc, char** argv,
51 char*** sha1s, Value*** patches, int* num_patches) {
52 *num_patches = argc;
53 *sha1s = malloc(*num_patches * sizeof(char*));
54 *patches = malloc(*num_patches * sizeof(Value*));
55 memset(*patches, 0, *num_patches * sizeof(Value*));
56
57 uint8_t digest[SHA_DIGEST_SIZE];
58
59 int i;
60 for (i = 0; i < *num_patches; ++i) {
61 char* colon = strchr(argv[i], ':');
62 if (colon != NULL) {
63 *colon = '\0';
64 ++colon;
65 }
66
67 if (ParseSha1(argv[i], digest) != 0) {
68 printf("failed to parse sha1 \"%s\"\n", argv[i]);
69 return -1;
70 }
71
72 (*sha1s)[i] = argv[i];
73 if (colon == NULL) {
74 (*patches)[i] = NULL;
75 } else {
76 FileContents fc;
77 if (LoadFileContents(colon, &fc) != 0) {
78 goto abort;
79 }
80 (*patches)[i] = malloc(sizeof(Value));
81 (*patches)[i]->type = VAL_BLOB;
82 (*patches)[i]->size = fc.size;
83 (*patches)[i]->data = (char*)fc.data;
84 }
85 }
86
87 return 0;
88
89 abort:
90 for (i = 0; i < *num_patches; ++i) {
91 Value* p = (*patches)[i];
92 if (p != NULL) {
93 free(p->data);
94 free(p);
95 }
96 }
97 free(*sha1s);
98 free(*patches);
99 return -1;
100}
101
102int PatchMode(int argc, char** argv) {
103 if (argc < 6) {
104 return 2;
105 }
106
107 char* endptr;
108 size_t target_size = strtol(argv[4], &endptr, 10);
109 if (target_size == 0 && endptr == argv[4]) {
110 printf("can't parse \"%s\" as byte count\n\n", argv[4]);
111 return 1;
112 }
113
114 char** sha1s;
115 Value** patches;
116 int num_patches;
117 if (ParsePatchArgs(argc-5, argv+5, &sha1s, &patches, &num_patches) != 0) {
118 printf("failed to parse patch args\n");
119 return 1;
120 }
121
122 int result = applypatch(argv[1], argv[2], argv[3], target_size,
123 num_patches, sha1s, patches);
124
125 int i;
126 for (i = 0; i < num_patches; ++i) {
127 Value* p = patches[i];
128 if (p != NULL) {
129 free(p->data);
130 free(p);
131 }
132 }
133 free(sha1s);
134 free(patches);
135
136 return result;
137}
20 138
21// This program applies binary patches to files in a way that is safe 139// This program applies binary patches to files in a way that is safe
22// (the original file is not touched until we have the desired 140// (the original file is not touched until we have the desired
@@ -42,9 +160,9 @@ extern int applypatch(int argc, char** argv);
42// LoadMTDContents() function above for the format of such a filename. 160// LoadMTDContents() function above for the format of such a filename.
43 161
44int main(int argc, char** argv) { 162int main(int argc, char** argv) {
45 int result = applypatch(argc, argv); 163 if (argc < 2) {
46 if (result == 2) { 164 usage:
47 printf( 165 printf(
48 "usage: %s <src-file> <tgt-file> <tgt-sha1> <tgt-size> " 166 "usage: %s <src-file> <tgt-file> <tgt-sha1> <tgt-size> "
49 "[<src-sha1>:<patch> ...]\n" 167 "[<src-sha1>:<patch> ...]\n"
50 " or %s -c <file> [<sha1> ...]\n" 168 " or %s -c <file> [<sha1> ...]\n"
@@ -55,6 +173,23 @@ int main(int argc, char** argv) {
55 " MTD:<partition>:<len_1>:<sha1_1>:<len_2>:<sha1_2>:...\n" 173 " MTD:<partition>:<len_1>:<sha1_1>:<len_2>:<sha1_2>:...\n"
56 "to specify reading from or writing to an MTD partition.\n\n", 174 "to specify reading from or writing to an MTD partition.\n\n",
57 argv[0], argv[0], argv[0], argv[0]); 175 argv[0], argv[0], argv[0], argv[0]);
58 } 176 return 2;
59 return result; 177 }
178
179 int result;
180
181 if (strncmp(argv[1], "-l", 3) == 0) {
182 result = ShowLicenses();
183 } else if (strncmp(argv[1], "-c", 3) == 0) {
184 result = CheckMode(argc, argv);
185 } else if (strncmp(argv[1], "-s", 3) == 0) {
186 result = SpaceMode(argc, argv);
187 } else {
188 result = PatchMode(argc, argv);
189 }
190
191 if (result == 2) {
192 goto usage;
193 }
194 return result;
60} 195}
diff --git a/applypatch/utils.c b/applypatch/utils.c
index 912229bc..41ff676d 100644
--- a/applypatch/utils.c
+++ b/applypatch/utils.c
@@ -38,25 +38,28 @@ void Write8(long long value, FILE* f) {
38 fputc((value >> 56) & 0xff, f); 38 fputc((value >> 56) & 0xff, f);
39} 39}
40 40
41int Read2(unsigned char* p) { 41int Read2(void* pv) {
42 return (int)(((unsigned int)p[1] << 8) | 42 unsigned char* p = pv;
43 (unsigned int)p[0]); 43 return (int)(((unsigned int)p[1] << 8) |
44 (unsigned int)p[0]);
44} 45}
45 46
46int Read4(unsigned char* p) { 47int Read4(void* pv) {
47 return (int)(((unsigned int)p[3] << 24) | 48 unsigned char* p = pv;
48 ((unsigned int)p[2] << 16) | 49 return (int)(((unsigned int)p[3] << 24) |
49 ((unsigned int)p[1] << 8) | 50 ((unsigned int)p[2] << 16) |
50 (unsigned int)p[0]); 51 ((unsigned int)p[1] << 8) |
52 (unsigned int)p[0]);
51} 53}
52 54
53long long Read8(unsigned char* p) { 55long long Read8(void* pv) {
54 return (long long)(((unsigned long long)p[7] << 56) | 56 unsigned char* p = pv;
55 ((unsigned long long)p[6] << 48) | 57 return (long long)(((unsigned long long)p[7] << 56) |
56 ((unsigned long long)p[5] << 40) | 58 ((unsigned long long)p[6] << 48) |
57 ((unsigned long long)p[4] << 32) | 59 ((unsigned long long)p[5] << 40) |
58 ((unsigned long long)p[3] << 24) | 60 ((unsigned long long)p[4] << 32) |
59 ((unsigned long long)p[2] << 16) | 61 ((unsigned long long)p[3] << 24) |
60 ((unsigned long long)p[1] << 8) | 62 ((unsigned long long)p[2] << 16) |
61 (unsigned long long)p[0]); 63 ((unsigned long long)p[1] << 8) |
64 (unsigned long long)p[0]);
62} 65}
diff --git a/applypatch/utils.h b/applypatch/utils.h
index d6d6f1d3..bc97f172 100644
--- a/applypatch/utils.h
+++ b/applypatch/utils.h
@@ -23,8 +23,8 @@
23 23
24void Write4(int value, FILE* f); 24void Write4(int value, FILE* f);
25void Write8(long long value, FILE* f); 25void Write8(long long value, FILE* f);
26int Read2(unsigned char* p); 26int Read2(void* p);
27int Read4(unsigned char* p); 27int Read4(void* p);
28long long Read8(unsigned char* p); 28long long Read8(void* p);
29 29
30#endif // _BUILD_TOOLS_APPLYPATCH_UTILS_H 30#endif // _BUILD_TOOLS_APPLYPATCH_UTILS_H
diff --git a/edify/main.c b/edify/main.c
index a2b74ad9..85570438 100644
--- a/edify/main.c
+++ b/edify/main.c
@@ -42,11 +42,12 @@ int expect(const char* expr_str, const char* expected, int* errors) {
42 42
43 State state; 43 State state;
44 state.cookie = NULL; 44 state.cookie = NULL;
45 state.script = expr_str; 45 state.script = strdup(expr_str);
46 state.errmsg = NULL; 46 state.errmsg = NULL;
47 47
48 result = Evaluate(&state, e); 48 result = Evaluate(&state, e);
49 free(state.errmsg); 49 free(state.errmsg);
50 free(state.script);
50 if (result == NULL && expected != NULL) { 51 if (result == NULL && expected != NULL) {
51 fprintf(stderr, "error evaluating \"%s\"\n", expr_str); 52 fprintf(stderr, "error evaluating \"%s\"\n", expr_str);
52 ++*errors; 53 ++*errors;
diff --git a/edify/yydefs.h b/edify/yydefs.h
index 62578625..aca398fb 100644
--- a/edify/yydefs.h
+++ b/edify/yydefs.h
@@ -33,4 +33,6 @@ typedef struct {
33 } \ 33 } \
34 } while (0) 34 } while (0)
35 35
36int yylex();
37
36#endif 38#endif
diff --git a/updater/install.c b/updater/install.c
index 2ffb3842..e869134b 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -705,52 +705,124 @@ done:
705 return StringValue(result); 705 return StringValue(result);
706} 706}
707 707
708// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...)
709// apply_patch_check(file, sha1, ...)
710// apply_patch_space(bytes) 708// apply_patch_space(bytes)
711Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { 709Value* ApplyPatchSpaceFn(const char* name, State* state,
712 printf("in applypatchfn (%s)\n", name); 710 int argc, Expr* argv[]) {
711 char* bytes_str;
712 if (ReadArgs(state, argv, 1, &bytes_str) < 0) {
713 return NULL;
714 }
713 715
714 char* prepend = NULL; 716 char* endptr;
715 if (strstr(name, "check") != NULL) { 717 size_t bytes = strtol(bytes_str, &endptr, 10);
716 prepend = "-c"; 718 if (bytes == 0 && endptr == bytes_str) {
717 } else if (strstr(name, "space") != NULL) { 719 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
718 prepend = "-s"; 720 name, bytes_str);
721 free(bytes_str);
722 return NULL;
719 } 723 }
720 724
721 char** args = ReadVarArgs(state, argc, argv); 725 return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
722 if (args == NULL) return NULL; 726}
723 727
724 // insert the "program name" argv[0] and a copy of the "prepend"
725 // string (if any) at the start of the args.
726 728
727 int extra = 1 + (prepend != NULL ? 1 : 0); 729// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
728 char** temp = malloc((argc+extra) * sizeof(char*)); 730Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
729 memcpy(temp+extra, args, argc * sizeof(char*)); 731 if (argc < 6 || (argc % 2) == 1) {
730 temp[0] = strdup("updater"); 732 return ErrorAbort(state, "%s(): expected at least 6 args and an "
731 if (prepend) { 733 "even number, got %d",
732 temp[1] = strdup(prepend); 734 name, argc);
735 }
736
737 char* source_filename;
738 char* target_filename;
739 char* target_sha1;
740 char* target_size_str;
741 if (ReadArgs(state, argv, 4, &source_filename, &target_filename,
742 &target_sha1, &target_size_str) < 0) {
743 return NULL;
733 } 744 }
734 free(args);
735 args = temp;
736 argc += extra;
737 745
738 printf("calling applypatch\n"); 746 char* endptr;
739 fflush(stdout); 747 size_t target_size = strtol(target_size_str, &endptr, 10);
740 int result = applypatch(argc, args); 748 if (target_size == 0 && endptr == target_size_str) {
741 printf("applypatch returned %d\n", result); 749 ErrorAbort(state, "%s(): can't parse \"%s\" as byte count",
750 name, target_size_str);
751 free(source_filename);
752 free(target_filename);
753 free(target_sha1);
754 free(target_size_str);
755 return NULL;
756 }
757
758 int patchcount = (argc-4) / 2;
759 Value** patches = ReadValueVarArgs(state, argc-4, argv+4);
742 760
743 int i; 761 int i;
744 for (i = 0; i < argc; ++i) { 762 for (i = 0; i < patchcount; ++i) {
745 free(args[i]); 763 if (patches[i*2]->type != VAL_STRING) {
764 ErrorAbort(state, "%s(): sha-1 #%d is not string", name, i);
765 break;
766 }
767 if (patches[i*2+1]->type != VAL_BLOB) {
768 ErrorAbort(state, "%s(): patch #%d is not blob", name, i);
769 break;
770 }
771 }
772 if (i != patchcount) {
773 for (i = 0; i < patchcount*2; ++i) {
774 FreeValue(patches[i]);
775 }
776 free(patches);
777 return NULL;
746 } 778 }
747 free(args);
748 779
749 switch (result) { 780 char** patch_sha_str = malloc(patchcount * sizeof(char*));
750 case 0: return StringValue(strdup("t")); 781 for (i = 0; i < patchcount; ++i) {
751 case 1: return StringValue(strdup("")); 782 patch_sha_str[i] = patches[i*2]->data;
752 default: return ErrorAbort(state, "applypatch couldn't parse args"); 783 patches[i*2]->data = NULL;
784 FreeValue(patches[i*2]);
785 patches[i] = patches[i*2+1];
753 } 786 }
787
788 int result = applypatch(source_filename, target_filename,
789 target_sha1, target_size,
790 patchcount, patch_sha_str, patches);
791
792 for (i = 0; i < patchcount; ++i) {
793 FreeValue(patches[i]);
794 }
795 free(patch_sha_str);
796 free(patches);
797
798 return StringValue(strdup(result == 0 ? "t" : ""));
799}
800
801// apply_patch_check(file, [sha1_1, ...])
802Value* ApplyPatchCheckFn(const char* name, State* state,
803 int argc, Expr* argv[]) {
804 if (argc < 1) {
805 return ErrorAbort(state, "%s(): expected at least 1 arg, got %d",
806 name, argc);
807 }
808
809 char* filename;
810 if (ReadArgs(state, argv, 1, &filename) < 0) {
811 return NULL;
812 }
813
814 int patchcount = argc-1;
815 char** sha1s = ReadVarArgs(state, argc-1, argv+1);
816
817 int result = applypatch_check(filename, patchcount, sha1s);
818
819 int i;
820 for (i = 0; i < patchcount; ++i) {
821 free(sha1s[i]);
822 }
823 free(sha1s);
824
825 return StringValue(strdup(result == 0 ? "t" : ""));
754} 826}
755 827
756Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { 828Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) {
@@ -831,36 +903,6 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
831 return StringValue(strdup(buffer)); 903 return StringValue(strdup(buffer));
832} 904}
833 905
834// Take a string 'str' of 40 hex digits and parse it into the 20
835// byte array 'digest'. 'str' may contain only the digest or be of
836// the form "<digest>:<anything>". Return 0 on success, -1 on any
837// error.
838static int ParseSha1(const char* str, uint8_t* digest) {
839 int i;
840 const char* ps = str;
841 uint8_t* pd = digest;
842 for (i = 0; i < SHA_DIGEST_SIZE * 2; ++i, ++ps) {
843 int digit;
844 if (*ps >= '0' && *ps <= '9') {
845 digit = *ps - '0';
846 } else if (*ps >= 'a' && *ps <= 'f') {
847 digit = *ps - 'a' + 10;
848 } else if (*ps >= 'A' && *ps <= 'F') {
849 digit = *ps - 'A' + 10;
850 } else {
851 return -1;
852 }
853 if (i % 2 == 0) {
854 *pd = digit << 4;
855 } else {
856 *pd |= digit;
857 ++pd;
858 }
859 }
860 if (*ps != '\0') return -1;
861 return 0;
862}
863
864// Take a sha-1 digest and return it as a newly-allocated hex string. 906// Take a sha-1 digest and return it as a newly-allocated hex string.
865static char* PrintSha1(uint8_t* digest) { 907static char* PrintSha1(uint8_t* digest) {
866 char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1); 908 char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
@@ -981,8 +1023,8 @@ void RegisterInstallFunctions() {
981 RegisterFunction("write_raw_image", WriteRawImageFn); 1023 RegisterFunction("write_raw_image", WriteRawImageFn);
982 1024
983 RegisterFunction("apply_patch", ApplyPatchFn); 1025 RegisterFunction("apply_patch", ApplyPatchFn);
984 RegisterFunction("apply_patch_check", ApplyPatchFn); 1026 RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
985 RegisterFunction("apply_patch_space", ApplyPatchFn); 1027 RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
986 1028
987 RegisterFunction("read_file", ReadFileFn); 1029 RegisterFunction("read_file", ReadFileFn);
988 RegisterFunction("sha1_check", Sha1CheckFn); 1030 RegisterFunction("sha1_check", Sha1CheckFn);