[llvm] r319786 - Delete temp file if rename fails.
Rafael Espindola via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 5 08:40:56 PST 2017
Author: rafael
Date: Tue Dec 5 08:40:56 2017
New Revision: 319786
URL: http://llvm.org/viewvc/llvm-project?rev=319786&view=rev
Log:
Delete temp file if rename fails.
Without this when lld failed to replace the output file it would leave
the temporary behind. The problem is that the existing logic is
- cancel the delete flag
- rename
We have to cancel first to avoid renaming and then crashing and
deleting the old version. What is missing then is deleting the
temporary file if the rename fails.
This can be an issue on both unix and windows, but I am not sure how
to cause the rename to fail reliably on unix. I think it can be done
on ZFS since it has an ACL system similar to what windows uses, but
adding support for checking that in llvm-lit is probably not worth it.
Added:
llvm/trunk/test/tools/llvm-objcopy/cannot-delete-dest.test
Modified:
llvm/trunk/lib/Support/Path.cpp
llvm/trunk/lib/Support/Windows/Path.inc
Modified: llvm/trunk/lib/Support/Path.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Path.cpp?rev=319786&r1=319785&r2=319786&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Path.cpp (original)
+++ llvm/trunk/lib/Support/Path.cpp Tue Dec 5 08:40:56 2017
@@ -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
Modified: llvm/trunk/lib/Support/Windows/Path.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Path.inc?rev=319786&r1=319785&r2=319786&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Windows/Path.inc (original)
+++ llvm/trunk/lib/Support/Windows/Path.inc Tue Dec 5 08:40:56 2017
@@ -391,6 +391,20 @@ std::error_code is_local(int FD, bool &R
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 cancelDeleteOnClo
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);
Added: llvm/trunk/test/tools/llvm-objcopy/cannot-delete-dest.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/cannot-delete-dest.test?rev=319786&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/cannot-delete-dest.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/cannot-delete-dest.test Tue Dec 5 08:40:56 2017
@@ -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
More information about the llvm-commits
mailing list