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:
parent
1315408eeb
commit
cbeeec22b4
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user