Global Metrics

path: .metrics.nexits.sum
old: 12.0
new: 57.0

path: .metrics.nexits.average
old: 1.0
new: 2.0357142857142856

path: .metrics.cyclomatic.average
old: 1.0666666666666669
new: 3.6333333333333337

path: .metrics.cyclomatic.sum
old: 16.0
new: 109.0

path: .metrics.cognitive.sum
old: 1.0
new: 101.0

path: .metrics.cognitive.average
old: 0.08333333333333333
new: 3.607142857142857

path: .metrics.mi.mi_sei
old: 39.02046083841565
new: -43.414715661562255

path: .metrics.mi.mi_original
old: 55.37400774766395
new: -1.0070750520263942

path: .metrics.mi.mi_visual_studio
old: 32.382460671148515
new: 0.0

path: .metrics.nom.total
old: 12.0
new: 28.0

path: .metrics.nom.functions
old: 12.0
new: 28.0

path: .metrics.nargs.average
old: 0.0
new: 1.3928571428571428

path: .metrics.nargs.sum
old: 0.0
new: 39.0

path: .metrics.halstead.effort
old: 24296.07546156776
new: 901018.9424597644

path: .metrics.halstead.level
old: 0.07258064516129031
new: 0.014705882352941176

path: .metrics.halstead.n2
old: 72.0
new: 170.0

path: .metrics.halstead.vocabulary
old: 88.0
new: 204.0

path: .metrics.halstead.N2
old: 124.0
new: 680.0

path: .metrics.halstead.bugs
old: 0.27962081496386565
new: 3.1095773163343776

path: .metrics.halstead.length
old: 273.0
new: 1727.0

path: .metrics.halstead.volume
old: 1763.4248318879822
new: 13250.278565584773

path: .metrics.halstead.estimated_program_length
old: 508.2346001038465
new: 1432.5701957459207

path: .metrics.halstead.N1
old: 149.0
new: 1047.0

path: .metrics.halstead.time
old: 1349.7819700870978
new: 50056.60791443136

path: .metrics.halstead.n1
old: 16.0
new: 34.0

path: .metrics.halstead.difficulty
old: 13.77777777777778
new: 68.0

path: .metrics.halstead.purity_ratio
old: 1.8616652018455917
new: 0.8295137207561788

path: .metrics.loc.cloc
old: 20.0
new: 38.0

path: .metrics.loc.sloc
old: 91.0
new: 413.0

path: .metrics.loc.lloc
old: 12.0
new: 174.0

path: .metrics.loc.ploc
old: 55.0
new: 319.0

path: .metrics.loc.blank
old: 16.0
new: 56.0

Spaces Data

Minimal test - lines (206, 208)

path: .spaces[0].spaces[8].metrics.halstead.N1
old: 5.0
new: 11.0

path: .spaces[0].spaces[8].metrics.halstead.N2
old: 3.0
new: 7.0

path: .spaces[0].spaces[8].metrics.halstead.length
old: 8.0
new: 18.0

path: .spaces[0].spaces[8].metrics.halstead.n2
old: 3.0
new: 5.0

path: .spaces[0].spaces[8].metrics.halstead.level
old: 0.4
new: 0.2040816326530612

path: .spaces[0].spaces[8].metrics.halstead.vocabulary
old: 8.0
new: 12.0

path: .spaces[0].spaces[8].metrics.halstead.estimated_program_length
old: 16.36452797660028
new: 31.26112492884004

path: .spaces[0].spaces[8].metrics.halstead.effort
old: 60.0
new: 316.19369256360596

path: .spaces[0].spaces[8].metrics.halstead.time
old: 3.3333333333333335
new: 17.566316253533664

path: .spaces[0].spaces[8].metrics.halstead.volume
old: 24.0
new: 64.5293250129808

path: .spaces[0].spaces[8].metrics.halstead.bugs
old: 0.005108729549290353
new: 0.015470851358978374

path: .spaces[0].spaces[8].metrics.halstead.purity_ratio
old: 2.045565997075035
new: 1.7367291627133357

path: .spaces[0].spaces[8].metrics.halstead.difficulty
old: 2.5
new: 4.9

path: .spaces[0].spaces[8].metrics.halstead.n1
old: 5.0
new: 7.0

path: .spaces[0].spaces[8].metrics.mi.mi_original
old: 154.24412008219068
new: 131.30345810999222

path: .spaces[0].spaces[8].metrics.mi.mi_sei
old: 146.92819499625
new: 113.83181573424925

path: .spaces[0].spaces[8].metrics.mi.mi_visual_studio
old: 90.2012398141466
new: 76.78564801753932

path: .spaces[0].spaces[8].metrics.loc.sloc
old: 1.0
new: 3.0

path: .spaces[0].spaces[8].metrics.loc.ploc
old: 1.0
new: 3.0

Code

FILE* OpenFile(int Fd, const char* Mode) {
  return _fdopen(Fd, Mode);
}

Minimal test - lines (151, 200)

path: .spaces[0].spaces[6].metrics.cognitive.average
old: 0.0
new: 14.0

path: .spaces[0].spaces[6].metrics.cognitive.sum
old: 0.0
new: 14.0

path: .spaces[0].spaces[6].metrics.loc.ploc
old: 1.0
new: 40.0

path: .spaces[0].spaces[6].metrics.loc.lloc
old: 1.0
new: 21.0

path: .spaces[0].spaces[6].metrics.loc.blank
old: 0.0
new: 6.0

path: .spaces[0].spaces[6].metrics.loc.cloc
old: 0.0
new: 4.0

path: .spaces[0].spaces[6].metrics.loc.sloc
old: 1.0
new: 50.0

path: .spaces[0].spaces[6].metrics.mi.mi_visual_studio
old: 90.80912574437468
new: 39.3046583652914

path: .spaces[0].spaces[6].metrics.mi.mi_sei
old: 148.4278547652622
new: 43.59861067684025

path: .spaces[0].spaces[6].metrics.mi.mi_original
old: 155.2836050228807
new: 67.2109658046483

path: .spaces[0].spaces[6].metrics.nargs.average
old: 0.0
new: 4.0

path: .spaces[0].spaces[6].metrics.nargs.sum
old: 0.0
new: 4.0

path: .spaces[0].spaces[6].metrics.nexits.sum
old: 1.0
new: 2.0

