Blame view

mon_inotify.c 5.15 KB
redmine authored
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
    clsync - file tree sync utility based on inotify/kqueue
    
    Copyright (C) 2013-2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    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 General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "common.h"
#include "port-hacks.h"
#include "error.h"
#include "sync.h"
#include "indexes.h"
redmine authored
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
#include "mon_inotify.h"

enum event_bits {
	UEM_DIR		= 0x01,
	UEM_CREATED	= 0x02,
	UEM_DELETED	= 0x04,
};

struct recognize_event_return {
	union {
		struct {
			eventobjtype_t objtype_old:16;
			eventobjtype_t objtype_new:16;
		} v;
		uint32_t i;
	} u;
};

static inline uint32_t recognize_event(uint32_t event) {
redmine authored
44
	struct recognize_event_return r = {{{0}}};
redmine authored
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66

	eventobjtype_t type;
	int is_created;
	int is_deleted;

	type = (event & IN_ISDIR ? EOT_DIR : EOT_FILE);
	is_created = event & (IN_CREATE|IN_MOVED_TO);
	is_deleted = event & (IN_DELETE_SELF|IN_DELETE|IN_MOVED_FROM);

	debug(4, "type == %x; is_created == %x; is_deleted == %x", type, is_created, is_deleted);

	r.u.v.objtype_old = type;
	r.u.v.objtype_new = type;

	if (is_created)
		r.u.v.objtype_old = EOT_DOESNTEXIST;

	if (is_deleted)
		r.u.v.objtype_new = EOT_DOESNTEXIST;

	return r.u.i;
}
redmine authored
67

redmine authored
68 69 70 71
int inotify_add_watch_dir(ctx_t *ctx_p, indexes_t *indexes_p, const char *const accpath) {
	int inotify_d = (int)(long)ctx_p->fsmondata;
	return inotify_add_watch(inotify_d, accpath, INOTIFY_MARKMASK);
}
redmine authored
72

redmine authored
73
int inotify_wait(ctx_t *ctx_p, struct indexes *indexes_p, struct timeval *tv_p) {
redmine authored
74
	int inotify_d = (int)(long)ctx_p->fsmondata;
redmine authored
75

redmine authored
76
	debug(3, "select with timeout %li secs.", tv_p->tv_sec);
redmine authored
77 78 79
	fd_set rfds;
	FD_ZERO(&rfds);
	FD_SET(inotify_d, &rfds);
redmine authored
80
	return select(inotify_d+1, &rfds, NULL, NULL, tv_p);
redmine authored
81 82 83 84 85 86 87 88
}

#define INOTIFY_HANDLE_CONTINUE {\
	ptr += sizeof(struct inotify_event) + event->len;\
	count++;\
	continue;\
}

redmine authored
89
int inotify_handle(ctx_t *ctx_p, indexes_t *indexes_p) {
redmine authored
90
	static struct timeval tv={0};
redmine authored
91
	int inotify_d = (int)(long)ctx_p->fsmondata;
redmine authored
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158

	int count = 0;

	fd_set rfds;
	FD_ZERO(&rfds);
	FD_SET(inotify_d, &rfds);

	char   *path_rel	= NULL;
	size_t  path_rel_len	= 0;
	char   *path_full	= NULL;
	size_t  path_full_size	= 0;
	while (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) {

		char buf[BUFSIZ + 1];
		size_t r = read(inotify_d, buf, BUFSIZ);
		if (r <= 0) {
			error("Got error while reading events from inotify with read().");
			count = -1;
			goto l_inotify_handle_end;
		}

#ifdef PARANOID
		g_hash_table_remove_all(indexes_p->fpath2ei_ht);
#endif

		char *ptr =  buf;
		char *end = &buf[r];
		while (ptr < end) {
			struct inotify_event *event = (struct inotify_event *)ptr;

			// Removing stale wd-s

			if(event->mask & IN_IGNORED) {
				debug(2, "Cleaning up info about watch descriptor %i.", event->wd);
				indexes_remove_bywd(indexes_p, event->wd);
				INOTIFY_HANDLE_CONTINUE;
			}

			// Getting path

			char *fpath = indexes_wd2fpath(indexes_p, event->wd);

			if(fpath == NULL) {
				debug(2, "Event %p on stale watch (wd: %i).", (void *)(long)event->mask, event->wd);
				INOTIFY_HANDLE_CONTINUE;
			}
			debug(2, "Event %p on \"%s\" (wd: %i; fpath: \"%s\").", (void *)(long)event->mask, event->len>0?event->name:"", event->wd, fpath);

			// Getting full path

			size_t path_full_memreq = strlen(fpath) + event->len + 2;
			if (path_full_size < path_full_memreq) {
				path_full      = xrealloc(path_full, path_full_memreq);
				path_full_size = path_full_memreq;
			}

			if (event->len>0)
				sprintf(path_full, "%s/%s", fpath, event->name);
			else
				sprintf(path_full, "%s", fpath);

			// Getting infomation about file/dir/etc

			stat64_t lstat;
			mode_t st_mode;
			size_t st_size;
			if (lstat64(path_full, &lstat)) {
redmine authored
159
				debug(2, "Cannot lstat64(\"%s\", lstat). Seems, that the object disappeared.", path_full);
redmine authored
160 161 162 163 164 165 166 167 168 169
				if(event->mask & IN_ISDIR)
					st_mode = S_IFDIR;
				else
					st_mode = S_IFREG;
				st_size = 0;
			} else {
				st_mode = lstat.st_mode;
				st_size = lstat.st_size;
			}

redmine authored
170 171 172 173
			struct  recognize_event_return r;
			r.u.i = recognize_event(event->mask);

			if (sync_prequeue_loadmark(1, ctx_p, indexes_p, path_full, NULL, r.u.v.objtype_old, r.u.v.objtype_new, event->mask, event->wd, st_mode, st_size, &path_rel, &path_rel_len, NULL)) {
redmine authored
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
				count = -1;
				goto l_inotify_handle_end;
			}

			INOTIFY_HANDLE_CONTINUE;
		}

		// Globally queueing captured events:
		// Moving events from local queue to global ones
		sync_prequeue_unload(ctx_p, indexes_p);
	}

l_inotify_handle_end:
	if(path_full != NULL)
		free(path_full);

	if(path_rel != NULL)
		free(path_rel);

	return count;
}
redmine authored
195 196 197 198 199 200 201

int inotify_deinit(ctx_t *ctx_p) {
	int inotify_d = (int)(long)ctx_p->fsmondata;
	debug(3, "Closing inotify_d");
	return close(inotify_d);
}