mon_inotify.c
5.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*
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 "error.h"
#include "sync.h"
#include "indexes.h"
#include "privileged.h"
#include "mon_inotify.h"
enum event_bits {
UEM_DIR = 0x01,
UEM_CREATED = 0x02,
UEM_DELETED = 0x04,
};
struct recognize_event_return {
eventobjtype_t objtype_old;
eventobjtype_t objtype_new;
};
static inline void recognize_event(struct recognize_event_return *r, uint32_t event) {
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->objtype_old = (is_created ? EOT_DOESNTEXIST : type);
r->objtype_new = (is_deleted ? EOT_DOESNTEXIST : type);
return;
}
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 privileged_inotify_add_watch(inotify_d, accpath, INOTIFY_MARKMASK, PC_INOTIFY_ADD_WATCH_DIR);
}
int inotify_wait(ctx_t *ctx_p, struct indexes *indexes_p, struct timeval *tv_p) {
int inotify_d = (int)(long)ctx_p->fsmondata;
debug(3, "select with timeout %li secs (fd == %u).", tv_p->tv_sec, inotify_d);
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(inotify_d, &rfds);
return select(inotify_d+1, &rfds, NULL, NULL, tv_p);
}
#define INOTIFY_HANDLE_CONTINUE {\
ptr += sizeof(struct inotify_event) + event->len;\
count++;\
continue;\
}
int inotify_handle(ctx_t *ctx_p, indexes_t *indexes_p) {
static struct timeval tv={0};
int inotify_d = (int)(long)ctx_p->fsmondata;
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
struct recognize_event_return r = {0};
recognize_event(&r, event->mask);
stat64_t lstat, *lstat_p;
mode_t st_mode;
size_t st_size;
if ((r.objtype_new == EOT_DOESNTEXIST) || (ctx_p->flags[CANCEL_SYSCALLS]&CSC_MON_STAT) || lstat64(path_full, &lstat)) {
debug(2, "Cannot lstat64(\"%s\", lstat). Seems, that the object had been deleted (%i) or option \"--cancel-syscalls mon_stat\" (%i) is set.", path_full, r.objtype_new == EOT_DOESNTEXIST, ctx_p->flags[CANCEL_SYSCALLS]&CSC_MON_STAT);
st_mode = (event->mask & IN_ISDIR ? S_IFDIR : S_IFREG);
st_size = 0;
lstat_p = NULL;
} else {
st_mode = lstat.st_mode;
st_size = lstat.st_size;
lstat_p = &lstat;
}
if (sync_prequeue_loadmark(1, ctx_p, indexes_p, path_full, NULL, lstat_p, r.objtype_old, r.objtype_new, event->mask, event->wd, st_mode, st_size, &path_rel, &path_rel_len, NULL)) {
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;
}
int inotify_deinit(ctx_t *ctx_p) {
int inotify_d = (int)(long)ctx_p->fsmondata;
debug(3, "Closing inotify_d");
return close(inotify_d);
}