You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
285 lines
8.4 KiB
285 lines
8.4 KiB
// Copyright 2019 The Chromium OS Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "brillo/files/file_util_test.h"
|
|
|
|
#include <base/files/file_util.h>
|
|
#include <base/rand_util.h>
|
|
#include <base/stl_util.h>
|
|
#include <base/strings/string_number_conversions.h>
|
|
#include <brillo/files/file_util.h>
|
|
#include <brillo/files/safe_fd.h>
|
|
|
|
namespace brillo {
|
|
|
|
#define TO_STRING_HELPER(x) \
|
|
case brillo::SafeFD::Error::x: \
|
|
return #x;
|
|
std::string to_string(brillo::SafeFD::Error err) {
|
|
switch (err) {
|
|
TO_STRING_HELPER(kNoError)
|
|
TO_STRING_HELPER(kBadArgument)
|
|
TO_STRING_HELPER(kNotInitialized)
|
|
TO_STRING_HELPER(kIOError)
|
|
TO_STRING_HELPER(kDoesNotExist)
|
|
TO_STRING_HELPER(kSymlinkDetected)
|
|
TO_STRING_HELPER(kWrongType)
|
|
TO_STRING_HELPER(kWrongUID)
|
|
TO_STRING_HELPER(kWrongGID)
|
|
TO_STRING_HELPER(kWrongPermissions)
|
|
TO_STRING_HELPER(kExceededMaximum)
|
|
default:
|
|
return std::string("unknown (") + std::to_string(static_cast<int>(err)) +
|
|
")";
|
|
}
|
|
}
|
|
#undef TO_STRING_HELPER
|
|
|
|
std::ostream& operator<<(std::ostream& os, const brillo::SafeFD::Error err) {
|
|
return os << to_string(err); // whatever needed to print bar to os
|
|
}
|
|
|
|
std::string GetRandomSuffix() {
|
|
const int kBufferSize = 6;
|
|
unsigned char buffer[kBufferSize];
|
|
base::RandBytes(buffer, base::size(buffer));
|
|
return base::HexEncode(buffer, base::size(buffer));
|
|
}
|
|
|
|
void FileTest::SetUpTestCase() {
|
|
umask(0);
|
|
}
|
|
|
|
FileTest::FileTest() {
|
|
CHECK(temp_dir_.CreateUniqueTempDir()) << strerror(errno);
|
|
sub_dir_path_ = temp_dir_.GetPath().Append(kSubdirName);
|
|
file_path_ = sub_dir_path_.Append(kFileName);
|
|
|
|
std::string path = temp_dir_.GetPath().value();
|
|
temp_dir_path_.reserve(path.size() + 1);
|
|
temp_dir_path_.assign(temp_dir_.GetPath().value().begin(),
|
|
temp_dir_.GetPath().value().end());
|
|
temp_dir_path_.push_back('\0');
|
|
|
|
CHECK_EQ(chmod(temp_dir_path_.data(), SafeFD::kDefaultDirPermissions), 0);
|
|
SafeFD::SetRootPathForTesting(temp_dir_path_.data());
|
|
root_ = SafeFD::Root().first;
|
|
CHECK(root_.is_valid());
|
|
}
|
|
|
|
bool FileTest::SetupSubdir() {
|
|
if (!base::CreateDirectory(sub_dir_path_)) {
|
|
PLOG(ERROR) << "Failed to create '" << sub_dir_path_.value() << "'";
|
|
return false;
|
|
}
|
|
if (chmod(sub_dir_path_.value().c_str(), SafeFD::kDefaultDirPermissions) !=
|
|
0) {
|
|
PLOG(ERROR) << "Failed to set permissions of '" << sub_dir_path_.value()
|
|
<< "'";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool FileTest::SetupSymlinks() {
|
|
symlink_file_path_ = temp_dir_.GetPath().Append(kSymbolicFileName);
|
|
symlink_dir_path_ = temp_dir_.GetPath().Append(kSymbolicDirName);
|
|
if (!base::CreateSymbolicLink(file_path_, symlink_file_path_)) {
|
|
PLOG(ERROR) << "Failed to create symlink to '" << symlink_file_path_.value()
|
|
<< "'";
|
|
return false;
|
|
}
|
|
if (!base::CreateSymbolicLink(temp_dir_.GetPath(), symlink_dir_path_)) {
|
|
PLOG(ERROR) << "Failed to create symlink to'" << symlink_dir_path_.value()
|
|
<< "'";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool FileTest::WriteFile(const std::string& contents) {
|
|
if (!SetupSubdir()) {
|
|
return false;
|
|
}
|
|
if (contents.length() !=
|
|
base::WriteFile(file_path_, contents.c_str(), contents.length())) {
|
|
PLOG(ERROR) << "base::WriteFile failed";
|
|
return false;
|
|
}
|
|
if (chmod(file_path_.value().c_str(), SafeFD::kDefaultFilePermissions) != 0) {
|
|
PLOG(ERROR) << "chmod failed";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void FileTest::ExpectFileContains(const std::string& contents) {
|
|
EXPECT_TRUE(base::PathExists(file_path_));
|
|
std::string new_contents;
|
|
EXPECT_TRUE(base::ReadFileToString(file_path_, &new_contents));
|
|
EXPECT_EQ(contents, new_contents);
|
|
}
|
|
|
|
void FileTest::ExpectPermissions(base::FilePath path, int permissions) {
|
|
int actual_permissions = 0;
|
|
// This breaks out of the ExpectPermissions() call but not the test case.
|
|
ASSERT_TRUE(base::GetPosixFilePermissions(path, &actual_permissions));
|
|
EXPECT_EQ(permissions, actual_permissions);
|
|
}
|
|
|
|
// Creates a file with a random name in the temporary directory.
|
|
base::FilePath FileTest::GetTempName() {
|
|
return temp_dir_.GetPath().Append(GetRandomSuffix());
|
|
}
|
|
|
|
constexpr char FileTest::kFileName[];
|
|
constexpr char FileTest::kSubdirName[];
|
|
constexpr char FileTest::kSymbolicFileName[];
|
|
constexpr char FileTest::kSymbolicDirName[];
|
|
|
|
class FileUtilTest : public FileTest {};
|
|
|
|
TEST_F(FileUtilTest, GetFDPath_SimpleSuccess) {
|
|
EXPECT_EQ(GetFDPath(root_.get()), temp_dir_.GetPath());
|
|
}
|
|
|
|
TEST_F(FileUtilTest, GetFDPath_BadFD) {
|
|
base::FilePath path = GetFDPath(-1);
|
|
EXPECT_TRUE(path.empty());
|
|
}
|
|
|
|
TEST_F(FileUtilTest, OpenOrRemakeDir_SimpleSuccess) {
|
|
SafeFD::Error err;
|
|
SafeFD dir;
|
|
|
|
std::tie(dir, err) = root_.OpenExistingDir(temp_dir_.GetPath());
|
|
EXPECT_EQ(err, SafeFD::Error::kNoError);
|
|
ASSERT_TRUE(dir.is_valid());
|
|
|
|
SafeFD subdir;
|
|
std::tie(subdir, err) = OpenOrRemakeDir(&dir, kSubdirName);
|
|
EXPECT_EQ(err, SafeFD::Error::kNoError);
|
|
EXPECT_TRUE(subdir.is_valid());
|
|
}
|
|
|
|
TEST_F(FileUtilTest, OpenOrRemakeDir_SuccessAfterRetry) {
|
|
ASSERT_NE(base::WriteFile(sub_dir_path_, "", 0), -1);
|
|
SafeFD::Error err;
|
|
SafeFD dir;
|
|
|
|
std::tie(dir, err) = root_.OpenExistingDir(temp_dir_.GetPath());
|
|
EXPECT_EQ(err, SafeFD::Error::kNoError);
|
|
ASSERT_TRUE(dir.is_valid());
|
|
|
|
SafeFD subdir;
|
|
std::tie(subdir, err) = OpenOrRemakeDir(&dir, kSubdirName);
|
|
EXPECT_EQ(err, SafeFD::Error::kNoError);
|
|
EXPECT_TRUE(subdir.is_valid());
|
|
}
|
|
|
|
TEST_F(FileUtilTest, OpenOrRemakeDir_BadArgument) {
|
|
SafeFD::Error err;
|
|
SafeFD dir;
|
|
|
|
std::tie(dir, err) = root_.OpenExistingDir(temp_dir_.GetPath());
|
|
EXPECT_EQ(err, SafeFD::Error::kNoError);
|
|
ASSERT_TRUE(dir.is_valid());
|
|
|
|
SafeFD subdir;
|
|
std::tie(subdir, err) = OpenOrRemakeDir(&dir, ".");
|
|
EXPECT_EQ(err, SafeFD::Error::kBadArgument);
|
|
EXPECT_FALSE(subdir.is_valid());
|
|
std::tie(subdir, err) = OpenOrRemakeDir(&dir, "..");
|
|
EXPECT_EQ(err, SafeFD::Error::kBadArgument);
|
|
EXPECT_FALSE(subdir.is_valid());
|
|
std::tie(subdir, err) = OpenOrRemakeDir(&dir, "a/a");
|
|
EXPECT_EQ(err, SafeFD::Error::kBadArgument);
|
|
EXPECT_FALSE(subdir.is_valid());
|
|
}
|
|
|
|
TEST_F(FileUtilTest, OpenOrRemakeDir_NotInitialized) {
|
|
SafeFD::Error err;
|
|
SafeFD dir;
|
|
|
|
SafeFD subdir;
|
|
std::tie(subdir, err) = OpenOrRemakeDir(&dir, kSubdirName);
|
|
EXPECT_EQ(err, SafeFD::Error::kNotInitialized);
|
|
EXPECT_FALSE(subdir.is_valid());
|
|
}
|
|
|
|
TEST_F(FileUtilTest, OpenOrRemakeDir_IOError) {
|
|
SafeFD::Error err;
|
|
SafeFD dir;
|
|
|
|
std::tie(dir, err) = root_.OpenExistingDir(temp_dir_.GetPath());
|
|
EXPECT_EQ(err, SafeFD::Error::kNoError);
|
|
ASSERT_TRUE(dir.is_valid());
|
|
ASSERT_EQ(chmod(temp_dir_path_.data(), 0000), 0);
|
|
|
|
SafeFD subdir;
|
|
std::tie(subdir, err) = OpenOrRemakeDir(&dir, kSubdirName);
|
|
EXPECT_EQ(err, SafeFD::Error::kIOError);
|
|
EXPECT_FALSE(subdir.is_valid());
|
|
}
|
|
|
|
TEST_F(FileUtilTest, OpenOrRemakeFile_SimpleSuccess) {
|
|
ASSERT_TRUE(SetupSubdir());
|
|
SafeFD::Error err;
|
|
SafeFD dir;
|
|
|
|
std::tie(dir, err) = root_.OpenExistingDir(sub_dir_path_);
|
|
EXPECT_EQ(err, SafeFD::Error::kNoError);
|
|
ASSERT_TRUE(dir.is_valid());
|
|
|
|
SafeFD file;
|
|
std::tie(file, err) = OpenOrRemakeFile(&dir, kFileName);
|
|
EXPECT_EQ(err, SafeFD::Error::kNoError);
|
|
EXPECT_TRUE(file.is_valid());
|
|
}
|
|
|
|
TEST_F(FileUtilTest, OpenOrRemakeFile_SuccessAfterRetry) {
|
|
ASSERT_TRUE(SetupSubdir());
|
|
ASSERT_TRUE(base::CreateDirectory(file_path_));
|
|
SafeFD::Error err;
|
|
SafeFD dir;
|
|
|
|
std::tie(dir, err) = root_.OpenExistingDir(sub_dir_path_);
|
|
EXPECT_EQ(err, SafeFD::Error::kNoError);
|
|
ASSERT_TRUE(dir.is_valid());
|
|
|
|
SafeFD file;
|
|
std::tie(file, err) = OpenOrRemakeFile(&dir, kFileName);
|
|
EXPECT_EQ(err, SafeFD::Error::kNoError);
|
|
EXPECT_TRUE(file.is_valid());
|
|
}
|
|
|
|
TEST_F(FileUtilTest, OpenOrRemakeFile_NotInitialized) {
|
|
ASSERT_TRUE(SetupSubdir());
|
|
SafeFD::Error err;
|
|
SafeFD dir;
|
|
|
|
SafeFD file;
|
|
std::tie(file, err) = OpenOrRemakeFile(&dir, kFileName);
|
|
EXPECT_EQ(err, SafeFD::Error::kNotInitialized);
|
|
EXPECT_FALSE(file.is_valid());
|
|
}
|
|
|
|
TEST_F(FileUtilTest, OpenOrRemakeFile_IOError) {
|
|
ASSERT_TRUE(SetupSubdir());
|
|
SafeFD::Error err;
|
|
SafeFD dir;
|
|
|
|
std::tie(dir, err) = root_.OpenExistingDir(sub_dir_path_);
|
|
EXPECT_EQ(err, SafeFD::Error::kNoError);
|
|
ASSERT_TRUE(dir.is_valid());
|
|
ASSERT_EQ(chmod(sub_dir_path_.value().c_str(), 0000), 0);
|
|
|
|
SafeFD file;
|
|
std::tie(file, err) = OpenOrRemakeFile(&dir, kFileName);
|
|
EXPECT_EQ(err, SafeFD::Error::kIOError);
|
|
EXPECT_FALSE(file.is_valid());
|
|
}
|
|
|
|
} // namespace brillo
|