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 27 bool IsFile(const std::string &Path) { 28 struct stat St; 29 if (stat(Path.c_str(), &St)) 30 return false; 31 return S_ISREG(St.st_mode); 32 } 33 34 bool IsDirectory(const std::string &Path) { 35 struct stat St; 36 if (stat(Path.c_str(), &St)) 37 return false; 38 return S_ISDIR(St.st_mode); 39 } 40 41 size_t FileSize(const std::string &Path) { 42 struct stat St; 43 if (stat(Path.c_str(), &St)) 44 return 0; 45 return St.st_size; 46 } 47 48 std::string Basename(const std::string &Path) { 49 size_t Pos = Path.rfind(GetSeparator()); 50 if (Pos == std::string::npos) return Path; 51 assert(Pos < Path.size()); 52 return Path.substr(Pos + 1); 53 } 54 55 void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, 56 Vector<std::string> *V, bool TopDir) { 57 auto E = GetEpoch(Dir); 58 if (Epoch) 59 if (E && *Epoch >= E) return; 60 61 DIR *D = opendir(Dir.c_str()); 62 if (!D) { 63 Printf("%s: %s; exiting\n", strerror(errno), Dir.c_str()); 64 exit(1); 65 } 66 while (auto E = readdir(D)) { 67 std::string Path = DirPlusFile(Dir, E->d_name); 68 if (E->d_type == DT_REG || E->d_type == DT_LNK || 69 (E->d_type == DT_UNKNOWN && IsFile(Path))) 70 V->push_back(Path); 71 else if ((E->d_type == DT_DIR || 72 (E->d_type == DT_UNKNOWN && IsDirectory(Path))) && 73 *E->d_name != '.') 74 ListFilesInDirRecursive(Path, Epoch, V, false); 75 } 76 closedir(D); 77 if (Epoch && TopDir) 78 *Epoch = E; 79 } 80 81 82 void IterateDirRecursive(const std::string &Dir, 83 void (*DirPreCallback)(const std::string &Dir), 84 void (*DirPostCallback)(const std::string &Dir), 85 void (*FileCallback)(const std::string &Dir)) { 86 DirPreCallback(Dir); 87 DIR *D = opendir(Dir.c_str()); 88 if (!D) return; 89 while (auto E = readdir(D)) { 90 std::string Path = DirPlusFile(Dir, E->d_name); 91 if (E->d_type == DT_REG || E->d_type == DT_LNK || 92 (E->d_type == DT_UNKNOWN && IsFile(Path))) 93 FileCallback(Path); 94 else if ((E->d_type == DT_DIR || 95 (E->d_type == DT_UNKNOWN && IsDirectory(Path))) && 96 *E->d_name != '.') 97 IterateDirRecursive(Path, DirPreCallback, DirPostCallback, FileCallback); 98 } 99 closedir(D); 100 DirPostCallback(Dir); 101 } 102 103 char GetSeparator() { 104 return '/'; 105 } 106 107 bool IsSeparator(char C) { 108 return C == '/'; 109 } 110 111 FILE* OpenFile(int Fd, const char* Mode) { 112 return fdopen(Fd, Mode); 113 } 114 115 int CloseFile(int fd) { 116 return close(fd); 117 } 118 119 int DuplicateFile(int Fd) { 120 return dup(Fd); 121 } 122 123 void RemoveFile(const std::string &Path) { 124 unlink(Path.c_str()); 125 } 126 127 void RenameFile(const std::string &OldPath, const std::string &NewPath) { 128 rename(OldPath.c_str(), NewPath.c_str()); 129 } 130 131 intptr_t GetHandleFromFd(int fd) { 132 return static_cast<intptr_t>(fd); 133 } 134 135 std::string DirName(const std::string &FileName) { 136 char *Tmp = new char[FileName.size() + 1]; 137 memcpy(Tmp, FileName.c_str(), FileName.size() + 1); 138 std::string Res = dirname(Tmp); 139 delete [] Tmp; 140 return Res; 141 } 142 143 std::string TmpDir() { 144 if (auto Env = getenv("TMPDIR")) 145 return Env; 146 return "/tmp"; 147 } 148 149 bool IsInterestingCoverageFile(const std::string &FileName) { 150 if (FileName.find("compiler-rt/lib/") != std::string::npos) 151 return false; // sanitizer internal. 152 if (FileName.find("/usr/lib/") != std::string::npos) 153 return false; 154 if (FileName.find("/usr/include/") != std::string::npos) 155 return false; 156 if (FileName == "<null>") 157 return false; 158 return true; 159 } 160 161 void RawPrint(const char *Str) { 162 (void)write(2, Str, strlen(Str)); 163 } 164 165 void MkDir(const std::string &Path) { 166 mkdir(Path.c_str(), 0700); 167 } 168 169 void RmDir(const std::string &Path) { 170 rmdir(Path.c_str()); 171 } 172 173 const std::string &getDevNull() { 174 static const std::string devNull = "/dev/null"; 175 return devNull; 176 } 177 178 } // namespace fuzzer 179 180 #endif // LIBFUZZER_POSIX 181