summaryrefslogtreecommitdiffstats
path: root/applypatch/applypatch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'applypatch/applypatch.cpp')
-rw-r--r--applypatch/applypatch.cpp91
1 files changed, 71 insertions, 20 deletions
diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp
index 026863330..1767761a8 100644
--- a/applypatch/applypatch.cpp
+++ b/applypatch/applypatch.cpp
@@ -31,6 +31,7 @@
#include "applypatch.h"
#include "mtdutils/mtdutils.h"
#include "edify/expr.h"
+#include "print_sha1.h"
static int LoadPartitionContents(const char* filename, FileContents* file);
static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token);
@@ -311,13 +312,14 @@ int SaveFileContents(const char* filename, const FileContents* file) {
}
// Write a memory buffer to 'target' partition, a string of the form
-// "MTD:<partition>[:...]" or "EMMC:<partition_device>". Return 0 on
-// success.
+// "MTD:<partition>[:...]" or "EMMC:<partition_device>[:...]". The target name
+// might contain multiple colons, but WriteToPartition() only uses the first
+// two and ignores the rest. Return 0 on success.
int WriteToPartition(unsigned char* data, size_t len, const char* target) {
std::string copy(target);
std::vector<std::string> pieces = android::base::Split(copy, ":");
- if (pieces.size() != 2) {
+ if (pieces.size() < 2) {
printf("WriteToPartition called with bad target (%s)\n", target);
return -1;
}
@@ -461,7 +463,7 @@ int WriteToPartition(unsigned char* data, size_t len, const char* target) {
}
if (start == len) {
- printf("verification read succeeded (attempt %d)\n", attempt+1);
+ printf("verification read succeeded (attempt %zu)\n", attempt+1);
success = true;
break;
}
@@ -628,14 +630,6 @@ int CacheSizeCheck(size_t bytes) {
}
}
-static void print_short_sha1(const uint8_t sha1[SHA_DIGEST_SIZE]) {
- const char* hex = "0123456789abcdef";
- for (size_t i = 0; i < 4; ++i) {
- putchar(hex[(sha1[i]>>4) & 0xf]);
- putchar(hex[sha1[i] & 0xf]);
- }
-}
-
// This function applies binary patches to files in a way that is safe
// (the original file is not touched until we have the desired
// replacement for it) and idempotent (it's okay to run this program
@@ -648,7 +642,7 @@ static void print_short_sha1(const uint8_t sha1[SHA_DIGEST_SIZE]) {
// entries in <patch_sha1_str>, the corresponding patch from
// <patch_data> (which must be a VAL_BLOB) is applied to produce a
// new file (the type of patch is automatically detected from the
-// blob daat). If that new file has sha1 hash <target_sha1_str>,
+// blob data). If that new file has sha1 hash <target_sha1_str>,
// moves it to replace <target_filename>, and exits successfully.
// Note that if <source_filename> and <target_filename> are not the
// same, <source_filename> is NOT deleted on success.
@@ -659,7 +653,7 @@ static void print_short_sha1(const uint8_t sha1[SHA_DIGEST_SIZE]) {
// status.
//
// <source_filename> may refer to a partition to read the source data.
-// See the comments for the LoadPartition Contents() function above
+// See the comments for the LoadPartitionContents() function above
// for the format of such a filename.
int applypatch(const char* source_filename,
@@ -694,9 +688,7 @@ int applypatch(const char* source_filename,
if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) {
// The early-exit case: the patch was already applied, this file
// has the desired hash, nothing for us to do.
- printf("already ");
- print_short_sha1(target_sha1);
- putchar('\n');
+ printf("already %s\n", short_sha1(target_sha1).c_str());
free(source_file.data);
return 0;
}
@@ -753,6 +745,67 @@ int applypatch(const char* source_filename,
return result;
}
+/*
+ * This function flashes a given image to the target partition. It verifies
+ * the target cheksum first, and will return if target has the desired hash.
+ * It checks the checksum of the given source image before flashing, and
+ * verifies the target partition afterwards. The function is idempotent.
+ * Returns zero on success.
+ */
+int applypatch_flash(const char* source_filename, const char* target_filename,
+ const char* target_sha1_str, size_t target_size) {
+ printf("flash %s: ", target_filename);
+
+ uint8_t target_sha1[SHA_DIGEST_SIZE];
+ if (ParseSha1(target_sha1_str, target_sha1) != 0) {
+ printf("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str);
+ return 1;
+ }
+
+ FileContents source_file;
+ source_file.data = NULL;
+ std::string target_str(target_filename);
+
+ std::vector<std::string> pieces = android::base::Split(target_str, ":");
+ if (pieces.size() != 2 || (pieces[0] != "MTD" && pieces[0] != "EMMC")) {
+ printf("invalid target name \"%s\"", target_filename);
+ return 1;
+ }
+
+ // Load the target into the source_file object to see if already applied.
+ pieces.push_back(std::to_string(target_size));
+ pieces.push_back(target_sha1_str);
+ std::string fullname = android::base::Join(pieces, ':');
+ if (LoadPartitionContents(fullname.c_str(), &source_file) == 0 &&
+ memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) {
+ // The early-exit case: the image was already applied, this partition
+ // has the desired hash, nothing for us to do.
+ printf("already %s\n", short_sha1(target_sha1).c_str());
+ free(source_file.data);
+ return 0;
+ }
+
+ if (LoadFileContents(source_filename, &source_file) == 0) {
+ if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) != 0) {
+ // The source doesn't have desired checksum.
+ printf("source \"%s\" doesn't have expected sha1 sum\n", source_filename);
+ printf("expected: %s, found: %s\n", short_sha1(target_sha1).c_str(),
+ short_sha1(source_file.sha1).c_str());
+ free(source_file.data);
+ return 1;
+ }
+ }
+
+ if (WriteToPartition(source_file.data, target_size, target_filename) != 0) {
+ printf("write of copied data to %s failed\n", target_filename);
+ free(source_file.data);
+ return 1;
+ }
+
+ free(source_file.data);
+ return 0;
+}
+
static int GenerateTarget(FileContents* source_file,
const Value* source_patch_value,
FileContents* copy_file,
@@ -953,9 +1006,7 @@ static int GenerateTarget(FileContents* source_file,
printf("patch did not produce expected sha1\n");
return 1;
} else {
- printf("now ");
- print_short_sha1(target_sha1);
- putchar('\n');
+ printf("now %s\n", short_sha1(target_sha1).c_str());
}
if (output < 0) {