static WatchedFile* NewWatchedFile(const WCHAR* filePath, const std::function<void()>& onFileChangedCb) { bool isManualCheck = PathIsNetworkPath(filePath); AutoFreeW dirPath(path::GetDir(filePath)); WatchedDir* wd = nullptr; bool newDir = false; if (!isManualCheck) { wd = FindExistingWatchedDir(dirPath); if (!wd) { wd = NewWatchedDir(dirPath); if (!wd) return nullptr; newDir = true; } } WatchedFile* wf = AllocStruct<WatchedFile>(); wf->filePath = str::Dup(filePath); wf->onFileChangedCb = onFileChangedCb; wf->watchedDir = wd; wf->isManualCheck = isManualCheck; ListInsert(&g_watchedFiles, wf); if (wf->isManualCheck) { GetFileState(filePath, &wf->fileState); AwakeWatcherThread(); } else { if (newDir) StartMonitoringDirForChanges(wf->watchedDir); } return wf; }
static WatchedFile *NewWatchedFile(const WCHAR *filePath, FileChangeObserver *observer) { bool isManualCheck = PathIsNetworkPath(filePath); ScopedMem<WCHAR> dirPath(path::GetDir(filePath)); WatchedDir *wd = nullptr; bool newDir = false; if (!isManualCheck) { wd = FindExistingWatchedDir(dirPath); if (!wd) { wd = NewWatchedDir(dirPath); if (!wd) return nullptr; newDir = true; } } WatchedFile *wf = AllocStruct<WatchedFile>(); wf->filePath = str::Dup(filePath); wf->observer = observer; wf->watchedDir = wd; wf->isManualCheck = isManualCheck; ListInsert(&g_watchedFiles, wf); if (wf->isManualCheck) { GetFileState(filePath, &wf->fileState); AwakeWatcherThread(); } else { if (newDir) StartMonitoringDirForChanges(wf->watchedDir); } return wf; }
static void CALLBACK ReadDirectoryChangesNotification(DWORD errCode, DWORD bytesTransfered, LPOVERLAPPED overlapped) { ScopedCritSec cs(&g_threadCritSec); OverlappedEx *over = (OverlappedEx*)overlapped; WatchedDir* wd = (WatchedDir*)over->data; lf(L"ReadDirectoryChangesNotification() dir: %s, numBytes: %d", wd->dirPath, (int)bytesTransfered); CrashIf(wd != wd->overlapped.data); if (errCode == ERROR_OPERATION_ABORTED) { lf(" ERROR_OPERATION_ABORTED"); DeleteWatchedDir(wd); InterlockedDecrement(&gRemovalsPending); return; } // This might mean overflow? Not sure. if (!bytesTransfered) return; FILE_NOTIFY_INFORMATION *notify = (FILE_NOTIFY_INFORMATION*)wd->buf; // collect files that changed, removing duplicates WStrVec changedFiles; for (;;) { ScopedMem<WCHAR> fileName(str::DupN(notify->FileName, notify->FileNameLength / sizeof(WCHAR))); // files can get updated either by writing to them directly or // by writing to a .tmp file first and then moving that file in place // (the latter only yields a RENAMED action with the expected file name) if (notify->Action == FILE_ACTION_MODIFIED || notify->Action == FILE_ACTION_RENAMED_NEW_NAME) { if (!changedFiles.Contains(fileName)) { lf(L"ReadDirectoryChangesNotification() FILE_ACTION_MODIFIED, for '%s'", fileName); changedFiles.Append(fileName.StealData()); } else { lf(L"ReadDirectoryChangesNotification() eliminating duplicate notification for '%s'", fileName); } } else { lf(L"ReadDirectoryChangesNotification() action=%d, for '%s'", (int)notify->Action, fileName); } // step to the next entry if there is one DWORD nextOff = notify->NextEntryOffset; if (!nextOff) break; notify = (FILE_NOTIFY_INFORMATION *)((char*)notify + nextOff); } StartMonitoringDirForChanges(wd); for (const WCHAR *f : changedFiles) { NotifyAboutFile(wd, f); } }
static void CALLBACK ReadDirectoryChangesNotification(DWORD errCode, DWORD bytesTransfered, LPOVERLAPPED overlapped) { ScopedCritSec cs(&g_threadCritSec); OverlappedEx *over = (OverlappedEx*)overlapped; WatchedDir* wd = (WatchedDir*)over->data; lf(L"ReadDirectoryChangesNotification() dir: %s, numBytes: %d", wd->dirPath, (int)bytesTransfered); CrashIf(wd != wd->overlapped.data); if (errCode == ERROR_OPERATION_ABORTED) { lf(" ERROR_OPERATION_ABORTED"); DeleteWatchedDir(wd); return; } // This might mean overflow? Not sure. if (!bytesTransfered) return; FILE_NOTIFY_INFORMATION *notify = (FILE_NOTIFY_INFORMATION*)wd->buf; // collect files that changed, removing duplicates WStrVec changedFiles; for (;;) { WCHAR *fileName = str::DupN(notify->FileName, notify->FileNameLength / sizeof(WCHAR)); if (notify->Action == FILE_ACTION_MODIFIED) { if (!changedFiles.Contains(fileName)) { lf(L"ReadDirectoryChangesNotification() FILE_ACTION_MODIFIED, for '%s'", fileName); changedFiles.Append(fileName); fileName = NULL; } else { lf(L"ReadDirectoryChangesNotification() eliminating duplicate notification for '%s'", fileName); } } else { lf(L"ReadDirectoryChangesNotification() action=%d, for '%s'", (int)notify->Action, fileName); } free(fileName); // step to the next entry if there is one DWORD nextOff = notify->NextEntryOffset; if (!nextOff) break; notify = (FILE_NOTIFY_INFORMATION *)((char*)notify + nextOff); } StartMonitoringDirForChanges(wd); for (WCHAR **f = changedFiles.IterStart(); f; f = changedFiles.IterNext()) { NotifyAboutFile(wd, *f); } }