base: add parameter that controls O_NOFOLLOW in file functions.

Bug: http://b/31491920
Change-Id: I19cb06941d87c0180ccab8bb2d85e57338811624
Test: m
This commit is contained in:
Josh Gao 2016-09-14 16:11:45 -07:00
parent 1a73e9b7e2
commit ffabc9651f
3 changed files with 35 additions and 9 deletions

View File

@ -55,10 +55,11 @@ bool ReadFdToString(int fd, std::string* content) {
return (n == 0) ? true : false;
}
bool ReadFileToString(const std::string& path, std::string* content) {
bool ReadFileToString(const std::string& path, std::string* content, bool follow_symlinks) {
content->clear();
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
int flags = O_RDONLY | O_CLOEXEC | O_BINARY | (follow_symlinks ? 0 : O_NOFOLLOW);
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags));
if (fd == -1) {
return false;
}
@ -91,8 +92,10 @@ static bool CleanUpAfterFailedWrite(const std::string& path) {
#if !defined(_WIN32)
bool WriteStringToFile(const std::string& content, const std::string& path,
mode_t mode, uid_t owner, gid_t group) {
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
mode_t mode, uid_t owner, gid_t group,
bool follow_symlinks) {
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY |
(follow_symlinks ? 0 : O_NOFOLLOW);
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
if (fd == -1) {
PLOG(ERROR) << "android::WriteStringToFile open failed";
@ -118,8 +121,10 @@ bool WriteStringToFile(const std::string& content, const std::string& path,
}
#endif
bool WriteStringToFile(const std::string& content, const std::string& path) {
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
bool WriteStringToFile(const std::string& content, const std::string& path,
bool follow_symlinks) {
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY |
(follow_symlinks ? 0 : O_NOFOLLOW);
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, DEFFILEMODE));
if (fd == -1) {
return false;

View File

@ -45,6 +45,24 @@ TEST(file, ReadFileToString_WriteStringToFile) {
EXPECT_EQ("abc", s);
}
// symlinks require elevated privileges on Windows.
#if !defined(_WIN32)
TEST(file, ReadFileToString_WriteStringToFile_symlink) {
TemporaryFile target, link;
ASSERT_EQ(0, unlink(link.path));
ASSERT_EQ(0, symlink(target.path, link.path));
ASSERT_FALSE(android::base::WriteStringToFile("foo", link.path, false));
ASSERT_EQ(ELOOP, errno);
ASSERT_TRUE(android::base::WriteStringToFile("foo", link.path, true));
std::string s;
ASSERT_FALSE(android::base::ReadFileToString(link.path, &s));
ASSERT_EQ(ELOOP, errno);
ASSERT_TRUE(android::base::ReadFileToString(link.path, &s, true));
ASSERT_EQ("foo", s);
}
#endif
// WriteStringToFile2 is explicitly for setting Unix permissions, which make no
// sense on Windows.
#if !defined(_WIN32)

View File

@ -28,14 +28,17 @@ namespace android {
namespace base {
bool ReadFdToString(int fd, std::string* content);
bool ReadFileToString(const std::string& path, std::string* content);
bool ReadFileToString(const std::string& path, std::string* content,
bool follow_symlinks = false);
bool WriteStringToFile(const std::string& content, const std::string& path);
bool WriteStringToFile(const std::string& content, const std::string& path,
bool follow_symlinks = false);
bool WriteStringToFd(const std::string& content, int fd);
#if !defined(_WIN32)
bool WriteStringToFile(const std::string& content, const std::string& path,
mode_t mode, uid_t owner, gid_t group);
mode_t mode, uid_t owner, gid_t group,
bool follow_symlinks = false);
#endif
bool ReadFully(int fd, void* data, size_t byte_count);