diff options
-rw-r--r-- | llvm/lib/Support/Path.cpp | 6 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/Path.inc | 22 | ||||
-rw-r--r-- | llvm/test/tools/llvm-objcopy/cannot-delete-dest.test | 22 |
3 files changed, 45 insertions, 5 deletions
diff --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp index d4b9d02e030..f229f23a4f8 100644 --- a/llvm/lib/Support/Path.cpp +++ b/llvm/lib/Support/Path.cpp @@ -1099,8 +1099,14 @@ Error TempFile::keep(const Twine &Name) { std::error_code RenameEC = cancelDeleteOnClose(FD); if (!RenameEC) RenameEC = rename_fd(FD, Name); + // If we can't rename, discard the temporary file. + if (RenameEC) + removeFD(FD); #else std::error_code RenameEC = fs::rename(TmpName, Name); + // If we can't rename, discard the temporary file. + if (RenameEC) + remove(TmpName); sys::DontRemoveFileOnSignal(TmpName); #endif diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc index f5b1c0ffe69..f81790b17df 100644 --- a/llvm/lib/Support/Windows/Path.inc +++ b/llvm/lib/Support/Windows/Path.inc @@ -391,6 +391,20 @@ std::error_code is_local(int FD, bool &Result) { return is_local_internal(FinalPath, Result); } +static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) { + FILE_DISPOSITION_INFO Disposition; + Disposition.DeleteFile = Delete; + if (!SetFileInformationByHandle(Handle, FileDispositionInfo, &Disposition, + sizeof(Disposition))) + return mapWindowsError(::GetLastError()); + return std::error_code(); +} + +static std::error_code removeFD(int FD) { + HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + return setDeleteDisposition(Handle, true); +} + /// In order to handle temporary files we want the following properties /// /// * The temporary file is deleted on crashes @@ -425,11 +439,9 @@ static std::error_code cancelDeleteOnClose(int &FD) { if (close(FD)) return mapWindowsError(::GetLastError()); - FILE_DISPOSITION_INFO Disposition; - Disposition.DeleteFile = false; - if (!SetFileInformationByHandle(NewHandle, FileDispositionInfo, &Disposition, - sizeof(Disposition))) - return mapWindowsError(::GetLastError()); + if (std::error_code EC = setDeleteDisposition(NewHandle, false)) + return EC; + FD = ::_open_osfhandle(intptr_t(NewHandle), 0); if (FD == -1) { ::CloseHandle(NewHandle); diff --git a/llvm/test/tools/llvm-objcopy/cannot-delete-dest.test b/llvm/test/tools/llvm-objcopy/cannot-delete-dest.test new file mode 100644 index 00000000000..c07346b7384 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/cannot-delete-dest.test @@ -0,0 +1,22 @@ +# REQUIRES: system-windows +# RUN: icacls %t /grant Everyone:(DC) || true +# RUN: rm -rf %t +# RUN: mkdir %t +# RUN: cd %t +# RUN: yaml2obj %s > test.o +# RUN: cp test.o test2.o +# RUN: icacls test2.o /deny Everyone:(D) +# RUN: icacls . /deny Everyone:(DC) + +# This fails because it cannot replace test2.o +# RUN: not llvm-objcopy test.o test2.o + +# But it doesn't leave any temporary files behind. +# RUN: not ls test2.o.tmp* + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 |