Share a createUniqueEntity implementation between unix and windows.
authorRafael Espindola <rafael.espindola@gmail.com>
Mon, 24 Feb 2014 03:07:41 +0000 (03:07 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Mon, 24 Feb 2014 03:07:41 +0000 (03:07 +0000)
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
lib/Support/Path.cpp
lib/Support/Unix/Path.inc
lib/Support/Windows/Path.inc

index 176f935933521014a20b0568015458033ffe92b0..6fa4728f3d397a245ef379980d0a3d13024a8f84 100644 (file)
@@ -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) {
index 535ff00bae031d162517ebabc0b1086403cf0dab..5b8be18db3f7137d7ee015092ea2b0c1a9694c66 100644 (file)
@@ -27,6 +27,8 @@
 #include <io.h>
 #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<char> &ResultPath,
-                   bool MakeAbsolute, unsigned Mode, FSEntity Type);
+static error_code TempDir(SmallVectorImpl<char> &result);
+
+static error_code createUniqueEntity(const Twine &Model, int &ResultFD,
+                                     SmallVectorImpl<char> &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  {
index e211ac99110aa67c0a68e411c4c1e35577b5ed05..2249b64b451e20c7e63e137c7fa79dfe07e7c994 100644 (file)
@@ -103,76 +103,6 @@ static error_code TempDir(SmallVectorImpl<char> &result) {
   return error_code::success();
 }
 
-static error_code createUniqueEntity(const Twine &Model, int &ResultFD,
-                                     SmallVectorImpl<char> &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;
index 2e33c129e31d013e523de2a2fd9947d199d0be07..a72d0bf0b1be450855c4d6eb9a9f54a2f3fec506 100644 (file)
@@ -44,20 +44,21 @@ using namespace llvm;
 using llvm::sys::windows::UTF8ToUTF16;
 using llvm::sys::windows::UTF16ToUTF8;
 
-static error_code TempDir(SmallVectorImpl<wchar_t> &result) {
+static error_code TempDir(SmallVectorImpl<char> &Result) {
+  SmallVector<wchar_t, 64> 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<char> &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<wchar_t, 128> 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<wchar_t, 64> 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<wchar_t, 128> random_path_utf16;
-
-retry_random_path:
-  random_path_utf16.set_size(0);
-  for (SmallVectorImpl<wchar_t>::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);