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