1 // Copyright 2014 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 "brillo/file_utils.h" 6 7 #include <sys/stat.h> 8 #include <unistd.h> 9 10 #include <string> 11 12 #include <base/files/file_util.h> 13 #include <base/files/scoped_temp_dir.h> 14 #include <base/rand_util.h> 15 #include <base/strings/string_number_conversions.h> 16 #include <gtest/gtest.h> 17 18 namespace brillo { 19 20 namespace { 21 22 constexpr int kPermissions600 = 23 base::FILE_PERMISSION_READ_BY_USER | base::FILE_PERMISSION_WRITE_BY_USER; 24 constexpr int kPermissions700 = base::FILE_PERMISSION_USER_MASK; 25 constexpr int kPermissions777 = base::FILE_PERMISSION_MASK; 26 27 std::string GetRandomSuffix() { 28 const int kBufferSize = 6; 29 unsigned char buffer[kBufferSize]; 30 base::RandBytes(buffer, arraysize(buffer)); 31 return base::HexEncode(buffer, arraysize(buffer)); 32 } 33 34 } // namespace 35 36 class FileUtilsTest : public testing::Test { 37 public: 38 FileUtilsTest() { 39 CHECK(temp_dir_.CreateUniqueTempDir()); 40 file_path_ = temp_dir_.GetPath().Append("test.temp"); 41 } 42 43 protected: 44 base::FilePath file_path_; 45 base::ScopedTempDir temp_dir_; 46 47 // Writes |contents| to |file_path_|. Pulled into a separate function just 48 // to improve readability of tests. 49 void WriteFile(const std::string& contents) { 50 EXPECT_EQ(contents.length(), 51 base::WriteFile(file_path_, contents.c_str(), contents.length())); 52 } 53 54 // Verifies that the file at |file_path_| exists and contains |contents|. 55 void ExpectFileContains(const std::string& contents) { 56 EXPECT_TRUE(base::PathExists(file_path_)); 57 std::string new_contents; 58 EXPECT_TRUE(base::ReadFileToString(file_path_, &new_contents)); 59 EXPECT_EQ(contents, new_contents); 60 } 61 62 // Verifies that the file at |file_path_| has |permissions|. 63 void ExpectFilePermissions(int permissions) { 64 int actual_permissions; 65 EXPECT_TRUE(base::GetPosixFilePermissions(file_path_, &actual_permissions)); 66 EXPECT_EQ(permissions, actual_permissions); 67 } 68 69 // Creates a file with a random name in the temporary directory. 70 base::FilePath GetTempName() { 71 return temp_dir_.GetPath().Append(GetRandomSuffix()); 72 } 73 }; 74 75 TEST_F(FileUtilsTest, TouchFileCreate) { 76 EXPECT_TRUE(TouchFile(file_path_)); 77 ExpectFileContains(""); 78 ExpectFilePermissions(kPermissions600); 79 } 80 81 TEST_F(FileUtilsTest, TouchFileCreateThroughUmask) { 82 mode_t old_umask = umask(kPermissions777); 83 EXPECT_TRUE(TouchFile(file_path_)); 84 umask(old_umask); 85 ExpectFileContains(""); 86 ExpectFilePermissions(kPermissions600); 87 } 88 89 TEST_F(FileUtilsTest, TouchFileCreateDirectoryStructure) { 90 file_path_ = temp_dir_.GetPath().Append("foo/bar/baz/test.temp"); 91 EXPECT_TRUE(TouchFile(file_path_)); 92 ExpectFileContains(""); 93 } 94 95 TEST_F(FileUtilsTest, TouchFileExisting) { 96 WriteFile("abcd"); 97 EXPECT_TRUE(TouchFile(file_path_)); 98 ExpectFileContains("abcd"); 99 } 100 101 TEST_F(FileUtilsTest, TouchFileReplaceDirectory) { 102 EXPECT_TRUE(base::CreateDirectory(file_path_)); 103 EXPECT_TRUE(TouchFile(file_path_)); 104 EXPECT_FALSE(base::DirectoryExists(file_path_)); 105 ExpectFileContains(""); 106 } 107 108 TEST_F(FileUtilsTest, TouchFileReplaceSymlink) { 109 base::FilePath symlink_target = temp_dir_.GetPath().Append("target.temp"); 110 EXPECT_TRUE(base::CreateSymbolicLink(symlink_target, file_path_)); 111 EXPECT_TRUE(TouchFile(file_path_)); 112 EXPECT_FALSE(base::IsLink(file_path_)); 113 ExpectFileContains(""); 114 } 115 116 TEST_F(FileUtilsTest, TouchFileReplaceOtherUser) { 117 WriteFile("abcd"); 118 EXPECT_TRUE(TouchFile(file_path_, kPermissions777, geteuid() + 1, getegid())); 119 ExpectFileContains(""); 120 } 121 122 TEST_F(FileUtilsTest, TouchFileReplaceOtherGroup) { 123 WriteFile("abcd"); 124 EXPECT_TRUE(TouchFile(file_path_, kPermissions777, geteuid(), getegid() + 1)); 125 ExpectFileContains(""); 126 } 127 128 TEST_F(FileUtilsTest, TouchFileCreateWithAllPermissions) { 129 EXPECT_TRUE(TouchFile(file_path_, kPermissions777, geteuid(), getegid())); 130 ExpectFileContains(""); 131 ExpectFilePermissions(kPermissions777); 132 } 133 134 TEST_F(FileUtilsTest, TouchFileCreateWithOwnerPermissions) { 135 EXPECT_TRUE(TouchFile(file_path_, kPermissions700, geteuid(), getegid())); 136 ExpectFileContains(""); 137 ExpectFilePermissions(kPermissions700); 138 } 139 140 TEST_F(FileUtilsTest, TouchFileExistingPermissionsUnchanged) { 141 EXPECT_TRUE(TouchFile(file_path_, kPermissions777, geteuid(), getegid())); 142 EXPECT_TRUE(TouchFile(file_path_, kPermissions700, geteuid(), getegid())); 143 ExpectFileContains(""); 144 ExpectFilePermissions(kPermissions777); 145 } 146 147 TEST_F(FileUtilsTest, WriteFileCanBeReadBack) { 148 const base::FilePath filename(GetTempName()); 149 const std::string content("blablabla"); 150 EXPECT_TRUE(WriteStringToFile(filename, content)); 151 std::string output; 152 EXPECT_TRUE(ReadFileToString(filename, &output)); 153 EXPECT_EQ(content, output); 154 } 155 156 TEST_F(FileUtilsTest, WriteFileSets0666) { 157 const mode_t mask = 0000; 158 const mode_t mode = 0666; 159 const base::FilePath filename(GetTempName()); 160 const std::string content("blablabla"); 161 const mode_t old_mask = umask(mask); 162 EXPECT_TRUE(WriteStringToFile(filename, content)); 163 int file_mode = 0; 164 EXPECT_TRUE(base::GetPosixFilePermissions(filename, &file_mode)); 165 EXPECT_EQ(mode & ~mask, file_mode & 0777); 166 umask(old_mask); 167 } 168 169 TEST_F(FileUtilsTest, WriteFileCreatesMissingParentDirectoriesWith0700) { 170 const mode_t mask = 0000; 171 const mode_t mode = 0700; 172 const base::FilePath dirname(GetTempName()); 173 const base::FilePath subdirname(dirname.Append(GetRandomSuffix())); 174 const base::FilePath filename(subdirname.Append(GetRandomSuffix())); 175 const std::string content("blablabla"); 176 EXPECT_TRUE(WriteStringToFile(filename, content)); 177 int dir_mode = 0; 178 int subdir_mode = 0; 179 EXPECT_TRUE(base::GetPosixFilePermissions(dirname, &dir_mode)); 180 EXPECT_TRUE(base::GetPosixFilePermissions(subdirname, &subdir_mode)); 181 EXPECT_EQ(mode & ~mask, dir_mode & 0777); 182 EXPECT_EQ(mode & ~mask, subdir_mode & 0777); 183 const mode_t old_mask = umask(mask); 184 umask(old_mask); 185 } 186 187 TEST_F(FileUtilsTest, WriteToFileAtomicCanBeReadBack) { 188 const base::FilePath filename(GetTempName()); 189 const std::string content("blablabla"); 190 EXPECT_TRUE( 191 WriteToFileAtomic(filename, content.data(), content.size(), 0644)); 192 std::string output; 193 EXPECT_TRUE(ReadFileToString(filename, &output)); 194 EXPECT_EQ(content, output); 195 } 196 197 TEST_F(FileUtilsTest, WriteToFileAtomicHonorsMode) { 198 const mode_t mask = 0000; 199 const mode_t mode = 0616; 200 const base::FilePath filename(GetTempName()); 201 const std::string content("blablabla"); 202 const mode_t old_mask = umask(mask); 203 EXPECT_TRUE( 204 WriteToFileAtomic(filename, content.data(), content.size(), mode)); 205 int file_mode = 0; 206 EXPECT_TRUE(base::GetPosixFilePermissions(filename, &file_mode)); 207 EXPECT_EQ(mode & ~mask, file_mode & 0777); 208 umask(old_mask); 209 } 210 211 TEST_F(FileUtilsTest, WriteToFileAtomicHonorsUmask) { 212 const mode_t mask = 0073; 213 const mode_t mode = 0777; 214 const base::FilePath filename(GetTempName()); 215 const std::string content("blablabla"); 216 const mode_t old_mask = umask(mask); 217 EXPECT_TRUE( 218 WriteToFileAtomic(filename, content.data(), content.size(), mode)); 219 int file_mode = 0; 220 EXPECT_TRUE(base::GetPosixFilePermissions(filename, &file_mode)); 221 EXPECT_EQ(mode & ~mask, file_mode & 0777); 222 umask(old_mask); 223 } 224 225 TEST_F(FileUtilsTest, 226 WriteToFileAtomicCreatesMissingParentDirectoriesWith0700) { 227 const mode_t mask = 0000; 228 const mode_t mode = 0700; 229 const base::FilePath dirname(GetTempName()); 230 const base::FilePath subdirname(dirname.Append(GetRandomSuffix())); 231 const base::FilePath filename(subdirname.Append(GetRandomSuffix())); 232 const std::string content("blablabla"); 233 EXPECT_TRUE( 234 WriteToFileAtomic(filename, content.data(), content.size(), 0777)); 235 int dir_mode = 0; 236 int subdir_mode = 0; 237 EXPECT_TRUE(base::GetPosixFilePermissions(dirname, &dir_mode)); 238 EXPECT_TRUE(base::GetPosixFilePermissions(subdirname, &subdir_mode)); 239 EXPECT_EQ(mode & ~mask, dir_mode & 0777); 240 EXPECT_EQ(mode & ~mask, subdir_mode & 0777); 241 const mode_t old_mask = umask(mask); 242 umask(old_mask); 243 } 244 245 } // namespace brillo 246