2007-04-23 Martin Baulig <martin@ximian.com>
[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         /* the build_path calls here should be avoided, since we provide the full name */
67         filename = mono_dl_build_path (NULL, "libgamin-1.so.0", &iter);
68         fam_module = mono_dl_open (filename, MONO_DL_LAZY, NULL);
69         g_free (filename);
70         if (fam_module == NULL) {
71                 lib_used = 2; /* FAM */
72                 iter = NULL;
73                 filename = mono_dl_build_path (NULL, "libfam.so.0", &iter);
74                 fam_module = mono_dl_open (filename, MONO_DL_LAZY, NULL);
75                 g_free (filename);
76         }
77
78         if (fam_module == NULL)
79                 return 0;
80
81         err = mono_dl_symbol (fam_module, "FAMNextEvent", (gpointer *) &FAMNextEvent);
82         g_free (err);
83         if (FAMNextEvent == NULL)
84                 return 0;
85
86         return lib_used;
87 #endif
88 }
89
90 /* Almost copied from fam.h. Weird, I know */
91 typedef struct {
92         gint reqnum;
93 } FAMRequest;
94
95 typedef struct FAMEvent {
96         gpointer fc;
97         FAMRequest fr;
98         gchar *hostname;
99         gchar filename [PATH_MAX];
100         gpointer userdata;
101         gint code;
102 } FAMEvent;
103
104 gboolean
105 ves_icall_System_IO_FAMW_InternalFAMNextEvent (gpointer conn,
106                                                MonoString **filename,
107                                                gint *code,
108                                                gint *reqnum)
109 {
110         FAMEvent ev;
111
112         MONO_ARCH_SAVE_REGS;
113
114         if (FAMNextEvent (conn, &ev) == 1) {
115                 *filename = mono_string_new (mono_domain_get (), ev.filename);
116                 *code = ev.code;
117                 *reqnum = ev.fr.reqnum;
118                 return TRUE;
119         }
120
121         return FALSE;
122 }
123 #endif
124
125 #if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H) && !defined(__NR_inotify_init)
126 #  if defined(__i386__)
127 #     define __NR_inotify_init          291
128 #  elif defined(__x86_64__)
129 #     define __NR_inotify_init          253
130 #  elif defined(__ppc__) || defined(__powerpc__) || defined(__powerpc64__)
131 #     define __NR_inotify_init          275
132 #  elif defined (__s390__) || defined (__s390x__)
133 #     define __NR_inotify_init          284
134 #  elif defined(__sparc__) || defined (__sparc64__)
135 #     define __NR_inotify_init          151
136 #  elif defined (__ia64__)
137 #     define __NR_inotify_init          1277
138 #  elif defined (__arm__)
139 #     define __NR_inotify_init          316
140 #  elif defined(__alpha__)
141 #     define __NR_inotify_init          444
142 #  endif
143 #ifdef __NR_inotify_init
144 #  ifndef __NR_inotify_add_watch
145 #    define __NR_inotify_add_watch (__NR_inotify_init + 1)
146 #  endif
147 #  ifndef __NR_inotify_rm_watch
148 #    define __NR_inotify_rm_watch (__NR_inotify_init + 2)
149 #  endif
150 #endif
151 #endif
152
153 #if !defined(__linux__) || !defined(__NR_inotify_init)
154 int ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ()
155 {
156         return -1;
157 }
158
159 int ves_icall_System_IO_InotifyWatcher_AddWatch (int fd, MonoString *directory, gint32 mask)
160 {
161         return -1;
162 }
163
164 int ves_icall_System_IO_InotifyWatcher_RemoveWatch (int fd, int watch_descriptor)
165 {
166         return -1;
167 }
168 #else
169 #include <errno.h>
170
171 int
172 ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ()
173 {
174         return syscall (__NR_inotify_init);
175 }
176
177 int
178 ves_icall_System_IO_InotifyWatcher_AddWatch (int fd, MonoString *name, gint32 mask)
179 {
180         char *str;
181         int retval;
182
183         MONO_ARCH_SAVE_REGS;
184
185         if (name == NULL)
186                 return -1;
187
188         str = mono_string_to_utf8 (name);
189         retval = syscall (__NR_inotify_add_watch, fd, str, mask);
190         if (retval < 0) {
191                 switch (errno) {
192                 case EACCES:
193                         errno = ERROR_ACCESS_DENIED;
194                         break;
195                 case EBADF:
196                         errno = ERROR_INVALID_HANDLE;
197                         break;
198                 case EFAULT:
199                         errno = ERROR_INVALID_ACCESS;
200                         break;
201                 case EINVAL:
202                         errno = ERROR_INVALID_DATA;
203                         break;
204                 case ENOMEM:
205                         errno = ERROR_NOT_ENOUGH_MEMORY;
206                         break;
207                 case ENOSPC:
208                         errno = ERROR_TOO_MANY_OPEN_FILES;
209                         break;
210                 default:
211                         errno = ERROR_GEN_FAILURE;
212                         break;
213                 }
214                 mono_marshal_set_last_error ();
215         }
216         g_free (str);
217         return retval;
218 }
219
220 int
221 ves_icall_System_IO_InotifyWatcher_RemoveWatch (int fd, gint32 watch_descriptor)
222 {
223         return syscall (__NR_inotify_rm_watch, fd, watch_descriptor);
224 }
225 #endif
226