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) { @@ -1225,20 +1234,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); + std::error_code RenameEC; + if (!RemoveOnClose) + 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) { @@ -1268,9 +1286,11 @@ Done = true; #ifdef _WIN32 - auto H = reinterpret_cast(_get_osfhandle(FD)); - if (std::error_code EC = setDeleteDisposition(H, false)) - return errorCodeToError(EC); + if (!RemoveOnClose) { + auto H = reinterpret_cast(_get_osfhandle(FD)); + if (std::error_code EC = setDeleteDisposition(H, false)) + return errorCodeToError(EC); + } #else sys::DontRemoveFileOnSignal(TmpName); #endif @@ -1290,12 +1310,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 @@ -427,7 +427,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. @@ -1106,13 +1106,13 @@ } static DWORD nativeAccess(FileAccess Access, OpenFlags Flags) { - DWORD Result = 0; + // Surprising operations need DELETE; + // SetFileInformationByHandle(FileRenameInfo) fails if this isn't set. + DWORD Result = DELETE; if (Access & FA_Read) Result |= GENERIC_READ; if (Access & FA_Write) Result |= GENERIC_WRITE; - if (Flags & OF_Delete) - Result |= DELETE; if (Flags & OF_UpdateAtime) Result |= FILE_WRITE_ATTRIBUTES; return Result;