path: .spaces[0].spaces[6].metrics.nexits.average
old: 1.0
new: 2.0

path: .spaces[0].spaces[6].metrics.cyclomatic.sum
old: 1.0
new: 11.0

path: .spaces[0].spaces[6].metrics.cyclomatic.average
old: 1.0
new: 11.0

path: .spaces[0].spaces[6].metrics.halstead.N1
old: 4.0
new: 152.0

path: .spaces[0].spaces[6].metrics.halstead.estimated_program_length
old: 12.754887502163468
new: 292.5692484333749

path: .spaces[0].spaces[6].metrics.halstead.purity_ratio
old: 1.8221267860233523
new: 1.179714711424899

path: .spaces[0].spaces[6].metrics.halstead.length
old: 7.0
new: 248.0

path: .spaces[0].spaces[6].metrics.halstead.level
old: 0.5
new: 0.040624999999999994

path: .spaces[0].spaces[6].metrics.halstead.N2
old: 3.0
new: 96.0

path: .spaces[0].spaces[6].metrics.halstead.effort
old: 39.302968908806456
new: 35911.27326133506

path: .spaces[0].spaces[6].metrics.halstead.time
old: 2.1834982727114696
new: 1995.0707367408368

path: .spaces[0].spaces[6].metrics.halstead.n2
old: 3.0
new: 39.0

path: .spaces[0].spaces[6].metrics.halstead.difficulty
old: 2.0
new: 24.615384615384617

path: .spaces[0].spaces[6].metrics.halstead.bugs
old: 0.0038532659414573967
new: 0.3628267352915559

path: .spaces[0].spaces[6].metrics.halstead.volume
old: 19.651484454403228
new: 1458.8954762417368

path: .spaces[0].spaces[6].metrics.halstead.vocabulary
old: 7.0
new: 59.0

path: .spaces[0].spaces[6].metrics.halstead.n1
old: 4.0
new: 20.0

Code

void IterateDirRecursive(const std::string &Dir,
                         void (*DirPreCallback)(const std::string &Dir),
                         void (*DirPostCallback)(const std::string &Dir),
                         void (*FileCallback)(const std::string &Dir)) {
  // TODO(metzman): Implement ListFilesInDirRecursive via this function.
  DirPreCallback(Dir);

  DWORD DirAttrs = GetFileAttributesA(Dir.c_str());
  if (!IsDir(DirAttrs)) return;

  std::string TargetDir(Dir);
  assert(!TargetDir.empty());
  if (TargetDir.back() != '\\') TargetDir.push_back('\\');
  TargetDir.push_back('*');

  WIN32_FIND_DATAA FindInfo;
  // Find the directory's first file.
  HANDLE FindHandle = FindFirstFileA(TargetDir.c_str(), &FindInfo);
  if (FindHandle == INVALID_HANDLE_VALUE) {
    DWORD LastError = GetLastError();
    if (LastError != ERROR_FILE_NOT_FOUND) {
      // If the directory isn't empty, then something abnormal is going on.
      Printf("FindFirstFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
             LastError);
    }
    return;
  }

  do {
    std::string Path = DirPlusFile(Dir, FindInfo.cFileName);
    DWORD PathAttrs = FindInfo.dwFileAttributes;
    if (IsDir(PathAttrs)) {
      // Is Path the current directory (".") or the parent ("..")?
      if (strcmp(FindInfo.cFileName, ".") == 0 ||
          strcmp(FindInfo.cFileName, "..") == 0)
        continue;
      IterateDirRecursive(Path, DirPreCallback, DirPostCallback, FileCallback);
    } else if (PathAttrs != INVALID_FILE_ATTRIBUTES) {
      FileCallback(Path);
    }
  } while (FindNextFileA(FindHandle, &FindInfo));

  DWORD LastError = GetLastError();
  if (LastError != ERROR_NO_MORE_FILES)
    Printf("FindNextFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
           LastError);

  FindClose(FindHandle);
  DirPostCallback(Dir);
}

Minimal test - lines (79, 84)

path: .spaces[0].spaces[3].metrics.nargs.sum
old: 0.0
new: 1.0

path: .spaces[0].spaces[3].metrics.nargs.average
old: 0.0
new: 1.0

path: .spaces[0].spaces[3].metrics.cognitive.sum
old: 0.0
new: 1.0

path: .spaces[0].spaces[3].metrics.cognitive.average
old: 0.0
new: 1.0

path: .spaces[0].spaces[3].metrics.halstead.level
old: 0.4
new: 0.08906882591093118

path: .spaces[0].spaces[3].metrics.halstead.volume
old: 28.52932501298081
new: 210.90827503317317

path: .spaces[0].spaces[3].metrics.halstead.length
old: 9.0
new: 46.0

path: .spaces[0].spaces[3].metrics.halstead.bugs
old: 0.005732795045386515
new: 0.05921849147793715

path: .spaces[0].spaces[3].metrics.halstead.N1
old: 5.0
new: 27.0

path: .spaces[0].spaces[3].metrics.halstead.estimated_program_length
old: 19.60964047443681
new: 86.15946414084446

path: .spaces[0].spaces[3].metrics.halstead.effort
old: 71.32331253245202
new: 2367.92472423608

path: .spaces[0].spaces[3].metrics.halstead.purity_ratio
old: 2.1788489416040897
new: 1.8730318291487928

path: .spaces[0].spaces[3].metrics.halstead.time
old: 3.96240625180289
new: 131.55137356867112

path: .spaces[0].spaces[3].metrics.halstead.N2
old: 4.0
new: 19.0

path: .spaces[0].spaces[3].metrics.halstead.difficulty
old: 2.5
new: 11.227272727272728

path: .spaces[0].spaces[3].metrics.halstead.n2
old: 4.0
new: 11.0

path: .spaces[0].spaces[3].metrics.halstead.n1
old: 5.0
new: 13.0

path: .spaces[0].spaces[3].metrics.halstead.vocabulary
old: 9.0
new: 24.0

path: .spaces[0].spaces[3].metrics.mi.mi_original
old: 153.34515096830847
new: 113.68609531642348

path: .spaces[0].spaces[3].metrics.mi.mi_visual_studio
old: 89.67552688205174
new: 66.48309667627105

path: .spaces[0].spaces[3].metrics.mi.mi_sei
old: 145.63125671373976
new: 88.51715365783039

