2 * File-change notification.
4 * ----------------------------------------------------------------
7 * Copyright (C) 2004 Mojave Group, Caltech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation,
12 * version 2.1 of the License.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * Additional permission is given to link this library with the
24 * OpenSSL project's "OpenSSL" library, and with the OCaml runtime,
25 * and you may distribute the linked executables. See the file
26 * LICENSE.libmojave for more details.
28 * Author: Jason Hickey
29 * @email{jyh@cs.caltech.edu}
33 #include <caml/mlvalues.h>
34 #include <caml/alloc.h>
35 #include <caml/memory.h>
36 #include <caml/fail.h>
37 #include <caml/custom.h>
38 #include <caml/signals.h>
44 /* Disable some of the warnings */
45 #pragma warning( disable : 4100 4189 4127 4702 4996 )
49 #include "fam_pseudo.h"
50 #else /* FAM_PSEUDO */
55 #include <sys/select.h>
56 #endif /* FAM_PSEUDO */
66 #define FAMInfo_val(v) ((FAMInfo *) Data_custom_val(v))
67 #define FAMConnection_val(v) ((FAMInfo_val(v)->fc))
70 #define ErrFmt(buffer, fmt) snprintf(buffer, sizeof(buffer), fmt, FamErrlist[FAMErrno])
72 #define ErrFmt(buffer, fmt) sprintf(buffer, fmt, FamErrlist[FAMErrno])
75 #define CheckCode(fmt, expr) \
76 enter_blocking_section(); \
78 leave_blocking_section(); \
81 ErrFmt(buffer, fmt); \
85 static int fam_connection_compare(value v1
, value v2
)
87 FAMConnection
*info1
= FAMConnection_val(v1
);
88 FAMConnection
*info2
= FAMConnection_val(v2
);
91 return info1
->id
== info2
->id
? 0 : info1
->id
< info2
->id
? -1 : 1;
92 #else /* FAM_PSEUDO */
93 return info1
->fd
== info2
->fd
? 0 : info1
->fd
< info2
->fd
? -1 : 1;
94 #endif /* !FAM_PSEUDO */
97 static long fam_connection_hash(value v
)
99 return (long) FAMConnection_val(v
);
102 static void fam_connection_finalize(value v_info
)
106 info
= FAMInfo_val(v_info
);
115 * Pass info in a custom block.
117 static struct custom_operations fam_connection_ops
= {
119 fam_connection_finalize
,
120 fam_connection_compare
,
122 custom_serialize_default
,
123 custom_deserialize_default
127 * Is this module enabled?
129 value
om_notify_enabled(value v_unit
)
135 * Open the FAM connection.
137 value
om_notify_open(value v_unit
)
145 v
= alloc_custom(&fam_connection_ops
, sizeof(FAMInfo
), 0, 1);
146 info
= FAMInfo_val(v
);
147 fc
= malloc(sizeof(FAMConnection
));
149 invalid_argument("om_notify_open: out of memory");
151 CheckCode("om_notify_open: %s", FAMOpen(fc
));
152 #ifdef HAVE_FAMNOEXISTS
153 CheckCode("om_notify_open: FAMNoExists: %s", FAMNoExists(fc
));
154 #endif /* HAVE_FAMNOEXISTS */
160 * Close the FAM connection.
162 value
om_notify_close(value v_fc
)
164 fam_connection_finalize(v_fc
);
169 * Get the file descriptor.
171 value
om_notify_fd(value v_fc
)
177 fc
= FAMConnection_val(v_fc
);
178 return Val_int(fc
->id
);
179 #else /* FAM_PSEUDO && !FAM_INOTIFY */
180 failwith("No file descriptors in pseudo-FAM");
182 #endif /* FAM_INOTIFY */
183 #else /* FAM_PSEUDO */
186 fc
= FAMConnection_val(v_fc
);
187 return Val_int(FAMCONNECTION_GETFD(fc
));
188 #endif /* FAM_PSEUDO */
192 * Monitor a directory.
194 value
om_notify_monitor_directory(value v_fc
, value v_name
, value v_recursive
)
196 CAMLparam3(v_fc
, v_name
, v_recursive
);
202 fc
= FAMConnection_val(v_fc
);
203 name
= String_val(v_name
);
204 recursive
= Int_val(v_recursive
);
207 code
= FAMMonitorDirectoryTree(fc
, name
, &request
, 0);
209 failwith("om_notify_monitor_directory: recursive monitoring is not allowed");
213 code
= FAMMonitorDirectory(fc
, name
, &request
, 0);
214 CheckCode("om_notify_monitor_directory: %s", code
);
215 CAMLreturn(Val_int(request
.reqnum
));
219 * Suspend the monitor.
221 value
om_notify_suspend(value v_fc
, value v_request
)
223 CAMLparam2(v_fc
, v_request
);
228 fc
= FAMConnection_val(v_fc
);
229 request
.reqnum
= Int_val(v_request
);
230 CheckCode("om_notify_suspend: %s", FAMSuspendMonitor(fc
, &request
));
231 CAMLreturn(Val_unit
);
235 * Resume the monitor.
237 value
om_notify_resume(value v_fc
, value v_request
)
239 CAMLparam2(v_fc
, v_request
);
244 fc
= FAMConnection_val(v_fc
);
245 request
.reqnum
= Int_val(v_request
);
246 CheckCode("om_notify_resume: %s", FAMResumeMonitor(fc
, &request
));
247 CAMLreturn(Val_unit
);
251 * Cancel the monitor.
253 value
om_notify_cancel(value v_fc
, value v_request
)
255 CAMLparam2(v_fc
, v_request
);
260 fc
= FAMConnection_val(v_fc
);
261 request
.reqnum
= Int_val(v_request
);
262 CheckCode("om_notify_cancel: %s", FAMCancelMonitor(fc
, &request
));
263 CAMLreturn(Val_unit
);
267 * Check for a pending event.
269 value
om_notify_pending(value v_fc
)
275 fc
= FAMConnection_val(v_fc
);
276 CheckCode("om_notify_pending: %s", FAMPending(fc
));
277 CAMLreturn(code
? Val_true
: Val_false
);
281 * Get the next event.
283 value
om_notify_next_event(value v_fc
)
286 CAMLlocal2(v_name
, v_tuple
);
291 fc
= FAMConnection_val(v_fc
);
292 CheckCode("om_notify_next_event: %s", FAMNextEvent(fc
, &event
));
294 if(code
< 1 || code
> 10)
295 failwith("om_notify_next_event: code out of bounds");
297 /* Allocate the string name */
298 v_name
= copy_string(event
.filename
);
300 /* Allocate the tuple */
301 v_tuple
= alloc_tuple(3);
302 Field(v_tuple
, 0) = Val_int(event
.fr
.reqnum
);
303 Field(v_tuple
, 1) = v_name
;
304 Field(v_tuple
, 2) = Val_int(code
- 1);
308 #else /* FAM_ENABLED */
311 * Is this module enabled?
313 value
om_notify_enabled(value v_unit
)
319 * Open the FAM connection.
321 value
om_notify_open(value v_unit
)
327 * Get the file descriptor.
329 value
om_notify_fd(value v_fc
)
331 invalid_argument("FAM not enabled");
336 * Close the FAM connection.
338 value
om_notify_close(value v_fc
)
344 * Monitor a directory.
346 value
om_notify_monitor_directory(value v_fc
, value v_name
, value v_recursive
)
352 * Suspend the monitor.
354 value
om_notify_suspend(value v_fc
, value v_request
)
361 * Suspend the monitor.
363 value
om_notify_resume(value v_fc
, value v_request
)
370 * Suspend the monitor.
372 value
om_notify_cancel(value v_fc
, value v_request
)
378 * Check for a pending event.
380 value
om_notify_pending(value v_fc
)
386 * Get the next event.
388 value
om_notify_next_event(value v_fc
)
390 invalid_argument("FAM not enabled");
394 #endif /* !FAM_ENABLED */