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 std::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 void IterateDirRecursive(const std::string &Dir, 82 void (*DirPreCallback)(const std::string &Dir), 83 void (*DirPostCallback)(const std::string &Dir), 84 void (*FileCallback)(const std::string &Dir)) { 85 DirPreCallback(Dir); 86 DIR *D = opendir(Dir.c_str()); 87 if (!D) return; 88 while (auto E = readdir(D)) { 89 std::string Path = DirPlusFile(Dir, E->d_name); 90 if (E->d_type == DT_REG || E->d_type == DT_LNK || 91 (E->d_type == DT_UNKNOWN && IsFile(Path))) 92 FileCallback(Path); 93 else if ((E->d_type == DT_DIR || 94 (E->d_type == DT_UNKNOWN && IsDirectory(Path))) && 95 *E->d_name != '.') 96 IterateDirRecursive(Path, DirPreCallback, DirPostCallback, FileCallback); 97 } 98 closedir(D); 99 DirPostCallback(Dir); 100 } 101 102 char GetSeparator() { 103 return '/'; 104 } 105 106 bool IsSeparator(char C) { 107 return C == '/'; 108 } 109 110 FILE* OpenFile(int Fd, const char* Mode) { 111 return fdopen(Fd, Mode); 112 } 113 114 int CloseFile(int fd) { 115 return close(fd); 116 } 117 118 int DuplicateFile(int Fd) { 119 return dup(Fd); 120 } 121 122 void RemoveFile(const std::string &Path) { 123 unlink(Path.c_str()); 124 } 125 126 void RenameFile(const std::string &OldPath, const std::string &NewPath) { 127 rename(OldPath.c_str(), NewPath.c_str()); 128 } 129 130 intptr_t GetHandleFromFd(int fd) { 131 return static_cast<intptr_t>(fd); 132 } 133 134 std::string DirName(const std::string &FileName) { 135 char *Tmp = new char[FileName.size() + 1]; 136 memcpy(Tmp, FileName.c_str(), FileName.size() + 1); 137 std::string Res = dirname(Tmp); 138 delete [] Tmp; 139 return Res; 140 } 141 142 std::string TmpDir() { 143 if (auto Env = getenv("TMPDIR")) 144 return Env; 145 return "/tmp"; 146 } 147 148 bool IsInterestingCoverageFile(const std::string &FileName) { 149 if (FileName.find("compiler-rt/lib/") != std::string::npos) 150 return false; // sanitizer internal. 151 if (FileName.find("/usr/lib/") != std::string::npos) 152 return false; 153 if (FileName.find("/usr/include/") != std::string::npos) 154 return false; 155 if (FileName == "<null>") 156 return false; 157 return true; 158 } 159 160 void RawPrint(const char *Str) { 161 (void)write(2, Str, strlen(Str)); 162 } 163 164 void MkDir(const std::string &Path) { 165 mkdir(Path.c_str(), 0700); 166 } 167 168 void RmDir(const std::string &Path) { 169 rmdir(Path.c_str()); 170 } 171 172 const std::string &getDevNull() { 173 static const std::string devNull = "/dev/null"; 174 return devNull; 175 } 176 177 } // namespace fuzzer 178 179 #endif // LIBFUZZER_POSIX 180