inotify_c.c 3.27 KB
Newer Older
Camil Staps's avatar
Camil Staps committed
1 2 3 4 5 6 7 8 9 10 11
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/inotify.h>
#include <unistd.h>

#include "Clean.h"

12
/** The empty string, as a CleanString */
Camil Staps's avatar
Camil Staps committed
13 14
static struct {int length; char chars[1]; } empty_string = {0,""};

15 16 17 18 19 20 21 22 23
/**
 * 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) {
Camil Staps's avatar
Camil Staps committed
24
	struct pollfd pfd = {fd, POLLIN, 0};
25
	*re_nrevents = poll(&pfd, 1, timeout);
Camil Staps's avatar
Camil Staps committed
26 27 28
	*re_fd = fd;
}

29 30 31 32
/**
 * CleanStrings that are returned from clean_inotify_check (so that we don't
 * have to malloc all the time.)
 */
Camil Staps's avatar
Camil Staps committed
33 34
static CleanStringVariable(wds_string, 1024);
static CleanStringVariable(masks_string, 1024);
35
static CleanStringVariable(names_string, 4096);
Camil Staps's avatar
Camil Staps committed
36

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
/**
 * 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).
 */
Camil Staps's avatar
Camil Staps committed
52
void clean_inotify_check(int fd,
53 54
		int *re_ok, CleanString* re_wds, CleanString* re_masks,
		CleanString* re_fnames, int *re_fd) {
Camil Staps's avatar
Camil Staps committed
55 56 57 58 59 60 61 62 63 64
	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);
65
	char *names_ptr = CleanStringCharacters(names_string);
Camil Staps's avatar
Camil Staps committed
66 67
	CleanStringLength(wds_string) = 0;
	CleanStringLength(masks_string) = 0;
68
	CleanStringLength(names_string) = 0;
Camil Staps's avatar
Camil Staps committed
69 70 71 72 73 74

	*re_ok = 0;
	*re_fd = fd;

	*re_wds = (CleanString) &empty_string;
	*re_masks = (CleanString) &empty_string;
75
	*re_fnames = (CleanString) &empty_string;
Camil Staps's avatar
Camil Staps committed
76 77

	for (;;) {
78
		poll_n = poll(&pfd, 1, 0);
Camil Staps's avatar
Camil Staps committed
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
		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);
104 105 106 107 108 109

			int len = strlen(ev->name);
			memcpy(names_ptr, &ev->name, len);
			names_ptr += len + 1;
			*(names_ptr - 1) = '\00';
			CleanStringLength(names_string) += len + 1;
Camil Staps's avatar
Camil Staps committed
110 111 112 113 114
		}
	}

	*re_wds = (CleanString) wds_string;
	*re_masks = (CleanString) masks_string;
115
	*re_fnames = (CleanString) names_string;
Camil Staps's avatar
Camil Staps committed
116 117 118

	*re_ok = 1;
}