[llvm] r319137 - Use FILE_FLAG_DELETE_ON_CLOSE for TempFile on windows.
Rafael Espindola via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 27 17:41:23 PST 2017
Author: rafael
Date: Mon Nov 27 17:41:22 2017
New Revision: 319137
URL: http://llvm.org/viewvc/llvm-project?rev=319137&view=rev
Log:
Use FILE_FLAG_DELETE_ON_CLOSE for TempFile on windows.
We won't see the temp file no more.
Modified:
llvm/trunk/include/llvm/Support/FileSystem.h
llvm/trunk/lib/Support/Path.cpp
llvm/trunk/lib/Support/Windows/Path.inc
Modified: llvm/trunk/include/llvm/Support/FileSystem.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileSystem.h?rev=319137&r1=319136&r2=319137&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/FileSystem.h (original)
+++ llvm/trunk/include/llvm/Support/FileSystem.h Mon Nov 27 17:41:22 2017
@@ -685,8 +685,7 @@ enum OpenFlags : unsigned {
/// Open the file for read and write.
F_RW = 8,
- /// The returned handle can be used for deleting the file. Only makes a
- /// difference on windows.
+ /// Delete the file on close. Only makes a difference on windows.
F_Delete = 16
};
Modified: llvm/trunk/lib/Support/Path.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Path.cpp?rev=319137&r1=319136&r2=319137&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Path.cpp (original)
+++ llvm/trunk/lib/Support/Path.cpp Mon Nov 27 17:41:22 2017
@@ -1068,12 +1068,15 @@ TempFile::~TempFile() { assert(Done); }
Error TempFile::discard() {
Done = true;
- // Always try to close and remove.
std::error_code RemoveEC;
+// On windows closing will remove the file.
+#ifndef LLVM_ON_WIN32
+ // Always try to close and remove.
if (!TmpName.empty()) {
RemoveEC = fs::remove(TmpName);
sys::DontRemoveFileOnSignal(TmpName);
}
+#endif
if (!RemoveEC)
TmpName = "";
@@ -1091,8 +1094,15 @@ Error TempFile::keep(const Twine &Name)
assert(!Done);
Done = true;
// Always try to close and rename.
+#ifdef LLVM_ON_WIN32
+ // If we cant't cancel the delete don't rename.
+ std::error_code RenameEC = cancelDeleteOnClose(FD);
+ if (!RenameEC)
+ RenameEC = rename_fd(FD, Name);
+#else
std::error_code RenameEC = fs::rename(TmpName, Name);
sys::DontRemoveFileOnSignal(TmpName);
+#endif
if (!RenameEC)
TmpName = "";
@@ -1110,7 +1120,13 @@ Error TempFile::keep() {
assert(!Done);
Done = true;
+#ifdef LLVM_ON_WIN32
+ if (std::error_code EC = cancelDeleteOnClose(FD))
+ return errorCodeToError(EC);
+#else
sys::DontRemoveFileOnSignal(TmpName);
+#endif
+
TmpName = "";
if (close(FD) == -1) {
@@ -1125,16 +1141,19 @@ Error TempFile::keep() {
Expected<TempFile> TempFile::create(const Twine &Model, unsigned Mode) {
int FD;
SmallString<128> ResultPath;
- if (std::error_code EC = createUniqueFile(Model, FD, ResultPath, Mode))
+ if (std::error_code EC = createUniqueFile(Model, FD, ResultPath, Mode,
+ sys::fs::F_RW | sys::fs::F_Delete))
return errorCodeToError(EC);
- // Make sure we delete the file when RemoveFileOnSignal fails.
TempFile Ret(ResultPath, FD);
+#ifndef LLVM_ON_WIN32
if (sys::RemoveFileOnSignal(ResultPath)) {
+ // Make sure we delete the file when RemoveFileOnSignal fails.
consumeError(Ret.discard());
std::error_code EC(errc::operation_not_permitted);
return errorCodeToError(EC);
}
+#endif
return std::move(Ret);
}
}
Modified: llvm/trunk/lib/Support/Windows/Path.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Path.inc?rev=319137&r1=319136&r2=319137&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Windows/Path.inc (original)
+++ llvm/trunk/lib/Support/Windows/Path.inc Mon Nov 27 17:41:22 2017
@@ -391,6 +391,53 @@ std::error_code is_local(int FD, bool &R
return is_local_internal(FinalPath, Result);
}
+/// In order to handle temporary files we want the following properties
+///
+/// * The temporary file is deleted on crashes
+/// * We can use (read, rename, etc) the temporary file.
+/// * We can cancel the delete to keep the file.
+///
+/// Using FILE_DISPOSITION_INFO with DeleteFile=true will create a file that is
+/// deleted on close, but it has a few problems:
+///
+/// * The file cannot be used. An attempt to open or rename the file will fail.
+/// This makes the temporary file almost useless, as it cannot be part of
+/// any other CreateFileW call in the current or in another process.
+/// * It is not atomic. A crash just after CreateFileW or just after canceling
+/// the delete will leave the file on disk.
+///
+/// Using FILE_FLAG_DELETE_ON_CLOSE solves the first issues and the first part
+/// of the second one, but there is no way to cancel it in place. What works is
+/// to create a second handle to prevent the deletion, close the first one and
+/// then clear DeleteFile with SetFileInformationByHandle. This requires
+/// changing the handle and file descriptor the caller uses.
+static std::error_code cancelDeleteOnClose(int &FD) {
+ HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
+ SmallVector<wchar_t, MAX_PATH> Name;
+ if (std::error_code EC = realPathFromHandle(Handle, Name))
+ return EC;
+ HANDLE NewHandle =
+ ::CreateFileW(Name.data(), GENERIC_READ | GENERIC_WRITE | DELETE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (NewHandle == INVALID_HANDLE_VALUE)
+ return mapWindowsError(::GetLastError());
+ if (close(FD))
+ return mapWindowsError(::GetLastError());
+
+ FILE_DISPOSITION_INFO Disposition;
+ Disposition.DeleteFile = false;
+ if (!SetFileInformationByHandle(NewHandle, FileDispositionInfo, &Disposition,
+ sizeof(Disposition)))
+ return mapWindowsError(::GetLastError());
+ FD = ::_open_osfhandle(intptr_t(NewHandle), 0);
+ if (FD == -1) {
+ ::CloseHandle(NewHandle);
+ return mapWindowsError(ERROR_INVALID_HANDLE);
+ }
+ return std::error_code();
+}
+
static std::error_code rename_internal(HANDLE FromHandle, const Twine &To,
bool ReplaceIfExists) {
SmallVector<wchar_t, 0> ToWide;
@@ -513,6 +560,11 @@ static std::error_code rename_handle(HAN
return errc::permission_denied;
}
+static std::error_code rename_fd(int FromFD, const Twine &To) {
+ HANDLE FromHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FromFD));
+ return rename_handle(FromHandle, To);
+}
+
std::error_code rename(const Twine &From, const Twine &To) {
// Convert to utf-16.
SmallVector<wchar_t, 128> WideFrom;
@@ -1029,15 +1081,18 @@ std::error_code openFileForWrite(const T
CreationDisposition = CREATE_ALWAYS;
DWORD Access = GENERIC_WRITE;
+ DWORD Attributes = FILE_ATTRIBUTE_NORMAL;
if (Flags & F_RW)
Access |= GENERIC_READ;
- if (Flags & F_Delete)
+ if (Flags & F_Delete) {
Access |= DELETE;
+ Attributes |= FILE_FLAG_DELETE_ON_CLOSE;
+ }
HANDLE H =
- ::CreateFileW(PathUTF16.begin(), Access,
+ ::CreateFileW(PathUTF16.data(), Access,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
+ NULL, CreationDisposition, Attributes, NULL);
if (H == INVALID_HANDLE_VALUE) {
DWORD LastError = ::GetLastError();
More information about the llvm-commits
mailing list