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 @@ -772,7 +772,8 @@ /// The file should be opened in append mode. OF_Append = 4, - /// Delete the file on close. Only makes a difference on windows. + /// The returned handle can be used for deleting the file. Only makes a + /// difference on windows. OF_Delete = 8, /// When a child process is launched, this file should remain open in the @@ -865,6 +866,11 @@ // The open file descriptor. int FD = -1; +#ifdef _WIN32 + // Whether we need to manually remove the file on close. + bool RemoveOnClose = 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 + RemoveOnClose = Other.RemoveOnClose; + Other.RemoveOnClose = false; +#endif return *this; } @@ -1202,20 +1206,25 @@ FD = -1; #ifdef _WIN32 - // On windows closing will remove the file. - TmpName = ""; - return Error::success(); + // On Windows, closing will remove the file, if we set the delete + // disposition. If not, remove it manually. + bool Remove = RemoveOnClose; #else - // Always try to close and remove. + // Always try to remove the file. + bool Remove = true; +#endif std::error_code RemoveEC; - if (!TmpName.empty()) { + if (Remove && !TmpName.empty()) { RemoveEC = fs::remove(TmpName); +#ifndef _WIN32 sys::DontRemoveFileOnSignal(TmpName); +#endif if (!RemoveEC) TmpName = ""; + } else { + TmpName = ""; } return errorCodeToError(RemoveEC); -#endif } Error TempFile::keep(const Twine &Name) { @@ -1226,19 +1235,26 @@ // 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 ShouldDelete = 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); + ShouldDelete = true; } } - // If we can't rename, discard the temporary file. + // If we can't rename or copy, discard the temporary file. if (RenameEC) - setDeleteDisposition(H, true); + ShouldDelete = true; + if (ShouldDelete) { + if (!RemoveOnClose) + setDeleteDisposition(H, true); + else + remove(TmpName); + } #else std::error_code RenameEC = fs::rename(TmpName, Name); if (RenameEC) { @@ -1295,7 +1311,12 @@ return errorCodeToError(EC); TempFile Ret(ResultPath, FD); -#ifndef _WIN32 +#ifdef _WIN32 + auto H = reinterpret_cast(_get_osfhandle(FD)); + if (std::error_code EC = setDeleteDisposition(H, true)) { + Ret.RemoveOnClose = 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 @@ -416,8 +416,7 @@ // Check if the file is on a network (non-local) drive. If so, don't // continue when DeleteFile is true, since it prevents opening the file for - // writes. Note -- this will leak temporary files on disk, but only when the - // target file is on a network drive. + // writes. SmallVector FinalPath; if (std::error_code EC = realPathFromHandle(Handle, FinalPath)) return EC; @@ -427,7 +426,7 @@ return EC; if (!IsLocal) - return std::error_code(); + return errc::not_supported; // The file is on a local drive, we can safely set FILE_DISPOSITION_INFO's // flag. @@ -1183,12 +1182,6 @@ } } - if (Flags & OF_Delete) { - if ((EC = setDeleteDisposition(Result, true))) { - ::CloseHandle(Result); - return errorCodeToError(EC); - } - } return Result; }