A customer was having trouble with some code that copies a bunch of files and then processes the copy. Here’s the code they shared (suitably redacted):
// copy the files char command[512] = {NULL}; sprintf_s(command, 512, "copy /Y %s %s >nul 2>&1", sourcePath, destPath); printf("The command is %s\n", command); Log("The command is %s", command); system(command); // process the files char searchPattern[256] = {NULL}; sprintf_s(searchPattern, 256, "%s\\*", destPath); printf("The directory is %s.\n", searchPattern); Log("The directory is %s", searchPattern); hFile = FindFirstFileA(searchPattern, &FindFileData); // error when searching files if (hFile == INVALID_HANDLE_VALUE) { DWORD lastError = GetLastError(); if (lastError == ERROR_FILE_NOT_FOUND) { printf("No files under directory %s.\n", searchPattern); Log("No files under directory %s", searchPattern); return S_OK; } else { printf("FindFirstFile failed in directory %s with error: %d.\n", searchPattern, lastError); Log("FindFirstFile failed under directory %s with error: %d", searchPattern, lastError); return E_FAIL; } } do { printf("The file is %s.\n", FindFileData.cFileName); Log("The file is %s", FindFileData.cFileName); ...
The customer reported that “It appears that FindFirstFileA
does not wait for system()
to finish copying the files. Here’s a sample log file:
The command is copy /Y \\server\path\to\data\* D:\data >nul 2>&1 The directory is D:\data\* The file is .
“Observe that FindFirstFileA
did not find the files we copied. How can we wait for the system()
function to finish copying the files before the program proceeds to the FindFirstFileA
?”
In the ensuing discussion, people suggested using CopyFile
or SHFileOperation
instead of shelling out to cmd.exe
. Issues with spaces and other characters in the directory names. But can you find the reason why FindFirstFileA
couldn’t find the files?
Look carefully at the last line of the log: “The file is .” Part of this is confusing because the program both prints its output to the screen as well as to the log file, but prints them differently. The output to the screen includes a period at the end; the output to the log file does not.
And that’s the key. Since the output to the log file does not include a period at the end, it means that the period in the output is the actual contents of FindFileData.cFileName
.
The customer misread their log file. The issue isn’t that the FindFirstFileA
ran before the files were copied. The issue is that the first thing found by FindFirstFileA
was the file whose name consists of a single period.
Recall that every directory has two artificial entries, one for the directory itself (.
), and one for the directory’s parent (..
). What you found was the first artificial entry, the one that represents the directory itself. Instead of giving up right away, keep looking, and the files you copied will show up later.
(Assuming they were all successfully copied. The program doesn’t actually check.)
0 comments