Home | History | Annotate | Download | only in brillo
      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