From cac0bd801ae0dc2cf4ed4badfe5eb4438e7abf0e Mon Sep 17 00:00:00 2001 From: T Ar Creator Date: Sat, 18 Nov 2006 14:36:15 +0000 Subject: [PATCH] initial implementation. --- ocaml_inotify-0.1Makefile | 42 +++++++++++ ocaml_inotify-0.1inotify.ml | 106 ++++++++++++++++++++++++++ ocaml_inotify-0.1inotify_stubs.c | 123 +++++++++++++++++++++++++++++++ ocaml_inotify-0.1test.inotify.ml | 31 ++++++++ 4 files changed, 302 insertions(+) create mode 100644 ocaml_inotify-0.1Makefile create mode 100644 ocaml_inotify-0.1inotify.ml create mode 100644 ocaml_inotify-0.1inotify_stubs.c create mode 100644 ocaml_inotify-0.1test.inotify.ml diff --git a/ocaml_inotify-0.1Makefile b/ocaml_inotify-0.1Makefile new file mode 100644 index 0000000..64a31db --- /dev/null +++ b/ocaml_inotify-0.1Makefile @@ -0,0 +1,42 @@ +CC = gcc +CFLAGS = -Wall -O2 +OCAMLC = ocamlc +OCAMLOPT = ocamlopt + +OCAMLOPTFLAGS = + +OCAML_TEST_INC = -I `ocamlfind query oUnit` +OCAML_TEST_LIB = `ocamlfind query oUnit`/oUnit.cmxa + +LIBS = inotify.cmxa inotify.cma +PROGRAMS = test.inotify + +all: $(LIBS) $(PROGRAMS) + +bins: $(PROGRAMS) + +libs: $(LIBS) + +inotify.cma: inotify_stubs.o inotify.cmo + $(OCAMLC) -a -o $@ -custom $+ + +inotify.cmxa: inotify_stubs.o inotify.cmx + $(OCAMLOPT) $(OCAMLOPTFLAGS) -a -o $@ $+ + +%.cmo: %.ml + $(OCAMLC) -c -o $@ $< + +%.cmi: %.mli + $(OCAMLC) -c -o $@ $< + +%.cmx: %.ml + $(OCAMLOPT) $(OCAMLOPTFLAGS) -c -o $@ $< + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +test.inotify: inotify.cmxa test.inotify.ml + $(OCAMLOPT) -o $@ unix.cmxa $+ + +clean: + rm -f *.o *.a *.cmo *.cmi *.cma *.cmx *.cmxa $(LIBS) $(PROGRAMS) diff --git a/ocaml_inotify-0.1inotify.ml b/ocaml_inotify-0.1inotify.ml new file mode 100644 index 0000000..d5b220e --- /dev/null +++ b/ocaml_inotify-0.1inotify.ml @@ -0,0 +1,106 @@ +(* + * Copyright (C) 2006 Vincent Hanquez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; version 2 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Inotify OCaml binding + *) + +type select_event = + | Access + | Attrib + | Close_write + | Close_nowrite + | Create + | Delete + | Delete_self + | Modify + | Move_self + | Moved_from + | Moved_to + | Open + | Dont_follow + | Mask_add + | Oneshot + | Onlydir + (* convenience *) + | Move + | Close + | All + +type type_event = + | Access + | Attrib + | Close_write + | Close_nowrite + | Create + | Delete + | Delete_self + | Modify + | Move_self + | Moved_from + | Moved_to + | Open + | Ignored + | Isdir + | Q_overflow + | Unmount + +let string_of_event = function + | Access -> "ACCESS" + | Attrib -> "ATTRIB" + | Close_write -> "CLOSE_WRITE" + | Close_nowrite -> "CLOSE_NOWRITE" + | Create -> "CREATE" + | Delete -> "DELETE" + | Delete_self -> "DELETE_SELF" + | Modify -> "MODIFY" + | Move_self -> "MOVE_SELF" + | Moved_from -> "MOVED_FROM" + | Moved_to -> "MOVED_TO" + | Open -> "OPEN" + | Ignored -> "IGNORED" + | Isdir -> "ISDIR" + | Q_overflow -> "Q_OVERFLOW" + | Unmount -> "UNMOUNT" + +type wd = int +type event = wd * type_event list * int32 * string option + +external init : unit -> Unix.file_descr = "stub_inotify_init" +external add_watch : Unix.file_descr -> string -> select_event list -> wd + = "stub_inotify_add_watch" +external rm_watch : Unix.file_descr -> wd -> unit = "stub_inotify_rm_watch" +external convert : string -> (int * type_event list * int32 * int) + = "stub_inotify_convert" +external struct_size : unit -> int = "stub_inotify_struct_size" + +external to_read : Unix.file_descr -> int = "stub_inotify_ioctl_fionread" + +let read fd = + let ss = struct_size () in + let toread = to_read fd in + + let ret = ref [] in + let buf = String.make toread '\000' in + let rd = Unix.read fd buf 0 toread in + + let i = ref 0 in + + + while !i < toread + do + let wd, l, cookie, len = convert (String.sub buf !i ss) in + let s = if len > 0 then Some (String.sub buf (!i + ss) len) else None in + ret := (wd, l, cookie, s) :: !ret; + i := !i + (ss + len); + done; + + List.rev !ret diff --git a/ocaml_inotify-0.1inotify_stubs.c b/ocaml_inotify-0.1inotify_stubs.c new file mode 100644 index 0000000..34a137a --- /dev/null +++ b/ocaml_inotify-0.1inotify_stubs.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2006 Vincent Hanquez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; version 2 only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Inotify Ocaml binding - C glue + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int inotify_flag_table[] = { + IN_ACCESS, IN_ATTRIB, IN_CLOSE_WRITE, IN_CLOSE_NOWRITE, + IN_CREATE, IN_DELETE, IN_DELETE_SELF, IN_MODIFY, + IN_MOVE_SELF, IN_MOVED_FROM, IN_MOVED_TO, IN_OPEN, + IN_DONT_FOLLOW, IN_MASK_ADD, IN_ONESHOT, IN_ONLYDIR, + IN_MOVE, IN_CLOSE, IN_ALL_EVENTS, 0 +}; + +static int inotify_return_table[] = { + IN_ACCESS, IN_ATTRIB, IN_CLOSE_WRITE, IN_CLOSE_NOWRITE, + IN_CREATE, IN_DELETE, IN_DELETE_SELF, IN_MODIFY, + IN_MOVE_SELF, IN_MOVED_FROM, IN_MOVED_TO, IN_OPEN, + IN_IGNORED, IN_ISDIR, IN_Q_OVERFLOW, IN_UNMOUNT, 0 +}; + +#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0])) + +value stub_inotify_init(value unit) +{ + CAMLparam1(unit); + int fd; + + fd = inotify_init(); + CAMLreturn(Val_int(fd)); +} + +value stub_inotify_ioctl_fionread(value fd) +{ + CAMLparam1(fd); + int rc, bytes; + + rc = ioctl(Int_val(fd), FIONREAD, &bytes); + if (rc == -1) + caml_failwith("ioctl fionread"); + + CAMLreturn(Val_int(bytes)); +} + +value stub_inotify_add_watch(value fd, value path, value mask) +{ + CAMLparam3(fd, path, mask); + int cv_mask, wd; + + cv_mask = caml_convert_flag_list(mask, inotify_flag_table); + wd = inotify_add_watch(Int_val(fd), String_val(path), cv_mask); + if (wd < 0) + caml_failwith("inotify_add_watch"); + CAMLreturn(Val_int(wd)); +} + +value stub_inotify_rm_watch(value fd, value wd) +{ + CAMLparam2(fd, wd); + int ret; + + ret = inotify_rm_watch(Int_val(fd), Int_val(wd)); + if (ret == -1) + caml_failwith("inotify_rm_watch"); + CAMLreturn(Val_unit); +} + +value stub_inotify_struct_size(void) +{ + CAMLparam0(); + CAMLreturn(Val_int(sizeof(struct inotify_event))); +} + +value stub_inotify_convert(value buf) +{ + CAMLparam1(buf); + CAMLlocal3(event, l, tmpl); + struct inotify_event ev; + int i; + + l = Val_emptylist; + tmpl = Val_emptylist; + + memcpy(&ev, String_val(buf), sizeof(struct inotify_event)); + + for (i = 0; inotify_return_table[i]; i++) { + if (!(ev.mask & inotify_return_table[i])) + continue; + tmpl = caml_alloc_small(2, Tag_cons); + Field(tmpl, 0) = Val_int(i); + Field(tmpl, 1) = l; + l = tmpl; + } + + event = caml_alloc_tuple(4); + Store_field(event, 0, Val_int(ev.wd)); + Store_field(event, 1, l); + Store_field(event, 2, caml_copy_int32(ev.cookie)); + Store_field(event, 3, Val_int(ev.len)); + + CAMLreturn(event); +} diff --git a/ocaml_inotify-0.1test.inotify.ml b/ocaml_inotify-0.1test.inotify.ml new file mode 100644 index 0000000..7b42363 --- /dev/null +++ b/ocaml_inotify-0.1test.inotify.ml @@ -0,0 +1,31 @@ +(* unit testing inotify *) + +open Printf + +let _ = + if Array.length Sys.argv < 2 then ( + eprintf "usage: %s \n" Sys.argv.(0); + exit 1 + ); + + let fd = Inotify.init () in + let wd = Inotify.add_watch fd Sys.argv.(1) [ Inotify.All ] in + + let string_of_event ev = + let wd,mask,cookie,s = ev in + let mask = String.concat ":" (List.map Inotify.string_of_event mask) in + let s = match s with Some s -> s | None -> "\"\"" in + sprintf "wd [%u] mask[%s] cookie[%ld] %s" wd mask cookie s + in + + let nb = ref 0 in + while true + do + let _, _, _ = Unix.select [ fd ] [] [] (-1.) in + let evs = Inotify.read fd in + List.iter (fun ev -> + printf "[%d] %s\n%!" !nb (string_of_event ev)) evs; + incr nb + done; + + Unix.close fd