path: .spaces[0].spaces[3].metrics.cyclomatic.average
old: 1.0
new: 2.0

path: .spaces[0].spaces[3].metrics.cyclomatic.sum
old: 1.0
new: 2.0

path: .spaces[0].spaces[3].metrics.nexits.average
old: 1.0
new: 2.0

path: .spaces[0].spaces[3].metrics.nexits.sum
old: 1.0
new: 2.0

path: .spaces[0].spaces[3].metrics.loc.ploc
old: 1.0
new: 6.0

path: .spaces[0].spaces[3].metrics.loc.lloc
old: 1.0
new: 4.0

path: .spaces[0].spaces[3].metrics.loc.sloc
old: 1.0
new: 6.0

Code

std::string Basename(const std::string &Path) {
  size_t Pos = Path.find_last_of("/\\");
  if (Pos == std::string::npos) return Path;
  assert(Pos < Path.size());
  return Path.substr(Pos + 1);
}

Minimal test - lines (62, 72)

path: .spaces[0].spaces[1].metrics.nexits.sum
old: 1.0
new: 2.0

path: .spaces[0].spaces[1].metrics.nexits.average
old: 1.0
new: 2.0

path: .spaces[0].spaces[1].metrics.nargs.average
old: 0.0
new: 1.0

path: .spaces[0].spaces[1].metrics.nargs.sum
old: 0.0
new: 1.0

path: .spaces[0].spaces[1].metrics.cyclomatic.average
old: 1.0
new: 2.0

path: .spaces[0].spaces[1].metrics.cyclomatic.sum
old: 1.0
new: 2.0

path: .spaces[0].spaces[1].metrics.loc.ploc
old: 1.0
new: 9.0

path: .spaces[0].spaces[1].metrics.loc.sloc
old: 1.0
new: 11.0

path: .spaces[0].spaces[1].metrics.loc.blank
old: 0.0
new: 2.0

path: .spaces[0].spaces[1].metrics.loc.lloc
old: 1.0
new: 4.0

path: .spaces[0].spaces[1].metrics.cognitive.sum
old: 0.0
new: 1.0

path: .spaces[0].spaces[1].metrics.cognitive.average
old: 0.0
new: 1.0

path: .spaces[0].spaces[1].metrics.mi.mi_visual_studio
old: 88.53493745197343
new: 60.78175598781615

path: .spaces[0].spaces[1].metrics.mi.mi_sei
old: 142.81741287200575
new: 74.45189760444485

path: .spaces[0].spaces[1].metrics.mi.mi_original
old: 151.39474304287458
new: 103.9368027391656

path: .spaces[0].spaces[1].metrics.halstead.N1
old: 7.0
new: 28.0

path: .spaces[0].spaces[1].metrics.halstead.time
old: 6.9188632372745955
new: 113.5002818065214

path: .spaces[0].spaces[1].metrics.halstead.N2
old: 5.0
new: 18.0

path: .spaces[0].spaces[1].metrics.halstead.bugs
old: 0.00831285578253799
new: 0.05366919014034088

path: .spaces[0].spaces[1].metrics.halstead.effort
old: 124.53953827094271
new: 2043.0050725173855

path: .spaces[0].spaces[1].metrics.halstead.difficulty
old: 3.0
new: 9.818181818181818

path: .spaces[0].spaces[1].metrics.halstead.level
old: 0.3333333333333333
new: 0.10185185185185185

path: .spaces[0].spaces[1].metrics.halstead.n2
old: 5.0
new: 11.0

path: .spaces[0].spaces[1].metrics.halstead.n1
old: 6.0
new: 12.0

path: .spaces[0].spaces[1].metrics.halstead.volume
old: 41.51317942364757
new: 208.0838499786226

path: .spaces[0].spaces[1].metrics.halstead.estimated_program_length
old: 27.11941547876375
new: 81.07329781366414

path: .spaces[0].spaces[1].metrics.halstead.purity_ratio
old: 2.259951289896979
new: 1.7624629959492204

path: .spaces[0].spaces[1].metrics.halstead.length
old: 12.0
new: 46.0

path: .spaces[0].spaces[1].metrics.halstead.vocabulary
old: 11.0
new: 23.0

Code

bool IsFile(const std::string &Path) {
  DWORD Att = GetFileAttributesA(Path.c_str());

  if (Att == INVALID_FILE_ATTRIBUTES) {
    Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n",
        Path.c_str(), GetLastError());
    return false;
  }

  return IsFile(Path, Att);
}

Minimal test - lines (24, 411)

path: .spaces[0].metrics.mi.mi_original
old: 58.41380699801309
new: 0.2659463619974787

path: .spaces[0].metrics.mi.mi_sei
old: 40.7784340554111
new: -44.45121567986864

path: .spaces[0].metrics.mi.mi_visual_studio
old: 34.160121051469645
new: 0.1555241883026191

path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 39.0

path: .spaces[0].metrics.nargs.average
old: 0.0
new: 1.3928571428571428

path: .spaces[0].metrics.cyclomatic.sum
old: 15.0
new: 108.0

path: .spaces[0].metrics.cyclomatic.average
old: 1.0714285714285714
new: 3.724137931034482

path: .spaces[0].metrics.nexits.sum
old: 12.0
new: 57.0

path: .spaces[0].metrics.nexits.average
old: 1.0
new: 2.0357142857142856

path: .spaces[0].metrics.cognitive.sum
old: 1.0
new: 101.0

path: .spaces[0].metrics.cognitive.average
old: 0.08333333333333333
new: 3.607142857142857

path: .spaces[0].metrics.halstead.difficulty
old: 13.82857142857143
new: 69.2289156626506

path: .spaces[0].metrics.halstead.volume
old: 1728.6652190148643
new: 13170.36421498185

path: .spaces[0].metrics.halstead.n2
old: 70.0
new: 166.0

path: .spaces[0].metrics.halstead.estimated_program_length
old: 493.0498111861476
new: 1397.230282206101

path: .spaces[0].metrics.halstead.length
old: 269.0
new: 1723.0

path: .spaces[0].metrics.halstead.effort
old: 23904.970457234125
new: 911770.03348537

path: .spaces[0].metrics.halstead.level
old: 0.07231404958677685
new: 0.014444831186912636

path: .spaces[0].metrics.halstead.purity_ratio
old: 1.832898926342556
new: 0.8109287766721422

