1 // Copyright 2015 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "bsdiff/test_utils.h" 6 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <sys/stat.h> 11 #include <unistd.h> 12 13 #include <gtest/gtest.h> 14 15 using std::vector; 16 17 namespace { 18 19 // If |path| is absolute, or explicit relative to the current working directory, 20 // leaves it as is. Otherwise, if TMPDIR is defined in the environment and is 21 // non-empty, prepends it to |path|. Otherwise, prepends /tmp. Returns the 22 // resulting path. 23 const std::string PrependTmpdir(const std::string& path) { 24 if (path[0] == '/') 25 return path; 26 27 const char* tmpdir = getenv("TMPDIR"); 28 const std::string prefix = (tmpdir && *tmpdir ? tmpdir : "/tmp"); 29 return prefix + "/" + path; 30 } 31 32 bool MakeTempFile(const std::string& base_filename_template, 33 std::string* filename) { 34 const std::string filename_template = PrependTmpdir(base_filename_template); 35 vector<char> result(filename_template.size() + 1, '\0'); 36 memcpy(result.data(), filename_template.data(), filename_template.size()); 37 38 int mkstemp_fd = mkstemp(result.data()); 39 if (mkstemp_fd < 0) { 40 PLOG(ERROR) << "mkstemp() Failed"; 41 return false; 42 } 43 close(mkstemp_fd); 44 45 if (filename) 46 *filename = result.data(); 47 return true; 48 } 49 50 } // namespace 51 52 namespace test_utils { 53 54 void BsdiffTestEnvironment::SetUp() { 55 #ifdef BSDIFF_TARGET_UNITTEST 56 #define BSDIFF_TARGET_TMP_BASE "/data/tmp" 57 if (access(BSDIFF_TARGET_TMP_BASE, F_OK) == -1) { 58 mkdir(BSDIFF_TARGET_TMP_BASE, S_IRWXU | S_IRWXG | S_IROTH | S_IWOTH); 59 } 60 setenv("TMPDIR", BSDIFF_TARGET_TMP_BASE, 1); 61 #endif // defined (BSDIFF_TARGET_UNITTEST) 62 } 63 64 bool ReadFile(const std::string& path, vector<uint8_t>* out) { 65 FILE* fp = fopen(path.c_str(), "r"); 66 if (!fp) 67 return false; 68 out->clear(); 69 70 uint8_t buf[16 * 1024]; 71 while (true) { 72 size_t bytes_read = fread(buf, 1, sizeof(buf), fp); 73 if (!bytes_read) 74 break; 75 out->insert(out->end(), buf, buf + bytes_read); 76 } 77 bool result = !ferror(fp); 78 fclose(fp); 79 return result; 80 } 81 82 bool WriteFile(const std::string& path, vector<uint8_t> contents) { 83 FILE* fp = fopen(path.c_str(), "r"); 84 if (!fp) 85 return false; 86 size_t written = fwrite(contents.data(), 1, contents.size(), fp); 87 bool result = written == contents.size() && !ferror(fp); 88 fclose(fp); 89 return result; 90 } 91 92 ScopedTempFile::ScopedTempFile(const std::string& pattern) { 93 EXPECT_TRUE(MakeTempFile(pattern, &filename_)); 94 } 95 96 ScopedTempFile::~ScopedTempFile() { 97 if (!filename_.empty() && unlink(filename_.c_str()) < 0) { 98 PLOG(ERROR) << "Unable to remove temporary file."; 99 } 100 } 101 102 bool BsdiffPatchFile::LoadFromFile(const std::string& filename) { 103 vector<uint8_t> contents; 104 if (!ReadFile(filename, &contents)) 105 return false; 106 file_size = contents.size(); 107 // Check that the file includes at least the header. 108 TEST_AND_RETURN_FALSE(contents.size() >= kHeaderSize); 109 magic = std::string(contents.data(), contents.data() + 8); 110 memcpy(&ctrl_len, contents.data() + 8, sizeof(ctrl_len)); 111 memcpy(&diff_len, contents.data() + 16, sizeof(diff_len)); 112 memcpy(&new_file_len, contents.data() + 24, sizeof(new_file_len)); 113 114 // Sanity check before we attempt to parse the bz2 streams. 115 TEST_AND_RETURN_FALSE(ctrl_len >= 0); 116 TEST_AND_RETURN_FALSE(diff_len >= 0); 117 118 // The cast is safe since ctrl_len and diff_len are both positive. 119 TEST_AND_RETURN_FALSE(file_size >= 120 static_cast<uint64_t>(kHeaderSize + ctrl_len + diff_len)); 121 extra_len = file_size - kHeaderSize - ctrl_len - diff_len; 122 123 uint8_t* ptr = contents.data() + kHeaderSize; 124 bz2_ctrl = vector<uint8_t>(ptr, ptr + ctrl_len); 125 ptr += ctrl_len; 126 bz2_diff = vector<uint8_t>(ptr, ptr + diff_len); 127 ptr += diff_len; 128 bz2_extra = vector<uint8_t>(ptr, ptr + extra_len); 129 130 return true; 131 } 132 133 bool BsdiffPatchFile::IsValid() const { 134 TEST_AND_RETURN_FALSE(ctrl_len >= 0); 135 TEST_AND_RETURN_FALSE(diff_len >= 0); 136 TEST_AND_RETURN_FALSE(new_file_len >= 0); 137 138 // TODO(deymo): Test that the length of the decompressed bz2 streams |diff| 139 // plus |extra| are equal to the |new_file_len|. 140 // TODO(deymo): Test that all the |bz2_ctrl| triplets (x, y, z) have a "x" 141 // and "y" value >= 0 ("z" can be negative). 142 return true; 143 } 144 145 } // namespace test_utils 146