Home | History | Annotate | Download | only in applypatch
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 // This file is a nearly line-for-line copy of bspatch.c from the
     18 // bsdiff-4.3 distribution; the primary differences being how the
     19 // input and output data are read and the error handling.  Running
     20 // applypatch with the -l option will display the bsdiff license
     21 // notice.
     22 
     23 #include <stdio.h>
     24 #include <sys/stat.h>
     25 #include <errno.h>
     26 #include <unistd.h>
     27 #include <string.h>
     28 
     29 #include <bzlib.h>
     30 
     31 #include "mincrypt/sha.h"
     32 #include "applypatch.h"
     33 
     34 void ShowBSDiffLicense() {
     35     puts("The bsdiff library used herein is:\n"
     36          "\n"
     37          "Copyright 2003-2005 Colin Percival\n"
     38          "All rights reserved\n"
     39          "\n"
     40          "Redistribution and use in source and binary forms, with or without\n"
     41          "modification, are permitted providing that the following conditions\n"
     42          "are met:\n"
     43          "1. Redistributions of source code must retain the above copyright\n"
     44          "   notice, this list of conditions and the following disclaimer.\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"
     47          "   documentation and/or other materials provided with the distribution.\n"
     48          "\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"
     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"
     53          "DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\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"
     56          "HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\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"
     59          "POSSIBILITY OF SUCH DAMAGE.\n"
     60          "\n------------------\n\n"
     61          "This program uses Julian R Seward's \"libbzip2\" library, available\n"
     62          "from http://www.bzip.org/.\n"
     63         );
     64 }
     65 
     66 static off_t offtin(u_char *buf)
     67 {
     68     off_t y;
     69 
     70     y=buf[7]&0x7F;
     71     y=y*256;y+=buf[6];
     72     y=y*256;y+=buf[5];
     73     y=y*256;y+=buf[4];
     74     y=y*256;y+=buf[3];
     75     y=y*256;y+=buf[2];
     76     y=y*256;y+=buf[1];
     77     y=y*256;y+=buf[0];
     78 
     79     if(buf[7]&0x80) y=-y;
     80 
     81     return y;
     82 }
     83 
     84 int 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 }
     99 
    100 int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
    101                      const Value* patch, ssize_t patch_offset,
    102                      SinkFn sink, void* token, SHA_CTX* ctx) {
    103 
    104     unsigned char* new_data;
    105     ssize_t new_size;
    106     if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset,
    107                             &new_data, &new_size) != 0) {
    108         return -1;
    109     }
    110 
    111     if (sink(new_data, new_size, token) < new_size) {
    112         printf("short write of output: %d (%s)\n", errno, strerror(errno));
    113         return 1;
    114     }
    115     if (ctx) {
    116         SHA_update(ctx, new_data, new_size);
    117     }
    118     free(new_data);
    119 
    120     return 0;
    121 }
    122 
    123 int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
    124                         const Value* patch, ssize_t patch_offset,
    125                         unsigned char** new_data, ssize_t* new_size) {
    126     // Patch data format:
    127     //   0       8       "BSDIFF40"
    128     //   8       8       X
    129     //   16      8       Y
    130     //   24      8       sizeof(newfile)
    131     //   32      X       bzip2(control block)
    132     //   32+X    Y       bzip2(diff block)
    133     //   32+X+Y  ???     bzip2(extra block)
    134     // with control block a set of triples (x,y,z) meaning "add x bytes
    135     // from oldfile to x bytes from the diff block; copy y bytes from the
    136     // extra block; seek forwards in oldfile by z bytes".
    137 
    138     unsigned char* header = (unsigned char*) patch->data + patch_offset;
    139     if (memcmp(header, "BSDIFF40", 8) != 0) {
    140         printf("corrupt bsdiff patch file header (magic number)\n");
    141         return 1;
    142     }
    143 
    144     ssize_t ctrl_len, data_len;
    145     ctrl_len = offtin(header+8);
    146     data_len = offtin(header+16);
    147     *new_size = offtin(header+24);
    148 
    149     if (ctrl_len < 0 || data_len < 0 || *new_size < 0) {
    150         printf("corrupt patch file header (data lengths)\n");
    151         return 1;
    152     }
    153 
    154     int bzerr;
    155 
    156     bz_stream cstream;
    157     cstream.next_in = patch->data + patch_offset + 32;
    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     }
    165 
    166     bz_stream dstream;
    167     dstream.next_in = patch->data + patch_offset + 32 + ctrl_len;
    168     dstream.avail_in = data_len;
    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);
    174     }
    175 
    176     bz_stream estream;
    177     estream.next_in = patch->data + patch_offset + 32 + ctrl_len + data_len;
    178     estream.avail_in = patch->size - (patch_offset + 32 + ctrl_len + data_len);
    179     estream.bzalloc = NULL;
    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);
    184     }
    185 
    186     *new_data = malloc(*new_size);
    187     if (*new_data == NULL) {
    188         printf("failed to allocate %ld bytes of memory for output file\n",
    189                (long)*new_size);
    190         return 1;
    191     }
    192 
    193     off_t oldpos = 0, newpos = 0;
    194     off_t ctrl[3];
    195     off_t len_read;
    196     int i;
    197     unsigned char buf[24];
    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     }
    247 
    248     BZ2_bzDecompressEnd(&cstream);
    249     BZ2_bzDecompressEnd(&dstream);
    250     BZ2_bzDecompressEnd(&estream);
    251     return 0;
    252 }
    253