path: .spaces[0].metrics.halstead.time
old: 1328.0539142907846
new: 50653.89074918722

path: .spaces[0].metrics.halstead.vocabulary
old: 86.0
new: 200.0

path: .spaces[0].metrics.halstead.N1
old: 148.0
new: 1047.0

path: .spaces[0].metrics.halstead.N2
old: 121.0
new: 676.0

path: .spaces[0].metrics.halstead.bugs
old: 0.2766119168062828
new: 3.134264340265713

path: .spaces[0].metrics.halstead.n1
old: 16.0
new: 34.0

path: .spaces[0].metrics.loc.sloc
old: 77.0
new: 388.0

path: .spaces[0].metrics.loc.cloc
old: 14.0
new: 27.0

path: .spaces[0].metrics.loc.blank
old: 12.0
new: 55.0

path: .spaces[0].metrics.loc.lloc
old: 12.0
new: 174.0

path: .spaces[0].metrics.loc.ploc
old: 51.0
new: 306.0

path: .spaces[0].metrics.nom.functions
old: 12.0
new: 28.0

path: .spaces[0].metrics.nom.total
old: 12.0
new: 28.0

Code

namespace fuzzer {

static bool IsFile(const std::string &Path, const DWORD &FileAttributes) {

  if (FileAttributes & FILE_ATTRIBUTE_NORMAL)
    return true;

  if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
    return false;

  HANDLE FileHandle(
      CreateFileA(Path.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
                  FILE_FLAG_BACKUP_SEMANTICS, 0));

  if (FileHandle == INVALID_HANDLE_VALUE) {
    Printf("CreateFileA() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
        GetLastError());
    return false;
  }

  DWORD FileType = GetFileType(FileHandle);

  if (FileType == FILE_TYPE_UNKNOWN) {
    Printf("GetFileType() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
        GetLastError());
    CloseHandle(FileHandle);
    return false;
  }

  if (FileType != FILE_TYPE_DISK) {
    CloseHandle(FileHandle);
    return false;
  }

  CloseHandle(FileHandle);
  return true;
}

bool IsFile(const std::string &Path) {
  DWORD Att = GetFileAttributesA(Path.c_str());

  if (Att == INVALID_FILE_ATTRIBUTES) {
    Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n",
        Path.c_str(), GetLastError());
    return false;
  }

  return IsFile(Path, Att);
}

static bool IsDir(DWORD FileAttrs) {
  if (FileAttrs == INVALID_FILE_ATTRIBUTES) return false;
  return FileAttrs & FILE_ATTRIBUTE_DIRECTORY;
}

std::string Basename(const std::string &Path) {
  size_t Pos = Path.find_last_of("/\\");
  if (Pos == std::string::npos) return Path;
  assert(Pos < Path.size());
  return Path.substr(Pos + 1);
}

size_t FileSize(const std::string &Path) {
  WIN32_FILE_ATTRIBUTE_DATA attr;
  if (!GetFileAttributesExA(Path.c_str(), GetFileExInfoStandard, &attr)) {
    DWORD LastError = GetLastError();
    if (LastError != ERROR_FILE_NOT_FOUND)
      Printf("GetFileAttributesExA() failed for \"%s\" (Error code: %lu).\n",
             Path.c_str(), LastError);
    return 0;
  }
  ULARGE_INTEGER size;
  size.HighPart = attr.nFileSizeHigh;
  size.LowPart = attr.nFileSizeLow;
  return size.QuadPart;
}

void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
                             Vector *V, bool TopDir) {
  auto E = GetEpoch(Dir);
  if (Epoch)
    if (E && *Epoch >= E) return;

  std::string Path(Dir);
  assert(!Path.empty());
  if (Path.back() != '\\')
      Path.push_back('\\');
  Path.push_back('*');

  // Get the first directory entry.
  WIN32_FIND_DATAA FindInfo;
  HANDLE FindHandle(FindFirstFileA(Path.c_str(), &FindInfo));
  if (FindHandle == INVALID_HANDLE_VALUE)
  {
    if (GetLastError() == ERROR_FILE_NOT_FOUND)
      return;
    Printf("No such file or directory: %s; exiting\n", Dir.c_str());
    exit(1);
  }

  do {
    std::string FileName = DirPlusFile(Dir, FindInfo.cFileName);

    if (FindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
      size_t FilenameLen = strlen(FindInfo.cFileName);
      if ((FilenameLen == 1 && FindInfo.cFileName[0] == '.') ||
          (FilenameLen == 2 && FindInfo.cFileName[0] == '.' &&
                               FindInfo.cFileName[1] == '.'))
        continue;

      ListFilesInDirRecursive(FileName, Epoch, V, false);
    }
    else if (IsFile(FileName, FindInfo.dwFileAttributes))
      V->push_back(FileName);
  } while (FindNextFileA(FindHandle, &FindInfo));

  DWORD LastError = GetLastError();
  if (LastError != ERROR_NO_MORE_FILES)
    Printf("FindNextFileA failed (Error code: %lu).\n", LastError);

  FindClose(FindHandle);

  if (Epoch && TopDir)
    *Epoch = E;
}


void IterateDirRecursive(const std::string &Dir,
                         void (*DirPreCallback)(const std::string &Dir),
                         void (*DirPostCallback)(const std::string &Dir),
                         void (*FileCallback)(const std::string &Dir)) {
  // TODO(metzman): Implement ListFilesInDirRecursive via this function.
  DirPreCallback(Dir);

  DWORD DirAttrs = GetFileAttributesA(Dir.c_str());
  if (!IsDir(DirAttrs)) return;

  std::string TargetDir(Dir);
  assert(!TargetDir.empty());
  if (TargetDir.back() != '\\') TargetDir.push_back('\\');
  TargetDir.push_back('*');

  WIN32_FIND_DATAA FindInfo;
  // Find the directory's first file.
  HANDLE FindHandle = FindFirstFileA(TargetDir.c_str(), &FindInfo);
  if (FindHandle == INVALID_HANDLE_VALUE) {
    DWORD LastError = GetLastError();
    if (LastError != ERROR_FILE_NOT_FOUND) {
      // If the directory isn't empty, then something abnormal is going on.
      Printf("FindFirstFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
             LastError);
    }
    return;
  }

  do {
    std::string Path = DirPlusFile(Dir, FindInfo.cFileName);
    DWORD PathAttrs = FindInfo.dwFileAttributes;
    if (IsDir(PathAttrs)) {
      // Is Path the current directory (".") or the parent ("..")?
      if (strcmp(FindInfo.cFileName, ".") == 0 ||
          strcmp(FindInfo.cFileName, "..") == 0)
        continue;
      IterateDirRecursive(Path, DirPreCallback, DirPostCallback, FileCallback);
    } else if (PathAttrs != INVALID_FILE_ATTRIBUTES) {
      FileCallback(Path);
    }
  } while (FindNextFileA(FindHandle, &FindInfo));

  DWORD LastError = GetLastError();
  if (LastError != ERROR_NO_MORE_FILES)
    Printf("FindNextFileA failed for %s (Error code: %lu).\n", Dir.c_str(),
           LastError);

  FindClose(FindHandle);
  DirPostCallback(Dir);
}

