From 69aeeee4e1b58c76cdef06b3cbe0fcad2556b9a2 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Mon, 24 Feb 2014 03:07:41 +0000 Subject: [PATCH] Share a createUniqueEntity implementation between unix and windows. The only extra bit of functionality that had to be exposed for this be be implemented in Path.cpp is opening a file in rw mode. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@202005 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Support/FileSystem.h | 5 +- lib/Support/Path.cpp | 75 +++++++++++++++- lib/Support/Unix/Path.inc | 77 ++-------------- lib/Support/Windows/Path.inc | 143 +++--------------------------- 4 files changed, 94 insertions(+), 206 deletions(-) diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h index 176f9359335..6fa4728f3d3 100644 --- a/include/llvm/Support/FileSystem.h +++ b/include/llvm/Support/FileSystem.h @@ -580,7 +580,10 @@ enum OpenFlags { /// F_Binary - The file should be opened in binary mode on platforms that /// make this distinction. - F_Binary = 4 + F_Binary = 4, + + /// Open the file for read and write. + F_RW = 8 }; inline OpenFlags operator|(OpenFlags A, OpenFlags B) { diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp index 535ff00bae0..5b8be18db3f 100644 --- a/lib/Support/Path.cpp +++ b/lib/Support/Path.cpp @@ -27,6 +27,8 @@ #include #endif +using namespace llvm; + namespace { using llvm::StringRef; using llvm::sys::path::is_separator; @@ -162,10 +164,75 @@ enum FSEntity { }; // Implemented in Unix/Path.inc and Windows/Path.inc. -static llvm::error_code -createUniqueEntity(const llvm::Twine &Model, int &ResultFD, - llvm::SmallVectorImpl &ResultPath, - bool MakeAbsolute, unsigned Mode, FSEntity Type); +static error_code TempDir(SmallVectorImpl &result); + +static error_code createUniqueEntity(const Twine &Model, int &ResultFD, + SmallVectorImpl &ResultPath, + bool MakeAbsolute, unsigned Mode, + FSEntity Type) { + SmallString<128> ModelStorage; + Model.toVector(ModelStorage); + + if (MakeAbsolute) { + // Make model absolute by prepending a temp directory if it's not already. + if (!sys::path::is_absolute(Twine(ModelStorage))) { + SmallString<128> TDir; + if (error_code EC = TempDir(TDir)) + return EC; + sys::path::append(TDir, Twine(ModelStorage)); + ModelStorage.swap(TDir); + } + } + + // From here on, DO NOT modify model. It may be needed if the randomly chosen + // path already exists. + ResultPath = ModelStorage; + // Null terminate. + ResultPath.push_back(0); + ResultPath.pop_back(); + +retry_random_path: + // Replace '%' with random chars. + for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) { + if (ModelStorage[i] == '%') + ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; + } + + // Try to open + create the file. + switch (Type) { + case FS_File: { + if (error_code EC = sys::fs::openFileForWrite( + Twine(ResultPath.begin()), ResultFD, + sys::fs::F_RW | sys::fs::F_Excl | sys::fs::F_Binary, Mode)) { + if (EC == errc::file_exists) + goto retry_random_path; + return EC; + } + + return error_code::success(); + } + + case FS_Name: { + bool Exists; + error_code EC = sys::fs::exists(ResultPath.begin(), Exists); + if (EC) + return EC; + if (Exists) + goto retry_random_path; + return error_code::success(); + } + + case FS_Dir: { + if (error_code EC = sys::fs::create_directory(ResultPath.begin(), false)) { + if (EC == errc::file_exists) + goto retry_random_path; + return EC; + } + return error_code::success(); + } + } + llvm_unreachable("Invalid Type"); +} namespace llvm { namespace sys { diff --git a/lib/Support/Unix/Path.inc b/lib/Support/Unix/Path.inc index e211ac99110..2249b64b451 100644 --- a/lib/Support/Unix/Path.inc +++ b/lib/Support/Unix/Path.inc @@ -103,76 +103,6 @@ static error_code TempDir(SmallVectorImpl &result) { return error_code::success(); } -static error_code createUniqueEntity(const Twine &Model, int &ResultFD, - SmallVectorImpl &ResultPath, - bool MakeAbsolute, unsigned Mode, - FSEntity Type) { - SmallString<128> ModelStorage; - Model.toVector(ModelStorage); - - if (MakeAbsolute) { - // Make model absolute by prepending a temp directory if it's not already. - bool absolute = sys::path::is_absolute(Twine(ModelStorage)); - if (!absolute) { - SmallString<128> TDir; - if (error_code ec = TempDir(TDir)) return ec; - sys::path::append(TDir, Twine(ModelStorage)); - ModelStorage.swap(TDir); - } - } - - // From here on, DO NOT modify model. It may be needed if the randomly chosen - // path already exists. - ResultPath = ModelStorage; - // Null terminate. - ResultPath.push_back(0); - ResultPath.pop_back(); - -retry_random_path: - // Replace '%' with random chars. - for (unsigned i = 0, e = ModelStorage.size(); i != e; ++i) { - if (ModelStorage[i] == '%') - ResultPath[i] = "0123456789abcdef"[sys::Process::GetRandomNumber() & 15]; - } - - // Try to open + create the file. - switch (Type) { - case FS_File: { - int RandomFD = ::open(ResultPath.begin(), O_RDWR | O_CREAT | O_EXCL, Mode); - if (RandomFD == -1) { - int SavedErrno = errno; - // If the file existed, try again, otherwise, error. - if (SavedErrno == errc::file_exists) - goto retry_random_path; - return error_code(SavedErrno, system_category()); - } - - ResultFD = RandomFD; - return error_code::success(); - } - - case FS_Name: { - bool Exists; - error_code EC = sys::fs::exists(ResultPath.begin(), Exists); - if (EC) - return EC; - if (Exists) - goto retry_random_path; - return error_code::success(); - } - - case FS_Dir: { - if (error_code EC = sys::fs::create_directory(ResultPath.begin(), false)) { - if (EC == errc::file_exists) - goto retry_random_path; - return EC; - } - return error_code::success(); - } - } - llvm_unreachable("Invalid Type"); -} - namespace llvm { namespace sys { namespace fs { @@ -755,7 +685,12 @@ error_code openFileForWrite(const Twine &Name, int &ResultFD, assert((!(Flags & sys::fs::F_Excl) || !(Flags & sys::fs::F_Append)) && "Cannot specify both 'excl' and 'append' file creation flags!"); - int OpenFlags = O_WRONLY | O_CREAT; + int OpenFlags = O_CREAT; + + if (Flags & F_RW) + OpenFlags |= O_RDWR; + else + OpenFlags |= O_WRONLY; if (Flags & F_Append) OpenFlags |= O_APPEND; diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc index 2e33c129e31..a72d0bf0b1b 100644 --- a/lib/Support/Windows/Path.inc +++ b/lib/Support/Windows/Path.inc @@ -44,20 +44,21 @@ using namespace llvm; using llvm::sys::windows::UTF8ToUTF16; using llvm::sys::windows::UTF16ToUTF8; -static error_code TempDir(SmallVectorImpl &result) { +static error_code TempDir(SmallVectorImpl &Result) { + SmallVector Res; retry_temp_dir: - DWORD len = ::GetTempPathW(result.capacity(), result.begin()); + DWORD Len = ::GetTempPathW(Res.capacity(), Res.begin()); - if (len == 0) + if (Len == 0) return windows_error(::GetLastError()); - if (len > result.capacity()) { - result.reserve(len); + if (Len > Res.capacity()) { + Res.reserve(Len); goto retry_temp_dir; } - result.set_size(len); - return error_code::success(); + Res.set_size(Len); + return UTF16ToUTF8(Res.begin(), Res.size(), Result); } static bool is_separator(const wchar_t value) { @@ -70,128 +71,6 @@ static bool is_separator(const wchar_t value) { } } -// FIXME: mode should be used here and default to user r/w only, -// it currently comes in as a UNIX mode. -static error_code createUniqueEntity(const Twine &model, int &result_fd, - SmallVectorImpl &result_path, - bool makeAbsolute, unsigned mode, - FSEntity Type) { - // Use result_path as temp storage. - result_path.set_size(0); - StringRef m = model.toStringRef(result_path); - - SmallVector model_utf16; - if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec; - - if (makeAbsolute) { - // Make model absolute by prepending a temp directory if it's not already. - bool absolute = sys::path::is_absolute(m); - - if (!absolute) { - SmallVector temp_dir; - if (error_code ec = TempDir(temp_dir)) return ec; - // Handle c: by removing it. - if (model_utf16.size() > 2 && model_utf16[1] == L':') { - model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2); - } - model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end()); - } - } - - // Replace '%' with random chars. From here on, DO NOT modify model. It may be - // needed if the randomly chosen path already exists. - SmallVector random_path_utf16; - -retry_random_path: - random_path_utf16.set_size(0); - for (SmallVectorImpl::const_iterator i = model_utf16.begin(), - e = model_utf16.end(); - i != e; ++i) { - if (*i == L'%') { - unsigned val = sys::Process::GetRandomNumber(); - random_path_utf16.push_back(L"0123456789abcdef"[val & 15]); - } - else - random_path_utf16.push_back(*i); - } - // Make random_path_utf16 null terminated. - random_path_utf16.push_back(0); - random_path_utf16.pop_back(); - - HANDLE TempFileHandle = INVALID_HANDLE_VALUE; - - switch (Type) { - case FS_File: { - // Try to create + open the path. - TempFileHandle = - ::CreateFileW(random_path_utf16.begin(), GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ, NULL, - // Return ERROR_FILE_EXISTS if the file - // already exists. - CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, NULL); - if (TempFileHandle == INVALID_HANDLE_VALUE) { - // If the file existed, try again, otherwise, error. - error_code ec = windows_error(::GetLastError()); - if (ec == windows_error::file_exists) - goto retry_random_path; - - return ec; - } - - // Convert the Windows API file handle into a C-runtime handle. - int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0); - if (fd == -1) { - ::CloseHandle(TempFileHandle); - ::DeleteFileW(random_path_utf16.begin()); - // MSDN doesn't say anything about _open_osfhandle setting errno or - // GetLastError(), so just return invalid_handle. - return windows_error::invalid_handle; - } - - result_fd = fd; - break; - } - - case FS_Name: { - DWORD attributes = ::GetFileAttributesW(random_path_utf16.begin()); - if (attributes != INVALID_FILE_ATTRIBUTES) - goto retry_random_path; - error_code EC = make_error_code(windows_error(::GetLastError())); - if (EC != windows_error::file_not_found && - EC != windows_error::path_not_found) - return EC; - break; - } - - case FS_Dir: - if (!::CreateDirectoryW(random_path_utf16.begin(), NULL)) { - error_code EC = windows_error(::GetLastError()); - if (EC != windows_error::already_exists) - return EC; - goto retry_random_path; - } - break; - } - - // Set result_path to the utf-8 representation of the path. - if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), - random_path_utf16.size(), result_path)) { - switch (Type) { - case FS_File: - ::CloseHandle(TempFileHandle); - ::DeleteFileW(random_path_utf16.begin()); - case FS_Name: - break; - case FS_Dir: - ::RemoveDirectoryW(random_path_utf16.begin()); - break; - } - return ec; - } - - return error_code::success(); -} - namespace llvm { namespace sys { namespace fs { @@ -973,7 +852,11 @@ error_code openFileForWrite(const Twine &Name, int &ResultFD, else CreationDisposition = CREATE_ALWAYS; - HANDLE H = ::CreateFileW(PathUTF16.begin(), GENERIC_WRITE, + DWORD Access = GENERIC_WRITE; + if (Flags & F_RW) + Access |= GENERIC_READ; + + HANDLE H = ::CreateFileW(PathUTF16.begin(), Access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); -- 2.34.1