Index: llvm/trunk/include/llvm/Support/FileSystem.h =================================================================== --- llvm/trunk/include/llvm/Support/FileSystem.h +++ llvm/trunk/include/llvm/Support/FileSystem.h @@ -54,6 +54,15 @@ 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 @@ 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 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 openFileForRead(const Twine &Name, int &ResultFD, SmallVectorImpl *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 +openNativeFileForRead(const Twine &Name, + SmallVectorImpl *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. Index: llvm/trunk/lib/Support/Unix/Path.inc =================================================================== --- llvm/trunk/lib/Support/Unix/Path.inc +++ llvm/trunk/lib/Support/Unix/Path.inc @@ -93,6 +93,9 @@ 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 @@ return std::error_code(); } +Expected openNativeFileForRead(const Twine &Name, + SmallVectorImpl *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 @@ return std::error_code(); } +Expected 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 static std::error_code remove_directories_impl(const T &Entry, bool IgnoreErrors) { Index: llvm/trunk/lib/Support/Windows/Path.inc =================================================================== --- llvm/trunk/lib/Support/Windows/Path.inc +++ llvm/trunk/lib/Support/Windows/Path.inc @@ -123,6 +123,8 @@ namespace fs { +const file_t kInvalidFile = INVALID_HANDLE_VALUE; + std::string getMainExecutable(const char *argv0, void *MainExecAddr) { SmallVector PathName; DWORD Size = ::GetModuleFileNameW(NULL, PathName.data(), PathName.capacity()); @@ -1051,13 +1053,32 @@ return EC; } +static std::error_code nativeFileToFd(Expected 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 *RealPath) { - ResultFD = -1; + Expected NativeFile = openNativeFileForRead(Name, RealPath); + return nativeFileToFd(std::move(NativeFile), ResultFD, 0); +} + +Expected openNativeFileForRead(const Twine &Name, + SmallVectorImpl *RealPath) { SmallVector 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 @@ // 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 NativeFile = openNativeFileForWrite(Name, Flags, Mode); + return nativeFileToFd(std::move(NativeFile), ResultFD, OpenFlags); +} + +Expected 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 PathUTF16; if (std::error_code EC = widenPath(Name, PathUTF16)) - return EC; + return errorCodeToError(EC); DWORD CreationDisposition; if (Flags & F_Excl) @@ -1130,26 +1157,18 @@ // 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; - - 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 H; +} - return std::error_code(); +void closeFile(file_t &F) { + ::CloseHandle(F); + F = kInvalidFile; } std::error_code remove_directories(const Twine &path, bool IgnoreErrors) {