123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131(*
* Copyright (C) 2006-2008 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.1 only. with the special
* exception on linking described in file LICENSE.
*
* 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 Lesser General Public License for more details.
*
* Inotify OCaml binding
*)typeselector=|S_Access|S_Attrib|S_Close_write|S_Close_nowrite|S_Create|S_Delete|S_Delete_self|S_Modify|S_Move_self|S_Moved_from|S_Moved_to|S_Open|S_Dont_follow|S_Mask_add|S_Oneshot|S_Onlydir(* convenience *)|S_Move|S_Close|S_Alltypeevent_kind=|Access|Attrib|Close_write|Close_nowrite|Create|Delete|Delete_self|Modify|Move_self|Moved_from|Moved_to|Open|Ignored|Isdir|Q_overflow|Unmountletstring_of_event_kind=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"typewatch=inttypeevent=watch*event_kindlist*int32*stringoptionexternalcreate:unit->Unix.file_descr="caml_inotify_init"externaladd_watch:Unix.file_descr->string->selectorlist->watch="caml_inotify_add_watch"externalrm_watch:Unix.file_descr->watch->unit="caml_inotify_rm_watch"externalconvert:Bytes.t->(watch*event_kindlist*int32*int)="caml_inotify_convert"externalstruct_size:unit->int="caml_inotify_struct_size"externalname_max:unit->int="caml_inotify_name_max"letint_of_watchwatch=watchletwatch_of_intwatch=watchletstring_of_event(watch,events,cookie,name)=Printf.sprintf"watch=%d cookie=%ld events=%s%s"watchcookie(String.concat"|"(List.mapstring_of_event_kindevents))(matchnamewith|None->""|Somename'->Printf.sprintf" %S"name')letreadfd=(* Turns out that reading from blocking descriptors always requires a buffer
of the maximum size, which is, from the inotify man page:
The behavior when the buffer given to read(2) is too small to return
information about the next event depends on the kernel version: in
kernels before 2.6.21, read(2) returns 0; since kernel 2.6.21,
read(2) fails with the error EINVAL. Specifying a buffer of size
sizeof(struct inotify_event) + NAME_MAX + 1
*)letevent_size=struct_size()inletbuf_size=event_size+(name_max())+1inletbuf=Bytes.createbuf_sizeinletbytes_read=Unix.readfdbuf0buf_sizeinletread_c_stringpos=Bytes.sub_stringbufpos((Bytes.index_frombufpos'\x00')-pos)inletrecread_oneposrest=ifbytes_read<pos+event_sizethenrestelseletwatch,mask,cookie,len=convert(Bytes.subbufposevent_size)inifbytes_read<pos+event_size+lenthenrestelseletname=iflen>0thenSome(read_c_string(pos+event_size))elseNoneinread_one(pos+event_size+len)((watch,mask,cookie,name)::rest)inList.rev(read_one0[])