diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/ecore/src/lib/ecore_file/ecore_file_monitor_win32.c | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore_file/ecore_file_monitor_win32.c b/libraries/ecore/src/lib/ecore_file/ecore_file_monitor_win32.c new file mode 100644 index 0000000..7f3af09 --- /dev/null +++ b/libraries/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 | |||
19 | typedef struct _Ecore_File_Monitor_Win32 Ecore_File_Monitor_Win32; | ||
20 | typedef 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 | |||
26 | struct _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 | |||
38 | struct _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 | |||
45 | static Ecore_File_Monitor *_monitors = NULL; | ||
46 | |||
47 | static Eina_Bool _ecore_file_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh); | ||
48 | |||
49 | |||
50 | static 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 | |||
118 | static 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 | |||
128 | static Eina_Bool | ||
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 1; | ||
225 | } | ||
226 | |||
227 | int | ||
228 | ecore_file_monitor_win32_init(void) | ||
229 | { | ||
230 | return 1; | ||
231 | } | ||
232 | |||
233 | int | ||
234 | ecore_file_monitor_win32_shutdown(void) | ||
235 | { | ||
236 | return 1; | ||
237 | } | ||
238 | |||
239 | Ecore_File_Monitor * | ||
240 | ecore_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 | |||
295 | void | ||
296 | ecore_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 | ||