char GetSeparator() {
  return '\\';
}

FILE* OpenFile(int Fd, const char* Mode) {
  return _fdopen(Fd, Mode);
}

int CloseFile(int Fd) {
  return _close(Fd);
}

int DuplicateFile(int Fd) {
  return _dup(Fd);
}

void RemoveFile(const std::string &Path) {
  _unlink(Path.c_str());
}

void RenameFile(const std::string &OldPath, const std::string &NewPath) {
  rename(OldPath.c_str(), NewPath.c_str());
}

intptr_t GetHandleFromFd(int fd) {
  return _get_osfhandle(fd);
}

static bool IsSeparator(char C) {
  return C == '\\' || C == '/';
}

// Parse disk designators, like "C:\". If Relative == true, also accepts: "C:".
// Returns number of characters considered if successful.
static size_t ParseDrive(const std::string &FileName, const size_t Offset,
                         bool Relative = true) {
  if (Offset + 1 >= FileName.size() || FileName[Offset + 1] != ':')
    return 0;
  if (Offset + 2 >= FileName.size() || !IsSeparator(FileName[Offset + 2])) {
    if (!Relative) // Accept relative path?
      return 0;
    else
      return 2;
  }
  return 3;
}

// Parse a file name, like: SomeFile.txt
// Returns number of characters considered if successful.
static size_t ParseFileName(const std::string &FileName, const size_t Offset) {
  size_t Pos = Offset;
  const size_t End = FileName.size();
  for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
    ;
  return Pos - Offset;
}

// Parse a directory ending in separator, like: `SomeDir\`
// Returns number of characters considered if successful.
static size_t ParseDir(const std::string &FileName, const size_t Offset) {
  size_t Pos = Offset;
  const size_t End = FileName.size();
  if (Pos >= End || IsSeparator(FileName[Pos]))
    return 0;
  for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
    ;
  if (Pos >= End)
    return 0;
  ++Pos; // Include separator.
  return Pos - Offset;
}

// Parse a servername and share, like: `SomeServer\SomeShare\`
// Returns number of characters considered if successful.
static size_t ParseServerAndShare(const std::string &FileName,
                                  const size_t Offset) {
  size_t Pos = Offset, Res;
  if (!(Res = ParseDir(FileName, Pos)))
    return 0;
  Pos += Res;
  if (!(Res = ParseDir(FileName, Pos)))
    return 0;
  Pos += Res;
  return Pos - Offset;
}

// Parse the given Ref string from the position Offset, to exactly match the given
// string Patt.
// Returns number of characters considered if successful.
static size_t ParseCustomString(const std::string &Ref, size_t Offset,
                                const char *Patt) {
  size_t Len = strlen(Patt);
  if (Offset + Len > Ref.size())
    return 0;
  return Ref.compare(Offset, Len, Patt) == 0 ? Len : 0;
}

// Parse a location, like:
// \\?\UNC\Server\Share\  \\?\C:\  \\Server\Share\  \  C:\  C:
// Returns number of characters considered if successful.
static size_t ParseLocation(const std::string &FileName) {
  size_t Pos = 0, Res;

  if ((Res = ParseCustomString(FileName, Pos, R"(\\?\)"))) {
    Pos += Res;
    if ((Res = ParseCustomString(FileName, Pos, R"(UNC\)"))) {
      Pos += Res;
      if ((Res = ParseServerAndShare(FileName, Pos)))
        return Pos + Res;
      return 0;
    }
    if ((Res = ParseDrive(FileName, Pos, false)))
      return Pos + Res;
    return 0;
  }

  if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
    ++Pos;
    if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
      ++Pos;
      if ((Res = ParseServerAndShare(FileName, Pos)))
        return Pos + Res;
      return 0;
    }
    return Pos;
  }

  if ((Res = ParseDrive(FileName, Pos)))
    return Pos + Res;

  return Pos;
}

std::string DirName(const std::string &FileName) {
  size_t LocationLen = ParseLocation(FileName);
  size_t DirLen = 0, Res;
  while ((Res = ParseDir(FileName, LocationLen + DirLen)))
    DirLen += Res;
  size_t FileLen = ParseFileName(FileName, LocationLen + DirLen);

  if (LocationLen + DirLen + FileLen != FileName.size()) {
    Printf("DirName() failed for \"%s\", invalid path.\n", FileName.c_str());
    exit(1);
  }

  if (DirLen) {
    --DirLen; // Remove trailing separator.
    if (!FileLen) { // Path ended in separator.
      assert(DirLen);
      // Remove file name from Dir.
      while (DirLen && !IsSeparator(FileName[LocationLen + DirLen - 1]))
        --DirLen;
      if (DirLen) // Remove trailing separator.
        --DirLen;
    }
  }

  if (!LocationLen) { // Relative path.
    if (!DirLen)
      return ".";
    return std::string(".\\").append(FileName, 0, DirLen);
  }

  return FileName.substr(0, LocationLen + DirLen);
}

std::string TmpDir() {
  std::string Tmp;
  Tmp.resize(MAX_PATH + 1);
  DWORD Size = GetTempPathA(Tmp.size(), &Tmp[0]);
  if (Size == 0) {
    Printf("Couldn't get Tmp path.\n");
    exit(1);
  }
  Tmp.resize(Size);
  return Tmp;
}

bool IsInterestingCoverageFile(const std::string &FileName) {
  if (FileName.find("Program Files") != std::string::npos)
    return false;
  if (FileName.find("compiler-rt\\lib\\") != std::string::npos)
    return false; // sanitizer internal.
  if (FileName == "")
    return false;
  return true;
}

