//=================================== void ConfigDestroy () { s_critsect.Enter(); { for_each(s_dirMonitors.begin(), s_dirMonitors.end(), DestroyDirMonitor_CS()); s_dirMonitors.clear(); } s_critsect.Leave(); // Wait until all directory monitors are deleted asynchronously while (s_dirCount) Sleep(1); }
//=================================== void DirMonitor::TaskComplete ( unsigned bytes, OVERLAPPED * ) { s_critsect.Enter(); { if (m_handle == INVALID_HANDLE_VALUE) { // The monitor is ready to be deleted } // If no bytes read then m_buffer wasn't large enough to hold all the // updates; scan the directory to see which files need to be updated else if (!bytes) { ScanDirectoryForChanges_CS(); } // Otherwise process the file notifications else for (const FILE_NOTIFY_INFORMATION * info = (const FILE_NOTIFY_INFORMATION *) m_buffer;;) { // Validate the structure // DebugMsg(" %u: %.*S\n", info->Action, info->FileNameLength / sizeof(info->FileName[0]), info->FileName); #ifdef ASSERTIONS_ENABLED size_t offset = (size_t) ((const byte *) info - (const byte *) m_buffer); ASSERT(offset < bytes); ASSERT(offset < sizeof_field(DirMonitor, m_buffer)); #endif // Deleting or renaming a file does not cause re-parsing if ((info->Action == FILE_ACTION_REMOVED) || (info->Action == FILE_ACTION_RENAMED_OLD_NAME)) { // DebugMsg("%.*S deleted\n", info->FileNameLength / sizeof(info->FileName[0]), filename); } else { // Convert to lowercase for hash matching wchar filename[MAX_PATH]; StrCopy(filename, min(_countof(filename), info->FileNameLength / sizeof(info->FileName[0]) + 1), info->FileName); CharLowerW(filename); // Reparse if file changed CheckReparseFile_CS(filename); } // Move to next entry if (!info->NextEntryOffset) break; info = (const FILE_NOTIFY_INFORMATION *) ((const byte *) info + info->NextEntryOffset); } WatchDirectory_CS(); } s_critsect.Leave(); }
//=================================== void ConfigMonitorFile (const wchar filename[]) { // Convert to canonical lowercase form wchar fullpath[MAX_PATH]; if (!GetFullPathNameW(filename, _countof(fullpath), fullpath, NULL)) { LOG_OS_LAST_ERROR(L"GetFullPathNameW"); FatalError(); } CharLowerW(fullpath); // Create the directory that contains the file to be watched wchar directory[MAX_PATH]; PathRemoveFileName(directory, _countof(directory), fullpath); if (!PathCreateDirectory(directory)) FatalError(); // Get the filename part filename = PathFindFileNameW(fullpath); s_critsect.Enter(); { // Create a monitor for this directory DirMonitor * dir = FindOrCreateDirectoryMonitor_CS(directory); // Does this file already exist in the monitor's file list? ConfigFile * file; ConfigFileMap::iterator pair = dir->m_files.find(filename); if (pair == dir->m_files.end()) { file = new ConfigFile(fullpath); dir->m_files.insert(ConfigFilePair(file->m_filename, file)); } else { file = pair->second; } // TODO: signal file for reparsing so the callback gets called. } s_critsect.Leave(); }