Browse Source

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
Doug Zongker 11 years ago
parent
commit
c4351c7910
12 changed files with 1296 additions and 1322 deletions
  1. 2
    0
      applypatch/Android.mk
  2. 637
    722
      applypatch/applypatch.c
  3. 18
    4
      applypatch/applypatch.h
  4. 8
    3
      applypatch/applypatch.sh
  5. 186
    186
      applypatch/bspatch.c
  6. 170
    315
      applypatch/imgpatch.c
  7. 141
    6
      applypatch/main.c
  8. 20
    17
      applypatch/utils.c
  9. 3
    3
      applypatch/utils.h
  10. 2
    1
      edify/main.c
  11. 2
    0
      edify/yydefs.h
  12. 107
    65
      updater/install.c

+ 2
- 0
applypatch/Android.mk View File

@@ -29,6 +29,7 @@ include $(CLEAR_VARS)
29 29
 
30 30
 LOCAL_SRC_FILES := main.c
31 31
 LOCAL_MODULE := applypatch
32
+LOCAL_C_INCLUDES += bootable/recovery
32 33
 LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz
33 34
 LOCAL_SHARED_LIBRARIES += libz libcutils libstdc++ libc
34 35
 
@@ -40,6 +41,7 @@ LOCAL_SRC_FILES := main.c
40 41
 LOCAL_MODULE := applypatch_static
41 42
 LOCAL_FORCE_STATIC_EXECUTABLE := true
42 43
 LOCAL_MODULE_TAGS := eng
44
+LOCAL_C_INCLUDES += bootable/recovery
43 45
 LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz
44 46
 LOCAL_STATIC_LIBRARIES += libz libcutils libstdc++ libc
45 47
 

+ 637
- 722
applypatch/applypatch.c
File diff suppressed because it is too large
View File


+ 18
- 4
applypatch/applypatch.h View File

@@ -19,6 +19,7 @@
19 19
 
20 20
 #include <sys/stat.h>
21 21
 #include "mincrypt/sha.h"
22
+#include "edify/expr.h"
22 23
 
23 24
 typedef struct _Patch {
24 25
   uint8_t sha1[SHA_DIGEST_SIZE];
@@ -42,8 +43,21 @@ typedef struct _FileContents {
42 43
 typedef ssize_t (*SinkFn)(unsigned char*, ssize_t, void*);
43 44
 
44 45
 // applypatch.c
46
+int ShowLicenses();
45 47
 size_t FreeSpaceForFile(const char* filename);
46
-int applypatch(int argc, char** argv);
48
+int CacheSizeCheck(size_t bytes);
49
+int ParseSha1(const char* str, uint8_t* digest);
50
+
51
+int 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);
58
+int applypatch_check(const char* filename,
59
+                     int num_patches,
60
+                     char** const patch_sha1_str);
47 61
 
48 62
 // Read a file into memory; store it and its associated metadata in
49 63
 // *file.  Return 0 on success.
@@ -53,15 +67,15 @@ void FreeFileContents(FileContents* file);
53 67
 // bsdiff.c
54 68
 void ShowBSDiffLicense();
55 69
 int 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 71
                      SinkFn sink, void* token, SHA_CTX* ctx);
58 72
 int 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 74
                         unsigned char** new_data, ssize_t* new_size);
61 75
 
62 76
 // imgpatch.c
63 77
 int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
64
-                    const char* patch_filename,
78
+                    const Value* patch,
65 79
                     SinkFn sink, void* token, SHA_CTX* ctx);
66 80
 
67 81
 // freecache.c

+ 8
- 3
applypatch/applypatch.sh View File

@@ -11,7 +11,7 @@
11 11
 # the tests.
12 12
 
13 13
 EMULATOR_PORT=5580
14
-DATA_DIR=$ANDROID_BUILD_TOP/build/tools/applypatch/testdata
14
+DATA_DIR=$ANDROID_BUILD_TOP/bootable/recovery/applypatch/testdata
15 15
 
