Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 66c5422a authored by Mark Punzalan's avatar Mark Punzalan Committed by Android (Google) Code Review
Browse files

Merge "[aapt2] Ensure all zip entry times are the same" into main

parents b920b8c4 e5671597
Loading
Loading
Loading
Loading
+110 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
 * limitations under the License.
 */

#include <stdlib.h>

#include "test/Test.h"

namespace aapt {
@@ -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) {
@@ -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);
@@ -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
+9 −0
Original line number Diff line number Diff line
@@ -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
@@ -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);

+20 −0
Original line number Diff line number Diff line
@@ -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"
@@ -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()) {}

+1 −0
Original line number Diff line number Diff line
@@ -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);
+8 −0
Original line number Diff line number Diff line
@@ -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