1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <stdio.h> 18 19 #include <string> 20 #include <vector> 21 22 #include <android-base/file.h> 23 #include <android-base/memory.h> 24 #include <android-base/test_utils.h> 25 #include <applypatch/imgdiff.h> 26 #include <applypatch/imgpatch.h> 27 #include <gtest/gtest.h> 28 #include <ziparchive/zip_writer.h> 29 30 using android::base::get_unaligned; 31 32 // Sanity check for the given imgdiff patch header. 33 static void verify_patch_header(const std::string& patch, size_t* num_normal, size_t* num_raw, 34 size_t* num_deflate) { 35 const size_t size = patch.size(); 36 const char* data = patch.data(); 37 38 ASSERT_GE(size, 12U); 39 ASSERT_EQ("IMGDIFF2", std::string(data, 8)); 40 41 const int num_chunks = get_unaligned<int32_t>(data + 8); 42 ASSERT_GE(num_chunks, 0); 43 44 size_t normal = 0; 45 size_t raw = 0; 46 size_t deflate = 0; 47 48 size_t pos = 12; 49 for (int i = 0; i < num_chunks; ++i) { 50 ASSERT_LE(pos + 4, size); 51 int type = get_unaligned<int32_t>(data + pos); 52 pos += 4; 53 if (type == CHUNK_NORMAL) { 54 pos += 24; 55 ASSERT_LE(pos, size); 56 normal++; 57 } else if (type == CHUNK_RAW) { 58 ASSERT_LE(pos + 4, size); 59 ssize_t data_len = get_unaligned<int32_t>(data + pos); 60 ASSERT_GT(data_len, 0); 61 pos += 4 + data_len; 62 ASSERT_LE(pos, size); 63 raw++; 64 } else if (type == CHUNK_DEFLATE) { 65 pos += 60; 66 ASSERT_LE(pos, size); 67 deflate++; 68 } else { 69 FAIL() << "Invalid patch type: " << type; 70 } 71 } 72 73 if (num_normal != nullptr) *num_normal = normal; 74 if (num_raw != nullptr) *num_raw = raw; 75 if (num_deflate != nullptr) *num_deflate = deflate; 76 } 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 90 TEST(ImgdiffTest, invalid_args) { 91 // Insufficient inputs. 92 ASSERT_EQ(2, imgdiff(1, (const char* []){ "imgdiff" })); 93 ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-z" })); 94 ASSERT_EQ(2, imgdiff(2, (const char* []){ "imgdiff", "-b" })); 95 ASSERT_EQ(2, imgdiff(3, (const char* []){ "imgdiff", "-z", "-b" })); 96 97 // Failed to read bonus file. 98 ASSERT_EQ(1, imgdiff(3, (const char* []){ "imgdiff", "-b", "doesntexist" })); 99 100 // Failed to read input files. 101 ASSERT_EQ(1, imgdiff(4, (const char* []){ "imgdiff", "doesntexist", "doesntexist", "output" })); 102 ASSERT_EQ( 103 1, imgdiff(5, (const char* []){ "imgdiff", "-z", "doesntexist", "doesntexist", "output" })); 104 } 105 106 TEST(ImgdiffTest, image_mode_smoke) { 107 // Random bytes. 108 const std::string src("abcdefg"); 109 TemporaryFile src_file; 110 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); 111 112 const std::string tgt("abcdefgxyz"); 113 TemporaryFile tgt_file; 114 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); 115 116 TemporaryFile patch_file; 117 std::vector<const char*> args = { 118 "imgdiff", src_file.path, tgt_file.path, patch_file.path, 119 }; 120 ASSERT_EQ(0, imgdiff(args.size(), args.data())); 121 122 // Verify. 123 std::string patch; 124 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); 125 126 // Expect one CHUNK_RAW entry. 127 size_t num_normal; 128 size_t num_raw; 129 size_t num_deflate; 130 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); 131 ASSERT_EQ(0U, num_normal); 132 ASSERT_EQ(0U, num_deflate); 133 ASSERT_EQ(1U, num_raw); 134 135 verify_patched_image(src, patch, tgt); 136 } 137 138 TEST(ImgdiffTest, zip_mode_smoke_store) { 139 // Construct src and tgt zip files. 140 TemporaryFile src_file; 141 FILE* src_file_ptr = fdopen(src_file.fd, "wb"); 142 ZipWriter src_writer(src_file_ptr); 143 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", 0)); // Store mode. 144 const std::string src_content("abcdefg"); 145 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size())); 146 ASSERT_EQ(0, src_writer.FinishEntry()); 147 ASSERT_EQ(0, src_writer.Finish()); 148 ASSERT_EQ(0, fclose(src_file_ptr)); 149 150 TemporaryFile tgt_file; 151 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb"); 152 ZipWriter tgt_writer(tgt_file_ptr); 153 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", 0)); // Store mode. 154 const std::string tgt_content("abcdefgxyz"); 155 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size())); 156 ASSERT_EQ(0, tgt_writer.FinishEntry()); 157 ASSERT_EQ(0, tgt_writer.Finish()); 158 ASSERT_EQ(0, fclose(tgt_file_ptr)); 159 160 // Compute patch. 161 TemporaryFile patch_file; 162 std::vector<const char*> args = { 163 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path, 164 }; 165 ASSERT_EQ(0, imgdiff(args.size(), args.data())); 166 167 // Verify. 168 std::string tgt; 169 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt)); 170 std::string src; 171 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src)); 172 std::string patch; 173 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); 174 175 // Expect one CHUNK_RAW entry. 176 size_t num_normal; 177 size_t num_raw; 178 size_t num_deflate; 179 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); 180 ASSERT_EQ(0U, num_normal); 181 ASSERT_EQ(0U, num_deflate); 182 ASSERT_EQ(1U, num_raw); 183 184 verify_patched_image(src, patch, tgt); 185 } 186 187 TEST(ImgdiffTest, zip_mode_smoke_compressed) { 188 // Construct src and tgt zip files. 189 TemporaryFile src_file; 190 FILE* src_file_ptr = fdopen(src_file.fd, "wb"); 191 ZipWriter src_writer(src_file_ptr); 192 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress)); 193 const std::string src_content("abcdefg"); 194 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size())); 195 ASSERT_EQ(0, src_writer.FinishEntry()); 196 ASSERT_EQ(0, src_writer.Finish()); 197 ASSERT_EQ(0, fclose(src_file_ptr)); 198 199 TemporaryFile tgt_file; 200 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb"); 201 ZipWriter tgt_writer(tgt_file_ptr); 202 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress)); 203 const std::string tgt_content("abcdefgxyz"); 204 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size())); 205 ASSERT_EQ(0, tgt_writer.FinishEntry()); 206 ASSERT_EQ(0, tgt_writer.Finish()); 207 ASSERT_EQ(0, fclose(tgt_file_ptr)); 208 209 // Compute patch. 210 TemporaryFile patch_file; 211 std::vector<const char*> args = { 212 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path, 213 }; 214 ASSERT_EQ(0, imgdiff(args.size(), args.data())); 215 216 // Verify. 217 std::string tgt; 218 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt)); 219 std::string src; 220 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src)); 221 std::string patch; 222 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); 223 224 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer). 225 size_t num_normal; 226 size_t num_raw; 227 size_t num_deflate; 228 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); 229 ASSERT_EQ(0U, num_normal); 230 ASSERT_EQ(1U, num_deflate); 231 ASSERT_EQ(2U, num_raw); 232 233 verify_patched_image(src, patch, tgt); 234 } 235 236 TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) { 237 // Construct src and tgt zip files. 238 TemporaryFile src_file; 239 FILE* src_file_ptr = fdopen(src_file.fd, "wb"); 240 ZipWriter src_writer(src_file_ptr); 241 ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress)); 242 const std::string src_content("abcdefg"); 243 ASSERT_EQ(0, src_writer.WriteBytes(src_content.data(), src_content.size())); 244 ASSERT_EQ(0, src_writer.FinishEntry()); 245 ASSERT_EQ(0, src_writer.Finish()); 246 ASSERT_EQ(0, fclose(src_file_ptr)); 247 248 TemporaryFile tgt_file; 249 FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb"); 250 ZipWriter tgt_writer(tgt_file_ptr); 251 ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress)); 252 const std::string tgt_content("abcdefgxyz"); 253 ASSERT_EQ(0, tgt_writer.WriteBytes(tgt_content.data(), tgt_content.size())); 254 ASSERT_EQ(0, tgt_writer.FinishEntry()); 255 ASSERT_EQ(0, tgt_writer.Finish()); 256 // Add trailing zeros to the target zip file. 257 std::vector<uint8_t> zeros(10); 258 ASSERT_EQ(zeros.size(), fwrite(zeros.data(), sizeof(uint8_t), zeros.size(), tgt_file_ptr)); 259 ASSERT_EQ(0, fclose(tgt_file_ptr)); 260 261 // Compute patch. 262 TemporaryFile patch_file; 263 std::vector<const char*> args = { 264 "imgdiff", "-z", src_file.path, tgt_file.path, patch_file.path, 265 }; 266 ASSERT_EQ(0, imgdiff(args.size(), args.data())); 267 268 // Verify. 269 std::string tgt; 270 ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt)); 271 std::string src; 272 ASSERT_TRUE(android::base::ReadFileToString(src_file.path, &src)); 273 std::string patch; 274 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); 275 276 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer). 277 size_t num_normal; 278 size_t num_raw; 279 size_t num_deflate; 280 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); 281 ASSERT_EQ(0U, num_normal); 282 ASSERT_EQ(1U, num_deflate); 283 ASSERT_EQ(2U, num_raw); 284 285 verify_patched_image(src, patch, tgt); 286 } 287 288 TEST(ImgdiffTest, image_mode_simple) { 289 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd). 290 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 291 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e', 292 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', 293 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', 294 '\x00', '\x00', '\x00' }; 295 const std::string src(src_data.cbegin(), src_data.cend()); 296 TemporaryFile src_file; 297 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); 298 299 // tgt: "abcdefgxyz" + gzipped "xxyyzz". 300 const std::vector<char> tgt_data = { 301 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b', 302 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac', 303 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00' 304 }; 305 const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); 306 TemporaryFile tgt_file; 307 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); 308 309 TemporaryFile patch_file; 310 std::vector<const char*> args = { 311 "imgdiff", src_file.path, tgt_file.path, patch_file.path, 312 }; 313 ASSERT_EQ(0, imgdiff(args.size(), args.data())); 314 315 // Verify. 316 std::string patch; 317 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); 318 319 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer). 320 size_t num_normal; 321 size_t num_raw; 322 size_t num_deflate; 323 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); 324 ASSERT_EQ(0U, num_normal); 325 ASSERT_EQ(1U, num_deflate); 326 ASSERT_EQ(2U, num_raw); 327 328 verify_patched_image(src, patch, tgt); 329 } 330 331 TEST(ImgdiffTest, image_mode_bad_gzip) { 332 // Modify the uncompressed length in the gzip footer. 333 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 334 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e', 335 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', 336 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', 337 '\xff', '\xff', '\xff' }; 338 const std::string src(src_data.cbegin(), src_data.cend()); 339 TemporaryFile src_file; 340 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); 341 342 // Modify the uncompressed length in the gzip footer. 343 const std::vector<char> tgt_data = { 344 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b', 345 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac', 346 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\xff', '\xff', '\xff' 347 }; 348 const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); 349 TemporaryFile tgt_file; 350 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); 351 352 TemporaryFile patch_file; 353 std::vector<const char*> args = { 354 "imgdiff", src_file.path, tgt_file.path, patch_file.path, 355 }; 356 ASSERT_EQ(0, imgdiff(args.size(), args.data())); 357 358 // Verify. 359 std::string patch; 360 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); 361 verify_patched_image(src, patch, tgt); 362 } 363 364 TEST(ImgdiffTest, image_mode_different_num_chunks) { 365 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd) + gzipped "test". 366 const std::vector<char> src_data = { 367 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\x1f', '\x8b', '\x08', 368 '\x00', '\xc4', '\x1e', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', '\x02', 369 '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', '\x00', '\x00', '\x00', '\x1f', '\x8b', 370 '\x08', '\x00', '\xb2', '\x3a', '\x53', '\x58', '\x00', '\x03', '\x2b', '\x49', '\x2d', 371 '\x2e', '\x01', '\x00', '\x0c', '\x7e', '\x7f', '\xd8', '\x04', '\x00', '\x00', '\x00' 372 }; 373 const std::string src(src_data.cbegin(), src_data.cend()); 374 TemporaryFile src_file; 375 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); 376 377 // tgt: "abcdefgxyz" + gzipped "xxyyzz". 378 const std::vector<char> tgt_data = { 379 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b', 380 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac', 381 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00' 382 }; 383 const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); 384 TemporaryFile tgt_file; 385 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); 386 387 TemporaryFile patch_file; 388 std::vector<const char*> args = { 389 "imgdiff", src_file.path, tgt_file.path, patch_file.path, 390 }; 391 ASSERT_EQ(1, imgdiff(args.size(), args.data())); 392 } 393 394 TEST(ImgdiffTest, image_mode_merge_chunks) { 395 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd). 396 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 397 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e', 398 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', 399 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', 400 '\x00', '\x00', '\x00' }; 401 const std::string src(src_data.cbegin(), src_data.cend()); 402 TemporaryFile src_file; 403 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); 404 405 // tgt: gzipped "xyz" + "abcdefgh". 406 const std::vector<char> tgt_data = { 407 '\x1f', '\x8b', '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', 408 '\xa8', '\xac', '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', 409 '\x00', '\x00', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' 410 }; 411 const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); 412 TemporaryFile tgt_file; 413 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); 414 415 // Since a gzipped entry will become CHUNK_RAW (header) + CHUNK_DEFLATE (data) + 416 // CHUNK_RAW (footer), they both should contain the same chunk types after merging. 417 418 TemporaryFile patch_file; 419 std::vector<const char*> args = { 420 "imgdiff", src_file.path, tgt_file.path, patch_file.path, 421 }; 422 ASSERT_EQ(0, imgdiff(args.size(), args.data())); 423 424 // Verify. 425 std::string patch; 426 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); 427 428 // Expect three entries: CHUNK_RAW (header) + CHUNK_DEFLATE (data) + CHUNK_RAW (footer). 429 size_t num_normal; 430 size_t num_raw; 431 size_t num_deflate; 432 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); 433 ASSERT_EQ(0U, num_normal); 434 ASSERT_EQ(1U, num_deflate); 435 ASSERT_EQ(2U, num_raw); 436 437 verify_patched_image(src, patch, tgt); 438 } 439 440 TEST(ImgdiffTest, image_mode_spurious_magic) { 441 // src: "abcdefgh" + '0x1f8b0b00' + some bytes. 442 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 443 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e', 444 '\x53', '\x58', 't', 'e', 's', 't' }; 445 const std::string src(src_data.cbegin(), src_data.cend()); 446 TemporaryFile src_file; 447 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); 448 449 // tgt: "abcdefgxyz". 450 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' }; 451 const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); 452 TemporaryFile tgt_file; 453 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); 454 455 TemporaryFile patch_file; 456 std::vector<const char*> args = { 457 "imgdiff", src_file.path, tgt_file.path, patch_file.path, 458 }; 459 ASSERT_EQ(0, imgdiff(args.size(), args.data())); 460 461 // Verify. 462 std::string patch; 463 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); 464 465 // Expect one CHUNK_RAW (header) entry. 466 size_t num_normal; 467 size_t num_raw; 468 size_t num_deflate; 469 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); 470 ASSERT_EQ(0U, num_normal); 471 ASSERT_EQ(0U, num_deflate); 472 ASSERT_EQ(1U, num_raw); 473 474 verify_patched_image(src, patch, tgt); 475 } 476 477 TEST(ImgdiffTest, image_mode_short_input1) { 478 // src: "abcdefgh" + '0x1f8b0b'. 479 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 480 'g', 'h', '\x1f', '\x8b', '\x08' }; 481 const std::string src(src_data.cbegin(), src_data.cend()); 482 TemporaryFile src_file; 483 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); 484 485 // tgt: "abcdefgxyz". 486 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' }; 487 const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); 488 TemporaryFile tgt_file; 489 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); 490 491 TemporaryFile patch_file; 492 std::vector<const char*> args = { 493 "imgdiff", src_file.path, tgt_file.path, patch_file.path, 494 }; 495 ASSERT_EQ(0, imgdiff(args.size(), args.data())); 496 497 // Verify. 498 std::string patch; 499 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); 500 501 // Expect one CHUNK_RAW (header) entry. 502 size_t num_normal; 503 size_t num_raw; 504 size_t num_deflate; 505 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); 506 ASSERT_EQ(0U, num_normal); 507 ASSERT_EQ(0U, num_deflate); 508 ASSERT_EQ(1U, num_raw); 509 510 verify_patched_image(src, patch, tgt); 511 } 512 513 TEST(ImgdiffTest, image_mode_short_input2) { 514 // src: "abcdefgh" + '0x1f8b0b00'. 515 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 516 'g', 'h', '\x1f', '\x8b', '\x08', '\x00' }; 517 const std::string src(src_data.cbegin(), src_data.cend()); 518 TemporaryFile src_file; 519 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); 520 521 // tgt: "abcdefgxyz". 522 const std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' }; 523 const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); 524 TemporaryFile tgt_file; 525 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); 526 527 TemporaryFile patch_file; 528 std::vector<const char*> args = { 529 "imgdiff", src_file.path, tgt_file.path, patch_file.path, 530 }; 531 ASSERT_EQ(0, imgdiff(args.size(), args.data())); 532 533 // Verify. 534 std::string patch; 535 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); 536 537 // Expect one CHUNK_RAW (header) entry. 538 size_t num_normal; 539 size_t num_raw; 540 size_t num_deflate; 541 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); 542 ASSERT_EQ(0U, num_normal); 543 ASSERT_EQ(0U, num_deflate); 544 ASSERT_EQ(1U, num_raw); 545 546 verify_patched_image(src, patch, tgt); 547 } 548 549 TEST(ImgdiffTest, image_mode_single_entry_long) { 550 // src: "abcdefgh" + '0x1f8b0b00' + some bytes. 551 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 552 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e', 553 '\x53', '\x58', 't', 'e', 's', 't' }; 554 const std::string src(src_data.cbegin(), src_data.cend()); 555 TemporaryFile src_file; 556 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); 557 558 // tgt: "abcdefgxyz" + 200 bytes. 559 std::vector<char> tgt_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z' }; 560 tgt_data.resize(tgt_data.size() + 200); 561 562 const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); 563 TemporaryFile tgt_file; 564 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); 565 566 TemporaryFile patch_file; 567 std::vector<const char*> args = { 568 "imgdiff", src_file.path, tgt_file.path, patch_file.path, 569 }; 570 ASSERT_EQ(0, imgdiff(args.size(), args.data())); 571 572 // Verify. 573 std::string patch; 574 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); 575 576 // Expect one CHUNK_NORMAL entry, since it's exceeding the 160-byte limit for RAW. 577 size_t num_normal; 578 size_t num_raw; 579 size_t num_deflate; 580 verify_patch_header(patch, &num_normal, &num_raw, &num_deflate); 581 ASSERT_EQ(1U, num_normal); 582 ASSERT_EQ(0U, num_deflate); 583 ASSERT_EQ(0U, num_raw); 584 585 verify_patched_image(src, patch, tgt); 586 } 587 588 TEST(ImgpatchTest, image_mode_patch_corruption) { 589 // src: "abcdefgh" + gzipped "xyz" (echo -n "xyz" | gzip -f | hd). 590 const std::vector<char> src_data = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 591 'h', '\x1f', '\x8b', '\x08', '\x00', '\xc4', '\x1e', 592 '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xac', 593 '\x02', '\x00', '\x67', '\xba', '\x8e', '\xeb', '\x03', 594 '\x00', '\x00', '\x00' }; 595 const std::string src(src_data.cbegin(), src_data.cend()); 596 TemporaryFile src_file; 597 ASSERT_TRUE(android::base::WriteStringToFile(src, src_file.path)); 598 599 // tgt: "abcdefgxyz" + gzipped "xxyyzz". 600 const std::vector<char> tgt_data = { 601 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z', '\x1f', '\x8b', 602 '\x08', '\x00', '\x62', '\x1f', '\x53', '\x58', '\x00', '\x03', '\xab', '\xa8', '\xa8', '\xac', 603 '\xac', '\xaa', '\x02', '\x00', '\x96', '\x30', '\x06', '\xb7', '\x06', '\x00', '\x00', '\x00' 604 }; 605 const std::string tgt(tgt_data.cbegin(), tgt_data.cend()); 606 TemporaryFile tgt_file; 607 ASSERT_TRUE(android::base::WriteStringToFile(tgt, tgt_file.path)); 608 609 TemporaryFile patch_file; 610 std::vector<const char*> args = { 611 "imgdiff", src_file.path, tgt_file.path, patch_file.path, 612 }; 613 ASSERT_EQ(0, imgdiff(args.size(), args.data())); 614 615 // Verify. 616 std::string patch; 617 ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch)); 618 verify_patched_image(src, patch, tgt); 619 620 // Corrupt the end of the patch and expect the ApplyImagePatch to fail. 621 patch.insert(patch.end() - 10, 10, '0'); 622 ASSERT_EQ(-1, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(), 623 reinterpret_cast<const unsigned char*>(patch.data()), patch.size(), 624 [](const unsigned char* /*data*/, size_t len) { return len; })); 625 } 626