2 #include <sys/inotify.h>
8 static int list2mask(interp
, list
, mask
) //<<<
16 static CONST
char *mask_bits
[] = {
29 "IN_CLOSE", // IN_CLOSE_WRITE | IN_CLOSE_NOWRITE
30 "IN_MOVE", // IN_MOVED_FROM | IN_MOVED_TO
62 TEST_OK(Tcl_ListObjGetElements(interp
, list
, &objc
, &objv
));
64 for (i
=0; i
<objc
; i
++) {
65 TEST_OK(Tcl_GetIndexFromObj(interp
, objv
[i
], mask_bits
, "mask bit",
76 static Tcl_Obj
*mask2list(uint32_t mask
) //<<<
78 Tcl_Obj
*result
= Tcl_NewListObj(0, NULL
);
80 #define CHECK_BIT(bit, str) \
81 if ((mask & bit) == bit) \
82 Tcl_ListObjAppendElement(NULL, result, Tcl_NewStringObj(str, -1));
84 CHECK_BIT(IN_ACCESS
, "IN_ACCESS");
85 CHECK_BIT(IN_ATTRIB
, "IN_ATTRIB");
86 CHECK_BIT(IN_CLOSE_WRITE
, "IN_CLOSE_WRITE");
87 CHECK_BIT(IN_CLOSE_NOWRITE
, "IN_CLOSE_NOWRITE");
88 CHECK_BIT(IN_CREATE
, "IN_CREATE");
89 CHECK_BIT(IN_DELETE
, "IN_DELETE");
90 CHECK_BIT(IN_DELETE_SELF
, "IN_DELETE_SELF");
91 CHECK_BIT(IN_MODIFY
, "IN_MODIFY");
92 CHECK_BIT(IN_MOVE_SELF
, "IN_MOVE_SELF");
93 CHECK_BIT(IN_MOVED_FROM
, "IN_MOVED_FROM");
94 CHECK_BIT(IN_MOVED_TO
, "IN_MOVED_TO");
95 CHECK_BIT(IN_OPEN
, "IN_OPEN");
96 CHECK_BIT(IN_IGNORED
, "IN_IGNORED");
97 CHECK_BIT(IN_ISDIR
, "IN_ISDIR");
98 CHECK_BIT(IN_Q_OVERFLOW
, "IN_Q_OVERFLOW");
99 CHECK_BIT(IN_UNMOUNT
, "IN_UNMOUNT");
105 static int glue_create_queue(cdata
, interp
, objc
, objv
) //<<<
109 Tcl_Obj
*CONST objv
[];
111 const char *channel_name
;
117 queue_fd
= inotify_init();
118 channel
= Tcl_MakeFileChannel((ClientData
)queue_fd
, TCL_READABLE
);
119 Tcl_RegisterChannel(interp
, channel
);
120 channel_name
= Tcl_GetChannelName(channel
);
122 Tcl_SetObjResult(interp
, Tcl_NewStringObj(channel_name
, -1));
128 static int get_queue_fd_from_chan(interp
, handle
, queue_fd
) //<<<
136 channel
= Tcl_GetChannel(interp
, Tcl_GetString(handle
), &chan_mode
);
138 THROW_ERROR("Invalid queue handle: ", Tcl_GetString(handle
));
140 if ((chan_mode
& TCL_READABLE
) != TCL_READABLE
)
141 THROW_ERROR("Queue exists, but is not readable. Wierd, man");
143 if (Tcl_GetChannelHandle(channel
, TCL_READABLE
, (ClientData
*)queue_fd
) != TCL_OK
) {
144 THROW_ERROR("Couldn't retrieve queue fd from channel");
151 static int glue_add_watch(cdata
, interp
, objc
, objv
) //<<<
155 Tcl_Obj
*CONST objv
[];
157 int queue_fd
, wd
, is_new
;
161 CHECK_ARGS(3, "queue path mask");
163 TEST_OK(get_queue_fd_from_chan(interp
, objv
[1], &queue_fd
));
164 path
= Tcl_GetString(objv
[2]);
165 TEST_OK(list2mask(interp
, objv
[3], &mask
));
167 wd
= inotify_add_watch(queue_fd
, path
, mask
);
169 THROW_ERROR("Problem creating watch on ", path
);
171 Tcl_SetObjResult(interp
, Tcl_NewIntObj(wd
));
177 static int glue_rm_watch(cdata
, interp
, objc
, objv
) //<<<
181 Tcl_Obj
*CONST objv
[];
183 int queue_fd
, wd
, ret
;
185 CHECK_ARGS(2, "queue wd");
187 TEST_OK(get_queue_fd_from_chan(interp
, objv
[1], &queue_fd
));
188 TEST_OK(Tcl_GetIntFromObj(interp
, objv
[2], &wd
));
190 ret
= inotify_rm_watch(queue_fd
, wd
);
192 Tcl_SetObjResult(interp
, Tcl_NewIntObj(ret
));
198 static int glue_decode_events(cdata
, interp
, objc
, objv
) //<<<
202 Tcl_Obj
*CONST objv
[];
205 int raw_len
, remaining
, eventsize
, offset
;
206 struct inotify_event
*event
;
209 CHECK_ARGS(1, "raw_event_data");
211 raw
= Tcl_GetByteArrayFromObj(objv
[1], &raw_len
);
215 event
= (struct inotify_event
*)(raw
+ offset
);
217 result
= Tcl_NewListObj(0, NULL
);
219 while (remaining
> 0) {
220 Tcl_Obj
*evdata
= Tcl_NewListObj(0, NULL
);
222 eventsize
= sizeof(struct inotify_event
) + event
->len
;
223 remaining
-= eventsize
;
226 #define ADD_ELEM(elem) \
227 TEST_OK(Tcl_ListObjAppendElement(interp, evdata, elem));
229 ADD_ELEM(Tcl_NewIntObj(event
->wd
));
230 ADD_ELEM(mask2list(event
->mask
));
231 ADD_ELEM(Tcl_NewIntObj(event
->cookie
));
232 //ADD_ELEM(Tcl_NewIntObj(event->len));
233 if (event
->len
> 0) {
234 // Why not give event->len as the length? len includes null padding
235 ADD_ELEM(Tcl_NewStringObj(event
->name
, -1));
237 ADD_ELEM(Tcl_NewStringObj("", 0));
240 TEST_OK(Tcl_ListObjAppendElement(interp
, result
, evdata
));
242 event
= (struct inotify_event
*)(raw
+ offset
);
245 Tcl_SetObjResult(interp
, result
);
251 int Inotify_Init(Tcl_Interp
*interp
) //<<<
253 if (Tcl_InitStubs(interp
, "8.1", 0) == NULL
)
256 if (sizeof(ClientData
) < sizeof(int))
257 THROW_ERROR("On this platform ints are bigger than pointers. That freaks us out, sorry");
259 NEW_CMD("inotify::create_queue", glue_create_queue
);
260 NEW_CMD("inotify::add_watch", glue_add_watch
);
261 NEW_CMD("inotify::rm_watch", glue_rm_watch
);
262 NEW_CMD("inotify::decode_events", glue_decode_events
);
268 // vim: foldmethod=marker foldmarker=<<<,>>>