16 16
 # This must be the filename that applypatch uses for its copies.
17 17
 CACHE_TEMP_SOURCE=/cache/saved.file
@@ -81,6 +81,7 @@ cleanup() {
81 81
   testname "removing test files"
82 82
   run_command rm $WORK_DIR/bloat.dat
83 83
   run_command rm $WORK_DIR/old.file
84
+  run_command rm $WORK_DIR/foo
84 85
   run_command rm $WORK_DIR/patch.bsdiff
85 86
   run_command rm $WORK_DIR/applypatch
86 87
   run_command rm $CACHE_TEMP_SOURCE
@@ -88,10 +89,12 @@ cleanup() {
88 89
 
89 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
 
94
-cleanup
97
+cleanup leave_tmp
95 98
 
96 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 157
 $ADB push $DATA_DIR/old.file $WORK_DIR
155 158
 $ADB push $DATA_DIR/patch.bsdiff $WORK_DIR
159
+echo hello > $tmpdir/foo
160
+$ADB push $tmpdir/foo $WORK_DIR
156 161
 
157 162
 # Check that the partition has enough space to apply the patch without
158 163
 # copying.  If it doesn't, we'll be testing the low-space condition

+ 186
- 186
applypatch/bspatch.c View File

@@ -32,221 +32,221 @@
32 32
 #include "applypatch.h"
33 33
 
34 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
-       );
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 64
 }
65 65
 
66 66
 static off_t offtin(u_char *buf)
67 67
 {
68
-  off_t y;
68
+    off_t y;
69 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];
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 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
 
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
+}
84 99
 
85 100
 int 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 102
                      SinkFn sink, void* token, SHA_CTX* ctx) {
88 103
 
89
-  unsigned char* new_data;
90
-  ssize_t new_size;
91
-  if (ApplyBSDiffPatchMem(old_data, old_size, patch_filename, patch_offset,
92
-                          &new_data, &new_size) != 0) {
93
-    return -1;
94
-  }
95
-
96
-  if (sink(new_data, new_size, token) < new_size) {
97
-    fprintf(stderr, "short write of output: %d (%s)\n", errno, strerror(errno));
98
-    return 1;
99
-  }
100
-  if (ctx) {
101
-    SHA_update(ctx, new_data, new_size);
102
-  }
103
-  free(new_data);
104
-
105
-  return 0;
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;
106 121
 }
107 122
 
108 123
 int 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 125
                         unsigned char** new_data, ssize_t* new_size) {
111
-
112
-  FILE* f;
113
-  if ((f = fopen(patch_filename, "rb")) == NULL) {
114
-    fprintf(stderr, "failed to open patch file\n");
115
-    return 1;
116
-  }
117
-
118
-  // File format:
119
-  //   0       8       "BSDIFF40"
120
-  //   8       8       X
121
-  //   16      8       Y
122
-  //   24      8       sizeof(newfile)
123
-  //   32      X       bzip2(control block)
124
-  //   32+X    Y       bzip2(diff block)
125
-  //   32+X+Y  ???     bzip2(extra block)
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");
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");
197 141
         return 1;
198
-      }
199
-      ctrl[i] = offtin(buf);
200 142
     }
201 143
 
202
-    // Sanity check
203
-    if (newpos + ctrl[0] > *new_size) {
204
-      fprintf(stderr, "corrupt patch (new file overrun)\n");
205
-      return 1;
206
-    }
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);
207 148
 
208
-    // Read diff string
209
-    len_read = BZ2_bzRead(&bzerr, dpfbz2, *new_data + newpos, ctrl[0]);
210
-    if (len_read < ctrl[0] || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) {
211
-      fprintf(stderr, "corrupt patch (read diff)\n");
212
-      return 1;
149
+    if (ctrl_len < 0 || data_len < 0 || *new_size < 0) {
150
+        printf("corrupt patch file header (data lengths)\n");
151
+        return 1;
213 152
     }
214 153
 
215
-    // Add old data to diff string
216
-    for (i = 0; i < ctrl[0]; ++i) {
217
-      if ((oldpos+i >= 0) && (oldpos+i < old_size)) {
218
-        (*new_data)[newpos+i] += old_data[oldpos+i];
219
-      }
220
-    }
154
+    int bzerr;
221 155
 
222
-    // Adjust pointers
223
-    newpos += ctrl[0];
224
-    oldpos += ctrl[0];
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
+    }
225 165
 
