summaryrefslogtreecommitdiff
path: root/src/lib/eio/eio_monitor_win32.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/eio/eio_monitor_win32.c')
-rw-r--r--src/lib/eio/eio_monitor_win32.c425
1 files changed, 425 insertions, 0 deletions
diff --git a/src/lib/eio/eio_monitor_win32.c b/src/lib/eio/eio_monitor_win32.c
new file mode 100644
index 0000000..50404e2
--- /dev/null
+++ b/src/lib/eio/eio_monitor_win32.c
@@ -0,0 +1,425 @@
1/* EIO - EFL data type library
2 * Copyright (C) 2011 Enlightenment Developers:
3 * Cedric Bail <cedric.bail@free.fr>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library;
17 * if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "eio_private.h"
21#include "Eio.h"
22
23/*============================================================================*
24 * Local *
25 *============================================================================*/
26
27/**
28 * @cond LOCAL
29 */
30
31typedef struct _Eio_Monitor_Win32_Watcher Eio_Monitor_Win32_Watcher;
32
33/* 4096 = 256 * sizeof(FILE_NOTIFY_INFORMATION) */
34# define EIO_MONITOR_WIN32_BUFFER_SIZE 4096
35
36struct _Eio_Monitor_Win32_Watcher
37{
38 char buffer[EIO_MONITOR_WIN32_BUFFER_SIZE];
39 OVERLAPPED overlapped;
40 HANDLE handle;
41 HANDLE event;
42 Eio_Monitor *monitor;
43 Ecore_Win32_Handler *h;
44 char *current;
45 char *file;
46 DWORD buf_length;
47 Eina_Bool monitor_file : 1;
48 Eina_Bool monitor_parent : 1;
49};
50
51struct _Eio_Monitor_Backend
52{
53 Eio_Monitor *parent;
54 Eio_Monitor_Win32_Watcher *watcher_file;
55 Eio_Monitor_Win32_Watcher *watcher_dir;
56 Eio_Monitor_Win32_Watcher *watcher_parent;
57};
58
59static Eina_Bool _eio_monitor_win32_native = EINA_FALSE;
60
61static Eina_Bool
62_eio_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh EINA_UNUSED)
63{
64 PFILE_NOTIFY_INFORMATION fni;
65 Eio_Monitor_Win32_Watcher *w;
66 wchar_t *wname;
67 char *name;
68 DWORD filter;
69 DWORD offset;
70 DWORD buf_length;
71 int event;
72
73 w = (Eio_Monitor_Win32_Watcher *)data;
74
75 if (!GetOverlappedResult(w->handle, &w->overlapped, &buf_length, TRUE))
76 return ECORE_CALLBACK_RENEW;
77
78 fni = (PFILE_NOTIFY_INFORMATION)w->buffer;
79 do {
80 if (!fni)
81 break;
82 offset = fni->NextEntryOffset;
83
84 wname = (wchar_t *)malloc(fni->FileNameLength + sizeof(wchar_t));
85 if (!wname)
86 return 0;
87
88 memcpy(wname, fni->FileName, fni->FileNameLength);
89 wname[fni->FileNameLength / sizeof(wchar_t)] = 0;
90 name = evil_wchar_to_char(wname);
91 free(wname);
92 if (!name)
93 return ECORE_CALLBACK_CANCEL;
94
95 event = -1;
96 switch (fni->Action)
97 {
98 case FILE_ACTION_ADDED:
99 if (!w->monitor_parent)
100 {
101 if (w->monitor_file)
102 event = EIO_MONITOR_FILE_CREATED;
103 else
104 event = EIO_MONITOR_DIRECTORY_CREATED;
105 }
106 break;
107 case FILE_ACTION_REMOVED:
108 if (w->monitor_parent)
109 {
110 char path[MAX_PATH];
111 char *res;
112
113 res = _fullpath(path, name, MAX_PATH);
114 if (res && (strcmp(res, w->current) == 0))
115 event = EIO_MONITOR_SELF_DELETED;
116 }
117 else
118 {
119 if (w->monitor_file)
120 event = EIO_MONITOR_FILE_DELETED;
121 else
122 event = EIO_MONITOR_DIRECTORY_DELETED;
123 }
124 break;
125 case FILE_ACTION_MODIFIED:
126 if (!w->monitor_parent)
127 {
128 if (w->monitor_file)
129 event = EIO_MONITOR_FILE_MODIFIED;
130 else
131 event = EIO_MONITOR_DIRECTORY_MODIFIED;
132 }
133 break;
134 case FILE_ACTION_RENAMED_OLD_NAME:
135 if (!w->monitor_parent)
136 {
137 if (w->monitor_file)
138 event = EIO_MONITOR_FILE_DELETED;
139 else
140 event = EIO_MONITOR_DIRECTORY_DELETED;
141 }
142 break;
143 case FILE_ACTION_RENAMED_NEW_NAME:
144 if (!w->monitor_parent)
145 {
146 if (w->monitor_file)
147 event = EIO_MONITOR_FILE_CREATED;
148 else
149 event = EIO_MONITOR_DIRECTORY_CREATED;
150 }
151 break;
152 default:
153 ERR("unknown event");
154 event = EIO_MONITOR_ERROR;
155 break;
156 }
157
158 if (event >= 0)
159 _eio_monitor_send(w->monitor, name, event);
160
161 free(name);
162
163 fni = (PFILE_NOTIFY_INFORMATION)((LPBYTE)fni + offset);
164 } while (offset);
165
166 filter =
167 FILE_NOTIFY_CHANGE_ATTRIBUTES |
168 FILE_NOTIFY_CHANGE_SIZE |
169 FILE_NOTIFY_CHANGE_LAST_WRITE |
170 FILE_NOTIFY_CHANGE_LAST_ACCESS |
171 FILE_NOTIFY_CHANGE_CREATION |
172 FILE_NOTIFY_CHANGE_SECURITY;
173 if (w->monitor_file)
174 filter |= FILE_NOTIFY_CHANGE_FILE_NAME;
175 else
176 filter |= FILE_NOTIFY_CHANGE_DIR_NAME;
177
178 ReadDirectoryChangesW(w->handle,
179 (LPVOID)w->buffer,
180 EIO_MONITOR_WIN32_BUFFER_SIZE,
181 FALSE,
182 filter,
183 &w->buf_length,
184 &w->overlapped,
185 NULL);
186
187 return ECORE_CALLBACK_RENEW;
188}
189
190static Eio_Monitor_Win32_Watcher *
191_eio_monitor_win32_watcher_new(Eio_Monitor *monitor,
192 char *current,
193 char *file,
194 Eina_Bool monitor_file,
195 Eina_Bool monitor_parent)
196{
197 Eio_Monitor_Win32_Watcher *w;
198 char *monitored;
199 DWORD filter;
200
201 w = (Eio_Monitor_Win32_Watcher *)calloc(1, sizeof(Eio_Monitor_Win32_Watcher));
202 if (!w) return NULL;
203
204 if (!monitor_parent)
205 monitored = current;
206 else
207 {
208 char *tmp;
209
210 tmp = strrchr(current, '\\');
211 monitored = (char *)alloca((tmp - current) + 1);
212 memcpy(monitored, current, tmp - current);
213 monitored[tmp - current] = '\0';
214 }
215
216 w->handle = CreateFile(monitored,
217 FILE_LIST_DIRECTORY,
218 FILE_SHARE_READ |
219 FILE_SHARE_WRITE,
220 NULL,
221 OPEN_EXISTING,
222 FILE_FLAG_BACKUP_SEMANTICS |
223 FILE_FLAG_OVERLAPPED,
224 NULL);
225 if (w->handle == INVALID_HANDLE_VALUE)
226 goto free_w;
227
228 w->event = CreateEvent(NULL, FALSE, FALSE, NULL);
229 if (!w->event)
230 goto close_handle;
231
232 ZeroMemory (&w->overlapped, sizeof(w->overlapped));
233 w->overlapped.hEvent = w->event;
234
235 filter =
236 FILE_NOTIFY_CHANGE_ATTRIBUTES |
237 FILE_NOTIFY_CHANGE_SIZE |
238 FILE_NOTIFY_CHANGE_LAST_WRITE |
239 FILE_NOTIFY_CHANGE_LAST_ACCESS |
240 FILE_NOTIFY_CHANGE_CREATION |
241 FILE_NOTIFY_CHANGE_SECURITY;
242 if (monitor_file)
243 filter |= FILE_NOTIFY_CHANGE_FILE_NAME;
244 else
245 filter |= FILE_NOTIFY_CHANGE_DIR_NAME;
246
247 if (!ReadDirectoryChangesW(w->handle,
248 (LPVOID)w->buffer,
249 EIO_MONITOR_WIN32_BUFFER_SIZE,
250 FALSE,
251 filter,
252 &w->buf_length,
253 &w->overlapped,
254 NULL))
255 {
256 char *msg;
257
258 msg = evil_last_error_get();
259 if (msg)
260 {
261 ERR("%s", msg);
262 free(msg);
263 }
264 goto close_event;
265 }
266
267 w->h = ecore_main_win32_handler_add(w->event,
268 _eio_monitor_win32_cb,
269 w);
270 if (!w->h)
271 goto close_event;
272
273 w->monitor = monitor;
274 w->monitor_file = monitor_file;
275 w->monitor_parent = monitor_parent;
276 w->file = file;
277 w->current = current;
278
279 return w;
280
281 close_event:
282 CloseHandle(w->event);
283 close_handle:
284 CloseHandle(w->handle);
285 free_w:
286 free(w);
287
288 return NULL;
289}
290
291static void
292_eio_monitor_win32_watcher_free(Eio_Monitor_Win32_Watcher *w)
293{
294 if (!w) return;
295
296 if (w->file)
297 free(w->file);
298 free(w->current);
299 CloseHandle(w->event);
300 CloseHandle (w->handle);
301 free (w);
302}
303
304/**
305 * @endcond
306 */
307
308/*============================================================================*
309 * Global *
310 *============================================================================*/
311
312/**
313 * @cond LOCAL
314 */
315
316void eio_monitor_backend_init(void)
317{
318}
319
320void eio_monitor_backend_shutdown(void)
321{
322}
323
324void eio_monitor_backend_add(Eio_Monitor *monitor)
325{
326 char path[PATH_MAX];
327 struct _stat s;
328 char *res;
329 char *current;
330 char *file = NULL;
331 Eio_Monitor_Backend *backend;
332 int ret;
333
334 res = _fullpath(path, monitor->path, MAX_PATH);
335 if (!res)
336 goto fallback;
337
338 ret = _stat(res, &s);
339 if (ret != 0)
340 goto fallback;
341
342 if (_S_IFDIR & s.st_mode)
343 {
344 current = strdup(path);
345 if (!current)
346 goto fallback;
347 }
348 else if (_S_IFREG & s.st_mode)
349 {
350 char *tmp;
351
352 tmp = strrchr(path, '\\');
353 file = strdup(tmp + 1);
354 if (!file)
355 goto fallback;
356
357 *tmp = '\0';
358 current = strdup(path);
359 if (!current)
360 {
361 free(file);
362 goto fallback;
363 }
364 }
365 else
366 goto fallback;
367
368 backend = calloc(1, sizeof (Eio_Monitor_Backend));
369 if (!backend)
370 goto fallback;
371
372 backend->parent = monitor;
373
374 backend->watcher_file = _eio_monitor_win32_watcher_new(monitor, current, file, EINA_TRUE, EINA_FALSE);
375 if (!backend->watcher_file)
376 goto free_backend;
377
378 backend->watcher_dir = _eio_monitor_win32_watcher_new(monitor, current, file, EINA_FALSE, EINA_FALSE);
379 if (!backend->watcher_dir)
380 goto free_backend_file;
381
382 backend->watcher_parent = _eio_monitor_win32_watcher_new(monitor, current, file, EINA_FALSE, EINA_TRUE);
383 if (!backend->watcher_parent)
384 goto free_backend_dir;
385
386 _eio_monitor_win32_native = EINA_TRUE;
387 monitor->backend = backend;
388
389 return;
390
391 free_backend_dir:
392 _eio_monitor_win32_watcher_free(backend->watcher_dir);
393 free_backend_file:
394 _eio_monitor_win32_watcher_free(backend->watcher_file);
395 free_backend:
396 free(backend);
397 fallback:
398 INF("falling back to poll monitoring");
399 eio_monitor_fallback_add(monitor);
400}
401
402void eio_monitor_backend_del(Eio_Monitor *monitor)
403{
404 if (!_eio_monitor_win32_native)
405 {
406 eio_monitor_fallback_del(monitor);
407 return ;
408 }
409
410 _eio_monitor_win32_watcher_free(monitor->backend->watcher_parent);
411 _eio_monitor_win32_watcher_free(monitor->backend->watcher_dir);
412 _eio_monitor_win32_watcher_free(monitor->backend->watcher_file);
413 free(monitor->backend);
414 monitor->backend = NULL;
415}
416
417
418/**
419 * @endcond
420 */
421
422
423/*============================================================================*
424 * API *
425 *============================================================================*/