mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
[Support] Add functions that operate on native file handles on Windows.
Windows' CRT has a limit of 512 open file descriptors, and fds which are generated by converting a HANDLE via _get_osfhandle count towards this limit as well. Regardless, often you find yourself marshalling back and forth between native HANDLE objects and fds anyway. If we know from the getgo that we're going to need to work directly with the handle, we can cut out the marshalling layer while also not contributing to filling up the CRT's very limited handle table. On Unix these functions just delegate directly to the existing set of functions since an fd *is* the native file type. It would be nice, very long term, if we could convert most uses of fds to file_t. Differential Revision: https://reviews.llvm.org/D47688 llvm-svn: 333945
This commit is contained in:
parent
1042265b01
commit
971d9f9d57
@ -54,6 +54,15 @@ namespace llvm {
|
||||
namespace sys {
|
||||
namespace fs {
|
||||
|
||||
#if defined(_WIN32)
|
||||
// A Win32 HANDLE is a typedef of void*
|
||||
using file_t = void *;
|
||||
#else
|
||||
using file_t = int;
|
||||
#endif
|
||||
|
||||
extern const file_t kInvalidFile;
|
||||
|
||||
/// An enumeration for the file system's view of the type.
|
||||
enum class file_type {
|
||||
status_error,
|
||||
@ -835,6 +844,22 @@ inline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) {
|
||||
std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
|
||||
OpenFlags Flags, unsigned Mode = 0666);
|
||||
|
||||
/// @brief Opens the file with the given name in a write-only or read-write
|
||||
/// mode, returning its open file descriptor. If the file does not exist, it
|
||||
/// is created.
|
||||
///
|
||||
/// The caller is responsible for closing the freeing the file once they are
|
||||
/// finished with it.
|
||||
///
|
||||
/// @param Name The path of the file to open, relative or absolute.
|
||||
/// @param Flags Additional flags used to determine whether the file should be
|
||||
/// opened in, for example, read-write or in write-only mode.
|
||||
/// @param Mode The access permissions of the file, represented in octal.
|
||||
/// @returns a platform-specific file descriptor if \a Name has been opened,
|
||||
/// otherwise an error object.
|
||||
Expected<file_t> openNativeFileForWrite(const Twine &Name, OpenFlags Flags,
|
||||
unsigned Mode = 0666);
|
||||
|
||||
/// @brief Opens the file with the given name in a read-only mode, returning
|
||||
/// its open file descriptor.
|
||||
///
|
||||
@ -852,6 +877,29 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
|
||||
std::error_code openFileForRead(const Twine &Name, int &ResultFD,
|
||||
SmallVectorImpl<char> *RealPath = nullptr);
|
||||
|
||||
/// @brief Opens the file with the given name in a read-only mode, returning
|
||||
/// its open file descriptor.
|
||||
///
|
||||
/// The caller is responsible for closing the freeing the file once they are
|
||||
/// finished with it.
|
||||
///
|
||||
/// @param Name The path of the file to open, relative or absolute.
|
||||
/// @param RealPath If nonnull, extra work is done to determine the real path
|
||||
/// of the opened file, and that path is stored in this
|
||||
/// location.
|
||||
/// @returns a platform-specific file descriptor if \a Name has been opened,
|
||||
/// otherwise an error object.
|
||||
Expected<file_t>
|
||||
openNativeFileForRead(const Twine &Name,
|
||||
SmallVectorImpl<char> *RealPath = nullptr);
|
||||
|
||||
/// @brief Close the file object. This should be used instead of ::close for
|
||||
/// portability.
|
||||
///
|
||||
/// @param F On input, this is the file to close. On output, the file is
|
||||
/// set to kInvalidFile.
|
||||
void closeFile(file_t &F);
|
||||
|
||||
std::error_code getUniqueID(const Twine Path, UniqueID &Result);
|
||||
|
||||
/// Get disk space usage information.
|
||||
|
@ -93,6 +93,9 @@ using namespace llvm;
|
||||
namespace llvm {
|
||||
namespace sys {
|
||||
namespace fs {
|
||||
|
||||
const file_t kInvalidFile = -1;
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
|
||||
defined(__minix) || defined(__FreeBSD_kernel__) || defined(__linux__) || \
|
||||
defined(__CYGWIN__) || defined(__DragonFly__) || defined(_AIX)
|
||||
@ -761,6 +764,15 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
Expected<file_t> openNativeFileForRead(const Twine &Name,
|
||||
SmallVectorImpl<char> *RealPath) {
|
||||
file_t ResultFD;
|
||||
std::error_code EC = openFileForRead(Name, ResultFD, RealPath);
|
||||
if (EC)
|
||||
return errorCodeToError(EC);
|
||||
return ResultFD;
|
||||
}
|
||||
|
||||
std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
|
||||
sys::fs::OpenFlags Flags, unsigned Mode) {
|
||||
// Verify that we don't have both "append" and "excl".
|
||||
@ -798,6 +810,20 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
Expected<file_t> openNativeFileForWrite(const Twine &Name, OpenFlags Flags,
|
||||
unsigned Mode) {
|
||||
file_t ResultFD;
|
||||
std::error_code EC = openFileForWrite(Name, ResultFD, Flags, Mode);
|
||||
if (EC)
|
||||
return errorCodeToError(EC);
|
||||
return ResultFD;
|
||||
}
|
||||
|
||||
void closeFile(file_t &F) {
|
||||
::close(F);
|
||||
F = kInvalidFile;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::error_code remove_directories_impl(const T &Entry,
|
||||
bool IgnoreErrors) {
|
||||
|
@ -123,6 +123,8 @@ std::error_code widenPath(const Twine &Path8,
|
||||
|
||||
namespace fs {
|
||||
|
||||
const file_t kInvalidFile = INVALID_HANDLE_VALUE;
|
||||
|
||||
std::string getMainExecutable(const char *argv0, void *MainExecAddr) {
|
||||
SmallVector<wchar_t, MAX_PATH> PathName;
|
||||
DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity());
|
||||
@ -1051,13 +1053,32 @@ static std::error_code directoryRealPath(const Twine &Name,
|
||||
return EC;
|
||||
}
|
||||
|
||||
static std::error_code nativeFileToFd(Expected<HANDLE> H, int &ResultFD,
|
||||
int OpenFlags) {
|
||||
ResultFD = -1;
|
||||
if (!H)
|
||||
return errorToErrorCode(H.takeError());
|
||||
|
||||
ResultFD = ::_open_osfhandle(intptr_t(*H), OpenFlags);
|
||||
if (ResultFD == -1) {
|
||||
::CloseHandle(*H);
|
||||
return mapWindowsError(ERROR_INVALID_HANDLE);
|
||||
}
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
std::error_code openFileForRead(const Twine &Name, int &ResultFD,
|
||||
SmallVectorImpl<char> *RealPath) {
|
||||
ResultFD = -1;
|
||||
Expected<HANDLE> NativeFile = openNativeFileForRead(Name, RealPath);
|
||||
return nativeFileToFd(std::move(NativeFile), ResultFD, 0);
|
||||
}
|
||||
|
||||
Expected<file_t> openNativeFileForRead(const Twine &Name,
|
||||
SmallVectorImpl<char> *RealPath) {
|
||||
SmallVector<wchar_t, 128> PathUTF16;
|
||||
|
||||
if (std::error_code EC = widenPath(Name, PathUTF16))
|
||||
return EC;
|
||||
return errorCodeToError(EC);
|
||||
|
||||
HANDLE H =
|
||||
::CreateFileW(PathUTF16.begin(), GENERIC_READ,
|
||||
@ -1070,36 +1091,42 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
|
||||
// This only runs if we failed to open the file, so there is probably
|
||||
// no performances issues.
|
||||
if (LastError != ERROR_ACCESS_DENIED)
|
||||
return EC;
|
||||
return errorCodeToError(EC);
|
||||
if (is_directory(Name))
|
||||
return make_error_code(errc::is_a_directory);
|
||||
return EC;
|
||||
}
|
||||
|
||||
ResultFD = ::_open_osfhandle(intptr_t(H), 0);
|
||||
if (ResultFD == -1) {
|
||||
::CloseHandle(H);
|
||||
return mapWindowsError(ERROR_INVALID_HANDLE);
|
||||
return errorCodeToError(make_error_code(errc::is_a_directory));
|
||||
return errorCodeToError(EC);
|
||||
}
|
||||
|
||||
// Fetch the real name of the file, if the user asked
|
||||
if (RealPath)
|
||||
realPathFromHandle(H, *RealPath);
|
||||
|
||||
return std::error_code();
|
||||
return H;
|
||||
}
|
||||
|
||||
std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
|
||||
sys::fs::OpenFlags Flags, unsigned Mode) {
|
||||
int OpenFlags = 0;
|
||||
if (Flags & F_Append)
|
||||
OpenFlags |= _O_APPEND;
|
||||
|
||||
if (Flags & F_Text)
|
||||
OpenFlags |= _O_TEXT;
|
||||
|
||||
Expected<HANDLE> NativeFile = openNativeFileForWrite(Name, Flags, Mode);
|
||||
return nativeFileToFd(std::move(NativeFile), ResultFD, OpenFlags);
|
||||
}
|
||||
|
||||
Expected<file_t> openNativeFileForWrite(const Twine &Name, OpenFlags Flags,
|
||||
unsigned Mode) {
|
||||
// Verify that we don't have both "append" and "excl".
|
||||
assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) &&
|
||||
"Cannot specify both 'excl' and 'append' file creation flags!");
|
||||
|
||||
ResultFD = -1;
|
||||
SmallVector<wchar_t, 128> PathUTF16;
|
||||
|
||||
if (std::error_code EC = widenPath(Name, PathUTF16))
|
||||
return EC;
|
||||
return errorCodeToError(EC);
|
||||
|
||||
DWORD CreationDisposition;
|
||||
if (Flags & F_Excl)
|
||||
@ -1130,26 +1157,18 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
|
||||
// This only runs if we failed to open the file, so there is probably
|
||||
// no performances issues.
|
||||
if (LastError != ERROR_ACCESS_DENIED)
|
||||
return EC;
|
||||
return errorCodeToError(EC);
|
||||
if (is_directory(Name))
|
||||
return make_error_code(errc::is_a_directory);
|
||||
return EC;
|
||||
return errorCodeToError(make_error_code(errc::is_a_directory));
|
||||
return errorCodeToError(EC);
|
||||
}
|
||||
|
||||
int OpenFlags = 0;
|
||||
if (Flags & F_Append)
|
||||
OpenFlags |= _O_APPEND;
|
||||
return H;
|
||||
}
|
||||
|
||||
if (Flags & F_Text)
|
||||
OpenFlags |= _O_TEXT;
|
||||
|
||||
ResultFD = ::_open_osfhandle(intptr_t(H), OpenFlags);
|
||||
if (ResultFD == -1) {
|
||||
::CloseHandle(H);
|
||||
return mapWindowsError(ERROR_INVALID_HANDLE);
|
||||
}
|
||||
|
||||
return std::error_code();
|
||||
void closeFile(file_t &F) {
|
||||
::CloseHandle(F);
|
||||
F = kInvalidFile;
|
||||
}
|
||||
|
||||
std::error_code remove_directories(const Twine &path, bool IgnoreErrors) {
|
||||
|
Loading…
Reference in New Issue
Block a user