[linker] We need to mark nested types even if the declaring type isn't marked.
[mono-project.git] / mono / metadata / filewatcher.c
blobe6902c6caa394157f7ec2c223980bc84f42df8cd
1 /*
2 * filewatcher.c: File System Watcher internal calls
4 * Authors:
5 * Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
8 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
9 */
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
15 #ifdef HAVE_SYS_TYPES_H
16 #include <sys/types.h>
17 #endif
18 #ifdef HAVE_SYS_EVENT_H
19 #include <sys/event.h>
20 #endif
21 #ifdef HAVE_SYS_TIME_H
22 #include <sys/time.h>
23 #endif
25 #include <mono/metadata/appdomain.h>
26 #include <mono/metadata/exception.h>
27 #include <mono/metadata/filewatcher.h>
28 #include <mono/metadata/marshal.h>
29 #include <mono/utils/mono-dl.h>
30 #include <mono/utils/mono-io-portability.h>
31 #ifdef HOST_WIN32
34 * TODO:
35 * We use the managed watcher on windows, so the code inside this #if is never used
37 gint
38 ves_icall_System_IO_FSW_SupportsFSW (void)
40 return 1;
43 gboolean
44 ves_icall_System_IO_FAMW_InternalFAMNextEvent (gpointer conn,
45 MonoString **filename,
46 gint *code,
47 gint *reqnum)
49 return FALSE;
52 #else
54 static int (*FAMNextEvent) (gpointer, gpointer);
56 gint
57 ves_icall_System_IO_FSW_SupportsFSW (void)
59 #if HAVE_KQUEUE
60 return 3;
61 #else
62 MonoDl *fam_module;
63 int lib_used = 4; /* gamin */
64 int inotify_instance;
65 char *err;
67 inotify_instance = ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ();
68 if (inotify_instance != -1) {
69 close (inotify_instance);
70 return 5; /* inotify */
73 fam_module = mono_dl_open ("libgamin-1.so", MONO_DL_LAZY, NULL);
74 if (fam_module == NULL) {
75 lib_used = 2; /* FAM */
76 fam_module = mono_dl_open ("libfam.so", MONO_DL_LAZY, NULL);
79 if (fam_module == NULL)
80 return 0;
82 err = mono_dl_symbol (fam_module, "FAMNextEvent", (gpointer *) &FAMNextEvent);
83 g_free (err);
84 if (FAMNextEvent == NULL)
85 return 0;
87 return lib_used;
88 #endif
91 /* Almost copied from fam.h. Weird, I know */
92 typedef struct {
93 gint reqnum;
94 } FAMRequest;
96 typedef struct FAMEvent {
97 gpointer fc;
98 FAMRequest fr;
99 gchar *hostname;
100 gchar filename [PATH_MAX];
101 gpointer userdata;
102 gint code;
103 } FAMEvent;
105 gboolean
106 ves_icall_System_IO_FAMW_InternalFAMNextEvent (gpointer conn,
107 MonoString **filename,
108 gint *code,
109 gint *reqnum)
111 FAMEvent ev;
113 if (FAMNextEvent (conn, &ev) == 1) {
114 *filename = mono_string_new (mono_domain_get (), ev.filename);
115 *code = ev.code;
116 *reqnum = ev.fr.reqnum;
117 return TRUE;
120 return FALSE;
122 #endif
124 #ifndef HAVE_SYS_INOTIFY_H
125 int ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ()
127 return -1;
130 int ves_icall_System_IO_InotifyWatcher_AddWatch (int fd, MonoString *directory, gint32 mask)
132 return -1;
135 int ves_icall_System_IO_InotifyWatcher_RemoveWatch (int fd, gint32 watch_descriptor)
137 return -1;
139 #else
140 #include <sys/inotify.h>
141 #include <errno.h>
144 ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ()
146 return inotify_init ();
150 ves_icall_System_IO_InotifyWatcher_AddWatch (int fd, MonoString *name, gint32 mask)
152 MonoError error;
153 char *str, *path;
154 int retval;
156 if (name == NULL)
157 return -1;
159 str = mono_string_to_utf8_checked (name, &error);
160 if (mono_error_set_pending_exception (&error))
161 return -1;
162 path = mono_portability_find_file (str, TRUE);
163 if (!path)
164 path = str;
166 retval = inotify_add_watch (fd, path, mask);
167 if (retval < 0) {
168 switch (errno) {
169 case EACCES:
170 errno = ERROR_ACCESS_DENIED;
171 break;
172 case EBADF:
173 errno = ERROR_INVALID_HANDLE;
174 break;
175 case EFAULT:
176 errno = ERROR_INVALID_ACCESS;
177 break;
178 case EINVAL:
179 errno = ERROR_INVALID_DATA;
180 break;
181 case ENOMEM:
182 errno = ERROR_NOT_ENOUGH_MEMORY;
183 break;
184 case ENOSPC:
185 errno = ERROR_TOO_MANY_OPEN_FILES;
186 break;
187 default:
188 errno = ERROR_GEN_FAILURE;
189 break;
191 mono_marshal_set_last_error ();
193 if (path != str)
194 g_free (path);
195 g_free (str);
196 return retval;
200 ves_icall_System_IO_InotifyWatcher_RemoveWatch (int fd, gint32 watch_descriptor)
202 return inotify_rm_watch (fd, watch_descriptor);
204 #endif
206 #if HAVE_KQUEUE
208 static void
209 interrupt_kevent (gpointer data)
211 int *kq_ptr = data;
213 /* Interrupt the kevent () call by closing the fd */
214 close (*kq_ptr);
215 /* Signal to managed code that the fd is closed */
216 *kq_ptr = -1;
220 * ves_icall_System_IO_KqueueMonitor_kevent_notimeout:
222 * Call kevent (), while handling runtime interruptions.
225 ves_icall_System_IO_KqueueMonitor_kevent_notimeout (int *kq_ptr, gpointer changelist, int nchanges, gpointer eventlist, int nevents)
227 int res;
228 gboolean interrupted;
230 mono_thread_info_install_interrupt (interrupt_kevent, kq_ptr, &interrupted);
231 if (interrupted) {
232 close (*kq_ptr);
233 *kq_ptr = -1;
234 return -1;
237 MONO_ENTER_GC_SAFE;
238 res = kevent (*kq_ptr, changelist, nchanges, eventlist, nevents, NULL);
239 MONO_EXIT_GC_SAFE;
241 mono_thread_info_uninstall_interrupt (&interrupted);
243 return res;
246 #else
249 ves_icall_System_IO_KqueueMonitor_kevent_notimeout (int *kq_ptr, gpointer changelist, int nchanges, gpointer eventlist, int nevents)
251 g_assert_not_reached ();
252 return -1;
255 #endif /* #if HAVE_KQUEUE */