add syspatch support to updater

Add the syspatch() function, which can apply xdelta3+xz patches using
the libsyspatch library.

Change-Id: Idc1921e449020923bcaf425a1983bec0833e47ed
This commit is contained in:
Doug Zongker
2014-02-10 15:30:30 -08:00
parent a9300301ce
commit 52b4036eb8
2 changed files with 115 additions and 14 deletions
+2
View File
@@ -35,6 +35,8 @@ LOCAL_STATIC_LIBRARIES += libcutils liblog libstdc++ libc
LOCAL_STATIC_LIBRARIES += libselinux
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
LOCAL_STATIC_LIBRARIES += libsyspatch libxz libxdelta3
# Each library in TARGET_RECOVERY_UPDATER_LIBS should have a function
# named "Register_<libname>()". Here we emit a little C function that
# gets #included by updater.c. It calls all those registration
+113 -14
View File
@@ -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);