Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp
35262 views
1
//===- FuzzerIOWindows.cpp - IO utils for Windows. ------------------------===//
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 for Windows.
9
//===----------------------------------------------------------------------===//
10
#include "FuzzerPlatform.h"
11
#if LIBFUZZER_WINDOWS
12
13
#include "FuzzerExtFunctions.h"
14
#include "FuzzerIO.h"
15
#include <cstdarg>
16
#include <cstdio>
17
#include <fstream>
18
#include <io.h>
19
#include <iterator>
20
#include <sys/stat.h>
21
#include <sys/types.h>
22
#include <windows.h>
23
24
namespace fuzzer {
25
26
static bool IsFile(const std::string &Path, const DWORD &FileAttributes) {
27
28
if (FileAttributes & FILE_ATTRIBUTE_NORMAL)
29
return true;
30
31
if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
32
return false;
33
34
HANDLE FileHandle(
35
CreateFileA(Path.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
36
FILE_FLAG_BACKUP_SEMANTICS, 0));
37
38
if (FileHandle == INVALID_HANDLE_VALUE) {
39
Printf("CreateFileA() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
40
GetLastError());
41
return false;
42
}
43
44
DWORD FileType = GetFileType(FileHandle);
45
46
if (FileType == FILE_TYPE_UNKNOWN) {
47
Printf("GetFileType() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
48
GetLastError());
49
CloseHandle(FileHandle);
50
return false;
51
}
52
53
if (FileType != FILE_TYPE_DISK) {
54
CloseHandle(FileHandle);
55
return false;
56
}
57
58
CloseHandle(FileHandle);
59
return true;
60
}
61
62
bool IsFile(const std::string &Path) {
63
DWORD Att = GetFileAttributesA(Path.c_str());
64
65
if (Att == INVALID_FILE_ATTRIBUTES) {
66
Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n",
67
Path.c_str(), GetLastError());
68
return false;
69
}
70
71
return IsFile(Path, Att);
72
}
73
74
static bool IsDir(DWORD FileAttrs) {
75
if (FileAttrs == INVALID_FILE_ATTRIBUTES) return false;
76
return FileAttrs & FILE_ATTRIBUTE_DIRECTORY;
77
}
78
79
bool IsDirectory(const std::string &Path) {
80
DWORD Att = GetFileAttributesA(Path.c_str());
81
82
if (Att == INVALID_FILE_ATTRIBUTES) {
83
Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n",
84
Path.c_str(), GetLastError());
85
return false;
86
}
87
88
return IsDir(Att);
89
}
90
91
std::string Basename(const std::string &Path) {
92
size_t Pos = Path.find_last_of("/\\");
93
if (Pos == std::string::npos) return Path;
94
assert(Pos < Path.size());
95
return Path.substr(Pos + 1);
96
}
97
98
size_t FileSize(const std::string &Path) {
99
WIN32_FILE_ATTRIBUTE_DATA attr;
100
if (!GetFileAttributesExA(Path.c_str(), GetFileExInfoStandard, &attr)) {
101
DWORD LastError = GetLastError();
102
if (LastError != ERROR_FILE_NOT_FOUND)
103
Printf("GetFileAttributesExA() failed for \"%s\" (Error code: %lu).\n",
104
Path.c_str(), LastError);
105
return 0;
106
}
107
ULARGE_INTEGER size;
108
size.HighPart = attr.nFileSizeHigh;
109
size.LowPart = attr.nFileSizeLow;
110
return size.QuadPart;
111
}
112
113
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
114
std::vector<std::string> *V, bool TopDir) {
115
auto E = GetEpoch(Dir);
116
if (Epoch)
117
if (E && *Epoch >= E) return;
118
119
std::string Path(Dir);
120
assert(!Path.empty());
121
if (Path.back() != '\\')
122
Path.push_back('\\');
123
Path.push_back('*');
124
125
// Get the first directory entry.
126
WIN32_FIND_DATAA FindInfo;
127
HANDLE FindHandle(FindFirstFileA(Path.c_str(), &FindInfo));
128
if (FindHandle == INVALID_HANDLE_VALUE)
129
{
130
if (GetLastError() == ERROR_FILE_NOT_FOUND)
131
return;
132
Printf("No such file or directory: %s; exiting\n", Dir.c_str());
133
exit(1);
134
}
135
136
do {
137
std::string FileName = DirPlusFile(Dir, FindInfo.cFileName);
138
139
if (FindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
140
size_t FilenameLen = strlen(FindInfo.cFileName);
141
if ((FilenameLen == 1 && FindInfo.cFileName[0] == '.') ||
142
(FilenameLen == 2 && FindInfo.cFileName[0] == '.' &&
143
FindInfo.cFileName[1] == '.'))
144
continue;
145
146
ListFilesInDirRecursive(FileName, Epoch, V, false);
147
}
148
else if (IsFile(FileName, FindInfo.dwFileAttributes))
149
V->push_back(FileName);
150
} while (FindNextFileA(FindHandle, &FindInfo));
151
152
DWORD LastError = GetLastError();
153
if (LastError != ERROR_NO_MORE_FILES)
154
Printf("FindNextFileA failed (Error code: %lu).\n", LastError);
155
156
FindClose(FindHandle);
157
158
if (Epoch && TopDir)
159
*Epoch = E;
160
}
161
162
void IterateDirRecursive(const std::string &Dir,
163
void (*DirPreCallback)(const std::string &Dir),
164
void (*DirPostCallback)(const std::string &Dir),
165
void (*FileCallback)(const std::string &Dir)) {
166
// TODO(metzman): Implement ListFilesInDirRecursive via this function.
167
DirPreCallback(Dir);
168
169
DWORD DirAttrs = GetFileAttributesA(Dir.c_str());
170
if (!IsDir(DirAttrs)) return;
171
172
std::string TargetDir(Dir);
173
assert(!TargetDir.empty());
174
if (TargetDir.back() != '\\') TargetDir.push_back('\\');
175
TargetDir.push_back('*');
176
177
WIN32_FIND_DATAA FindInfo;
178
// Find the directory's first file.
179
HANDLE FindHandle = FindFirstFileA(TargetDir.c_str(), &FindInfo);
180
if (FindHandle == INVALID_HANDLE_VALUE) {
181
DWORD LastError = GetLastError();
182
if (LastError != ERROR_FILE_NOT_FOUND) {
183
// If the directory isn't empty, then something abnormal is going on.
184
Printf("FindFirstFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
185
LastError);
186
}
187
return;
188
}
189
190
do {
191
std::string Path = DirPlusFile(Dir, FindInfo.cFileName);
192
DWORD PathAttrs = FindInfo.dwFileAttributes;
193
if (IsDir(PathAttrs)) {
194
// Is Path the current directory (".") or the parent ("..")?
195
if (strcmp(FindInfo.cFileName, ".") == 0 ||
196
strcmp(FindInfo.cFileName, "..") == 0)
197
continue;
198
IterateDirRecursive(Path, DirPreCallback, DirPostCallback, FileCallback);
199
} else if (PathAttrs != INVALID_FILE_ATTRIBUTES) {
200
FileCallback(Path);
201
}
202
} while (FindNextFileA(FindHandle, &FindInfo));
203
204
DWORD LastError = GetLastError();
205
if (LastError != ERROR_NO_MORE_FILES)
206
Printf("FindNextFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
207
LastError);
208
209
FindClose(FindHandle);
210
DirPostCallback(Dir);
211
}
212
213
char GetSeparator() {
214
return '\\';
215
}
216
217
FILE* OpenFile(int Fd, const char* Mode) {
218
return _fdopen(Fd, Mode);
219
}
220
221
int CloseFile(int Fd) {
222
return _close(Fd);
223
}
224
225
int DuplicateFile(int Fd) {
226
return _dup(Fd);
227
}
228
229
void RemoveFile(const std::string &Path) {
230
_unlink(Path.c_str());
231
}
232
233
void RenameFile(const std::string &OldPath, const std::string &NewPath) {
234
rename(OldPath.c_str(), NewPath.c_str());
235
}
236
237
intptr_t GetHandleFromFd(int fd) {
238
return _get_osfhandle(fd);
239
}
240
241
bool IsSeparator(char C) {
242
return C == '\\' || C == '/';
243
}
244
245
// Parse disk designators, like "C:\". If Relative == true, also accepts: "C:".
246
// Returns number of characters considered if successful.
247
static size_t ParseDrive(const std::string &FileName, const size_t Offset,
248
bool Relative = true) {
249
if (Offset + 1 >= FileName.size() || FileName[Offset + 1] != ':')
250
return 0;
251
if (Offset + 2 >= FileName.size() || !IsSeparator(FileName[Offset + 2])) {
252
if (!Relative) // Accept relative path?
253
return 0;
254
else
255
return 2;
256
}
257
return 3;
258
}
259
260
// Parse a file name, like: SomeFile.txt
261
// Returns number of characters considered if successful.
262
static size_t ParseFileName(const std::string &FileName, const size_t Offset) {
263
size_t Pos = Offset;
264
const size_t End = FileName.size();
265
for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
266
;
267
return Pos - Offset;
268
}
269
270
// Parse a directory ending in separator, like: `SomeDir\`
271
// Returns number of characters considered if successful.
272
static size_t ParseDir(const std::string &FileName, const size_t Offset) {
273
size_t Pos = Offset;
274
const size_t End = FileName.size();
275
if (Pos >= End || IsSeparator(FileName[Pos]))
276
return 0;
277
for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
278
;
279
if (Pos >= End)
280
return 0;
281
++Pos; // Include separator.
282
return Pos - Offset;
283
}
284
285
// Parse a servername and share, like: `SomeServer\SomeShare\`
286
// Returns number of characters considered if successful.
287
static size_t ParseServerAndShare(const std::string &FileName,
288
const size_t Offset) {
289
size_t Pos = Offset, Res;
290
if (!(Res = ParseDir(FileName, Pos)))
291
return 0;
292
Pos += Res;
293
if (!(Res = ParseDir(FileName, Pos)))
294
return 0;
295
Pos += Res;
296
return Pos - Offset;
297
}
298
299
// Parse the given Ref string from the position Offset, to exactly match the
300
// given string Patt. Returns number of characters considered if successful.
301
static size_t ParseCustomString(const std::string &Ref, size_t Offset,
302
const char *Patt) {
303
size_t Len = strlen(Patt);
304
if (Offset + Len > Ref.size())
305
return 0;
306
return Ref.compare(Offset, Len, Patt) == 0 ? Len : 0;
307
}
308
309
// Parse a location, like:
310
// \\?\UNC\Server\Share\ \\?\C:\ \\Server\Share\ \ C:\ C:
311
// Returns number of characters considered if successful.
312
static size_t ParseLocation(const std::string &FileName) {
313
size_t Pos = 0, Res;
314
315
if ((Res = ParseCustomString(FileName, Pos, R"(\\?\)"))) {
316
Pos += Res;
317
if ((Res = ParseCustomString(FileName, Pos, R"(UNC\)"))) {
318
Pos += Res;
319
if ((Res = ParseServerAndShare(FileName, Pos)))
320
return Pos + Res;
321
return 0;
322
}
323
if ((Res = ParseDrive(FileName, Pos, false)))
324
return Pos + Res;
325
return 0;
326
}
327
328
if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
329
++Pos;
330
if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
331
++Pos;
332
if ((Res = ParseServerAndShare(FileName, Pos)))
333
return Pos + Res;
334
return 0;
335
}
336
return Pos;
337
}
338
339
if ((Res = ParseDrive(FileName, Pos)))
340
return Pos + Res;
341
342
return Pos;
343
}
344
345
std::string DirName(const std::string &FileName) {
346
size_t LocationLen = ParseLocation(FileName);
347
size_t DirLen = 0, Res;
348
while ((Res = ParseDir(FileName, LocationLen + DirLen)))
349
DirLen += Res;
350
size_t FileLen = ParseFileName(FileName, LocationLen + DirLen);
351
352
if (LocationLen + DirLen + FileLen != FileName.size()) {
353
Printf("DirName() failed for \"%s\", invalid path.\n", FileName.c_str());
354
exit(1);
355
}
356
357
if (DirLen) {
358
--DirLen; // Remove trailing separator.
359
if (!FileLen) { // Path ended in separator.
360
assert(DirLen);
361
// Remove file name from Dir.
362
while (DirLen && !IsSeparator(FileName[LocationLen + DirLen - 1]))
363
--DirLen;
364
if (DirLen) // Remove trailing separator.
365
--DirLen;
366
}
367
}
368
369
if (!LocationLen) { // Relative path.
370
if (!DirLen)
371
return ".";
372
return std::string(".\\").append(FileName, 0, DirLen);
373
}
374
375
return FileName.substr(0, LocationLen + DirLen);
376
}
377
378
std::string TmpDir() {
379
std::string Tmp;
380
Tmp.resize(MAX_PATH + 1);
381
DWORD Size = GetTempPathA(Tmp.size(), &Tmp[0]);
382
if (Size == 0) {
383
Printf("Couldn't get Tmp path.\n");
384
exit(1);
385
}
386
Tmp.resize(Size);
387
return Tmp;
388
}
389
390
bool IsInterestingCoverageFile(const std::string &FileName) {
391
if (FileName.find("Program Files") != std::string::npos)
392
return false;
393
if (FileName.find("compiler-rt\\lib\\") != std::string::npos)
394
return false; // sanitizer internal.
395
if (FileName == "<null>")
396
return false;
397
return true;
398
}
399
400
void RawPrint(const char *Str) {
401
_write(2, Str, strlen(Str));
402
}
403
404
void MkDir(const std::string &Path) {
405
if (CreateDirectoryA(Path.c_str(), nullptr)) return;
406
Printf("CreateDirectoryA failed for %s (Error code: %lu).\n", Path.c_str(),
407
GetLastError());
408
}
409
410
void RmDir(const std::string &Path) {
411
if (RemoveDirectoryA(Path.c_str())) return;
412
Printf("RemoveDirectoryA failed for %s (Error code: %lu).\n", Path.c_str(),
413
GetLastError());
414
}
415
416
const std::string &getDevNull() {
417
static const std::string devNull = "NUL";
418
return devNull;
419
}
420
421
} // namespace fuzzer
422
423
#endif // LIBFUZZER_WINDOWS
424
425