1 //===- FuzzerIO.cpp - IO utils. -------------------------------------------===//
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 // IO functions.
9 //===----------------------------------------------------------------------===//
10 
11 #include "FuzzerIO.h"
12 #include "FuzzerDefs.h"
13 #include "FuzzerExtFunctions.h"
14 #include <algorithm>
15 #include <cstdarg>
16 #include <fstream>
17 #include <iterator>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 
21 namespace fuzzer {
22 
23 static FILE *OutputFile = stderr;
24 
25 long GetEpoch(const std::string &Path) {
26   struct stat St;
27   if (stat(Path.c_str(), &St))
28     return 0;  // Can't stat, be conservative.
29   return St.st_mtime;
30 }
31 
32 Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
33   std::ifstream T(Path, std::ios::binary);
34   if (ExitOnError && !T) {
35     Printf("No such directory: %s; exiting\n", Path.c_str());
36     exit(1);
37   }
38 
39   T.seekg(0, T.end);
40   auto EndPos = T.tellg();
41   if (EndPos < 0) return {};
42   size_t FileLen = EndPos;
43   if (MaxSize)
44     FileLen = std::min(FileLen, MaxSize);
45 
46   T.seekg(0, T.beg);
47   Unit Res(FileLen);
48   T.read(reinterpret_cast<char *>(Res.data()), FileLen);
49   return Res;
50 }
51 
52 std::string FileToString(const std::string &Path) {
53   std::ifstream T(Path, std::ios::binary);
54   return std::string((std::istreambuf_iterator<char>(T)),
55                      std::istreambuf_iterator<char>());
56 }
57 
58 void CopyFileToErr(const std::string &Path) {
59   Printf("%s", FileToString(Path).c_str());
60 }
61 
62 void WriteToFile(const Unit &U, const std::string &Path) {
63   // Use raw C interface because this function may be called from a sig handler.
64   FILE *Out = fopen(Path.c_str(), "w");
65   if (!Out) return;
66   fwrite(U.data(), sizeof(U[0]), U.size(), Out);
67   fclose(Out);
68 }
69 
70 void ReadDirToVectorOfUnits(const char *Path, Vector<Unit> *V,
71                             long *Epoch, size_t MaxSize, bool ExitOnError) {
72   long E = Epoch ? *Epoch : 0;
73   Vector<std::string> Files;
74   ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
75   size_t NumLoaded = 0;
76   for (size_t i = 0; i < Files.size(); i++) {
77     auto &X = Files[i];
78     if (Epoch && GetEpoch(X) < E) continue;
79     NumLoaded++;
80     if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024)
81       Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path);
82     auto S = FileToVector(X, MaxSize, ExitOnError);
83     if (!S.empty())
84       V->push_back(S);
85   }
86 }
87 
88 
89 void GetSizedFilesFromDir(const std::string &Dir, Vector<SizedFile> *V) {
90   Vector<std::string> Files;
91   ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true);
92   for (auto &File : Files)
93     if (size_t Size = FileSize(File))
94       V->push_back({File, Size});
95 }
96 
97 std::string DirPlusFile(const std::string &DirPath,
98                         const std::string &FileName) {
99   return DirPath + GetSeparator() + FileName;
100 }
101 
102 void DupAndCloseStderr() {
103   int OutputFd = DuplicateFile(2);
104   if (OutputFd > 0) {
105     FILE *NewOutputFile = OpenFile(OutputFd, "w");
106     if (NewOutputFile) {
107       OutputFile = NewOutputFile;
108       if (EF->__sanitizer_set_report_fd)
109         EF->__sanitizer_set_report_fd(
110             reinterpret_cast<void *>(GetHandleFromFd(OutputFd)));
111       DiscardOutput(2);
112     }
113   }
114 }
115 
116 void CloseStdout() {
117   DiscardOutput(1);
118 }
119 
120 void Printf(const char *Fmt, ...) {
121   va_list ap;
122   va_start(ap, Fmt);
123   vfprintf(OutputFile, Fmt, ap);
124   va_end(ap);
125   fflush(OutputFile);
126 }
127 
128 }  // namespace fuzzer
129