blob: 96bd88e8899b95b08731295119dd1f7a2414bb84 [file] [log] [blame]
Doug Zongker512536a2010-02-17 16:11:44 -08001/*
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#include <errno.h>
Tao Baoba9a42a2015-06-23 23:23:33 -070018#include <fcntl.h>
Doug Zongker512536a2010-02-17 16:11:44 -080019#include <libgen.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <sys/stat.h>
24#include <sys/statfs.h>
25#include <sys/types.h>
Doug Zongker512536a2010-02-17 16:11:44 -080026#include <unistd.h>
27
28#include "mincrypt/sha.h"
29#include "applypatch.h"
30#include "mtdutils/mtdutils.h"
Doug Zongkerc4351c72010-02-22 14:46:32 -080031#include "edify/expr.h"
Doug Zongker512536a2010-02-17 16:11:44 -080032
Doug Zongkerf291d852010-07-07 13:55:25 -070033static int LoadPartitionContents(const char* filename, FileContents* file);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070034static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token);
Doug Zongker1c43c972012-02-28 11:07:09 -080035static int GenerateTarget(FileContents* source_file,
36 const Value* source_patch_value,
37 FileContents* copy_file,
38 const Value* copy_patch_value,
39 const char* source_filename,
40 const char* target_filename,
41 const uint8_t target_sha1[SHA_DIGEST_SIZE],
Doug Zongkera3ccba62012-08-20 15:28:02 -070042 size_t target_size,
43 const Value* bonus_data);
Doug Zongker512536a2010-02-17 16:11:44 -080044
45static int mtd_partitions_scanned = 0;
46
Doug Zongkera1bc1482014-02-13 15:18:19 -080047// Read a file into memory; store the file contents and associated
Hristo Bojinovdb314d62010-08-02 10:29:49 -070048// metadata in *file.
49//
50// Return 0 on success.
Doug Zongkera1bc1482014-02-13 15:18:19 -080051int LoadFileContents(const char* filename, FileContents* file) {
Doug Zongker512536a2010-02-17 16:11:44 -080052 file->data = NULL;
Doug Zongker512536a2010-02-17 16:11:44 -080053
Doug Zongkerf291d852010-07-07 13:55:25 -070054 // A special 'filename' beginning with "MTD:" or "EMMC:" means to
55 // load the contents of a partition.
56 if (strncmp(filename, "MTD:", 4) == 0 ||
57 strncmp(filename, "EMMC:", 5) == 0) {
58 return LoadPartitionContents(filename, file);
Doug Zongkerc4351c72010-02-22 14:46:32 -080059 }
Doug Zongker512536a2010-02-17 16:11:44 -080060
Doug Zongkerc4351c72010-02-22 14:46:32 -080061 if (stat(filename, &file->st) != 0) {
62 printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
63 return -1;
64 }
65
66 file->size = file->st.st_size;
Tao Baoba9a42a2015-06-23 23:23:33 -070067 file->data = reinterpret_cast<unsigned char*>(malloc(file->size));
Doug Zongkerc4351c72010-02-22 14:46:32 -080068
69 FILE* f = fopen(filename, "rb");
70 if (f == NULL) {
71 printf("failed to open \"%s\": %s\n", filename, strerror(errno));
72 free(file->data);
73 file->data = NULL;
74 return -1;
75 }
76
Tao Baoba9a42a2015-06-23 23:23:33 -070077 size_t bytes_read = fread(file->data, 1, file->size, f);
78 if (bytes_read != static_cast<size_t>(file->size)) {
79 printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, file->size);
Doug Zongkerc4351c72010-02-22 14:46:32 -080080 free(file->data);
81 file->data = NULL;
82 return -1;
83 }
84 fclose(f);
85
Doug Zongkerbac7fba2013-04-10 11:32:17 -070086 SHA_hash(file->data, file->size, file->sha1);
Doug Zongkerc4351c72010-02-22 14:46:32 -080087 return 0;
Doug Zongker512536a2010-02-17 16:11:44 -080088}
89
90static size_t* size_array;
91// comparison function for qsort()ing an int array of indexes into
92// size_array[].
93static int compare_size_indices(const void* a, const void* b) {
Tao Baoba9a42a2015-06-23 23:23:33 -070094 const int aa = *reinterpret_cast<const int*>(a);
95 const int bb = *reinterpret_cast<const int*>(b);
Doug Zongkerc4351c72010-02-22 14:46:32 -080096 if (size_array[aa] < size_array[bb]) {
97 return -1;
98 } else if (size_array[aa] > size_array[bb]) {
99 return 1;
100 } else {
101 return 0;
102 }
Doug Zongker512536a2010-02-17 16:11:44 -0800103}
104
Doug Zongkerf291d852010-07-07 13:55:25 -0700105// Load the contents of an MTD or EMMC partition into the provided
Doug Zongker512536a2010-02-17 16:11:44 -0800106// FileContents. filename should be a string of the form
Doug Zongkerf291d852010-07-07 13:55:25 -0700107// "MTD:<partition_name>:<size_1>:<sha1_1>:<size_2>:<sha1_2>:..." (or
108// "EMMC:<partition_device>:..."). The smallest size_n bytes for
109// which that prefix of the partition contents has the corresponding
110// sha1 hash will be loaded. It is acceptable for a size value to be
111// repeated with different sha1s. Will return 0 on success.
Doug Zongker512536a2010-02-17 16:11:44 -0800112//
113// This complexity is needed because if an OTA installation is
114// interrupted, the partition might contain either the source or the
115// target data, which might be of different lengths. We need to know
Doug Zongkerf291d852010-07-07 13:55:25 -0700116// the length in order to read from a partition (there is no
117// "end-of-file" marker), so the caller must specify the possible
118// lengths and the hash of the data, and we'll do the load expecting
119// to find one of those hashes.
120enum PartitionType { MTD, EMMC };
121
122static int LoadPartitionContents(const char* filename, FileContents* file) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800123 char* copy = strdup(filename);
124 const char* magic = strtok(copy, ":");
Doug Zongkerf291d852010-07-07 13:55:25 -0700125
126 enum PartitionType type;
127
128 if (strcmp(magic, "MTD") == 0) {
129 type = MTD;
130 } else if (strcmp(magic, "EMMC") == 0) {
131 type = EMMC;
132 } else {
Tao Baoba9a42a2015-06-23 23:23:33 -0700133 printf("LoadPartitionContents called with bad filename (%s)\n", filename);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800134 return -1;
Doug Zongker512536a2010-02-17 16:11:44 -0800135 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800136 const char* partition = strtok(NULL, ":");
Doug Zongker512536a2010-02-17 16:11:44 -0800137
Doug Zongkerc4351c72010-02-22 14:46:32 -0800138 int i;
139 int colons = 0;
140 for (i = 0; filename[i] != '\0'; ++i) {
141 if (filename[i] == ':') {
142 ++colons;
143 }
Doug Zongker512536a2010-02-17 16:11:44 -0800144 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800145 if (colons < 3 || colons%2 == 0) {
Doug Zongkerf291d852010-07-07 13:55:25 -0700146 printf("LoadPartitionContents called with bad filename (%s)\n",
Doug Zongkerc4351c72010-02-22 14:46:32 -0800147 filename);
148 }
Doug Zongker512536a2010-02-17 16:11:44 -0800149
Doug Zongkerc4351c72010-02-22 14:46:32 -0800150 int pairs = (colons-1)/2; // # of (size,sha1) pairs in filename
Tao Baoba9a42a2015-06-23 23:23:33 -0700151 int* index = reinterpret_cast<int*>(malloc(pairs * sizeof(int)));
152 size_t* size = reinterpret_cast<size_t*>(malloc(pairs * sizeof(size_t)));
153 char** sha1sum = reinterpret_cast<char**>(malloc(pairs * sizeof(char*)));
Doug Zongker512536a2010-02-17 16:11:44 -0800154
Doug Zongkerc4351c72010-02-22 14:46:32 -0800155 for (i = 0; i < pairs; ++i) {
156 const char* size_str = strtok(NULL, ":");
157 size[i] = strtol(size_str, NULL, 10);
158 if (size[i] == 0) {
Doug Zongkerf291d852010-07-07 13:55:25 -0700159 printf("LoadPartitionContents called with bad size (%s)\n", filename);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800160 return -1;
161 }
162 sha1sum[i] = strtok(NULL, ":");
163 index[i] = i;
164 }
Doug Zongker512536a2010-02-17 16:11:44 -0800165
Doug Zongkerc4351c72010-02-22 14:46:32 -0800166 // sort the index[] array so it indexes the pairs in order of
167 // increasing size.
168 size_array = size;
169 qsort(index, pairs, sizeof(int), compare_size_indices);
Doug Zongker512536a2010-02-17 16:11:44 -0800170
Doug Zongkerf291d852010-07-07 13:55:25 -0700171 MtdReadContext* ctx = NULL;
172 FILE* dev = NULL;
Doug Zongker512536a2010-02-17 16:11:44 -0800173
Doug Zongkerf291d852010-07-07 13:55:25 -0700174 switch (type) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700175 case MTD: {
Doug Zongkerf291d852010-07-07 13:55:25 -0700176 if (!mtd_partitions_scanned) {
177 mtd_scan_partitions();
178 mtd_partitions_scanned = 1;
179 }
Doug Zongker512536a2010-02-17 16:11:44 -0800180
Doug Zongkerf291d852010-07-07 13:55:25 -0700181 const MtdPartition* mtd = mtd_find_partition_by_name(partition);
182 if (mtd == NULL) {
183 printf("mtd partition \"%s\" not found (loading %s)\n",
184 partition, filename);
185 return -1;
186 }
187
188 ctx = mtd_read_partition(mtd);
189 if (ctx == NULL) {
190 printf("failed to initialize read of mtd partition \"%s\"\n",
191 partition);
192 return -1;
193 }
194 break;
Tao Baoba9a42a2015-06-23 23:23:33 -0700195 }
Doug Zongkerf291d852010-07-07 13:55:25 -0700196
197 case EMMC:
198 dev = fopen(partition, "rb");
199 if (dev == NULL) {
200 printf("failed to open emmc partition \"%s\": %s\n",
201 partition, strerror(errno));
202 return -1;
203 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800204 }
Doug Zongker512536a2010-02-17 16:11:44 -0800205
Doug Zongkerc4351c72010-02-22 14:46:32 -0800206 SHA_CTX sha_ctx;
207 SHA_init(&sha_ctx);
208 uint8_t parsed_sha[SHA_DIGEST_SIZE];
209
210 // allocate enough memory to hold the largest size.
Tao Baoba9a42a2015-06-23 23:23:33 -0700211 file->data = reinterpret_cast<unsigned char*>(malloc(size[index[pairs-1]]));
Doug Zongkerc4351c72010-02-22 14:46:32 -0800212 char* p = (char*)file->data;
213 file->size = 0; // # bytes read so far
214
215 for (i = 0; i < pairs; ++i) {
216 // Read enough additional bytes to get us up to the next size
217 // (again, we're trying the possibilities in order of increasing
218 // size).
219 size_t next = size[index[i]] - file->size;
220 size_t read = 0;
221 if (next > 0) {
Doug Zongkerf291d852010-07-07 13:55:25 -0700222 switch (type) {
223 case MTD:
224 read = mtd_read_data(ctx, p, next);
225 break;
226
227 case EMMC:
228 read = fread(p, 1, next, dev);
229 break;
230 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800231 if (next != read) {
Mark Salyzynf3bb31c2014-03-14 09:39:48 -0700232 printf("short read (%zu bytes of %zu) for partition \"%s\"\n",
Doug Zongkerc4351c72010-02-22 14:46:32 -0800233 read, next, partition);
234 free(file->data);
235 file->data = NULL;
236 return -1;
237 }
238 SHA_update(&sha_ctx, p, read);
239 file->size += read;
240 }
241
242 // Duplicate the SHA context and finalize the duplicate so we can
243 // check it against this pair's expected hash.
244 SHA_CTX temp_ctx;
245 memcpy(&temp_ctx, &sha_ctx, sizeof(SHA_CTX));
246 const uint8_t* sha_so_far = SHA_final(&temp_ctx);
247
248 if (ParseSha1(sha1sum[index[i]], parsed_sha) != 0) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700249 printf("failed to parse sha1 %s in %s\n", sha1sum[index[i]], filename);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800250 free(file->data);
251 file->data = NULL;
252 return -1;
253 }
254
255 if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_SIZE) == 0) {
256 // we have a match. stop reading the partition; we'll return
257 // the data we've read so far.
Mark Salyzynf3bb31c2014-03-14 09:39:48 -0700258 printf("partition read matched size %zu sha %s\n",
Doug Zongkerc4351c72010-02-22 14:46:32 -0800259 size[index[i]], sha1sum[index[i]]);
260 break;
261 }
262
263 p += read;
264 }
265
Doug Zongkerf291d852010-07-07 13:55:25 -0700266 switch (type) {
267 case MTD:
268 mtd_read_close(ctx);
269 break;
270
271 case EMMC:
272 fclose(dev);
273 break;
274 }
275
Doug Zongkerc4351c72010-02-22 14:46:32 -0800276
277 if (i == pairs) {
278 // Ran off the end of the list of (size,sha1) pairs without
279 // finding a match.
Tao Baoba9a42a2015-06-23 23:23:33 -0700280 printf("contents of partition \"%s\" didn't match %s\n", partition, filename);
Doug Zongker512536a2010-02-17 16:11:44 -0800281 free(file->data);
282 file->data = NULL;
283 return -1;
Doug Zongker512536a2010-02-17 16:11:44 -0800284 }
285
Doug Zongkerc4351c72010-02-22 14:46:32 -0800286 const uint8_t* sha_final = SHA_final(&sha_ctx);
Tao Baoba9a42a2015-06-23 23:23:33 -0700287 for (size_t i = 0; i < SHA_DIGEST_SIZE; ++i) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800288 file->sha1[i] = sha_final[i];
Doug Zongker512536a2010-02-17 16:11:44 -0800289 }
290
Doug Zongkerc4351c72010-02-22 14:46:32 -0800291 // Fake some stat() info.
292 file->st.st_mode = 0644;
293 file->st.st_uid = 0;
294 file->st.st_gid = 0;
Doug Zongker512536a2010-02-17 16:11:44 -0800295
Doug Zongkerc4351c72010-02-22 14:46:32 -0800296 free(copy);
297 free(index);
298 free(size);
299 free(sha1sum);
Doug Zongker512536a2010-02-17 16:11:44 -0800300
Doug Zongkerc4351c72010-02-22 14:46:32 -0800301 return 0;
Doug Zongker512536a2010-02-17 16:11:44 -0800302}
303
304
305// Save the contents of the given FileContents object under the given
306// filename. Return 0 on success.
Doug Zongker1c43c972012-02-28 11:07:09 -0800307int SaveFileContents(const char* filename, const FileContents* file) {
Michael Rungebe81e512014-10-29 12:42:15 -0700308 int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800309 if (fd < 0) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700310 printf("failed to open \"%s\" for write: %s\n", filename, strerror(errno));
Doug Zongkerc4351c72010-02-22 14:46:32 -0800311 return -1;
312 }
Doug Zongker512536a2010-02-17 16:11:44 -0800313
Doug Zongker1c43c972012-02-28 11:07:09 -0800314 ssize_t bytes_written = FileSink(file->data, file->size, &fd);
315 if (bytes_written != file->size) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700316 printf("short write of \"%s\" (%zd bytes of %zd) (%s)\n",
317 filename, bytes_written, file->size, strerror(errno));
Doug Zongkerc4351c72010-02-22 14:46:32 -0800318 close(fd);
319 return -1;
320 }
Michael Rungebe81e512014-10-29 12:42:15 -0700321 if (fsync(fd) != 0) {
322 printf("fsync of \"%s\" failed: %s\n", filename, strerror(errno));
323 return -1;
324 }
325 if (close(fd) != 0) {
326 printf("close of \"%s\" failed: %s\n", filename, strerror(errno));
327 return -1;
328 }
Doug Zongker512536a2010-02-17 16:11:44 -0800329
Doug Zongker1c43c972012-02-28 11:07:09 -0800330 if (chmod(filename, file->st.st_mode) != 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800331 printf("chmod of \"%s\" failed: %s\n", filename, strerror(errno));
332 return -1;
333 }
Doug Zongker1c43c972012-02-28 11:07:09 -0800334 if (chown(filename, file->st.st_uid, file->st.st_gid) != 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800335 printf("chown of \"%s\" failed: %s\n", filename, strerror(errno));
336 return -1;
337 }
Doug Zongker512536a2010-02-17 16:11:44 -0800338
Doug Zongkerc4351c72010-02-22 14:46:32 -0800339 return 0;
Doug Zongker512536a2010-02-17 16:11:44 -0800340}
341
Doug Zongkerf291d852010-07-07 13:55:25 -0700342// Write a memory buffer to 'target' partition, a string of the form
343// "MTD:<partition>[:...]" or "EMMC:<partition_device>:". Return 0 on
344// success.
Tao Baoba9a42a2015-06-23 23:23:33 -0700345int WriteToPartition(unsigned char* data, size_t len, const char* target) {
Doug Zongkerf291d852010-07-07 13:55:25 -0700346 char* copy = strdup(target);
347 const char* magic = strtok(copy, ":");
348
349 enum PartitionType type;
350 if (strcmp(magic, "MTD") == 0) {
351 type = MTD;
352 } else if (strcmp(magic, "EMMC") == 0) {
353 type = EMMC;
354 } else {
355 printf("WriteToPartition called with bad target (%s)\n", target);
356 return -1;
357 }
358 const char* partition = strtok(NULL, ":");
359
Doug Zongkerc4351c72010-02-22 14:46:32 -0800360 if (partition == NULL) {
Doug Zongkerf291d852010-07-07 13:55:25 -0700361 printf("bad partition target name \"%s\"\n", target);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800362 return -1;
363 }
Doug Zongker512536a2010-02-17 16:11:44 -0800364
Doug Zongkerf291d852010-07-07 13:55:25 -0700365 switch (type) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700366 case MTD: {
Doug Zongkerf291d852010-07-07 13:55:25 -0700367 if (!mtd_partitions_scanned) {
368 mtd_scan_partitions();
369 mtd_partitions_scanned = 1;
370 }
371
372 const MtdPartition* mtd = mtd_find_partition_by_name(partition);
373 if (mtd == NULL) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700374 printf("mtd partition \"%s\" not found for writing\n", partition);
Doug Zongkerf291d852010-07-07 13:55:25 -0700375 return -1;
376 }
377
378 MtdWriteContext* ctx = mtd_write_partition(mtd);
379 if (ctx == NULL) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700380 printf("failed to init mtd partition \"%s\" for writing\n", partition);
Doug Zongkerf291d852010-07-07 13:55:25 -0700381 return -1;
382 }
383
Tao Baoba9a42a2015-06-23 23:23:33 -0700384 size_t written = mtd_write_data(ctx, reinterpret_cast<char*>(data), len);
Doug Zongkerf291d852010-07-07 13:55:25 -0700385 if (written != len) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700386 printf("only wrote %zu of %zu bytes to MTD %s\n", written, len, partition);
Doug Zongkerf291d852010-07-07 13:55:25 -0700387 mtd_write_close(ctx);
388 return -1;
389 }
390
391 if (mtd_erase_blocks(ctx, -1) < 0) {
392 printf("error finishing mtd write of %s\n", partition);
393 mtd_write_close(ctx);
394 return -1;
395 }
396
397 if (mtd_write_close(ctx)) {
398 printf("error closing mtd write of %s\n", partition);
399 return -1;
400 }
401 break;
Tao Baoba9a42a2015-06-23 23:23:33 -0700402 }
Doug Zongkerf291d852010-07-07 13:55:25 -0700403
Tao Baoba9a42a2015-06-23 23:23:33 -0700404 case EMMC: {
Doug Zongker044a0b42013-07-08 09:42:54 -0700405 size_t start = 0;
Tao Baoba9a42a2015-06-23 23:23:33 -0700406 bool success = false;
Michael Rungebe81e512014-10-29 12:42:15 -0700407 int fd = open(partition, O_RDWR | O_SYNC);
Doug Zongkerc870a992013-07-09 10:34:46 -0700408 if (fd < 0) {
Doug Zongker044a0b42013-07-08 09:42:54 -0700409 printf("failed to open %s: %s\n", partition, strerror(errno));
Doug Zongkerf291d852010-07-07 13:55:25 -0700410 return -1;
411 }
Doug Zongker044a0b42013-07-08 09:42:54 -0700412
Tao Baoba9a42a2015-06-23 23:23:33 -0700413 for (int attempt = 0; attempt < 2; ++attempt) {
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700414 if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700415 printf("failed seek on %s: %s\n", partition, strerror(errno));
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700416 return -1;
417 }
Doug Zongker044a0b42013-07-08 09:42:54 -0700418 while (start < len) {
419 size_t to_write = len - start;
Doug Zongker168724c2013-12-19 15:16:57 -0800420 if (to_write > 1<<20) to_write = 1<<20;
Doug Zongker044a0b42013-07-08 09:42:54 -0700421
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700422 ssize_t written = TEMP_FAILURE_RETRY(write(fd, data+start, to_write));
423 if (written == -1) {
424 printf("failed write writing to %s: %s\n", partition, strerror(errno));
425 return -1;
Doug Zongker044a0b42013-07-08 09:42:54 -0700426 }
Doug Zongkerc870a992013-07-09 10:34:46 -0700427 start += written;
Doug Zongker044a0b42013-07-08 09:42:54 -0700428 }
Michael Rungebe81e512014-10-29 12:42:15 -0700429 if (fsync(fd) != 0) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700430 printf("failed to sync to %s (%s)\n", partition, strerror(errno));
Michael Rungebe81e512014-10-29 12:42:15 -0700431 return -1;
432 }
433 if (close(fd) != 0) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700434 printf("failed to close %s (%s)\n", partition, strerror(errno));
Michael Rungebe81e512014-10-29 12:42:15 -0700435 return -1;
436 }
437 fd = open(partition, O_RDONLY);
438 if (fd < 0) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700439 printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno));
Michael Rungebe81e512014-10-29 12:42:15 -0700440 return -1;
441 }
Doug Zongker044a0b42013-07-08 09:42:54 -0700442
Tao Baoba9a42a2015-06-23 23:23:33 -0700443 // Drop caches so our subsequent verification read
Doug Zongker044a0b42013-07-08 09:42:54 -0700444 // won't just be reading the cache.
445 sync();
Doug Zongkerc870a992013-07-09 10:34:46 -0700446 int dc = open("/proc/sys/vm/drop_caches", O_WRONLY);
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700447 if (TEMP_FAILURE_RETRY(write(dc, "3\n", 2)) == -1) {
448 printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno));
449 } else {
450 printf(" caches dropped\n");
451 }
Doug Zongkerc870a992013-07-09 10:34:46 -0700452 close(dc);
Doug Zongker044a0b42013-07-08 09:42:54 -0700453 sleep(1);
Doug Zongker044a0b42013-07-08 09:42:54 -0700454
455 // verify
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700456 if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) {
457 printf("failed to seek back to beginning of %s: %s\n",
458 partition, strerror(errno));
459 return -1;
460 }
Doug Zongker044a0b42013-07-08 09:42:54 -0700461 unsigned char buffer[4096];
462 start = len;
Tao Baoba9a42a2015-06-23 23:23:33 -0700463 for (size_t p = 0; p < len; p += sizeof(buffer)) {
Doug Zongker044a0b42013-07-08 09:42:54 -0700464 size_t to_read = len - p;
Tao Baoba9a42a2015-06-23 23:23:33 -0700465 if (to_read > sizeof(buffer)) {
466 to_read = sizeof(buffer);
467 }
Doug Zongker044a0b42013-07-08 09:42:54 -0700468
Doug Zongkerc870a992013-07-09 10:34:46 -0700469 size_t so_far = 0;
470 while (so_far < to_read) {
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700471 ssize_t read_count =
472 TEMP_FAILURE_RETRY(read(fd, buffer+so_far, to_read-so_far));
473 if (read_count == -1) {
474 printf("verify read error %s at %zu: %s\n",
475 partition, p, strerror(errno));
476 return -1;
Doug Zongkerc870a992013-07-09 10:34:46 -0700477 }
Tao Baoba9a42a2015-06-23 23:23:33 -0700478 if (static_cast<size_t>(read_count) < to_read) {
Mark Salyzynf3bb31c2014-03-14 09:39:48 -0700479 printf("short verify read %s at %zu: %zd %zu %s\n",
Doug Zongkerc870a992013-07-09 10:34:46 -0700480 partition, p, read_count, to_read, strerror(errno));
481 }
482 so_far += read_count;
Doug Zongker044a0b42013-07-08 09:42:54 -0700483 }
484
Tao Baoba9a42a2015-06-23 23:23:33 -0700485 if (memcmp(buffer, data+p, to_read) != 0) {
Mark Salyzynf3bb31c2014-03-14 09:39:48 -0700486 printf("verification failed starting at %zu\n", p);
Doug Zongker044a0b42013-07-08 09:42:54 -0700487 start = p;
488 break;
489 }
490 }
491
492 if (start == len) {
493 printf("verification read succeeded (attempt %d)\n", attempt+1);
494 success = true;
495 break;
496 }
497 }
498
499 if (!success) {
500 printf("failed to verify after all attempts\n");
501 return -1;
502 }
503
Doug Zongkerc870a992013-07-09 10:34:46 -0700504 if (close(fd) != 0) {
Doug Zongkerf291d852010-07-07 13:55:25 -0700505 printf("error closing %s (%s)\n", partition, strerror(errno));
506 return -1;
507 }
Doug Zongkerbf4a69a2013-07-10 13:39:50 -0700508 sync();
Doug Zongkerf291d852010-07-07 13:55:25 -0700509 break;
Doug Zongker044a0b42013-07-08 09:42:54 -0700510 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800511 }
Doug Zongker512536a2010-02-17 16:11:44 -0800512
Doug Zongkerf291d852010-07-07 13:55:25 -0700513 free(copy);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800514 return 0;
Doug Zongker512536a2010-02-17 16:11:44 -0800515}
516
517
518// Take a string 'str' of 40 hex digits and parse it into the 20
519// byte array 'digest'. 'str' may contain only the digest or be of
520// the form "<digest>:<anything>". Return 0 on success, -1 on any
521// error.
522int ParseSha1(const char* str, uint8_t* digest) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800523 const char* ps = str;
524 uint8_t* pd = digest;
Tao Baoba9a42a2015-06-23 23:23:33 -0700525 for (int i = 0; i < SHA_DIGEST_SIZE * 2; ++i, ++ps) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800526 int digit;
527 if (*ps >= '0' && *ps <= '9') {
528 digit = *ps - '0';
529 } else if (*ps >= 'a' && *ps <= 'f') {
530 digit = *ps - 'a' + 10;
531 } else if (*ps >= 'A' && *ps <= 'F') {
532 digit = *ps - 'A' + 10;
533 } else {
534 return -1;
535 }
536 if (i % 2 == 0) {
537 *pd = digit << 4;
538 } else {
539 *pd |= digit;
540 ++pd;
541 }
Doug Zongker512536a2010-02-17 16:11:44 -0800542 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800543 if (*ps != '\0') return -1;
544 return 0;
Doug Zongker512536a2010-02-17 16:11:44 -0800545}
546
Doug Zongkerc4351c72010-02-22 14:46:32 -0800547// Search an array of sha1 strings for one matching the given sha1.
548// Return the index of the match on success, or -1 if no match is
549// found.
Doug Zongker044a0b42013-07-08 09:42:54 -0700550int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str,
Doug Zongkerc4351c72010-02-22 14:46:32 -0800551 int num_patches) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800552 uint8_t patch_sha1[SHA_DIGEST_SIZE];
Tao Baoba9a42a2015-06-23 23:23:33 -0700553 for (int i = 0; i < num_patches; ++i) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800554 if (ParseSha1(patch_sha1_str[i], patch_sha1) == 0 &&
555 memcmp(patch_sha1, sha1, SHA_DIGEST_SIZE) == 0) {
556 return i;
557 }
Doug Zongker512536a2010-02-17 16:11:44 -0800558 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800559 return -1;
Doug Zongker512536a2010-02-17 16:11:44 -0800560}
561
562// Returns 0 if the contents of the file (argv[2]) or the cached file
563// match any of the sha1's on the command line (argv[3:]). Returns
564// nonzero otherwise.
Tao Baoba9a42a2015-06-23 23:23:33 -0700565int applypatch_check(const char* filename, int num_patches,
566 char** const patch_sha1_str) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800567 FileContents file;
568 file.data = NULL;
Doug Zongker512536a2010-02-17 16:11:44 -0800569
Doug Zongkerc4351c72010-02-22 14:46:32 -0800570 // It's okay to specify no sha1s; the check will pass if the
Doug Zongkerf291d852010-07-07 13:55:25 -0700571 // LoadFileContents is successful. (Useful for reading
Doug Zongkerc4351c72010-02-22 14:46:32 -0800572 // partitions, where the filename encodes the sha1s; no need to
573 // check them twice.)
Doug Zongkera1bc1482014-02-13 15:18:19 -0800574 if (LoadFileContents(filename, &file) != 0 ||
Doug Zongkerc4351c72010-02-22 14:46:32 -0800575 (num_patches > 0 &&
576 FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0)) {
577 printf("file \"%s\" doesn't have any of expected "
578 "sha1 sums; checking cache\n", filename);
Doug Zongker512536a2010-02-17 16:11:44 -0800579
Doug Zongkerc4351c72010-02-22 14:46:32 -0800580 free(file.data);
Doug Zongker1c43c972012-02-28 11:07:09 -0800581 file.data = NULL;
Doug Zongker512536a2010-02-17 16:11:44 -0800582
Doug Zongkerc4351c72010-02-22 14:46:32 -0800583 // If the source file is missing or corrupted, it might be because
584 // we were killed in the middle of patching it. A copy of it
585 // should have been made in CACHE_TEMP_SOURCE. If that file
586 // exists and matches the sha1 we're looking for, the check still
587 // passes.
588
Doug Zongkera1bc1482014-02-13 15:18:19 -0800589 if (LoadFileContents(CACHE_TEMP_SOURCE, &file) != 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800590 printf("failed to load cache file\n");
591 return 1;
592 }
593
594 if (FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0) {
595 printf("cache bits don't match any sha1 for \"%s\"\n", filename);
596 free(file.data);
597 return 1;
598 }
599 }
Doug Zongker512536a2010-02-17 16:11:44 -0800600
601 free(file.data);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800602 return 0;
Doug Zongker512536a2010-02-17 16:11:44 -0800603}
604
605int ShowLicenses() {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800606 ShowBSDiffLicense();
607 return 0;
Doug Zongker512536a2010-02-17 16:11:44 -0800608}
609
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700610ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700611 int fd = *reinterpret_cast<int *>(token);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800612 ssize_t done = 0;
613 ssize_t wrote;
Tao Baoba9a42a2015-06-23 23:23:33 -0700614 while (done < len) {
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700615 wrote = TEMP_FAILURE_RETRY(write(fd, data+done, len-done));
616 if (wrote == -1) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700617 printf("error writing %zd bytes: %s\n", (len-done), strerror(errno));
Doug Zongkerc4351c72010-02-22 14:46:32 -0800618 return done;
619 }
620 done += wrote;
Doug Zongker512536a2010-02-17 16:11:44 -0800621 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800622 return done;
Doug Zongker512536a2010-02-17 16:11:44 -0800623}
624
625typedef struct {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800626 unsigned char* buffer;
627 ssize_t size;
628 ssize_t pos;
Doug Zongker512536a2010-02-17 16:11:44 -0800629} MemorySinkInfo;
630
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700631ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700632 MemorySinkInfo* msi = reinterpret_cast<MemorySinkInfo*>(token);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800633 if (msi->size - msi->pos < len) {
634 return -1;
635 }
636 memcpy(msi->buffer + msi->pos, data, len);
637 msi->pos += len;
638 return len;
Doug Zongker512536a2010-02-17 16:11:44 -0800639}
640
641// Return the amount of free space (in bytes) on the filesystem
642// containing filename. filename must exist. Return -1 on error.
643size_t FreeSpaceForFile(const char* filename) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800644 struct statfs sf;
645 if (statfs(filename, &sf) != 0) {
646 printf("failed to statfs %s: %s\n", filename, strerror(errno));
647 return -1;
648 }
caozhiyuan3b497762015-05-19 17:21:00 +0800649 return sf.f_bsize * sf.f_bavail;
Doug Zongker512536a2010-02-17 16:11:44 -0800650}
651
Doug Zongkerc4351c72010-02-22 14:46:32 -0800652int CacheSizeCheck(size_t bytes) {
653 if (MakeFreeSpaceOnCache(bytes) < 0) {
654 printf("unable to make %ld bytes available on /cache\n", (long)bytes);
655 return 1;
656 } else {
657 return 0;
658 }
659}
660
Doug Zongkerbf80f492012-10-19 12:24:26 -0700661static void print_short_sha1(const uint8_t sha1[SHA_DIGEST_SIZE]) {
Doug Zongkerbf80f492012-10-19 12:24:26 -0700662 const char* hex = "0123456789abcdef";
Tao Baoba9a42a2015-06-23 23:23:33 -0700663 for (size_t i = 0; i < 4; ++i) {
Doug Zongkerbf80f492012-10-19 12:24:26 -0700664 putchar(hex[(sha1[i]>>4) & 0xf]);
665 putchar(hex[sha1[i] & 0xf]);
666 }
667}
Doug Zongkerc4351c72010-02-22 14:46:32 -0800668
669// This function applies binary patches to files in a way that is safe
Doug Zongker512536a2010-02-17 16:11:44 -0800670// (the original file is not touched until we have the desired
671// replacement for it) and idempotent (it's okay to run this program
672// multiple times).
673//
Doug Zongkerc4351c72010-02-22 14:46:32 -0800674// - if the sha1 hash of <target_filename> is <target_sha1_string>,
675// does nothing and exits successfully.
Doug Zongker512536a2010-02-17 16:11:44 -0800676//
Doug Zongkerc4351c72010-02-22 14:46:32 -0800677// - otherwise, if the sha1 hash of <source_filename> is one of the
678// entries in <patch_sha1_str>, the corresponding patch from
679// <patch_data> (which must be a VAL_BLOB) is applied to produce a
680// new file (the type of patch is automatically detected from the
681// blob daat). If that new file has sha1 hash <target_sha1_str>,
682// moves it to replace <target_filename>, and exits successfully.
683// Note that if <source_filename> and <target_filename> are not the
684// same, <source_filename> is NOT deleted on success.
685// <target_filename> may be the string "-" to mean "the same as
686// source_filename".
Doug Zongker512536a2010-02-17 16:11:44 -0800687//
688// - otherwise, or if any error is encountered, exits with non-zero
689// status.
690//
Doug Zongkerf291d852010-07-07 13:55:25 -0700691// <source_filename> may refer to a partition to read the source data.
692// See the comments for the LoadPartition Contents() function above
Doug Zongkerc4351c72010-02-22 14:46:32 -0800693// for the format of such a filename.
Doug Zongker512536a2010-02-17 16:11:44 -0800694
Doug Zongkerc4351c72010-02-22 14:46:32 -0800695int applypatch(const char* source_filename,
696 const char* target_filename,
697 const char* target_sha1_str,
698 size_t target_size,
699 int num_patches,
700 char** const patch_sha1_str,
Doug Zongkera3ccba62012-08-20 15:28:02 -0700701 Value** patch_data,
702 Value* bonus_data) {
Doug Zongkerbf80f492012-10-19 12:24:26 -0700703 printf("patch %s: ", source_filename);
Doug Zongker512536a2010-02-17 16:11:44 -0800704
Tao Baoba9a42a2015-06-23 23:23:33 -0700705 if (target_filename[0] == '-' && target_filename[1] == '\0') {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800706 target_filename = source_filename;
Doug Zongker512536a2010-02-17 16:11:44 -0800707 }
708
Doug Zongkerc4351c72010-02-22 14:46:32 -0800709 uint8_t target_sha1[SHA_DIGEST_SIZE];
710 if (ParseSha1(target_sha1_str, target_sha1) != 0) {
711 printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str);
Doug Zongker512536a2010-02-17 16:11:44 -0800712 return 1;
Doug Zongkerc4351c72010-02-22 14:46:32 -0800713 }
Doug Zongker512536a2010-02-17 16:11:44 -0800714
Doug Zongkerc4351c72010-02-22 14:46:32 -0800715 FileContents copy_file;
716 FileContents source_file;
Doug Zongker1c43c972012-02-28 11:07:09 -0800717 copy_file.data = NULL;
718 source_file.data = NULL;
Doug Zongkerc4351c72010-02-22 14:46:32 -0800719 const Value* source_patch_value = NULL;
720 const Value* copy_patch_value = NULL;
Doug Zongker512536a2010-02-17 16:11:44 -0800721
Doug Zongkerc4351c72010-02-22 14:46:32 -0800722 // We try to load the target file into the source_file object.
Doug Zongkera1bc1482014-02-13 15:18:19 -0800723 if (LoadFileContents(target_filename, &source_file) == 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800724 if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) {
725 // The early-exit case: the patch was already applied, this file
726 // has the desired hash, nothing for us to do.
Doug Zongkerbf80f492012-10-19 12:24:26 -0700727 printf("already ");
728 print_short_sha1(target_sha1);
729 putchar('\n');
Doug Zongker1c43c972012-02-28 11:07:09 -0800730 free(source_file.data);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800731 return 0;
732 }
733 }
Doug Zongker512536a2010-02-17 16:11:44 -0800734
Doug Zongkerc4351c72010-02-22 14:46:32 -0800735 if (source_file.data == NULL ||
736 (target_filename != source_filename &&
737 strcmp(target_filename, source_filename) != 0)) {
738 // Need to load the source file: either we failed to load the
739 // target file, or we did but it's different from the source file.
740 free(source_file.data);
Doug Zongker1c43c972012-02-28 11:07:09 -0800741 source_file.data = NULL;
Doug Zongkera1bc1482014-02-13 15:18:19 -0800742 LoadFileContents(source_filename, &source_file);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800743 }
744
745 if (source_file.data != NULL) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700746 int to_use = FindMatchingPatch(source_file.sha1, patch_sha1_str, num_patches);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800747 if (to_use >= 0) {
748 source_patch_value = patch_data[to_use];
749 }
750 }
751
752 if (source_patch_value == NULL) {
753 free(source_file.data);
Doug Zongker1c43c972012-02-28 11:07:09 -0800754 source_file.data = NULL;
Doug Zongkerc4351c72010-02-22 14:46:32 -0800755 printf("source file is bad; trying copy\n");
756
Doug Zongkera1bc1482014-02-13 15:18:19 -0800757 if (LoadFileContents(CACHE_TEMP_SOURCE, &copy_file) < 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800758 // fail.
759 printf("failed to read copy file\n");
760 return 1;
Doug Zongker512536a2010-02-17 16:11:44 -0800761 }
762
Tao Baoba9a42a2015-06-23 23:23:33 -0700763 int to_use = FindMatchingPatch(copy_file.sha1, patch_sha1_str, num_patches);
Doug Zongker8cd9e4f2010-08-12 17:38:09 -0700764 if (to_use >= 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800765 copy_patch_value = patch_data[to_use];
Doug Zongker512536a2010-02-17 16:11:44 -0800766 }
767
Doug Zongkerc4351c72010-02-22 14:46:32 -0800768 if (copy_patch_value == NULL) {
769 // fail.
770 printf("copy file doesn't match source SHA-1s either\n");
Doug Zongker1c43c972012-02-28 11:07:09 -0800771 free(copy_file.data);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800772 return 1;
Doug Zongker512536a2010-02-17 16:11:44 -0800773 }
Doug Zongker512536a2010-02-17 16:11:44 -0800774 }
775
Doug Zongker1c43c972012-02-28 11:07:09 -0800776 int result = GenerateTarget(&source_file, source_patch_value,
777 &copy_file, copy_patch_value,
778 source_filename, target_filename,
Doug Zongkera3ccba62012-08-20 15:28:02 -0700779 target_sha1, target_size, bonus_data);
Doug Zongker1c43c972012-02-28 11:07:09 -0800780 free(source_file.data);
781 free(copy_file.data);
782
783 return result;
784}
785
786static int GenerateTarget(FileContents* source_file,
787 const Value* source_patch_value,
788 FileContents* copy_file,
789 const Value* copy_patch_value,
790 const char* source_filename,
791 const char* target_filename,
792 const uint8_t target_sha1[SHA_DIGEST_SIZE],
Doug Zongkera3ccba62012-08-20 15:28:02 -0700793 size_t target_size,
794 const Value* bonus_data) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800795 int retry = 1;
796 SHA_CTX ctx;
797 int output;
798 MemorySinkInfo msi;
799 FileContents* source_to_use;
800 char* outname;
Doug Zongker1c43c972012-02-28 11:07:09 -0800801 int made_copy = 0;
Doug Zongkerc4351c72010-02-22 14:46:32 -0800802
803 // assume that target_filename (eg "/system/app/Foo.apk") is located
804 // on the same filesystem as its top-level directory ("/system").
805 // We need something that exists for calling statfs().
806 char target_fs[strlen(target_filename)+1];
807 char* slash = strchr(target_filename+1, '/');
808 if (slash != NULL) {
809 int count = slash - target_filename;
810 strncpy(target_fs, target_filename, count);
811 target_fs[count] = '\0';
Doug Zongker512536a2010-02-17 16:11:44 -0800812 } else {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800813 strcpy(target_fs, target_filename);
Doug Zongker512536a2010-02-17 16:11:44 -0800814 }
815
Doug Zongkerc4351c72010-02-22 14:46:32 -0800816 do {
817 // Is there enough room in the target filesystem to hold the patched
818 // file?
819
Doug Zongkerf291d852010-07-07 13:55:25 -0700820 if (strncmp(target_filename, "MTD:", 4) == 0 ||
821 strncmp(target_filename, "EMMC:", 5) == 0) {
822 // If the target is a partition, we're actually going to
823 // write the output to /tmp and then copy it to the
824 // partition. statfs() always returns 0 blocks free for
825 // /tmp, so instead we'll just assume that /tmp has enough
826 // space to hold the file.
Doug Zongkerc4351c72010-02-22 14:46:32 -0800827
Doug Zongkerf291d852010-07-07 13:55:25 -0700828 // We still write the original source to cache, in case
829 // the partition write is interrupted.
Doug Zongker1c43c972012-02-28 11:07:09 -0800830 if (MakeFreeSpaceOnCache(source_file->size) < 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800831 printf("not enough free space on /cache\n");
832 return 1;
833 }
834 if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
835 printf("failed to back up source file\n");
836 return 1;
837 }
838 made_copy = 1;
839 retry = 0;
840 } else {
841 int enough_space = 0;
842 if (retry > 0) {
843 size_t free_space = FreeSpaceForFile(target_fs);
Doug Zongker201cd462010-08-13 09:41:21 -0700844 enough_space =
845 (free_space > (256 << 10)) && // 256k (two-block) minimum
Doug Zongkerc4351c72010-02-22 14:46:32 -0800846 (free_space > (target_size * 3 / 2)); // 50% margin of error
Doug Zongkerbf80f492012-10-19 12:24:26 -0700847 if (!enough_space) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700848 printf("target %zu bytes; free space %zu bytes; retry %d; enough %d\n",
849 target_size, free_space, retry, enough_space);
Doug Zongkerbf80f492012-10-19 12:24:26 -0700850 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800851 }
852
853 if (!enough_space) {
854 retry = 0;
855 }
856
857 if (!enough_space && source_patch_value != NULL) {
858 // Using the original source, but not enough free space. First
859 // copy the source file to cache, then delete it from the original
860 // location.
861
Doug Zongkerf291d852010-07-07 13:55:25 -0700862 if (strncmp(source_filename, "MTD:", 4) == 0 ||
863 strncmp(source_filename, "EMMC:", 5) == 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800864 // It's impossible to free space on the target filesystem by
Doug Zongkerf291d852010-07-07 13:55:25 -0700865 // deleting the source if the source is a partition. If
Doug Zongkerc4351c72010-02-22 14:46:32 -0800866 // we're ever in a state where we need to do this, fail.
Tao Baoba9a42a2015-06-23 23:23:33 -0700867 printf("not enough free space for target but source is partition\n");
Doug Zongkerc4351c72010-02-22 14:46:32 -0800868 return 1;
869 }
870
Doug Zongker1c43c972012-02-28 11:07:09 -0800871 if (MakeFreeSpaceOnCache(source_file->size) < 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800872 printf("not enough free space on /cache\n");
873 return 1;
874 }
875
876 if (SaveFileContents(CACHE_TEMP_SOURCE, source_file) < 0) {
877 printf("failed to back up source file\n");
878 return 1;
879 }
880 made_copy = 1;
881 unlink(source_filename);
882
883 size_t free_space = FreeSpaceForFile(target_fs);
Tao Baoba9a42a2015-06-23 23:23:33 -0700884 printf("(now %zu bytes free for target) ", free_space);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800885 }
886 }
887
888 const Value* patch;
889 if (source_patch_value != NULL) {
Doug Zongker1c43c972012-02-28 11:07:09 -0800890 source_to_use = source_file;
Doug Zongkerc4351c72010-02-22 14:46:32 -0800891 patch = source_patch_value;
892 } else {
Doug Zongker1c43c972012-02-28 11:07:09 -0800893 source_to_use = copy_file;
Doug Zongkerc4351c72010-02-22 14:46:32 -0800894 patch = copy_patch_value;
895 }
896
897 if (patch->type != VAL_BLOB) {
898 printf("patch is not a blob\n");
899 return 1;
900 }
901
902 SinkFn sink = NULL;
903 void* token = NULL;
904 output = -1;
905 outname = NULL;
Doug Zongkerf291d852010-07-07 13:55:25 -0700906 if (strncmp(target_filename, "MTD:", 4) == 0 ||
907 strncmp(target_filename, "EMMC:", 5) == 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800908 // We store the decoded output in memory.
Tao Baoba9a42a2015-06-23 23:23:33 -0700909 msi.buffer = reinterpret_cast<unsigned char*>(malloc(target_size));
Doug Zongkerc4351c72010-02-22 14:46:32 -0800910 if (msi.buffer == NULL) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700911 printf("failed to alloc %zu bytes for output\n", target_size);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800912 return 1;
913 }
914 msi.pos = 0;
915 msi.size = target_size;
916 sink = MemorySink;
917 token = &msi;
918 } else {
919 // We write the decoded output to "<tgt-file>.patch".
Tao Baoba9a42a2015-06-23 23:23:33 -0700920 outname = reinterpret_cast<char*>(malloc(strlen(target_filename) + 10));
Doug Zongkerc4351c72010-02-22 14:46:32 -0800921 strcpy(outname, target_filename);
922 strcat(outname, ".patch");
923
Tao Baoba9a42a2015-06-23 23:23:33 -0700924 output = open(outname, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800925 if (output < 0) {
926 printf("failed to open output file %s: %s\n",
927 outname, strerror(errno));
928 return 1;
929 }
930 sink = FileSink;
931 token = &output;
932 }
933
934 char* header = patch->data;
935 ssize_t header_bytes_read = patch->size;
936
937 SHA_init(&ctx);
938
939 int result;
940
941 if (header_bytes_read >= 8 &&
942 memcmp(header, "BSDIFF40", 8) == 0) {
943 result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size,
944 patch, 0, sink, token, &ctx);
945 } else if (header_bytes_read >= 8 &&
946 memcmp(header, "IMGDIFF2", 8) == 0) {
947 result = ApplyImagePatch(source_to_use->data, source_to_use->size,
Doug Zongkera3ccba62012-08-20 15:28:02 -0700948 patch, sink, token, &ctx, bonus_data);
Doug Zongkerc4351c72010-02-22 14:46:32 -0800949 } else {
950 printf("Unknown patch file format\n");
951 return 1;
952 }
953
954 if (output >= 0) {
Michael Rungebe81e512014-10-29 12:42:15 -0700955 if (fsync(output) != 0) {
956 printf("failed to fsync file \"%s\" (%s)\n", outname, strerror(errno));
957 result = 1;
958 }
959 if (close(output) != 0) {
960 printf("failed to close file \"%s\" (%s)\n", outname, strerror(errno));
961 result = 1;
962 }
Doug Zongkerc4351c72010-02-22 14:46:32 -0800963 }
964
965 if (result != 0) {
966 if (retry == 0) {
967 printf("applying patch failed\n");
968 return result != 0;
969 } else {
970 printf("applying patch failed; retrying\n");
971 }
972 if (outname != NULL) {
973 unlink(outname);
974 }
975 } else {
976 // succeeded; no need to retry
977 break;
978 }
979 } while (retry-- > 0);
980
981 const uint8_t* current_target_sha1 = SHA_final(&ctx);
982 if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 0) {
983 printf("patch did not produce expected sha1\n");
Doug Zongker512536a2010-02-17 16:11:44 -0800984 return 1;
Doug Zongkerbf80f492012-10-19 12:24:26 -0700985 } else {
986 printf("now ");
987 print_short_sha1(target_sha1);
988 putchar('\n');
Doug Zongkerc4351c72010-02-22 14:46:32 -0800989 }
990
991 if (output < 0) {
Doug Zongkerf291d852010-07-07 13:55:25 -0700992 // Copy the temp file to the partition.
993 if (WriteToPartition(msi.buffer, msi.pos, target_filename) != 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800994 printf("write of patched data to %s failed\n", target_filename);
995 return 1;
996 }
997 free(msi.buffer);
Doug Zongker512536a2010-02-17 16:11:44 -0800998 } else {
Doug Zongkerc4351c72010-02-22 14:46:32 -0800999 // Give the .patch file the same owner, group, and mode of the
1000 // original source file.
1001 if (chmod(outname, source_to_use->st.st_mode) != 0) {
1002 printf("chmod of \"%s\" failed: %s\n", outname, strerror(errno));
1003 return 1;
1004 }
Tao Baoba9a42a2015-06-23 23:23:33 -07001005 if (chown(outname, source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) {
Doug Zongkerc4351c72010-02-22 14:46:32 -08001006 printf("chown of \"%s\" failed: %s\n", outname, strerror(errno));
1007 return 1;
1008 }
Doug Zongker512536a2010-02-17 16:11:44 -08001009
Doug Zongkerc4351c72010-02-22 14:46:32 -08001010 // Finally, rename the .patch file to replace the target file.
1011 if (rename(outname, target_filename) != 0) {
Tao Baoba9a42a2015-06-23 23:23:33 -07001012 printf("rename of .patch to \"%s\" failed: %s\n", target_filename, strerror(errno));
Doug Zongkerc4351c72010-02-22 14:46:32 -08001013 return 1;
1014 }
Doug Zongker512536a2010-02-17 16:11:44 -08001015 }
1016
Doug Zongkerc4351c72010-02-22 14:46:32 -08001017 // If this run of applypatch created the copy, and we're here, we
1018 // can delete it.
Tao Baoba9a42a2015-06-23 23:23:33 -07001019 if (made_copy) {
1020 unlink(CACHE_TEMP_SOURCE);
1021 }
Doug Zongker512536a2010-02-17 16:11:44 -08001022
Doug Zongkerc4351c72010-02-22 14:46:32 -08001023 // Success!
1024 return 0;
Doug Zongker512536a2010-02-17 16:11:44 -08001025}