Merge branch 'master' into msbuilddll2
[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  * Copyright 2004-2009 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 #include <mono/utils/mono-dl.h>
19 #include <mono/utils/mono-io-portability.h>
20 #ifdef HOST_WIN32
21
22 /*
23  * TODO:
24  * We use the managed watcher on windows, so the code inside this #if is never used
25  */
26 gint
27 ves_icall_System_IO_FSW_SupportsFSW (void)
28 {
29         return 1;
30 }
31
32 gboolean
33 ves_icall_System_IO_FAMW_InternalFAMNextEvent (gpointer conn,
34                                                MonoString **filename,
35                                                gint *code,
36                                                gint *reqnum)
37 {
38         return FALSE;
39 }
40
41 #else
42
43 static int (*FAMNextEvent) (gpointer, gpointer);
44
45 gint
46 ves_icall_System_IO_FSW_SupportsFSW (void)
47 {
48 #if HAVE_KQUEUE
49         return 3;
50 #else
51         MonoDl *fam_module;
52         int lib_used = 4; /* gamin */
53         int inotify_instance;
54         void *iter;
55         char *err;
56
57         MONO_ARCH_SAVE_REGS;
58
59         inotify_instance = ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ();
60         if (inotify_instance != -1) {
61                 close (inotify_instance);
62                 return 5; /* inotify */
63         }
64
65         iter = NULL;
66         fam_module = mono_dl_open ("libgamin-1.so", MONO_DL_LAZY, NULL);
67         if (fam_module == NULL) {
68                 lib_used = 2; /* FAM */
69                 iter = NULL;
70                 fam_module = mono_dl_open ("libfam.so", MONO_DL_LAZY, NULL);
71         }
72
73         if (fam_module == NULL)
74                 return 0;
75
76         err = mono_dl_symbol (fam_module, "FAMNextEvent", (gpointer *) &FAMNextEvent);
77         g_free (err);
78         if (FAMNextEvent == NULL)
79                 return 0;
80
81         return lib_used;
82 #endif
83 }
84
85 /* Almost copied from fam.h. Weird, I know */
86 typedef struct {
87         gint reqnum;
88 } FAMRequest;
89
90 typedef struct FAMEvent {
91         gpointer fc;
92         FAMRequest fr;
93         gchar *hostname;
94         gchar filename [PATH_MAX];
95         gpointer userdata;
96         gint code;
97 } FAMEvent;
98
99 gboolean
100 ves_icall_System_IO_FAMW_InternalFAMNextEvent (gpointer conn,
101                                                MonoString **filename,
102                                                gint *code,
103                                                gint *reqnum)
104 {
105         FAMEvent ev;
106
107         MONO_ARCH_SAVE_REGS;
108
109         if (FAMNextEvent (conn, &ev) == 1) {
110                 *filename = mono_string_new (mono_domain_get (), ev.filename);
111                 *code = ev.code;
112                 *reqnum = ev.fr.reqnum;
113                 return TRUE;
114         }
115
116         return FALSE;
117 }
118 #endif
119
120 #ifndef HAVE_SYS_INOTIFY_H
121 int ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ()
122 {
123         return -1;
124 }
125
126 int ves_icall_System_IO_InotifyWatcher_AddWatch (int fd, MonoString *directory, gint32 mask)
127 {
128         return -1;
129 }
130
131 int ves_icall_System_IO_InotifyWatcher_RemoveWatch (int fd, gint32 watch_descriptor)
132 {
133         return -1;
134 }
135 #else
136 #include <sys/inotify.h>
137 #include <errno.h>
138
139 int
140 ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ()
141 {
142         return inotify_init ();
143 }
144
145 int
146 ves_icall_System_IO_InotifyWatcher_AddWatch (int fd, MonoString *name, gint32 mask)
147 {
148         char *str, *path;
149         int retval;
150
151         MONO_ARCH_SAVE_REGS;
152
153         if (name == NULL)
154                 return -1;
155
156         str = mono_string_to_utf8 (name);
157         path = mono_portability_find_file (str, TRUE);
158         if (!path)
159                 path = str;
160
161         retval = inotify_add_watch (fd, path, mask);
162         if (retval < 0) {
163                 switch (errno) {
164                 case EACCES:
165                         errno = ERROR_ACCESS_DENIED;
166                         break;
167                 case EBADF:
168                         errno = ERROR_INVALID_HANDLE;
169                         break;
170                 case EFAULT:
171                         errno = ERROR_INVALID_ACCESS;
172                         break;
173                 case EINVAL:
174                         errno = ERROR_INVALID_DATA;
175                         break;
176                 case ENOMEM:
177                         errno = ERROR_NOT_ENOUGH_MEMORY;
178                         break;
179                 case ENOSPC:
180                         errno = ERROR_TOO_MANY_OPEN_FILES;
181                         break;
182                 default:
183                         errno = ERROR_GEN_FAILURE;
184                         break;
185                 }
186                 mono_marshal_set_last_error ();
187         }
188         if (path != str)
189                 g_free (path);
190         g_free (str);
191         return retval;
192 }
193
194 int
195 ves_icall_System_IO_InotifyWatcher_RemoveWatch (int fd, gint32 watch_descriptor)
196 {
197         return inotify_rm_watch (fd, watch_descriptor);
198 }
199 #endif
200