void RawPrint(const char *Str) {
  _write(2, Str, strlen(Str));
}

void MkDir(const std::string &Path) {
  if (CreateDirectoryA(Path.c_str(), nullptr)) return;
  Printf("CreateDirectoryA failed for %s (Error code: %lu).\n", Path.c_str(),
         GetLastError());
}

void RmDir(const std::string &Path) {
  if (RemoveDirectoryA(Path.c_str())) return;
  Printf("RemoveDirectoryA failed for %s (Error code: %lu).\n", Path.c_str(),
         GetLastError());
}

const std::string &getDevNull() {
  static const std::string devNull = "NUL";
  return devNull;
}

}  // namespace fuzzer

Minimal test - lines (26, 60)

path: .spaces[0].spaces[0].metrics.loc.sloc
old: 22.0
new: 35.0

path: .spaces[0].spaces[0].metrics.loc.cloc
old: 12.0
new: 0.0

path: .spaces[0].spaces[0].metrics.loc.lloc
old: 4.0
new: 16.0

path: .spaces[0].spaces[0].metrics.loc.blank
old: 0.0
new: 8.0

path: .spaces[0].spaces[0].metrics.loc.ploc
old: 10.0
new: 27.0

path: .spaces[0].spaces[0].metrics.mi.mi_original
old: 89.67353394498502
new: 78.34226940064421

path: .spaces[0].spaces[0].metrics.mi.mi_sei
old: 99.7996697498515
new: 37.93407072071062

path: .spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 52.44066312572224
new: 45.81419263195568

path: .spaces[0].spaces[0].metrics.cyclomatic.average
old: 1.2
new: 6.0

path: .spaces[0].spaces[0].metrics.cognitive.sum
old: 1.0
new: 5.0

path: .spaces[0].spaces[0].metrics.cognitive.average
old: 0.25
new: 5.0

path: .spaces[0].spaces[0].metrics.halstead.effort
old: 3046.6611818540064
new: 7963.779793270693

path: .spaces[0].spaces[0].metrics.halstead.N2
old: 26.0
new: 49.0

path: .spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 107.01955000865388
new: 170.3171490075026

path: .spaces[0].spaces[0].metrics.halstead.vocabulary
old: 28.0
new: 39.0

path: .spaces[0].spaces[0].metrics.halstead.time
old: 169.2589545474448
new: 442.4322107372607

path: .spaces[0].spaces[0].metrics.halstead.n1
old: 12.0
new: 13.0

path: .spaces[0].spaces[0].metrics.halstead.difficulty
old: 9.75
new: 12.25

path: .spaces[0].spaces[0].metrics.halstead.N1
old: 39.0
new: 74.0

path: .spaces[0].spaces[0].metrics.halstead.n2
old: 16.0
new: 26.0

path: .spaces[0].spaces[0].metrics.halstead.length
old: 65.0
new: 123.0

path: .spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 1.646454615517752
new: 1.3846922683536795

path: .spaces[0].spaces[0].metrics.halstead.volume
old: 312.4780699337442
new: 650.1044729200565

path: .spaces[0].spaces[0].metrics.halstead.bugs
old: 0.07005323327136247
new: 0.132930582297863

path: .spaces[0].spaces[0].metrics.halstead.level
old: 0.10256410256410256
new: 0.08163265306122448

path: .spaces[0].spaces[0].metrics.nom.functions
old: 4.0
new: 1.0

path: .spaces[0].spaces[0].metrics.nom.total
old: 4.0
new: 1.0

path: .spaces[0].spaces[0].metrics.nargs.sum
old: 0.0
new: 2.0

path: .spaces[0].spaces[0].metrics.nargs.average
old: 0.0
new: 2.0

path: .spaces[0].spaces[0].metrics.nexits.average
old: 1.0
new: 6.0

path: .spaces[0].spaces[0].metrics.nexits.sum
old: 4.0
new: 6.0

Code

static bool IsFile(const std::string &Path, const DWORD &FileAttributes) {

  if (FileAttributes & FILE_ATTRIBUTE_NORMAL)
    return true;

  if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
    return false;

  HANDLE FileHandle(
      CreateFileA(Path.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
                  FILE_FLAG_BACKUP_SEMANTICS, 0));

  if (FileHandle == INVALID_HANDLE_VALUE) {
    Printf("CreateFileA() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
        GetLastError());
    return false;
  }

  DWORD FileType = GetFileType(FileHandle);

  if (FileType == FILE_TYPE_UNKNOWN) {
    Printf("GetFileType() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
        GetLastError());
    CloseHandle(FileHandle);
    return false;
  }

  if (FileType != FILE_TYPE_DISK) {
    CloseHandle(FileHandle);
    return false;
  }

  CloseHandle(FileHandle);
  return true;
}

Minimal test - lines (74, 77)

path: .spaces[0].spaces[2].metrics.nargs.sum
old: 0.0
new: 1.0

path: .spaces[0].spaces[2].metrics.nargs.average
old: 0.0
new: 1.0

path: .spaces[0].spaces[2].metrics.halstead.estimated_program_length
old: 12.754887502163468
new: 35.60964047443681

path: .spaces[0].spaces[2].metrics.halstead.purity_ratio
old: 1.8221267860233523
new: 1.8741916039177269

path: .spaces[0].spaces[2].metrics.halstead.n2
old: 3.0
new: 5.0

path: .spaces[0].spaces[2].metrics.halstead.N2
old: 3.0
new: 7.0

path: .spaces[0].spaces[2].metrics.halstead.difficulty
old: 2.0
new: 5.6

path: .spaces[0].spaces[2].metrics.halstead.volume
old: 19.651484454403228
new: 70.30835464468075

path: .spaces[0].spaces[2].metrics.halstead.level
old: 0.5
new: 0.17857142857142858

path: .spaces[0].spaces[2].metrics.halstead.n1
old: 4.0
new: 8.0

path: .spaces[0].spaces[2].metrics.halstead.vocabulary
old: 7.0
new: 13.0

path: .spaces[0].spaces[2].metrics.halstead.effort
old: 39.302968908806456
new: 393.72678601021215

path: .spaces[0].spaces[2].metrics.halstead.bugs
old: 0.0038532659414573967
new: 0.01790641806124263

path: .spaces[0].spaces[2].metrics.halstead.length
old: 7.0
new: 19.0

