#include #include #include #include #include #include #include #include #include "Clean.h" /** The empty string, as a CleanString */ static struct {int length; char chars[1]; } empty_string = {0,""}; /** * Poll an inotify file descriptor * * fd The inotify file descriptor to poll * timeout The timeout (negative for no timeout) * re_nrevents Will be set to the number of polled events * re_fd Will be set to fd (needed for uniqueness) */ void clean_poll(int fd, int timeout, int *re_nrevents, int *re_fd) { struct pollfd pfd = {fd, POLLIN, 0}; *re_nrevents = poll(&pfd, 1, timeout); *re_fd = fd; } /** * CleanStrings that are returned from clean_inotify_check (so that we don't * have to malloc all the time.) */ static CleanStringVariable(wds_string, 1024); static CleanStringVariable(masks_string, 1024); static CleanStringVariable(names_string, 4096); /** * Check for events on an inotify file descriptor. * * fd The inotify file descriptor * re_ok Will be set to 1 on success, 0 on failure * re_wds An array of ints, the watch descriptors that had events * re_masks An array of ints, the events * re_fnames A list of strings, the filenames of the events (may be empty) * re_fd Will be set to fd (needed for uniqueness) * * re_wds, re_masks and re_fnames are hacks because ccall doesn't allow * returning {#Int} or {#String}. The int arrays can be read by taking 4 chars * at a time and casting that to an int. The string array can be read by * splitting on \0 (since they are filenames, \0 cannot occur). */ void clean_inotify_check(int fd, int *re_ok, CleanString* re_wds, CleanString* re_masks, CleanString* re_fnames, int *re_fd) { char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event)))); const struct inotify_event *ev; ssize_t len; char *ptr; struct pollfd pfd = {fd, POLLIN, 0}; int poll_n; char *wds_ptr = CleanStringCharacters(wds_string); char *masks_ptr = CleanStringCharacters(masks_string); char *names_ptr = CleanStringCharacters(names_string); CleanStringLength(wds_string) = 0; CleanStringLength(masks_string) = 0; CleanStringLength(names_string) = 0; *re_ok = 0; *re_fd = fd; *re_wds = (CleanString) &empty_string; *re_masks = (CleanString) &empty_string; *re_fnames = (CleanString) &empty_string; for (;;) { poll_n = poll(&pfd, 1, 0); if (poll_n < 0) { return; } else if (poll_n == 0) { break; } len = read(fd, buf, sizeof buf); if (len == -1 && errno != EAGAIN) { return; } if (len <= 0) { break; } for (ptr = buf; ptr < buf + len; ptr += sizeof(struct inotify_event) + ev->len) { ev = (const struct inotify_event*) ptr; memcpy(masks_ptr, &ev->mask, 4); masks_ptr += 4; CleanStringLength(masks_string) += 4; memcpy(wds_ptr, &ev->wd, sizeof(int)); wds_ptr += sizeof(int); CleanStringLength(wds_string) += sizeof(int); memcpy (names_ptr,&ev->name,ev->len); names_ptr+=ev->len+1; *(names_ptr-1)='\0'; CleanStringLength (names_string)+=ev->len+1; } } *re_wds = (CleanString) wds_string; *re_masks = (CleanString) masks_string; *re_fnames = (CleanString) names_string; *re_ok = 1; }