16#include "../../config.h"
17#include "inotifytools_p.h"
31#include <sys/select.h>
37#include "inotifytools/inotify.h"
40struct fanotify_event_fid;
42#define FAN_EVENT_INFO_TYPE_FID 1
43#define FAN_EVENT_INFO_TYPE_DFID_NAME 2
44#define FAN_EVENT_INFO_TYPE_DFID 3
46#elif !defined __ANDROID__
52#include "inotifytools/fanotify.h"
56#define __kernel_fsid_t fsid_t
59struct fanotify_event_info_fid_wo_handle {
60 struct fanotify_event_info_header hdr;
64struct fanotify_event_fid {
65 struct fanotify_event_info_fid_wo_handle info;
66 struct file_handle handle;
157#define MAX_EVENTS 4096
158#define INOTIFY_PROCDIR "/proc/sys/fs/inotify/"
159#define WATCHES_SIZE_PATH INOTIFY_PROCDIR "max_user_watches"
160#define QUEUE_SIZE_PATH INOTIFY_PROCDIR "max_queued_watches"
161#define INSTANCES_PATH INOTIFY_PROCDIR "max_user_instances"
163static int inotify_fd = -1;
165static int recursive_watch = 0;
166int collect_stats = 0;
168struct rbtree* tree_wd = 0;
169struct rbtree* tree_fid = 0;
170struct rbtree* tree_filename = 0;
174int fanotify_mode = 0;
175int fanotify_mark_type = 0;
176static pid_t self_pid = 0;
183 bool empty() {
return !size_; }
192 void set_size(
int size) {
194 if (size > capacity_)
198 ~str() { free(c_str_); }
202static regex_t* regex = 0;
204static int invert_regexp = 0;
206static int isdir(
char const* path);
207void record_stats(
struct inotify_event
const* event);
208int onestr_to_event(
char const* event);
210#define nasprintf(...) niceassert(-1 != asprintf(__VA_ARGS__), "out of memory")
229long _niceassert(
long cond,
238 fprintf(stderr,
"%s:%d assertion ( %s ) failed: %s\n", file,
239 line, condstr, mesg);
241 fprintf(stderr,
"%s:%d assertion ( %s ) failed.\n", file, line,
248static void charcat(
char* s,
const char c) {
249 size_t l = strlen(s);
257static int read_num_from_file(
const char* filename,
int* num) {
258 FILE* file = fopen(filename,
"r");
264 if (EOF == fscanf(file,
"%d", num)) {
266 const int fclose_ret = fclose(file);
267 niceassert(!fclose_ret, 0);
271 const int fclose_ret = fclose(file);
272 niceassert(!fclose_ret, 0);
277static int wd_compare(
const char* d1,
const char* d2,
const void* config) {
280 return ((watch*)d1)->wd - ((watch*)d2)->wd;
283static int fid_compare(
const char* d1,
const char* d2,
const void* config) {
287 watch* w1 = (watch*)d1;
288 watch* w2 = (watch*)d2;
290 n1 = w1->fid->info.hdr.len;
291 n2 = w2->fid->info.hdr.len;
294 return memcmp(w1->fid, w2->fid, n1);
300static int filename_compare(
const char* d1,
302 const void* config) {
305 return strcmp(((watch*)d1)->filename, ((watch*)d2)->filename);
311watch* watch_from_wd(
int wd) {
314 return (watch*)rbfind(&w, tree_wd);
320watch* watch_from_fid(
struct fanotify_event_fid* fid) {
323 return (watch*)rbfind(&w, tree_fid);
329watch* watch_from_filename(
char const* filename) {
331 w.filename = (
char*)filename;
332 return (watch*)rbfind(&w, tree_filename);
357 watch_filesystem ? FAN_MARK_FILESYSTEM : FAN_MARK_INODE;
359 fanotify_init(FAN_REPORT_FID | FAN_REPORT_DFID_NAME, 0);
363 inotify_fd = inotify_init();
365 if (inotify_fd < 0) {
372 tree_wd = rbinit(wd_compare, 0);
373 tree_fid = rbinit(fid_compare, 0);
374 tree_filename = rbinit(filename_compare, 0);
380int inotifytools_initialize() {
387void destroy_watch(watch* w) {
400void cleanup_tree(
const void* nodep,
404 if (which != endorder && which != leaf)
406 watch* w = (watch*)nodep;
432 rbwalk(tree_wd, cleanup_tree, 0);
435 rbdestroy(tree_filename);
444struct replace_filename_data {
445 char const* old_name;
446 char const* new_name;
453static void replace_filename_impl(
const void* nodep,
456 const struct replace_filename_data* data) {
457 if (which != endorder && which != leaf)
459 watch* w = (watch*)nodep;
461 if (0 == strncmp(data->old_name, w->filename, data->old_len)) {
462 nasprintf(&name,
"%s%s", data->new_name,
463 &(w->filename[data->old_len]));
464 if (!strcmp(w->filename, data->new_name)) {
467 rbdelete(w, tree_filename);
470 rbsearch(w, tree_filename);
478static void replace_filename(
const void* nodep,
482 replace_filename_impl(nodep, which, depth,
483 (
const struct replace_filename_data*)data);
489static void get_num(
const void* nodep,
493 if (which != endorder && which != leaf)
527 "abcdefghijklmnopqrstuvwxyz"
528 "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
534 char *event1, *event2;
535 static const size_t eventstr_size = 4096;
536 char eventstr[eventstr_size];
539 if (!event || !event[0])
542 event1 = (
char*)event;
543 event2 = strchr(event1, sep);
544 while (event1 && event1[0]) {
546 len = event2 - event1;
547 niceassert(len < eventstr_size,
548 "malformed event string (very long)");
550 len = strlen(event1);
552 if (len > eventstr_size - 1)
553 len = eventstr_size - 1;
555 strncpy(eventstr, event1, len);
559 int ret1 = onestr_to_event(eventstr);
560 if (0 == ret1 || -1 == ret1) {
567 if (event1 && event1[0]) {
573 event2 = strchr(event1, sep);
618int onestr_to_event(
char const* event) {
622 if (!event || !event[0])
624 else if (0 == strcasecmp(event,
"ACCESS"))
626 else if (0 == strcasecmp(event,
"MODIFY"))
628 else if (0 == strcasecmp(event,
"ATTRIB"))
630 else if (0 == strcasecmp(event,
"CLOSE_WRITE"))
631 ret = IN_CLOSE_WRITE;
632 else if (0 == strcasecmp(event,
"CLOSE_NOWRITE"))
633 ret = IN_CLOSE_NOWRITE;
634 else if (0 == strcasecmp(event,
"OPEN"))
636 else if (0 == strcasecmp(event,
"MOVED_FROM"))
638 else if (0 == strcasecmp(event,
"MOVED_TO"))
640 else if (0 == strcasecmp(event,
"CREATE"))
642 else if (0 == strcasecmp(event,
"DELETE"))
644 else if (0 == strcasecmp(event,
"DELETE_SELF"))
645 ret = IN_DELETE_SELF;
646 else if (0 == strcasecmp(event,
"UNMOUNT"))
648 else if (0 == strcasecmp(event,
"Q_OVERFLOW"))
650 else if (0 == strcasecmp(event,
"IGNORED"))
652 else if (0 == strcasecmp(event,
"CLOSE"))
654 else if (0 == strcasecmp(event,
"MOVE_SELF"))
656 else if (0 == strcasecmp(event,
"MOVE"))
658 else if (0 == strcasecmp(event,
"ISDIR"))
660 else if (0 == strcasecmp(event,
"ONESHOT"))
662 else if (0 == strcasecmp(event,
"ALL_EVENTS"))
718 static char ret[1024];
722 if (IN_ACCESS & events) {
724 strncat(ret,
"ACCESS", 7);
726 if (IN_MODIFY & events) {
728 strncat(ret,
"MODIFY", 7);
730 if (IN_ATTRIB & events) {
732 strncat(ret,
"ATTRIB", 7);
734 if (IN_CLOSE_WRITE & events) {
736 strncat(ret,
"CLOSE_WRITE", 12);
738 if (IN_CLOSE_NOWRITE & events) {
740 strncat(ret,
"CLOSE_NOWRITE", 14);
742 if (IN_OPEN & events) {
744 strncat(ret,
"OPEN", 5);
746 if (IN_MOVED_FROM & events) {
748 strncat(ret,
"MOVED_FROM", 11);
750 if (IN_MOVED_TO & events) {
752 strncat(ret,
"MOVED_TO", 9);
754 if (IN_CREATE & events) {
756 strncat(ret,
"CREATE", 7);
758 if (IN_DELETE & events) {
760 strncat(ret,
"DELETE", 7);
762 if (IN_DELETE_SELF & events) {
764 strncat(ret,
"DELETE_SELF", 12);
766 if (IN_UNMOUNT & events) {
768 strncat(ret,
"UNMOUNT", 8);
770 if (IN_Q_OVERFLOW & events) {
772 strncat(ret,
"Q_OVERFLOW", 11);
774 if (IN_IGNORED & events) {
776 strncat(ret,
"IGNORED", 8);
778 if (IN_CLOSE & events) {
780 strncat(ret,
"CLOSE", 6);
782 if (IN_MOVE_SELF & events) {
784 strncat(ret,
"MOVE_SELF", 10);
786 if (IN_ISDIR & events) {
788 strncat(ret,
"ISDIR", 6);
790 if (IN_ONESHOT & events) {
792 strncat(ret,
"ONESHOT", 8);
796 if (ret[0] ==
'\0') {
797 niceassert(-1 != sprintf(ret,
"%c0x%08x", sep, events), 0);
809static const char* inotifytools_filename_from_fid(
810 struct fanotify_event_fid* fid) {
812 static char filename[PATH_MAX];
813 struct fanotify_event_fid fsid = {};
814 int dirf = 0, mount_fd = AT_FDCWD;
815 int len = 0, name_len = 0;
818 fsid.info.fsid.val[0] = fid->info.fsid.val[0];
819 fsid.info.fsid.val[1] = fid->info.fsid.val[1];
820 fsid.info.hdr.info_type = FAN_EVENT_INFO_TYPE_FID;
821 fsid.info.hdr.len =
sizeof(fsid);
822 watch* mnt = watch_from_fid(&fsid);
824 mount_fd = mnt->dirf;
826 if (fid->info.hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME) {
827 int fid_len =
sizeof(*fid) + fid->handle.handle_bytes;
829 name_len = fid->info.hdr.len - fid_len;
830 if (name_len && !fid->handle.f_handle[fid->handle.handle_bytes])
835 dirf = open_by_handle_at(mount_fd, &fid->handle, 0);
838 }
else if (fanotify_mark_type == FAN_MARK_FILESYSTEM) {
839 fprintf(stderr,
"Failed to decode directory fid.\n");
841 }
else if (name_len) {
843 fid->info.hdr.info_type = FAN_EVENT_INFO_TYPE_DFID;
844 fid->info.hdr.len -= name_len;
846 watch* w = watch_from_fid(fid);
848 fid->info.hdr.info_type = FAN_EVENT_INFO_TYPE_DFID_NAME;
849 fid->info.hdr.len += name_len;
853 "Failed to lookup path by directory fid.\n");
857 dirf = w->dirf ? dup(w->dirf) : -1;
859 fprintf(stderr,
"Failed to get directory fd.\n");
867 sprintf(sym,
"/proc/self/fd/%d", dirf);
871 len = readlink(sym, filename, PATH_MAX - 2);
874 fprintf(stderr,
"Failed to resolve path from directory fd.\n");
878 filename[len++] =
'/';
882 const char* name = (
const char*)fid->handle.f_handle +
883 fid->handle.handle_bytes;
884 int deleted = faccessat(dirf, name, F_OK, AT_SYMLINK_NOFOLLOW);
885 if (deleted && errno != ENOENT) {
886 fprintf(stderr,
"Failed to access file %s (%s).\n",
887 name, strerror(errno));
891 memcpy(filename + len, name, name_len);
893 strncat(filename,
" (deleted)", 11);
911 if (!w->fid || !fanotify_mark_type)
914 return inotifytools_filename_from_fid(w->fid) ?: w->filename;
938 niceassert(initialized,
"inotifytools_initialize not called yet");
941 watch* w = watch_from_wd(wd);
957 size_t* dirnamelen) {
959 const char* dirsep = NULL;
967 dirsep = strrchr(filename,
'/');
969 *dirnamelen = strlen(filename);
973 *dirnamelen = dirsep - filename + 1;
986 char const** eventname,
987 size_t* dirnamelen) {
989 *eventname =
event->name;
993 const char* filename =
997 if (filename && filename[*dirnamelen])
998 *eventname = filename + *dirnamelen;
1014 if (!filename || !*filename || !(event->mask & IN_ISDIR)) {
1023 nasprintf(&path,
"%s%s/", filename, fanotify_mode ?
"" : event->name);
1043 niceassert(initialized,
"inotifytools_initialize not called yet");
1044 if (!filename || !*filename)
1046 watch* w = watch_from_filename(filename);
1067 niceassert(initialized,
"inotifytools_initialize not called yet");
1068 watch* w = watch_from_wd(wd);
1073 w->filename = strdup(filename);
1091 char const* newname) {
1092 watch* w = watch_from_filename(oldname);
1097 w->filename = strdup(newname);
1123 if (!oldname || !newname)
1125 if (!*oldname || !*newname)
1127 struct replace_filename_data data;
1128 data.old_name = oldname;
1129 data.new_name = newname;
1130 data.old_len = strlen(oldname);
1131 rbwalk(tree_filename, replace_filename, (
void*)&data);
1137int remove_inotify_watch(watch* w) {
1142 int status = inotify_rm_watch(inotify_fd, w->wd);
1144 fprintf(stderr,
"Failed to remove watch on %s: %s\n",
1145 w->filename, strerror(status));
1155watch* create_watch(
int wd,
1156 struct fanotify_event_fid* fid,
1157 const char* filename,
1159 if (wd < 0 || !filename)
1162 watch* w = (watch*)calloc(1,
sizeof(watch));
1164 fprintf(stderr,
"Failed to allocate watch.\n");
1167 w->wd = wd ?: (
unsigned long)fid;
1170 w->filename = strdup(filename);
1171 rbsearch(w, tree_wd);
1173 rbsearch(w, tree_fid);
1175 rbsearch(w, tree_filename);
1192 niceassert(initialized,
"inotifytools_initialize not called yet");
1193 watch* w = watch_from_wd(wd);
1197 if (!remove_inotify_watch(w))
1199 rbdelete(w, tree_wd);
1201 rbdelete(w, tree_fid);
1202 rbdelete(w, tree_filename);
1219 niceassert(initialized,
"inotifytools_initialize not called yet");
1220 watch* w = watch_from_filename(filename);
1224 if (!remove_inotify_watch(w))
1226 rbdelete(w, tree_wd);
1228 rbdelete(w, tree_fid);
1229 rbdelete(w, tree_filename);
1246 static char const* filenames[2];
1247 filenames[0] = filename;
1248 filenames[1] = NULL;
1268 niceassert(initialized,
"inotifytools_initialize not called yet");
1272 for (i = 0; filenames[i]; ++i) {
1274 if (fanotify_mode) {
1275#ifdef LINUX_FANOTIFY
1276 unsigned int flags = FAN_MARK_ADD | fanotify_mark_type;
1278 if (events & IN_DONT_FOLLOW) {
1279 events &= ~IN_DONT_FOLLOW;
1280 flags |= FAN_MARK_DONT_FOLLOW;
1283 wd = fanotify_mark(inotify_fd, flags,
1284 events | FAN_EVENT_ON_CHILD,
1285 AT_FDCWD, filenames[i]);
1289 inotify_add_watch(inotify_fd, filenames[i], events);
1299 "Failed to watch %s: returned wd was %d "
1300 "(expected -1 or >0 )",
1307 const char* filename = filenames[i];
1308 size_t filenamelen = strlen(filename);
1312 if (!isdir(filename)) {
1314 }
else if (filename[filenamelen - 1] ==
'/') {
1315 dirname = strdup(filename);
1317 nasprintf(&dirname,
"%s/", filename);
1322 struct fanotify_event_fid* fid = NULL;
1323#ifdef LINUX_FANOTIFY
1325 fid = (fanotify_event_fid*)calloc(
1326 1,
sizeof(*fid) + MAX_FID_LEN);
1328 fprintf(stderr,
"Failed to allocate fid");
1334 if (statfs(filenames[i], &buf)) {
1336 fprintf(stderr,
"Statfs failed on %s: %s\n",
1337 filenames[i], strerror(errno));
1341 memcpy(&fid->info.fsid, &buf.f_fsid,
1342 sizeof(__kernel_fsid_t));
1346 watch* mnt = dirname ? watch_from_fid(fid) : NULL;
1347 if (dirname && !mnt) {
1348 struct fanotify_event_fid* fsid;
1350 fsid = (fanotify_event_fid*)calloc(
1355 "Failed to allocate fsid");
1359 fsid->info.fsid.val[0] = fid->info.fsid.val[0];
1360 fsid->info.fsid.val[1] = fid->info.fsid.val[1];
1361 fsid->info.hdr.info_type =
1362 FAN_EVENT_INFO_TYPE_FID;
1363 fsid->info.hdr.len =
sizeof(*fsid);
1364 mntid = open(dirname, O_RDONLY);
1369 "Failed to open %s: %s\n",
1370 dirname, strerror(errno));
1375 dirname[filenamelen - 1] = 0;
1376 create_watch(0, fsid, dirname, mntid);
1377 dirname[filenamelen - 1] =
'/';
1380 fid->handle.handle_bytes = MAX_FID_LEN;
1381 ret = name_to_handle_at(AT_FDCWD, filenames[i],
1382 &fid->handle, &mntid, 0);
1383 if (ret || fid->handle.handle_bytes > MAX_FID_LEN) {
1385 fprintf(stderr,
"Encode fid failed on %s: %s\n",
1386 filenames[i], strerror(errno));
1390 fid->info.hdr.info_type = dirname
1391 ? FAN_EVENT_INFO_TYPE_DFID
1392 : FAN_EVENT_INFO_TYPE_FID;
1394 sizeof(*fid) + fid->handle.handle_bytes;
1396 dirf = open(dirname, O_PATH);
1400 "Failed to open %s: %s\n",
1401 dirname, strerror(errno));
1408 create_watch(wd, fid, filename, dirf);
1499 niceassert(initialized,
"inotifytools_initialize not called yet");
1500 niceassert(num_events <= MAX_EVENTS,
"too many events requested");
1506 static struct inotify_event event[2 * MAX_EVENTS];
1507 static struct inotify_event* ret;
1508 static int first_byte = 0;
1509 static ssize_t bytes;
1510 static ssize_t this_bytes;
1512 static struct nstring match_name;
1513 static char match_name_string[MAX_STRLEN + 1];
1517 pid_t event_pid = 0;
1521 if (first_byte != 0 &&
1522 first_byte <= (
int)(bytes -
sizeof(
struct inotify_event))) {
1523 ret = (
struct inotify_event*)((
char*)&event[0] + first_byte);
1524 if (!fanotify_mode &&
1525 first_byte +
sizeof(*ret) + ret->len > bytes) {
1532 niceassert((
long)((
char*)&event[0] +
1533 sizeof(
struct inotify_event) +
1534 event[0].len) <= (
long)ret,
1535 "extremely unlucky user, death imminent");
1537 bytes = (
char*)&event[0] + bytes - (
char*)ret;
1538 memcpy(&event[0], ret, bytes);
1546 else if (first_byte == 0) {
1550 static unsigned int bytes_to_read;
1552 static fd_set read_fds;
1554 static struct timeval read_timeout;
1555 read_timeout.tv_sec = timeout;
1556 read_timeout.tv_usec = 0;
1557 static struct timeval* read_timeout_ptr;
1558 read_timeout_ptr = (timeout < 0 ? NULL : &read_timeout);
1561 FD_SET(inotify_fd, &read_fds);
1562 rc = select(inotify_fd + 1, &read_fds, NULL, NULL, read_timeout_ptr);
1567 }
else if (rc == 0) {
1574 rc = ioctl(inotify_fd, FIONREAD, &bytes_to_read);
1576 bytes_to_read <
sizeof(
struct inotify_event) * num_events);
1583 this_bytes = read(inotify_fd, (
char*)&event[0] + bytes,
1584 sizeof(
struct inotify_event) * MAX_EVENTS - bytes);
1585 if (this_bytes < 0) {
1589 if (this_bytes == 0) {
1591 "Inotify reported end-of-file. Possibly too many "
1592 "events occurred at once.\n");
1596 ret = (
struct inotify_event*)((
char*)&event[0] + first_byte);
1597#ifdef LINUX_FANOTIFY
1599 if (fanotify_mode) {
1600 struct fanotify_event_metadata* meta =
1601 (fanotify_event_metadata*)ret;
1602 struct fanotify_event_info_fid* info =
1603 (fanotify_event_info_fid*)(meta + 1);
1604 struct fanotify_event_fid* fid = NULL;
1605 const char* name =
"";
1609 first_byte += meta->event_len;
1611 if (meta->event_len >
sizeof(*meta)) {
1612 switch (info->hdr.info_type) {
1613 case FAN_EVENT_INFO_TYPE_FID:
1614 case FAN_EVENT_INFO_TYPE_DFID:
1615 case FAN_EVENT_INFO_TYPE_DFID_NAME:
1616 fid = (fanotify_event_fid*)info;
1617 fid_len =
sizeof(*fid) +
1618 fid->handle.handle_bytes;
1619 if (info->hdr.info_type ==
1620 FAN_EVENT_INFO_TYPE_DFID_NAME) {
1622 info->hdr.len - fid_len;
1627 fid->handle.f_handle +
1628 fid->handle.handle_bytes;
1638 (name[0] ==
'.' && !name[1]))) {
1639 info->hdr.len -= name_len;
1646 fprintf(stderr,
"No fid in fanotify event.\n");
1649 if (verbosity > 1) {
1651 "fanotify_event: bytes=%zd, first_byte=%d, "
1652 "this_bytes=%zd, event_len=%u, fid_len=%d, "
1653 "name_len=%d, name=%s\n",
1654 bytes, first_byte, this_bytes, meta->event_len,
1655 fid_len, name_len, name);
1658 ret = &
event[MAX_EVENTS];
1659 watch* w = watch_from_fid(fid);
1661 struct fanotify_event_fid* newfid =
1662 (fanotify_event_fid*)calloc(1, info->hdr.len);
1664 fprintf(stderr,
"Failed to allocate fid.\n");
1667 memcpy(newfid, fid, info->hdr.len);
1668 const char* filename =
1669 inotifytools_filename_from_fid(fid);
1671 w = create_watch(0, newfid, filename, 0);
1680 memcpy((
void*)&
id, fid->handle.f_handle,
1682 printf(
"[fid=%x.%x.%lx;name='%s'] %s\n",
1683 fid->info.fsid.val[0],
1684 fid->info.fsid.val[1],
id, name,
1688 ret->wd = w ? w->wd : 0;
1689 ret->mask = (uint32_t)meta->mask;
1690 ret->len = name_len;
1692 memcpy(ret->name, name, name_len);
1693 event_pid = meta->pid;
1695 first_byte +=
sizeof(
struct inotify_event) + ret->len;
1699 bytes += this_bytes;
1700 niceassert(first_byte <= bytes,
1701 "ridiculously long filename, things will "
1702 "almost certainly screw up.");
1703 if (first_byte == bytes) {
1708 if (self_pid && self_pid == event_pid) {
1714 if (recursive_watch && (ret->mask & IN_ISDIR) &&
1715 (ret->mask & (IN_CREATE | IN_MOVED_TO))) {
1719 memcpy(&match_name_string, &match_name.
buf, match_name.
len);
1720 match_name_string[match_name.
len] =
'\0';
1721 if (0 == regexec(regex, match_name_string, 0, 0, 0)) {
1731 if (collect_stats) {
1801 char const** exclude_list) {
1802 niceassert(initialized,
"inotifytools_initialize not called yet");
1807 dir = opendir(path);
1810 if (errno == ENOTDIR) {
1818 if (path[strlen(path) - 1] !=
'/') {
1819 nasprintf(&my_path,
"%s/", path);
1821 my_path = (
char*)path;
1824 static struct dirent* ent;
1826 static struct stat my_stat;
1830 if ((0 != strcmp(ent->d_name,
".")) &&
1831 (0 != strcmp(ent->d_name,
".."))) {
1832 nasprintf(&next_file,
"%s%s", my_path, ent->d_name);
1833 if (-1 == lstat(next_file, &my_stat)) {
1836 if (errno != EACCES) {
1838 if (my_path != path)
1843 }
else if (S_ISDIR(my_stat.st_mode) &&
1844 !S_ISLNK(my_stat.st_mode)) {
1846 nasprintf(&next_file,
"%s%s/", my_path,
1848 static unsigned int no_watch;
1849 static char const** exclude_entry;
1852 for (exclude_entry = exclude_list;
1853 exclude_entry && *exclude_entry &&
1856 static int exclude_length;
1858 exclude_length = strlen(*exclude_entry);
1859 if ((*exclude_entry)[exclude_length -
1863 if (strlen(next_file) ==
1864 (
unsigned)(exclude_length +
1866 !strncmp(*exclude_entry, next_file,
1880 if (!status && (EACCES != error) &&
1881 (ENOENT != error) &&
1884 if (my_path != path)
1903 if (my_path != path)
1925static int isdir(
char const* path) {
1926 static struct stat my_stat;
1928 if (-1 == lstat(path, &my_stat)) {
1929 if (errno == ENOENT)
1931 fprintf(stderr,
"Stat failed on %s: %s\n", path,
1936 return S_ISDIR(my_stat.st_mode) && !S_ISLNK(my_stat.st_mode);
1947 rbwalk(tree_filename, get_num, (
void*)&ret);
2045 struct inotify_event* event,
2051 fwrite(out.
buf,
sizeof(
char), out.
len, file);
2108 struct inotify_event* event,
2165 struct inotify_event* event,
2167 const char* eventstr;
2168 static unsigned int i, ind;
2170 static char timestr[MAX_STRLEN];
2173 size_t dirnamelen = 0;
2174 const char* eventname;
2175 const char* filename =
2178 if (!fmt || 0 == strlen(fmt)) {
2182 if (strlen(fmt) > MAX_STRLEN || size > MAX_STRLEN) {
2188 for (i = 0; i < strlen(fmt) && (int)ind < size - 1; ++i) {
2189 if (fmt[i] !=
'%') {
2190 out->
buf[ind++] = fmt[i];
2194 if (i == strlen(fmt) - 1) {
2203 out->
buf[ind++] =
'%';
2209 out->
buf[ind++] =
'\0';
2215 out->
buf[ind++] =
'\n';
2221 if (filename && dirnamelen <= size - ind) {
2222 strncpy(&out->
buf[ind], filename, dirnamelen);
2231 strncpy(&out->
buf[ind], eventname, size - ind);
2232 ind += strlen(eventname);
2239 ind += snprintf(&out->
buf[ind], size - ind,
"%x",
2247 strncpy(&out->
buf[ind], eventstr, size - ind);
2248 ind += strlen(eventstr);
2254 if (!timefmt.empty()) {
2257 if (!strftime(timestr, MAX_STRLEN - 1,
2259 localtime_r(&now, &now_tm))) {
2268 strncpy(&out->
buf[ind], timestr, size - ind);
2269 ind += strlen(timestr);
2275 if (i < strlen(fmt) - 2 && fmt[i + 2] ==
'e') {
2278 strncpy(&out->
buf[ind], eventstr, size - ind);
2279 ind += strlen(eventstr);
2286 if (ind < MAX_STRLEN)
2287 out->
buf[ind++] =
'%';
2288 if (ind < MAX_STRLEN)
2289 out->
buf[ind++] = ch1;
2307 timefmt.set_size(nasprintf(&timefmt.c_str_,
"%s", fmt));
2310void inotifytools_clear_timefmt() {
2324 if (!read_num_from_file(QUEUE_SIZE_PATH, &ret))
2340 if (!read_num_from_file(INSTANCES_PATH, &ret))
2356 if (!read_num_from_file(WATCHES_SIZE_PATH, &ret))
2374static int do_ignore_events_by_regex(
char const* pattern,
2390 regex = (regex_t*)malloc(
sizeof(regex_t));
2393 invert_regexp = invert;
2394 recursive_watch = recursive;
2396 int ret = regcomp(regex, pattern, flags | REG_NOSUB);
2419 return do_ignore_events_by_regex(pattern, flags, 0, recursive);
2434 return do_ignore_events_by_regex(pattern, flags, 1, recursive);
2437int event_compare(
const char* p1,
const char* p2,
const void* config) {
2441 long sort_event = (long)config;
2442 if (sort_event == -1) {
2445 }
else if (sort_event < 0) {
2446 sort_event = -sort_event;
2449 unsigned int* i1 = stat_ptr((watch*)p1, sort_event);
2450 unsigned int* i2 = stat_ptr((watch*)p2, sort_event);
2451 if (0 == *i1 - *i2) {
2452 return ((watch*)p1)->wd - ((watch*)p2)->wd;
2460struct rbtree* inotifytools_wd_sorted_by_event(
int sort_event) {
2461 struct rbtree* ret =
2462 rbinit(event_compare, (
void*)(uintptr_t)sort_event);
2463 RBLIST* all = rbopenlist(tree_wd);
2464 void const* p = rbreadlist(all);
2466 void const* r = rbsearch(p, ret);
2467 niceassert((
int)(r == p),
2468 "Couldn't insert watch into new tree");
2469 p = rbreadlist(all);
This structure holds string that can contain any character including NULL.