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