1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 11:13:28 +01:00

Use FILE_FLAG_DELETE_ON_CLOSE for TempFile on windows.

We won't see the temp file no more.

llvm-svn: 319137
This commit is contained in:
Rafael Espindola 2017-11-28 01:41:22 +00:00
parent 1315408eeb
commit cbeeec22b4
3 changed files with 81 additions and 8 deletions

View File

@ -685,8 +685,7 @@ enum OpenFlags : unsigned {
/// Open the file for read and write. /// Open the file for read and write.
F_RW = 8, F_RW = 8,
/// The returned handle can be used for deleting the file. Only makes a /// Delete the file on close. Only makes a difference on windows.
/// difference on windows.
F_Delete = 16 F_Delete = 16
}; };

View File

@ -1068,12 +1068,15 @@ TempFile::~TempFile() { assert(Done); }
Error TempFile::discard() { Error TempFile::discard() {
Done = true; Done = true;
// Always try to close and remove.
std::error_code RemoveEC; std::error_code RemoveEC;
// On windows closing will remove the file.
#ifndef LLVM_ON_WIN32
// Always try to close and remove.
if (!TmpName.empty()) { if (!TmpName.empty()) {
RemoveEC = fs::remove(TmpName); RemoveEC = fs::remove(TmpName);
sys::DontRemoveFileOnSignal(TmpName); sys::DontRemoveFileOnSignal(TmpName);
} }
#endif
if (!RemoveEC) if (!RemoveEC)
TmpName = ""; TmpName = "";
@ -1091,8 +1094,15 @@ Error TempFile::keep(const Twine &Name) {
assert(!Done); assert(!Done);
Done = true; Done = true;
// Always try to close and rename. // 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); std::error_code RenameEC = fs::rename(TmpName, Name);
sys::DontRemoveFileOnSignal(TmpName); sys::DontRemoveFileOnSignal(TmpName);
#endif
if (!RenameEC) if (!RenameEC)
TmpName = ""; TmpName = "";
@ -1110,7 +1120,13 @@ Error TempFile::keep() {
assert(!Done); assert(!Done);
Done = true; Done = true;
#ifdef LLVM_ON_WIN32
if (std::error_code EC = cancelDeleteOnClose(FD))
return errorCodeToError(EC);
#else
sys::DontRemoveFileOnSignal(TmpName); sys::DontRemoveFileOnSignal(TmpName);
#endif
TmpName = ""; TmpName = "";
if (close(FD) == -1) { if (close(FD) == -1) {
@ -1125,16 +1141,19 @@ Error TempFile::keep() {
Expected<TempFile> TempFile::create(const Twine &Model, unsigned Mode) { Expected<TempFile> TempFile::create(const Twine &Model, unsigned Mode) {
int FD; int FD;
SmallString<128> ResultPath; 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); return errorCodeToError(EC);
// Make sure we delete the file when RemoveFileOnSignal fails.
TempFile Ret(ResultPath, FD); TempFile Ret(ResultPath, FD);
#ifndef LLVM_ON_WIN32
if (sys::RemoveFileOnSignal(ResultPath)) { if (sys::RemoveFileOnSignal(ResultPath)) {
// Make sure we delete the file when RemoveFileOnSignal fails.
consumeError(Ret.discard()); consumeError(Ret.discard());
std::error_code EC(errc::operation_not_permitted); std::error_code EC(errc::operation_not_permitted);
return errorCodeToError(EC); return errorCodeToError(EC);
} }
#endif
return std::move(Ret); return std::move(Ret);
} }
} }

View File

@ -391,6 +391,53 @@ std::error_code is_local(int FD, bool &Result) {
return is_local_internal(FinalPath, Result); 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, static std::error_code rename_internal(HANDLE FromHandle, const Twine &To,
bool ReplaceIfExists) { bool ReplaceIfExists) {
SmallVector<wchar_t, 0> ToWide; SmallVector<wchar_t, 0> ToWide;
@ -513,6 +560,11 @@ static std::error_code rename_handle(HANDLE FromHandle, const Twine &To) {
return errc::permission_denied; 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) { std::error_code rename(const Twine &From, const Twine &To) {
// Convert to utf-16. // Convert to utf-16.
SmallVector<wchar_t, 128> WideFrom; SmallVector<wchar_t, 128> WideFrom;
@ -1029,15 +1081,18 @@ std::error_code openFileForWrite(const Twine &Name, int &ResultFD,
CreationDisposition = CREATE_ALWAYS; CreationDisposition = CREATE_ALWAYS;
DWORD Access = GENERIC_WRITE; DWORD Access = GENERIC_WRITE;
DWORD Attributes = FILE_ATTRIBUTE_NORMAL;
if (Flags & F_RW) if (Flags & F_RW)
Access |= GENERIC_READ; Access |= GENERIC_READ;
if (Flags & F_Delete) if (Flags & F_Delete) {
Access |= DELETE; Access |= DELETE;
Attributes |= FILE_FLAG_DELETE_ON_CLOSE;
}
HANDLE H = HANDLE H =
::CreateFileW(PathUTF16.begin(), Access, ::CreateFileW(PathUTF16.data(), Access,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, CreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); NULL, CreationDisposition, Attributes, NULL);
if (H == INVALID_HANDLE_VALUE) { if (H == INVALID_HANDLE_VALUE) {
DWORD LastError = ::GetLastError(); DWORD LastError = ::GetLastError();