summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Support/Path.cpp6
-rw-r--r--llvm/lib/Support/Windows/Path.inc22
-rw-r--r--llvm/test/tools/llvm-objcopy/cannot-delete-dest.test22
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
OpenPOWER on IntegriCloud