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