I’m using ReadDirectoryChangesW
to spy a folder that I opened with CreateFile
, once a file was added I call a function (OnFileChanged
) that read the size and open it for reading, my application works fine for small sized file but the problem occurs when I try to copy a big file into my folder(7,24 M), and I get Permission denied
error after calling fopen to read it.
the watching process is based on this
void Init(const QString FullPath)
{ ...
hDir = CreateFile(
dirPath, // pointer to the directory containing the tex files
FILE_LIST_DIRECTORY|GENERIC_READ, // access (read-write) mode
FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, // share mode
NULL, // security descriptor
OPEN_EXISTING, // how to create
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED , // file attributes
NULL); // file with attributes to copy
SecureZeroMemory (&overl, sizeof(overl));
SecureZeroMemory(buffer, sizeof(buffer));
overl.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// watch the directory
BOOL res= ReadDirectoryChangesW(
hDir, /* handle to directory */
&buffer[curBuffer], /* read results buffer */
sizeof(buffer[curBuffer]), /* length of buffer */
FALSE, /* monitoring option */
FILE_NOTIFY_CHANGE_FILE_NAME ,
//FILE_NOTIFY_CHANGE_LAST_WRITE, /* filter conditions */
NULL, /* bytes returned */
&overl, /* overlapped buffer */
NULL); /* completion routine */
}
void StartWatchThread()
{
// if the thread already exists then stop it
if (IsThreadRunning())
SynchronousAbort();
//CrashIf(!hDir);
if(!hDir)
{ qDebug()<<" handle "<<hDir<<" last error"<<GetLastError();
exit(-1);}
else
{// reset the hEvtStopWatching event so that it can be set if
// some thread requires the watching thread to stop
ResetEvent(hEvtStopWatching);
DWORD watchingthreadID;
qDebug()<<"befrore creating thread";
hWatchingThread = CreateThread(NULL, 0, WatchingThread, this, 0, &watchingthreadID);
qDebug()<<"watchingthreadID"<<watchingthreadID;
}
}
DWORD WINAPI WatchingThread(void *param)
{
//qDebug()<<"in WatchingThread";
FileWatcher *fw = (FileWatcher *)param;
HANDLE hp[2] = { fw->hEvtStopWatching, fw->overl.hEvent };
for (;;)
{
DWORD dwObj = WaitForMultipleObjects((sizeof(hp)/(sizeof(hp[0])))
, hp, FALSE, INFINITE);
if (dwObj == WAIT_OBJECT_0) // the user asked to quit the program
{
qDebug()<<"in WatchingThread the user asked to quit the program";
//exit(-1);
break;
}
if (dwObj != WAIT_OBJECT_0 + 1)
{
// BUG!
//assert(0);
qDebug()<<"dwObj "<<dwObj<<" last error "<<GetLastError();
break;
}
//qDebug()<<"WatchingThread fw->NotifyChange() ";
//if (fw->wakeup)
fw->NotifyChange();
}
return 0;
}
bool NotifyChange()
{
//qDebug()<<"in NotifyChange";
GetOverlappedResult(hDir, &overl, &dwNumberbytes, FALSE);
FILE_NOTIFY_INFORMATION *pFileNotify = (FILE_NOTIFY_INFORMATION *)buffer[curBuffer];
// Switch the 2 buffers
curBuffer = (curBuffer + 1) % (sizeof(buffer)/(sizeof(buffer[0])));
SecureZeroMemory(buffer[curBuffer], sizeof(buffer[curBuffer]));
// start a new asynchronous call to ReadDirectory in the alternate buffer
ReadDirectoryChangesW(
hDir, /* handle to directory */
&buffer[curBuffer], /* read results buffer */
sizeof(buffer[curBuffer]), /* length of buffer */
FALSE, /* monitoring option */
FILE_NOTIFY_CHANGE_FILE_NAME ,
//FILE_NOTIFY_CHANGE_LAST_WRITE, /* filter conditions */
NULL, /* bytes returned */
&overl, /* overlapped buffer */
NULL); /* completion routine */
// Note: the ReadDirectoryChangesW API fills the buffer with WCHAR strings.
for (;;) {
if (pFileNotify->Action == FILE_ACTION_ADDED)
{
qDebug()<<"in NotifyChange if ";
char szAction[42];
char szFilename[MAX_PATH] ;
memset(szFilename,'\0',sizeof( szFilename));
strcpy(szAction,"added");
wcstombs( szFilename, pFileNotify->FileName, MAX_PATH);
OnFileChanged(szFilename,szAction);
qDebug()<<"in NotifyChange after OnFileChanged ";
}
// step to the next entry if there is one
if (!pFileNotify->NextEntryOffset)
return false;
pFileNotify = (FILE_NOTIFY_INFORMATION *)((PBYTE)pFileNotify + pFileNotify->NextEntryOffset);
}
pFileNotify=NULL;
return true;
}
I couldn't figure out how is handling the file and don't let me read it?
I tried to call Sleep() after calling OnFileChanged
and wake up when it finish but in vain.
Any idea please .
That is pretty much guaranteed to fail sooner or later. File-changed notifications are generated while a process is writing to the file. Which prevents you from opening the file if the process hasn't completed writing yet or is otherwise keeping the file open. And didn't permit read sharing, very common for programs that write a file. It is certainly related to file size, the larger the file, the longer it takes to write so the greater the odds you are trying to open it while the other process didn't close it yet.
You'll need to deal with this possible mishap. Nothing you can do but keep the path in a queue so you can try later.