Home | History | Annotate | Line # | Download | only in fuzzer
      1  1.1  kamil //===- FuzzerIOWindows.cpp - IO utils for Windows. ------------------------===//
      2  1.1  kamil //
      3  1.1  kamil //                     The LLVM Compiler Infrastructure
      4  1.1  kamil //
      5  1.1  kamil // This file is distributed under the University of Illinois Open Source
      6  1.1  kamil // License. See LICENSE.TXT for details.
      7  1.1  kamil //
      8  1.1  kamil //===----------------------------------------------------------------------===//
      9  1.1  kamil // IO functions implementation for Windows.
     10  1.1  kamil //===----------------------------------------------------------------------===//
     11  1.1  kamil #include "FuzzerDefs.h"
     12  1.1  kamil #if LIBFUZZER_WINDOWS
     13  1.1  kamil 
     14  1.1  kamil #include "FuzzerExtFunctions.h"
     15  1.1  kamil #include "FuzzerIO.h"
     16  1.1  kamil #include <cstdarg>
     17  1.1  kamil #include <cstdio>
     18  1.1  kamil #include <fstream>
     19  1.1  kamil #include <io.h>
     20  1.1  kamil #include <iterator>
     21  1.1  kamil #include <sys/stat.h>
     22  1.1  kamil #include <sys/types.h>
     23  1.1  kamil #include <windows.h>
     24  1.1  kamil 
     25  1.1  kamil namespace fuzzer {
     26  1.1  kamil 
     27  1.1  kamil static bool IsFile(const std::string &Path, const DWORD &FileAttributes) {
     28  1.1  kamil 
     29  1.1  kamil   if (FileAttributes & FILE_ATTRIBUTE_NORMAL)
     30  1.1  kamil     return true;
     31  1.1  kamil 
     32  1.1  kamil   if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
     33  1.1  kamil     return false;
     34  1.1  kamil 
     35  1.1  kamil   HANDLE FileHandle(
     36  1.1  kamil       CreateFileA(Path.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
     37  1.1  kamil                   FILE_FLAG_BACKUP_SEMANTICS, 0));
     38  1.1  kamil 
     39  1.1  kamil   if (FileHandle == INVALID_HANDLE_VALUE) {
     40  1.1  kamil     Printf("CreateFileA() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
     41  1.1  kamil         GetLastError());
     42  1.1  kamil     return false;
     43  1.1  kamil   }
     44  1.1  kamil 
     45  1.1  kamil   DWORD FileType = GetFileType(FileHandle);
     46  1.1  kamil 
     47  1.1  kamil   if (FileType == FILE_TYPE_UNKNOWN) {
     48  1.1  kamil     Printf("GetFileType() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
     49  1.1  kamil         GetLastError());
     50  1.1  kamil     CloseHandle(FileHandle);
     51  1.1  kamil     return false;
     52  1.1  kamil   }
     53  1.1  kamil 
     54  1.1  kamil   if (FileType != FILE_TYPE_DISK) {
     55  1.1  kamil     CloseHandle(FileHandle);
     56  1.1  kamil     return false;
     57  1.1  kamil   }
     58  1.1  kamil 
     59  1.1  kamil   CloseHandle(FileHandle);
     60  1.1  kamil   return true;
     61  1.1  kamil }
     62  1.1  kamil 
     63  1.1  kamil bool IsFile(const std::string &Path) {
     64  1.1  kamil   DWORD Att = GetFileAttributesA(Path.c_str());
     65  1.1  kamil 
     66  1.1  kamil   if (Att == INVALID_FILE_ATTRIBUTES) {
     67  1.1  kamil     Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n",
     68  1.1  kamil         Path.c_str(), GetLastError());
     69  1.1  kamil     return false;
     70  1.1  kamil   }
     71  1.1  kamil 
     72  1.1  kamil   return IsFile(Path, Att);
     73  1.1  kamil }
     74  1.1  kamil 
     75  1.1  kamil std::string Basename(const std::string &Path) {
     76  1.1  kamil   size_t Pos = Path.find_last_of("/\\");
     77  1.1  kamil   if (Pos == std::string::npos) return Path;
     78  1.1  kamil   assert(Pos < Path.size());
     79  1.1  kamil   return Path.substr(Pos + 1);
     80  1.1  kamil }
     81  1.1  kamil 
     82  1.1  kamil size_t FileSize(const std::string &Path) {
     83  1.1  kamil   WIN32_FILE_ATTRIBUTE_DATA attr;
     84  1.1  kamil   if (!GetFileAttributesExA(Path.c_str(), GetFileExInfoStandard, &attr)) {
     85  1.1  kamil     Printf("GetFileAttributesExA() failed for \"%s\" (Error code: %lu).\n",
     86  1.1  kamil            Path.c_str(), GetLastError());
     87  1.1  kamil     return 0;
     88  1.1  kamil   }
     89  1.1  kamil   ULARGE_INTEGER size;
     90  1.1  kamil   size.HighPart = attr.nFileSizeHigh;
     91  1.1  kamil   size.LowPart = attr.nFileSizeLow;
     92  1.1  kamil   return size.QuadPart;
     93  1.1  kamil }
     94  1.1  kamil 
     95  1.1  kamil void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
     96  1.1  kamil                              Vector<std::string> *V, bool TopDir) {
     97  1.1  kamil   auto E = GetEpoch(Dir);
     98  1.1  kamil   if (Epoch)
     99  1.1  kamil     if (E && *Epoch >= E) return;
    100  1.1  kamil 
    101  1.1  kamil   std::string Path(Dir);
    102  1.1  kamil   assert(!Path.empty());
    103  1.1  kamil   if (Path.back() != '\\')
    104  1.1  kamil       Path.push_back('\\');
    105  1.1  kamil   Path.push_back('*');
    106  1.1  kamil 
    107  1.1  kamil   // Get the first directory entry.
    108  1.1  kamil   WIN32_FIND_DATAA FindInfo;
    109  1.1  kamil   HANDLE FindHandle(FindFirstFileA(Path.c_str(), &FindInfo));
    110  1.1  kamil   if (FindHandle == INVALID_HANDLE_VALUE)
    111  1.1  kamil   {
    112  1.1  kamil     if (GetLastError() == ERROR_FILE_NOT_FOUND)
    113  1.1  kamil       return;
    114  1.1  kamil     Printf("No such file or directory: %s; exiting\n", Dir.c_str());
    115  1.1  kamil     exit(1);
    116  1.1  kamil   }
    117  1.1  kamil 
    118  1.1  kamil   do {
    119  1.1  kamil     std::string FileName = DirPlusFile(Dir, FindInfo.cFileName);
    120  1.1  kamil 
    121  1.1  kamil     if (FindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
    122  1.1  kamil       size_t FilenameLen = strlen(FindInfo.cFileName);
    123  1.1  kamil       if ((FilenameLen == 1 && FindInfo.cFileName[0] == '.') ||
    124  1.1  kamil           (FilenameLen == 2 && FindInfo.cFileName[0] == '.' &&
    125  1.1  kamil                                FindInfo.cFileName[1] == '.'))
    126  1.1  kamil         continue;
    127  1.1  kamil 
    128  1.1  kamil       ListFilesInDirRecursive(FileName, Epoch, V, false);
    129  1.1  kamil     }
    130  1.1  kamil     else if (IsFile(FileName, FindInfo.dwFileAttributes))
    131  1.1  kamil       V->push_back(FileName);
    132  1.1  kamil   } while (FindNextFileA(FindHandle, &FindInfo));
    133  1.1  kamil 
    134  1.1  kamil   DWORD LastError = GetLastError();
    135  1.1  kamil   if (LastError != ERROR_NO_MORE_FILES)
    136  1.1  kamil     Printf("FindNextFileA failed (Error code: %lu).\n", LastError);
    137  1.1  kamil 
    138  1.1  kamil   FindClose(FindHandle);
    139  1.1  kamil 
    140  1.1  kamil   if (Epoch && TopDir)
    141  1.1  kamil     *Epoch = E;
    142  1.1  kamil }
    143  1.1  kamil 
    144  1.1  kamil char GetSeparator() {
    145  1.1  kamil   return '\\';
    146  1.1  kamil }
    147  1.1  kamil 
    148  1.1  kamil FILE* OpenFile(int Fd, const char* Mode) {
    149  1.1  kamil   return _fdopen(Fd, Mode);
    150  1.1  kamil }
    151  1.1  kamil 
    152  1.1  kamil int CloseFile(int Fd) {
    153  1.1  kamil   return _close(Fd);
    154  1.1  kamil }
    155  1.1  kamil 
    156  1.1  kamil int DuplicateFile(int Fd) {
    157  1.1  kamil   return _dup(Fd);
    158  1.1  kamil }
    159  1.1  kamil 
    160  1.1  kamil void RemoveFile(const std::string &Path) {
    161  1.1  kamil   _unlink(Path.c_str());
    162  1.1  kamil }
    163  1.1  kamil 
    164  1.1  kamil void DiscardOutput(int Fd) {
    165  1.1  kamil   FILE* Temp = fopen("nul", "w");
    166  1.1  kamil   if (!Temp)
    167  1.1  kamil     return;
    168  1.1  kamil   _dup2(_fileno(Temp), Fd);
    169  1.1  kamil   fclose(Temp);
    170  1.1  kamil }
    171  1.1  kamil 
    172  1.1  kamil intptr_t GetHandleFromFd(int fd) {
    173  1.1  kamil   return _get_osfhandle(fd);
    174  1.1  kamil }
    175  1.1  kamil 
    176  1.1  kamil static bool IsSeparator(char C) {
    177  1.1  kamil   return C == '\\' || C == '/';
    178  1.1  kamil }
    179  1.1  kamil 
    180  1.1  kamil // Parse disk designators, like "C:\". If Relative == true, also accepts: "C:".
    181  1.1  kamil // Returns number of characters considered if successful.
    182  1.1  kamil static size_t ParseDrive(const std::string &FileName, const size_t Offset,
    183  1.1  kamil                          bool Relative = true) {
    184  1.1  kamil   if (Offset + 1 >= FileName.size() || FileName[Offset + 1] != ':')
    185  1.1  kamil     return 0;
    186  1.1  kamil   if (Offset + 2 >= FileName.size() || !IsSeparator(FileName[Offset + 2])) {
    187  1.1  kamil     if (!Relative) // Accept relative path?
    188  1.1  kamil       return 0;
    189  1.1  kamil     else
    190  1.1  kamil       return 2;
    191  1.1  kamil   }
    192  1.1  kamil   return 3;
    193  1.1  kamil }
    194  1.1  kamil 
    195  1.1  kamil // Parse a file name, like: SomeFile.txt
    196  1.1  kamil // Returns number of characters considered if successful.
    197  1.1  kamil static size_t ParseFileName(const std::string &FileName, const size_t Offset) {
    198  1.1  kamil   size_t Pos = Offset;
    199  1.1  kamil   const size_t End = FileName.size();
    200  1.1  kamil   for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
    201  1.1  kamil     ;
    202  1.1  kamil   return Pos - Offset;
    203  1.1  kamil }
    204  1.1  kamil 
    205  1.1  kamil // Parse a directory ending in separator, like: `SomeDir\`
    206  1.1  kamil // Returns number of characters considered if successful.
    207  1.1  kamil static size_t ParseDir(const std::string &FileName, const size_t Offset) {
    208  1.1  kamil   size_t Pos = Offset;
    209  1.1  kamil   const size_t End = FileName.size();
    210  1.1  kamil   if (Pos >= End || IsSeparator(FileName[Pos]))
    211  1.1  kamil     return 0;
    212  1.1  kamil   for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
    213  1.1  kamil     ;
    214  1.1  kamil   if (Pos >= End)
    215  1.1  kamil     return 0;
    216  1.1  kamil   ++Pos; // Include separator.
    217  1.1  kamil   return Pos - Offset;
    218  1.1  kamil }
    219  1.1  kamil 
    220  1.1  kamil // Parse a servername and share, like: `SomeServer\SomeShare\`
    221  1.1  kamil // Returns number of characters considered if successful.
    222  1.1  kamil static size_t ParseServerAndShare(const std::string &FileName,
    223  1.1  kamil                                   const size_t Offset) {
    224  1.1  kamil   size_t Pos = Offset, Res;
    225  1.1  kamil   if (!(Res = ParseDir(FileName, Pos)))
    226  1.1  kamil     return 0;
    227  1.1  kamil   Pos += Res;
    228  1.1  kamil   if (!(Res = ParseDir(FileName, Pos)))
    229  1.1  kamil     return 0;
    230  1.1  kamil   Pos += Res;
    231  1.1  kamil   return Pos - Offset;
    232  1.1  kamil }
    233  1.1  kamil 
    234  1.1  kamil // Parse the given Ref string from the position Offset, to exactly match the given
    235  1.1  kamil // string Patt.
    236  1.1  kamil // Returns number of characters considered if successful.
    237  1.1  kamil static size_t ParseCustomString(const std::string &Ref, size_t Offset,
    238  1.1  kamil                                 const char *Patt) {
    239  1.1  kamil   size_t Len = strlen(Patt);
    240  1.1  kamil   if (Offset + Len > Ref.size())
    241  1.1  kamil     return 0;
    242  1.1  kamil   return Ref.compare(Offset, Len, Patt) == 0 ? Len : 0;
    243  1.1  kamil }
    244  1.1  kamil 
    245  1.1  kamil // Parse a location, like:
    246  1.1  kamil // \\?\UNC\Server\Share\  \\?\C:\  \\Server\Share\  \  C:\  C:
    247  1.1  kamil // Returns number of characters considered if successful.
    248  1.1  kamil static size_t ParseLocation(const std::string &FileName) {
    249  1.1  kamil   size_t Pos = 0, Res;
    250  1.1  kamil 
    251  1.1  kamil   if ((Res = ParseCustomString(FileName, Pos, R"(\\?\)"))) {
    252  1.1  kamil     Pos += Res;
    253  1.1  kamil     if ((Res = ParseCustomString(FileName, Pos, R"(UNC\)"))) {
    254  1.1  kamil       Pos += Res;
    255  1.1  kamil       if ((Res = ParseServerAndShare(FileName, Pos)))
    256  1.1  kamil         return Pos + Res;
    257  1.1  kamil       return 0;
    258  1.1  kamil     }
    259  1.1  kamil     if ((Res = ParseDrive(FileName, Pos, false)))
    260  1.1  kamil       return Pos + Res;
    261  1.1  kamil     return 0;
    262  1.1  kamil   }
    263  1.1  kamil 
    264  1.1  kamil   if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
    265  1.1  kamil     ++Pos;
    266  1.1  kamil     if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
    267  1.1  kamil       ++Pos;
    268  1.1  kamil       if ((Res = ParseServerAndShare(FileName, Pos)))
    269  1.1  kamil         return Pos + Res;
    270  1.1  kamil       return 0;
    271  1.1  kamil     }
    272  1.1  kamil     return Pos;
    273  1.1  kamil   }
    274  1.1  kamil 
    275  1.1  kamil   if ((Res = ParseDrive(FileName, Pos)))
    276  1.1  kamil     return Pos + Res;
    277  1.1  kamil 
    278  1.1  kamil   return Pos;
    279  1.1  kamil }
    280  1.1  kamil 
    281  1.1  kamil std::string DirName(const std::string &FileName) {
    282  1.1  kamil   size_t LocationLen = ParseLocation(FileName);
    283  1.1  kamil   size_t DirLen = 0, Res;
    284  1.1  kamil   while ((Res = ParseDir(FileName, LocationLen + DirLen)))
    285  1.1  kamil     DirLen += Res;
    286  1.1  kamil   size_t FileLen = ParseFileName(FileName, LocationLen + DirLen);
    287  1.1  kamil 
    288  1.1  kamil   if (LocationLen + DirLen + FileLen != FileName.size()) {
    289  1.1  kamil     Printf("DirName() failed for \"%s\", invalid path.\n", FileName.c_str());
    290  1.1  kamil     exit(1);
    291  1.1  kamil   }
    292  1.1  kamil 
    293  1.1  kamil   if (DirLen) {
    294  1.1  kamil     --DirLen; // Remove trailing separator.
    295  1.1  kamil     if (!FileLen) { // Path ended in separator.
    296  1.1  kamil       assert(DirLen);
    297  1.1  kamil       // Remove file name from Dir.
    298  1.1  kamil       while (DirLen && !IsSeparator(FileName[LocationLen + DirLen - 1]))
    299  1.1  kamil         --DirLen;
    300  1.1  kamil       if (DirLen) // Remove trailing separator.
    301  1.1  kamil         --DirLen;
    302  1.1  kamil     }
    303  1.1  kamil   }
    304  1.1  kamil 
    305  1.1  kamil   if (!LocationLen) { // Relative path.
    306  1.1  kamil     if (!DirLen)
    307  1.1  kamil       return ".";
    308  1.1  kamil     return std::string(".\\").append(FileName, 0, DirLen);
    309  1.1  kamil   }
    310  1.1  kamil 
    311  1.1  kamil   return FileName.substr(0, LocationLen + DirLen);
    312  1.1  kamil }
    313  1.1  kamil 
    314  1.1  kamil std::string TmpDir() {
    315  1.1  kamil   std::string Tmp;
    316  1.1  kamil   Tmp.resize(MAX_PATH + 1);
    317  1.1  kamil   DWORD Size = GetTempPathA(Tmp.size(), &Tmp[0]);
    318  1.1  kamil   if (Size == 0) {
    319  1.1  kamil     Printf("Couldn't get Tmp path.\n");
    320  1.1  kamil     exit(1);
    321  1.1  kamil   }
    322  1.1  kamil   Tmp.resize(Size);
    323  1.1  kamil   return Tmp;
    324  1.1  kamil }
    325  1.1  kamil 
    326  1.1  kamil bool IsInterestingCoverageFile(const std::string &FileName) {
    327  1.1  kamil   if (FileName.find("Program Files") != std::string::npos)
    328  1.1  kamil     return false;
    329  1.1  kamil   if (FileName.find("compiler-rt\\lib\\") != std::string::npos)
    330  1.1  kamil     return false; // sanitizer internal.
    331  1.1  kamil   if (FileName == "<null>")
    332  1.1  kamil     return false;
    333  1.1  kamil   return true;
    334  1.1  kamil }
    335  1.1  kamil 
    336  1.1  kamil void RawPrint(const char *Str) {
    337  1.1  kamil   // Not tested, may or may not work. Fix if needed.
    338  1.1  kamil   Printf("%s", Str);
    339  1.1  kamil }
    340  1.1  kamil 
    341  1.1  kamil }  // namespace fuzzer
    342  1.1  kamil 
    343  1.1  kamil #endif // LIBFUZZER_WINDOWS
    344