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;
}