1 //===- FuzzerIOPosix.cpp - IO utils for Posix. ----------------------------===//
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 implementation using Posix API.
9 //===----------------------------------------------------------------------===//
10 #include "FuzzerPlatform.h"
11 #if LIBFUZZER_POSIX || LIBFUZZER_FUCHSIA
12 
13   #include "FuzzerExtFunctions.h"
14   #include "FuzzerIO.h"
15   #include <cstdarg>
16   #include <cstdio>
17   #include <dirent.h>
18   #include <fstream>
19   #include <iterator>
20   #include <libgen.h>
21   #include <sys/stat.h>
22   #include <sys/types.h>
23   #include <unistd.h>
24 
25 namespace fuzzer {
26 
IsFile(const std::string & Path)27 bool IsFile(const std::string &Path) {
28 
29   struct stat St;
30   if (stat(Path.c_str(), &St)) return false;
31   return S_ISREG(St.st_mode);
32 
33 }
34 
IsDirectory(const std::string & Path)35 bool IsDirectory(const std::string &Path) {
36 
37   struct stat St;
38   if (stat(Path.c_str(), &St)) return false;
39   return S_ISDIR(St.st_mode);
40 
41 }
42 
FileSize(const std::string & Path)43 size_t FileSize(const std::string &Path) {
44 
45   struct stat St;
46   if (stat(Path.c_str(), &St)) return 0;
47   return St.st_size;
48 
49 }
50 
Basename(const std::string & Path)51 std::string Basename(const std::string &Path) {
52 
53   size_t Pos = Path.rfind(GetSeparator());
54   if (Pos == std::string::npos) return Path;
55   assert(Pos < Path.size());
56   return Path.substr(Pos + 1);
57 
58 }
59 
ListFilesInDirRecursive(const std::string & Dir,long * Epoch,Vector<std::string> * V,bool TopDir)60 void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
61                              Vector<std::string> *V, bool TopDir) {
62 
63   auto E = GetEpoch(Dir);
64   if (Epoch)
65     if (E && *Epoch >= E) return;
66 
67   DIR *D = opendir(Dir.c_str());
68   if (!D) {
69 
70     Printf("%s: %s; exiting\n", strerror(errno), Dir.c_str());
71     exit(1);
72 
73   }
74 
75   while (auto E = readdir(D)) {
76 
77     std::string Path = DirPlusFile(Dir, E->d_name);
78     if (E->d_type == DT_REG || E->d_type == DT_LNK ||
79         (E->d_type == DT_UNKNOWN && IsFile(Path)))
80       V->push_back(Path);
81     else if ((E->d_type == DT_DIR ||
82               (E->d_type == DT_UNKNOWN && IsDirectory(Path))) &&
83              *E->d_name != '.')
84       ListFilesInDirRecursive(Path, Epoch, V, false);
85 
86   }
87 
88   closedir(D);
89   if (Epoch && TopDir) *Epoch = E;
90 
91 }
92 
IterateDirRecursive(const std::string & Dir,void (* DirPreCallback)(const std::string & Dir),void (* DirPostCallback)(const std::string & Dir),void (* FileCallback)(const std::string & Dir))93 void IterateDirRecursive(const std::string &Dir,
94                          void (*DirPreCallback)(const std::string &Dir),
95                          void (*DirPostCallback)(const std::string &Dir),
96                          void (*FileCallback)(const std::string &Dir)) {
97 
98   DirPreCallback(Dir);
99   DIR *D = opendir(Dir.c_str());
100   if (!D) return;
101   while (auto E = readdir(D)) {
102 
103     std::string Path = DirPlusFile(Dir, E->d_name);
104     if (E->d_type == DT_REG || E->d_type == DT_LNK ||
105         (E->d_type == DT_UNKNOWN && IsFile(Path)))
106       FileCallback(Path);
107     else if ((E->d_type == DT_DIR ||
108               (E->d_type == DT_UNKNOWN && IsDirectory(Path))) &&
109              *E->d_name != '.')
110       IterateDirRecursive(Path, DirPreCallback, DirPostCallback, FileCallback);
111 
112   }
113 
114   closedir(D);
115   DirPostCallback(Dir);
116 
117 }
118 
GetSeparator()119 char GetSeparator() {
120 
121   return '/';
122 
123 }
124 
IsSeparator(char C)125 bool IsSeparator(char C) {
126 
127   return C == '/';
128 
129 }
130 
OpenFile(int Fd,const char * Mode)131 FILE *OpenFile(int Fd, const char *Mode) {
132 
133   return fdopen(Fd, Mode);
134 
135 }
136 
CloseFile(int fd)137 int CloseFile(int fd) {
138 
139   return close(fd);
140 
141 }
142 
DuplicateFile(int Fd)143 int DuplicateFile(int Fd) {
144 
145   return dup(Fd);
146 
147 }
148 
RemoveFile(const std::string & Path)149 void RemoveFile(const std::string &Path) {
150 
151   unlink(Path.c_str());
152 
153 }
154 
RenameFile(const std::string & OldPath,const std::string & NewPath)155 void RenameFile(const std::string &OldPath, const std::string &NewPath) {
156 
157   rename(OldPath.c_str(), NewPath.c_str());
158 
159 }
160 
GetHandleFromFd(int fd)161 intptr_t GetHandleFromFd(int fd) {
162 
163   return static_cast<intptr_t>(fd);
164 
165 }
166 
DirName(const std::string & FileName)167 std::string DirName(const std::string &FileName) {
168 
169   char *Tmp = new char[FileName.size() + 1];
170   memcpy(Tmp, FileName.c_str(), FileName.size() + 1);
171   std::string Res = dirname(Tmp);
172   delete[] Tmp;
173   return Res;
174 
175 }
176 
TmpDir()177 std::string TmpDir() {
178 
179   if (auto Env = getenv("TMPDIR")) return Env;
180   return "/tmp";
181 
182 }
183 
IsInterestingCoverageFile(const std::string & FileName)184 bool IsInterestingCoverageFile(const std::string &FileName) {
185 
186   if (FileName.find("compiler-rt/lib/") != std::string::npos)
187     return false;  // sanitizer internal.
188   if (FileName.find("/usr/lib/") != std::string::npos) return false;
189   if (FileName.find("/usr/include/") != std::string::npos) return false;
190   if (FileName == "<null>") return false;
191   return true;
192 
193 }
194 
RawPrint(const char * Str)195 void RawPrint(const char *Str) {
196 
197   write(2, Str, strlen(Str));
198 
199 }
200 
MkDir(const std::string & Path)201 void MkDir(const std::string &Path) {
202 
203   mkdir(Path.c_str(), 0700);
204 
205 }
206 
RmDir(const std::string & Path)207 void RmDir(const std::string &Path) {
208 
209   rmdir(Path.c_str());
210 
211 }
212 
getDevNull()213 const std::string &getDevNull() {
214 
215   static const std::string devNull = "/dev/null";
216   return devNull;
217 
218 }
219 
220 }  // namespace fuzzer
221 
222 #endif  // LIBFUZZER_POSIX
223 
224