Misc cleanups to the FileSytem api.

The main difference is the removal of

std::error_code exists(const Twine &path, bool &result);

It was an horribly redundant interface since a file not existing is also a valid
error_code. Now we have an access function that returns just an error_code. This
is the only function that has to be implemented for Unix and Windows. The
functions can_write, exists and can_execute an now just wrappers.

One still has to be very careful using these function to avoid introducing
race conditions (Time of check to time of use).

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@217625 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Rafael Espindola
2014-09-11 20:30:02 +00:00
parent d4604dca94
commit 8d230cd536
7 changed files with 70 additions and 90 deletions

View File

@@ -352,33 +352,37 @@ std::error_code resize_file(const Twine &path, uint64_t size);
/// not. /// not.
bool exists(file_status status); bool exists(file_status status);
/// @brief Does file exist? /// @brief Can the file be accessed?
/// ///
/// @param path Input path. /// @param path Input path.
/// @param result Set to true if the file represented by status exists, false if /// @returns errc::success if the path can be accessed, otherwise a
/// it does not. Undefined otherwise.
/// @returns errc::success if result has been successfully set, otherwise a
/// platform-specific error_code. /// platform-specific error_code.
std::error_code exists(const Twine &path, bool &result); enum class AccessMode { Exist, Write, Execute };
std::error_code access(const Twine &Path, AccessMode Mode);
/// @brief Simpler version of exists for clients that don't need to /// @brief Does file exist?
/// differentiate between an error and false. ///
inline bool exists(const Twine &path) { /// @param Path Input path.
bool result; /// @returns True if it exists, false otherwise.
return !exists(path, result) && result; inline bool exists(const Twine &Path) {
return !access(Path, AccessMode::Exist);
} }
/// @brief Can we execute this file? /// @brief Can we execute this file?
/// ///
/// @param Path Input path. /// @param Path Input path.
/// @returns True if we can execute it, false otherwise. /// @returns True if we can execute it, false otherwise.
bool can_execute(const Twine &Path); inline bool can_execute(const Twine &Path) {
return !access(Path, AccessMode::Execute);
}
/// @brief Can we write this file? /// @brief Can we write this file?
/// ///
/// @param Path Input path. /// @param Path Input path.
/// @returns True if we can write to it, false otherwise. /// @returns True if we can write to it, false otherwise.
bool can_write(const Twine &Path); inline bool can_write(const Twine &Path) {
return !access(Path, AccessMode::Write);
}
/// @brief Do file_status's represent the same thing? /// @brief Do file_status's represent the same thing?
/// ///

View File

