Question

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 .

Was it helpful?

Solution

I call a function (OnFileChanged) that read the size and open it for reading

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top