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(file: Path.c_str(), buf: &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(file: Path.c_str(), buf: &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(file: Path.c_str(), buf: &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(c: GetSeparator()); |
50 | if (Pos == std::string::npos) return Path; |
51 | assert(Pos < Path.size()); |
52 | return Path.substr(pos: 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(Path: Dir); |
58 | if (Epoch) |
59 | if (E && *Epoch >= E) return; |
60 | |
61 | DIR *D = opendir(name: Dir.c_str()); |
62 | if (!D) { |
63 | Printf(Fmt: "%s: %s; exiting\n" , strerror(errno), Dir.c_str()); |
64 | exit(status: 1); |
65 | } |
66 | while (auto E = readdir(dirp: D)) { |
67 | std::string Path = DirPlusFile(DirPath: Dir, FileName: 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(x: Path); |
71 | else if ((E->d_type == DT_DIR || |
72 | (E->d_type == DT_UNKNOWN && IsDirectory(Path))) && |
73 | *E->d_name != '.') |
74 | ListFilesInDirRecursive(Dir: Path, Epoch, V, TopDir: false); |
75 | } |
76 | closedir(dirp: 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(name: Dir.c_str()); |
87 | if (!D) return; |
88 | while (auto E = readdir(dirp: D)) { |
89 | std::string Path = DirPlusFile(DirPath: Dir, FileName: 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(Dir: Path, DirPreCallback, DirPostCallback, FileCallback); |
97 | } |
98 | closedir(dirp: 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: Fd, modes: Mode); |
112 | } |
113 | |
114 | int CloseFile(int fd) { |
115 | return close(fd: fd); |
116 | } |
117 | |
118 | int DuplicateFile(int Fd) { |
119 | return dup(fd: Fd); |
120 | } |
121 | |
122 | void RemoveFile(const std::string &Path) { |
123 | unlink(name: Path.c_str()); |
124 | } |
125 | |
126 | void RenameFile(const std::string &OldPath, const std::string &NewPath) { |
127 | rename(old: OldPath.c_str(), new: 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(dest: Tmp, src: FileName.c_str(), n: FileName.size() + 1); |
137 | std::string Res = dirname(path: Tmp); |
138 | delete [] Tmp; |
139 | return Res; |
140 | } |
141 | |
142 | std::string TmpDir() { |
143 | if (auto Env = getenv(name: "TMPDIR" )) |
144 | return Env; |
145 | return "/tmp" ; |
146 | } |
147 | |
148 | bool IsInterestingCoverageFile(const std::string &FileName) { |
149 | if (FileName.find(s: "compiler-rt/lib/" ) != std::string::npos) |
150 | return false; // sanitizer internal. |
151 | if (FileName.find(s: "/usr/lib/" ) != std::string::npos) |
152 | return false; |
153 | if (FileName.find(s: "/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(fd: 2, buf: Str, n: strlen(s: Str)); |
162 | } |
163 | |
164 | void MkDir(const std::string &Path) { |
165 | mkdir(path: Path.c_str(), mode: 0700); |
166 | } |
167 | |
168 | void RmDir(const std::string &Path) { |
169 | rmdir(path: 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 | |