llvm.org GIT mirror llvm / cf230cb
Support outputting to /dev/null. When writing to a non regular file we cannot rename to it. Since we have to write, we may as well create a temporary file to avoid trying to create an unique file in /dev when trying to write to /dev/null. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@291485 91177308-0d34-0410-b5e6-96231b3b80d8 Rafael Espindola 3 years ago
2 changed file(s) with 46 addition(s) and 23 deletion(s). Raw diff Collapse all Expand all
7777 FileOutputBuffer &operator=(const FileOutputBuffer &) = delete;
7878
7979 FileOutputBuffer(std::unique_ptr R,
80 StringRef Path, StringRef TempPath);
80 StringRef Path, StringRef TempPath, bool IsRegular);
8181
8282 std::unique_ptr Region;
8383 SmallString<128> FinalPath;
8484 SmallString<128> TempPath;
85 bool IsRegular;
8586 };
8687 } // end namespace llvm
8788
1414 #include "llvm/ADT/STLExtras.h"
1515 #include "llvm/ADT/SmallString.h"
1616 #include "llvm/Support/Errc.h"
17 #include "llvm/Support/Path.h"
1718 #include "llvm/Support/Signals.h"
1819 #include
1920
2728
2829 namespace llvm {
2930 FileOutputBuffer::FileOutputBuffer(std::unique_ptr R,
30 StringRef Path, StringRef TmpPath)
31 : Region(std::move(R)), FinalPath(Path), TempPath(TmpPath) {}
31 StringRef Path, StringRef TmpPath,
32 bool IsRegular)
33 : Region(std::move(R)), FinalPath(Path), TempPath(TmpPath),
34 IsRegular(IsRegular) {}
3235
3336 FileOutputBuffer::~FileOutputBuffer() {
3437 // Close the mapping before deleting the temp file, so that the removal
3942
4043 ErrorOr>
4144 FileOutputBuffer::create(StringRef FilePath, size_t Size, unsigned Flags) {
42 // If file already exists, it must be a regular file (to be mappable).
45 // Check file is not a regular file, in which case we cannot remove it.
4346 sys::fs::file_status Stat;
4447 std::error_code EC = sys::fs::status(FilePath, Stat);
48 bool IsRegular = true;
4549 switch (Stat.type()) {
4650 case sys::fs::file_type::file_not_found:
4751 // If file does not exist, we'll create one.
5559 default:
5660 if (EC)
5761 return EC;
58 else
59 return make_error_code(errc::operation_not_permitted);
62 IsRegular = false;
6063 }
6164
62 // Delete target file.
63 EC = sys::fs::remove(FilePath);
64 if (EC)
65 return EC;
65 if (IsRegular) {
66 // Delete target file.
67 EC = sys::fs::remove(FilePath);
68 if (EC)
69 return EC;
70 }
6671
67 unsigned Mode = sys::fs::all_read | sys::fs::all_write;
68 // If requested, make the output file executable.
69 if (Flags & F_executable)
70 Mode |= sys::fs::all_exe;
71
72 // Create new file in same directory but with random name.
7372 SmallString<128> TempFilePath;
7473 int FD;
75 EC = sys::fs::createUniqueFile(Twine(FilePath) + ".tmp%%%%%%%", FD,
76 TempFilePath, Mode);
74 if (IsRegular) {
75 unsigned Mode = sys::fs::all_read | sys::fs::all_write;
76 // If requested, make the output file executable.
77 if (Flags & F_executable)
78 Mode |= sys::fs::all_exe;
79 // Create new file in same directory but with random name.
80 EC = sys::fs::createUniqueFile(Twine(FilePath) + ".tmp%%%%%%%", FD,
81 TempFilePath, Mode);
82 } else {
83 // Create a temporary file. Since this is a special file, we will not move
84 // it and the new file can be in another filesystem. This avoids trying to
85 // create a temporary file in /dev when outputting to /dev/null for example.
86 EC = sys::fs::createTemporaryFile(sys::path::filename(FilePath), "", FD,
87 TempFilePath);
88 }
89
7790 if (EC)
7891 return EC;
7992
98111 if (Ret)
99112 return std::error_code(errno, std::generic_category());
100113
101 std::unique_ptr Buf(
102 new FileOutputBuffer(std::move(MappedFile), FilePath, TempFilePath));
114 std::unique_ptr Buf(new FileOutputBuffer(
115 std::move(MappedFile), FilePath, TempFilePath, IsRegular));
103116 return std::move(Buf);
104117 }
105118
107120 // Unmap buffer, letting OS flush dirty pages to file on disk.
108121 Region.reset();
109122
123 std::error_code EC;
124 if (IsRegular) {
125 // Rename file to final name.
126 EC = sys::fs::rename(Twine(TempPath), Twine(FinalPath));
127 sys::DontRemoveFileOnSignal(TempPath);
128 } else {
129 EC = sys::fs::copy_file(TempPath, FinalPath);
130 std::error_code RMEC = sys::fs::remove(TempPath);
131 sys::DontRemoveFileOnSignal(TempPath);
132 if (RMEC)
133 return RMEC;
134 }
110135
111 // Rename file to final name.
112 std::error_code EC = sys::fs::rename(Twine(TempPath), Twine(FinalPath));
113 sys::DontRemoveFileOnSignal(TempPath);
114136 return EC;
115137 }
116138 } // namespace