New test.
[mono.git] / mono / metadata / filewatcher.c
1 /*
2  * filewatcher.c: File System Watcher internal calls
3  *
4  * Authors:
5  *      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6  *
7  * (C) 2004,2005,2006 Novell, Inc. (http://www.novell.com)
8  */
9
10 #ifdef HAVE_CONFIG_H
11 #include <config.h>
12 #endif
13
14 #include <mono/metadata/appdomain.h>
15 #include <mono/metadata/exception.h>
16 #include <mono/metadata/filewatcher.h>
17 #include <mono/metadata/marshal.h>
18 #if (defined (PLATFORM_WIN32) && WINVER >= 0x0400)
19
20 /*
21  * TODO:
22  * We use the managed watcher on windows, so the code inside this #if is never used
23  */
24 gint
25 ves_icall_System_IO_FSW_SupportsFSW (void)
26 {
27         return 1;
28 }
29
30 gpointer
31 ves_icall_System_IO_FSW_OpenDirectory (MonoString *path, gpointer reserved)
32 {
33         return NULL;
34         /*
35         gpointer dir;
36         gchar *utf8path;
37
38         MONO_ARCH_SAVE_REGS;
39
40         dir = CreateFile (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE,
41                           NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
42
43         return dir;
44         */
45 }
46
47 gboolean
48 ves_icall_System_IO_FSW_CloseDirectory (gpointer handle)
49 {
50         return FALSE;
51         /*
52         MONO_ARCH_SAVE_REGS;
53
54         return CloseHandle (handle);
55         */
56 }
57
58 gboolean
59 ves_icall_System_IO_FSW_ReadDirectoryChanges (gpointer handle,
60                                               MonoArray *buffer,
61                                               gboolean includeSubdirs,
62                                               gint filters,
63                                               gpointer overlap,
64                                               gpointer callback)
65 {
66         return FALSE;
67         /*
68         gpointer dest;
69         gint size;
70         MonoObject *delegate = (MonoObject *) callback;
71         MonoMethod *im;
72         LPOVERLAPPED_COMPLETION_ROUTINE func;
73
74         MONO_ARCH_SAVE_REGS;
75
76         size = mono_array_length (buffer);
77         dest = mono_array_addr_with_size (buffer, 1, 0);
78
79         im = mono_get_delegate_invoke (mono_object_get_class (delegate));
80         func = mono_compile_method (im);
81         return FALSE;
82         * return ReadDirectoryChanges (handle, dest, size, includeSubdirs, filters,
83                                      NULL, (LPOVERLAPPED) overlap,
84                                      func); */
85 }
86
87 gboolean
88 ves_icall_System_IO_FAMW_InternalFAMNextEvent (gpointer conn,
89                                                MonoString **filename,
90                                                gint *code,
91                                                gint *reqnum)
92 {
93         return FALSE;
94 }
95
96 #else
97
98 static int (*FAMNextEvent) (gpointer, gpointer);
99
100 gint
101 ves_icall_System_IO_FSW_SupportsFSW (void)
102 {
103 #if HAVE_KQUEUE
104         return 3;
105 #else
106         GModule *fam_module;
107         gchar *filename;
108         int lib_used = 4; /* gamin */
109         int inotify_instance;
110
111         MONO_ARCH_SAVE_REGS;
112
113         inotify_instance = ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ();
114         if (inotify_instance != -1) {
115                 close (inotify_instance);
116                 return 5; /* inotify */
117         }
118
119         filename = g_module_build_path (NULL, "libgamin-1.so.0");
120         fam_module = g_module_open (filename, G_MODULE_BIND_LAZY);
121         g_free (filename);
122         if (fam_module == NULL) {
123                 lib_used = 2; /* FAM */
124                 filename = g_module_build_path (NULL, "libfam.so.0");
125                 fam_module = g_module_open (filename, G_MODULE_BIND_LAZY);
126                 g_free (filename);
127         }
128
129         if (fam_module == NULL)
130                 return 0;
131
132         g_module_symbol (fam_module, "FAMNextEvent", (gpointer *) &FAMNextEvent);
133         if (FAMNextEvent == NULL)
134                 return 0;
135
136         return lib_used;
137 #endif
138 }
139
140 gpointer
141 ves_icall_System_IO_FSW_OpenDirectory (MonoString *path, gpointer reserved)
142 {
143         return NULL;
144 }
145
146 gboolean
147 ves_icall_System_IO_FSW_CloseDirectory (gpointer handle)
148 {
149         return FALSE;
150 }
151
152 gboolean
153 ves_icall_System_IO_FSW_ReadDirectoryChanges (gpointer handle,
154                                               MonoArray *buffer,
155                                               gboolean includeSubdirs,
156                                               gint filters,
157                                               gpointer overlap,
158                                               gpointer callback)
159 {
160         return FALSE;
161 }
162
163 /* Almost copied from fam.h. Weird, I know */
164 typedef struct {
165         gint reqnum;
166 } FAMRequest;
167
168 typedef struct FAMEvent {
169         gpointer fc;
170         FAMRequest fr;
171         gchar *hostname;
172         gchar filename [PATH_MAX];
173         gpointer userdata;
174         gint code;
175 } FAMEvent;
176
177 gboolean
178 ves_icall_System_IO_FAMW_InternalFAMNextEvent (gpointer conn,
179                                                MonoString **filename,
180                                                gint *code,
181                                                gint *reqnum)
182 {
183         FAMEvent ev;
184
185         MONO_ARCH_SAVE_REGS;
186
187         if (FAMNextEvent (conn, &ev) == 1) {
188                 *filename = mono_string_new (mono_domain_get (), ev.filename);
189                 *code = ev.code;
190                 *reqnum = ev.fr.reqnum;
191                 return TRUE;
192         }
193
194         return FALSE;
195 }
196 #endif
197
198 #if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) && !defined(__NR_inotify_init)
199 #  if defined(__i386__)
200 #     define __NR_inotify_init          291
201 #  elif defined(__x86_64__)
202 #     define __NR_inotify_init          253
203 #  elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__)
204 #     define __NR_inotify_init          275
205 #  elif defined (__s390__) || defined (__s390x__)
206 #     define __NR_inotify_init          284
207 #  elif defined(__sparc__) || defined (__sparc64__)
208 #     define __NR_inotify_init          151
209 #  elif defined (__ia64__)
210 #     define __NR_inotify_init          1277
211 #  elif defined (__arm__)
212 #     define __NR_inotify_init          316
213 #  elif defined(__alpha__)
214 #     define __NR_inotify_init          444
215 #  endif
216 #ifdef __NR_inotify_init
217 #  ifndef __NR_inotify_add_watch
218 #    define __NR_inotify_add_watch (__NR_inotify_init + 1)
219 #  endif
220 #  ifndef __NR_inotify_rm_watch
221 #    define __NR_inotify_rm_watch (__NR_inotify_init + 2)
222 #  endif
223 #endif
224 #endif
225
226 #if !defined(__linux__) || !defined(__NR_inotify_init)
227 int ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ()
228 {
229         return -1;
230 }
231
232 int ves_icall_System_IO_InotifyWatcher_AddWatch (int fd, MonoString *directory, gint32 mask)
233 {
234         return -1;
235 }
236
237 int ves_icall_System_IO_InotifyWatcher_RemoveWatch (int fd, int watch_descriptor)
238 {
239         return -1;
240 }
241 #else
242 #include <errno.h>
243
244 int
245 ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ()
246 {
247         return syscall (__NR_inotify_init);
248 }
249
250 int
251 ves_icall_System_IO_InotifyWatcher_AddWatch (int fd, MonoString *name, gint32 mask)
252 {
253         char *str;
254         int retval;
255
256         MONO_ARCH_SAVE_REGS;
257
258         if (name == NULL)
259                 return -1;
260
261         str = mono_string_to_utf8 (name);
262         retval = syscall (__NR_inotify_add_watch, fd, str, mask);
263         if (retval < 0) {
264                 switch (errno) {
265                 case EACCES:
266                         errno = ERROR_ACCESS_DENIED;
267                         break;
268                 case EBADF:
269                         errno = ERROR_INVALID_HANDLE;
270                         break;
271                 case EFAULT:
272                         errno = ERROR_INVALID_ACCESS;
273                         break;
274                 case EINVAL:
275                         errno = ERROR_INVALID_DATA;
276                         break;
277                 case ENOMEM:
278                         errno = ERROR_NOT_ENOUGH_MEMORY;
279                         break;
280                 case ENOSPC:
281                         errno = ERROR_TOO_MANY_OPEN_FILES;
282                         break;
283                 default:
284                         errno = ERROR_GEN_FAILURE;
285                         break;
286                 }
287                 mono_marshal_set_last_error ();
288         }
289         g_free (str);
290         return retval;
291 }
292
293 int
294 ves_icall_System_IO_InotifyWatcher_RemoveWatch (int fd, gint32 watch_descriptor)
295 {
296         return syscall (__NR_inotify_rm_watch, fd, watch_descriptor);
297 }
298 #endif
299