1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  * This program constructs binary patches for images -- such as boot.img
19  * and recovery.img -- that consist primarily of large chunks of gzipped
20  * data interspersed with uncompressed data.  Doing a naive bsdiff of
21  * these files is not useful because small changes in the data lead to
22  * large changes in the compressed bitstream; bsdiff patches of gzipped
23  * data are typically as large as the data itself.
24  *
25  * To patch these usefully, we break the source and target images up into
26  * chunks of two types: "normal" and "gzip".  Normal chunks are simply
27  * patched using a plain bsdiff.  Gzip chunks are first expanded, then a
28  * bsdiff is applied to the uncompressed data, then the patched data is
29  * gzipped using the same encoder parameters.  Patched chunks are
30  * concatenated together to create the output file; the output image
31  * should be *exactly* the same series of bytes as the target image used
32  * originally to generate the patch.
33  *
34  * To work well with this tool, the gzipped sections of the target
35  * image must have been generated using the same deflate encoder that
36  * is available in applypatch, namely, the one in the zlib library.
37  * In practice this means that images should be compressed using the
38  * "minigzip" tool included in the zlib distribution, not the GNU gzip
39  * program.
40  *
41  * An "imgdiff" patch consists of a header describing the chunk structure
42  * of the file and any encoding parameters needed for the gzipped
43  * chunks, followed by N bsdiff patches, one per chunk.
44  *
45  * For a diff to be generated, the source and target images must have the
46  * same "chunk" structure: that is, the same number of gzipped and normal
47  * chunks in the same order.  Android boot and recovery images currently
48  * consist of five chunks:  a small normal header, a gzipped kernel, a
49  * small normal section, a gzipped ramdisk, and finally a small normal
50  * footer.
51  *
52  * Caveats:  we locate gzipped sections within the source and target
53  * images by searching for the byte sequence 1f8b0800:  1f8b is the gzip
54  * magic number; 08 specifies the "deflate" encoding [the only encoding
55  * supported by the gzip standard]; and 00 is the flags byte.  We do not
56  * currently support any extra header fields (which would be indicated by
57  * a nonzero flags byte).  We also don't handle the case when that byte
58  * sequence appears spuriously in the file.  (Note that it would have to
59  * occur spuriously within a normal chunk to be a problem.)
60  *
61  *
62  * The imgdiff patch header looks like this:
63  *
64  *    "IMGDIFF1"                  (8)   [magic number and version]
65  *    chunk count                 (4)
66  *    for each chunk:
67  *        chunk type              (4)   [CHUNK_{NORMAL, GZIP, DEFLATE, RAW}]
68  *        if chunk type == CHUNK_NORMAL:
69  *           source start         (8)
70  *           source len           (8)
71  *           bsdiff patch offset  (8)   [from start of patch file]
72  *        if chunk type == CHUNK_GZIP:      (version 1 only)
73  *           source start         (8)
74  *           source len           (8)
75  *           bsdiff patch offset  (8)   [from start of patch file]
76  *           source expanded len  (8)   [size of uncompressed source]
77  *           target expected len  (8)   [size of uncompressed target]
78  *           gzip level           (4)
79  *                method          (4)
80  *                windowBits      (4)
81  *                memLevel        (4)
82  *                strategy        (4)
83  *           gzip header len      (4)
84  *           gzip header          (gzip header len)
85  *           gzip footer          (8)
86  *        if chunk type == CHUNK_DEFLATE:   (version 2 only)
87  *           source start         (8)
88  *           source len           (8)
89  *           bsdiff patch offset  (8)   [from start of patch file]
90  *           source expanded len  (8)   [size of uncompressed source]
91  *           target expected len  (8)   [size of uncompressed target]
92  *           gzip level           (4)
93  *                method          (4)
94  *                windowBits      (4)
95  *                memLevel        (4)
96  *                strategy        (4)
97  *        if chunk type == RAW:             (version 2 only)
98  *           target len           (4)
99  *           data                 (target len)
100  *
101  * All integers are little-endian.  "source start" and "source len"
102  * specify the section of the input image that comprises this chunk,
103  * including the gzip header and footer for gzip chunks.  "source
104  * expanded len" is the size of the uncompressed source data.  "target
105  * expected len" is the size of the uncompressed data after applying
106  * the bsdiff patch.  The next five parameters specify the zlib
107  * parameters to be used when compressing the patched data, and the
108  * next three specify the header and footer to be wrapped around the
109  * compressed data to create the output chunk (so that header contents
110  * like the timestamp are recreated exactly).
111  *
112  * After the header there are 'chunk count' bsdiff patches; the offset
113  * of each from the beginning of the file is specified in the header.
114  *
115  * This tool can take an optional file of "bonus data".  This is an
116  * extra file of data that is appended to chunk #1 after it is
117  * compressed (it must be a CHUNK_DEFLATE chunk).  The same file must
118  * be available (and passed to applypatch with -b) when applying the
119  * patch.  This is used to reduce the size of recovery-from-boot
120  * patches by combining the boot image with recovery ramdisk
121  * information that is stored on the system partition.
122  */
123 
124 #include <errno.h>
125 #include <stdio.h>
126 #include <stdlib.h>
127 #include <string.h>
128 #include <sys/stat.h>
129 #include <unistd.h>
130 #include <sys/types.h>
131 
132 #include "zlib.h"
133 #include "imgdiff.h"
134 #include "utils.h"
135 
136 typedef struct {
137   int type;             // CHUNK_NORMAL, CHUNK_DEFLATE
138   size_t start;         // offset of chunk in original image file
139 
140   size_t len;
141   unsigned char* data;  // data to be patched (uncompressed, for deflate chunks)
142 
143   size_t source_start;
144   size_t source_len;
145 
146   off_t* I;             // used by bsdiff
147 
148   // --- for CHUNK_DEFLATE chunks only: ---
149 
150   // original (compressed) deflate data
151   size_t deflate_len;
152   unsigned char* deflate_data;
153 
154   char* filename;       // used for zip entries
155 
156   // deflate encoder parameters
157   int level, method, windowBits, memLevel, strategy;
158 
159   size_t source_uncompressed_len;
160 } ImageChunk;
161 
162 typedef struct {
163   int data_offset;
164   int deflate_len;
165   int uncomp_len;
166   char* filename;
167 } ZipFileEntry;
168 
fileentry_compare(const void * a,const void * b)169 static int fileentry_compare(const void* a, const void* b) {
170   int ao = ((ZipFileEntry*)a)->data_offset;
171   int bo = ((ZipFileEntry*)b)->data_offset;
172   if (ao < bo) {
173     return -1;
174   } else if (ao > bo) {
175     return 1;
176   } else {
177     return 0;
178   }
179 }
180 
181 // from bsdiff.c
182 int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* new, off_t newsize,
183            const char* patch_filename);
184 
ReadZip(const char * filename,int * num_chunks,ImageChunk ** chunks,int include_pseudo_chunk)185 unsigned char* ReadZip(const char* filename,
186                        int* num_chunks, ImageChunk** chunks,
187                        int include_pseudo_chunk) {
188   struct stat st;
189   if (stat(filename, &st) != 0) {
190     printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
191     return NULL;
192   }
193 
194   unsigned char* img = malloc(st.st_size);
195   FILE* f = fopen(filename, "rb");
196   if (fread(img, 1, st.st_size, f) != st.st_size) {
197     printf("failed to read \"%s\" %s\n", filename, strerror(errno));
198     fclose(f);
199     return NULL;
200   }
201   fclose(f);
202 
203   // look for the end-of-central-directory record.
204 
205   int i;
206   for (i = st.st_size-20; i >= 0 && i > st.st_size - 65600; --i) {
207     if (img[i] == 0x50 && img[i+1] == 0x4b &&
208         img[i+2] == 0x05 && img[i+3] == 0x06) {
209       break;
210     }
211   }
212   // double-check: this archive consists of a single "disk"
213   if (!(img[i+4] == 0 && img[i+5] == 0 && img[i+6] == 0 && img[i+7] == 0)) {
214     printf("can't process multi-disk archive\n");
215     return NULL;
216   }
217 
218   int cdcount = Read2(img+i+8);
219   int cdoffset = Read4(img+i+16);
220 
221   ZipFileEntry* temp_entries = malloc(cdcount * sizeof(ZipFileEntry));
222   int entrycount = 0;
223 
224   unsigned char* cd = img+cdoffset;
225   for (i = 0; i < cdcount; ++i) {
226     if (!(cd[0] == 0x50 && cd[1] == 0x4b && cd[2] == 0x01 && cd[3] == 0x02)) {
227       printf("bad central directory entry %d\n", i);
228       return NULL;
229     }
230 
231     int clen = Read4(cd+20);   // compressed len
232     int ulen = Read4(cd+24);   // uncompressed len
233     int nlen = Read2(cd+28);   // filename len
234     int xlen = Read2(cd+30);   // extra field len
235     int mlen = Read2(cd+32);   // file comment len
236     int hoffset = Read4(cd+42);   // local header offset
237 
238     char* filename = malloc(nlen+1);
239     memcpy(filename, cd+46, nlen);
240     filename[nlen] = '\0';
241 
242     int method = Read2(cd+10);
243 
244     cd += 46 + nlen + xlen + mlen;
245 
246     if (method != 8) {  // 8 == deflate
247       free(filename);
248       continue;
249     }
250 
251     unsigned char* lh = img + hoffset;
252 
253     if (!(lh[0] == 0x50 && lh[1] == 0x4b && lh[2] == 0x03 && lh[3] == 0x04)) {
254       printf("bad local file header entry %d\n", i);
255       return NULL;
256     }
257 
258     if (Read2(lh+26) != nlen || memcmp(lh+30, filename, nlen) != 0) {
259       printf("central dir filename doesn't match local header\n");
260       return NULL;
261     }
262 
263     xlen = Read2(lh+28);   // extra field len; might be different from CD entry?
264 
265     temp_entries[entrycount].data_offset = hoffset+30+nlen+xlen;
266     temp_entries[entrycount].deflate_len = clen;
267     temp_entries[entrycount].uncomp_len = ulen;
268     temp_entries[entrycount].filename = filename;
269     ++entrycount;
270   }
271 
272   qsort(temp_entries, entrycount, sizeof(ZipFileEntry), fileentry_compare);
273 
274 #if 0
275   printf("found %d deflated entries\n", entrycount);
276   for (i = 0; i < entrycount; ++i) {
277     printf("off %10d  len %10d unlen %10d   %p %s\n",
278            temp_entries[i].data_offset,
279            temp_entries[i].deflate_len,
280            temp_entries[i].uncomp_len,
281            temp_entries[i].filename,
282            temp_entries[i].filename);
283   }
284 #endif
285 
286   *num_chunks = 0;
287   *chunks = malloc((entrycount*2+2) * sizeof(ImageChunk));
288   ImageChunk* curr = *chunks;
289 
290   if (include_pseudo_chunk) {
291     curr->type = CHUNK_NORMAL;
292     curr->start = 0;
293     curr->len = st.st_size;
294     curr->data = img;
295     curr->filename = NULL;
296     curr->I = NULL;
297     ++curr;
298     ++*num_chunks;
299   }
300 
301   int pos = 0;
302   int nextentry = 0;
303 
304   while (pos < st.st_size) {
305     if (nextentry < entrycount && pos == temp_entries[nextentry].data_offset) {
306       curr->type = CHUNK_DEFLATE;
307       curr->start = pos;
308       curr->deflate_len = temp_entries[nextentry].deflate_len;
309       curr->deflate_data = img + pos;
310       curr->filename = temp_entries[nextentry].filename;
311       curr->I = NULL;
312 
313       curr->len = temp_entries[nextentry].uncomp_len;
314       curr->data = malloc(curr->len);
315 
316       z_stream strm;
317       strm.zalloc = Z_NULL;
318       strm.zfree = Z_NULL;
319       strm.opaque = Z_NULL;
320       strm.avail_in = curr->deflate_len;
321       strm.next_in = curr->deflate_data;
322 
323       // -15 means we are decoding a 'raw' deflate stream; zlib will
324       // not expect zlib headers.
325       int ret = inflateInit2(&strm, -15);
326 
327       strm.avail_out = curr->len;
328       strm.next_out = curr->data;
329       ret = inflate(&strm, Z_NO_FLUSH);
330       if (ret != Z_STREAM_END) {
331         printf("failed to inflate \"%s\"; %d\n", curr->filename, ret);
332         return NULL;
333       }
334 
335       inflateEnd(&strm);
336 
337       pos += curr->deflate_len;
338       ++nextentry;
339       ++*num_chunks;
340       ++curr;
341       continue;
342     }
343 
344     // use a normal chunk to take all the data up to the start of the
345     // next deflate section.
346 
347     curr->type = CHUNK_NORMAL;
348     curr->start = pos;
349     if (nextentry < entrycount) {
350       curr->len = temp_entries[nextentry].data_offset - pos;
351     } else {
352       curr->len = st.st_size - pos;
353     }
354     curr->data = img + pos;
355     curr->filename = NULL;
356     curr->I = NULL;
357     pos += curr->len;
358 
359     ++*num_chunks;
360     ++curr;
361   }
362 
363   free(temp_entries);
364   return img;
365 }
366 
367 /*
368  * Read the given file and break it up into chunks, putting the number
369  * of chunks and their info in *num_chunks and **chunks,
370  * respectively.  Returns a malloc'd block of memory containing the
371  * contents of the file; various pointers in the output chunk array
372  * will point into this block of memory.  The caller should free the
373  * return value when done with all the chunks.  Returns NULL on
374  * failure.
375  */
ReadImage(const char * filename,int * num_chunks,ImageChunk ** chunks)376 unsigned char* ReadImage(const char* filename,
377                          int* num_chunks, ImageChunk** chunks) {
378   struct stat st;
379   if (stat(filename, &st) != 0) {
380     printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
381     return NULL;
382   }
383 
384   unsigned char* img = malloc(st.st_size + 4);
385   FILE* f = fopen(filename, "rb");
386   if (fread(img, 1, st.st_size, f) != st.st_size) {
387     printf("failed to read \"%s\" %s\n", filename, strerror(errno));
388     fclose(f);
389     return NULL;
390   }
391   fclose(f);
392 
393   // append 4 zero bytes to the data so we can always search for the
394   // four-byte string 1f8b0800 starting at any point in the actual
395   // file data, without special-casing the end of the data.
396   memset(img+st.st_size, 0, 4);
397 
398   size_t pos = 0;
399 
400   *num_chunks = 0;
401   *chunks = NULL;
402 
403   while (pos < st.st_size) {
404     unsigned char* p = img+pos;
405 
406     if (st.st_size - pos >= 4 &&
407         p[0] == 0x1f && p[1] == 0x8b &&
408         p[2] == 0x08 &&    // deflate compression
409         p[3] == 0x00) {    // no header flags
410       // 'pos' is the offset of the start of a gzip chunk.
411       size_t chunk_offset = pos;
412 
413       *num_chunks += 3;
414       *chunks = realloc(*chunks, *num_chunks * sizeof(ImageChunk));
415       ImageChunk* curr = *chunks + (*num_chunks-3);
416 
417       // create a normal chunk for the header.
418       curr->start = pos;
419       curr->type = CHUNK_NORMAL;
420       curr->len = GZIP_HEADER_LEN;
421       curr->data = p;
422       curr->I = NULL;
423 
424       pos += curr->len;
425       p += curr->len;
426       ++curr;
427 
428       curr->type = CHUNK_DEFLATE;
429       curr->filename = NULL;
430       curr->I = NULL;
431 
432       // We must decompress this chunk in order to discover where it
433       // ends, and so we can put the uncompressed data and its length
434       // into curr->data and curr->len.
435 
436       size_t allocated = 32768;
437       curr->len = 0;
438       curr->data = malloc(allocated);
439       curr->start = pos;
440       curr->deflate_data = p;
441 
442       z_stream strm;
443       strm.zalloc = Z_NULL;
444       strm.zfree = Z_NULL;
445       strm.opaque = Z_NULL;
446       strm.avail_in = st.st_size - pos;
447       strm.next_in = p;
448 
449       // -15 means we are decoding a 'raw' deflate stream; zlib will
450       // not expect zlib headers.
451       int ret = inflateInit2(&strm, -15);
452 
453       do {
454         strm.avail_out = allocated - curr->len;
455         strm.next_out = curr->data + curr->len;
456         ret = inflate(&strm, Z_NO_FLUSH);
457         if (ret < 0) {
458             printf("Error: inflate failed [%s] at file offset [%zu]\n"
459                     "imgdiff only supports gzip kernel compression,"
460                     " did you try CONFIG_KERNEL_LZO?\n",
461                     strm.msg, chunk_offset);
462             free(img);
463             return NULL;
464         }
465         curr->len = allocated - strm.avail_out;
466         if (strm.avail_out == 0) {
467           allocated *= 2;
468           curr->data = realloc(curr->data, allocated);
469         }
470       } while (ret != Z_STREAM_END);
471 
472       curr->deflate_len = st.st_size - strm.avail_in - pos;
473       inflateEnd(&strm);
474       pos += curr->deflate_len;
475       p += curr->deflate_len;
476       ++curr;
477 
478       // create a normal chunk for the footer
479 
480       curr->type = CHUNK_NORMAL;
481       curr->start = pos;
482       curr->len = GZIP_FOOTER_LEN;
483       curr->data = img+pos;
484       curr->I = NULL;
485 
486       pos += curr->len;
487       p += curr->len;
488       ++curr;
489 
490       // The footer (that we just skipped over) contains the size of
491       // the uncompressed data.  Double-check to make sure that it
492       // matches the size of the data we got when we actually did
493       // the decompression.
494       size_t footer_size = Read4(p-4);
495       if (footer_size != curr[-2].len) {
496         printf("Error: footer size %d != decompressed size %d\n",
497                 footer_size, curr[-2].len);
498         free(img);
499         return NULL;
500       }
501     } else {
502       // Reallocate the list for every chunk; we expect the number of
503       // chunks to be small (5 for typical boot and recovery images).
504       ++*num_chunks;
505       *chunks = realloc(*chunks, *num_chunks * sizeof(ImageChunk));
506       ImageChunk* curr = *chunks + (*num_chunks-1);
507       curr->start = pos;
508       curr->I = NULL;
509 
510       // 'pos' is not the offset of the start of a gzip chunk, so scan
511       // forward until we find a gzip header.
512       curr->type = CHUNK_NORMAL;
513       curr->data = p;
514 
515       for (curr->len = 0; curr->len < (st.st_size - pos); ++curr->len) {
516         if (p[curr->len] == 0x1f &&
517             p[curr->len+1] == 0x8b &&
518             p[curr->len+2] == 0x08 &&
519             p[curr->len+3] == 0x00) {
520           break;
521         }
522       }
523       pos += curr->len;
524     }
525   }
526 
527   return img;
528 }
529 
530 #define BUFFER_SIZE 32768
531 
532 /*
533  * Takes the uncompressed data stored in the chunk, compresses it
534  * using the zlib parameters stored in the chunk, and checks that it
535  * matches exactly the compressed data we started with (also stored in
536  * the chunk).  Return 0 on success.
537  */
TryReconstruction(ImageChunk * chunk,unsigned char * out)538 int TryReconstruction(ImageChunk* chunk, unsigned char* out) {
539   size_t p = 0;
540 
541 #if 0
542   printf("trying %d %d %d %d %d\n",
543           chunk->level, chunk->method, chunk->windowBits,
544           chunk->memLevel, chunk->strategy);
545 #endif
546 
547   z_stream strm;
548   strm.zalloc = Z_NULL;
549   strm.zfree = Z_NULL;
550   strm.opaque = Z_NULL;
551   strm.avail_in = chunk->len;
552   strm.next_in = chunk->data;
553   int ret;
554   ret = deflateInit2(&strm, chunk->level, chunk->method, chunk->windowBits,
555                      chunk->memLevel, chunk->strategy);
556   do {
557     strm.avail_out = BUFFER_SIZE;
558     strm.next_out = out;
559     ret = deflate(&strm, Z_FINISH);
560     size_t have = BUFFER_SIZE - strm.avail_out;
561 
562     if (memcmp(out, chunk->deflate_data+p, have) != 0) {
563       // mismatch; data isn't the same.
564       deflateEnd(&strm);
565       return -1;
566     }
567     p += have;
568   } while (ret != Z_STREAM_END);
569   deflateEnd(&strm);
570   if (p != chunk->deflate_len) {
571     // mismatch; ran out of data before we should have.
572     return -1;
573   }
574   return 0;
575 }
576 
577 /*
578  * Verify that we can reproduce exactly the same compressed data that
579  * we started with.  Sets the level, method, windowBits, memLevel, and
580  * strategy fields in the chunk to the encoding parameters needed to
581  * produce the right output.  Returns 0 on success.
582  */
ReconstructDeflateChunk(ImageChunk * chunk)583 int ReconstructDeflateChunk(ImageChunk* chunk) {
584   if (chunk->type != CHUNK_DEFLATE) {
585     printf("attempt to reconstruct non-deflate chunk\n");
586     return -1;
587   }
588 
589   size_t p = 0;
590   unsigned char* out = malloc(BUFFER_SIZE);
591 
592   // We only check two combinations of encoder parameters:  level 6
593   // (the default) and level 9 (the maximum).
594   for (chunk->level = 6; chunk->level <= 9; chunk->level += 3) {
595     chunk->windowBits = -15;  // 32kb window; negative to indicate a raw stream.
596     chunk->memLevel = 8;      // the default value.
597     chunk->method = Z_DEFLATED;
598     chunk->strategy = Z_DEFAULT_STRATEGY;
599 
600     if (TryReconstruction(chunk, out) == 0) {
601       free(out);
602       return 0;
603     }
604   }
605 
606   free(out);
607   return -1;
608 }
609 
610 /*
611  * Given source and target chunks, compute a bsdiff patch between them
612  * by running bsdiff in a subprocess.  Return the patch data, placing
613  * its length in *size.  Return NULL on failure.  We expect the bsdiff
614  * program to be in the path.
615  */
MakePatch(ImageChunk * src,ImageChunk * tgt,size_t * size)616 unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) {
617   if (tgt->type == CHUNK_NORMAL) {
618     if (tgt->len <= 160) {
619       tgt->type = CHUNK_RAW;
620       *size = tgt->len;
621       return tgt->data;
622     }
623   }
624 
625   char ptemp[] = "/tmp/imgdiff-patch-XXXXXX";
626   mkstemp(ptemp);
627 
628   int r = bsdiff(src->data, src->len, &(src->I), tgt->data, tgt->len, ptemp);
629   if (r != 0) {
630     printf("bsdiff() failed: %d\n", r);
631     return NULL;
632   }
633 
634   struct stat st;
635   if (stat(ptemp, &st) != 0) {
636     printf("failed to stat patch file %s: %s\n",
637             ptemp, strerror(errno));
638     return NULL;
639   }
640 
641   unsigned char* data = malloc(st.st_size);
642 
643   if (tgt->type == CHUNK_NORMAL && tgt->len <= st.st_size) {
644     unlink(ptemp);
645 
646     tgt->type = CHUNK_RAW;
647     *size = tgt->len;
648     return tgt->data;
649   }
650 
651   *size = st.st_size;
652 
653   FILE* f = fopen(ptemp, "rb");
654   if (f == NULL) {
655     printf("failed to open patch %s: %s\n", ptemp, strerror(errno));
656     return NULL;
657   }
658   if (fread(data, 1, st.st_size, f) != st.st_size) {
659     printf("failed to read patch %s: %s\n", ptemp, strerror(errno));
660     return NULL;
661   }
662   fclose(f);
663 
664   unlink(ptemp);
665 
666   tgt->source_start = src->start;
667   switch (tgt->type) {
668     case CHUNK_NORMAL:
669       tgt->source_len = src->len;
670       break;
671     case CHUNK_DEFLATE:
672       tgt->source_len = src->deflate_len;
673       tgt->source_uncompressed_len = src->len;
674       break;
675   }
676 
677   return data;
678 }
679 
680 /*
681  * Cause a gzip chunk to be treated as a normal chunk (ie, as a blob
682  * of uninterpreted data).  The resulting patch will likely be about
683  * as big as the target file, but it lets us handle the case of images
684  * where some gzip chunks are reconstructible but others aren't (by
685  * treating the ones that aren't as normal chunks).
686  */
ChangeDeflateChunkToNormal(ImageChunk * ch)687 void ChangeDeflateChunkToNormal(ImageChunk* ch) {
688   if (ch->type != CHUNK_DEFLATE) return;
689   ch->type = CHUNK_NORMAL;
690   free(ch->data);
691   ch->data = ch->deflate_data;
692   ch->len = ch->deflate_len;
693 }
694 
695 /*
696  * Return true if the data in the chunk is identical (including the
697  * compressed representation, for gzip chunks).
698  */
AreChunksEqual(ImageChunk * a,ImageChunk * b)699 int AreChunksEqual(ImageChunk* a, ImageChunk* b) {
700     if (a->type != b->type) return 0;
701 
702     switch (a->type) {
703         case CHUNK_NORMAL:
704             return a->len == b->len && memcmp(a->data, b->data, a->len) == 0;
705 
706         case CHUNK_DEFLATE:
707             return a->deflate_len == b->deflate_len &&
708                 memcmp(a->deflate_data, b->deflate_data, a->deflate_len) == 0;
709 
710         default:
711             printf("unknown chunk type %d\n", a->type);
712             return 0;
713     }
714 }
715 
716 /*
717  * Look for runs of adjacent normal chunks and compress them down into
718  * a single chunk.  (Such runs can be produced when deflate chunks are
719  * changed to normal chunks.)
720  */
MergeAdjacentNormalChunks(ImageChunk * chunks,int * num_chunks)721 void MergeAdjacentNormalChunks(ImageChunk* chunks, int* num_chunks) {
722   int out = 0;
723   int in_start = 0, in_end;
724   while (in_start < *num_chunks) {
725     if (chunks[in_start].type != CHUNK_NORMAL) {
726       in_end = in_start+1;
727     } else {
728       // in_start is a normal chunk.  Look for a run of normal chunks
729       // that constitute a solid block of data (ie, each chunk begins
730       // where the previous one ended).
731       for (in_end = in_start+1;
732            in_end < *num_chunks && chunks[in_end].type == CHUNK_NORMAL &&
733              (chunks[in_end].start ==
734               chunks[in_end-1].start + chunks[in_end-1].len &&
735               chunks[in_end].data ==
736               chunks[in_end-1].data + chunks[in_end-1].len);
737            ++in_end);
738     }
739 
740     if (in_end == in_start+1) {
741 #if 0
742       printf("chunk %d is now %d\n", in_start, out);
743 #endif
744       if (out != in_start) {
745         memcpy(chunks+out, chunks+in_start, sizeof(ImageChunk));
746       }
747     } else {
748 #if 0
749       printf("collapse normal chunks %d-%d into %d\n", in_start, in_end-1, out);
750 #endif
751 
752       // Merge chunks [in_start, in_end-1] into one chunk.  Since the
753       // data member of each chunk is just a pointer into an in-memory
754       // copy of the file, this can be done without recopying (the
755       // output chunk has the first chunk's start location and data
756       // pointer, and length equal to the sum of the input chunk
757       // lengths).
758       chunks[out].type = CHUNK_NORMAL;
759       chunks[out].start = chunks[in_start].start;
760       chunks[out].data = chunks[in_start].data;
761       chunks[out].len = chunks[in_end-1].len +
762         (chunks[in_end-1].start - chunks[in_start].start);
763     }
764 
765     ++out;
766     in_start = in_end;
767   }
768   *num_chunks = out;
769 }
770 
FindChunkByName(const char * name,ImageChunk * chunks,int num_chunks)771 ImageChunk* FindChunkByName(const char* name,
772                             ImageChunk* chunks, int num_chunks) {
773   int i;
774   for (i = 0; i < num_chunks; ++i) {
775     if (chunks[i].type == CHUNK_DEFLATE && chunks[i].filename &&
776         strcmp(name, chunks[i].filename) == 0) {
777       return chunks+i;
778     }
779   }
780   return NULL;
781 }
782 
DumpChunks(ImageChunk * chunks,int num_chunks)783 void DumpChunks(ImageChunk* chunks, int num_chunks) {
784     int i;
785     for (i = 0; i < num_chunks; ++i) {
786         printf("chunk %d: type %d start %d len %d\n",
787                i, chunks[i].type, chunks[i].start, chunks[i].len);
788     }
789 }
790 
main(int argc,char ** argv)791 int main(int argc, char** argv) {
792   int zip_mode = 0;
793 
794   if (argc >= 2 && strcmp(argv[1], "-z") == 0) {
795     zip_mode = 1;
796     --argc;
797     ++argv;
798   }
799 
800   size_t bonus_size = 0;
801   unsigned char* bonus_data = NULL;
802   if (argc >= 3 && strcmp(argv[1], "-b") == 0) {
803     struct stat st;
804     if (stat(argv[2], &st) != 0) {
805       printf("failed to stat bonus file %s: %s\n", argv[2], strerror(errno));
806       return 1;
807     }
808     bonus_size = st.st_size;
809     bonus_data = malloc(bonus_size);
810     FILE* f = fopen(argv[2], "rb");
811     if (f == NULL) {
812       printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno));
813       return 1;
814     }
815     if (fread(bonus_data, 1, bonus_size, f) != bonus_size) {
816       printf("failed to read bonus file %s: %s\n", argv[2], strerror(errno));
817       return 1;
818     }
819     fclose(f);
820 
821     argc -= 2;
822     argv += 2;
823   }
824 
825   if (argc != 4) {
826     usage:
827     printf("usage: %s [-z] [-b <bonus-file>] <src-img> <tgt-img> <patch-file>\n",
828             argv[0]);
829     return 2;
830   }
831 
832   int num_src_chunks;
833   ImageChunk* src_chunks;
834   int num_tgt_chunks;
835   ImageChunk* tgt_chunks;
836   int i;
837 
838   if (zip_mode) {
839     if (ReadZip(argv[1], &num_src_chunks, &src_chunks, 1) == NULL) {
840       printf("failed to break apart source zip file\n");
841       return 1;
842     }
843     if (ReadZip(argv[2], &num_tgt_chunks, &tgt_chunks, 0) == NULL) {
844       printf("failed to break apart target zip file\n");
845       return 1;
846     }
847   } else {
848     if (ReadImage(argv[1], &num_src_chunks, &src_chunks) == NULL) {
849       printf("failed to break apart source image\n");
850       return 1;
851     }
852     if (ReadImage(argv[2], &num_tgt_chunks, &tgt_chunks) == NULL) {
853       printf("failed to break apart target image\n");
854       return 1;
855     }
856 
857     // Verify that the source and target images have the same chunk
858     // structure (ie, the same sequence of deflate and normal chunks).
859 
860     if (!zip_mode) {
861         // Merge the gzip header and footer in with any adjacent
862         // normal chunks.
863         MergeAdjacentNormalChunks(tgt_chunks, &num_tgt_chunks);
864         MergeAdjacentNormalChunks(src_chunks, &num_src_chunks);
865     }
866 
867     if (num_src_chunks != num_tgt_chunks) {
868       printf("source and target don't have same number of chunks!\n");
869       printf("source chunks:\n");
870       DumpChunks(src_chunks, num_src_chunks);
871       printf("target chunks:\n");
872       DumpChunks(tgt_chunks, num_tgt_chunks);
873       return 1;
874     }
875     for (i = 0; i < num_src_chunks; ++i) {
876       if (src_chunks[i].type != tgt_chunks[i].type) {
877         printf("source and target don't have same chunk "
878                 "structure! (chunk %d)\n", i);
879         printf("source chunks:\n");
880         DumpChunks(src_chunks, num_src_chunks);
881         printf("target chunks:\n");
882         DumpChunks(tgt_chunks, num_tgt_chunks);
883         return 1;
884       }
885     }
886   }
887 
888   for (i = 0; i < num_tgt_chunks; ++i) {
889     if (tgt_chunks[i].type == CHUNK_DEFLATE) {
890       // Confirm that given the uncompressed chunk data in the target, we
891       // can recompress it and get exactly the same bits as are in the
892       // input target image.  If this fails, treat the chunk as a normal
893       // non-deflated chunk.
894       if (ReconstructDeflateChunk(tgt_chunks+i) < 0) {
895         printf("failed to reconstruct target deflate chunk %d [%s]; "
896                "treating as normal\n", i, tgt_chunks[i].filename);
897         ChangeDeflateChunkToNormal(tgt_chunks+i);
898         if (zip_mode) {
899           ImageChunk* src = FindChunkByName(tgt_chunks[i].filename, src_chunks, num_src_chunks);
900           if (src) {
901             ChangeDeflateChunkToNormal(src);
902           }
903         } else {
904           ChangeDeflateChunkToNormal(src_chunks+i);
905         }
906         continue;
907       }
908 
909       // If two deflate chunks are identical (eg, the kernel has not
910       // changed between two builds), treat them as normal chunks.
911       // This makes applypatch much faster -- it can apply a trivial
912       // patch to the compressed data, rather than uncompressing and
913       // recompressing to apply the trivial patch to the uncompressed
914       // data.
915       ImageChunk* src;
916       if (zip_mode) {
917         src = FindChunkByName(tgt_chunks[i].filename, src_chunks, num_src_chunks);
918       } else {
919         src = src_chunks+i;
920       }
921 
922       if (src == NULL || AreChunksEqual(tgt_chunks+i, src)) {
923         ChangeDeflateChunkToNormal(tgt_chunks+i);
924         if (src) {
925           ChangeDeflateChunkToNormal(src);
926         }
927       }
928     }
929   }
930 
931   // Merging neighboring normal chunks.
932   if (zip_mode) {
933     // For zips, we only need to do this to the target:  deflated
934     // chunks are matched via filename, and normal chunks are patched
935     // using the entire source file as the source.
936     MergeAdjacentNormalChunks(tgt_chunks, &num_tgt_chunks);
937   } else {
938     // For images, we need to maintain the parallel structure of the
939     // chunk lists, so do the merging in both the source and target
940     // lists.
941     MergeAdjacentNormalChunks(tgt_chunks, &num_tgt_chunks);
942     MergeAdjacentNormalChunks(src_chunks, &num_src_chunks);
943     if (num_src_chunks != num_tgt_chunks) {
944       // This shouldn't happen.
945       printf("merging normal chunks went awry\n");
946       return 1;
947     }
948   }
949 
950   // Compute bsdiff patches for each chunk's data (the uncompressed
951   // data, in the case of deflate chunks).
952 
953   DumpChunks(src_chunks, num_src_chunks);
954 
955   printf("Construct patches for %d chunks...\n", num_tgt_chunks);
956   unsigned char** patch_data = malloc(num_tgt_chunks * sizeof(unsigned char*));
957   size_t* patch_size = malloc(num_tgt_chunks * sizeof(size_t));
958   for (i = 0; i < num_tgt_chunks; ++i) {
959     if (zip_mode) {
960       ImageChunk* src;
961       if (tgt_chunks[i].type == CHUNK_DEFLATE &&
962           (src = FindChunkByName(tgt_chunks[i].filename, src_chunks,
963                                  num_src_chunks))) {
964         patch_data[i] = MakePatch(src, tgt_chunks+i, patch_size+i);
965       } else {
966         patch_data[i] = MakePatch(src_chunks, tgt_chunks+i, patch_size+i);
967       }
968     } else {
969       if (i == 1 && bonus_data) {
970         printf("  using %d bytes of bonus data for chunk %d\n", bonus_size, i);
971         src_chunks[i].data = realloc(src_chunks[i].data, src_chunks[i].len + bonus_size);
972         memcpy(src_chunks[i].data+src_chunks[i].len, bonus_data, bonus_size);
973         src_chunks[i].len += bonus_size;
974      }
975 
976       patch_data[i] = MakePatch(src_chunks+i, tgt_chunks+i, patch_size+i);
977     }
978     printf("patch %3d is %d bytes (of %d)\n",
979            i, patch_size[i], tgt_chunks[i].source_len);
980   }
981 
982   // Figure out how big the imgdiff file header is going to be, so
983   // that we can correctly compute the offset of each bsdiff patch
984   // within the file.
985 
986   size_t total_header_size = 12;
987   for (i = 0; i < num_tgt_chunks; ++i) {
988     total_header_size += 4;
989     switch (tgt_chunks[i].type) {
990       case CHUNK_NORMAL:
991         total_header_size += 8*3;
992         break;
993       case CHUNK_DEFLATE:
994         total_header_size += 8*5 + 4*5;
995         break;
996       case CHUNK_RAW:
997         total_header_size += 4 + patch_size[i];
998         break;
999     }
1000   }
1001 
1002   size_t offset = total_header_size;
1003 
1004   FILE* f = fopen(argv[3], "wb");
1005 
1006   // Write out the headers.
1007 
1008   fwrite("IMGDIFF2", 1, 8, f);
1009   Write4(num_tgt_chunks, f);
1010   for (i = 0; i < num_tgt_chunks; ++i) {
1011     Write4(tgt_chunks[i].type, f);
1012 
1013     switch (tgt_chunks[i].type) {
1014       case CHUNK_NORMAL:
1015         printf("chunk %3d: normal   (%10d, %10d)  %10d\n", i,
1016                tgt_chunks[i].start, tgt_chunks[i].len, patch_size[i]);
1017         Write8(tgt_chunks[i].source_start, f);
1018         Write8(tgt_chunks[i].source_len, f);
1019         Write8(offset, f);
1020         offset += patch_size[i];
1021         break;
1022 
1023       case CHUNK_DEFLATE:
1024         printf("chunk %3d: deflate  (%10d, %10d)  %10d  %s\n", i,
1025                tgt_chunks[i].start, tgt_chunks[i].deflate_len, patch_size[i],
1026                tgt_chunks[i].filename);
1027         Write8(tgt_chunks[i].source_start, f);
1028         Write8(tgt_chunks[i].source_len, f);
1029         Write8(offset, f);
1030         Write8(tgt_chunks[i].source_uncompressed_len, f);
1031         Write8(tgt_chunks[i].len, f);
1032         Write4(tgt_chunks[i].level, f);
1033         Write4(tgt_chunks[i].method, f);
1034         Write4(tgt_chunks[i].windowBits, f);
1035         Write4(tgt_chunks[i].memLevel, f);
1036         Write4(tgt_chunks[i].strategy, f);
1037         offset += patch_size[i];
1038         break;
1039 
1040       case CHUNK_RAW:
1041         printf("chunk %3d: raw      (%10d, %10d)\n", i,
1042                tgt_chunks[i].start, tgt_chunks[i].len);
1043         Write4(patch_size[i], f);
1044         fwrite(patch_data[i], 1, patch_size[i], f);
1045         break;
1046     }
1047   }
1048 
1049   // Append each chunk's bsdiff patch, in order.
1050 
1051   for (i = 0; i < num_tgt_chunks; ++i) {
1052     if (tgt_chunks[i].type != CHUNK_RAW) {
1053       fwrite(patch_data[i], 1, patch_size[i], f);
1054     }
1055   }
1056 
1057   fclose(f);
1058 
1059   return 0;
1060 }
1061