Bring back file-based OTA edify functions
Author: Tom Marshall <tdm.code@gmail.com>
Date: Wed Oct 25 20:27:08 2017 +0200
Revert "kill package_extract_dir"
changes for P:
- bring back the mkdir_recursively variant which takes a timestamp.
- add libziparchive dependency
- fix otautil header paths
changes for Q:
- change ziputil naming convention to lowercase
This reverts commit 53c38b15381ace565227e49104a6fd64c4c28dcc.
Change-Id: I71c488e96a1f23aace3c38fc283aae0165129a12
Author: Tom Marshall <tdm.code@gmail.com>
Date: Thu Dec 14 22:37:17 2017 +0100
Revert "Remove the obsolete package_extract_dir() test"
This reverts commit bb7e005a7906b02857ba328c5dfb11f1f3cb938e.
Change-Id: I643235d6605d7da2a189eca10ec999b25c23e1f9
Author: Tom Marshall <tdm.code@gmail.com>
Date: Wed Aug 23 18:14:00 2017 +0000
Revert "updater: Remove some obsoleted functions for file-based OTA."
This reverts commit 63d786cf22cb44fe32e8b9c1f18b32da3c9d2e1b.
These functions will be used for third party OTA zips, so keep them.
Change-Id: I24b67ba4c86f8f86d0a41429a395fece1a383efd
Author: Stricted <info@stricted.net>
Date: Mon Mar 12 18:11:56 2018 +0100
recovery: updater: Fix SymlinkFn args
Change-Id: If2ba1b7a8b5ac471a2db84f352273fd0ea7c81a2
Author: Simon Shields <simon@lineageos.org>
Date: Thu Aug 9 01:17:21 2018 +1000
Revert "updater: Remove dead make_parents()."
This reverts commit 5902691764e041bfed8edbc66a72e0854d18dfda.
Change-Id: I69eadf1a091f6ecd45531789dedf72a178a055ba
Author: Simon Shields <simon@lineageos.org>
Date: Thu Aug 9 01:20:40 2018 +1000
Revert "otautil: Delete dirUnlinkHierarchy()."
changes for P:
- Fix missing PATH_MAX macro from limits.h
This reverts commit 7934985e0cac4a3849418af3b8c9671f4d61078a.
Change-Id: I67ce71a1644b58a393dce45a6c3dee97830b9ee4
[mikeioannina]: Squash for Q and run through clang-format
Change-Id: I91973bc9e9f8d100688c0112fda9043fd45eb86a
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index a0a7b66..af2deae 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -306,6 +306,215 @@
expect("", script6, kNoCause);
}
+TEST_F(UpdaterTest, delete) {
+ // Delete none.
+ expect("0", "delete()", kNoCause);
+ expect("0", "delete(\"/doesntexist\")", kNoCause);
+ expect("0", "delete(\"/doesntexist1\", \"/doesntexist2\")", kNoCause);
+ expect("0", "delete(\"/doesntexist1\", \"/doesntexist2\", \"/doesntexist3\")", kNoCause);
+
+ // Delete one file.
+ TemporaryFile temp_file1;
+ ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file1.path));
+ std::string script1("delete(\"" + std::string(temp_file1.path) + "\")");
+ expect("1", script1.c_str(), kNoCause);
+
+ // Delete two files.
+ TemporaryFile temp_file2;
+ ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file2.path));
+ TemporaryFile temp_file3;
+ ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file3.path));
+ std::string script2("delete(\"" + std::string(temp_file2.path) + "\", \"" +
+ std::string(temp_file3.path) + "\")");
+ expect("2", script2.c_str(), kNoCause);
+
+ // Delete already deleted files.
+ expect("0", script2.c_str(), kNoCause);
+
+ // Delete one out of three.
+ TemporaryFile temp_file4;
+ ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file4.path));
+ std::string script3("delete(\"/doesntexist1\", \"" + std::string(temp_file4.path) +
+ "\", \"/doesntexist2\")");
+ expect("1", script3.c_str(), kNoCause);
+}
+
+TEST_F(UpdaterTest, rename) {
+ // rename() expects two arguments.
+ expect(nullptr, "rename()", kArgsParsingFailure);
+ expect(nullptr, "rename(\"arg1\")", kArgsParsingFailure);
+ expect(nullptr, "rename(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
+
+ // src_name or dst_name cannot be empty.
+ expect(nullptr, "rename(\"\", \"arg2\")", kArgsParsingFailure);
+ expect(nullptr, "rename(\"arg1\", \"\")", kArgsParsingFailure);
+
+ // File doesn't exist (both of src and dst).
+ expect(nullptr, "rename(\"/doesntexist\", \"/doesntexisteither\")", kFileRenameFailure);
+
+ // Can't create parent directory.
+ TemporaryFile temp_file1;
+ ASSERT_TRUE(android::base::WriteStringToFile("abc", temp_file1.path));
+ std::string script1("rename(\"" + std::string(temp_file1.path) + "\", \"/proc/0/file1\")");
+ expect(nullptr, script1.c_str(), kFileRenameFailure);
+
+ // Rename.
+ TemporaryFile temp_file2;
+ std::string script2("rename(\"" + std::string(temp_file1.path) + "\", \"" +
+ std::string(temp_file2.path) + "\")");
+ expect(temp_file2.path, script2.c_str(), kNoCause);
+
+ // Already renamed.
+ expect(temp_file2.path, script2.c_str(), kNoCause);
+
+ // Parents create successfully.
+ TemporaryFile temp_file3;
+ TemporaryDir td;
+ std::string temp_dir(td.path);
+ std::string dst_file = temp_dir + "/aaa/bbb/a.txt";
+ std::string script3("rename(\"" + std::string(temp_file3.path) + "\", \"" + dst_file + "\")");
+ expect(dst_file.c_str(), script3.c_str(), kNoCause);
+
+ // Clean up the temp files under td.
+ ASSERT_EQ(0, unlink(dst_file.c_str()));
+ ASSERT_EQ(0, rmdir((temp_dir + "/aaa/bbb").c_str()));
+ ASSERT_EQ(0, rmdir((temp_dir + "/aaa").c_str()));
+}
+
+TEST_F(UpdaterTest, symlink) {
+ // symlink expects 1+ argument.
+ expect(nullptr, "symlink()", kArgsParsingFailure);
+
+ // symlink should fail if src is an empty string.
+ TemporaryFile temp_file1;
+ std::string script1("symlink(\"" + std::string(temp_file1.path) + "\", \"\")");
+ expect(nullptr, script1.c_str(), kSymlinkFailure);
+
+ std::string script2("symlink(\"" + std::string(temp_file1.path) + "\", \"src1\", \"\")");
+ expect(nullptr, script2.c_str(), kSymlinkFailure);
+
+ // symlink failed to remove old src.
+ std::string script3("symlink(\"" + std::string(temp_file1.path) + "\", \"/proc\")");
+ expect(nullptr, script3.c_str(), kSymlinkFailure);
+
+ // symlink can create symlinks.
+ TemporaryFile temp_file;
+ std::string content = "magicvalue";
+ ASSERT_TRUE(android::base::WriteStringToFile(content, temp_file.path));
+
+ TemporaryDir td;
+ std::string src1 = std::string(td.path) + "/symlink1";
+ std::string src2 = std::string(td.path) + "/symlink2";
+ std::string script4("symlink(\"" + std::string(temp_file.path) + "\", \"" + src1 + "\", \"" +
+ src2 + "\")");
+ expect("t", script4.c_str(), kNoCause);
+
+ // Verify the created symlinks.
+ struct stat sb;
+ ASSERT_TRUE(lstat(src1.c_str(), &sb) == 0 && S_ISLNK(sb.st_mode));
+ ASSERT_TRUE(lstat(src2.c_str(), &sb) == 0 && S_ISLNK(sb.st_mode));
+
+ // Clean up the leftovers.
+ ASSERT_EQ(0, unlink(src1.c_str()));
+ ASSERT_EQ(0, unlink(src2.c_str()));
+}
+
+TEST_F(UpdaterTest, package_extract_dir) {
+ // package_extract_dir expects 2 arguments.
+ expect(nullptr, "package_extract_dir()", kArgsParsingFailure);
+ expect(nullptr, "package_extract_dir(\"arg1\")", kArgsParsingFailure);
+ expect(nullptr, "package_extract_dir(\"arg1\", \"arg2\", \"arg3\")", kArgsParsingFailure);
+
+ std::string zip_path = from_testdata_base("ziptest_valid.zip");
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchive(zip_path.c_str(), &handle));
+
+ // Need to set up the ziphandle.
+ UpdaterInfo updater_info;
+ updater_info.package_zip = handle;
+
+ // Extract "b/c.txt" and "b/d.txt" with package_extract_dir("b", "<dir>").
+ TemporaryDir td;
+ std::string temp_dir(td.path);
+ std::string script("package_extract_dir(\"b\", \"" + temp_dir + "\")");
+ expect("t", script.c_str(), kNoCause, &updater_info);
+
+ // Verify.
+ std::string data;
+ std::string file_c = temp_dir + "/c.txt";
+ ASSERT_TRUE(android::base::ReadFileToString(file_c, &data));
+ ASSERT_EQ(kCTxtContents, data);
+
+ std::string file_d = temp_dir + "/d.txt";
+ ASSERT_TRUE(android::base::ReadFileToString(file_d, &data));
+ ASSERT_EQ(kDTxtContents, data);
+
+ // Modify the contents in order to retry. It's expected to be overwritten.
+ ASSERT_TRUE(android::base::WriteStringToFile("random", file_c));
+ ASSERT_TRUE(android::base::WriteStringToFile("random", file_d));
+
+ // Extract again and verify.
+ expect("t", script.c_str(), kNoCause, &updater_info);
+
+ ASSERT_TRUE(android::base::ReadFileToString(file_c, &data));
+ ASSERT_EQ(kCTxtContents, data);
+ ASSERT_TRUE(android::base::ReadFileToString(file_d, &data));
+ ASSERT_EQ(kDTxtContents, data);
+
+ // Clean up the temp files under td.
+ ASSERT_EQ(0, unlink(file_c.c_str()));
+ ASSERT_EQ(0, unlink(file_d.c_str()));
+
+ // Extracting "b/" (with slash) should give the same result.
+ script = "package_extract_dir(\"b/\", \"" + temp_dir + "\")";
+ expect("t", script.c_str(), kNoCause, &updater_info);
+
+ ASSERT_TRUE(android::base::ReadFileToString(file_c, &data));
+ ASSERT_EQ(kCTxtContents, data);
+ ASSERT_TRUE(android::base::ReadFileToString(file_d, &data));
+ ASSERT_EQ(kDTxtContents, data);
+
+ ASSERT_EQ(0, unlink(file_c.c_str()));
+ ASSERT_EQ(0, unlink(file_d.c_str()));
+
+ // Extracting "" is allowed. The entries will carry the path name.
+ script = "package_extract_dir(\"\", \"" + temp_dir + "\")";
+ expect("t", script.c_str(), kNoCause, &updater_info);
+
+ std::string file_a = temp_dir + "/a.txt";
+ ASSERT_TRUE(android::base::ReadFileToString(file_a, &data));
+ ASSERT_EQ(kATxtContents, data);
+ std::string file_b = temp_dir + "/b.txt";
+ ASSERT_TRUE(android::base::ReadFileToString(file_b, &data));
+ ASSERT_EQ(kBTxtContents, data);
+ std::string file_b_c = temp_dir + "/b/c.txt";
+ ASSERT_TRUE(android::base::ReadFileToString(file_b_c, &data));
+ ASSERT_EQ(kCTxtContents, data);
+ std::string file_b_d = temp_dir + "/b/d.txt";
+ ASSERT_TRUE(android::base::ReadFileToString(file_b_d, &data));
+ ASSERT_EQ(kDTxtContents, data);
+
+ ASSERT_EQ(0, unlink(file_a.c_str()));
+ ASSERT_EQ(0, unlink(file_b.c_str()));
+ ASSERT_EQ(0, unlink(file_b_c.c_str()));
+ ASSERT_EQ(0, unlink(file_b_d.c_str()));
+ ASSERT_EQ(0, rmdir((temp_dir + "/b").c_str()));
+
+ // Extracting non-existent entry should still give "t".
+ script = "package_extract_dir(\"doesntexist\", \"" + temp_dir + "\")";
+ expect("t", script.c_str(), kNoCause, &updater_info);
+
+ // Only relative zip_path is allowed.
+ script = "package_extract_dir(\"/b\", \"" + temp_dir + "\")";
+ expect("", script.c_str(), kNoCause, &updater_info);
+
+ // Only absolute dest_path is allowed.
+ script = "package_extract_dir(\"b\", \"path\")";
+ expect("", script.c_str(), kNoCause, &updater_info);
+
+ CloseArchive(handle);
+}
+
// TODO: Test extracting to block device.
TEST_F(UpdaterTest, package_extract_file) {
// package_extract_file expects 1 or 2 arguments.