aboutsummaryrefslogtreecommitdiffstats
path: root/updater/install.c
diff options
context:
space:
mode:
authorDoug Zongker <dougz@android.com>2014-02-10 15:30:30 -0800
committerDoug Zongker <dougz@android.com>2014-02-13 14:15:26 -0800
commit52b4036eb820042d0309b32b579c52b63ca58b4d (patch)
tree8d922234a59cdf847fa8d7f71b20020c61038fa0 /updater/install.c
parenta9300301ce0bddb6f46e1e1a7499c13b615713c6 (diff)
downloadbootable_recovery-52b4036eb820042d0309b32b579c52b63ca58b4d.zip
bootable_recovery-52b4036eb820042d0309b32b579c52b63ca58b4d.tar.gz
bootable_recovery-52b4036eb820042d0309b32b579c52b63ca58b4d.tar.bz2
add syspatch support to updater
Add the syspatch() function, which can apply xdelta3+xz patches using the libsyspatch library. Change-Id: Idc1921e449020923bcaf425a1983bec0833e47ed
Diffstat (limited to 'updater/install.c')
-rw-r--r--updater/install.c127
1 files changed, 113 insertions, 14 deletions
diff --git a/updater/install.c b/updater/install.c
index aebd4f3..2cf00bf 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -45,11 +45,25 @@
#include "mtdutils/mounts.h"
#include "mtdutils/mtdutils.h"
#include "updater.h"
+#include "syspatch.h"
#ifdef USE_EXT4
#include "make_ext4fs.h"
#endif
+// Take a sha-1 digest and return it as a newly-allocated hex string.
+static char* PrintSha1(uint8_t* digest) {
+ char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
+ int i;
+ const char* alphabet = "0123456789abcdef";
+ for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
+ buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
+ buffer[i*2+1] = alphabet[digest[i] & 0xf];
+ }
+ buffer[i*2] = '\0';
+ return buffer;
+}
+
// mount(fs_type, partition_type, location, mount_point)
//
// fs_type="yaffs2" partition_type="MTD" location=partition
@@ -1053,8 +1067,104 @@ Value* ApplyPatchSpaceFn(const char* name, State* state,
return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t"));
}
+// syspatch(file, size, tgt_sha1, init_sha1, patch)
+
+Value* SysPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
+ if (argc != 5) {
+ return ErrorAbort(state, "%s(): expected 5 args, got %d", name, argc);
+ }
+
+ char* filename;
+ char* filename_size_str;
+ char* target_sha1;
+ char* init_sha1;
+ char* patch_filename;
+ uint8_t target_digest[SHA_DIGEST_SIZE];
+ uint8_t init_digest[SHA_DIGEST_SIZE];
+
+ if (ReadArgs(state, argv, 5, &filename, &filename_size_str,
+ &target_sha1, &init_sha1, &patch_filename) < 0) {
+ return NULL;
+ }
+
+ if (ParseSha1(target_sha1, target_digest) != 0) {
+ printf("%s(): failed to parse '%s' as target SHA-1", name, target_sha1);
+ memset(target_digest, 0, SHA_DIGEST_SIZE);
+ }
+ if (ParseSha1(init_sha1, init_digest) != 0) {
+ printf("%s(): failed to parse '%s' as init SHA-1", name, init_sha1);
+ memset(init_digest, 0, SHA_DIGEST_SIZE);
+ }
+
+ size_t len = strtoull(filename_size_str, NULL, 0);
+
+ SHA_CTX ctx;
+ SHA_init(&ctx);
+ FILE* src = fopen(filename, "r");
+ size_t pos = 0;
+ unsigned char buffer[4096];
+ while (pos < len) {
+ size_t to_read = len - pos;
+ if (to_read > sizeof(buffer)) to_read = sizeof(buffer);
+ size_t read = fread(buffer, 1, to_read, src);
+ if (read <= 0) {
+ printf("%s(): short read after %zu bytes\n", name, pos);
+ break;
+ }
+ SHA_update(&ctx, buffer, read);
+ pos += read;
+ }
+ rewind(src);
+ uint8_t* digest = SHA_final(&ctx);
+
+ char* hexdigest = PrintSha1(digest);
+ printf(" system partition sha1 = %s\n", hexdigest);
+
+ if (memcmp(digest, target_digest, SHA_DIGEST_SIZE) == 0) {
+ printf("%s(): %s is already target\n", name, filename);
+ fclose(src);
+ goto done;
+ }
+
+ if (memcmp(digest, init_digest, SHA_DIGEST_SIZE) != 0) {
+ return ErrorAbort(state, "%s(): %s in unknown state\n", name, filename);
+ }
+
+ ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
+
+ const ZipEntry* entry = mzFindZipEntry(za, patch_filename);
+ if (entry == NULL) {
+ return ErrorAbort(state, "%s(): no %s in package\n", name, patch_filename);
+ }
+
+ unsigned char* patch_data;
+ size_t patch_len;
+ if (!mzGetStoredEntry(za, entry, &patch_data, &patch_len)) {
+ return ErrorAbort(state, "%s(): failed to get %s entry\n", name, patch_filename);
+ }
+
+ FILE* tgt = fopen(filename, "r+");
+
+ int ret = syspatch(src, patch_data, patch_len, tgt);
+
+ fclose(src);
+ fclose(tgt);
+
+ if (ret != 0) {
+ return ErrorAbort(state, "%s(): patching failed\n", name);
+ }
+
+ done:
+ free(filename_size_str);
+ free(target_sha1);
+ free(init_sha1);
+ free(patch_filename);
+ return StringValue(filename);
+
+}
+
+// apply_patch(file, size, init_sha1, tgt_sha1, patch)
-// apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1_1, patch_1, ...)
Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc < 6 || (argc % 2) == 1) {
return ErrorAbort(state, "%s(): expected at least 6 args and an "
@@ -1239,19 +1349,6 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) {
return StringValue(strdup(buffer));
}
-// Take a sha-1 digest and return it as a newly-allocated hex string.
-static char* PrintSha1(uint8_t* digest) {
- char* buffer = malloc(SHA_DIGEST_SIZE*2 + 1);
- int i;
- const char* alphabet = "0123456789abcdef";
- for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
- buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf];
- buffer[i*2+1] = alphabet[digest[i] & 0xf];
- }
- buffer[i*2] = '\0';
- return buffer;
-}
-
// sha1_check(data)
// to return the sha1 of the data (given in the format returned by
// read_file).
@@ -1469,6 +1566,8 @@ void RegisterInstallFunctions() {
RegisterFunction("apply_patch_check", ApplyPatchCheckFn);
RegisterFunction("apply_patch_space", ApplyPatchSpaceFn);
+ RegisterFunction("syspatch", SysPatchFn);
+
RegisterFunction("read_file", ReadFileFn);
RegisterFunction("sha1_check", Sha1CheckFn);
RegisterFunction("rename", RenameFn);