* 1 Bugfix which might have caused vsys to block when reopened several times in succe...
[vsys.git] / dirwatcher.ml
1 (** Watches directories for events. Agnostic to vsys semantics of backends and
2   frontends *)
3 open Inotify
4 open Fdwatcher
5 open Printf
6 open Globals
7
8 (* I don't know if a wd corresponding to a deleted directory is evicted or just
9  * leaks - fix implementation of rmdir accordingly
10  *)
11 let wdmap = Hashtbl.create 1024
12 let masks = Hashtbl.create 1024
13
14 let fd = Inotify.init ()
15
16 let rec list_check lst elt =
17   match lst with
18     | [] -> false
19     | car::cdr -> if (car==elt) then true else list_check cdr elt
20
21 let handle_dir_event dirname evlist str = 
22   let fname = String.concat "/" [dirname;str] in
23     logprint "File: %s. " fname;
24     List.iter 
25       (fun e -> 
26          logprint "Event: %s\n" (string_of_event e)) 
27       evlist
28
29 let add_watch dir events handler =
30   let wd = Inotify.add_watch fd dir events in
31     Hashtbl.add wdmap wd (dir,Some(handler))
32       (* Ignore the possibility that the whole directory can disappear and come
33        * back while it is masked *)
34
35 let mask_watch fqp =
36   try 
37     Hashtbl.replace masks fqp true
38   with _ ->
39     ()
40
41 let unmask_watch fqp =
42   if (Hashtbl.mem masks fqp) then
43     begin
44       Hashtbl.remove masks fqp
45     end
46   else
47     logprint "WARNING: %s -- Unpaired unmask\n" fqp
48   
49 let asciiz s =
50   let rec findfirstnul str idx len =
51     if ((idx==len) || 
52         (str.[idx]==(char_of_int 0))) then idx
53     else
54       findfirstnul str (idx+1) len
55   in
56   let nulterm = findfirstnul s 0 (String.length s) in
57     String.sub s 0 nulterm
58
59 let receive_event (eventdescriptor:fname_and_fd) (bla:fname_and_fd) =
60   let (_,fd) = eventdescriptor in
61   let evs = Inotify.read fd in
62     List.iter (fun x->
63                  match x with
64                    | (wd,evlist,_,Some(str)) ->
65                        begin
66                                let purestr = asciiz(str) in
67                                let (dirname,handler) = 
68                                  try Hashtbl.find wdmap wd with Not_found->("",None)
69                                in
70                                    match handler with
71                                      | None->logprint "Unhandled watch descriptor\n"
72                                      | Some(handler)->
73                                          let fqp = String.concat "/" [dirname;purestr] in
74                                          let mask_filter = Hashtbl.mem masks fqp in
75                                            begin
76                                            if ((not mask_filter)) then
77                                              begin
78                                                 (*logprint "Received event for - %s\n"
79                                                         fqp;*)
80                                                 handler wd dirname evlist
81                                                  purestr
82                                              end
83                                            else
84                                              unmask_watch fqp
85                                            end
86                        end
87                    | _ -> ()) 
88       evs
89
90 let initialize () =
91   Fdwatcher.add_fd (None,fd) (None,fd) receive_event