path: .spaces[0].spaces[2].metrics.halstead.time
old: 2.1834982727114696
new: 21.873710333900675

path: .spaces[0].spaces[2].metrics.halstead.N1
old: 4.0
new: 12.0

path: .spaces[0].spaces[2].metrics.loc.ploc
old: 1.0
new: 4.0

path: .spaces[0].spaces[2].metrics.loc.sloc
old: 1.0
new: 4.0

path: .spaces[0].spaces[2].metrics.loc.lloc
old: 1.0
new: 3.0

path: .spaces[0].spaces[2].metrics.mi.mi_sei
old: 148.4278547652622
new: 106.23475401527978

path: .spaces[0].spaces[2].metrics.mi.mi_original
old: 155.2836050228807
new: 125.96700005047744

path: .spaces[0].spaces[2].metrics.mi.mi_visual_studio
old: 90.80912574437468
new: 73.66491231022073

path: .spaces[0].spaces[2].metrics.cognitive.sum
old: 0.0
new: 1.0

path: .spaces[0].spaces[2].metrics.cognitive.average
old: 0.0
new: 1.0

path: .spaces[0].spaces[2].metrics.cyclomatic.average
old: 1.0
new: 2.0

path: .spaces[0].spaces[2].metrics.cyclomatic.sum
old: 1.0
new: 2.0

path: .spaces[0].spaces[2].metrics.nexits.average
old: 1.0
new: 2.0

path: .spaces[0].spaces[2].metrics.nexits.sum
old: 1.0
new: 2.0

Code

static bool IsDir(DWORD FileAttrs) {
  if (FileAttrs == INVALID_FILE_ATTRIBUTES) return false;
  return FileAttrs & FILE_ATTRIBUTE_DIRECTORY;
}

Minimal test - lines (202, 204)

path: .spaces[0].spaces[7].metrics.halstead.N1
old: 4.0
new: 5.0

path: .spaces[0].spaces[7].metrics.halstead.N2
old: 3.0
new: 1.0

path: .spaces[0].spaces[7].metrics.halstead.level
old: 0.5
new: 0.4

path: .spaces[0].spaces[7].metrics.halstead.estimated_program_length
old: 12.754887502163468
new: 11.60964047443681

path: .spaces[0].spaces[7].metrics.halstead.volume
old: 19.651484454403228
new: 15.509775004326936

path: .spaces[0].spaces[7].metrics.halstead.n2
old: 3.0
new: 1.0

path: .spaces[0].spaces[7].metrics.halstead.time
old: 2.1834982727114696
new: 2.1541354172676304

path: .spaces[0].spaces[7].metrics.halstead.vocabulary
old: 7.0
new: 6.0

path: .spaces[0].spaces[7].metrics.halstead.difficulty
old: 2.0
new: 2.5

path: .spaces[0].spaces[7].metrics.halstead.purity_ratio
old: 1.8221267860233523
new: 1.9349400790728015

path: .spaces[0].spaces[7].metrics.halstead.effort
old: 39.302968908806456
new: 38.77443751081734

path: .spaces[0].spaces[7].metrics.halstead.bugs
old: 0.0038532659414573967
new: 0.00381864321284214

path: .spaces[0].spaces[7].metrics.halstead.n1
old: 4.0
new: 5.0

path: .spaces[0].spaces[7].metrics.halstead.length
old: 7.0
new: 6.0

path: .spaces[0].spaces[7].metrics.mi.mi_sei
old: 148.4278547652622
new: 124.52705705444804

path: .spaces[0].spaces[7].metrics.mi.mi_original
old: 155.2836050228807
new: 138.71683447649625

path: .spaces[0].spaces[7].metrics.mi.mi_visual_studio
old: 90.80912574437468
new: 81.12095583420833

path: .spaces[0].spaces[7].metrics.loc.sloc
old: 1.0
new: 3.0

path: .spaces[0].spaces[7].metrics.loc.ploc
old: 1.0
new: 3.0

Code

char GetSeparator() {
  return '\\';
}

Minimal test - lines (86, 99)

path: .spaces[0].spaces[4].metrics.nexits.average
old: 1.0
new: 2.0

path: .spaces[0].spaces[4].metrics.nexits.sum
old: 1.0
new: 2.0

path: .spaces[0].spaces[4].metrics.cyclomatic.average
old: 1.0
new: 3.0

path: .spaces[0].spaces[4].metrics.cyclomatic.sum
old: 1.0
new: 3.0

path: .spaces[0].spaces[4].metrics.mi.mi_sei
old: 146.92819499625
new: 64.03687204171334

path: .spaces[0].spaces[4].metrics.mi.mi_visual_studio
old: 90.2012398141466
new: 56.51876081077621

path: .spaces[0].spaces[4].metrics.mi.mi_original
old: 154.24412008219068
new: 96.64708098642733

path: .spaces[0].spaces[4].metrics.loc.lloc
old: 1.0
new: 7.0

path: .spaces[0].spaces[4].metrics.loc.sloc
old: 1.0
new: 14.0

path: .spaces[0].spaces[4].metrics.loc.ploc
old: 1.0
new: 14.0

path: .spaces[0].spaces[4].metrics.nargs.sum
old: 0.0
new: 1.0

path: .spaces[0].spaces[4].metrics.nargs.average
old: 0.0
new: 1.0

path: .spaces[0].spaces[4].metrics.halstead.difficulty
old: 2.5
new: 9.904761904761903

path: .spaces[0].spaces[4].metrics.halstead.N2
old: 3.0
new: 32.0

path: .spaces[0].spaces[4].metrics.halstead.estimated_program_length
old: 16.36452797660028
new: 140.34438221418816

path: .spaces[0].spaces[4].metrics.halstead.vocabulary
old: 8.0
new: 34.0

path: .spaces[0].spaces[4].metrics.halstead.effort
old: 60.0
new: 3779.258110643109

path: .spaces[0].spaces[4].metrics.halstead.n1
old: 5.0
new: 13.0

path: .spaces[0].spaces[4].metrics.halstead.bugs
old: 0.005108729549290353
new: 0.08087540114591991

path: .spaces[0].spaces[4].metrics.halstead.length
old: 8.0
new: 75.0

path: .spaces[0].spaces[4].metrics.halstead.purity_ratio
old: 2.045565997075035
new: 1.8712584295225088

