diff options
-rw-r--r-- | applypatch/applypatch.cpp | 45 | ||||
-rw-r--r-- | applypatch/bspatch.cpp | 14 | ||||
-rw-r--r-- | applypatch/imgpatch.cpp | 26 | ||||
-rw-r--r-- | applypatch/include/applypatch/applypatch.h | 19 | ||||
-rw-r--r-- | applypatch/include/applypatch/imgpatch.h | 9 | ||||
-rw-r--r-- | tests/component/imgdiff_test.cpp | 80 | ||||
-rw-r--r-- | updater/blockimg.cpp | 228 |
7 files changed, 190 insertions, 231 deletions
diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 7be3fdbd..51bf3932 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <sys/types.h> | 27 | #include <sys/types.h> |
28 | #include <unistd.h> | 28 | #include <unistd.h> |
29 | 29 | ||
30 | #include <functional> | ||
30 | #include <memory> | 31 | #include <memory> |
31 | #include <string> | 32 | #include <string> |
32 | #include <utility> | 33 | #include <utility> |
@@ -42,7 +43,7 @@ | |||
42 | #include "print_sha1.h" | 43 | #include "print_sha1.h" |
43 | 44 | ||
44 | static int LoadPartitionContents(const std::string& filename, FileContents* file); | 45 | static int LoadPartitionContents(const std::string& filename, FileContents* file); |
45 | static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token); | 46 | static size_t FileSink(const unsigned char* data, size_t len, int fd); |
46 | static int GenerateTarget(const FileContents& source_file, const std::unique_ptr<Value>& patch, | 47 | static int GenerateTarget(const FileContents& source_file, const std::unique_ptr<Value>& patch, |
47 | const std::string& target_filename, | 48 | const std::string& target_filename, |
48 | const uint8_t target_sha1[SHA_DIGEST_LENGTH], const Value* bonus_data); | 49 | const uint8_t target_sha1[SHA_DIGEST_LENGTH], const Value* bonus_data); |
@@ -194,8 +195,8 @@ int SaveFileContents(const char* filename, const FileContents* file) { | |||
194 | return -1; | 195 | return -1; |
195 | } | 196 | } |
196 | 197 | ||
197 | ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd); | 198 | size_t bytes_written = FileSink(file->data.data(), file->data.size(), fd); |
198 | if (bytes_written != static_cast<ssize_t>(file->data.size())) { | 199 | if (bytes_written != file->data.size()) { |
199 | printf("short write of \"%s\" (%zd bytes of %zu): %s\n", filename, bytes_written, | 200 | printf("short write of \"%s\" (%zd bytes of %zu): %s\n", filename, bytes_written, |
200 | file->data.size(), strerror(errno)); | 201 | file->data.size(), strerror(errno)); |
201 | return -1; | 202 | return -1; |
@@ -433,25 +434,17 @@ int ShowLicenses() { | |||
433 | return 0; | 434 | return 0; |
434 | } | 435 | } |
435 | 436 | ||
436 | ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) { | 437 | static size_t FileSink(const unsigned char* data, size_t len, int fd) { |
437 | int fd = *static_cast<int*>(token); | 438 | size_t done = 0; |
438 | ssize_t done = 0; | 439 | while (done < len) { |
439 | ssize_t wrote; | 440 | ssize_t wrote = TEMP_FAILURE_RETRY(ota_write(fd, data + done, len - done)); |
440 | while (done < len) { | 441 | if (wrote == -1) { |
441 | wrote = TEMP_FAILURE_RETRY(ota_write(fd, data+done, len-done)); | 442 | printf("error writing %zd bytes: %s\n", (len - done), strerror(errno)); |
442 | if (wrote == -1) { | 443 | return done; |
443 | printf("error writing %zd bytes: %s\n", (len-done), strerror(errno)); | ||
444 | return done; | ||
445 | } | ||
446 | done += wrote; | ||
447 | } | 444 | } |
448 | return done; | 445 | done += wrote; |
449 | } | 446 | } |
450 | 447 | return done; | |
451 | ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) { | ||
452 | std::string* s = static_cast<std::string*>(token); | ||
453 | s->append(reinterpret_cast<const char*>(data), len); | ||
454 | return len; | ||
455 | } | 448 | } |
456 | 449 | ||
457 | // Return the amount of free space (in bytes) on the filesystem | 450 | // Return the amount of free space (in bytes) on the filesystem |
@@ -647,9 +640,11 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr | |||
647 | } | 640 | } |
648 | 641 | ||
649 | // We store the decoded output in memory. | 642 | // We store the decoded output in memory. |
650 | SinkFn sink = MemorySink; | ||
651 | std::string memory_sink_str; // Don't need to reserve space. | 643 | std::string memory_sink_str; // Don't need to reserve space. |
652 | void* token = &memory_sink_str; | 644 | SinkFn sink = [&memory_sink_str](const unsigned char* data, size_t len) { |
645 | memory_sink_str.append(reinterpret_cast<const char*>(data), len); | ||
646 | return len; | ||
647 | }; | ||
653 | 648 | ||
654 | SHA_CTX ctx; | 649 | SHA_CTX ctx; |
655 | SHA1_Init(&ctx); | 650 | SHA1_Init(&ctx); |
@@ -657,10 +652,10 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr | |||
657 | int result; | 652 | int result; |
658 | if (use_bsdiff) { | 653 | if (use_bsdiff) { |
659 | result = ApplyBSDiffPatch(source_file.data.data(), source_file.data.size(), patch.get(), 0, | 654 | result = ApplyBSDiffPatch(source_file.data.data(), source_file.data.size(), patch.get(), 0, |
660 | sink, token, &ctx); | 655 | sink, &ctx); |
661 | } else { | 656 | } else { |
662 | result = ApplyImagePatch(source_file.data.data(), source_file.data.size(), patch.get(), sink, | 657 | result = ApplyImagePatch(source_file.data.data(), source_file.data.size(), patch.get(), sink, |
663 | token, &ctx, bonus_data); | 658 | &ctx, bonus_data); |
664 | } | 659 | } |
665 | 660 | ||
666 | if (result != 0) { | 661 | if (result != 0) { |
diff --git a/applypatch/bspatch.cpp b/applypatch/bspatch.cpp index 9920c2be..f75a2c68 100644 --- a/applypatch/bspatch.cpp +++ b/applypatch/bspatch.cpp | |||
@@ -24,9 +24,9 @@ | |||
24 | #include <sys/types.h> | 24 | #include <sys/types.h> |
25 | 25 | ||
26 | #include <bspatch.h> | 26 | #include <bspatch.h> |
27 | #include <openssl/sha.h> | ||
27 | 28 | ||
28 | #include "applypatch/applypatch.h" | 29 | #include "applypatch/applypatch.h" |
29 | #include "openssl/sha.h" | ||
30 | 30 | ||
31 | void ShowBSDiffLicense() { | 31 | void ShowBSDiffLicense() { |
32 | puts("The bsdiff library used herein is:\n" | 32 | puts("The bsdiff library used herein is:\n" |
@@ -60,10 +60,10 @@ void ShowBSDiffLicense() { | |||
60 | ); | 60 | ); |
61 | } | 61 | } |
62 | 62 | ||
63 | int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, const Value* patch, | 63 | int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value* patch, |
64 | ssize_t patch_offset, SinkFn sink, void* token, SHA_CTX* ctx) { | 64 | size_t patch_offset, SinkFn sink, SHA_CTX* ctx) { |
65 | auto sha_sink = [&](const uint8_t* data, size_t len) { | 65 | auto sha_sink = [&sink, &ctx](const uint8_t* data, size_t len) { |
66 | len = sink(data, len, token); | 66 | len = sink(data, len); |
67 | if (ctx) SHA1_Update(ctx, data, len); | 67 | if (ctx) SHA1_Update(ctx, data, len); |
68 | return len; | 68 | return len; |
69 | }; | 69 | }; |
@@ -72,8 +72,8 @@ int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, const Valu | |||
72 | patch->data.size(), sha_sink); | 72 | patch->data.size(), sha_sink); |
73 | } | 73 | } |
74 | 74 | ||
75 | int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, const Value* patch, | 75 | int ApplyBSDiffPatchMem(const unsigned char* old_data, size_t old_size, const Value* patch, |
76 | ssize_t patch_offset, std::vector<unsigned char>* new_data) { | 76 | size_t patch_offset, std::vector<unsigned char>* new_data) { |
77 | auto vector_sink = [new_data](const uint8_t* data, size_t len) { | 77 | auto vector_sink = [new_data](const uint8_t* data, size_t len) { |
78 | new_data->insert(new_data->end(), data, data + len); | 78 | new_data->insert(new_data->end(), data, data + len); |
79 | return len; | 79 | return len; |
diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp index adcc61fd..7d8b7361 100644 --- a/applypatch/imgpatch.cpp +++ b/applypatch/imgpatch.cpp | |||
@@ -43,12 +43,11 @@ static inline int32_t Read4(const void *address) { | |||
43 | return android::base::get_unaligned<int32_t>(address); | 43 | return android::base::get_unaligned<int32_t>(address); |
44 | } | 44 | } |
45 | 45 | ||
46 | int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, | 46 | int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const unsigned char* patch_data, |
47 | const unsigned char* patch_data, ssize_t patch_size, | 47 | size_t patch_size, SinkFn sink) { |
48 | SinkFn sink, void* token) { | ||
49 | Value patch(VAL_BLOB, std::string(reinterpret_cast<const char*>(patch_data), patch_size)); | 48 | Value patch(VAL_BLOB, std::string(reinterpret_cast<const char*>(patch_data), patch_size)); |
50 | 49 | ||
51 | return ApplyImagePatch(old_data, old_size, &patch, sink, token, nullptr, nullptr); | 50 | return ApplyImagePatch(old_data, old_size, &patch, sink, nullptr, nullptr); |
52 | } | 51 | } |
53 | 52 | ||
54 | /* | 53 | /* |
@@ -57,8 +56,8 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, | |||
57 | * file, and update the SHA context with the output data as well. | 56 | * file, and update the SHA context with the output data as well. |
58 | * Return 0 on success. | 57 | * Return 0 on success. |
59 | */ | 58 | */ |
60 | int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value* patch, | 59 | int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value* patch, SinkFn sink, |
61 | SinkFn sink, void* token, SHA_CTX* ctx, const Value* bonus_data) { | 60 | SHA_CTX* ctx, const Value* bonus_data) { |
62 | if (patch->data.size() < 12) { | 61 | if (patch->data.size() < 12) { |
63 | printf("patch too short to contain header\n"); | 62 | printf("patch too short to contain header\n"); |
64 | return -1; | 63 | return -1; |
@@ -97,11 +96,11 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value | |||
97 | size_t src_len = static_cast<size_t>(Read8(normal_header + 8)); | 96 | size_t src_len = static_cast<size_t>(Read8(normal_header + 8)); |
98 | size_t patch_offset = static_cast<size_t>(Read8(normal_header + 16)); | 97 | size_t patch_offset = static_cast<size_t>(Read8(normal_header + 16)); |
99 | 98 | ||
100 | if (src_start + src_len > static_cast<size_t>(old_size)) { | 99 | if (src_start + src_len > old_size) { |
101 | printf("source data too short\n"); | 100 | printf("source data too short\n"); |
102 | return -1; | 101 | return -1; |
103 | } | 102 | } |
104 | ApplyBSDiffPatch(old_data + src_start, src_len, patch, patch_offset, sink, token, ctx); | 103 | ApplyBSDiffPatch(old_data + src_start, src_len, patch, patch_offset, sink, ctx); |
105 | } else if (type == CHUNK_RAW) { | 104 | } else if (type == CHUNK_RAW) { |
106 | const char* raw_header = &patch->data[pos]; | 105 | const char* raw_header = &patch->data[pos]; |
107 | pos += 4; | 106 | pos += 4; |
@@ -110,15 +109,14 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value | |||
110 | return -1; | 109 | return -1; |
111 | } | 110 | } |
112 | 111 | ||
113 | ssize_t data_len = Read4(raw_header); | 112 | size_t data_len = static_cast<size_t>(Read4(raw_header)); |
114 | 113 | ||
115 | if (pos + data_len > patch->data.size()) { | 114 | if (pos + data_len > patch->data.size()) { |
116 | printf("failed to read chunk %d raw data\n", i); | 115 | printf("failed to read chunk %d raw data\n", i); |
117 | return -1; | 116 | return -1; |
118 | } | 117 | } |
119 | if (ctx) SHA1_Update(ctx, &patch->data[pos], data_len); | 118 | if (ctx) SHA1_Update(ctx, &patch->data[pos], data_len); |
120 | if (sink(reinterpret_cast<const unsigned char*>(&patch->data[pos]), data_len, token) != | 119 | if (sink(reinterpret_cast<const unsigned char*>(&patch->data[pos]), data_len) != data_len) { |
121 | data_len) { | ||
122 | printf("failed to write chunk %d raw data\n", i); | 120 | printf("failed to write chunk %d raw data\n", i); |
123 | return -1; | 121 | return -1; |
124 | } | 122 | } |
@@ -143,7 +141,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value | |||
143 | int memLevel = Read4(deflate_header + 52); | 141 | int memLevel = Read4(deflate_header + 52); |
144 | int strategy = Read4(deflate_header + 56); | 142 | int strategy = Read4(deflate_header + 56); |
145 | 143 | ||
146 | if (src_start + src_len > static_cast<size_t>(old_size)) { | 144 | if (src_start + src_len > old_size) { |
147 | printf("source data too short\n"); | 145 | printf("source data too short\n"); |
148 | return -1; | 146 | return -1; |
149 | } | 147 | } |
@@ -240,9 +238,9 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value | |||
240 | strm.avail_out = temp_data.size(); | 238 | strm.avail_out = temp_data.size(); |
241 | strm.next_out = temp_data.data(); | 239 | strm.next_out = temp_data.data(); |
242 | ret = deflate(&strm, Z_FINISH); | 240 | ret = deflate(&strm, Z_FINISH); |
243 | ssize_t have = temp_data.size() - strm.avail_out; | 241 | size_t have = temp_data.size() - strm.avail_out; |
244 | 242 | ||
245 | if (sink(temp_data.data(), have, token) != have) { | 243 | if (sink(temp_data.data(), have) != have) { |
246 | printf("failed to write %zd compressed bytes to output\n", have); | 244 | printf("failed to write %zd compressed bytes to output\n", have); |
247 | return -1; | 245 | return -1; |
248 | } | 246 | } |
diff --git a/applypatch/include/applypatch/applypatch.h b/applypatch/include/applypatch/applypatch.h index 4489decb..da55432d 100644 --- a/applypatch/include/applypatch/applypatch.h +++ b/applypatch/include/applypatch/applypatch.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <stdint.h> | 20 | #include <stdint.h> |
21 | #include <sys/stat.h> | 21 | #include <sys/stat.h> |
22 | 22 | ||
23 | #include <functional> | ||
23 | #include <memory> | 24 | #include <memory> |
24 | #include <string> | 25 | #include <string> |
25 | #include <vector> | 26 | #include <vector> |
@@ -41,7 +42,7 @@ struct FileContents { | |||
41 | // and use it as the source instead. | 42 | // and use it as the source instead. |
42 | #define CACHE_TEMP_SOURCE "/cache/saved.file" | 43 | #define CACHE_TEMP_SOURCE "/cache/saved.file" |
43 | 44 | ||
44 | typedef ssize_t (*SinkFn)(const unsigned char*, ssize_t, void*); | 45 | using SinkFn = std::function<size_t(const unsigned char*, size_t)>; |
45 | 46 | ||
46 | // applypatch.cpp | 47 | // applypatch.cpp |
47 | int ShowLicenses(); | 48 | int ShowLicenses(); |
@@ -66,18 +67,14 @@ int SaveFileContents(const char* filename, const FileContents* file); | |||
66 | 67 | ||
67 | // bspatch.cpp | 68 | // bspatch.cpp |
68 | void ShowBSDiffLicense(); | 69 | void ShowBSDiffLicense(); |
69 | int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, | 70 | int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value* patch, |
70 | const Value* patch, ssize_t patch_offset, | 71 | size_t patch_offset, SinkFn sink, SHA_CTX* ctx); |
71 | SinkFn sink, void* token, SHA_CTX* ctx); | 72 | int ApplyBSDiffPatchMem(const unsigned char* old_data, size_t old_size, const Value* patch, |
72 | int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, | 73 | size_t patch_offset, std::vector<unsigned char>* new_data); |
73 | const Value* patch, ssize_t patch_offset, | ||
74 | std::vector<unsigned char>* new_data); | ||
75 | 74 | ||
76 | // imgpatch.cpp | 75 | // imgpatch.cpp |
77 | int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, | 76 | int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value* patch, SinkFn sink, |
78 | const Value* patch, | 77 | SHA_CTX* ctx, const Value* bonus_data); |
79 | SinkFn sink, void* token, SHA_CTX* ctx, | ||
80 | const Value* bonus_data); | ||
81 | 78 | ||
82 | // freecache.cpp | 79 | // freecache.cpp |
83 | int MakeFreeSpaceOnCache(size_t bytes_needed); | 80 | int MakeFreeSpaceOnCache(size_t bytes_needed); |
diff --git a/applypatch/include/applypatch/imgpatch.h b/applypatch/include/applypatch/imgpatch.h index 6549f79f..07c66094 100644 --- a/applypatch/include/applypatch/imgpatch.h +++ b/applypatch/include/applypatch/imgpatch.h | |||
@@ -19,10 +19,11 @@ | |||
19 | 19 | ||
20 | #include <sys/types.h> | 20 | #include <sys/types.h> |
21 | 21 | ||
22 | using SinkFn = ssize_t (*)(const unsigned char*, ssize_t, void*); | 22 | #include <functional> |
23 | 23 | ||
24 | int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, | 24 | using SinkFn = std::function<size_t(const unsigned char*, size_t)>; |
25 | const unsigned char* patch_data, ssize_t patch_size, | 25 | |
26 | SinkFn sink, void* token); | 26 | int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const unsigned char* patch_data, |
27 | size_t patch_size, SinkFn sink); | ||
27 | 28 | ||
28 | #endif // _APPLYPATCH_IMGPATCH_H | 29 | #endif // _APPLYPATCH_IMGPATCH_H |
diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp index 2f648501..7d00a3d5 100644 --- a/tests/component/imgdiff_test.cpp +++ b/tests/component/imgdiff_test.cpp | |||
@@ -14,6 +14,8 @@ | |||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <stdio.h> | ||
18 | |||
17 | #include <string> | 19 | #include <string> |
18 | #include <vector> | 20 | #include <vector> |
19 | 21 | ||
@@ -27,12 +29,6 @@ | |||
27 | 29 | ||
28 | using android::base::get_unaligned; | 30 | using android::base::get_unaligned; |
29 | 31 | ||
30 | static ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) { | ||
31 | std::string* s = static_cast<std::string*>(token); | ||
32 | s->append(reinterpret_cast<const char*>(data), len); | ||
33 | return len; | ||
34 | } | ||
35 | |||
36 | // Sanity check for the given imgdiff patch header. | 32 | // Sanity check for the given imgdiff patch header. |
37 | static void verify_patch_header(const std::string& patch, size_t* num_normal, size_t* num_raw, | 33 | static void verify_patch_header(const std::string& patch, size_t* num_normal, size_t* num_raw, |
38 | size_t* num_deflate) { | 34 | size_t* num_deflate) { |
@@ -79,6 +75,18 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si | |||
79 | if (num_deflate != nullptr) *num_deflate = deflate; | 75 | if (num_deflate != nullptr) *num_deflate = deflate; |
80 | } | 76 | } |
81 | 77 | ||
78 | static void verify_patched_image(const std::string& src, const std::string& patch, | ||
79 | const std::string& tgt) { | ||
80 | std::string patched; | ||
81 | ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(), | ||
82 | reinterpret_cast<const unsigned char*>(patch.data()), patch.size(), | ||
83 | [&patched](const unsigned char* data, size_t len) { | ||
84 | patched.append(reinterpret_cast<const char*>(data), len); | ||
85 | return len; | ||
86 | })); | ||
87 | ASSERT_EQ(tgt, patched); | ||
88 | } | ||
89 | |||
82 | TEST(ImgdiffTest, invalid_args) { | 90 | TEST(ImgdiffTest, invalid_args) { |
83 | // Insufficient inputs. | 91 | // Insufficient inputs. |
84 | ASSERT_EQ(2, imgdiff(1, (const char* []){ "imgdiff" })); | 92 | ASSERT_EQ(2, imgdiff(1, (const char* []){ "imgdiff" })); |
@@ -124,11 +132,7 @@ TEST(ImgdiffTest, image_mode_smoke) { | |||
124 | ASSERT_EQ(0U, num_deflate); | 132 | ASSERT_EQ(0U, num_deflate); |
125 | ASSERT_EQ(1U, num_raw); | 133 | ASSERT_EQ(1U, num_raw); |
126 | 134 | ||
127 | std::string patched; | 135 | verify_patched_image(src, patch, tgt); |
128 | ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(), | ||
129 | reinterpret_cast<const unsigned char*>(patch.data()), patch.size(), | ||
130 | MemorySink, &patched)); | ||
131 | ASSERT_EQ(tgt, patched); | ||
132 | } | 136 | } |
133 | 137 | ||
134 | TEST(ImgdiffTest, zip_mode_smoke_store) { | 138 | TEST(ImgdiffTest, zip_mode_smoke_store) { |
@@ -177,11 +181,7 @@ TEST(ImgdiffTest, zip_mode_smoke_store) { | |||
177 | ASSERT_EQ(0U, num_deflate); | 181 | ASSERT_EQ(0U, num_deflate); |
178 | ASSERT_EQ(1U, num_raw); | 182 | ASSERT_EQ(1U, num_raw); |
179 | 183 | ||
180 | std::string patched; | 184 | verify_patched_image(src, patch, tgt); |
181 | ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(), | ||
182 | reinterpret_cast<const unsigned char*>(patch.data()), patch.size(), | ||
183 | MemorySink, &patched)); | ||
184 | ASSERT_EQ(tgt, patched); | ||
185 | } | 185 | } |
186 | 186 | ||
187 | TEST(ImgdiffTest, zip_mode_smoke_compressed) { | 187 | TEST(ImgdiffTest, zip_mode_smoke_compressed) { |
@@ -230,11 +230,7 @@ TEST(ImgdiffTest, zip_mode_smoke_compressed) { | |||
230 | ASSERT_EQ(1U, num_deflate); | 230 | ASSERT_EQ(1U, num_deflate); |
231 | ASSERT_EQ(2U, num_raw); | 231 | ASSERT_EQ(2U, num_raw); |
232 | 232 | ||
233 | std::string patched; | 233 | verify_patched_image(src, patch, tgt); |
234 | ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(), | ||
235 | reinterpret_cast<const unsigned char*>(patch.data()), patch.size(), | ||
236 | MemorySink, &patched)); | ||
237 | ASSERT_EQ(tgt, patched); | ||
238 | } | 234 | } |
239 | 235 | ||
240 | TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) { | 236 | TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) { |
@@ -286,11 +282,7 @@ TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) { | |||
286 | ASSERT_EQ(1U, num_deflate); | 282 | ASSERT_EQ(1U, num_deflate); |
287 | ASSERT_EQ(2U, num_raw); | 283 | ASSERT_EQ(2U, num_raw); |
288 | 284 | ||
289 | std::string patched; | 285 | verify_patched_image(src, patch, tgt); |
290 | ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(), | ||
291 | reinterpret_cast<const unsigned char*>(patch.data()), patch.size(), | ||
292 | MemorySink, &patched)); | ||
293 | ASSERT_EQ(tgt, patched); | ||
294 | } | 286 | } |
295 | 287 | ||
296 | TEST(ImgdiffTest, image_mode_simple) { | 288 | TEST(ImgdiffTest, image_mode_simple) { |
@@ -333,11 +325,7 @@ TEST(ImgdiffTest, image_mode_simple) { | |||
333 | ASSERT_EQ(1U, num_deflate); | 325 | ASSERT_EQ(1U, num_deflate); |
334 | ASSERT_EQ(2U, num_raw); | 326 | ASSERT_EQ(2U, num_raw); |
335 | 327 | ||
336 | std::string patched; | 328 | verify_patched_image(src, patch, tgt); |
337 | ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(), | ||
338 | reinterpret_cast<const unsigned char*>(patch.data()), patch.size(), | ||
339 | MemorySink, &patched)); | ||
340 | ASSERT_EQ(tgt, patched); | ||
341 | } | 329 | } |
342 | 330 | ||
343 | TEST(ImgdiffTest, image_mode_different_num_chunks) { | 331 | TEST(ImgdiffTest, image_mode_different_num_chunks) { |
@@ -413,11 +401,7 @@ TEST(ImgdiffTest, image_mode_merge_chunks) { | |||
413 | ASSERT_EQ(1U, num_deflate); | 401 | ASSERT_EQ(1U, num_deflate); |
414 | ASSERT_EQ(2U, num_raw); | 402 | ASSERT_EQ(2U, num_raw); |
415 | 403 | ||
416 | std::string patched; | 404 | verify_patched_image(src, patch, tgt); |
417 | ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(), | ||
418 | reinterpret_cast<const unsigned char*>(patch.data()), patch.size(), | ||
419 | MemorySink, &patched)); | ||
420 | ASSERT_EQ(tgt, patched); | ||
421 | } | 405 | } |
422 | 406 | ||
423 | TEST(ImgdiffTest, image_mode_spurious_magic) { | 407 | TEST(ImgdiffTest, image_mode_spurious_magic) { |
@@ -454,11 +438,7 @@ TEST(ImgdiffTest, image_mode_spurious_magic) { | |||
454 | ASSERT_EQ(0U, num_deflate); | 438 | ASSERT_EQ(0U, num_deflate); |
455 | ASSERT_EQ(1U, num_raw); | 439 | ASSERT_EQ(1U, num_raw); |
456 | 440 | ||
457 | std::string patched; | 441 | verify_patched_image(src, patch, tgt); |
458 | ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(), | ||
459 | reinterpret_cast<const unsigned char*>(patch.data()), patch.size(), | ||
460 | MemorySink, &patched)); | ||
461 | ASSERT_EQ(tgt, patched); | ||
462 | } | 442 | } |
463 | 443 | ||
464 | TEST(ImgdiffTest, image_mode_short_input1) { | 444 | TEST(ImgdiffTest, image_mode_short_input1) { |
@@ -494,11 +474,7 @@ TEST(ImgdiffTest, image_mode_short_input1) { | |||
494 | ASSERT_EQ(0U, num_deflate); | 474 | ASSERT_EQ(0U, num_deflate); |
495 | ASSERT_EQ(1U, num_raw); | 475 | ASSERT_EQ(1U, num_raw); |
496 | 476 | ||
497 | std::string patched; | 477 | verify_patched_image(src, patch, tgt); |
498 | ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(), | ||
499 | reinterpret_cast<const unsigned char*>(patch.data()), patch.size(), | ||
500 | MemorySink, &patched)); | ||
501 | ASSERT_EQ(tgt, patched); | ||
502 | } | 478 | } |
503 | 479 | ||
504 | TEST(ImgdiffTest, image_mode_short_input2) { | 480 | TEST(ImgdiffTest, image_mode_short_input2) { |
@@ -534,11 +510,7 @@ TEST(ImgdiffTest, image_mode_short_input2) { | |||
534 | ASSERT_EQ(0U, num_deflate); | 510 | ASSERT_EQ(0U, num_deflate); |
535 | ASSERT_EQ(1U, num_raw); | 511 | ASSERT_EQ(1U, num_raw); |
536 | 512 | ||
537 | std::string patched; | 513 | verify_patched_image(src, patch, tgt); |
538 | ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(), | ||
539 | reinterpret_cast<const unsigned char*>(patch.data()), patch.size(), | ||
540 | MemorySink, &patched)); | ||
541 | ASSERT_EQ(tgt, patched); | ||
542 | } | 514 | } |
543 | 515 | ||
544 | TEST(ImgdiffTest, image_mode_single_entry_long) { | 516 | TEST(ImgdiffTest, image_mode_single_entry_long) { |
@@ -577,9 +549,5 @@ TEST(ImgdiffTest, image_mode_single_entry_long) { | |||
577 | ASSERT_EQ(0U, num_deflate); | 549 | ASSERT_EQ(0U, num_deflate); |
578 | ASSERT_EQ(0U, num_raw); | 550 | ASSERT_EQ(0U, num_raw); |
579 | 551 | ||
580 | std::string patched; | 552 | verify_patched_image(src, patch, tgt); |
581 | ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(), | ||
582 | reinterpret_cast<const unsigned char*>(patch.data()), patch.size(), | ||
583 | MemorySink, &patched)); | ||
584 | ASSERT_EQ(tgt, patched); | ||
585 | } | 553 | } |
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 1cad6da9..8c0f885a 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp | |||
@@ -240,57 +240,54 @@ struct RangeSinkState { | |||
240 | size_t p_remain; | 240 | size_t p_remain; |
241 | }; | 241 | }; |
242 | 242 | ||
243 | static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) { | 243 | static size_t RangeSinkWrite(const uint8_t* data, size_t size, RangeSinkState* rss) { |
244 | RangeSinkState* rss = reinterpret_cast<RangeSinkState*>(token); | 244 | if (rss->p_remain == 0) { |
245 | 245 | LOG(ERROR) << "range sink write overrun"; | |
246 | if (rss->p_remain == 0) { | 246 | return 0; |
247 | LOG(ERROR) << "range sink write overrun"; | 247 | } |
248 | return 0; | ||
249 | } | ||
250 | |||
251 | ssize_t written = 0; | ||
252 | while (size > 0) { | ||
253 | size_t write_now = size; | ||
254 | |||
255 | if (rss->p_remain < write_now) { | ||
256 | write_now = rss->p_remain; | ||
257 | } | ||
258 | 248 | ||
259 | if (write_all(rss->fd, data, write_now) == -1) { | 249 | size_t written = 0; |
260 | break; | 250 | while (size > 0) { |
261 | } | 251 | size_t write_now = size; |
262 | 252 | ||
263 | data += write_now; | 253 | if (rss->p_remain < write_now) { |
264 | size -= write_now; | 254 | write_now = rss->p_remain; |
255 | } | ||
265 | 256 | ||
266 | rss->p_remain -= write_now; | 257 | if (write_all(rss->fd, data, write_now) == -1) { |
267 | written += write_now; | 258 | break; |
259 | } | ||
268 | 260 | ||
269 | if (rss->p_remain == 0) { | 261 | data += write_now; |
270 | // move to the next block | 262 | size -= write_now; |
271 | ++rss->p_block; | ||
272 | if (rss->p_block < rss->tgt.count) { | ||
273 | rss->p_remain = (rss->tgt.pos[rss->p_block * 2 + 1] - | ||
274 | rss->tgt.pos[rss->p_block * 2]) * BLOCKSIZE; | ||
275 | 263 | ||
276 | off64_t offset = static_cast<off64_t>(rss->tgt.pos[rss->p_block*2]) * BLOCKSIZE; | 264 | rss->p_remain -= write_now; |
277 | if (!discard_blocks(rss->fd, offset, rss->p_remain)) { | 265 | written += write_now; |
278 | break; | ||
279 | } | ||
280 | 266 | ||
281 | if (!check_lseek(rss->fd, offset, SEEK_SET)) { | 267 | if (rss->p_remain == 0) { |
282 | break; | 268 | // Move to the next block. |
283 | } | 269 | ++rss->p_block; |
270 | if (rss->p_block < rss->tgt.count) { | ||
271 | rss->p_remain = | ||
272 | (rss->tgt.pos[rss->p_block * 2 + 1] - rss->tgt.pos[rss->p_block * 2]) * BLOCKSIZE; | ||
273 | |||
274 | off64_t offset = static_cast<off64_t>(rss->tgt.pos[rss->p_block * 2]) * BLOCKSIZE; | ||
275 | if (!discard_blocks(rss->fd, offset, rss->p_remain)) { | ||
276 | break; | ||
277 | } | ||
284 | 278 | ||
285 | } else { | 279 | if (!check_lseek(rss->fd, offset, SEEK_SET)) { |
286 | // we can't write any more; return how many bytes have | 280 | break; |
287 | // been written so far. | ||
288 | break; | ||
289 | } | ||
290 | } | 281 | } |
282 | |||
283 | } else { | ||
284 | // We can't write any more; return how many bytes have been written so far. | ||
285 | break; | ||
286 | } | ||
291 | } | 287 | } |
288 | } | ||
292 | 289 | ||
293 | return written; | 290 | return written; |
294 | } | 291 | } |
295 | 292 | ||
296 | // All of the data for all the 'new' transfers is contained in one | 293 | // All of the data for all the 'new' transfers is contained in one |
@@ -338,7 +335,7 @@ static bool receive_new_data(const uint8_t* data, size_t size, void* cookie) { | |||
338 | 335 | ||
339 | // At this point nti->rss is set, and we own it. The main | 336 | // At this point nti->rss is set, and we own it. The main |
340 | // thread is waiting for it to disappear from nti. | 337 | // thread is waiting for it to disappear from nti. |
341 | ssize_t written = RangeSinkWrite(data, size, nti->rss); | 338 | size_t written = RangeSinkWrite(data, size, nti->rss); |
342 | data += written; | 339 | data += written; |
343 | size -= written; | 340 | size -= written; |
344 | 341 | ||
@@ -1259,92 +1256,95 @@ static int PerformCommandNew(CommandParameters& params) { | |||
1259 | } | 1256 | } |
1260 | 1257 | ||
1261 | static int PerformCommandDiff(CommandParameters& params) { | 1258 | static int PerformCommandDiff(CommandParameters& params) { |
1259 | // <offset> <length> | ||
1260 | if (params.cpos + 1 >= params.tokens.size()) { | ||
1261 | LOG(ERROR) << "missing patch offset or length for " << params.cmdname; | ||
1262 | return -1; | ||
1263 | } | ||
1262 | 1264 | ||
1263 | // <offset> <length> | 1265 | size_t offset; |
1264 | if (params.cpos + 1 >= params.tokens.size()) { | 1266 | if (!android::base::ParseUint(params.tokens[params.cpos++], &offset)) { |
1265 | LOG(ERROR) << "missing patch offset or length for " << params.cmdname; | 1267 | LOG(ERROR) << "invalid patch offset"; |
1266 | return -1; | 1268 | return -1; |
1267 | } | 1269 | } |
1268 | 1270 | ||
1269 | size_t offset; | 1271 | size_t len; |
1270 | if (!android::base::ParseUint(params.tokens[params.cpos++], &offset)) { | 1272 | if (!android::base::ParseUint(params.tokens[params.cpos++], &len)) { |
1271 | LOG(ERROR) << "invalid patch offset"; | 1273 | LOG(ERROR) << "invalid patch len"; |
1272 | return -1; | 1274 | return -1; |
1273 | } | 1275 | } |
1274 | 1276 | ||
1275 | size_t len; | 1277 | RangeSet tgt; |
1276 | if (!android::base::ParseUint(params.tokens[params.cpos++], &len)) { | 1278 | size_t blocks = 0; |
1277 | LOG(ERROR) << "invalid patch len"; | 1279 | bool overlap = false; |
1278 | return -1; | 1280 | int status = LoadSrcTgtVersion3(params, tgt, &blocks, false, &overlap); |
1279 | } | ||
1280 | 1281 | ||
1281 | RangeSet tgt; | 1282 | if (status == -1) { |
1282 | size_t blocks = 0; | 1283 | LOG(ERROR) << "failed to read blocks for diff"; |
1283 | bool overlap = false; | 1284 | return -1; |
1284 | int status = LoadSrcTgtVersion3(params, tgt, &blocks, false, &overlap); | 1285 | } |
1285 | 1286 | ||
1286 | if (status == -1) { | 1287 | if (status == 0) { |
1287 | LOG(ERROR) << "failed to read blocks for diff"; | 1288 | params.foundwrites = true; |
1288 | return -1; | 1289 | } else if (params.foundwrites) { |
1289 | } | 1290 | LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]"; |
1291 | } | ||
1290 | 1292 | ||
1293 | if (params.canwrite) { | ||
1291 | if (status == 0) { | 1294 | if (status == 0) { |
1292 | params.foundwrites = true; | 1295 | LOG(INFO) << "patching " << blocks << " blocks to " << tgt.size; |
1293 | } else if (params.foundwrites) { | 1296 | Value patch_value( |
1294 | LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]"; | 1297 | VAL_BLOB, std::string(reinterpret_cast<const char*>(params.patch_start + offset), len)); |
1295 | } | 1298 | RangeSinkState rss(tgt); |
1296 | 1299 | rss.fd = params.fd; | |
1297 | if (params.canwrite) { | 1300 | rss.p_block = 0; |
1298 | if (status == 0) { | 1301 | rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE; |
1299 | LOG(INFO) << "patching " << blocks << " blocks to " << tgt.size; | 1302 | |
1300 | Value patch_value(VAL_BLOB, | 1303 | off64_t offset = static_cast<off64_t>(tgt.pos[0]) * BLOCKSIZE; |
1301 | std::string(reinterpret_cast<const char*>(params.patch_start + offset), len)); | 1304 | if (!discard_blocks(params.fd, offset, rss.p_remain)) { |
1302 | RangeSinkState rss(tgt); | 1305 | return -1; |
1303 | rss.fd = params.fd; | 1306 | } |
1304 | rss.p_block = 0; | ||
1305 | rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE; | ||
1306 | |||
1307 | off64_t offset = static_cast<off64_t>(tgt.pos[0]) * BLOCKSIZE; | ||
1308 | if (!discard_blocks(params.fd, offset, rss.p_remain)) { | ||
1309 | return -1; | ||
1310 | } | ||
1311 | |||
1312 | if (!check_lseek(params.fd, offset, SEEK_SET)) { | ||
1313 | return -1; | ||
1314 | } | ||
1315 | 1307 | ||
1316 | if (params.cmdname[0] == 'i') { // imgdiff | 1308 | if (!check_lseek(params.fd, offset, SEEK_SET)) { |
1317 | if (ApplyImagePatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value, | 1309 | return -1; |
1318 | &RangeSinkWrite, &rss, nullptr, nullptr) != 0) { | 1310 | } |
1319 | LOG(ERROR) << "Failed to apply image patch."; | ||
1320 | return -1; | ||
1321 | } | ||
1322 | } else { | ||
1323 | if (ApplyBSDiffPatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value, | ||
1324 | 0, &RangeSinkWrite, &rss, nullptr) != 0) { | ||
1325 | LOG(ERROR) << "Failed to apply bsdiff patch."; | ||
1326 | return -1; | ||
1327 | } | ||
1328 | } | ||
1329 | 1311 | ||
1330 | // We expect the output of the patcher to fill the tgt ranges exactly. | 1312 | if (params.cmdname[0] == 'i') { // imgdiff |
1331 | if (rss.p_block != tgt.count || rss.p_remain != 0) { | 1313 | if (ApplyImagePatch( |
1332 | LOG(ERROR) << "range sink underrun?"; | 1314 | params.buffer.data(), blocks * BLOCKSIZE, &patch_value, |
1333 | } | 1315 | std::bind(&RangeSinkWrite, std::placeholders::_1, std::placeholders::_2, &rss), |
1334 | } else { | 1316 | nullptr, nullptr) != 0) { |
1335 | LOG(INFO) << "skipping " << blocks << " blocks already patched to " << tgt.size | 1317 | LOG(ERROR) << "Failed to apply image patch."; |
1336 | << " [" << params.cmdline << "]"; | 1318 | return -1; |
1337 | } | 1319 | } |
1338 | } | 1320 | } else { |
1321 | if (ApplyBSDiffPatch( | ||
1322 | params.buffer.data(), blocks * BLOCKSIZE, &patch_value, 0, | ||
1323 | std::bind(&RangeSinkWrite, std::placeholders::_1, std::placeholders::_2, &rss), | ||
1324 | nullptr) != 0) { | ||
1325 | LOG(ERROR) << "Failed to apply bsdiff patch."; | ||
1326 | return -1; | ||
1327 | } | ||
1328 | } | ||
1339 | 1329 | ||
1340 | if (!params.freestash.empty()) { | 1330 | // We expect the output of the patcher to fill the tgt ranges exactly. |
1341 | FreeStash(params.stashbase, params.freestash); | 1331 | if (rss.p_block != tgt.count || rss.p_remain != 0) { |
1342 | params.freestash.clear(); | 1332 | LOG(ERROR) << "range sink underrun?"; |
1333 | } | ||
1334 | } else { | ||
1335 | LOG(INFO) << "skipping " << blocks << " blocks already patched to " << tgt.size << " [" | ||
1336 | << params.cmdline << "]"; | ||
1343 | } | 1337 | } |
1338 | } | ||
1344 | 1339 | ||
1345 | params.written += tgt.size; | 1340 | if (!params.freestash.empty()) { |
1341 | FreeStash(params.stashbase, params.freestash); | ||
1342 | params.freestash.clear(); | ||
1343 | } | ||
1346 | 1344 | ||
1347 | return 0; | 1345 | params.written += tgt.size; |
1346 | |||
1347 | return 0; | ||
1348 | } | 1348 | } |
1349 | 1349 | ||
1350 | static int PerformCommandErase(CommandParameters& params) { | 1350 | static int PerformCommandErase(CommandParameters& params) { |