aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--applypatch/Android.mk30
-rw-r--r--applypatch/applypatch_main.cpp28
-rw-r--r--applypatch/applypatch_modes.cpp (renamed from applypatch/main.cpp)52
-rw-r--r--applypatch/applypatch_modes.h22
-rw-r--r--tests/Android.mk3
-rw-r--r--tests/component/applypatch_test.cpp578
-rw-r--r--tests/testdata/bonus.filebin0 -> 557334 bytes
-rw-r--r--tests/testdata/boot.imgbin0 -> 783655 bytes
-rw-r--r--tests/testdata/recovery-from-boot-with-bonus.pbin0 -> 381615 bytes
-rw-r--r--tests/testdata/recovery-from-boot.pbin0 -> 5404 bytes
-rw-r--r--tests/testdata/recovery.imgbin0 -> 529707 bytes
11 files changed, 426 insertions, 287 deletions
diff --git a/applypatch/Android.mk b/applypatch/Android.mk
index 9bbac441..fa0fe8a3 100644
--- a/applypatch/Android.mk
+++ b/applypatch/Android.mk
@@ -68,21 +68,41 @@ LOCAL_STATIC_LIBRARIES += libcrypto libbz libz
68LOCAL_CFLAGS := -Werror 68LOCAL_CFLAGS := -Werror
69include $(BUILD_HOST_STATIC_LIBRARY) 69include $(BUILD_HOST_STATIC_LIBRARY)
70 70
71# applypatch (executable) 71# libapplypatch_modes (static library)
72# =============================== 72# ===============================
73include $(CLEAR_VARS) 73include $(CLEAR_VARS)
74LOCAL_CLANG := true 74LOCAL_CLANG := true
75LOCAL_SRC_FILES := main.cpp 75LOCAL_SRC_FILES := \
76 applypatch_modes.cpp
77LOCAL_MODULE := libapplypatch_modes
78LOCAL_C_INCLUDES := bootable/recovery
79LOCAL_STATIC_LIBRARIES := \
80 libapplypatch \
81 libbase \
82 libedify \
83 libcrypto
84LOCAL_CFLAGS := -Werror
85include $(BUILD_STATIC_LIBRARY)
86
87# applypatch (target executable)
88# ===============================
89include $(CLEAR_VARS)
90LOCAL_CLANG := true
91LOCAL_SRC_FILES := applypatch_main.cpp
76LOCAL_MODULE := applypatch 92LOCAL_MODULE := applypatch
77LOCAL_C_INCLUDES += bootable/recovery 93LOCAL_C_INCLUDES := bootable/recovery
78LOCAL_STATIC_LIBRARIES += \ 94LOCAL_STATIC_LIBRARIES := \
95 libapplypatch_modes \
79 libapplypatch \ 96 libapplypatch \
80 libbase \ 97 libbase \
81 libedify \ 98 libedify \
82 libotafault \ 99 libotafault \
83 libcrypto \ 100 libcrypto \
84 libbz 101 libbz
85LOCAL_SHARED_LIBRARIES += libbase libz libcutils libc 102LOCAL_SHARED_LIBRARIES := \
103 libbase \
104 libz \
105 libcutils
86LOCAL_CFLAGS := -Werror 106LOCAL_CFLAGS := -Werror
87include $(BUILD_EXECUTABLE) 107include $(BUILD_EXECUTABLE)
88 108
diff --git a/applypatch/applypatch_main.cpp b/applypatch/applypatch_main.cpp
new file mode 100644
index 00000000..197077c9
--- /dev/null
+++ b/applypatch/applypatch_main.cpp
@@ -0,0 +1,28 @@
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 "applypatch_modes.h"
18
19// This program (applypatch) applies binary patches to files in a way that
20// is safe (the original file is not touched until we have the desired
21// replacement for it) and idempotent (it's okay to run this program
22// multiple times).
23//
24// See the comments to applypatch_modes() function.
25
26int main(int argc, char** argv) {
27 return applypatch_modes(argc, const_cast<const char**>(argv));
28}
diff --git a/applypatch/main.cpp b/applypatch/applypatch_modes.cpp
index 988b6f9b..7b191a80 100644
--- a/applypatch/main.cpp
+++ b/applypatch/applypatch_modes.cpp
@@ -14,6 +14,8 @@
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 16
17#include "applypatch_modes.h"
18
17#include <stdio.h> 19#include <stdio.h>
18#include <stdlib.h> 20#include <stdlib.h>
19#include <string.h> 21#include <string.h>
@@ -23,12 +25,14 @@
23#include <string> 25#include <string>
24#include <vector> 26#include <vector>
25 27
28#include <android-base/parseint.h>
29#include <android-base/strings.h>
26#include <openssl/sha.h> 30#include <openssl/sha.h>
27 31
28#include "applypatch/applypatch.h" 32#include "applypatch/applypatch.h"
29#include "edify/expr.h" 33#include "edify/expr.h"
30 34
31static int CheckMode(int argc, char** argv) { 35static int CheckMode(int argc, const char** argv) {
32 if (argc < 3) { 36 if (argc < 3) {
33 return 2; 37 return 2;
34 } 38 }
@@ -40,44 +44,42 @@ static int CheckMode(int argc, char** argv) {
40 return applypatch_check(argv[2], sha1); 44 return applypatch_check(argv[2], sha1);
41} 45}
42 46
43static int SpaceMode(int argc, char** argv) { 47static int SpaceMode(int argc, const char** argv) {
44 if (argc != 3) { 48 if (argc != 3) {
45 return 2; 49 return 2;
46 } 50 }
47 char* endptr; 51
48 size_t bytes = strtol(argv[2], &endptr, 10); 52 size_t bytes;
49 if (bytes == 0 && endptr == argv[2]) { 53 if (!android::base::ParseUint(argv[2], &bytes) || bytes == 0) {
50 printf("can't parse \"%s\" as byte count\n\n", argv[2]); 54 printf("can't parse \"%s\" as byte count\n\n", argv[2]);
51 return 1; 55 return 1;
52 } 56 }
53 return CacheSizeCheck(bytes); 57 return CacheSizeCheck(bytes);
54} 58}
55 59
56// Parse arguments (which should be of the form "<sha1>:<filename>" 60// Parse arguments (which should be of the form "<sha1>:<filename>" into the
57// into the new parallel arrays *sha1s and *files.Returns true on 61// new parallel arrays *sha1s and *files. Returns true on success.
58// success. 62static bool ParsePatchArgs(int argc, const char** argv, std::vector<std::string>* sha1s,
59static bool ParsePatchArgs(int argc, char** argv, std::vector<std::string>* sha1s,
60 std::vector<FileContents>* files) { 63 std::vector<FileContents>* files) {
61 if (sha1s == nullptr) { 64 if (sha1s == nullptr) {
62 return false; 65 return false;
63 } 66 }
64 for (int i = 0; i < argc; ++i) { 67 for (int i = 0; i < argc; ++i) {
65 uint8_t digest[SHA_DIGEST_LENGTH]; 68 std::vector<std::string> pieces = android::base::Split(argv[i], ":");
66 char* colon = strchr(argv[i], ':'); 69 if (pieces.size() != 2) {
67 if (colon == nullptr) { 70 printf("failed to parse patch argument \"%s\"\n", argv[i]);
68 printf("no ':' in patch argument \"%s\"\n", argv[i]);
69 return false; 71 return false;
70 } 72 }
71 *colon = '\0'; 73
72 ++colon; 74 uint8_t digest[SHA_DIGEST_LENGTH];
73 if (ParseSha1(argv[i], digest) != 0) { 75 if (ParseSha1(pieces[0].c_str(), digest) != 0) {
74 printf("failed to parse sha1 \"%s\"\n", argv[i]); 76 printf("failed to parse sha1 \"%s\"\n", argv[i]);
75 return false; 77 return false;
76 } 78 }
77 79
78 sha1s->push_back(argv[i]); 80 sha1s->push_back(pieces[0]);
79 FileContents fc; 81 FileContents fc;
80 if (LoadFileContents(colon, &fc) != 0) { 82 if (LoadFileContents(pieces[1].c_str(), &fc) != 0) {
81 return false; 83 return false;
82 } 84 }
83 files->push_back(std::move(fc)); 85 files->push_back(std::move(fc));
@@ -90,7 +92,7 @@ static int FlashMode(const char* src_filename, const char* tgt_filename,
90 return applypatch_flash(src_filename, tgt_filename, tgt_sha1, tgt_size); 92 return applypatch_flash(src_filename, tgt_filename, tgt_sha1, tgt_size);
91} 93}
92 94
93static int PatchMode(int argc, char** argv) { 95static int PatchMode(int argc, const char** argv) {
94 FileContents bonusFc; 96 FileContents bonusFc;
95 Value bonus(VAL_INVALID, ""); 97 Value bonus(VAL_INVALID, "");
96 98
@@ -109,9 +111,8 @@ static int PatchMode(int argc, char** argv) {
109 return 2; 111 return 2;
110 } 112 }
111 113
112 char* endptr; 114 size_t target_size;
113 size_t target_size = strtol(argv[4], &endptr, 10); 115 if (!android::base::ParseUint(argv[4], &target_size) || target_size == 0) {
114 if (target_size == 0 && endptr == argv[4]) {
115 printf("can't parse \"%s\" as byte count\n\n", argv[4]); 116 printf("can't parse \"%s\" as byte count\n\n", argv[4]);
116 return 1; 117 return 1;
117 } 118 }
@@ -124,6 +125,7 @@ static int PatchMode(int argc, char** argv) {
124 } 125 }
125 return FlashMode(argv[1], argv[2], argv[3], target_size); 126 return FlashMode(argv[1], argv[2], argv[3], target_size);
126 } 127 }
128
127 std::vector<std::string> sha1s; 129 std::vector<std::string> sha1s;
128 std::vector<FileContents> files; 130 std::vector<FileContents> files;
129 if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) { 131 if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) {
@@ -139,8 +141,8 @@ static int PatchMode(int argc, char** argv) {
139 return applypatch(argv[1], argv[2], argv[3], target_size, sha1s, patches, &bonus); 141 return applypatch(argv[1], argv[2], argv[3], target_size, sha1s, patches, &bonus);
140} 142}
141 143
142// This program applies binary patches to files in a way that is safe 144// This program (applypatch) applies binary patches to files in a way that
143// (the original file is not touched until we have the desired 145// is safe (the original file is not touched until we have the desired
144// replacement for it) and idempotent (it's okay to run this program 146// replacement for it) and idempotent (it's okay to run this program
145// multiple times). 147// multiple times).
146// 148//
@@ -166,7 +168,7 @@ static int PatchMode(int argc, char** argv) {
166// to read the source data. See the comments for the 168// to read the source data. See the comments for the
167// LoadPartitionContents() function for the format of such a filename. 169// LoadPartitionContents() function for the format of such a filename.
168 170
169int main(int argc, char** argv) { 171int applypatch_modes(int argc, const char** argv) {
170 if (argc < 2) { 172 if (argc < 2) {
171 usage: 173 usage:
172 printf( 174 printf(
diff --git a/applypatch/applypatch_modes.h b/applypatch/applypatch_modes.h
new file mode 100644
index 00000000..3d9d08df
--- /dev/null
+++ b/applypatch/applypatch_modes.h
@@ -0,0 +1,22 @@
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#ifndef _APPLYPATCH_MODES_H
18#define _APPLYPATCH_MODES_H
19
20int applypatch_modes(int argc, const char** argv);
21
22#endif // _APPLYPATCH_MODES_H
diff --git a/tests/Android.mk b/tests/Android.mk
index 3d05386b..461d6ef7 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -43,7 +43,7 @@ include $(BUILD_NATIVE_TEST)
43# Component tests 43# Component tests
44include $(CLEAR_VARS) 44include $(CLEAR_VARS)
45LOCAL_CLANG := true 45LOCAL_CLANG := true
46LOCAL_CFLAGS += -Wno-unused-parameter -Werror 46LOCAL_CFLAGS := -Werror
47LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk 47LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
48LOCAL_MODULE := recovery_component_test 48LOCAL_MODULE := recovery_component_test
49LOCAL_C_INCLUDES := bootable/recovery 49LOCAL_C_INCLUDES := bootable/recovery
@@ -63,6 +63,7 @@ tune2fs_static_libraries := \
63 libext2fs 63 libext2fs
64 64
65LOCAL_STATIC_LIBRARIES := \ 65LOCAL_STATIC_LIBRARIES := \
66 libapplypatch_modes \
66 libapplypatch \ 67 libapplypatch \
67 libedify \ 68 libedify \
68 libotafault \ 69 libotafault \
diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp
index e09c1e7b..f95ebed5 100644
--- a/tests/component/applypatch_test.cpp
+++ b/tests/component/applypatch_test.cpp
@@ -33,149 +33,155 @@
33#include <openssl/sha.h> 33#include <openssl/sha.h>
34 34
35#include "applypatch/applypatch.h" 35#include "applypatch/applypatch.h"
36#include "applypatch/applypatch_modes.h"
36#include "common/test_constants.h" 37#include "common/test_constants.h"
37#include "print_sha1.h" 38#include "print_sha1.h"
38 39
39static const std::string DATA_PATH = getenv("ANDROID_DATA"); 40static const std::string DATA_PATH = getenv("ANDROID_DATA");
40static const std::string TESTDATA_PATH = "/recovery/testdata"; 41static const std::string TESTDATA_PATH = "/recovery/testdata";
41 42
42static void sha1sum(const std::string& fname, std::string* sha1) { 43static void sha1sum(const std::string& fname, std::string* sha1, size_t* fsize = nullptr) {
43 ASSERT_NE(nullptr, sha1); 44 ASSERT_NE(nullptr, sha1);
44 45
45 std::string data; 46 std::string data;
46 ASSERT_TRUE(android::base::ReadFileToString(fname, &data)); 47 ASSERT_TRUE(android::base::ReadFileToString(fname, &data));
47 48
48 uint8_t digest[SHA_DIGEST_LENGTH]; 49 if (fsize != nullptr) {
49 SHA1(reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), digest); 50 *fsize = data.size();
50 *sha1 = print_sha1(digest); 51 }
52
53 uint8_t digest[SHA_DIGEST_LENGTH];
54 SHA1(reinterpret_cast<const uint8_t*>(data.c_str()), data.size(), digest);
55 *sha1 = print_sha1(digest);
51} 56}
52 57
53static void mangle_file(const std::string& fname) { 58static void mangle_file(const std::string& fname) {
54 std::string content; 59 std::string content;
55 content.reserve(1024); 60 content.reserve(1024);
56 for (size_t i = 0; i < 1024; i++) { 61 for (size_t i = 0; i < 1024; i++) {
57 content[i] = rand() % 256; 62 content[i] = rand() % 256;
58 } 63 }
59 ASSERT_TRUE(android::base::WriteStringToFile(content, fname)); 64 ASSERT_TRUE(android::base::WriteStringToFile(content, fname));
60} 65}
61 66
62static bool file_cmp(const std::string& f1, const std::string& f2) { 67static bool file_cmp(const std::string& f1, const std::string& f2) {
63 std::string c1; 68 std::string c1;
64 android::base::ReadFileToString(f1, &c1); 69 android::base::ReadFileToString(f1, &c1);
65 std::string c2; 70 std::string c2;
66 android::base::ReadFileToString(f2, &c2); 71 android::base::ReadFileToString(f2, &c2);
67 return c1 == c2; 72 return c1 == c2;
68} 73}
69 74
70static std::string from_testdata_base(const std::string& fname) { 75static std::string from_testdata_base(const std::string& fname) {
71 return DATA_PATH + NATIVE_TEST_PATH + TESTDATA_PATH + "/" + fname; 76 return DATA_PATH + NATIVE_TEST_PATH + TESTDATA_PATH + "/" + fname;
72} 77}
73 78
74class ApplyPatchTest : public ::testing::Test { 79class ApplyPatchTest : public ::testing::Test {
75 public: 80 public:
76 static void SetUpTestCase() { 81 static void SetUpTestCase() {
77 // set up files 82 // set up files
78 old_file = from_testdata_base("old.file"); 83 old_file = from_testdata_base("old.file");
79 new_file = from_testdata_base("new.file"); 84 new_file = from_testdata_base("new.file");
80 patch_file = from_testdata_base("patch.bsdiff"); 85 patch_file = from_testdata_base("patch.bsdiff");
81 rand_file = "/cache/applypatch_test_rand.file"; 86 rand_file = "/cache/applypatch_test_rand.file";
82 cache_file = "/cache/saved.file"; 87 cache_file = "/cache/saved.file";
83 88
84 // write stuff to rand_file 89 // write stuff to rand_file
85 ASSERT_TRUE(android::base::WriteStringToFile("hello", rand_file)); 90 ASSERT_TRUE(android::base::WriteStringToFile("hello", rand_file));
86 91
87 // set up SHA constants 92 // set up SHA constants
88 sha1sum(old_file, &old_sha1); 93 sha1sum(old_file, &old_sha1);
89 sha1sum(new_file, &new_sha1); 94 sha1sum(new_file, &new_sha1);
90 srand(time(NULL)); 95 srand(time(nullptr));
91 bad_sha1_a = android::base::StringPrintf("%040x", rand()); 96 bad_sha1_a = android::base::StringPrintf("%040x", rand());
92 bad_sha1_b = android::base::StringPrintf("%040x", rand()); 97 bad_sha1_b = android::base::StringPrintf("%040x", rand());
93 98
94 struct stat st; 99 struct stat st;
95 stat(&new_file[0], &st); 100 stat(&new_file[0], &st);
96 new_size = st.st_size; 101 new_size = st.st_size;
97 } 102 }
98 103
99 static std::string old_file; 104 static std::string old_file;
100 static std::string new_file; 105 static std::string new_file;
101 static std::string rand_file; 106 static std::string rand_file;
102 static std::string cache_file; 107 static std::string cache_file;
103 static std::string patch_file; 108 static std::string patch_file;
104 109
105 static std::string old_sha1; 110 static std::string old_sha1;
106 static std::string new_sha1; 111 static std::string new_sha1;
107 static std::string bad_sha1_a; 112 static std::string bad_sha1_a;
108 static std::string bad_sha1_b; 113 static std::string bad_sha1_b;
109 114
110 static size_t new_size; 115 static size_t new_size;
111}; 116};
112 117
113std::string ApplyPatchTest::old_file; 118std::string ApplyPatchTest::old_file;
114std::string ApplyPatchTest::new_file; 119std::string ApplyPatchTest::new_file;
115 120
116static void cp(const std::string& src, const std::string& tgt) { 121static void cp(const std::string& src, const std::string& tgt) {
117 std::string cmd = "cp " + src + " " + tgt; 122 std::string cmd = "cp " + src + " " + tgt;
118 system(&cmd[0]); 123 system(cmd.c_str());
119} 124}
120 125
121static void backup_old() { 126static void backup_old() {
122 cp(ApplyPatchTest::old_file, ApplyPatchTest::cache_file); 127 cp(ApplyPatchTest::old_file, ApplyPatchTest::cache_file);
123} 128}
124 129
125static void restore_old() { 130static void restore_old() {
126 cp(ApplyPatchTest::cache_file, ApplyPatchTest::old_file); 131 cp(ApplyPatchTest::cache_file, ApplyPatchTest::old_file);
127} 132}
128 133
129class ApplyPatchCacheTest : public ApplyPatchTest { 134class ApplyPatchCacheTest : public ApplyPatchTest {
130 public: 135 public:
131 virtual void SetUp() { 136 virtual void SetUp() {
132 backup_old(); 137 backup_old();
133 } 138 }
134 139
135 virtual void TearDown() { 140 virtual void TearDown() {
136 restore_old(); 141 restore_old();
137 } 142 }
138}; 143};
139 144
140class ApplyPatchFullTest : public ApplyPatchCacheTest { 145class ApplyPatchFullTest : public ApplyPatchCacheTest {
141 public: 146 public:
142 static void SetUpTestCase() { 147 static void SetUpTestCase() {
143 ApplyPatchTest::SetUpTestCase(); 148 ApplyPatchTest::SetUpTestCase();
144 149
145 output_f = new TemporaryFile(); 150 output_f = new TemporaryFile();
146 output_loc = std::string(output_f->path); 151 output_loc = std::string(output_f->path);
147 152
148 struct FileContents fc; 153 struct FileContents fc;
149 154
150 ASSERT_EQ(0, LoadFileContents(&rand_file[0], &fc)); 155 ASSERT_EQ(0, LoadFileContents(&rand_file[0], &fc));
151 patches.push_back( 156 patches.push_back(
152 std::make_unique<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()))); 157 std::make_unique<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end())));
153 158
154 ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc)); 159 ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc));
155 patches.push_back( 160 patches.push_back(
156 std::make_unique<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end()))); 161 std::make_unique<Value>(VAL_BLOB, std::string(fc.data.begin(), fc.data.end())));
157 } 162 }
158 163
159 static void TearDownTestCase() { 164 static void TearDownTestCase() {
160 delete output_f; 165 delete output_f;
161 } 166 patches.clear();
167 }
162 168
163 static std::vector<std::unique_ptr<Value>> patches; 169 static std::vector<std::unique_ptr<Value>> patches;
164 static TemporaryFile* output_f; 170 static TemporaryFile* output_f;
165 static std::string output_loc; 171 static std::string output_loc;
166}; 172};
167 173
168class ApplyPatchDoubleCacheTest : public ApplyPatchFullTest { 174class ApplyPatchDoubleCacheTest : public ApplyPatchFullTest {
169 public: 175 public:
170 virtual void SetUp() { 176 virtual void SetUp() {
171 ApplyPatchCacheTest::SetUp(); 177 ApplyPatchCacheTest::SetUp();
172 cp(cache_file, "/cache/reallysaved.file"); 178 cp(cache_file, "/cache/reallysaved.file");
173 } 179 }
174 180
175 virtual void TearDown() { 181 virtual void TearDown() {
176 cp("/cache/reallysaved.file", cache_file); 182 cp("/cache/reallysaved.file", cache_file);
177 ApplyPatchCacheTest::TearDown(); 183 ApplyPatchCacheTest::TearDown();
178 } 184 }
179}; 185};
180 186
181std::string ApplyPatchTest::rand_file; 187std::string ApplyPatchTest::rand_file;
@@ -193,203 +199,263 @@ TemporaryFile* ApplyPatchFullTest::output_f;
193std::string ApplyPatchFullTest::output_loc; 199std::string ApplyPatchFullTest::output_loc;
194 200
195TEST_F(ApplyPatchTest, CheckModeSkip) { 201TEST_F(ApplyPatchTest, CheckModeSkip) {
196 std::vector<std::string> sha1s; 202 std::vector<std::string> sha1s;
197 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); 203 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
198} 204}
199 205
200TEST_F(ApplyPatchTest, CheckModeSingle) { 206TEST_F(ApplyPatchTest, CheckModeSingle) {
201 std::vector<std::string> sha1s = { old_sha1 }; 207 std::vector<std::string> sha1s = { old_sha1 };
202 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); 208 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
203} 209}
204 210
205TEST_F(ApplyPatchTest, CheckModeMultiple) { 211TEST_F(ApplyPatchTest, CheckModeMultiple) {
206 std::vector<std::string> sha1s = { 212 std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b };
207 bad_sha1_a, 213 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
208 old_sha1,
209 bad_sha1_b
210 };
211 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
212} 214}
213 215
214TEST_F(ApplyPatchTest, CheckModeFailure) { 216TEST_F(ApplyPatchTest, CheckModeFailure) {
215 std::vector<std::string> sha1s = { 217 std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b };
216 bad_sha1_a, 218 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
217 bad_sha1_b
218 };
219 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
220} 219}
221 220
222TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) { 221TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) {
223 mangle_file(old_file); 222 mangle_file(old_file);
224 std::vector<std::string> sha1s = { old_sha1 }; 223 std::vector<std::string> sha1s = { old_sha1 };
225 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); 224 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
226} 225}
227 226
228TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) { 227TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) {
229 mangle_file(old_file); 228 mangle_file(old_file);
230 std::vector<std::string> sha1s = { 229 std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b };
231 bad_sha1_a, 230 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
232 old_sha1,
233 bad_sha1_b
234 };
235 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
236} 231}
237 232
238TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) { 233TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) {
239 mangle_file(old_file); 234 mangle_file(old_file);
240 std::vector<std::string> sha1s = { 235 std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b };
241 bad_sha1_a, 236 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
242 bad_sha1_b
243 };
244 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
245} 237}
246 238
247TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) { 239TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) {
248 unlink(&old_file[0]); 240 unlink(&old_file[0]);
249 std::vector<std::string> sha1s = { old_sha1 }; 241 std::vector<std::string> sha1s = { old_sha1 };
250 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s)); 242 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
251} 243}
252 244
253TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) { 245TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) {
254 unlink(&old_file[0]); 246 unlink(&old_file[0]);
255 std::vector<std::string> sha1s = { 247 std::vector<std::string> sha1s = { bad_sha1_a, old_sha1, bad_sha1_b };
256 bad_sha1_a, 248 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
257 old_sha1,
258 bad_sha1_b
259 };
260 ASSERT_EQ(0, applypatch_check(&old_file[0], sha1s));
261} 249}
262 250
263TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) { 251TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) {
264 unlink(&old_file[0]); 252 unlink(&old_file[0]);
265 std::vector<std::string> sha1s = { 253 std::vector<std::string> sha1s = { bad_sha1_a, bad_sha1_b };
266 bad_sha1_a, 254 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
267 bad_sha1_b
268 };
269 ASSERT_NE(0, applypatch_check(&old_file[0], sha1s));
270} 255}
271 256
272TEST_F(ApplyPatchFullTest, ApplyInPlace) { 257TEST_F(ApplyPatchFullTest, ApplyInPlace) {
273 std::vector<std::string> sha1s = { 258 std::vector<std::string> sha1s = { bad_sha1_a, old_sha1 };
274 bad_sha1_a, 259 ASSERT_EQ(0, applypatch(&old_file[0], "-", &new_sha1[0], new_size, sha1s, patches, nullptr));
275 old_sha1 260 ASSERT_TRUE(file_cmp(old_file, new_file));
276 }; 261
277 int ap_result = applypatch(&old_file[0], 262 // reapply, applypatch is idempotent so it should succeed
278 "-", 263 ASSERT_EQ(0, applypatch(&old_file[0], "-", &new_sha1[0], new_size, sha1s, patches, nullptr));
279 &new_sha1[0], 264 ASSERT_TRUE(file_cmp(old_file, new_file));
280 new_size,
281 sha1s,
282 patches,
283 nullptr);
284 ASSERT_EQ(0, ap_result);
285 ASSERT_TRUE(file_cmp(old_file, new_file));
286 // reapply, applypatch is idempotent so it should succeed
287 ap_result = applypatch(&old_file[0],
288 "-",
289 &new_sha1[0],
290 new_size,
291 sha1s,
292 patches,
293 nullptr);
294 ASSERT_EQ(0, ap_result);
295 ASSERT_TRUE(file_cmp(old_file, new_file));
296} 265}
297 266
298TEST_F(ApplyPatchFullTest, ApplyInNewLocation) { 267TEST_F(ApplyPatchFullTest, ApplyInNewLocation) {
299 std::vector<std::string> sha1s = { 268 std::vector<std::string> sha1s = { bad_sha1_a, old_sha1 };
300 bad_sha1_a, 269 // Apply bsdiff patch to new location.
301 old_sha1 270 ASSERT_EQ(
302 }; 271 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
303 // Apply bsdiff patch to new location. 272 ASSERT_TRUE(file_cmp(output_loc, new_file));
304 ASSERT_EQ(0, applypatch(&old_file[0], 273
305 &output_loc[0], 274 // Reapply to the same location.
306 &new_sha1[0], 275 ASSERT_EQ(
307 new_size, 276 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
308 sha1s, 277 ASSERT_TRUE(file_cmp(output_loc, new_file));
309 patches,
310 nullptr));
311 ASSERT_TRUE(file_cmp(output_loc, new_file));
312
313 // Reapply to the same location.
314 ASSERT_EQ(0, applypatch(&old_file[0],
315 &output_loc[0],
316 &new_sha1[0],
317 new_size,
318 sha1s,
319 patches,
320 nullptr));
321 ASSERT_TRUE(file_cmp(output_loc, new_file));
322} 278}
323 279
324TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) { 280TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) {
325 std::vector<std::string> sha1s = { 281 std::vector<std::string> sha1s = { bad_sha1_a, old_sha1 };
326 bad_sha1_a, 282 // Apply bsdiff patch to new location with corrupted source.
327 old_sha1 283 mangle_file(old_file);
328 }; 284 ASSERT_EQ(
329 // Apply bsdiff patch to new location with corrupted source. 285 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
330 mangle_file(old_file); 286 ASSERT_TRUE(file_cmp(output_loc, new_file));
331 int ap_result = applypatch(&old_file[0], 287
332 &output_loc[0], 288 // Reapply bsdiff patch to new location with corrupted source.
333 &new_sha1[0], 289 ASSERT_EQ(
334 new_size, 290 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
335 sha1s, 291 ASSERT_TRUE(file_cmp(output_loc, new_file));
336 patches,
337 nullptr);
338 ASSERT_EQ(0, ap_result);
339 ASSERT_TRUE(file_cmp(output_loc, new_file));
340
341 // Reapply bsdiff patch to new location with corrupted source.
342 ap_result = applypatch(&old_file[0],
343 &output_loc[0],
344 &new_sha1[0],
345 new_size,
346 sha1s,
347 patches,
348 nullptr);
349 ASSERT_EQ(0, ap_result);
350 ASSERT_TRUE(file_cmp(output_loc, new_file));
351} 292}
352 293
353TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) { 294TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) {
354 std::vector<std::string> sha1s = { 295 std::vector<std::string> sha1s = { bad_sha1_a, old_sha1 };
355 bad_sha1_a, 296
356 old_sha1 297 // Apply bsdiff patch to new location with corrupted source and copy (no new file).
357 }; 298 // Expected to fail.
358 299 mangle_file(old_file);
359 // Apply bsdiff patch to new location with corrupted source and copy (no new file). 300 mangle_file(cache_file);
360 // Expected to fail. 301 ASSERT_NE(
361 mangle_file(old_file); 302 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
362 mangle_file(cache_file); 303 ASSERT_FALSE(file_cmp(output_loc, new_file));
363 int ap_result = applypatch(&old_file[0], 304
364 &output_loc[0], 305 // Expected to fail again on retry.
365 &new_sha1[0], 306 ASSERT_NE(
366 new_size, 307 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
367 sha1s, 308 ASSERT_FALSE(file_cmp(output_loc, new_file));
368 patches, 309
369 nullptr); 310 // Expected to fail with incorrect new file.
370 ASSERT_NE(0, ap_result); 311 mangle_file(output_loc);
371 ASSERT_FALSE(file_cmp(output_loc, new_file)); 312 ASSERT_NE(
372 313 0, applypatch(&old_file[0], &output_loc[0], &new_sha1[0], new_size, sha1s, patches, nullptr));
373 // Expected to fail again on retry. 314 ASSERT_FALSE(file_cmp(output_loc, new_file));
374 ap_result = applypatch(&old_file[0], 315}
375 &output_loc[0], 316
376 &new_sha1[0], 317TEST(ApplyPatchModes, InvalidArgs) {
377 new_size, 318 // At least two args (including the filename).
378 sha1s, 319 ASSERT_EQ(2, applypatch_modes(1, (const char* []){ "applypatch" }));
379 patches, 320
380 nullptr); 321 // Unrecognized args.
381 ASSERT_NE(0, ap_result); 322 ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-x" }));
382 ASSERT_FALSE(file_cmp(output_loc, new_file)); 323}
383 324
384 // Expected to fail with incorrect new file. 325TEST(ApplyPatchModes, PatchMode) {
385 mangle_file(output_loc); 326 std::string boot_img = from_testdata_base("boot.img");
386 ap_result = applypatch(&old_file[0], 327 size_t boot_img_size;
387 &output_loc[0], 328 std::string boot_img_sha1;
388 &new_sha1[0], 329 sha1sum(boot_img, &boot_img_sha1, &boot_img_size);
389 new_size, 330
390 sha1s, 331 std::string recovery_img = from_testdata_base("recovery.img");
391 patches, 332 size_t recovery_img_size;
392 nullptr); 333 std::string recovery_img_sha1;
393 ASSERT_NE(0, ap_result); 334 sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size);
394 ASSERT_FALSE(file_cmp(output_loc, new_file)); 335
336 std::string bonus_file = from_testdata_base("bonus.file");
337
338 // applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch>
339 TemporaryFile tmp1;
340 std::vector<const char*> args = {
341 "applypatch",
342 "-b",
343 bonus_file.c_str(),
344 boot_img.c_str(),
345 tmp1.path,
346 recovery_img_sha1.c_str(),
347 std::to_string(recovery_img_size).c_str(),
348 (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p")).c_str()
349 };
350 ASSERT_EQ(0, applypatch_modes(args.size(), args.data()));
351
352 // applypatch <src-file> <tgt-file> <tgt-sha1> <tgt-size> <src-sha1>:<patch>
353 TemporaryFile tmp2;
354 std::vector<const char*> args2 = {
355 "applypatch",
356 boot_img.c_str(),
357 tmp2.path,
358 recovery_img_sha1.c_str(),
359 std::to_string(recovery_img_size).c_str(),
360 (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str()
361 };
362 ASSERT_EQ(0, applypatch_modes(args2.size(), args2.data()));
363
364 // applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size> \
365 // <src-sha1-fake>:<patch1> <src-sha1>:<patch2>
366 TemporaryFile tmp3;
367 std::string bad_sha1_a = android::base::StringPrintf("%040x", rand());
368 std::string bad_sha1_b = android::base::StringPrintf("%040x", rand());
369 std::vector<const char*> args3 = {
370 "applypatch",
371 "-b",
372 bonus_file.c_str(),
373 boot_img.c_str(),
374 tmp3.path,
375 recovery_img_sha1.c_str(),
376 std::to_string(recovery_img_size).c_str(),
377 (bad_sha1_a + ":" + from_testdata_base("recovery-from-boot.p")).c_str(),
378 (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot.p")).c_str(),
379 (bad_sha1_b + ":" + from_testdata_base("recovery-from-boot.p")).c_str(),
380 };
381 ASSERT_EQ(0, applypatch_modes(args3.size(), args3.data()));
382}
383
384TEST(ApplyPatchModes, PatchModeInvalidArgs) {
385 // Invalid bonus file.
386 ASSERT_NE(0, applypatch_modes(3, (const char* []){ "applypatch", "-b", "/doesntexist" }));
387
388 std::string bonus_file = from_testdata_base("bonus.file");
389 // With bonus file, but missing args.
390 ASSERT_EQ(2, applypatch_modes(3, (const char* []){ "applypatch", "-b", bonus_file.c_str() }));
391
392 std::string boot_img = from_testdata_base("boot.img");
393 size_t boot_img_size;
394 std::string boot_img_sha1;
395 sha1sum(boot_img, &boot_img_sha1, &boot_img_size);
396
397 std::string recovery_img = from_testdata_base("recovery.img");
398 size_t recovery_img_size;
399 std::string recovery_img_sha1;
400 sha1sum(recovery_img, &recovery_img_sha1, &recovery_img_size);
401
402 // Bonus file is not supported in flash mode.
403 // applypatch -b <bonus-file> <src-file> <tgt-file> <tgt-sha1> <tgt-size>
404 TemporaryFile tmp4;
405 std::vector<const char*> args4 = {
406 "applypatch",
407 "-b",
408 bonus_file.c_str(),
409 boot_img.c_str(),
410 tmp4.path,
411 recovery_img_sha1.c_str(),
412 std::to_string(recovery_img_size).c_str() };
413 ASSERT_NE(0, applypatch_modes(args4.size(), args4.data()));
414
415 // Failed to parse patch args.
416 TemporaryFile tmp5;
417 std::vector<const char*> args5 = {
418 "applypatch",
419 boot_img.c_str(),
420 tmp5.path,
421 recovery_img_sha1.c_str(),
422 std::to_string(recovery_img_size).c_str(),
423 ("invalid-sha1:filename" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str(),
424 };
425 ASSERT_NE(0, applypatch_modes(args5.size(), args5.data()));
426
427 // Target size cannot be zero.
428 TemporaryFile tmp6;
429 std::vector<const char*> args6 = {
430 "applypatch",
431 boot_img.c_str(),
432 tmp6.path,
433 recovery_img_sha1.c_str(),
434 "0", // target size
435 (boot_img_sha1 + ":" + from_testdata_base("recovery-from-boot-with-bonus.p")).c_str()
436 };
437 ASSERT_NE(0, applypatch_modes(args6.size(), args6.data()));
438}
439
440TEST(ApplyPatchModes, CheckModeInvalidArgs) {
441 // Insufficient args.
442 ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-c" }));
443}
444
445TEST(ApplyPatchModes, SpaceModeInvalidArgs) {
446 // Insufficient args.
447 ASSERT_EQ(2, applypatch_modes(2, (const char* []){ "applypatch", "-s" }));
448
449 // Invalid bytes arg.
450 ASSERT_EQ(1, applypatch_modes(3, (const char* []){ "applypatch", "-s", "x" }));
451
452 // 0 is invalid.
453 ASSERT_EQ(1, applypatch_modes(3, (const char* []){ "applypatch", "-s", "0" }));
454
455 // 0x10 is fine.
456 ASSERT_EQ(0, applypatch_modes(3, (const char* []){ "applypatch", "-s", "0x10" }));
457}
458
459TEST(ApplyPatchModes, ShowLicenses) {
460 ASSERT_EQ(0, applypatch_modes(2, (const char* []){ "applypatch", "-l" }));
395} 461}
diff --git a/tests/testdata/bonus.file b/tests/testdata/bonus.file
new file mode 100644
index 00000000..918ef8ac
--- /dev/null
+++ b/tests/testdata/bonus.file
Binary files differ
diff --git a/tests/testdata/boot.img b/tests/testdata/boot.img
new file mode 100644
index 00000000..dd489751
--- /dev/null
+++ b/tests/testdata/boot.img
Binary files differ
diff --git a/tests/testdata/recovery-from-boot-with-bonus.p b/tests/testdata/recovery-from-boot-with-bonus.p
new file mode 100644
index 00000000..08b6f55e
--- /dev/null
+++ b/tests/testdata/recovery-from-boot-with-bonus.p
Binary files differ
diff --git a/tests/testdata/recovery-from-boot.p b/tests/testdata/recovery-from-boot.p
new file mode 100644
index 00000000..06f6c299
--- /dev/null
+++ b/tests/testdata/recovery-from-boot.p
Binary files differ
diff --git a/tests/testdata/recovery.img b/tests/testdata/recovery.img
new file mode 100644
index 00000000..b862e6f0
--- /dev/null
+++ b/tests/testdata/recovery.img
Binary files differ