226
-    // Sanity check
227
-    if (newpos + ctrl[1] > *new_size) {
228
-      fprintf(stderr, "corrupt patch (new file overrun)\n");
229
-      return 1;
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);
230 174
     }
231 175
 
232
-    // Read extra string
233
-    len_read = BZ2_bzRead(&bzerr, epfbz2, *new_data + newpos, ctrl[1]);
234
-    if (len_read < ctrl[1] || !(bzerr == BZ_OK || bzerr == BZ_STREAM_END)) {
235
-      fprintf(stderr, "corrupt patch (read extra)\n");
236
-      return 1;
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);
237 184
     }
238 185
 
239
-    // Adjust pointers
240
-    newpos += ctrl[1];
241
-    oldpos += ctrl[2];
242
-  }
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
+    }
243 192
 
244
-  BZ2_bzReadClose(&bzerr, cpfbz2);
245
-  BZ2_bzReadClose(&bzerr, dpfbz2);
246
-  BZ2_bzReadClose(&bzerr, epfbz2);
247
-  fclose(cpf);
248
-  fclose(dpf);
249
-  fclose(epf);
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
+    }
250 247
 
251
-  return 0;
248
+    BZ2_bzDecompressEnd(&cstream);
249
+    BZ2_bzDecompressEnd(&dstream);
250
+    BZ2_bzDecompressEnd(&estream);
251
+    return 0;
252 252
 }

+ 170
- 315
applypatch/imgpatch.c View File

@@ -36,329 +36,184 @@
36 36
  * Return 0 on success.
37 37
  */
38 38
 int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
39
-                    const char* patch_filename,
39
+                    const Value* patch,
40 40
                     SinkFn sink, void* token, SHA_CTX* ctx) {
41
-  FILE* f;
42
-  if ((f = fopen(patch_filename, "rb")) == NULL) {
43
-    printf("failed to open patch file\n");
44
-    return -1;
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);
41
+    ssize_t pos = 12;
42
+    char* header = patch->data;
43
+    if (patch->size < 12) {
44
+        printf("patch too short to contain header\n");
163 45
         return -1;
164
-      }
165
-      inflateEnd(&strm);
46
+    }
166 47
 
167
-      // Next, apply the bsdiff patch (in memory) to the uncompressed
168
-      // data.
169
-      unsigned char* uncompressed_target_data;
170
-      ssize_t uncompressed_target_size;
171
-      if (ApplyBSDiffPatchMem(expanded_source, expanded_len,
172
-                              patch_filename, patch_offset,
173
-                              &uncompressed_target_data,
174
-                              &uncompressed_target_size) != 0) {
48
+    // IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW.
49
+    // (IMGDIFF1, which is no longer supported, used CHUNK_NORMAL and
50
+    // CHUNK_GZIP.)
51
+    if (memcmp(header, "IMGDIFF2", 8) != 0) {
52
+        printf("corrupt patch file header (magic number)\n");
175 53
         return -1;
176
-      }
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
-      }
54
+    }
195 55
 
196
-      // now the deflate stream
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;
56
+    int num_chunks = Read4(header+8);
209 57
 
