diff --git a/llvm/include/llvm/Support/FileSystem.h b/llvm/include/llvm/Support/FileSystem.h --- a/llvm/include/llvm/Support/FileSystem.h +++ b/llvm/include/llvm/Support/FileSystem.h @@ -865,6 +865,11 @@ // The open file descriptor. int FD = -1; +#ifdef _WIN32 + // Whether we need to manually delete the file on close. + bool DeleteOnClose = false; +#endif + // Keep this with the given name. Error keep(const Twine &Name); diff --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp --- a/llvm/lib/Support/Path.cpp +++ b/llvm/lib/Support/Path.cpp @@ -1188,6 +1188,10 @@ FD = Other.FD; Other.Done = true; Other.FD = -1; +#ifdef _WIN32 + DeleteOnClose = Other.DeleteOnClose; + Other.DeleteOnClose = false; +#endif return *this; } @@ -1202,9 +1206,17 @@ FD = -1; #ifdef _WIN32 - // On windows closing will remove the file. - TmpName = ""; - return Error::success(); + // On windows closing will remove the file, if we managed to set + // the delete disposition. If not, delete it manually. + std::error_code RemoveEC; + if (DeleteOnClose && !TmpName.empty()) { + RemoveEC = fs::remove(TmpName); + if (!RemoveEC) + TmpName = ""; + } else { + TmpName = ""; + } + return errorCodeToError(RemoveEC); #else // Always try to close and remove. std::error_code RemoveEC; @@ -1225,20 +1237,29 @@ #ifdef _WIN32 // If we can't cancel the delete don't rename. auto H = reinterpret_cast(_get_osfhandle(FD)); - std::error_code RenameEC = setDeleteDisposition(H, false); + bool Delete = false; + std::error_code RenameEC = setDeleteDisposition(H, Delete); + DeleteOnClose = false; if (!RenameEC) { RenameEC = rename_handle(H, Name); // If rename failed because it's cross-device, copy instead if (RenameEC == std::error_code(ERROR_NOT_SAME_DEVICE, std::system_category())) { RenameEC = copy_file(TmpName, Name); - setDeleteDisposition(H, true); + Delete = true; + setDeleteDisposition(H, Delete); + if (!Delete) + DeleteOnClose = true; } } // If we can't rename, discard the temporary file. - if (RenameEC) - setDeleteDisposition(H, true); + if (RenameEC) { + Delete = true; + setDeleteDisposition(H, Delete); + if (!Delete) + DeleteOnClose = true; + } #else std::error_code RenameEC = fs::rename(TmpName, Name); if (RenameEC) { @@ -1269,8 +1290,10 @@ #ifdef _WIN32 auto H = reinterpret_cast(_get_osfhandle(FD)); - if (std::error_code EC = setDeleteDisposition(H, false)) + bool Delete = false; + if (std::error_code EC = setDeleteDisposition(H, Delete)) return errorCodeToError(EC); + DeleteOnClose = false; #else sys::DontRemoveFileOnSignal(TmpName); #endif @@ -1295,7 +1318,22 @@ return errorCodeToError(EC); TempFile Ret(ResultPath, FD); -#ifndef _WIN32 +#ifdef _WIN32 + auto H = reinterpret_cast(_get_osfhandle(FD)); + bool Delete = true; + // TODO: This causes duplicate calls to setDeleteDisposition as createUniqueFile + // also calls it internally, but we can't easily know whether it succeeded or not. + // We can't leave out OF_Delete from the call, because it's needed to set the + // DELETE access mode flag. + if (std::error_code EC = setDeleteDisposition(H, Delete)) { + consumeError(Ret.discard()); + return errorCodeToError(EC); + } + // If we weren't able to set flag for implicitly deleting the file on + // close, make a note to delete it manually. + if (!Delete) + Ret.DeleteOnClose = true; +#else if (sys::RemoveFileOnSignal(ResultPath)) { // Make sure we delete the file when RemoveFileOnSignal fails. consumeError(Ret.discard()); diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc --- a/llvm/lib/Support/Windows/Path.inc +++ b/llvm/lib/Support/Windows/Path.inc @@ -401,7 +401,7 @@ return is_local_internal(FinalPath, Result); } -static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) { +static std::error_code setDeleteDisposition(HANDLE Handle, bool &Delete) { // Clear the FILE_DISPOSITION_INFO flag first, before checking if it's a // network file. On Windows 7 the function realPathFromHandle() below fails // if the FILE_DISPOSITION_INFO flag was already set to 'DeleteFile = true' by @@ -426,8 +426,10 @@ if (std::error_code EC = is_local_internal(FinalPath, IsLocal)) return EC; - if (!IsLocal) + if (!IsLocal) { + Delete = false; return std::error_code(); + } // The file is on a local drive, we can safely set FILE_DISPOSITION_INFO's // flag. @@ -1184,7 +1186,8 @@ } if (Flags & OF_Delete) { - if ((EC = setDeleteDisposition(Result, true))) { + bool Delete = true; + if ((EC = setDeleteDisposition(Result, Delete))) { ::CloseHandle(Result); return errorCodeToError(EC); }