Merge pull request #1952 from esdrubal/proc_name
[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         char *err;
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         fam_module = mono_dl_open ("libgamin-1.so", MONO_DL_LAZY, NULL);
63         if (fam_module == NULL) {
64                 lib_used = 2; /* FAM */
65                 fam_module = mono_dl_open ("libfam.so", MONO_DL_LAZY, NULL);
66         }
67
68         if (fam_module == NULL)
69                 return 0;
70
71         err = mono_dl_symbol (fam_module, "FAMNextEvent", (gpointer *) &FAMNextEvent);
72         g_free (err);
73         if (FAMNextEvent == NULL)
74                 return 0;
75
76         return lib_used;
77 #endif
78 }
79
80 /* Almost copied from fam.h. Weird, I know */
81 typedef struct {
82         gint reqnum;
83 } FAMRequest;
84
85 typedef struct FAMEvent {
86         gpointer fc;
87         FAMRequest fr;
88         gchar *hostname;
89         gchar filename [PATH_MAX];
90         gpointer userdata;
91         gint code;
92 } FAMEvent;
93
94 gboolean
95 ves_icall_System_IO_FAMW_InternalFAMNextEvent (gpointer conn,
96                                                MonoString **filename,
97                                                gint *code,
98                                                gint *reqnum)
99 {
100         FAMEvent ev;
101
102         if (FAMNextEvent (conn, &ev) == 1) {
103                 *filename = mono_string_new (mono_domain_get (), ev.filename);
104                 *code = ev.code;
105                 *reqnum = ev.fr.reqnum;
106                 return TRUE;
107         }
108
109         return FALSE;
110 }
111 #endif
112
113 #ifndef HAVE_SYS_INOTIFY_H
114 int ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ()
115 {
116         return -1;
117 }
118
119 int ves_icall_System_IO_InotifyWatcher_AddWatch (int fd, MonoString *directory, gint32 mask)
120 {
121         return -1;
122 }
123
124 int ves_icall_System_IO_InotifyWatcher_RemoveWatch (int fd, gint32 watch_descriptor)
125 {
126         return -1;
127 }
128 #else
129 #include <sys/inotify.h>
130 #include <errno.h>
131
132 int
133 ves_icall_System_IO_InotifyWatcher_GetInotifyInstance ()
134 {
135         return inotify_init ();
136 }
137
138 int
139 ves_icall_System_IO_InotifyWatcher_AddWatch (int fd, MonoString *name, gint32 mask)
140 {
141         char *str, *path;
142         int retval;
143
144         if (name == NULL)
145                 return -1;
146
147         str = mono_string_to_utf8 (name);
148         path = mono_portability_find_file (str, TRUE);
149         if (!path)
150                 path = str;
151
152         retval = inotify_add_watch (fd, path, mask);
153         if (retval < 0) {
154                 switch (errno) {
155                 case EACCES:
156                         errno = ERROR_ACCESS_DENIED;
157                         break;
158                 case EBADF:
159                         errno = ERROR_INVALID_HANDLE;
160                         break;
161                 case EFAULT:
162                         errno = ERROR_INVALID_ACCESS;
163                         break;
164                 case EINVAL:
165                         errno = ERROR_INVALID_DATA;
166                         break;
167                 case ENOMEM:
168                         errno = ERROR_NOT_ENOUGH_MEMORY;
169                         break;
170                 case ENOSPC:
171                         errno = ERROR_TOO_MANY_OPEN_FILES;
172                         break;
173                 default:
174                         errno = ERROR_GEN_FAILURE;
175                         break;
176                 }
177                 mono_marshal_set_last_error ();
178         }
179         if (path != str)
180                 g_free (path);
181         g_free (str);
182         return retval;
183 }
184
185 int
186 ves_icall_System_IO_InotifyWatcher_RemoveWatch (int fd, gint32 watch_descriptor)
187 {
188         return inotify_rm_watch (fd, watch_descriptor);
189 }
190 #endif