| // Copyright 2014 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 "cryptohome/platform.h" |
| |
| #include <sys/ioctl.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <sys/xattr.h> |
| |
| #include <linux/fs.h> |
| |
| #include <fcntl.h> |
| #include <string> |
| |
| #include <base/files/file.h> |
| #include <base/files/file_path.h> |
| #include <base/files/file_util.h> |
| #include <base/logging.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| using base::FilePath; |
| |
| namespace cryptohome { |
| |
| class PlatformTest : public ::testing::Test { |
| public: |
| virtual ~PlatformTest() {} |
| protected: |
| std::string GetRandomSuffix() { |
| return platform_.GetRandomSuffix(); |
| } |
| FilePath GetTempName() { |
| FilePath temp_directory; |
| EXPECT_TRUE(base::GetTempDir(&temp_directory)); |
| return temp_directory.Append(GetRandomSuffix()); |
| } |
| |
| Platform platform_; |
| }; |
| |
| TEST_F(PlatformTest, WriteFileCanBeReadBack) { |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| EXPECT_TRUE(platform_.WriteStringToFile(filename, content)); |
| std::string output; |
| EXPECT_TRUE(platform_.ReadFileToString(filename, &output)); |
| EXPECT_EQ(content, output); |
| platform_.DeleteFile(filename, false /* recursive */); |
| } |
| |
| TEST_F(PlatformTest, WriteFileSets0666) { |
| const mode_t mask = 0000; |
| const mode_t mode = 0666; |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| const mode_t old_mask = platform_.SetMask(mask); |
| EXPECT_TRUE(platform_.WriteStringToFile(filename, content)); |
| mode_t file_mode = 0; |
| EXPECT_TRUE(platform_.GetPermissions(filename, &file_mode)); |
| EXPECT_EQ(mode & ~mask, file_mode & 0777); |
| platform_.SetMask(old_mask); |
| platform_.DeleteFile(filename, false /* recursive */); |
| } |
| |
| TEST_F(PlatformTest, WriteFileCreatesMissingParentDirectoriesWith0700) { |
| const mode_t mask = 0000; |
| const mode_t mode = 0700; |
| const FilePath dirname(GetTempName()); |
| const FilePath subdirname(dirname.Append(GetRandomSuffix())); |
| const FilePath filename(subdirname.Append(GetRandomSuffix())); |
| const std::string content("blablabla"); |
| EXPECT_TRUE(platform_.WriteStringToFile(filename, content)); |
| mode_t dir_mode = 0; |
| mode_t subdir_mode = 0; |
| EXPECT_TRUE(platform_.GetPermissions(dirname, &dir_mode)); |
| EXPECT_TRUE(platform_.GetPermissions(subdirname, &subdir_mode)); |
| EXPECT_EQ(mode & ~mask, dir_mode & 0777); |
| EXPECT_EQ(mode & ~mask, subdir_mode & 0777); |
| const mode_t old_mask = platform_.SetMask(mask); |
| platform_.DeleteFile(dirname, true /* recursive */); |
| platform_.SetMask(old_mask); |
| } |
| |
| TEST_F(PlatformTest, WriteStringToFileAtomicCanBeReadBack) { |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| EXPECT_TRUE(platform_.WriteStringToFileAtomic(filename, content, 0644)); |
| std::string output; |
| EXPECT_TRUE(platform_.ReadFileToString(filename, &output)); |
| EXPECT_EQ(content, output); |
| platform_.DeleteFile(filename, false /* recursive */); |
| } |
| |
| TEST_F(PlatformTest, WriteStringToFileAtomicHonorsMode) { |
| const mode_t mask = 0000; |
| const mode_t mode = 0616; |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| const mode_t old_mask = platform_.SetMask(mask); |
| EXPECT_TRUE(platform_.WriteStringToFileAtomic(filename, content, mode)); |
| mode_t file_mode = 0; |
| EXPECT_TRUE(platform_.GetPermissions(filename, &file_mode)); |
| EXPECT_EQ(mode & ~mask, file_mode & 0777); |
| platform_.DeleteFile(filename, false /* recursive */); |
| platform_.SetMask(old_mask); |
| } |
| |
| TEST_F(PlatformTest, WriteStringToFileAtomicHonorsUmask) { |
| const mode_t mask = 0073; |
| const mode_t mode = 0777; |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| const mode_t old_mask = platform_.SetMask(mask); |
| EXPECT_TRUE(platform_.WriteStringToFileAtomic(filename, content, mode)); |
| mode_t file_mode = 0; |
| EXPECT_TRUE(platform_.GetPermissions(filename, &file_mode)); |
| EXPECT_EQ(mode & ~mask, file_mode & 0777); |
| platform_.DeleteFile(filename, false /* recursive */); |
| platform_.SetMask(old_mask); |
| } |
| |
| TEST_F(PlatformTest, |
| WriteStringToFileAtomicCreatesMissingParentDirectoriesWith0700) { |
| const mode_t mask = 0000; |
| const mode_t mode = 0700; |
| const FilePath dirname(GetTempName()); |
| const FilePath subdirname(dirname.Append(GetRandomSuffix())); |
| const FilePath filename(subdirname.Append(GetRandomSuffix())); |
| const std::string content("blablabla"); |
| EXPECT_TRUE(platform_.WriteStringToFileAtomic(filename, content, 0777)); |
| mode_t dir_mode = 0; |
| mode_t subdir_mode = 0; |
| EXPECT_TRUE(platform_.GetPermissions(dirname, &dir_mode)); |
| EXPECT_TRUE(platform_.GetPermissions(subdirname, &subdir_mode)); |
| EXPECT_EQ(mode & ~mask, dir_mode & 0777); |
| EXPECT_EQ(mode & ~mask, subdir_mode & 0777); |
| const mode_t old_mask = platform_.SetMask(mask); |
| platform_.DeleteFile(dirname, true /* recursive */); |
| platform_.SetMask(old_mask); |
| } |
| |
| TEST_F(PlatformTest, WriteStringToFileAtomicDurableCanBeReadBack) { |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| EXPECT_TRUE( |
| platform_.WriteStringToFileAtomicDurable(filename, content, 0644)); |
| std::string output; |
| EXPECT_TRUE(platform_.ReadFileToString(filename, &output)); |
| EXPECT_EQ(content, output); |
| platform_.DeleteFile(filename, false /* recursive */); |
| } |
| |
| TEST_F(PlatformTest, WriteStringToFileAtomicDurableHonorsMode) { |
| const mode_t mask = 0000; |
| const mode_t mode = 0616; |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| const mode_t old_mask = platform_.SetMask(mask); |
| EXPECT_TRUE( |
| platform_.WriteStringToFileAtomicDurable(filename, content, mode)); |
| mode_t file_mode = 0; |
| EXPECT_TRUE(platform_.GetPermissions(filename, &file_mode)); |
| EXPECT_EQ(mode & ~mask, file_mode & 0777); |
| platform_.DeleteFile(filename, false /* recursive */); |
| platform_.SetMask(old_mask); |
| } |
| |
| TEST_F(PlatformTest, WriteStringToFileAtomicDurableHonorsUmask) { |
| const mode_t mask = 0073; |
| const mode_t mode = 0777; |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| const mode_t old_mask = platform_.SetMask(mask); |
| EXPECT_TRUE( |
| platform_.WriteStringToFileAtomicDurable(filename, content, mode)); |
| mode_t file_mode = 0; |
| EXPECT_TRUE(platform_.GetPermissions(filename, &file_mode)); |
| EXPECT_EQ(mode & ~mask, file_mode & 0777); |
| platform_.DeleteFile(filename, false /* recursive */); |
| platform_.SetMask(old_mask); |
| } |
| |
| TEST_F(PlatformTest, |
| WriteStringToFileAtomicDurableCreatesMissingParentDirectoriesWith0700) { |
| const mode_t mask = 0000; |
| const mode_t mode = 0700; |
| const FilePath dirname(GetTempName()); |
| const FilePath subdirname(dirname.Append(GetRandomSuffix())); |
| const FilePath filename(subdirname.Append(GetRandomSuffix())); |
| const std::string content("blablabla"); |
| EXPECT_TRUE(platform_.WriteStringToFileAtomicDurable( |
| filename, content, 0777)); |
| mode_t dir_mode = 0; |
| mode_t subdir_mode = 0; |
| EXPECT_TRUE(platform_.GetPermissions(dirname, &dir_mode)); |
| EXPECT_TRUE(platform_.GetPermissions(subdirname, &subdir_mode)); |
| EXPECT_EQ(mode & ~mask, dir_mode & 0777); |
| EXPECT_EQ(mode & ~mask, subdir_mode & 0777); |
| const mode_t old_mask = platform_.SetMask(mask); |
| platform_.DeleteFile(dirname, true /* recursive */); |
| platform_.SetMask(old_mask); |
| } |
| |
| TEST_F(PlatformTest, TouchFileDurable) { |
| const FilePath filename(GetTempName()); |
| EXPECT_TRUE(platform_.TouchFileDurable(filename)); |
| int64_t size = -1; |
| EXPECT_TRUE(platform_.GetFileSize(filename, &size)); |
| EXPECT_EQ(0, size); |
| platform_.DeleteFile(filename, false /* recursive */); |
| } |
| |
| TEST_F(PlatformTest, TouchFileDurableSets0666) { |
| const mode_t mask = 0000; |
| const mode_t mode = 0666; |
| const FilePath filename(GetTempName()); |
| const mode_t old_mask = platform_.SetMask(mask); |
| EXPECT_TRUE(platform_.TouchFileDurable(filename)); |
| mode_t file_mode = 0; |
| EXPECT_TRUE(platform_.GetPermissions(filename, &file_mode)); |
| EXPECT_EQ(mode & ~mask, file_mode & 0777); |
| platform_.DeleteFile(filename, false /* recursive */); |
| platform_.SetMask(old_mask); |
| } |
| |
| TEST_F(PlatformTest, TouchFileDurableHonorsUmask) { |
| const mode_t mask = 0066; |
| const mode_t mode = 0640; |
| const FilePath filename(GetTempName()); |
| const mode_t old_mask = platform_.SetMask(mask); |
| EXPECT_TRUE(platform_.TouchFileDurable(filename)); |
| mode_t file_mode = 0; |
| EXPECT_TRUE(platform_.GetPermissions(filename, &file_mode)); |
| EXPECT_EQ(mode & ~mask, file_mode & 0777); |
| platform_.DeleteFile(filename, false /* recursive */); |
| platform_.SetMask(old_mask); |
| } |
| |
| TEST_F(PlatformTest, DataSyncFileHasSaneReturnCodes) { |
| const FilePath filename(GetTempName()); |
| const FilePath dirname(GetTempName()); |
| platform_.CreateDirectory(dirname); |
| EXPECT_FALSE(platform_.DataSyncFile(dirname)); |
| EXPECT_FALSE(platform_.DataSyncFile(filename)); |
| EXPECT_TRUE(platform_.WriteStringToFile(filename, "bla")); |
| EXPECT_TRUE(platform_.DataSyncFile(filename)); |
| platform_.DeleteFile(filename, false /* recursive */); |
| platform_.DeleteFile(dirname, true /* recursive */); |
| } |
| |
| TEST_F(PlatformTest, SyncFileHasSaneReturnCodes) { |
| const FilePath filename(GetTempName()); |
| const FilePath dirname(GetTempName()); |
| platform_.CreateDirectory(dirname); |
| EXPECT_FALSE(platform_.SyncFile(dirname)); |
| EXPECT_FALSE(platform_.SyncFile(filename)); |
| EXPECT_TRUE(platform_.WriteStringToFile(filename, "bla")); |
| EXPECT_TRUE(platform_.SyncFile(filename)); |
| platform_.DeleteFile(filename, false /* recursive */); |
| platform_.DeleteFile(dirname, true /* recursive */); |
| } |
| |
| TEST_F(PlatformTest, SyncDirectoryHasSaneReturnCodes) { |
| const FilePath filename(GetTempName()); |
| const FilePath dirname(GetTempName()); |
| platform_.WriteStringToFile(filename, "bla"); |
| EXPECT_FALSE(platform_.SyncDirectory(filename)); |
| EXPECT_FALSE(platform_.SyncDirectory(dirname)); |
| EXPECT_TRUE(platform_.CreateDirectory(dirname)); |
| EXPECT_TRUE(platform_.SyncDirectory(dirname)); |
| platform_.DeleteFile(filename, false /* recursive */); |
| platform_.DeleteFile(dirname, true /* recursive */); |
| } |
| |
| TEST_F(PlatformTest, HasExtendedFileAttribute) { |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| ASSERT_TRUE(platform_.WriteStringToFile(filename, content)); |
| const std::string name("user.foo"); |
| const std::string value("bar"); |
| |
| ASSERT_EQ(0, setxattr(filename.value().c_str(), name.c_str(), value.c_str(), |
| value.length(), 0)); |
| |
| EXPECT_TRUE(platform_.HasExtendedFileAttribute(filename, name)); |
| |
| EXPECT_FALSE(platform_.HasExtendedFileAttribute( |
| FilePath("file_not_exist"), name)); |
| EXPECT_FALSE(platform_.HasExtendedFileAttribute( |
| filename, "user.name_not_exist")); |
| } |
| |
| TEST_F(PlatformTest, ListExtendedFileAttribute) { |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| ASSERT_TRUE(platform_.WriteStringToFile(filename, content)); |
| const std::string name("user.foo"); |
| const std::string value("bar"); |
| const std::string name2("user.foo2"); |
| const std::string value2("bar2"); |
| |
| ASSERT_EQ(0, |
| setxattr(filename.value().c_str(), |
| name.c_str(), |
| value.c_str(), |
| value.length(), |
| 0)); |
| ASSERT_EQ(0, |
| setxattr(filename.value().c_str(), |
| name2.c_str(), |
| value2.c_str(), |
| value2.length(), |
| 0)); |
| |
| std::vector<std::string> attrs; |
| |
| EXPECT_TRUE(platform_.ListExtendedFileAttributes(filename, &attrs)); |
| EXPECT_THAT(attrs, testing::UnorderedElementsAre(name, name2)); |
| |
| attrs.clear(); |
| EXPECT_FALSE( |
| platform_.ListExtendedFileAttributes(FilePath("file_not_exist"), &attrs)); |
| EXPECT_TRUE(attrs.empty()); |
| } |
| |
| TEST_F(PlatformTest, GetExtendedAttributeAsString) { |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| ASSERT_TRUE(platform_.WriteStringToFile(filename, content)); |
| const std::string name("user.foo"); |
| const std::string value("bar"); |
| |
| ASSERT_EQ(0, |
| setxattr(filename.value().c_str(), |
| name.c_str(), |
| value.c_str(), |
| value.length(), |
| 0)); |
| |
| std::string got; |
| EXPECT_TRUE(platform_.GetExtendedFileAttributeAsString(filename, name, &got)); |
| EXPECT_EQ(value, got); |
| |
| EXPECT_FALSE(platform_.GetExtendedFileAttributeAsString( |
| FilePath("file_not_exist"), name, &got)); |
| EXPECT_FALSE(platform_.GetExtendedFileAttributeAsString( |
| filename, "user.name_not_exist", &got)); |
| } |
| |
| TEST_F(PlatformTest, GetExtendedAttribute) { |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| ASSERT_TRUE(platform_.WriteStringToFile(filename, content)); |
| const std::string name("user.foo"); |
| const int value = 42; |
| |
| ASSERT_EQ( |
| 0, |
| setxattr( |
| filename.value().c_str(), name.c_str(), &value, sizeof(value), 0)); |
| |
| int got; |
| EXPECT_TRUE(platform_.GetExtendedFileAttribute( |
| filename, name, reinterpret_cast<char*>(&got), sizeof(got))); |
| EXPECT_EQ(value, got); |
| |
| EXPECT_FALSE(platform_.GetExtendedFileAttribute(FilePath("file_not_exist"), |
| name, |
| reinterpret_cast<char*>(&got), |
| sizeof(got))); |
| EXPECT_FALSE(platform_.GetExtendedFileAttribute(filename, |
| "user.name_not_exist", |
| reinterpret_cast<char*>(&got), |
| sizeof(got))); |
| EXPECT_FALSE(platform_.GetExtendedFileAttribute( |
| filename, name, reinterpret_cast<char*>(&got), sizeof(got) - 1)); |
| EXPECT_FALSE(platform_.GetExtendedFileAttribute( |
| filename, name, reinterpret_cast<char*>(&got), sizeof(got) + 1)); |
| } |
| |
| TEST_F(PlatformTest, SetExtendedAttribute) { |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| ASSERT_TRUE(platform_.WriteStringToFile(filename, content)); |
| const std::string name("user.foo"); |
| std::string value("bar"); |
| EXPECT_TRUE(platform_.SetExtendedFileAttribute( |
| filename, name, value.c_str(), value.length())); |
| |
| std::vector<char> got(value.length()); |
| EXPECT_EQ( |
| value.length(), |
| getxattr( |
| filename.value().c_str(), name.c_str(), got.data(), value.length())); |
| |
| EXPECT_EQ(value, std::string(got.data(), got.size())); |
| |
| EXPECT_FALSE(platform_.SetExtendedFileAttribute( |
| FilePath("file_not_exist"), name, value.c_str(), sizeof(value))); |
| } |
| |
| TEST_F(PlatformTest, RemoveExtendedAttribute) { |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| ASSERT_TRUE(platform_.WriteStringToFile(filename, content)); |
| const std::string name("user.foo"); |
| std::string value("bar"); |
| ASSERT_EQ(0, |
| setxattr(filename.value().c_str(), |
| name.c_str(), |
| value.c_str(), |
| value.length(), |
| 0)); |
| EXPECT_TRUE(platform_.RemoveExtendedFileAttribute(filename, name)); |
| EXPECT_EQ(-1, getxattr(filename.value().c_str(), name.c_str(), nullptr, 0)); |
| EXPECT_EQ(ENODATA, errno); |
| |
| EXPECT_FALSE( |
| platform_.RemoveExtendedFileAttribute(FilePath("file_not_exist"), name)); |
| EXPECT_FALSE( |
| platform_.RemoveExtendedFileAttribute(filename, "attribute_not_exist")); |
| } |
| |
| TEST_F(PlatformTest, GetExtFileAttributes) { |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| ASSERT_TRUE(platform_.WriteStringToFile(filename, content)); |
| |
| int fd; |
| ASSERT_GT(fd = HANDLE_EINTR(open(filename.value().c_str(), O_RDONLY)), 0); |
| int flags = FS_UNRM_FL | FS_NODUMP_FL; |
| ASSERT_GE(ioctl(fd, FS_IOC_SETFLAGS, &flags), 0); |
| |
| int got; |
| EXPECT_TRUE(platform_.GetExtFileAttributes(filename, &got)); |
| EXPECT_EQ(flags, got); |
| close(fd); |
| } |
| |
| TEST_F(PlatformTest, SetExtFileAttributes) { |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| ASSERT_TRUE(platform_.WriteStringToFile(filename, content)); |
| |
| int flags = FS_UNRM_FL | FS_NODUMP_FL; |
| EXPECT_TRUE(platform_.SetExtFileAttributes(filename, flags)); |
| |
| int fd; |
| ASSERT_GT(fd = HANDLE_EINTR(open(filename.value().c_str(), O_RDONLY)), 0); |
| int new_flags; |
| ASSERT_GE(ioctl(fd, FS_IOC_GETFLAGS, &new_flags), 0); |
| |
| EXPECT_EQ(flags, new_flags); |
| close(fd); |
| } |
| |
| TEST_F(PlatformTest, HasNoDumpFileAttribute) { |
| const FilePath filename(GetTempName()); |
| const std::string content("blablabla"); |
| ASSERT_TRUE(platform_.WriteStringToFile(filename, content)); |
| |
| EXPECT_FALSE(platform_.HasNoDumpFileAttribute(filename)); |
| |
| int fd; |
| ASSERT_GT(fd = open(filename.value().c_str(), O_RDONLY), 0); |
| int flags = FS_UNRM_FL | FS_NODUMP_FL; |
| ASSERT_GE(ioctl(fd, FS_IOC_SETFLAGS, &flags), 0); |
| |
| EXPECT_TRUE(platform_.HasNoDumpFileAttribute(filename)); |
| close(fd); |
| } |
| |
| TEST_F(PlatformTest, DecodeProcInfoLineGood) { |
| std::string mount_info_contents; |
| |
| mount_info_contents.append("73 24 179:1 /beg/uid1/mount/user "); |
| mount_info_contents.append("/home/user/uid1 rw,nodev,relatime - ext4 "); |
| mount_info_contents.append("/dev/mmcblk0p1 rw,commit=600,data=ordered"); |
| |
| std::vector<std::string> args; |
| size_t fs_idx; |
| |
| EXPECT_TRUE(platform_.DecodeProcInfoLine( |
| mount_info_contents, &args, &fs_idx)); |
| EXPECT_EQ(fs_idx, 7); |
| } |
| |
| TEST_F(PlatformTest, DecodeProcInfoLineCorruptedMountInfo) { |
| std::string mount_info_contents; |
| |
| mount_info_contents.append("73 24 179:1 /beg/uid1/mount/user "); |
| mount_info_contents.append("/home/user/uid1 rw,nodev,relatime hypen ext4 "); |
| mount_info_contents.append("/dev/mmcblk0p1 rw,commit=600,data=ordered"); |
| |
| std::vector<std::string> args; |
| size_t fs_idx; |
| |
| EXPECT_FALSE(platform_.DecodeProcInfoLine( |
| mount_info_contents, &args, &fs_idx)); |
| } |
| |
| TEST_F(PlatformTest, DecodeProcInfoLineIncompleteMountInfo) { |
| std::string mount_info_contents; |
| |
| mount_info_contents.append("73 24 179:1 /beg/uid1/mount/user "); |
| |
| std::vector<std::string> args; |
| size_t fs_idx; |
| |
| EXPECT_FALSE(platform_.DecodeProcInfoLine( |
| mount_info_contents, &args, &fs_idx)); |
| } |
| |
| TEST_F(PlatformTest, GetMountsBySourcePrefixExt4) { |
| base::FilePath mount_info; |
| FILE *fp; |
| std::string filesystem, device_in, device_out, mount_info_contents; |
| |
| mount_info_contents.append("73 24 179:1 /beg/uid1/mount/user "); |
| mount_info_contents.append("/home/user/uid1 rw,nodev,relatime - ext4 "); |
| mount_info_contents.append("/dev/mmcblk0p1 rw,commit=600,data=ordered"); |
| |
| fp = base::CreateAndOpenTemporaryFile(&mount_info); |
| ASSERT_TRUE(fp != NULL); |
| EXPECT_EQ(fwrite(mount_info_contents.c_str(), |
| mount_info_contents.length(), 1, fp), 1); |
| EXPECT_EQ(fclose(fp), 0); |
| |
| platform_.set_mount_info_path(mount_info); |
| |
| /* Fails if item is missing. */ |
| std::multimap<const FilePath, const FilePath> mounts; |
| EXPECT_FALSE(platform_.GetMountsBySourcePrefix(FilePath("monkey"), &mounts)); |
| |
| /* Works normally. */ |
| mounts.clear(); |
| EXPECT_TRUE(platform_.GetMountsBySourcePrefix(FilePath("/beg"), &mounts)); |
| EXPECT_EQ(mounts.size(), 1); |
| auto it = mounts.begin(); |
| EXPECT_EQ(it->first.value(), "/beg/uid1/mount/user"); |
| EXPECT_EQ(it->second.value(), "/home/user/uid1"); |
| |
| /* Clean up. */ |
| EXPECT_TRUE(base::DeleteFile(mount_info, false)); |
| } |
| |
| TEST_F(PlatformTest, GetMountsBySourcePrefixECryptFs) { |
| base::FilePath mount_info; |
| FILE *fp; |
| std::string filesystem, device_in, device_out, mount_info_contents; |
| |
| mount_info_contents.append("84 24 0:29 /user /home/user/uid2 "); |
| mount_info_contents.append("rw,nosuid,nodev,noexec,relatime - ecryptfs "); |
| mount_info_contents.append("/beg/uid2/vault rw,ecryp..."); |
| |
| fp = base::CreateAndOpenTemporaryFile(&mount_info); |
| ASSERT_TRUE(fp != NULL); |
| EXPECT_EQ(fwrite(mount_info_contents.c_str(), |
| mount_info_contents.length(), 1, fp), 1); |
| EXPECT_EQ(fclose(fp), 0); |
| |
| platform_.set_mount_info_path(mount_info); |
| |
| /* Fails if item is missing. */ |
| std::multimap<const FilePath, const FilePath> mounts; |
| EXPECT_FALSE(platform_.GetMountsBySourcePrefix(FilePath("monkey"), &mounts)); |
| |
| /* Works normally. */ |
| mounts.clear(); |
| EXPECT_TRUE(platform_.GetMountsBySourcePrefix(FilePath("/beg"), &mounts)); |
| EXPECT_EQ(mounts.size(), 1); |
| auto it = mounts.begin(); |
| EXPECT_EQ(it->first.value(), "/beg/uid2/vault"); |
| EXPECT_EQ(it->second.value(), "/home/user/uid2"); |
| |
| /* Clean up. */ |
| EXPECT_TRUE(base::DeleteFile(mount_info, false)); |
| } |
| |
| TEST_F(PlatformTest, CreateSymbolicLink) { |
| const base::FilePath link(GetTempName()); |
| const base::FilePath target(GetTempName()); |
| const base::FilePath existing_file(GetTempName()); |
| ASSERT_TRUE(platform_.TouchFileDurable(existing_file)); |
| EXPECT_TRUE(platform_.CreateSymbolicLink(link, target)); |
| EXPECT_FALSE(platform_.CreateSymbolicLink(existing_file, target)); |
| base::FilePath read_target; |
| ASSERT_TRUE(base::ReadSymbolicLink(link, &read_target)); |
| EXPECT_EQ(target.value(), read_target.value()); |
| } |
| |
| TEST_F(PlatformTest, ReadLink) { |
| const base::FilePath valid_link(GetTempName()); |
| const base::FilePath not_link(GetTempName()); |
| const base::FilePath target(GetTempName()); |
| ASSERT_TRUE(base::CreateSymbolicLink(target, valid_link)); |
| ASSERT_TRUE(platform_.TouchFileDurable(not_link)); |
| base::FilePath read_target; |
| EXPECT_TRUE(platform_.ReadLink(valid_link, &read_target)); |
| EXPECT_EQ(target.value(), read_target.value()); |
| EXPECT_FALSE(platform_.ReadLink(not_link, &read_target)); |
| } |
| |
| TEST_F(PlatformTest, SetFileTimes) { |
| struct timespec atime1 = {123, 45}; |
| struct timespec mtime1 = {234, 56}; |
| struct timespec atime2 = {345, 67}; |
| struct timespec mtime2 = {456, 78}; |
| const base::FilePath regular_file(GetTempName()); |
| const base::FilePath link(GetTempName()); |
| ASSERT_TRUE(platform_.TouchFileDurable(regular_file)); |
| ASSERT_TRUE(platform_.CreateSymbolicLink(link, regular_file)); |
| |
| EXPECT_TRUE(platform_.SetFileTimes(regular_file, atime1, mtime1, true)); |
| struct stat stat; |
| ASSERT_TRUE(platform_.Stat(regular_file, &stat)); |
| EXPECT_EQ(atime1.tv_sec, stat.st_atim.tv_sec); |
| EXPECT_EQ(atime1.tv_nsec, stat.st_atim.tv_nsec); |
| EXPECT_EQ(mtime1.tv_sec, stat.st_mtim.tv_sec); |
| EXPECT_EQ(mtime1.tv_nsec, stat.st_mtim.tv_nsec); |
| |
| EXPECT_TRUE(platform_.SetFileTimes(link, atime2, mtime2, true)); |
| ASSERT_TRUE(platform_.Stat(regular_file, &stat)); |
| EXPECT_EQ(atime2.tv_sec, stat.st_atim.tv_sec); |
| EXPECT_EQ(atime2.tv_nsec, stat.st_atim.tv_nsec); |
| EXPECT_EQ(mtime2.tv_sec, stat.st_mtim.tv_sec); |
| EXPECT_EQ(mtime2.tv_nsec, stat.st_mtim.tv_nsec); |
| ASSERT_TRUE(platform_.Stat(link, &stat)); |
| EXPECT_NE(atime2.tv_sec, stat.st_atim.tv_sec); |
| EXPECT_NE(atime2.tv_nsec, stat.st_atim.tv_nsec); |
| EXPECT_NE(mtime2.tv_sec, stat.st_mtim.tv_sec); |
| EXPECT_NE(mtime2.tv_nsec, stat.st_mtim.tv_nsec); |
| } |
| |
| TEST_F(PlatformTest, SendFile) { |
| const base::FilePath from(GetTempName()); |
| const base::FilePath to(GetTempName()); |
| const std::string contents = "0123456789"; |
| ASSERT_TRUE(platform_.WriteStringToFile(from, contents)); |
| |
| const int offset = 5; |
| const int read_size = contents.length() - offset; |
| base::File from_file(from, base::File::FLAG_OPEN | base::File::FLAG_READ); |
| base::File to_file(to, base::File::FLAG_CREATE | base::File::FLAG_WRITE); |
| EXPECT_TRUE(platform_.SendFile(to_file.GetPlatformFile(), |
| from_file.GetPlatformFile(), |
| offset, read_size)); |
| std::string to_contents; |
| ASSERT_TRUE(platform_.ReadFileToString(to, &to_contents)); |
| EXPECT_EQ(contents.substr(offset, read_size), to_contents); |
| |
| EXPECT_FALSE(platform_.SendFile(-1, from_file.GetPlatformFile(), offset, |
| read_size)); |
| EXPECT_FALSE(platform_.SendFile(to_file.GetPlatformFile(), |
| from_file.GetPlatformFile(), |
| offset, read_size + 1)); |
| } |
| |
| } // namespace cryptohome |