210
-        if (sink(temp_data, have, token) != have) {
211
-          printf("failed to write %d compressed bytes to output\n",
212
-                  have);
213
-          return -1;
58
+    int i;
59
+    for (i = 0; i < num_chunks; ++i) {
60
+        // each chunk's header record starts with 4 bytes.
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);
216
-      } while (ret != Z_STREAM_END);
217
-      deflateEnd(&strm);
218
-
219
-      // lastly, the gzip footer.
220
-      sink(gzip+64+gzip_header_len, 8, token);
221
-      SHA_update(ctx, gzip+64+gzip_header_len, 8);
222
-
223
-      free(temp_data);
224
-      free(uncompressed_target_data);
225
-      free(gzip);
226
-    } else if (type == CHUNK_RAW) {
227
-      unsigned char raw_header[4];
228
-      if (fread(raw_header, 1, 4, f) != 4) {
229
-        printf("failed to read chunk %d raw header data\n", i);
230
-        return -1;
231
-      }
232
-
233
-      size_t data_len = Read4(raw_header);
234
-
235
-      printf("CHUNK %d:  raw      data %d\n", i, data_len);
236
-
237
-      unsigned char* temp = malloc(data_len);
238
-      if (fread(temp, 1, data_len, f) != data_len) {
239
-          printf("failed to read chunk %d raw data\n", i);
240
-          return -1;
241
-      }
242
-      SHA_update(ctx, temp, data_len);
243
-      if (sink(temp, data_len, token) != data_len) {
244
-          printf("failed to write chunk %d raw data\n", i);
245
-          return -1;
246
-      }
247
-    } else if (type == CHUNK_DEFLATE) {
248
-      // deflate chunks have an additional 60 bytes in their chunk header.
249
-      unsigned char deflate_header[60];
250
-      if (fread(deflate_header, 1, 60, f) != 60) {
251
-        printf("failed to read chunk %d deflate header data\n", i);
252
-        return -1;
253
-      }
254
-
255
-      size_t src_start = Read8(deflate_header);
256
-      size_t src_len = Read8(deflate_header+8);
257
-      size_t patch_offset = Read8(deflate_header+16);
258
-      size_t expanded_len = Read8(deflate_header+24);
259
-      size_t target_len = Read8(deflate_header+32);
260
-      int level = Read4(deflate_header+40);
261
-      int method = Read4(deflate_header+44);
262
-      int windowBits = Read4(deflate_header+48);
263
-      int memLevel = Read4(deflate_header+52);
264
-      int strategy = Read4(deflate_header+56);
265
-
266
-      printf("CHUNK %d:  deflate  patch offset %d\n", i, patch_offset);
267
-
268
-      // Decompress the source data; the chunk header tells us exactly
269
-      // how big we expect it to be when decompressed.
270
-
271
-      unsigned char* expanded_source = malloc(expanded_len);
272
-      if (expanded_source == NULL) {
273
-        printf("failed to allocate %d bytes for expanded_source\n",
274
-                expanded_len);
275
-        return -1;
276
-      }
277
-
278
-      z_stream strm;
279
-      strm.zalloc = Z_NULL;
280
-      strm.zfree = Z_NULL;
281
-      strm.opaque = Z_NULL;
282
-      strm.avail_in = src_len;
283
-      strm.next_in = (unsigned char*)(old_data + src_start);
284
-      strm.avail_out = expanded_len;
285
-      strm.next_out = expanded_source;
286
-
287
-      int ret;
288
-      ret = inflateInit2(&strm, -15);
289
-      if (ret != Z_OK) {
290
-        printf("failed to init source inflation: %d\n", ret);
291
-        return -1;
292
-      }
293
-
294
-      // Because we've provided enough room to accommodate the output
295
-      // data, we expect one call to inflate() to suffice.
296
-      ret = inflate(&strm, Z_SYNC_FLUSH);
297
-      if (ret != Z_STREAM_END) {
298
-        printf("source inflation returned %d\n", ret);
299
-        return -1;
300
-      }
301
-      // We should have filled the output buffer exactly.
302
-      if (strm.avail_out != 0) {
303
-        printf("source inflation short by %d bytes\n", strm.avail_out);
304
-        return -1;
305
-      }
306
-      inflateEnd(&strm);
307
-
308
-      // Next, apply the bsdiff patch (in memory) to the uncompressed
309
-      // data.
310
-      unsigned char* uncompressed_target_data;
311
-      ssize_t uncompressed_target_size;
312
-      if (ApplyBSDiffPatchMem(expanded_source, expanded_len,
313
-                              patch_filename, patch_offset,
314
-                              &uncompressed_target_data,
315
-                              &uncompressed_target_size) != 0) {
316
-        return -1;
317
-      }
318
-
319
-      // Now compress the target data and append it to the output.
320
-
321
-      // we're done with the expanded_source data buffer, so we'll
322
-      // reuse that memory to receive the output of deflate.
323
-      unsigned char* temp_data = expanded_source;
324
-      ssize_t temp_size = expanded_len;
325
-      if (temp_size < 32768) {
326
-        // ... unless the buffer is too small, in which case we'll
327
-        // allocate a fresh one.
328
-        free(temp_data);
329
-        temp_data = malloc(32768);
330
-        temp_size = 32768;
331
-      }
332
-
333
-      // now the deflate stream
334
-      strm.zalloc = Z_NULL;
335
-      strm.zfree = Z_NULL;
336
-      strm.opaque = Z_NULL;
337
-      strm.avail_in = uncompressed_target_size;
338
-      strm.next_in = uncompressed_target_data;
339
-      ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy);
340
-      do {
341
-        strm.avail_out = temp_size;
342
-        strm.next_out = temp_data;
343
-        ret = deflate(&strm, Z_FINISH);
344
-        size_t have = temp_size - strm.avail_out;
345
-
346
-        if (sink(temp_data, have, token) != have) {
347
-          printf("failed to write %d compressed bytes to output\n",
348
-                  have);
349
-          return -1;
65
+        int type = Read4(patch->data + pos);
66
+        pos += 4;
67
+
68
+        if (type == CHUNK_NORMAL) {
69
+            char* normal_header = patch->data + pos;
70
+            pos += 24;
71
+            if (pos > patch->size) {
72
+                printf("failed to read chunk %d normal header data\n", i);
73
+                return -1;
74
+            }
75
+
76
+            size_t src_start = Read8(normal_header);
77
+            size_t src_len = Read8(normal_header+8);
78
+            size_t patch_offset = Read8(normal_header+16);
79
+
80
+            ApplyBSDiffPatch(old_data + src_start, src_len,
81
+                             patch, patch_offset, sink, token, ctx);
82
+        } else if (type == CHUNK_RAW) {
83
+            char* raw_header = patch->data + pos;
84
+            pos += 4;
85
+            if (pos > patch->size) {
86
+                printf("failed to read chunk %d raw header data\n", i);
87
+                return -1;
88
+            }
89
+
90
+            ssize_t data_len = Read4(raw_header);
91
+
92
+            if (pos + data_len > patch->size) {
93
+                printf("failed to read chunk %d raw data\n", i);
94
+                return -1;
95
+            }
96
+            SHA_update(ctx, patch->data + pos, data_len);
97
+            if (sink((unsigned char*)patch->data + pos,
98
+                     data_len, token) != data_len) {
99
+                printf("failed to write chunk %d raw data\n", i);
100
+                return -1;
101
+            }
102
+            pos += data_len;
103
+        } else if (type == CHUNK_DEFLATE) {
104
+            // deflate chunks have an additional 60 bytes in their chunk header.
105
+            char* deflate_header = patch->data + pos;
106
+            pos += 60;
107
+            if (pos > patch->size) {
108
+                printf("failed to read chunk %d deflate header data\n", i);
109
+                return -1;
110
+            }
111
+
112
+            size_t src_start = Read8(deflate_header);
113
+            size_t src_len = Read8(deflate_header+8);
114
+            size_t patch_offset = Read8(deflate_header+16);
115
+            size_t expanded_len = Read8(deflate_header+24);
116
+            size_t target_len = Read8(deflate_header+32);
117
+            int level = Read4(deflate_header+40);
118
+            int method = Read4(deflate_header+44);
119
+            int windowBits = Read4(deflate_header+48);
120
+            int memLevel = Read4(deflate_header+52);
121
+            int strategy = Read4(deflate_header+56);
122
+
123
+            // Decompress the source data; the chunk header tells us exactly
124
+            // how big we expect it to be when decompressed.
125
+
126
+            unsigned char* expanded_source = malloc(expanded_len);
127
+            if (expanded_source == NULL) {
128
+                printf("failed to allocate %d bytes for expanded_source\n",
129
+                       expanded_len);
130
+                return -1;
131
+            }
132
+
133
+            z_stream strm;
134
+            strm.zalloc = Z_NULL;
135
+            strm.zfree = Z_NULL;
136
+            strm.opaque = Z_NULL;
137
+            strm.avail_in = src_len;
138
+            strm.next_in = (unsigned char*)(old_data + src_start);
139
+            strm.avail_out = expanded_len;
140
+            strm.next_out = expanded_source;
141
+
142
+            int ret;
143
+            ret = inflateInit2(&strm, -15);
144
+            if (ret != Z_OK) {
145
+                printf("failed to init source inflation: %d\n", ret);
146
+                return -1;
147
+            }
148
+
149
+            // Because we've provided enough room to accommodate the output
150
+            // data, we expect one call to inflate() to suffice.
151
+            ret = inflate(&strm, Z_SYNC_FLUSH);
152
+            if (ret != Z_STREAM_END) {
153
+                printf("source inflation returned %d\n", ret);
154
+                return -1;
155
+            }
156
+            // We should have filled the output buffer exactly.
157
+            if (strm.avail_out != 0) {
158
+                printf("source inflation short by %d bytes\n", strm.avail_out);
159
+                return -1;
160
+            }
161
+            inflateEnd(&strm);
162
+
163
+            // Next, apply the bsdiff patch (in memory) to the uncompressed
164
+            // data.
165
+            unsigned char* uncompressed_target_data;
166
+            ssize_t uncompressed_target_size;
167
+            if (ApplyBSDiffPatchMem(expanded_source, expanded_len,
168
+                                    patch, patch_offset,
169
+                                    &uncompressed_target_data,
170
+                                    &uncompressed_target_size) != 0) {
171
+                return -1;
172
+            }
173
+
174
+            // Now compress the target data and append it to the output.
175
+
176
+            // we're done with the expanded_source data buffer, so we'll
177
+            // reuse that memory to receive the output of deflate.
178
+            unsigned char* temp_data = expanded_source;
179
+            ssize_t temp_size = expanded_len;
180
+            if (temp_size < 32768) {
181
+                // ... unless the buffer is too small, in which case we'll
182
+                // allocate a fresh one.
183
+                free(temp_data);
184
+                temp_data = malloc(32768);
185
+                temp_size = 32768;
186
+            }
187
+
188
+            // now the deflate stream
189
+            strm.zalloc = Z_NULL;
190
+            strm.zfree = Z_NULL;
191
+            strm.opaque = Z_NULL;
192
+            strm.avail_in = uncompressed_target_size;
193
+            strm.next_in = uncompressed_target_data;
194
+            ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy);
195
+            do {
196
+                strm.avail_out = temp_size;
197
+                strm.next_out = temp_data;
198
+                ret = deflate(&strm, Z_FINISH);
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
 }

+ 141
- 6
applypatch/main.c View File

@@ -15,8 +15,126 @@
15 15
  */
16 16
 
17 17
 #include <stdio.h>
18
+#include <stdlib.h>
19
+#include <string.h>
20
+#include <unistd.h>
18 21
 
19
-extern int applypatch(int argc, char** argv);
22
+#include "applypatch.h"
23
+#include "edify/expr.h"
24
+#include "mincrypt/sha.h"
25
+
26
+int 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
+
33
+int 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.
50
+static 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
+
102
+int 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 139
 // This program applies binary patches to files in a way that is safe
22 140
 // (the original file is not touched until we have the desired
@@ -42,9 +160,9 @@ extern int applypatch(int argc, char** argv);
42 160
 // LoadMTDContents() function above for the format of such a filename.
43 161
 
44 162
 int main(int argc, char** argv) {
45
-  int result = applypatch(argc, argv);
46
-  if (result == 2) {
47
-    printf(
163
+    if (argc < 2) {
164
+      usage:
165
+        printf(
48 166
             "usage: %s <src-file> <tgt-file> <tgt-sha1> <tgt-size> "
49 167
             "[<src-sha1>:<patch> ...]\n"
50 168
             "   or  %s -c <file> [<sha1> ...]\n"
@@ -55,6 +173,23 @@ int main(int argc, char** argv) {
55 173
             "  MTD:<partition>:<len_1>:<sha1_1>:<len_2>:<sha1_2>:...\n"
56 174
             "to specify reading from or writing to an MTD partition.\n\n",
57 175
             argv[0], argv[0], argv[0], argv[0]);
58
-  }
59
-  return result;
176
+        return 2;
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
 }

+ 20
- 17
applypatch/utils.c View File

@@ -38,25 +38,28 @@ void Write8(long long value, FILE* f) {
38 38
   fputc((value >> 56) & 0xff, f);
39 39
 }
40 40
 
41
-int Read2(unsigned char* p) {
42
-  return (int)(((unsigned int)p[1] << 8) |
43
-               (unsigned int)p[0]);
41
+int Read2(void* pv) {
42
+    unsigned char* p = pv;
43
+    return (int)(((unsigned int)p[1] << 8) |
44
+                 (unsigned int)p[0]);
44 45
 }
45 46
 
46
-int Read4(unsigned char* p) {
47
-  return (int)(((unsigned int)p[3] << 24) |
48
-               ((unsigned int)p[2] << 16) |
49
-               ((unsigned int)p[1] << 8) |
50
-               (unsigned int)p[0]);
47
+int Read4(void* pv) {
48
+    unsigned char* p = pv;
49
+    return (int)(((unsigned int)p[3] << 24) |
50
+                 ((unsigned int)p[2] << 16) |
51
+                 ((unsigned int)p[1] << 8) |
52
+                 (unsigned int)p[0]);
51 53
 }
52 54
 
53
-long long Read8(unsigned char* p) {
54
-  return (long long)(((unsigned long long)p[7] << 56) |
55
-                     ((unsigned long long)p[6] << 48) |
56
-                     ((unsigned long long)p[5] << 40) |
57
-                     ((unsigned long long)p[4] << 32) |
58
-                     ((unsigned long long)p[3] << 24) |
59
-                     ((unsigned long long)p[2] << 16) |
60
-                     ((unsigned long long)p[1] << 8) |
61
-                     (unsigned long long)p[0]);
55
+long long Read8(void* pv) {
56
+    unsigned char* p = pv;
57
+    return (long long)(((unsigned long long)p[7] << 56) |
58
+                       ((unsigned long long)p[6] << 48) |
59
+                       ((unsigned long long)p[5] << 40) |
60
+                       ((unsigned long long)p[4] << 32) |
61
+                       ((unsigned long long)p[3] << 24) |
62
+                       ((unsigned long long)p[2] << 16) |
63
+                       ((unsigned long long)p[1] << 8) |
64
+                       (unsigned long long)p[0]);
62 65
 }

+ 3
- 3
applypatch/utils.h View File

@@ -23,8 +23,8 @@
23 23
 
24 24
 void Write4(int value, FILE* f);
25 25
 void Write8(long long value, FILE* f);
26
-int Read2(unsigned char* p);
27
-int Read4(unsigned char* p);
28
-long long Read8(unsigned char* p);
26
+int Read2(void* p);
27
+int Read4(void* p);
28
+long long Read8(void* p);
29 29
 
30 30
 #endif //  _BUILD_TOOLS_APPLYPATCH_UTILS_H

+ 2
- 1
edify/main.c View File

@@ -42,11 +42,12 @@ int expect(const char* expr_str, const char* expected, int* errors) {
42 42
 
43 43
     State state;
44 44
     state.cookie = NULL;
45
-    state.script = expr_str;
45
+    state.script = strdup(expr_str);
46 46
     state.errmsg = NULL;
47 47
 
48 48
     result = Evaluate(&state, e);
49 49
     free(state.errmsg);
50
+    free(state.script);
50 51
     if (result == NULL && expected != NULL) {
51 52
         fprintf(stderr, "error evaluating \"%s\"\n", expr_str);
52 53
         ++*errors;

+ 2
- 0
edify/yydefs.h View File

@@ -33,4 +33,6 @@ typedef struct {
33 33
         } \
34 34
     } while (0)
35 35
 
36
+int yylex();
37
+
36 38
 #endif

+ 107
- 65
updater/install.c View File

@@ -705,52 +705,124 @@ done:
705 705
     return StringValue(result);
706 706
 }
707 707
 
708
-// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...)
709
-// apply_patch_check(file, sha1, ...)
710 708
 // apply_patch_space(bytes)
711
-Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
712
-    printf("in applypatchfn (%s)\n", name);
709
+Value* ApplyPatchSpaceFn(const char* name, State* state,
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;
715
-    if (strstr(name, "check") != NULL) {
716
-        prepend = "-c";
717
-    } else if (strstr(name, "space") != NULL) {
718
-        prepend = "-s";
716
+    char* endptr;
717
+    size_t bytes = strtol(bytes_str, &endptr, 10);
718
+    if (bytes == 0 && endptr == bytes_str) {
719
+        ErrorAbort(state, "%s(): can't parse \"%s\" as byte count\n\n",
720
+                   name, bytes_str);
721
+        free(bytes_str);
722
+        return NULL;
719 723
     }
720 724
 
721
-    char** args = ReadVarArgs(state, argc, argv);
722
-    if (args == NULL) return NULL;
725
+    return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
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);
728
-    char** temp = malloc((argc+extra) * sizeof(char*));
729
-    memcpy(temp+extra, args, argc * sizeof(char*));
730
-    temp[0] = strdup("updater");
731
-    if (prepend) {
732
-        temp[1] = strdup(prepend);
729
+// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
730
+Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
731
+    if (argc < 6 || (argc % 2) == 1) {
732
+        return ErrorAbort(state, "%s(): expected at least 6 args and an "
733
+                                 "even number, got %d",
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");
739
-    fflush(stdout);
740
-    int result = applypatch(argc, args);
741
-    printf("applypatch returned %d\n", result);
746
+    char* endptr;
747
+    size_t target_size = strtol(target_size_str, &endptr, 10);
748
+    if (target_size == 0 && endptr == target_size_str) {
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 761
     int i;
744
-    for (i = 0; i < argc; ++i) {
745
-        free(args[i]);
762
+    for (i = 0; i < patchcount; ++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) {
750
-        case 0:   return StringValue(strdup("t"));
751
-        case 1:   return StringValue(strdup(""));
752
-        default:  return ErrorAbort(state, "applypatch couldn't parse args");
780
+    char** patch_sha_str = malloc(patchcount * sizeof(char*));
781
+    for (i = 0; i < patchcount; ++i) {
782
+        patch_sha_str[i] = patches[i*2]->data;
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, ...])
802
+Value* 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
 
756 828
 Value* 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 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.
838
-static 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 906
 // Take a sha-1 digest and return it as a newly-allocated hex string.
865 907
 static char* PrintSha1(uint8_t* digest) {
866 908
     char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
@@ -981,8 +1023,8 @@ void RegisterInstallFunctions() {
981 1023
     RegisterFunction("write_raw_image", WriteRawImageFn);
982 1024
 
983 1025
     RegisterFunction("apply_patch", ApplyPatchFn);
984
-    RegisterFunction("apply_patch_check", ApplyPatchFn);
985
-    RegisterFunction("apply_patch_space", ApplyPatchFn);
1026
+    RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
1027
+    RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
986 1028
 
987 1029
     RegisterFunction("read_file", ReadFileFn);
988 1030
     RegisterFunction("sha1_check", Sha1CheckFn);