update known-issues
[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 #include <mono/utils/mono-dl.h>
19 #if (defined (PLATFORM_WIN32) && WINVER >= 0x0400)
20
21 /*
22  * TODO:
23  * We use the managed watcher on windows, so the code inside this #if is never used
24  */
25 gint
26 ves_icall_System_IO_FSW_SupportsFSW (void)
27 {
28         return 1;
29 }
30
31 gboolean
32 ves_icall_System_IO_FAMW_InternalFAMNextEvent (gpointer conn,
33                                                MonoString **filename,
34                                                gint *code,
35                                                gint *reqnum)
36 {
37         return FALSE;
38 }
39
40 #else
41
42 static int (*FAMNextEvent) (gpointer, gpointer);
43
44 gint
45 ves_icall_System_IO_FSW_SupportsFSW (void)
46 {
47 #if HAVE_KQUEUE
48         return 3;
49 #else
50         MonoDl *fam_module;
51         gchar *filename;
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         g_free (filename);
68         if (fam_module == NULL) {
69                 lib_used = 2; /* FAM */
70                 iter = NULL;
71                 fam_module = mono_dl_open ("libfam.so", MONO_DL_LAZY, NULL);
72                 g_free (filename);
73         }
74
75         if (fam_module == NULL)
76                 return 0;
77
78         err = mono_dl_symbol (fam_module, "FAMNextEvent", (gpointer *) &FAMNextEvent);
79         g_free (err);
80         if (FAMNextEvent == NULL)
81                 return 0;
82
83         return lib_used;
84 #endif
85 }
86
87 /* Almost copied from fam.h. Weird, I know */
88 typedef struct {
89         gint reqnum;
90 } FAMRequest;
91
92 typedef struct FAMEvent {
93         gpointer fc;
94         FAMRequest fr;
95         gchar *hostname;
96         gchar filename [PATH_MAX];
97         gpointer userdata;
98         gint code;
99 } FAMEvent;
100
101 gboolean
102 ves_icall_System_IO_FAMW_InternalFAMNextEvent (gpointer conn,
103                                                MonoString **filename,
104                                                gint *code,
105                                                gint *reqnum)
106 {
107         FAMEvent ev;
108
109         MONO_ARCH_SAVE_REGS;
110
111         if (FAMNextEvent (conn, &ev) == 1) {
112                 *filename = mono_string_new (mono_domain_get (), ev.filename);
113                 *code = ev.code;
114                 *reqnum = ev.fr.reqnum;
115                 return TRUE;
116         }
117
118         return FALSE;
119 }
120 #endif
121
122 #if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) && !defined(__NR_inotify_init)
123 #  if defined(__i386__)
124 #     define __NR_inotify_init          291
125 #  elif defined(__x86_64__)
126 #     define __NR_inotify_init          253
127 #  elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__)
128 #     define __NR_inotify_init          275
129 #  elif defined (__s390__) || defined (__s390x__)
130 #     define __NR_inotify_init          284
131 #  elif defined(__sparc__) || defined (__sparc64__)
132 #     define __NR_inotify_init          151
133 #  elif defined (__ia64__)
134 #     define __NR_inotify_init          1277
135 #  elif defined (__arm__)
136 #     define __NR_inotify_init          316
137 #  elif defined(__alpha__)
138 #     define __NR_inotify_init          444
139 #  endif
140 #ifdef __NR_inotify_init
141 #  ifndef __NR_inotify_add_watch
142 #    define __NR_inotify_add_watch (__NR_inotify_init + 1)
143 #  endif
144 #  ifndef __NR_inotify_rm_watch
145 #    define __NR_inotify_rm_watch (__NR_inotify_init + 2)
146 #  endif
147 #endif
148 #endif
149
150 #if !defined(__linux__) || !defined(__NR_inotify_init)
151 int ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ()
152 {
153         return -1;
154 }
155
156 int ves_icall_System_IO_InotifyWatcher_AddWatch (int fd, MonoString *directory, gint32 mask)
157 {
158         return -1;
159 }
160
161 int ves_icall_System_IO_InotifyWatcher_RemoveWatch (int fd, int watch_descriptor)
162 {
163         return -1;
164 }
165 #else
166 #include <errno.h>
167
168 int
169 ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ()
170 {
171         return syscall (__NR_inotify_init);
172 }
173
174 int
175 ves_icall_System_IO_InotifyWatcher_AddWatch (int fd, MonoString *name, gint32 mask)
176 {
177         char *str;
178         int retval;
179
180         MONO_ARCH_SAVE_REGS;
181
182         if (name == NULL)
183                 return -1;
184
185         str = mono_string_to_utf8 (name);
186         retval = syscall (__NR_inotify_add_watch, fd, str, mask);
187         if (retval < 0) {
188                 switch (errno) {
189                 case EACCES:
190                         errno = ERROR_ACCESS_DENIED;
191                         break;
192                 case EBADF:
193                         errno = ERROR_INVALID_HANDLE;
194                         break;
195                 case EFAULT:
196                         errno = ERROR_INVALID_ACCESS;
197                         break;
198                 case EINVAL:
199                         errno = ERROR_INVALID_DATA;
200                         break;
201                 case ENOMEM:
202                         errno = ERROR_NOT_ENOUGH_MEMORY;
203                         break;
204                 case ENOSPC:
205                         errno = ERROR_TOO_MANY_OPEN_FILES;
206                         break;
207                 default:
208                         errno = ERROR_GEN_FAILURE;
209                         break;
210                 }
211                 mono_marshal_set_last_error ();
212         }
213         g_free (str);
214         return retval;
215 }
216
217 int
218 ves_icall_System_IO_InotifyWatcher_RemoveWatch (int fd, gint32 watch_descriptor)
219 {
220         return syscall (__NR_inotify_rm_watch, fd, watch_descriptor);
221 }
222 #endif
223