summaryrefslogtreecommitdiff
path: root/legacy/ecore/src/lib/ecore_file/ecore_file_monitor_win32.c
diff options
context:
space:
mode:
authorVincent Torri <vincent.torri@gmail.com>2009-11-11 17:45:55 +0000
committerVincent Torri <vincent.torri@gmail.com>2009-11-11 17:45:55 +0000
commita2f8b6a5261e9a2ca47d773130d738cb7f1eea51 (patch)
tree7d62839f9d4364f5b19dd663442eb7200bbb9e0a /legacy/ecore/src/lib/ecore_file/ecore_file_monitor_win32.c
parent9f839063c82aaab96fbcb79fd32a3e9039eb1462 (diff)
Add Windows directory monitoring to ecore_file. It was tough.
A lot of thanks to Lars Munch for his great help SVN revision: 43617
Diffstat (limited to '')
-rw-r--r--legacy/ecore/src/lib/ecore_file/ecore_file_monitor_win32.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/legacy/ecore/src/lib/ecore_file/ecore_file_monitor_win32.c b/legacy/ecore/src/lib/ecore_file/ecore_file_monitor_win32.c
new file mode 100644
index 0000000000..b63d674ce4
--- /dev/null
+++ b/legacy/ecore/src/lib/ecore_file/ecore_file_monitor_win32.c
@@ -0,0 +1,310 @@
1/*
2 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3 */
4
5#ifdef HAVE_CONFIG_H
6# include <config.h>
7#endif
8
9#ifdef HAVE_NOTIFY_WIN32
10
11# define WIN32_LEAN_AND_MEAN
12# include <windows.h>
13# undef WIN32_LEAN_AND_MEAN
14# include <process.h>
15
16# include "ecore_file_private.h"
17
18
19typedef struct _Ecore_File_Monitor_Win32 Ecore_File_Monitor_Win32;
20typedef struct _Ecore_File_Monitor_Win32_Data Ecore_File_Monitor_Win32_Data;
21
22/* 4096 = 256 * sizeof(FILE_NOTIFY_INFORMATION) */
23# define ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE 4096
24# define ECORE_FILE_MONITOR_WIN32(x) ((Ecore_File_Monitor_Win32 *)(x))
25
26struct _Ecore_File_Monitor_Win32_Data
27{
28 char buffer[ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE];
29 OVERLAPPED overlapped;
30 HANDLE handle;
31 HANDLE event;
32 Ecore_File_Monitor *monitor;
33 Ecore_Win32_Handler *h;
34 DWORD buf_length;
35 int is_dir;
36};
37
38struct _Ecore_File_Monitor_Win32
39{
40 Ecore_File_Monitor monitor;
41 Ecore_File_Monitor_Win32_Data *file;
42 Ecore_File_Monitor_Win32_Data *dir;
43};
44
45static Ecore_File_Monitor *_monitors = NULL;
46
47static int _ecore_file_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh);
48
49
50static Ecore_File_Monitor_Win32_Data *
51_ecore_file_monitor_win32_data_new(Ecore_File_Monitor *monitor, int type)
52{
53 Ecore_File_Monitor_Win32_Data *md;
54 DWORD filter;
55
56 md = (Ecore_File_Monitor_Win32_Data *)calloc(1, sizeof(Ecore_File_Monitor_Win32_Data));
57 if (!md) return NULL;
58
59 md->handle = CreateFile(monitor->path,
60 FILE_LIST_DIRECTORY,
61 FILE_SHARE_READ |
62 FILE_SHARE_WRITE,
63 NULL,
64 OPEN_EXISTING,
65 FILE_FLAG_BACKUP_SEMANTICS |
66 FILE_FLAG_OVERLAPPED,
67 NULL);
68 if (md->handle == INVALID_HANDLE_VALUE)
69 goto free_md;
70
71 md->event = CreateEvent(NULL, FALSE, FALSE, NULL);
72 if (!md->event)
73 goto close_handle;
74
75 ZeroMemory (&md->overlapped, sizeof(md->overlapped));
76 md->overlapped.hEvent = md->event;
77
78 filter = (type == 0) ? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
79 filter |=
80 FILE_NOTIFY_CHANGE_ATTRIBUTES |
81 FILE_NOTIFY_CHANGE_SIZE |
82 FILE_NOTIFY_CHANGE_LAST_WRITE |
83 FILE_NOTIFY_CHANGE_LAST_ACCESS |
84 FILE_NOTIFY_CHANGE_CREATION |
85 FILE_NOTIFY_CHANGE_SECURITY;
86
87 if (!ReadDirectoryChangesW(md->handle,
88 md->buffer,
89 ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE,
90 FALSE,
91 filter,
92 &md->buf_length,
93 &md->overlapped,
94 NULL))
95 goto close_event;
96
97 md->h = ecore_main_win32_handler_add(md->event,
98 _ecore_file_monitor_win32_cb,
99 md);
100 if (!md->h)
101 goto close_event;
102
103 md->monitor = monitor;
104 md->is_dir = type;
105
106 return md;
107
108 close_event:
109 CloseHandle(md->event);
110 close_handle:
111 CloseHandle(md->handle);
112 free_md:
113 free(md);
114
115 return NULL;
116}
117
118static void
119_ecore_file_monitor_win32_data_free(Ecore_File_Monitor_Win32_Data *md)
120{
121 if (!md) return;
122
123 CloseHandle(md->event);
124 CloseHandle (md->handle);
125 free (md);
126}
127
128static int
129_ecore_file_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh)
130{
131 char filename[PATH_MAX];
132 PFILE_NOTIFY_INFORMATION fni;
133 Ecore_File_Monitor_Win32_Data *md;
134 wchar_t *wname;
135 char *name;
136 DWORD filter;
137 DWORD offset;
138 DWORD buf_length;
139 Ecore_File_Event event = ECORE_FILE_EVENT_NONE;
140
141 md = (Ecore_File_Monitor_Win32_Data *)data;
142
143 if (!GetOverlappedResult (md->handle, &md->overlapped, &buf_length, TRUE))
144 return 1;
145
146 fni = (PFILE_NOTIFY_INFORMATION)md->buffer;
147 do {
148 if (!fni)
149 break;
150 offset = fni->NextEntryOffset;
151
152 wname = (wchar_t *)malloc(sizeof(wchar_t) * (fni->FileNameLength + 1));
153 if (!wname)
154 return 0;
155
156 memcpy(wname, fni->FileName, fni->FileNameLength);
157 wname[fni->FileNameLength]='\0';
158 name = evil_wchar_to_char(wname);
159 free(wname);
160 if (!name)
161 return 0;
162
163 _snprintf(filename, PATH_MAX, "%s\\%s", md->monitor->path, name);
164 free(name);
165
166 switch (fni->Action)
167 {
168 case FILE_ACTION_ADDED:
169 if (md->is_dir)
170 event = ECORE_FILE_EVENT_CREATED_DIRECTORY;
171 else
172 event = ECORE_FILE_EVENT_CREATED_FILE;
173 break;
174 case FILE_ACTION_REMOVED:
175 if (md->is_dir)
176 event = ECORE_FILE_EVENT_DELETED_DIRECTORY;
177 else
178 event = ECORE_FILE_EVENT_DELETED_FILE;
179 break;
180 case FILE_ACTION_MODIFIED:
181 if (!md->is_dir)
182 event = ECORE_FILE_EVENT_MODIFIED;
183 break;
184 case FILE_ACTION_RENAMED_OLD_NAME:
185 if (md->is_dir)
186 event = ECORE_FILE_EVENT_DELETED_DIRECTORY;
187 else
188 event = ECORE_FILE_EVENT_DELETED_FILE;
189 break;
190 case FILE_ACTION_RENAMED_NEW_NAME:
191 if (md->is_dir)
192 event = ECORE_FILE_EVENT_CREATED_DIRECTORY;
193 else
194 event = ECORE_FILE_EVENT_CREATED_FILE;
195 break;
196 default:
197 fprintf(stderr, "unknown event\n");
198 event = ECORE_FILE_EVENT_NONE;
199 break;
200 }
201 if (event != ECORE_FILE_EVENT_NONE)
202 md->monitor->func(md->monitor->data, md->monitor, event, filename);
203
204 fni = (PFILE_NOTIFY_INFORMATION)((LPBYTE)fni + offset);
205 } while (offset);
206
207 filter = (md->is_dir == 0) ? FILE_NOTIFY_CHANGE_FILE_NAME : FILE_NOTIFY_CHANGE_DIR_NAME;
208 filter |=
209 FILE_NOTIFY_CHANGE_ATTRIBUTES |
210 FILE_NOTIFY_CHANGE_SIZE |
211 FILE_NOTIFY_CHANGE_LAST_WRITE |
212 FILE_NOTIFY_CHANGE_LAST_ACCESS |
213 FILE_NOTIFY_CHANGE_CREATION |
214 FILE_NOTIFY_CHANGE_SECURITY;
215
216 ReadDirectoryChangesW(md->handle,
217 md->buffer,
218 ECORE_FILE_MONITOR_WIN32_BUFFER_SIZE,
219 FALSE,
220 filter,
221 &md->buf_length,
222 &md->overlapped,
223 NULL);
224 return 0;
225}
226
227int
228ecore_file_monitor_win32_init(void)
229{
230 return 1;
231}
232
233int
234ecore_file_monitor_win32_shutdown(void)
235{
236 return 1;
237}
238
239Ecore_File_Monitor *
240ecore_file_monitor_win32_add(const char *path,
241 void (*func) (void *data, Ecore_File_Monitor *em,
242 Ecore_File_Event event,
243 const char *path),
244 void *data)
245{
246 Ecore_File_Monitor_Win32 *m;
247 Ecore_File_Monitor *em;
248 size_t len;
249
250 if (!path || (*path == '\0')) return NULL;
251 if (!ecore_file_exists(path) || !ecore_file_is_dir(path))
252 return NULL;
253 if (!func) return NULL;
254
255 em = (Ecore_File_Monitor *)calloc(1, sizeof(Ecore_File_Monitor_Win32));
256 if (!em) return NULL;
257
258 em->func = func;
259 em->data = data;
260
261 em->path = strdup(path);
262 if (!em->path)
263 {
264 free(em);
265 return NULL;
266 }
267 len = strlen(em->path);
268 if (em->path[len - 1] == '/' || em->path[len - 1] == '\\')
269 em->path[len - 1] = '\0';
270
271 m = ECORE_FILE_MONITOR_WIN32(em);
272
273 m->file = _ecore_file_monitor_win32_data_new(em, 0);
274 if (!m->file)
275 {
276 free(em->path);
277 free(em);
278 return NULL;
279 }
280
281 m->dir = _ecore_file_monitor_win32_data_new(em, 1);
282 if (!m->dir)
283 {
284 _ecore_file_monitor_win32_data_free(m->file);
285 free(em->path);
286 free(em);
287 return NULL;
288 }
289
290 _monitors = ECORE_FILE_MONITOR(eina_inlist_append(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em)));
291
292 return em;
293}
294
295void
296ecore_file_monitor_win32_del(Ecore_File_Monitor *em)
297{
298 Ecore_File_Monitor_Win32 *m;
299
300 if (!em)
301 return;
302
303 m = ECORE_FILE_MONITOR_WIN32(em);
304 _ecore_file_monitor_win32_data_free(m->dir);
305 _ecore_file_monitor_win32_data_free(m->file);
306 free(em->path);
307 free(em);
308}
309
310#endif