103 #ifndef DRFSW_MAX_PATH
105 #define DRFSW_MAX_PATH 1024U
110 #define DRFSW_EVENT_QUEUE_SIZE 1024U
217 #ifdef DR_FSW_IMPLEMENTATION
234 #if defined(__clang__)
235 #pragma GCC diagnostic push
236 #pragma GCC diagnostic ignored "-Wcast-align"
239 #ifndef DRFSW_PRIVATE
240 #define DRFSW_PRIVATE static
244 #define WIN32_RDC_FNI_COUNT DRFSW_EVENT_QUEUE_SIZE
251 DRFSW_PRIVATE
void* drfsw_malloc(
size_t sizeInBytes)
253 return HeapAlloc(GetProcessHeap(), 0, sizeInBytes);
256 DRFSW_PRIVATE
void drfsw_free(
void* p)
258 HeapFree(GetProcessHeap(), 0, p);
261 DRFSW_PRIVATE
void drfsw_memcpy(
void* dst,
const void* src,
size_t sizeInBytes)
263 CopyMemory(dst, src, sizeInBytes);
266 DRFSW_PRIVATE
void drfsw_zeromemory(
void* dst,
size_t sizeInBytes)
268 ZeroMemory(dst, sizeInBytes);
274 DRFSW_PRIVATE
void* drfsw_malloc(
size_t sizeInBytes)
276 return malloc(sizeInBytes);
279 DRFSW_PRIVATE
void drfsw_free(
void* p)
284 DRFSW_PRIVATE
void drfsw_memcpy(
void* dst,
const void* src,
size_t sizeInBytes)
286 memcpy(dst, src, sizeInBytes);
289 DRFSW_PRIVATE
void drfsw_zeromemory(
void* dst,
size_t sizeInBytes)
291 memset(dst, 0, sizeInBytes);
296 DRFSW_PRIVATE
int drfsw_strcpy(
char* dst,
unsigned int dstSizeInBytes,
const char* src)
298 #if defined(_MSC_VER)
299 return strcpy_s(dst, dstSizeInBytes, src);
304 if (dstSizeInBytes == 0) {
313 const char* iSrc = src;
314 size_t remainingSizeInBytes = dstSizeInBytes;
315 while (remainingSizeInBytes > 0 && iSrc[0] !=
'\0')
321 remainingSizeInBytes -= 1;
324 if (remainingSizeInBytes > 0) {
336 DRFSW_PRIVATE
int drfsw_event_init(
drfsw_event* pEvent,
drfsw_event_type type,
const char* absolutePath,
const char* absolutePathNew,
const char* absoluteBasePath,
const char* absoluteBasePathNew)
342 if (absolutePath !=
NULL) {
348 if (absolutePathNew !=
NULL) {
355 if (absoluteBasePath !=
NULL) {
361 if (absoluteBasePathNew !=
NULL) {
380 unsigned int bufferSize;
386 unsigned int indexFirst;
400 DRFSW_PRIVATE
int drfsw_event_queue_init(drfsw_event_queue* pQueue)
404 pQueue->pBuffer =
NULL;
405 pQueue->bufferSize = 0;
406 pQueue->indexFirst = 0;
411 if (pQueue->hSemaphore ==
NULL)
413 drfsw_free(pQueue->pBuffer);
418 if (pQueue->hLock ==
NULL)
420 CloseHandle(pQueue->hSemaphore);
421 drfsw_free(pQueue->pBuffer);
432 DRFSW_PRIVATE
void drfsw_event_queue_uninit(drfsw_event_queue* pQueue)
436 drfsw_free(pQueue->pBuffer);
437 pQueue->pBuffer =
NULL;
439 pQueue->bufferSize = 0;
440 pQueue->indexFirst = 0;
444 CloseHandle(pQueue->hSemaphore);
445 pQueue->hSemaphore =
NULL;
447 CloseHandle(pQueue->hLock);
448 pQueue->hLock =
NULL;
453 DRFSW_PRIVATE
unsigned int drfsw_event_queue_getcount(drfsw_event_queue* pQueue)
457 return pQueue->count;
463 DRFSW_PRIVATE
void drfsw_event_queue_inflate(drfsw_event_queue* pQueue)
467 unsigned int newBufferSize = pQueue->bufferSize + 1;
468 if (pQueue->bufferSize > 0)
470 newBufferSize = pQueue->bufferSize*2;
476 for (
unsigned int iDst = 0; iDst < pQueue->count; ++iDst)
478 unsigned int iSrc = (pQueue->indexFirst + iDst) % pQueue->bufferSize;
479 drfsw_memcpy(pNewBuffer + iDst, pOldBuffer + iSrc,
sizeof(
drfsw_event));
483 pQueue->bufferSize = newBufferSize;
484 pQueue->pBuffer = pNewBuffer;
485 pQueue->indexFirst = 0;
487 drfsw_free(pOldBuffer);
491 DRFSW_PRIVATE
int drfsw_event_queue_pushback(drfsw_event_queue* pQueue,
drfsw_event* pEvent)
497 unsigned int count = drfsw_event_queue_getcount(pQueue);
504 if (
count == pQueue->bufferSize)
506 drfsw_event_queue_inflate(pQueue);
507 assert(count < pQueue->bufferSize);
512 unsigned int iDst = (pQueue->indexFirst + pQueue->count) % pQueue->bufferSize;
513 drfsw_memcpy(pQueue->pBuffer + iDst, pEvent,
sizeof(
drfsw_event));
527 DRFSW_PRIVATE
int drfsw_event_queue_pop(drfsw_event_queue* pQueue,
drfsw_event* pEventOut)
529 if (pQueue !=
NULL && pQueue->count > 0)
531 if (pEventOut !=
NULL)
533 drfsw_memcpy(pEventOut, pQueue->pBuffer + pQueue->indexFirst,
sizeof(
drfsw_event));
534 pQueue->indexFirst = (pQueue->indexFirst + 1) % pQueue->bufferSize;
549 DRFSW_PRIVATE
int drfsw_make_absolute_path(
const char* absolutePart,
const char* relativePart,
char absolutePathOut[
DRFSW_MAX_PATH])
551 size_t absolutePartLength = strlen(absolutePart);
552 size_t relativePartLength = strlen(relativePart);
554 if (absolutePartLength > 0)
556 if (absolutePart[absolutePartLength - 1] ==
'/')
558 absolutePartLength -= 1;
574 memcpy(absolutePathOut, absolutePart, absolutePartLength);
577 absolutePathOut[absolutePartLength] =
'/';
580 memcpy(absolutePathOut + absolutePartLength + 1, relativePart, relativePartLength);
583 absolutePathOut[absolutePartLength + 1 + relativePartLength] =
'\0';
590 DRFSW_PRIVATE
int drfsw_to_forward_slashes(
char* path)
594 unsigned int counter = 0;
616 unsigned int bufferSize;
623 DRFSW_PRIVATE
int drfsw_list_init(drfsw_list* pList)
627 pList->buffer =
NULL;
628 pList->bufferSize = 0;
637 DRFSW_PRIVATE
void drfsw_list_uninit(drfsw_list* pList)
641 drfsw_free(pList->buffer);
645 DRFSW_PRIVATE
void drfsw_list_inflate(drfsw_list* pList)
649 unsigned int newBufferSize = pList->bufferSize + 1;
650 if (pList->bufferSize > 0)
652 newBufferSize = pList->bufferSize*2;
655 void** pOldBuffer = pList->buffer;
656 void** pNewBuffer = (
void**)drfsw_malloc(newBufferSize*
sizeof(
void*));
659 for (
unsigned int i = 0; i < pList->count; ++i)
661 pNewBuffer[i] = pOldBuffer[i];
665 pList->bufferSize = newBufferSize;
666 pList->buffer = pNewBuffer;
670 DRFSW_PRIVATE
void drfsw_list_pushback(drfsw_list* pList,
void* pItem)
674 if (pList->count == pList->bufferSize)
676 drfsw_list_inflate(pList);
677 assert(pList->count < pList->bufferSize);
679 pList->buffer[pList->count] = pItem;
685 DRFSW_PRIVATE
void drfsw_list_removebyindex(drfsw_list* pList,
unsigned int index)
689 assert(index < pList->
count);
690 assert(pList->count > 0);
693 for (
unsigned int i = index; index < pList->count - 1; ++i)
695 pList->buffer[i] = pList->buffer[i + 1];
705 #define DRFSW_MAX_PATH_W (DRFSW_MAX_PATH / sizeof(wchar_t))
710 static const int WIN32_RDC_PENDING_WATCH = (1 << 0);
711 static const int WIN32_RDC_PENDING_DELETE = (1 << 1);
715 DRFSW_PRIVATE
int drfsw_to_back_slashes_wchar(
wchar_t* path)
719 unsigned int counter = 0;
720 while (*path++ !=
L'\0' && counter++ < DRFSW_MAX_PATH_W)
735 DRFSW_PRIVATE
int drfsw_utf8_to_wchar(
const char* str,
wchar_t wstrOut[DRFSW_MAX_PATH_W])
737 int wcharsWritten = MultiByteToWideChar(CP_UTF8, 0, str, -1, wstrOut, DRFSW_MAX_PATH_W);
738 if (wcharsWritten > 0)
740 assert((
unsigned int)wcharsWritten <= DRFSW_MAX_PATH_W);
747 DRFSW_PRIVATE
int drfsw_wchar_to_utf8(
const wchar_t* wstr,
int wstrCC,
char pathOut[
DRFSW_MAX_PATH])
749 int bytesWritten = WideCharToMultiByte(CP_UTF8, 0, wstr, wstrCC, pathOut,
DRFSW_MAX_PATH - 1,
NULL,
NULL);
750 if (bytesWritten > 0)
753 pathOut[bytesWritten] =
'\0';
762 DRFSW_PRIVATE
int drfsw_to_win32_path_wchar(
const char* path,
wchar_t wpathOut[DRFSW_MAX_PATH_W])
764 if (drfsw_utf8_to_wchar(path, wpathOut))
766 return drfsw_to_back_slashes_wchar(wpathOut);
773 DRFSW_PRIVATE
int drfsw_from_win32_path(
const wchar_t* wpath,
int wpathCC,
char pathOut[
DRFSW_MAX_PATH])
775 if (drfsw_wchar_to_utf8(wpath, wpathCC, pathOut))
777 return drfsw_to_forward_slashes(pathOut);
784 DRFSW_PRIVATE VOID
CALLBACK drfsw_win32_completionroutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped);
785 DRFSW_PRIVATE VOID
CALLBACK drfsw_win32_schedulewatchAPC(ULONG_PTR dwParam);
786 DRFSW_PRIVATE VOID
CALLBACK drfsw_win32_cancelioAPC(ULONG_PTR dwParam);
796 } drfsw_directory_list_win32;
802 drfsw_directory_list_win32 watchedDirectories;
805 drfsw_event_queue eventQueue;
812 HANDLE hTerminateEvent;
816 HANDLE hDeleteDirSemaphore;
819 BOOL terminateThread;
821 } drfsw_context_win32;
823 DRFSW_PRIVATE
drfsw_context* drfsw_create_context_win32(
void);
824 DRFSW_PRIVATE
void drfsw_delete_context_win32(drfsw_context_win32* pContext);
825 DRFSW_PRIVATE
int drfsw_add_directory_win32(drfsw_context_win32* pContext,
const char* absolutePath);
826 DRFSW_PRIVATE
void drfsw_remove_directory_win32(drfsw_context_win32* pContext,
const char* absolutePath);
827 DRFSW_PRIVATE
void drfsw_remove_all_directories_win32(drfsw_context_win32* pContext);
828 DRFSW_PRIVATE
int drfsw_is_watching_directory_win32(drfsw_context_win32* pContext,
const char* absolutePath);
829 DRFSW_PRIVATE
int drfsw_next_event_win32(drfsw_context_win32* pContext,
drfsw_event* pEventOut);
830 DRFSW_PRIVATE
int drfsw_peek_event_win32(drfsw_context_win32* pContext,
drfsw_event* pEventOut);
831 DRFSW_PRIVATE
void drfsw_postevent_win32(drfsw_context_win32* pContext,
drfsw_event* pEvent);
838 drfsw_context_win32* pContext;
848 OVERLAPPED overlapped;
853 FILE_NOTIFY_INFORMATION* pFNIBuffer1;
854 FILE_NOTIFY_INFORMATION* pFNIBuffer2;
857 DWORD fniBufferSizeInBytes;
862 } drfsw_directory_win32;
864 DRFSW_PRIVATE
int drfsw_directory_win32_beginwatch(drfsw_directory_win32* pDirectory);
867 DRFSW_PRIVATE
void drfsw_directory_win32_uninit(drfsw_directory_win32* pDirectory)
869 if (pDirectory !=
NULL)
871 if (pDirectory->hDirectory !=
NULL)
873 CloseHandle(pDirectory->hDirectory);
874 pDirectory->hDirectory =
NULL;
877 drfsw_free(pDirectory->pFNIBuffer1);
878 pDirectory->pFNIBuffer1 =
NULL;
880 drfsw_free(pDirectory->pFNIBuffer2);
881 pDirectory->pFNIBuffer2 =
NULL;
885 DRFSW_PRIVATE
int drfsw_directory_win32_init(drfsw_directory_win32* pDirectory, drfsw_context_win32* pContext,
const char* absolutePath)
887 if (pDirectory !=
NULL)
889 pDirectory->pContext = pContext;
891 pDirectory->hDirectory =
NULL;
892 pDirectory->pFNIBuffer1 =
NULL;
893 pDirectory->pFNIBuffer2 =
NULL;
894 pDirectory->fniBufferSizeInBytes = 0;
895 pDirectory->flags = 0;
897 size_t length = strlen(absolutePath);
900 memcpy(pDirectory->absolutePath, absolutePath, length);
901 pDirectory->absolutePath[length] =
'\0';
903 wchar_t absolutePathWithBackSlashes[DRFSW_MAX_PATH_W];
904 if (drfsw_to_win32_path_wchar(absolutePath, absolutePathWithBackSlashes))
906 pDirectory->hDirectory = CreateFileW(
907 absolutePathWithBackSlashes,
909 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
912 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
914 if (pDirectory->hDirectory != INVALID_HANDLE_VALUE)
922 ZeroMemory(&pDirectory->overlapped,
sizeof(pDirectory->overlapped));
923 pDirectory->overlapped.hEvent = pDirectory;
925 pDirectory->fniBufferSizeInBytes = WIN32_RDC_FNI_COUNT *
sizeof(FILE_NOTIFY_INFORMATION);
926 pDirectory->pFNIBuffer1 = (FILE_NOTIFY_INFORMATION*)drfsw_malloc(pDirectory->fniBufferSizeInBytes);
927 pDirectory->pFNIBuffer2 = (FILE_NOTIFY_INFORMATION*)drfsw_malloc(pDirectory->fniBufferSizeInBytes);
928 if (pDirectory->pFNIBuffer1 !=
NULL && pDirectory->pFNIBuffer2 !=
NULL)
937 drfsw_directory_win32_uninit(pDirectory);
942 drfsw_directory_win32_uninit(pDirectory);
947 drfsw_directory_win32_uninit(pDirectory);
955 DRFSW_PRIVATE
int drfsw_directory_win32_schedulewatch(drfsw_directory_win32* pDirectory)
957 if (pDirectory !=
NULL)
959 pDirectory->flags |= WIN32_RDC_PENDING_WATCH;
960 QueueUserAPC(drfsw_win32_schedulewatchAPC, pDirectory->pContext->hThread, (ULONG_PTR)pDirectory);
968 DRFSW_PRIVATE
int drfsw_directory_win32_scheduledelete(drfsw_directory_win32* pDirectory)
970 if (pDirectory !=
NULL)
972 pDirectory->flags |= WIN32_RDC_PENDING_DELETE;
973 QueueUserAPC(drfsw_win32_cancelioAPC, pDirectory->pContext->hThread, (ULONG_PTR)pDirectory);
981 DRFSW_PRIVATE
int drfsw_directory_win32_beginwatch(drfsw_directory_win32* pDirectory)
985 if (pDirectory !=
NULL)
987 DWORD dwNotifyFilter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION;
989 if (ReadDirectoryChangesW(pDirectory->hDirectory, pDirectory->pFNIBuffer1, pDirectory->fniBufferSizeInBytes,
TRUE, dwNotifyFilter, &dwBytes, &pDirectory->overlapped, drfsw_win32_completionroutine))
991 pDirectory->flags &= ~WIN32_RDC_PENDING_WATCH;
1002 DRFSW_PRIVATE
int drfsw_directory_list_win32_init(drfsw_directory_list_win32* pDirectories)
1004 if (pDirectories !=
NULL)
1006 drfsw_list_init(&pDirectories->list);
1009 if (pDirectories->hLock !=
NULL)
1018 DRFSW_PRIVATE
void drfsw_directory_list_win32_uninit(drfsw_directory_list_win32* pDirectories)
1020 if (pDirectories !=
NULL)
1022 drfsw_list_uninit(&pDirectories->list);
1024 CloseHandle(pDirectories->hLock);
1025 pDirectories->hLock =
NULL;
1033 DRFSW_PRIVATE VOID
CALLBACK drfsw_win32_completionroutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
1035 drfsw_directory_win32* pDirectory = (drfsw_directory_win32*)lpOverlapped->hEvent;
1036 if (pDirectory !=
NULL)
1038 if (dwErrorCode == ERROR_OPERATION_ABORTED)
1043 drfsw_context_win32* pContext = pDirectory->pContext;
1044 drfsw_directory_win32_uninit(pDirectory);
1045 drfsw_free(pDirectory);
1047 ReleaseSemaphore(pContext->hDeleteDirSemaphore, 1,
NULL);
1051 assert(dwNumberOfBytesTransfered >=
sizeof(FILE_NOTIFY_INFORMATION));
1057 FILE_NOTIFY_INFORMATION* temp = pDirectory->pFNIBuffer1;
1058 pDirectory->pFNIBuffer1 = pDirectory->pFNIBuffer2;
1059 pDirectory->pFNIBuffer2 = temp;
1065 drfsw_directory_win32_schedulewatch(pDirectory);
1072 drfsw_context_win32* pContext = pDirectory->pContext;
1075 FILE_NOTIFY_INFORMATION* pFNI = pDirectory->pFNIBuffer2;
1079 if (drfsw_from_win32_path(pFNI->FileName, pFNI->FileNameLength /
sizeof(
wchar_t), relativePath))
1082 if (drfsw_make_absolute_path(pDirectory->absolutePath, relativePath, absolutePath))
1084 switch (pFNI->Action)
1086 case FILE_ACTION_ADDED:
1091 drfsw_postevent_win32(pContext, &e);
1097 case FILE_ACTION_REMOVED:
1102 drfsw_postevent_win32(pContext, &e);
1108 case FILE_ACTION_RENAMED_OLD_NAME:
1110 drfsw_strcpy(absolutePathOld,
sizeof(absolutePathOld), absolutePath);
1111 drfsw_strcpy(absoluteBasePathOld,
sizeof(absoluteBasePathOld), pDirectory->absolutePath);
1115 case FILE_ACTION_RENAMED_NEW_NAME:
1118 if (drfsw_event_init(&e,
drfsw_event_type_renamed, absolutePathOld, absolutePath, absoluteBasePathOld, pDirectory->absolutePath))
1120 drfsw_postevent_win32(pContext, &e);
1126 case FILE_ACTION_MODIFIED:
1131 drfsw_postevent_win32(pContext, &e);
1144 if (pFNI->NextEntryOffset == 0)
1149 pFNI = (FILE_NOTIFY_INFORMATION*)(((
char*)pFNI) + pFNI->NextEntryOffset);
1154 DRFSW_PRIVATE VOID
CALLBACK drfsw_win32_schedulewatchAPC(ULONG_PTR dwParam)
1156 drfsw_directory_win32* pDirectory = (drfsw_directory_win32*)dwParam;
1157 if (pDirectory !=
NULL)
1159 if ((pDirectory->flags & WIN32_RDC_PENDING_WATCH) != 0)
1161 drfsw_directory_win32_beginwatch(pDirectory);
1166 DRFSW_PRIVATE VOID
CALLBACK drfsw_win32_cancelioAPC(ULONG_PTR dwParam)
1168 drfsw_directory_win32* pDirectory = (drfsw_directory_win32*)dwParam;
1169 if (pDirectory !=
NULL)
1171 if ((pDirectory->flags & WIN32_RDC_PENDING_DELETE) != 0)
1177 CancelIo(pDirectory->hDirectory);
1182 for (
unsigned int i = 0; i < pDirectory->pContext->watchedDirectories.list.count; ++i)
1184 if (pDirectory == pDirectory->pContext->watchedDirectories.list.buffer[i])
1186 drfsw_list_removebyindex(&pDirectory->pContext->watchedDirectories.list, i);
1197 DRFSW_PRIVATE DWORD WINAPI _WatcherThreadProc_RDC(drfsw_context_win32 *pContextRDC)
1199 while (!pContextRDC->terminateThread)
1203 DWORD rc = WaitForSingleObjectEx(pContextRDC->hTerminateEvent, INFINITE,
TRUE);
1206 case WAIT_OBJECT_0 + 0:
1209 pContextRDC->terminateThread =
TRUE;
1213 case WAIT_IO_COMPLETION:
1227 drfsw_context_win32* pContext = (drfsw_context_win32*)drfsw_malloc(
sizeof(drfsw_context_win32));
1228 if (pContext !=
NULL)
1230 if (drfsw_directory_list_win32_init(&pContext->watchedDirectories))
1232 if (drfsw_event_queue_init(&pContext->eventQueue))
1235 pContext->hDeleteDirSemaphore = CreateSemaphoreW(
NULL, 0, 1,
NULL);
1236 pContext->terminateThread =
FALSE;
1238 if (pContext->hTerminateEvent !=
NULL)
1240 pContext->hThread = CreateThread(
NULL, 0, (LPTHREAD_START_ROUTINE)_WatcherThreadProc_RDC, pContext, 0,
NULL);
1241 if (pContext->hThread !=
NULL)
1247 CloseHandle(pContext->hTerminateEvent);
1249 drfsw_free(pContext);
1255 drfsw_free(pContext);
1265 DRFSW_PRIVATE
void drfsw_delete_context_win32(drfsw_context_win32* pContext)
1267 if (pContext !=
NULL)
1270 drfsw_remove_all_directories_win32(pContext);
1274 SignalObjectAndWait(pContext->hTerminateEvent, pContext->hThread, INFINITE,
FALSE);
1277 CloseHandle(pContext->hThread);
1278 pContext->hThread =
NULL;
1283 WaitForSingleObject(pContext->eventQueue.hLock, INFINITE);
1284 drfsw_event_queue_uninit(&pContext->eventQueue);
1288 CloseHandle(pContext->hTerminateEvent);
1289 pContext->hTerminateEvent =
NULL;
1293 CloseHandle(pContext->hDeleteDirSemaphore);
1294 pContext->hDeleteDirSemaphore =
NULL;
1297 drfsw_directory_list_win32_uninit(&pContext->watchedDirectories);
1300 drfsw_free(pContext);
1304 DRFSW_PRIVATE drfsw_directory_win32* drfsw_find_directory_win32(drfsw_context_win32* pContext,
const char* absolutePath,
unsigned int* pIndexOut)
1306 assert(pContext !=
NULL);
1308 for (
unsigned int iDirectory = 0; iDirectory < pContext->watchedDirectories.list.count; ++iDirectory)
1310 drfsw_directory_win32* pDirectory = (drfsw_directory_win32*)pContext->watchedDirectories.list.buffer[iDirectory];
1311 if (pDirectory !=
NULL)
1313 if (strcmp(absolutePath, pDirectory->absolutePath) == 0)
1315 if (pIndexOut !=
NULL)
1317 *pIndexOut = iDirectory;
1328 DRFSW_PRIVATE
int drfsw_add_directory_win32(drfsw_context_win32* pContext,
const char* absolutePath)
1330 if (pContext !=
NULL)
1332 drfsw_directory_win32* pDirectory = (drfsw_directory_win32*)drfsw_malloc(
sizeof(drfsw_directory_win32));
1333 if (pDirectory !=
NULL)
1335 if (!drfsw_is_watching_directory_win32(pContext, absolutePath))
1337 if (drfsw_directory_win32_init(pDirectory, pContext, absolutePath))
1343 WaitForSingleObject(pContext->watchedDirectories.hLock, INFINITE);
1345 drfsw_list_pushback(&pContext->watchedDirectories.list, pDirectory);
1347 SetEvent(pContext->watchedDirectories.hLock);
1350 drfsw_directory_win32_schedulewatch(pDirectory);
1357 drfsw_free(pDirectory);
1363 drfsw_free(pDirectory);
1375 DRFSW_PRIVATE
void drfsw_remove_directory_win32_no_lock(drfsw_context_win32* pContext,
const char* absolutePath)
1377 assert(pContext !=
NULL);
1380 drfsw_directory_win32* pDirectory = drfsw_find_directory_win32(pContext, absolutePath, &index);
1381 if (pDirectory !=
NULL)
1388 drfsw_directory_win32_scheduledelete(pDirectory);
1392 WaitForSingleObject(pContext->hDeleteDirSemaphore, INFINITE);
1396 DRFSW_PRIVATE
void drfsw_remove_directory_win32(drfsw_context_win32* pContext,
const char* absolutePath)
1398 if (pContext !=
NULL)
1400 WaitForSingleObject(pContext->watchedDirectories.hLock, INFINITE);
1402 drfsw_remove_directory_win32_no_lock(pContext, absolutePath);
1404 SetEvent(pContext->watchedDirectories.hLock);
1408 DRFSW_PRIVATE
void drfsw_remove_all_directories_win32(drfsw_context_win32* pContext)
1410 if (pContext !=
NULL)
1412 WaitForSingleObject(pContext->watchedDirectories.hLock, INFINITE);
1414 for (
unsigned int i = pContext->watchedDirectories.list.count; i > 0; --i)
1416 drfsw_remove_directory_win32_no_lock(pContext, ((drfsw_directory_win32*)pContext->watchedDirectories.list.buffer[i - 1])->absolutePath);
1419 SetEvent(pContext->watchedDirectories.hLock);
1423 DRFSW_PRIVATE
int drfsw_is_watching_directory_win32(drfsw_context_win32* pContext,
const char* absolutePath)
1425 if (pContext !=
NULL)
1427 return drfsw_find_directory_win32(pContext, absolutePath,
NULL) !=
NULL;
1434 DRFSW_PRIVATE
int drfsw_next_event_win32(drfsw_context_win32* pContext,
drfsw_event* pEvent)
1437 if (pContext !=
NULL && !pContext->terminateThread)
1441 hEvents[0] = pContext->hThread;
1442 hEvents[1] = pContext->eventQueue.hSemaphore;
1444 DWORD rc = WaitForMultipleObjects(
sizeof(hEvents) /
sizeof(hEvents[0]), hEvents,
FALSE, INFINITE);
1447 case WAIT_OBJECT_0 + 0:
1454 case WAIT_OBJECT_0 + 1:
1458 if (!pContext->terminateThread)
1460 DWORD eventLockResult = WaitForSingleObject(pContext->eventQueue.hLock, INFINITE);
1461 if (eventLockResult == WAIT_OBJECT_0)
1463 drfsw_event_queue_pop(&pContext->eventQueue, pEvent);
1465 SetEvent(pContext->eventQueue.hLock);
1467 if (eventLockResult == WAIT_OBJECT_0)
1488 DRFSW_PRIVATE
int drfsw_peek_event_win32(drfsw_context_win32* pContext,
drfsw_event* pEvent)
1491 if (pContext !=
NULL)
1493 DWORD eventLockResult = WaitForSingleObject(pContext->eventQueue.hLock, INFINITE);
1496 WaitForSingleObject(pContext->eventQueue.hSemaphore, 0);
1499 if (eventLockResult == WAIT_OBJECT_0)
1501 if (drfsw_event_queue_getcount(&pContext->eventQueue) > 0)
1503 drfsw_event_queue_pop(&pContext->eventQueue, pEvent);
1517 SetEvent(pContext->eventQueue.hLock);
1523 DRFSW_PRIVATE
void drfsw_postevent_win32(drfsw_context_win32* pContext,
drfsw_event* pEvent)
1525 if (pContext !=
NULL && pEvent !=
NULL)
1528 WaitForSingleObject(pContext->eventQueue.hLock, INFINITE);
1530 drfsw_event_queue_pushback(&pContext->eventQueue, pEvent);
1532 SetEvent(pContext->eventQueue.hLock);
1536 ReleaseSemaphore(pContext->eventQueue.hSemaphore, 1,
NULL);
1547 return drfsw_create_context_win32();
1552 drfsw_delete_context_win32((drfsw_context_win32*)pContext);
1558 return drfsw_add_directory_win32((drfsw_context_win32*)pContext, absolutePath);
1563 drfsw_remove_directory_win32((drfsw_context_win32*)pContext, absolutePath);
1568 drfsw_remove_all_directories_win32((drfsw_context_win32*)pContext);
1573 return drfsw_is_watching_directory_win32((drfsw_context_win32*)pContext, absolutePath);
1579 return drfsw_next_event_win32((drfsw_context_win32*)pContext, pEventOut);
1584 return drfsw_peek_event_win32((drfsw_context_win32*)pContext, pEventOut);
1591 #if defined(__clang__)
1592 #pragma GCC diagnostic pop
1595 #endif //DR_FSW_IMPLEMENTATION