Skip to content

Commit

Permalink
initial implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
T Ar Creator authored and g2p committed Feb 17, 2010
0 parents commit cac0bd8
Show file tree
Hide file tree
Showing 4 changed files with 302 additions and 0 deletions.
42 changes: 42 additions & 0 deletions 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)
106 changes: 106 additions & 0 deletions ocaml_inotify-0.1inotify.ml
@@ -0,0 +1,106 @@
(*
* Copyright (C) 2006 Vincent Hanquez <vincent@snarc.org>
*
* 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
123 changes: 123 additions & 0 deletions ocaml_inotify-0.1inotify_stubs.c
@@ -0,0 +1,123 @@
/*
* Copyright (C) 2006 Vincent Hanquez <vincent@snarc.org>
*
* 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 <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/inotify.h>
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/alloc.h>
#include <caml/custom.h>
#include <caml/fail.h>
#include <caml/signals.h>

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);
}
31 changes: 31 additions & 0 deletions 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 <path>\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

0 comments on commit cac0bd8

Please sign in to comment.