// Read a file into memory; optionally (retouch_flag == RETOUCH_DO_MASK) mask // the retouched entries back to their original value (such that SHA-1 checks // don't fail due to randomization); store the file contents and associated // metadata in *file. // // Return 0 on success. int LoadFileContents(const char* filename, FileContents* file, int retouch_flag) { file->data = NULL; // A special 'filename' beginning with "MTD:" or "EMMC:" means to // load the contents of a partition. if (strncmp(filename, "MTD:", 4) == 0 || strncmp(filename, "EMMC:", 5) == 0) { return LoadPartitionContents(filename, file); } if (stat(filename, &file->st) != 0) { printf("failed to stat \"%s\": %s\n", filename, strerror(errno)); return -1; } file->size = file->st.st_size; file->data = malloc(file->size); FILE* f = fopen(filename, "rb"); if (f == NULL) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); free(file->data); file->data = NULL; return -1; } ssize_t bytes_read = fread(file->data, 1, file->size, f); if (bytes_read != file->size) { printf("short read of \"%s\" (%ld bytes of %ld)\n", filename, (long)bytes_read, (long)file->size); free(file->data); file->data = NULL; return -1; } fclose(f); // apply_patch[_check] functions are blind to randomization. Randomization // is taken care of in [Undo]RetouchBinariesFn. If there is a mismatch // within a file, this means the file is assumed "corrupt" for simplicity. if (retouch_flag) { int32_t desired_offset = 0; if (retouch_mask_data(file->data, file->size, &desired_offset, NULL) != RETOUCH_DATA_MATCHED) { printf("error trying to mask retouch entries\n"); free(file->data); file->data = NULL; return -1; } } SHA_hash(file->data, file->size, file->sha1); return 0; }
/* * 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; }
// Read a file into memory; store the file contents and associated // metadata in *file. // // Return 0 on success. int LoadFileContents(const char* filename, FileContents* file) { file->data = NULL; // A special 'filename' beginning with "MTD:" or "EMMC:" means to // load the contents of a partition. if (strncmp(filename, "MTD:", 4) == 0 || strncmp(filename, "EMMC:", 5) == 0) { return LoadPartitionContents(filename, file); } if (stat(filename, &file->st) != 0) { printf("failed to stat \"%s\": %s\n", filename, strerror(errno)); return -1; } file->size = file->st.st_size; file->data = malloc(file->size); FILE* f = fopen(filename, "rb"); if (f == NULL) { printf("failed to open \"%s\": %s\n", filename, strerror(errno)); free(file->data); file->data = NULL; return -1; } ssize_t bytes_read = fread(file->data, 1, file->size, f); if (bytes_read != file->size) { printf("short read of \"%s\" (%ld bytes of %ld)\n", filename, (long)bytes_read, (long)file->size); free(file->data); file->data = NULL; return -1; } fclose(f); SHA_hash(file->data, file->size, file->sha1); return 0; }