path: .spaces[0].spaces[4].metrics.halstead.volume
old: 24.0
new: 381.55971309377543

path: .spaces[0].spaces[4].metrics.halstead.N1
old: 5.0
new: 43.0

path: .spaces[0].spaces[4].metrics.halstead.n2
old: 3.0
new: 21.0

path: .spaces[0].spaces[4].metrics.halstead.level
old: 0.4
new: 0.10096153846153846

path: .spaces[0].spaces[4].metrics.halstead.time
old: 3.3333333333333335
new: 209.95878392461717

path: .spaces[0].spaces[4].metrics.cognitive.average
old: 0.0
new: 3.0

path: .spaces[0].spaces[4].metrics.cognitive.sum
old: 0.0
new: 3.0

Code

size_t FileSize(const std::string &Path) {
  WIN32_FILE_ATTRIBUTE_DATA attr;
  if (!GetFileAttributesExA(Path.c_str(), GetFileExInfoStandard, &attr)) {
    DWORD LastError = GetLastError();
    if (LastError != ERROR_FILE_NOT_FOUND)
      Printf("GetFileAttributesExA() failed for \"%s\" (Error code: %lu).\n",
             Path.c_str(), LastError);
    return 0;
  }
  ULARGE_INTEGER size;
  size.HighPart = attr.nFileSizeHigh;
  size.LowPart = attr.nFileSizeLow;
  return size.QuadPart;
}

Minimal test - lines (101, 148)

path: .spaces[0].spaces[5].metrics.nexits.average
old: 1.0
new: 2.0

path: .spaces[0].spaces[5].metrics.nexits.sum
old: 1.0
new: 2.0

path: .spaces[0].spaces[5].metrics.halstead.bugs
old: 0.005108729549290353
new: 0.42436522748983424

path: .spaces[0].spaces[5].metrics.halstead.N2
old: 3.0
new: 98.0

path: .spaces[0].spaces[5].metrics.halstead.purity_ratio
old: 2.045565997075035
new: 1.4174340017413671

path: .spaces[0].spaces[5].metrics.halstead.difficulty
old: 2.5
new: 30.333333333333332

path: .spaces[0].spaces[5].metrics.halstead.n2
old: 3.0
new: 42.0

path: .spaces[0].spaces[5].metrics.halstead.length
old: 8.0
new: 246.0

path: .spaces[0].spaces[5].metrics.halstead.n1
old: 5.0
new: 26.0

path: .spaces[0].spaces[5].metrics.halstead.volume
old: 24.0
new: 1497.5158589475834

path: .spaces[0].spaces[5].metrics.halstead.vocabulary
old: 8.0
new: 68.0

path: .spaces[0].spaces[5].metrics.halstead.level
old: 0.4
new: 0.03296703296703297

path: .spaces[0].spaces[5].metrics.halstead.N1
old: 5.0
new: 148.0

path: .spaces[0].spaces[5].metrics.halstead.effort
old: 60.0
new: 45424.64772141003

path: .spaces[0].spaces[5].metrics.halstead.estimated_program_length
old: 16.36452797660028
new: 348.6887644283763

path: .spaces[0].spaces[5].metrics.halstead.time
old: 3.3333333333333335
new: 2523.591540078335

path: .spaces[0].spaces[5].metrics.cognitive.sum
old: 0.0
new: 20.0

path: .spaces[0].spaces[5].metrics.cognitive.average
old: 0.0
new: 20.0

path: .spaces[0].spaces[5].metrics.cyclomatic.sum
old: 1.0
new: 18.0

path: .spaces[0].spaces[5].metrics.cyclomatic.average
old: 1.0
new: 18.0

path: .spaces[0].spaces[5].metrics.loc.ploc
old: 1.0
new: 39.0

path: .spaces[0].spaces[5].metrics.loc.sloc
old: 1.0
new: 48.0

path: .spaces[0].spaces[5].metrics.loc.blank
old: 0.0
new: 8.0

path: .spaces[0].spaces[5].metrics.loc.cloc
old: 0.0
new: 1.0

path: .spaces[0].spaces[5].metrics.loc.lloc
old: 1.0
new: 23.0

path: .spaces[0].spaces[5].metrics.mi.mi_sei
old: 146.92819499625
new: 32.61956157946088

path: .spaces[0].spaces[5].metrics.mi.mi_visual_studio
old: 90.2012398141466
new: 38.67041896969032

path: .spaces[0].spaces[5].metrics.mi.mi_original
old: 154.24412008219068
new: 66.12641643817045

path: .spaces[0].spaces[5].metrics.nargs.average
old: 0.0
new: 4.0

path: .spaces[0].spaces[5].metrics.nargs.sum
old: 0.0
new: 4.0

Code

void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
                             Vector *V, bool TopDir) {
  auto E = GetEpoch(Dir);
  if (Epoch)
    if (E && *Epoch >= E) return;

  std::string Path(Dir);
  assert(!Path.empty());
  if (Path.back() != '\\')
      Path.push_back('\\');
  Path.push_back('*');

  // Get the first directory entry.
  WIN32_FIND_DATAA FindInfo;
  HANDLE FindHandle(FindFirstFileA(Path.c_str(), &FindInfo));
  if (FindHandle == INVALID_HANDLE_VALUE)
  {
    if (GetLastError() == ERROR_FILE_NOT_FOUND)
      return;
    Printf("No such file or directory: %s; exiting\n", Dir.c_str());
    exit(1);
  }

  do {
    std::string FileName = DirPlusFile(Dir, FindInfo.cFileName);

    if (FindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
      size_t FilenameLen = strlen(FindInfo.cFileName);
      if ((FilenameLen == 1 && FindInfo.cFileName[0] == '.') ||
          (FilenameLen == 2 && FindInfo.cFileName[0] == '.' &&
                               FindInfo.cFileName[1] == '.'))
        continue;

      ListFilesInDirRecursive(FileName, Epoch, V, false);
    }
    else if (IsFile(FileName, FindInfo.dwFileAttributes))
      V->push_back(FileName);
  } while (FindNextFileA(FindHandle, &FindInfo));

  DWORD LastError = GetLastError();
  if (LastError != ERROR_NO_MORE_FILES)
    Printf("FindNextFileA failed (Error code: %lu).\n", LastError);

  FindClose(FindHandle);

  if (Epoch && TopDir)
    *Epoch = E;
}