FileUtilities.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. //===- Support/FileUtilities.cpp - File System Utilities ------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file implements a family of utility functions which are useful for doing
  10. // various things with files.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "llvm/Support/FileUtilities.h"
  14. #include "llvm/ADT/SmallString.h"
  15. #include "llvm/ADT/StringExtras.h"
  16. #include "llvm/Support/Error.h"
  17. #include "llvm/Support/ErrorOr.h"
  18. #include "llvm/Support/MemoryBuffer.h"
  19. #include "llvm/Support/Process.h"
  20. #include "llvm/Support/raw_ostream.h"
  21. #include <cmath>
  22. #include <cstdint>
  23. #include <cstdlib>
  24. #include <cstring>
  25. #include <memory>
  26. #include <system_error>
  27. using namespace llvm;
  28. static bool isSignedChar(char C) {
  29. return (C == '+' || C == '-');
  30. }
  31. static bool isExponentChar(char C) {
  32. switch (C) {
  33. case 'D': // Strange exponential notation.
  34. case 'd': // Strange exponential notation.
  35. case 'e':
  36. case 'E': return true;
  37. default: return false;
  38. }
  39. }
  40. static bool isNumberChar(char C) {
  41. switch (C) {
  42. case '0': case '1': case '2': case '3': case '4':
  43. case '5': case '6': case '7': case '8': case '9':
  44. case '.': return true;
  45. default: return isSignedChar(C) || isExponentChar(C);
  46. }
  47. }
  48. static const char *BackupNumber(const char *Pos, const char *FirstChar) {
  49. // If we didn't stop in the middle of a number, don't backup.
  50. if (!isNumberChar(*Pos)) return Pos;
  51. // Otherwise, return to the start of the number.
  52. bool HasPeriod = false;
  53. while (Pos > FirstChar && isNumberChar(Pos[-1])) {
  54. // Backup over at most one period.
  55. if (Pos[-1] == '.') {
  56. if (HasPeriod)
  57. break;
  58. HasPeriod = true;
  59. }
  60. --Pos;
  61. if (Pos > FirstChar && isSignedChar(Pos[0]) && !isExponentChar(Pos[-1]))
  62. break;
  63. }
  64. return Pos;
  65. }
  66. /// EndOfNumber - Return the first character that is not part of the specified
  67. /// number. This assumes that the buffer is null terminated, so it won't fall
  68. /// off the end.
  69. static const char *EndOfNumber(const char *Pos) {
  70. while (isNumberChar(*Pos))
  71. ++Pos;
  72. return Pos;
  73. }
  74. /// CompareNumbers - compare two numbers, returning true if they are different.
  75. static bool CompareNumbers(const char *&F1P, const char *&F2P,
  76. const char *F1End, const char *F2End,
  77. double AbsTolerance, double RelTolerance,
  78. std::string *ErrorMsg) {
  79. const char *F1NumEnd, *F2NumEnd;
  80. double V1 = 0.0, V2 = 0.0;
  81. // If one of the positions is at a space and the other isn't, chomp up 'til
  82. // the end of the space.
  83. while (isSpace(static_cast<unsigned char>(*F1P)) && F1P != F1End)
  84. ++F1P;
  85. while (isSpace(static_cast<unsigned char>(*F2P)) && F2P != F2End)
  86. ++F2P;
  87. // If we stop on numbers, compare their difference.
  88. if (!isNumberChar(*F1P) || !isNumberChar(*F2P)) {
  89. // The diff failed.
  90. F1NumEnd = F1P;
  91. F2NumEnd = F2P;
  92. } else {
  93. // Note that some ugliness is built into this to permit support for numbers
  94. // that use "D" or "d" as their exponential marker, e.g. "1.234D45". This
  95. // occurs in 200.sixtrack in spec2k.
  96. V1 = strtod(F1P, const_cast<char**>(&F1NumEnd));
  97. V2 = strtod(F2P, const_cast<char**>(&F2NumEnd));
  98. if (*F1NumEnd == 'D' || *F1NumEnd == 'd') {
  99. // Copy string into tmp buffer to replace the 'D' with an 'e'.
  100. SmallString<200> StrTmp(F1P, EndOfNumber(F1NumEnd)+1);
  101. // Strange exponential notation!
  102. StrTmp[static_cast<unsigned>(F1NumEnd-F1P)] = 'e';
  103. V1 = strtod(&StrTmp[0], const_cast<char**>(&F1NumEnd));
  104. F1NumEnd = F1P + (F1NumEnd-&StrTmp[0]);
  105. }
  106. if (*F2NumEnd == 'D' || *F2NumEnd == 'd') {
  107. // Copy string into tmp buffer to replace the 'D' with an 'e'.
  108. SmallString<200> StrTmp(F2P, EndOfNumber(F2NumEnd)+1);
  109. // Strange exponential notation!
  110. StrTmp[static_cast<unsigned>(F2NumEnd-F2P)] = 'e';
  111. V2 = strtod(&StrTmp[0], const_cast<char**>(&F2NumEnd));
  112. F2NumEnd = F2P + (F2NumEnd-&StrTmp[0]);
  113. }
  114. }
  115. if (F1NumEnd == F1P || F2NumEnd == F2P) {
  116. if (ErrorMsg) {
  117. *ErrorMsg = "FP Comparison failed, not a numeric difference between '";
  118. *ErrorMsg += F1P[0];
  119. *ErrorMsg += "' and '";
  120. *ErrorMsg += F2P[0];
  121. *ErrorMsg += "'";
  122. }
  123. return true;
  124. }
  125. // Check to see if these are inside the absolute tolerance
  126. if (AbsTolerance < std::abs(V1-V2)) {
  127. // Nope, check the relative tolerance...
  128. double Diff;
  129. if (V2)
  130. Diff = std::abs(V1/V2 - 1.0);
  131. else if (V1)
  132. Diff = std::abs(V2/V1 - 1.0);
  133. else
  134. Diff = 0; // Both zero.
  135. if (Diff > RelTolerance) {
  136. if (ErrorMsg) {
  137. raw_string_ostream(*ErrorMsg)
  138. << "Compared: " << V1 << " and " << V2 << '\n'
  139. << "abs. diff = " << std::abs(V1-V2) << " rel.diff = " << Diff << '\n'
  140. << "Out of tolerance: rel/abs: " << RelTolerance << '/'
  141. << AbsTolerance;
  142. }
  143. return true;
  144. }
  145. }
  146. // Otherwise, advance our read pointers to the end of the numbers.
  147. F1P = F1NumEnd; F2P = F2NumEnd;
  148. return false;
  149. }
  150. /// DiffFilesWithTolerance - Compare the two files specified, returning 0 if the
  151. /// files match, 1 if they are different, and 2 if there is a file error. This
  152. /// function differs from DiffFiles in that you can specify an absolete and
  153. /// relative FP error that is allowed to exist. If you specify a string to fill
  154. /// in for the error option, it will set the string to an error message if an
  155. /// error occurs, allowing the caller to distinguish between a failed diff and a
  156. /// file system error.
  157. ///
  158. int llvm::DiffFilesWithTolerance(StringRef NameA,
  159. StringRef NameB,
  160. double AbsTol, double RelTol,
  161. std::string *Error) {
  162. // Now its safe to mmap the files into memory because both files
  163. // have a non-zero size.
  164. ErrorOr<std::unique_ptr<MemoryBuffer>> F1OrErr = MemoryBuffer::getFile(NameA);
  165. if (std::error_code EC = F1OrErr.getError()) {
  166. if (Error)
  167. *Error = EC.message();
  168. return 2;
  169. }
  170. MemoryBuffer &F1 = *F1OrErr.get();
  171. ErrorOr<std::unique_ptr<MemoryBuffer>> F2OrErr = MemoryBuffer::getFile(NameB);
  172. if (std::error_code EC = F2OrErr.getError()) {
  173. if (Error)
  174. *Error = EC.message();
  175. return 2;
  176. }
  177. MemoryBuffer &F2 = *F2OrErr.get();
  178. // Okay, now that we opened the files, scan them for the first difference.
  179. const char *File1Start = F1.getBufferStart();
  180. const char *File2Start = F2.getBufferStart();
  181. const char *File1End = F1.getBufferEnd();
  182. const char *File2End = F2.getBufferEnd();
  183. const char *F1P = File1Start;
  184. const char *F2P = File2Start;
  185. uint64_t A_size = F1.getBufferSize();
  186. uint64_t B_size = F2.getBufferSize();
  187. // Are the buffers identical? Common case: Handle this efficiently.
  188. if (A_size == B_size &&
  189. std::memcmp(File1Start, File2Start, A_size) == 0)
  190. return 0;
  191. // Otherwise, we are done a tolerances are set.
  192. if (AbsTol == 0 && RelTol == 0) {
  193. if (Error)
  194. *Error = "Files differ without tolerance allowance";
  195. return 1; // Files different!
  196. }
  197. bool CompareFailed = false;
  198. while (true) {
  199. // Scan for the end of file or next difference.
  200. while (F1P < File1End && F2P < File2End && *F1P == *F2P) {
  201. ++F1P;
  202. ++F2P;
  203. }
  204. if (F1P >= File1End || F2P >= File2End) break;
  205. // Okay, we must have found a difference. Backup to the start of the
  206. // current number each stream is at so that we can compare from the
  207. // beginning.
  208. F1P = BackupNumber(F1P, File1Start);
  209. F2P = BackupNumber(F2P, File2Start);
  210. // Now that we are at the start of the numbers, compare them, exiting if
  211. // they don't match.
  212. if (CompareNumbers(F1P, F2P, File1End, File2End, AbsTol, RelTol, Error)) {
  213. CompareFailed = true;
  214. break;
  215. }
  216. }
  217. // Okay, we reached the end of file. If both files are at the end, we
  218. // succeeded.
  219. bool F1AtEnd = F1P >= File1End;
  220. bool F2AtEnd = F2P >= File2End;
  221. if (!CompareFailed && (!F1AtEnd || !F2AtEnd)) {
  222. // Else, we might have run off the end due to a number: backup and retry.
  223. if (F1AtEnd && isNumberChar(F1P[-1])) --F1P;
  224. if (F2AtEnd && isNumberChar(F2P[-1])) --F2P;
  225. F1P = BackupNumber(F1P, File1Start);
  226. F2P = BackupNumber(F2P, File2Start);
  227. // Now that we are at the start of the numbers, compare them, exiting if
  228. // they don't match.
  229. if (CompareNumbers(F1P, F2P, File1End, File2End, AbsTol, RelTol, Error))
  230. CompareFailed = true;
  231. // If we found the end, we succeeded.
  232. if (F1P < File1End || F2P < File2End)
  233. CompareFailed = true;
  234. }
  235. return CompareFailed;
  236. }
  237. void llvm::AtomicFileWriteError::log(raw_ostream &OS) const {
  238. OS << "atomic_write_error: ";
  239. switch (Error) {
  240. case atomic_write_error::failed_to_create_uniq_file:
  241. OS << "failed_to_create_uniq_file";
  242. return;
  243. case atomic_write_error::output_stream_error:
  244. OS << "output_stream_error";
  245. return;
  246. case atomic_write_error::failed_to_rename_temp_file:
  247. OS << "failed_to_rename_temp_file";
  248. return;
  249. }
  250. llvm_unreachable("unknown atomic_write_error value in "
  251. "failed_to_rename_temp_file::log()");
  252. }
  253. llvm::Error llvm::writeFileAtomically(StringRef TempPathModel,
  254. StringRef FinalPath, StringRef Buffer) {
  255. return writeFileAtomically(TempPathModel, FinalPath,
  256. [&Buffer](llvm::raw_ostream &OS) {
  257. OS.write(Buffer.data(), Buffer.size());
  258. return llvm::Error::success();
  259. });
  260. }
  261. llvm::Error llvm::writeFileAtomically(
  262. StringRef TempPathModel, StringRef FinalPath,
  263. std::function<llvm::Error(llvm::raw_ostream &)> Writer) {
  264. SmallString<128> GeneratedUniqPath;
  265. int TempFD;
  266. if (sys::fs::createUniqueFile(TempPathModel, TempFD, GeneratedUniqPath)) {
  267. return llvm::make_error<AtomicFileWriteError>(
  268. atomic_write_error::failed_to_create_uniq_file);
  269. }
  270. llvm::FileRemover RemoveTmpFileOnFail(GeneratedUniqPath);
  271. raw_fd_ostream OS(TempFD, /*shouldClose=*/true);
  272. if (llvm::Error Err = Writer(OS)) {
  273. return Err;
  274. }
  275. OS.close();
  276. if (OS.has_error()) {
  277. OS.clear_error();
  278. return llvm::make_error<AtomicFileWriteError>(
  279. atomic_write_error::output_stream_error);
  280. }
  281. if (sys::fs::rename(/*from=*/GeneratedUniqPath, /*to=*/FinalPath)) {
  282. return llvm::make_error<AtomicFileWriteError>(
  283. atomic_write_error::failed_to_rename_temp_file);
  284. }
  285. RemoveTmpFileOnFail.releaseFile();
  286. return Error::success();
  287. }
  288. Expected<FilePermissionsApplier>
  289. FilePermissionsApplier::create(StringRef InputFilename) {
  290. sys::fs::file_status Status;
  291. if (InputFilename != "-") {
  292. if (auto EC = sys::fs::status(InputFilename, Status))
  293. return createFileError(InputFilename, EC);
  294. } else {
  295. Status.permissions(static_cast<sys::fs::perms>(0777));
  296. }
  297. return FilePermissionsApplier(InputFilename, Status);
  298. }
  299. Error FilePermissionsApplier::apply(
  300. StringRef OutputFilename, bool CopyDates,
  301. std::optional<sys::fs::perms> OverwritePermissions) {
  302. sys::fs::file_status Status = InputStatus;
  303. if (OverwritePermissions)
  304. Status.permissions(*OverwritePermissions);
  305. int FD = 0;
  306. // Writing to stdout should not be treated as an error here, just
  307. // do not set access/modification times or permissions.
  308. if (OutputFilename == "-")
  309. return Error::success();
  310. if (std::error_code EC = sys::fs::openFileForWrite(OutputFilename, FD,
  311. sys::fs::CD_OpenExisting))
  312. return createFileError(OutputFilename, EC);
  313. if (CopyDates)
  314. if (std::error_code EC = sys::fs::setLastAccessAndModificationTime(
  315. FD, Status.getLastAccessedTime(), Status.getLastModificationTime()))
  316. return createFileError(OutputFilename, EC);
  317. sys::fs::file_status OStat;
  318. if (std::error_code EC = sys::fs::status(FD, OStat))
  319. return createFileError(OutputFilename, EC);
  320. if (OStat.type() == sys::fs::file_type::regular_file) {
  321. #ifndef _WIN32
  322. // Keep ownership if llvm-objcopy is called under root.
  323. if (OutputFilename == InputFilename && OStat.getUser() == 0)
  324. sys::fs::changeFileOwnership(FD, Status.getUser(), Status.getGroup());
  325. #endif
  326. sys::fs::perms Perm = Status.permissions();
  327. if (OutputFilename != InputFilename)
  328. Perm = static_cast<sys::fs::perms>(Perm & ~sys::fs::getUmask() & ~06000);
  329. #ifdef _WIN32
  330. if (std::error_code EC = sys::fs::setPermissions(OutputFilename, Perm))
  331. #else
  332. if (std::error_code EC = sys::fs::setPermissions(FD, Perm))
  333. #endif
  334. return createFileError(OutputFilename, EC);
  335. }
  336. if (std::error_code EC = sys::Process::SafelyCloseFileDescriptor(FD))
  337. return createFileError(OutputFilename, EC);
  338. return Error::success();
  339. }
  340. char llvm::AtomicFileWriteError::ID;