EVQ_API int evq_add_dirwatch (struct event_queue *evq, struct event *ev, const char *path) { const DWORD flags = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY; const unsigned int filter = (ev->flags >> EVENT_EOF_SHIFT_RES) ? FILE_NOTIFY_CHANGE_LAST_WRITE : flags; HANDLE fd; ev->flags &= ~EVENT_EOF_MASK_RES; { void *os_path = utf8_to_filename(path); if (!os_path) return -1; fd = is_WinNT ? FindFirstChangeNotificationW(os_path, FALSE, filter) : FindFirstChangeNotificationA(os_path, FALSE, filter); free(os_path); } if (fd == NULL || fd == INVALID_HANDLE_VALUE) return -1; ev->fd = fd; return evq_add(evq, ev); }
QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths, QStringList *files, QStringList *directories) { if (handles.isEmpty() || handles.count() == MAXIMUM_WAIT_OBJECTS) return paths; QMutexLocker locker(&mutex); QStringList p = paths; QMutableListIterator<QString> it(p); while (it.hasNext()) { QString path = it.next(); QString normalPath = path; if (normalPath.endsWith(QLatin1Char('/')) || normalPath.endsWith(QLatin1Char('\\'))) normalPath.chop(1); QFileInfo fileInfo(normalPath.toLower()); if (!fileInfo.exists()) continue; bool isDir = fileInfo.isDir(); if (isDir) { if (directories->contains(path)) continue; } else { if (files->contains(path)) continue; } const QString absolutePath = isDir ? fileInfo.absoluteFilePath() : fileInfo.absolutePath(); HANDLE handle = handleForDir.value(absolutePath, INVALID_HANDLE_VALUE); if (handle == INVALID_HANDLE_VALUE) { QT_WA({ handle = FindFirstChangeNotificationW((TCHAR *) absolutePath.utf16(), false, (FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SECURITY)); },{ handle = FindFirstChangeNotificationA(absolutePath.toLocal8Bit(), false, (FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SECURITY)); }) if (handle == INVALID_HANDLE_VALUE)
int CALLBACK IniRepositoryWatcherThread(int) { int result; // eax@8 HANDLE v2; // eax@24 DWORD v3; // eax@31 DWORD v4; // eax@51 char v5; // al@94 char v6; // al@99 char v7; // [sp+0h] [bp-2A0h]@7 DWORD v8; // [sp+6Ch] [bp-234h]@69 signed int v9; // [sp+70h] [bp-230h]@68 unsigned int v10; // [sp+74h] [bp-22Ch]@15 char Dst[268]; // [sp+78h] [bp-228h]@15 HANDLE hChangeHandle; // [sp+184h] [bp-11Ch]@10 HANDLE hHandle; // [sp+188h] [bp-118h]@9 char v14[4]; // [sp+18Ch] [bp-114h]@33 const CHAR Src; // [sp+190h] [bp-110h]@5 unsigned int v16; // [sp+298h] [bp-8h]@1 DWORD v17; // [sp+29Ch] [bp-4h]@33 int v18; // [sp+2A0h] [bp+0h]@1 if ( WndGetDevicesFolder((LPSTR)&Src, 0x104u, 0, 0) ) { hHandle = g_pMain->hStopMainProcessThreadEvent; while(TRUE) { hChangeHandle = FindFirstChangeNotificationA(&Src, 1, 1u); if ( hChangeHandle == INVALID_HANDLE_VALUE ) { strcpy_s(Dst, MAX_PATH, &Src); BYTE *pEnd = &Dst[strlen(Dst)]; do { while(*pEnd != '\\' && pEnd >= Dst) { --pEnd; } if(*pEnd != '\\') { return 0; } *pEnd = NULL; hChangeHandle = FindFirstChangeNotificationA(Dst, 0, 2u); } while(hChangeHandle == INVALID_HANDLE_VALUE); if(hChangeHandle == INVALID_HANDLE_VALUE) { return 0; } v17 = WaitForMultipleObjects(2u, &hChangeHandle, 0, 0xFFFFFFFFu); FindCloseChangeNotification(hChangeHandle); if ( !v17 ) { continue; } if ( v17 != 1 ) { continue; } result = 0; } else { if(hChangeHandle == INVALID_HANDLE_VALUE) { result = 0; } else { while ( 1 ) { v17 = WaitForMultipleObjects(2u, &hChangeHandle, 0, 0xFFFFFFFFu); if ( v17 ) break; if ( !WaitForSingleObject(hHandle, 0x3E8u) ) { break; } v9 = 1; if(g_pMain->dwOndemandReloadStartTime) { OnDemandReloadElapsedTime = GetTickCount() - g_pMain->dwOndemandReloadStartTime; if(OnDemandReloadElapsedTime < 5000) { v9 = 0; } } if(v9) { MainAPIBroadcastControl(5, 0, 0, 0, 1); if(IniLoadFilesFromPath((int *)&g_pMain->ModelTable, &g_pMain->ulModelCount, (void **)&g_pMain->field_1D1C, (int)&g_pMain->field_1D18, &Src, g_pGbl->dwFlags, 0)) { if(!WaitForSingleObject(hHandle, 1000) ) break; } MainAPIBroadcastControl(6, 0, 0, 0, 1); } if(!FindNextChangeNotification(hChangeHandle)) { break; } } FindCloseChangeNotification(hChangeHandle); result = 0; } } break; } } else { result = 0; } return result; }
void run() { ItemInfoMap entries; scan(entries); DWORD filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME; if (owner().eventMask() & DirectoryWatcher::DW_ITEM_MODIFIED) filter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE; std::string path(owner().directory().path()); #if defined(POCO_WIN32_UTF8) std::wstring upath; Poco::UnicodeConverter::toUTF16(path.c_str(), upath); HANDLE hChange = FindFirstChangeNotificationW(upath.c_str(), FALSE, filter); #else HANDLE hChange = FindFirstChangeNotificationA(path.c_str(), FALSE, filter); #endif if (hChange == INVALID_HANDLE_VALUE) { try { FileImpl::handleLastErrorImpl(path); } catch (Poco::Exception& exc) { owner().scanError(&owner(), exc); } return; } bool stopped = false; while (!stopped) { try { HANDLE h[2]; h[0] = _hStopped; h[1] = hChange; switch (WaitForMultipleObjects(2, h, FALSE, INFINITE)) { case WAIT_OBJECT_0: stopped = true; break; case WAIT_OBJECT_0 + 1: { ItemInfoMap newEntries; scan(newEntries); compare(entries, newEntries); std::swap(entries, newEntries); if (FindNextChangeNotification(hChange) == FALSE) { FileImpl::handleLastErrorImpl(path); } } break; default: throw SystemException("failed to wait for directory changes"); } } catch (Poco::Exception& exc) { owner().scanError(&owner(), exc); } } FindCloseChangeNotification(hChange); }
/** * @class kt::DirectoryWatcherService::Waiter */ void DirectoryWatcherService::Waiter::run() { // Prevent clients from running multiple directory watchers. // Which wouldn't be necessary if I'd put that handler into local data. std::lock_guard<std::mutex> lock(RUN_LOCK); // XXX Well... so actually, I can't print anything here or else the printing to the // command prompt is broken and nothing in the app prints at all. So yeah, now I really // want a logger that gets that print info to another thread. // VR_LOG_INFO("Start directory watcher"); // DBG_LINE(std::cout << "Start directory watcher" << std::endl); DWORD ans; HANDLE* handle; DWORD notify = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE; size_t k, count = mPath.size(); if (count < 1) return; // Insert my own handle I can wakeup ++count; if ((handle = new HANDLE[count]) == 0) return; handle[0] = CreateEventW(0, FALSE, FALSE, 0); setWakeup(handle[0]); for (k = 1; k < count; k++) { handle[k] = FindFirstChangeNotificationA(mPath[k-1].c_str(), true, notify); } if (handle[0] == INVALID_HANDLE_VALUE) goto cleanup; for (k = 1; k < count; k++) { if (handle[k] == INVALID_HANDLE_VALUE) { // VR_LOG_INFO("ERROR DirectoryWatcherOp invalid handle on " << mPath[k-1]); // DBG_LINE(std::cout << "ERROR DirectoryWatcherOp invalid handle on " << mPath[k-1] << std::endl); goto cleanup; } } // VR_LOG_INFO("Start DirectoryWatcher loop"); // DBG_LINE(std::cout << "Start DirectoryWatcher loop" << std::endl); while (TRUE) { // Wait for notification. ans = WaitForMultipleObjectsEx(count, handle, FALSE, INFINITE, TRUE); if (isStopped()) goto cleanup; if (ans < WAIT_OBJECT_0 || ans >= WAIT_OBJECT_0 + count) goto cleanup; ans -= WAIT_OBJECT_0; if (ans >= 1 && ans < count) { // cout << "CHANGED=" << mPath[ans-1] << endl; if (!onChanged(mPath[ans-1])) goto cleanup; } if (FindNextChangeNotification(handle[ans]) == FALSE) goto cleanup; } cleanup: // VR_LOG_INFO("End DirectoryWatcher"); // DBG_LINE(std::cout << "End DirectoryWatcher" << std::endl); setWakeup(INVALID_HANDLE_VALUE); if (handle[0] != INVALID_HANDLE_VALUE) { CloseHandle(handle[0]); } for (k = 1; k < count; k++) { if (handle[k] != INVALID_HANDLE_VALUE) FindCloseChangeNotification(handle[k]); } delete[] handle; }