static unsigned int __stdcall tr_watchdir_win32_thread (void * context) { const tr_watchdir_t handle = context; tr_watchdir_win32 * const backend = BACKEND_UPCAST (tr_watchdir_get_backend (handle)); DWORD bytes_transferred; while (tr_get_overlapped_result_ex (backend->fd, &backend->overlapped, &bytes_transferred, INFINITE, FALSE)) { PFILE_NOTIFY_INFORMATION info = (PFILE_NOTIFY_INFORMATION) backend->buffer; while (info->NextEntryOffset != 0) *((BYTE **) &info) += info->NextEntryOffset; info->NextEntryOffset = bytes_transferred - ((BYTE *) info - (BYTE *) backend->buffer); send (backend->notify_pipe[1], (const char *) backend->buffer, bytes_transferred, 0); if (!ReadDirectoryChangesW (backend->fd, backend->buffer, sizeof (backend->buffer), FALSE, WIN32_WATCH_MASK, NULL, &backend->overlapped, NULL)) { log_error ("Failed to read directory changes"); return 0; } } if (GetLastError () != ERROR_OPERATION_ABORTED) log_error ("Failed to wait for directory changes"); return 0; }
static void tr_watchdir_win32_free (tr_watchdir_backend * backend_base) { tr_watchdir_win32 * const backend = BACKEND_UPCAST (backend_base); if (backend == NULL) return; assert (backend->base.free_func == &tr_watchdir_win32_free); if (backend->fd != INVALID_HANDLE_VALUE) CancelIoEx (backend->fd, &backend->overlapped); if (backend->thread != NULL) { WaitForSingleObject (backend->thread, INFINITE); CloseHandle (backend->thread); } if (backend->event != NULL) bufferevent_free (backend->event); if (backend->notify_pipe[0] != TR_BAD_SOCKET) evutil_closesocket (backend->notify_pipe[0]); if (backend->notify_pipe[1] != TR_BAD_SOCKET) evutil_closesocket (backend->notify_pipe[1]); if (backend->fd != INVALID_HANDLE_VALUE) CloseHandle (backend->fd); tr_free (backend); }
static void tr_watchdir_kqueue_free (tr_watchdir_backend * backend_base) { tr_watchdir_kqueue * const backend = BACKEND_UPCAST (backend_base); if (backend == NULL) return; assert (backend->base.free_func == &tr_watchdir_kqueue_free); if (backend->event != NULL) { event_del (backend->event); event_free (backend->event); } if (backend->kq != -1) close (backend->kq); if (backend->dirfd != -1) close (backend->dirfd); tr_ptrArrayDestruct (&backend->dir_entries, &tr_free); tr_free (backend); }
static void tr_watchdir_inotify_on_event (struct bufferevent * event, void * context) { assert (context != NULL); const tr_watchdir_t handle = context; tr_watchdir_inotify * const backend = BACKEND_UPCAST (tr_watchdir_get_backend (handle)); struct inotify_event ev; size_t nread; size_t name_size = NAME_MAX + 1; char * name = tr_new (char, name_size); /* Read the size of the struct excluding name into buf. Guaranteed to have at least sizeof (ev) available */ while ((nread = bufferevent_read (event, &ev, sizeof (ev))) != 0) { if (nread == (size_t) -1) { log_error ("Failed to read inotify event: %s", tr_strerror (errno)); break; } if (nread != sizeof (ev)) { log_error ("Failed to read inotify event: expected %zu, got %zu bytes.", sizeof (ev), nread); break; } assert (ev.wd == backend->inwd); assert ((ev.mask & INOTIFY_WATCH_MASK) != 0); assert (ev.len > 0); if (ev.len > name_size) { name_size = ev.len; name = tr_renew (char, name, name_size); } /* Consume entire name into buffer */ if ((nread = bufferevent_read (event, name, ev.len)) == (size_t) -1) { log_error ("Failed to read inotify name: %s", tr_strerror (errno)); break; } if (nread != ev.len) { log_error ("Failed to read inotify name: expected %" PRIu32 ", got %zu bytes.", ev.len, nread); break; } tr_watchdir_process (handle, name); }
static void tr_watchdir_kqueue_on_event (evutil_socket_t fd UNUSED, short type UNUSED, void * context) { const tr_watchdir_t handle = context; tr_watchdir_kqueue * const backend = BACKEND_UPCAST (tr_watchdir_get_backend (handle)); struct kevent ke; const struct timespec ts = { 0, 0 }; if (kevent (backend->kq, NULL, 0, &ke, 1, &ts) == -1) { log_error ("Failed to fetch kevent: %s", tr_strerror (errno)); return; } /* Read directory with generic scan */ tr_watchdir_scan (handle, &backend->dir_entries); }