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 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) { @@ -1290,12 +1306,23 @@ OpenFlags ExtraFlags) { int FD; SmallString<128> ResultPath; +#ifdef _WIN32 + sys::fs::createUniquePath(Model, ResultPath, false); + StringRef TargetDir = path::parent_path(ResultPath); + if (TargetDir.empty()) + TargetDir = "."; + if (is_local(TargetDir)) + ExtraFlags |= OF_Delete; +#endif if (std::error_code EC = - createUniqueFile(Model, FD, ResultPath, OF_Delete | ExtraFlags, Mode)) + createUniqueFile(Model, FD, ResultPath, ExtraFlags, Mode)) return errorCodeToError(EC); TempFile Ret(ResultPath, FD); -#ifndef _WIN32 +#ifdef _WIN32 + if (!(ExtraFlags & OF_Delete)) + 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,9 @@ // 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. This returns an error (instead of silently not doing what was + // requested); TempFile::create checks whether the destination is local or + // not, and only sets OF_Delete if it's possible (if it's local). SmallVector FinalPath; if (std::error_code EC = realPathFromHandle(Handle, FinalPath)) return EC; @@ -427,7 +428,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. @@ -1109,8 +1110,9 @@ DWORD Result = 0; if (Access & FA_Read) Result |= GENERIC_READ; + // SetFileInformationByHandle(FileRenameInfo) needs DELETE if (Access & FA_Write) - Result |= GENERIC_WRITE; + Result |= GENERIC_WRITE | DELETE; if (Flags & OF_Delete) Result |= DELETE; if (Flags & OF_UpdateAtime)