From e66849b1dc2691e4256d1262c3a902e3320b1a40 Mon Sep 17 00:00:00 2001 From: Vincent Torri Date: Mon, 2 Apr 2012 16:46:16 +0000 Subject: [PATCH] Eio: add file monitoring on Windows (might contain bugs, though) SVN revision: 69867 --- legacy/eio/src/lib/eio_monitor_win32.c | 238 ++++++++++++++++++++++++- 1 file changed, 237 insertions(+), 1 deletion(-) diff --git a/legacy/eio/src/lib/eio_monitor_win32.c b/legacy/eio/src/lib/eio_monitor_win32.c index 30d86b6b8f..d2949f35a2 100644 --- a/legacy/eio/src/lib/eio_monitor_win32.c +++ b/legacy/eio/src/lib/eio_monitor_win32.c @@ -28,10 +28,209 @@ * @cond LOCAL */ +typedef struct _Eio_Monitor_Win32_Watcher Eio_Monitor_Win32_Watcher; + +/* 4096 = 256 * sizeof(FILE_NOTIFY_INFORMATION) */ +# define EIO_MONITOR_WIN32_BUFFER_SIZE 4096 + +struct _Eio_Monitor_Win32_Watcher +{ + char buffer[EIO_MONITOR_WIN32_BUFFER_SIZE]; + OVERLAPPED overlapped; + HANDLE handle; + HANDLE event; + Eio_Monitor *monitor; + Ecore_Win32_Handler *h; + DWORD buf_length; + int is_dir; +}; + struct _Eio_Monitor_Backend { + Eio_Monitor *parent; + + Eio_Monitor_Win32_Watcher *file; + Eio_Monitor_Win32_Watcher *dir; }; +static Eina_Bool +_eio_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh __UNUSED__) +{ + char filename[PATH_MAX]; + PFILE_NOTIFY_INFORMATION fni; + Eio_Monitor_Win32_Watcher *w; + wchar_t *wname; + char *name; + DWORD filter; + DWORD offset; + DWORD buf_length; + int event = EIO_MONITOR_ERROR; + + w = (Eio_Monitor_Win32_Watcher *)data; + + if (!GetOverlappedResult(w->handle, &w->overlapped, &buf_length, TRUE)) + return ECORE_CALLBACK_RENEW; + + fni = (PFILE_NOTIFY_INFORMATION)w->buffer; + do { + if (!fni) + break; + offset = fni->NextEntryOffset; + + wname = (wchar_t *)malloc(sizeof(wchar_t) * (fni->FileNameLength + 1)); + if (!wname) + return 0; + + memcpy(wname, fni->FileName, fni->FileNameLength); + wname[fni->FileNameLength]='\0'; + name = evil_wchar_to_char(wname); + free(wname); + if (!name) + return ECORE_CALLBACK_CANCEL; + + _snprintf(filename, PATH_MAX, "%s\\%s", w->monitor->path, name); + free(name); + + switch (fni->Action) + { + case FILE_ACTION_ADDED: + if (w->is_dir) + event = EIO_MONITOR_DIRECTORY_CREATED; + else + event = EIO_MONITOR_FILE_CREATED; + break; + case FILE_ACTION_REMOVED: + if (w->is_dir) + event = EIO_MONITOR_DIRECTORY_DELETED; + else + event = EIO_MONITOR_FILE_DELETED; + break; + case FILE_ACTION_MODIFIED: + if (!w->is_dir) + event = EIO_MONITOR_FILE_MODIFIED; + break; + case FILE_ACTION_RENAMED_OLD_NAME: + if (w->is_dir) + event = EIO_MONITOR_DIRECTORY_DELETED; + else + event = EIO_MONITOR_FILE_DELETED; + break; + case FILE_ACTION_RENAMED_NEW_NAME: + if (w->is_dir) + event = EIO_MONITOR_DIRECTORY_CREATED; + else + event = EIO_MONITOR_FILE_CREATED; + break; + default: + fprintf(stderr, "unknown event\n"); + event = EIO_MONITOR_ERROR; + break; + } + if (event != EIO_MONITOR_ERROR) + _eio_monitor_send(w->monitor, filename, event); + + fni = (PFILE_NOTIFY_INFORMATION)((LPBYTE)fni + offset); + } while (offset); + + filter = (w->is_dir == 0) ? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME; + filter |= + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_SECURITY; + + ReadDirectoryChangesW(w->handle, + w->buffer, + EIO_MONITOR_WIN32_BUFFER_SIZE, + FALSE, + filter, + &w->buf_length, + &w->overlapped, + NULL); + + return ECORE_CALLBACK_RENEW; +} + +static Eio_Monitor_Win32_Watcher * +_eio_monitor_win32_watcher_new(Eio_Monitor *monitor, unsigned char is_dir) +{ + Eio_Monitor_Win32_Watcher *w; + DWORD filter; + + w = (Eio_Monitor_Win32_Watcher *)calloc(1, sizeof(Eio_Monitor_Win32_Watcher)); + if (!w) return NULL; + + w->handle = CreateFile(monitor->path, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ | + FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OVERLAPPED, + NULL); + if (w->handle == INVALID_HANDLE_VALUE) + goto free_w; + + w->event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!w->event) + goto close_handle; + + ZeroMemory (&w->overlapped, sizeof(w->overlapped)); + w->overlapped.hEvent = w->event; + + filter = (is_dir == 0) ? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME; + filter |= + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_SECURITY; + + if (!ReadDirectoryChangesW(w->handle, + w->buffer, + EIO_MONITOR_WIN32_BUFFER_SIZE, + FALSE, + filter, + &w->buf_length, + &w->overlapped, + NULL)) + goto close_event; + + w->h = ecore_main_win32_handler_add(w->event, + _eio_monitor_win32_cb, + w); + if (!w->h) + goto close_event; + + w->monitor = monitor; + w->is_dir = is_dir; + + return w; + + close_event: + CloseHandle(w->event); + close_handle: + CloseHandle(w->handle); + free_w: + free(w); + + return NULL; +} + +static void +_eio_monitor_win32_watcher_free(Eio_Monitor_Win32_Watcher *w) +{ + if (!w) return; + + CloseHandle(w->event); + CloseHandle (w->handle); + free (w); +} + /** * @endcond */ @@ -46,7 +245,6 @@ struct _Eio_Monitor_Backend void eio_monitor_backend_init(void) { - abort(); } void eio_monitor_backend_shutdown(void) @@ -55,10 +253,48 @@ void eio_monitor_backend_shutdown(void) void eio_monitor_backend_add(Eio_Monitor *monitor) { + Eio_Monitor_Backend *backend; + + backend = calloc(1, sizeof (Eio_Monitor_Backend)); + if (!backend) + { + eio_monitor_fallback_add(monitor); + return; + } + + backend->parent = monitor; + backend->file = _eio_monitor_win32_watcher_new(monitor, 0); + if (!backend->file) + { + free(backend); + eio_monitor_fallback_add(monitor); + return; + } + + backend->dir = _eio_monitor_win32_watcher_new(monitor, 1); + if (!backend->dir) + { + _eio_monitor_win32_watcher_free(backend->file); + free(backend); + eio_monitor_fallback_add(monitor); + return; + } + + monitor->backend = backend; } void eio_monitor_backend_del(Eio_Monitor *monitor) { + if (!monitor->backend) + { + eio_monitor_fallback_del(monitor); + return ; + } + + _eio_monitor_win32_watcher_free(monitor->backend->file); + _eio_monitor_win32_watcher_free(monitor->backend->dir); + free(monitor->backend); + monitor->backend = NULL; }