Loading tools/aapt2/format/Archive_test.cpp +110 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. */ #include <stdlib.h> #include "test/Test.h" namespace aapt { Loading @@ -34,6 +36,29 @@ class TestData : public io::MallocData { std::string error_; }; class TzSetter { public: explicit TzSetter(const std::string& new_tz) { old_tz_ = getenv("TZ"); new_tz_ = "TZ=" + new_tz; putenv(const_cast<char*>(new_tz_.c_str())); tzset(); } ~TzSetter() { if (old_tz_) { putenv(old_tz_); } else { putenv(const_cast<char*>("TZ")); } tzset(); } private: char* old_tz_; std::string new_tz_; }; std::unique_ptr<uint8_t[]> MakeTestArray() { auto array = std::make_unique<uint8_t[]>(kTestDataLength); for (int index = 0; index < kTestDataLength; ++index) { Loading Loading @@ -86,6 +111,22 @@ void VerifyZipFile(const std::string& output_path, const std::string& file, cons } } void VerifyZipFileTimestamps(const std::string& output_path) { std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(output_path, nullptr); auto it = zip->Iterator(); while (it->HasNext()) { auto file = it->Next(); struct tm modification_time; ASSERT_TRUE(file->GetModificationTime(&modification_time)); EXPECT_EQ(modification_time.tm_year, 80); EXPECT_EQ(modification_time.tm_mon, 0); EXPECT_EQ(modification_time.tm_mday, 1); EXPECT_EQ(modification_time.tm_hour, 0); EXPECT_EQ(modification_time.tm_min, 0); EXPECT_EQ(modification_time.tm_sec, 0); } } TEST_F(ArchiveTest, DirectoryWriteEntrySuccess) { std::string output_path = GetTestPath("output"); std::unique_ptr<IArchiveWriter> writer = MakeDirectoryWriter(output_path); Loading Loading @@ -206,4 +247,73 @@ TEST_F(ArchiveTest, ZipFileWriteFileError) { ASSERT_EQ("ZipFileWriteFileError", writer->GetError()); } TEST_F(ArchiveTest, ZipFileTimeZoneUTC) { TzSetter tz("UTC0"); std::string output_path = GetTestPath("output.apk"); std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path); std::unique_ptr<uint8_t[]> data1 = MakeTestArray(); std::unique_ptr<uint8_t[]> data2 = MakeTestArray(); ASSERT_TRUE(writer->StartEntry("test1", 0)); ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength)); ASSERT_TRUE(writer->FinishEntry()); ASSERT_FALSE(writer->HadError()); ASSERT_TRUE(writer->StartEntry("test2", 0)); ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength)); ASSERT_TRUE(writer->FinishEntry()); ASSERT_FALSE(writer->HadError()); writer.reset(); // All zip file entries must have the same timestamp, regardless of time zone. See: b/277978832 VerifyZipFileTimestamps(output_path); } TEST_F(ArchiveTest, ZipFileTimeZoneWestOfUTC) { TzSetter tz("PST8"); std::string output_path = GetTestPath("output.apk"); std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path); std::unique_ptr<uint8_t[]> data1 = MakeTestArray(); std::unique_ptr<uint8_t[]> data2 = MakeTestArray(); ASSERT_TRUE(writer->StartEntry("test1", 0)); ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength)); ASSERT_TRUE(writer->FinishEntry()); ASSERT_FALSE(writer->HadError()); ASSERT_TRUE(writer->StartEntry("test2", 0)); ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength)); ASSERT_TRUE(writer->FinishEntry()); ASSERT_FALSE(writer->HadError()); writer.reset(); // All zip file entries must have the same timestamp, regardless of time zone. See: b/277978832 VerifyZipFileTimestamps(output_path); } TEST_F(ArchiveTest, ZipFileTimeZoneEastOfUTC) { TzSetter tz("EET-2"); std::string output_path = GetTestPath("output.apk"); std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path); std::unique_ptr<uint8_t[]> data1 = MakeTestArray(); std::unique_ptr<uint8_t[]> data2 = MakeTestArray(); ASSERT_TRUE(writer->StartEntry("test1", 0)); ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength)); ASSERT_TRUE(writer->FinishEntry()); ASSERT_FALSE(writer->HadError()); ASSERT_TRUE(writer->StartEntry("test2", 0)); ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength)); ASSERT_TRUE(writer->FinishEntry()); ASSERT_FALSE(writer->HadError()); writer.reset(); // All zip file entries must have the same timestamp, regardless of time zone. See: b/277978832 VerifyZipFileTimestamps(output_path); } } // namespace aapt tools/aapt2/io/File.h +9 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,11 @@ class IFile { return false; } // Fills in buf with the last modification time of the file. Returns true if successful, // otherwise false (i.e., the operation is not supported or the file system is unable to provide // a last modification time). virtual bool GetModificationTime(struct tm* buf) const = 0; private: // Any segments created from this IFile need to be owned by this IFile, so // keep them Loading @@ -79,6 +84,10 @@ class FileSegment : public IFile { return file_->GetSource(); } bool GetModificationTime(struct tm* buf) const override { return file_->GetModificationTime(buf); }; private: DISALLOW_COPY_AND_ASSIGN(FileSegment); Loading tools/aapt2/io/FileSystem.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -14,9 +14,12 @@ * limitations under the License. */ #define _POSIX_THREAD_SAFE_FUNCTIONS // For mingw localtime_r(). #include "io/FileSystem.h" #include <dirent.h> #include <sys/stat.h> #include "android-base/errors.h" #include "androidfw/Source.h" Loading Loading @@ -54,6 +57,23 @@ const android::Source& RegularFile::GetSource() const { return source_; } bool RegularFile::GetModificationTime(struct tm* buf) const { if (buf == nullptr) { return false; } struct stat stat_buf; if (stat(source_.path.c_str(), &stat_buf) != 0) { return false; } struct tm* ptm; struct tm tm_result; ptm = localtime_r(&stat_buf.st_mtime, &tm_result); *buf = *ptm; return true; } FileCollectionIterator::FileCollectionIterator(FileCollection* collection) : current_(collection->files_.begin()), end_(collection->files_.end()) {} Loading tools/aapt2/io/FileSystem.h +1 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ class RegularFile : public IFile { std::unique_ptr<IData> OpenAsData() override; std::unique_ptr<io::InputStream> OpenInputStream() override; const android::Source& GetSource() const override; bool GetModificationTime(struct tm* buf) const override; private: DISALLOW_COPY_AND_ASSIGN(RegularFile); Loading tools/aapt2/io/ZipArchive.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,14 @@ bool ZipFile::WasCompressed() { return zip_entry_.method != kCompressStored; } bool ZipFile::GetModificationTime(struct tm* buf) const { if (buf == nullptr) { return false; } *buf = zip_entry_.GetModificationTime(); return true; } ZipFileCollectionIterator::ZipFileCollectionIterator( ZipFileCollection* collection) : current_(collection->files_.begin()), end_(collection->files_.end()) {} Loading Loading
tools/aapt2/format/Archive_test.cpp +110 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. */ #include <stdlib.h> #include "test/Test.h" namespace aapt { Loading @@ -34,6 +36,29 @@ class TestData : public io::MallocData { std::string error_; }; class TzSetter { public: explicit TzSetter(const std::string& new_tz) { old_tz_ = getenv("TZ"); new_tz_ = "TZ=" + new_tz; putenv(const_cast<char*>(new_tz_.c_str())); tzset(); } ~TzSetter() { if (old_tz_) { putenv(old_tz_); } else { putenv(const_cast<char*>("TZ")); } tzset(); } private: char* old_tz_; std::string new_tz_; }; std::unique_ptr<uint8_t[]> MakeTestArray() { auto array = std::make_unique<uint8_t[]>(kTestDataLength); for (int index = 0; index < kTestDataLength; ++index) { Loading Loading @@ -86,6 +111,22 @@ void VerifyZipFile(const std::string& output_path, const std::string& file, cons } } void VerifyZipFileTimestamps(const std::string& output_path) { std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(output_path, nullptr); auto it = zip->Iterator(); while (it->HasNext()) { auto file = it->Next(); struct tm modification_time; ASSERT_TRUE(file->GetModificationTime(&modification_time)); EXPECT_EQ(modification_time.tm_year, 80); EXPECT_EQ(modification_time.tm_mon, 0); EXPECT_EQ(modification_time.tm_mday, 1); EXPECT_EQ(modification_time.tm_hour, 0); EXPECT_EQ(modification_time.tm_min, 0); EXPECT_EQ(modification_time.tm_sec, 0); } } TEST_F(ArchiveTest, DirectoryWriteEntrySuccess) { std::string output_path = GetTestPath("output"); std::unique_ptr<IArchiveWriter> writer = MakeDirectoryWriter(output_path); Loading Loading @@ -206,4 +247,73 @@ TEST_F(ArchiveTest, ZipFileWriteFileError) { ASSERT_EQ("ZipFileWriteFileError", writer->GetError()); } TEST_F(ArchiveTest, ZipFileTimeZoneUTC) { TzSetter tz("UTC0"); std::string output_path = GetTestPath("output.apk"); std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path); std::unique_ptr<uint8_t[]> data1 = MakeTestArray(); std::unique_ptr<uint8_t[]> data2 = MakeTestArray(); ASSERT_TRUE(writer->StartEntry("test1", 0)); ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength)); ASSERT_TRUE(writer->FinishEntry()); ASSERT_FALSE(writer->HadError()); ASSERT_TRUE(writer->StartEntry("test2", 0)); ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength)); ASSERT_TRUE(writer->FinishEntry()); ASSERT_FALSE(writer->HadError()); writer.reset(); // All zip file entries must have the same timestamp, regardless of time zone. See: b/277978832 VerifyZipFileTimestamps(output_path); } TEST_F(ArchiveTest, ZipFileTimeZoneWestOfUTC) { TzSetter tz("PST8"); std::string output_path = GetTestPath("output.apk"); std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path); std::unique_ptr<uint8_t[]> data1 = MakeTestArray(); std::unique_ptr<uint8_t[]> data2 = MakeTestArray(); ASSERT_TRUE(writer->StartEntry("test1", 0)); ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength)); ASSERT_TRUE(writer->FinishEntry()); ASSERT_FALSE(writer->HadError()); ASSERT_TRUE(writer->StartEntry("test2", 0)); ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength)); ASSERT_TRUE(writer->FinishEntry()); ASSERT_FALSE(writer->HadError()); writer.reset(); // All zip file entries must have the same timestamp, regardless of time zone. See: b/277978832 VerifyZipFileTimestamps(output_path); } TEST_F(ArchiveTest, ZipFileTimeZoneEastOfUTC) { TzSetter tz("EET-2"); std::string output_path = GetTestPath("output.apk"); std::unique_ptr<IArchiveWriter> writer = MakeZipFileWriter(output_path); std::unique_ptr<uint8_t[]> data1 = MakeTestArray(); std::unique_ptr<uint8_t[]> data2 = MakeTestArray(); ASSERT_TRUE(writer->StartEntry("test1", 0)); ASSERT_TRUE(writer->Write(static_cast<const void*>(data1.get()), kTestDataLength)); ASSERT_TRUE(writer->FinishEntry()); ASSERT_FALSE(writer->HadError()); ASSERT_TRUE(writer->StartEntry("test2", 0)); ASSERT_TRUE(writer->Write(static_cast<const void*>(data2.get()), kTestDataLength)); ASSERT_TRUE(writer->FinishEntry()); ASSERT_FALSE(writer->HadError()); writer.reset(); // All zip file entries must have the same timestamp, regardless of time zone. See: b/277978832 VerifyZipFileTimestamps(output_path); } } // namespace aapt
tools/aapt2/io/File.h +9 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,11 @@ class IFile { return false; } // Fills in buf with the last modification time of the file. Returns true if successful, // otherwise false (i.e., the operation is not supported or the file system is unable to provide // a last modification time). virtual bool GetModificationTime(struct tm* buf) const = 0; private: // Any segments created from this IFile need to be owned by this IFile, so // keep them Loading @@ -79,6 +84,10 @@ class FileSegment : public IFile { return file_->GetSource(); } bool GetModificationTime(struct tm* buf) const override { return file_->GetModificationTime(buf); }; private: DISALLOW_COPY_AND_ASSIGN(FileSegment); Loading
tools/aapt2/io/FileSystem.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -14,9 +14,12 @@ * limitations under the License. */ #define _POSIX_THREAD_SAFE_FUNCTIONS // For mingw localtime_r(). #include "io/FileSystem.h" #include <dirent.h> #include <sys/stat.h> #include "android-base/errors.h" #include "androidfw/Source.h" Loading Loading @@ -54,6 +57,23 @@ const android::Source& RegularFile::GetSource() const { return source_; } bool RegularFile::GetModificationTime(struct tm* buf) const { if (buf == nullptr) { return false; } struct stat stat_buf; if (stat(source_.path.c_str(), &stat_buf) != 0) { return false; } struct tm* ptm; struct tm tm_result; ptm = localtime_r(&stat_buf.st_mtime, &tm_result); *buf = *ptm; return true; } FileCollectionIterator::FileCollectionIterator(FileCollection* collection) : current_(collection->files_.begin()), end_(collection->files_.end()) {} Loading
tools/aapt2/io/FileSystem.h +1 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ class RegularFile : public IFile { std::unique_ptr<IData> OpenAsData() override; std::unique_ptr<io::InputStream> OpenInputStream() override; const android::Source& GetSource() const override; bool GetModificationTime(struct tm* buf) const override; private: DISALLOW_COPY_AND_ASSIGN(RegularFile); Loading
tools/aapt2/io/ZipArchive.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -75,6 +75,14 @@ bool ZipFile::WasCompressed() { return zip_entry_.method != kCompressStored; } bool ZipFile::GetModificationTime(struct tm* buf) const { if (buf == nullptr) { return false; } *buf = zip_entry_.GetModificationTime(); return true; } ZipFileCollectionIterator::ZipFileCollectionIterator( ZipFileCollection* collection) : current_(collection->files_.begin()), end_(collection->files_.end()) {} Loading