for private use and learning purpose I want to write a little program that helps me to detect if a directory changed (like files deleted/added and stuff) on windows.
Problem-related part of code:
typedef struct
{
char *fileName;
char *sPath;
unsigned long long byteSize;
unsigned long lastWrite;
} FileItem;
// handling files > 2^32 bytes
unsigned long long int constructByteSize(const unsigned long fileSizeLow, const unsigned long fileSizeHigh)
{
return (unsigned long long int)(fileSizeLow + ((unsigned long long int)fileSizeHigh << 32));
}
void traverse(const char * const inputPath, HANDLE * fHandle, WIN32_FIND_DATA * fData, FileItem (*fileItems)[], unsigned long * const fileCount, unsigned long * const dirCount,
unsigned long long * const totalSize, unsigned long long * const arraySize)
{
char sPath[256];
int index;
// specify file mask
sprintf(sPath, "%s\\*.*", inputPath);
if( (fHandle = FindFirstFile(sPath, fData)) == INVALID_HANDLE_VALUE )
{
fprintf(stderr, "%s is not a valid directory, aborting..\n", inputPath);
return;
}
do
{
// FindFirstFile always returns . and .. first
if( strcmp(fData->cFileName, ".") != 0 && strcmp(fData->cFileName, "..") != 0 )
{
// concatenate filepath
sprintf(sPath, "%s\\%s", inputPath, fData->cFileName);
// check if inputPath is directory or file
if( fData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
// output directory
printf("Directory: %s\n", sPath);
++(*dirCount);
// recursion
traverse(sPath, fHandle, fData, fileItems, fileCount, dirCount, totalSize, arraySize);
}
else
{
// output file
printf("File: %s\n", sPath, strlen(sPath));
// calculate how much memory we need
unsigned long requestBytes;
requestBytes = (strlen(fData->cFileName) + 1) + (strlen(sPath) + 1) + sizeof(unsigned long long) + sizeof(unsigned long);
*arraySize += requestBytes;
// allocate memory
fileItems = (FileItem (*)[]) realloc(fileItems, *arraySize);
while( *arraySize != 0 && fileItems == NULL)
{
fprintf(stderr, "Memory reallocation failed\n");
fileItems = (FileItem (*)[]) realloc(fileItems, *arraySize);
}
// add structure to our array
// check if file > 2^32 bytes then create new file struct
if( fData->nFileSizeHigh != 0 )
(*fileItems)[(*fileCount)] = (FileItem) { fData->cFileName, sPath, constructByteSize(fData->nFileSizeLow, fData->nFileSizeHigh), constructWriteTime(fData->ftLastWriteTime) };
else
(*fileItems)[(*fileCount)] = (FileItem) { fData->cFileName, sPath, fData->nFileSizeLow, constructWriteTime(fData->ftLastWriteTime) };
DEBUG_LOG((*fileItems)[(*fileCount)].fileName);
// add bytesize to sum
*totalSize += (*fileItems)[(*fileCount)].byteSize;
++*fileCount;
}
}
} while( FindNextFile(fHandle, fData) );
}
void printArray(FileItem (*fileItems)[], unsigned long * const size);
void startTraverse(const char * const root, HANDLE * fHandle, WIN32_FIND_DATA * fData, unsigned long * const fileCount, unsigned long * const dirCount)
{
// list of files
FileItem (*fileItems)[] = NULL;
// store meta-information (total bytesize, arraysize)
unsigned long long totalSize = 0, arraySize = 0;
// start directory traverse
printf("Traversing %s..\n", root);
traverse(root, fHandle, fData, fileItems, fileCount, dirCount, &totalSize, &arraySize);
// output stats
printf("\nFile Count: %d\n", *fileCount);
printf("Directory Count: %d\n\n", *dirCount);
printf("Total Size: %d Bytes\n", totalSize);
printf("Total Size: %d KBytes\n", totalSize / 1024 + totalSize % 1024);
printf("Total Size: %d MBytes\n", totalSize / (1024 * 1024));
printf("Total Size: %.2f GBytes\n\n", (float) totalSize / (1024 * 1024 * 1024));
printArray(fileItems, fileCount);
//cleanup
free(fileItems);
}
void printArray(FileItem (*fileItems)[], unsigned long * const size)
{
for(int i = 0; i < (*size); ++i)
{
printf("FileItem #%d: %s\n", i + 1, (*fileItems)[i].fileName);
}
}
int main(int argc, char **argv)
{
WIN32_FIND_DATA fData;
HANDLE fHandle = NULL;
unsigned long fileCount = 0, dirCount = 0;
printf("#############################\n");
printf("## File Change Detection ##\n");
printf("#############################\n\n");
// parsing arguments
if( argc == 1 )
{
printf("need more arguments, aborting..\n");
}
// parse files without comparing
else if( argc == 2 )
{
startTraverse(argv[1], &fHandle, &fData, &fileCount, &dirCount);
//writeToDisk(fileItems, &fileCount);
}
/*
// parse files with comparing
else if( argc == 3 )
{
FileItem (*fileItemsIn)[] = malloc(sizeof(FileItem));
readFromDisk(argv[2], fileItemsIn);
startTraverse(argv[1], &fHandle, &fData, &fileCount, &dirCount);
//compare(fileItems, fileItemsIn, &fileCount);
free(fileItemsIn);
}
*/
// too many arguments
else
printf("Too many arguments, aborting..\n");
// cleanup
FindClose(fHandle);
return EXIT_SUCCESS;
}
Parsing the files and directories and outputting their names (inside the traverse-function!) works fine (as far as I see), printing out the total size works fine, but the program crashes when my function printArray is called (or to be more specific, when the first iteration of the for-loop is executed). By testing purpose, I made the ptr to the array of FileItems static. This time, the program didnt crash, but every item of this array seems to have the name of the last parsed file (e.g. when given a directory with 958 files, and name of last parsed file was "playerout.bik", printArray prints FileItem#1: playerout.bik FileItem#2: playerout.bik . . . FileItem#957: playerout.bik FileItem#958: playerout.bik ).
This made me think that this problem may be scope-related, but I can't see what I'm doing wrong here.