@@ -204,8 +204,8 @@ LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() {
// If the lock file is still expected to be there, check whether it still // If the lock file is still expected to be there, check whether it still
// is. // is.
if (!LockFileGone) { if (!LockFileGone) {
bool Exists; if (sys::fs::access(LockFileName.c_str(), sys::fs::AccessMode::Exist) ==
if (!sys::fs::exists(LockFileName.str(), Exists) && !Exists) { errc::no_such_file_or_directory) {
LockFileGone = true; LockFileGone = true;
LockFileJustDisappeared = true; LockFileJustDisappeared = true;
} }

View File

@@ -210,13 +210,13 @@ retry_random_path:
} }
case FS_Name: { case FS_Name: {
bool Exists; std::error_code EC =
std::error_code EC = sys::fs::exists(ResultPath.begin(), Exists); sys::fs::access(ResultPath.begin(), sys::fs::AccessMode::Exist);
if (EC == errc::no_such_file_or_directory)
return std::error_code();
if (EC) if (EC)
return EC; return EC;
if (Exists) goto retry_random_path;
goto retry_random_path;
return std::error_code();
} }
case FS_Dir: { case FS_Dir: {

View File

@@ -321,40 +321,37 @@ std::error_code resize_file(const Twine &path, uint64_t size) {
return std::error_code(); return std::error_code();
} }
std::error_code exists(const Twine &path, bool &result) { static int convertAccessMode(AccessMode Mode) {
SmallString<128> path_storage; switch (Mode) {
StringRef p = path.toNullTerminatedStringRef(path_storage); case AccessMode::Exist:
return F_OK;
case AccessMode::Write:
return W_OK;
case AccessMode::Execute:
return R_OK | X_OK; // scripts also need R_OK.
}
llvm_unreachable("invalid enum");
}
if (::access(p.begin(), F_OK) == -1) { std::error_code access(const Twine &Path, AccessMode Mode) {
if (errno != ENOENT) SmallString<128> PathStorage;
return std::error_code(errno, std::generic_category()); StringRef P = Path.toNullTerminatedStringRef(PathStorage);
result = false;
} else if (::access(P.begin(), convertAccessMode(Mode)) == -1)
result = true; return std::error_code(errno, std::generic_category());
if (Mode == AccessMode::Execute) {
// Don't say that directories are executable.
struct stat buf;
if (0 != stat(P.begin(), &buf))
return errc::permission_denied;
if (!S_ISREG(buf.st_mode))
return errc::permission_denied;
}
return std::error_code(); return std::error_code();
} }
bool can_write(const Twine &Path) {
SmallString<128> PathStorage;
StringRef P = Path.toNullTerminatedStringRef(PathStorage);
return 0 == access(P.begin(), W_OK);
}
bool can_execute(const Twine &Path) {
SmallString<128> PathStorage;
StringRef P = Path.toNullTerminatedStringRef(PathStorage);
if (0 != access(P.begin(), R_OK | X_OK))
return false;
struct stat buf;
if (0 != stat(P.begin(), &buf))
return false;
if (!S_ISREG(buf.st_mode))
return false;
return true;
}
bool equivalent(file_status A, file_status B) { bool equivalent(file_status A, file_status B) {
assert(status_known(A) && status_known(B)); assert(status_known(A) && status_known(B));
return A.fs_st_dev == B.fs_st_dev && return A.fs_st_dev == B.fs_st_dev &&

View File

@@ -251,51 +251,31 @@ std::error_code resize_file(const Twine &path, uint64_t size) {
return std::error_code(error, std::generic_category()); return std::error_code(error, std::generic_category());
} }
std::error_code exists(const Twine &path, bool &result) { std::error_code access(const Twine &Path, AccessMode Mode) {
SmallString<128> path_storage; SmallString<128> PathStorage;
SmallVector<wchar_t, 128> path_utf16; SmallVector<wchar_t, 128> PathUtf16;
if (std::error_code ec = if (std::error_code EC =
UTF8ToUTF16(path.toStringRef(path_storage), path_utf16)) UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16))
return ec; return EC;
DWORD attributes = ::GetFileAttributesW(path_utf16.begin()); DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin());
if (attributes == INVALID_FILE_ATTRIBUTES) { if (Attributes == INVALID_FILE_ATTRIBUTES) {
// See if the file didn't actually exist. // See if the file didn't actually exist.
DWORD LastError = ::GetLastError(); DWORD LastError = ::GetLastError();
if (LastError != ERROR_FILE_NOT_FOUND && if (LastError != ERROR_FILE_NOT_FOUND &&
LastError != ERROR_PATH_NOT_FOUND) LastError != ERROR_PATH_NOT_FOUND)
return windows_error(LastError); return windows_error(LastError);
result = false; return errc::no_such_file_or_directory;
} else }
result = true;
if (Mode == AccessMode::Write && (Attributes & FILE_ATTRIBUTE_READONLY))
return errc::permission_denied;
return std::error_code(); return std::error_code();
} }
bool can_write(const Twine &Path) {
// FIXME: take security attributes into account.
SmallString<128> PathStorage;
SmallVector<wchar_t, 128> PathUtf16;
if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16))
return false;
DWORD Attr = ::GetFileAttributesW(PathUtf16.begin());
return (Attr != INVALID_FILE_ATTRIBUTES) && !(Attr & FILE_ATTRIBUTE_READONLY);
}
bool can_execute(const Twine &Path) {
SmallString<128> PathStorage;
SmallVector<wchar_t, 128> PathUtf16;
if (UTF8ToUTF16(Path.toStringRef(PathStorage), PathUtf16))
return false;
DWORD Attr = ::GetFileAttributesW(PathUtf16.begin());
return Attr != INVALID_FILE_ATTRIBUTES;
}
bool equivalent(file_status A, file_status B) { bool equivalent(file_status A, file_status B) {
assert(status_known(A) && status_known(B)); assert(status_known(A) && status_known(B));
return A.FileIndexHigh == B.FileIndexHigh && return A.FileIndexHigh == B.FileIndexHigh &&

View File

@@ -7,6 +7,7 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h" #include "llvm/Support/FileSystem.h"
@@ -65,9 +66,8 @@ TEST(FileOutputBuffer, Test) {
// Do *not* commit buffer. // Do *not* commit buffer.
} }
// Verify file does not exist (because buffer not committed). // Verify file does not exist (because buffer not committed).
bool Exists = false; ASSERT_EQ(fs::access(Twine(File2), fs::AccessMode::Exist),
ASSERT_NO_ERROR(fs::exists(Twine(File2), Exists)); errc::no_such_file_or_directory);
EXPECT_FALSE(Exists);
ASSERT_NO_ERROR(fs::remove(File2.str())); ASSERT_NO_ERROR(fs::remove(File2.str()));
// TEST 3: Verify sizing down case. // TEST 3: Verify sizing down case.

View File

@@ -361,9 +361,8 @@ TEST_F(FileSystemTest, TempFiles) {
EXPECT_EQ(B.type(), fs::file_type::file_not_found); EXPECT_EQ(B.type(), fs::file_type::file_not_found);
// Make sure Temp2 doesn't exist. // Make sure Temp2 doesn't exist.
bool TempFileExists; ASSERT_EQ(fs::access(Twine(TempPath2), sys::fs::AccessMode::Exist),
ASSERT_NO_ERROR(fs::exists(Twine(TempPath2), TempFileExists)); errc::no_such_file_or_directory);
EXPECT_FALSE(TempFileExists);
SmallString<64> TempPath3; SmallString<64> TempPath3;
ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "", TempPath3)); ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "", TempPath3));
@@ -386,8 +385,8 @@ TEST_F(FileSystemTest, TempFiles) {
ASSERT_NO_ERROR(fs::remove(Twine(TempPath2))); ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));
// Make sure Temp1 doesn't exist. // Make sure Temp1 doesn't exist.
ASSERT_NO_ERROR(fs::exists(Twine(TempPath), TempFileExists)); ASSERT_EQ(fs::access(Twine(TempPath), sys::fs::AccessMode::Exist),
EXPECT_FALSE(TempFileExists); errc::no_such_file_or_directory);
#ifdef LLVM_ON_WIN32 #ifdef LLVM_ON_WIN32
// Path name > 260 chars should get an error. // Path name > 260 chars should get an error.