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;
165int collect_stats = 0;
167struct rbtree* tree_wd = 0;
168struct rbtree* tree_fid = 0;
169struct rbtree* tree_filename = 0;
173int fanotify_mode = 0;
174int fanotify_mark_type = 0;
175static pid_t self_pid = 0;
182 bool empty() {
return !size_; }
191 void set_size(
int size) {
193 if (size > capacity_)
197 ~str() { free(c_str_); }
201static regex_t* regex = 0;
203static int invert_regexp = 0;
205static int isdir(
char const* path);
206void record_stats(
struct inotify_event
const* event);
207int onestr_to_event(
char const* event);
209#define nasprintf(...) niceassert(-1 != asprintf(__VA_ARGS__), "out of memory")
228long _niceassert(
long cond,
237 fprintf(stderr,
"%s:%d assertion ( %s ) failed: %s\n", file,
238 line, condstr, mesg);
240 fprintf(stderr,
"%s:%d assertion ( %s ) failed.\n", file, line,
247static void charcat(
char* s,
const char c) {
248 size_t l = strlen(s);
256static int read_num_from_file(
const char* filename,
int* num) {
257 FILE* file = fopen(filename,
"r");
263 if (EOF == fscanf(file,
"%d", num)) {
265 const int fclose_ret = fclose(file);
266 niceassert(!fclose_ret, 0);
270 const int fclose_ret = fclose(file);
271 niceassert(!fclose_ret, 0);
276static int wd_compare(
const char* d1,
const char* d2,
const void* config) {
279 return ((watch*)d1)->wd - ((watch*)d2)->wd;
282static int fid_compare(
const char* d1,
const char* d2,
const void* config) {
286 watch* w1 = (watch*)d1;
287 watch* w2 = (watch*)d2;
289 n1 = w1->fid->info.hdr.len;
290 n2 = w2->fid->info.hdr.len;
293 return memcmp(w1->fid, w2->fid, n1);
299static int filename_compare(
const char* d1,
301 const void* config) {
304 return strcmp(((watch*)d1)->filename, ((watch*)d2)->filename);
310watch* watch_from_wd(
int wd) {
313 return (watch*)rbfind(&w, tree_wd);
319watch* watch_from_fid(
struct fanotify_event_fid* fid) {
322 return (watch*)rbfind(&w, tree_fid);
328watch* watch_from_filename(
char const* filename) {
330 w.filename = (
char*)filename;
331 return (watch*)rbfind(&w, tree_filename);
356 watch_filesystem ? FAN_MARK_FILESYSTEM : FAN_MARK_INODE;
358 fanotify_init(FAN_REPORT_FID | FAN_REPORT_DFID_NAME, 0);
362 inotify_fd = inotify_init();
364 if (inotify_fd < 0) {
371 tree_wd = rbinit(wd_compare, 0);
372 tree_fid = rbinit(fid_compare, 0);
373 tree_filename = rbinit(filename_compare, 0);
379int inotifytools_initialize() {
386void destroy_watch(watch* w) {
399void cleanup_tree(
const void* nodep,
403 if (which != endorder && which != leaf)
405 watch* w = (watch*)nodep;
431 rbwalk(tree_wd, cleanup_tree, 0);
434 rbdestroy(tree_filename);
443struct replace_filename_data {
444 char const* old_name;
445 char const* new_name;
452static void replace_filename_impl(
const void* nodep,
455 const struct replace_filename_data* data) {
456 if (which != endorder && which != leaf)
458 watch* w = (watch*)nodep;
460 if (0 == strncmp(data->old_name, w->filename, data->old_len)) {
461 nasprintf(&name,
"%s%s", data->new_name,
462 &(w->filename[data->old_len]));
463 if (!strcmp(w->filename, data->new_name)) {
466 rbdelete(w, tree_filename);
469 rbsearch(w, tree_filename);
477static void replace_filename(
const void* nodep,
481 replace_filename_impl(nodep, which, depth,
482 (
const struct replace_filename_data*)data);
488static void get_num(
const void* nodep,
492 if (which != endorder && which != leaf)
526 "abcdefghijklmnopqrstuvwxyz"
527 "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
533 char *event1, *event2;
534 static const size_t eventstr_size = 4096;
535 char eventstr[eventstr_size];
538 if (!event || !event[0])
541 event1 = (
char*)event;
542 event2 = strchr(event1, sep);
543 while (event1 && event1[0]) {
545 len = event2 - event1;
546 niceassert(len < eventstr_size,
547 "malformed event string (very long)");
549 len = strlen(event1);
551 if (len > eventstr_size - 1)
552 len = eventstr_size - 1;
554 strncpy(eventstr, event1, len);
558 int ret1 = onestr_to_event(eventstr);
559 if (0 == ret1 || -1 == ret1) {
566 if (event1 && event1[0]) {
572 event2 = strchr(event1, sep);
617int onestr_to_event(
char const* event) {
621 if (!event || !event[0])
623 else if (0 == strcasecmp(event,
"ACCESS"))
625 else if (0 == strcasecmp(event,
"MODIFY"))
627 else if (0 == strcasecmp(event,
"ATTRIB"))
629 else if (0 == strcasecmp(event,
"CLOSE_WRITE"))
630 ret = IN_CLOSE_WRITE;
631 else if (0 == strcasecmp(event,
"CLOSE_NOWRITE"))
632 ret = IN_CLOSE_NOWRITE;
633 else if (0 == strcasecmp(event,
"OPEN"))
635 else if (0 == strcasecmp(event,
"MOVED_FROM"))
637 else if (0 == strcasecmp(event,
"MOVED_TO"))
639 else if (0 == strcasecmp(event,
"CREATE"))
641 else if (0 == strcasecmp(event,
"DELETE"))
643 else if (0 == strcasecmp(event,
"DELETE_SELF"))
644 ret = IN_DELETE_SELF;
645 else if (0 == strcasecmp(event,
"UNMOUNT"))
647 else if (0 == strcasecmp(event,
"Q_OVERFLOW"))
649 else if (0 == strcasecmp(event,
"IGNORED"))
651 else if (0 == strcasecmp(event,
"CLOSE"))
653 else if (0 == strcasecmp(event,
"MOVE_SELF"))
655 else if (0 == strcasecmp(event,
"MOVE"))
657 else if (0 == strcasecmp(event,
"ISDIR"))
659 else if (0 == strcasecmp(event,
"ONESHOT"))
661 else if (0 == strcasecmp(event,
"ALL_EVENTS"))
717 static char ret[1024];
721 if (IN_ACCESS & events) {
723 strncat(ret,
"ACCESS", 7);
725 if (IN_MODIFY & events) {
727 strncat(ret,
"MODIFY", 7);
729 if (IN_ATTRIB & events) {
731 strncat(ret,
"ATTRIB", 7);
733 if (IN_CLOSE_WRITE & events) {
735 strncat(ret,
"CLOSE_WRITE", 12);
737 if (IN_CLOSE_NOWRITE & events) {
739 strncat(ret,
"CLOSE_NOWRITE", 14);
741 if (IN_OPEN & events) {
743 strncat(ret,
"OPEN", 5);
745 if (IN_MOVED_FROM & events) {
747 strncat(ret,
"MOVED_FROM", 11);
749 if (IN_MOVED_TO & events) {
751 strncat(ret,
"MOVED_TO", 9);
753 if (IN_CREATE & events) {
755 strncat(ret,
"CREATE", 7);
757 if (IN_DELETE & events) {
759 strncat(ret,
"DELETE", 7);
761 if (IN_DELETE_SELF & events) {
763 strncat(ret,
"DELETE_SELF", 12);
765 if (IN_UNMOUNT & events) {
767 strncat(ret,
"UNMOUNT", 8);
769 if (IN_Q_OVERFLOW & events) {
771 strncat(ret,
"Q_OVERFLOW", 11);
773 if (IN_IGNORED & events) {
775 strncat(ret,
"IGNORED", 8);
777 if (IN_CLOSE & events) {
779 strncat(ret,
"CLOSE", 6);
781 if (IN_MOVE_SELF & events) {
783 strncat(ret,
"MOVE_SELF", 10);
785 if (IN_ISDIR & events) {
787 strncat(ret,
"ISDIR", 6);
789 if (IN_ONESHOT & events) {
791 strncat(ret,
"ONESHOT", 8);
795 if (ret[0] ==
'\0') {
796 niceassert(-1 != sprintf(ret,
"%c0x%08x", sep, events), 0);
808static const char* inotifytools_filename_from_fid(
809 struct fanotify_event_fid* fid) {
811 static char filename[PATH_MAX];
812 struct fanotify_event_fid fsid = {};
813 int dirf = 0, mount_fd = AT_FDCWD;
814 int len = 0, name_len = 0;
817 fsid.info.fsid.val[0] = fid->info.fsid.val[0];
818 fsid.info.fsid.val[1] = fid->info.fsid.val[1];
819 fsid.info.hdr.info_type = FAN_EVENT_INFO_TYPE_FID;
820 fsid.info.hdr.len =
sizeof(fsid);
821 watch* mnt = watch_from_fid(&fsid);
823 mount_fd = mnt->dirf;
825 if (fid->info.hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME) {
826 int fid_len =
sizeof(*fid) + fid->handle.handle_bytes;
828 name_len = fid->info.hdr.len - fid_len;
829 if (name_len && !fid->handle.f_handle[fid->handle.handle_bytes])
834 dirf = open_by_handle_at(mount_fd, &fid->handle, 0);
837 }
else if (fanotify_mark_type == FAN_MARK_FILESYSTEM) {
838 fprintf(stderr,
"Failed to decode directory fid.\n");
840 }
else if (name_len) {
842 fid->info.hdr.info_type = FAN_EVENT_INFO_TYPE_DFID;
843 fid->info.hdr.len -= name_len;
845 watch* w = watch_from_fid(fid);
847 fid->info.hdr.info_type = FAN_EVENT_INFO_TYPE_DFID_NAME;
848 fid->info.hdr.len += name_len;
852 "Failed to lookup path by directory fid.\n");
856 dirf = w->dirf ? dup(w->dirf) : -1;
858 fprintf(stderr,
"Failed to get directory fd.\n");
866 sprintf(sym,
"/proc/self/fd/%d", dirf);
870 len = readlink(sym, filename, PATH_MAX - 2);
873 fprintf(stderr,
"Failed to resolve path from directory fd.\n");
877 filename[len++] =
'/';
881 const char* name = (
const char*)fid->handle.f_handle +
882 fid->handle.handle_bytes;
883 int deleted = faccessat(dirf, name, F_OK, AT_SYMLINK_NOFOLLOW);
884 if (deleted && errno != ENOENT) {
885 fprintf(stderr,
"Failed to access file %s (%s).\n",
886 name, strerror(errno));
890 memcpy(filename + len, name, name_len);
892 strncat(filename,
" (deleted)", 11);
910 if (!w->fid || !fanotify_mark_type)
913 return inotifytools_filename_from_fid(w->fid) ?: w->filename;
937 niceassert(initialized,
"inotifytools_initialize not called yet");
940 watch* w = watch_from_wd(wd);
956 size_t* dirnamelen) {
958 const char* dirsep = NULL;
966 dirsep = strrchr(filename,
'/');
968 *dirnamelen = strlen(filename);
972 *dirnamelen = dirsep - filename + 1;
985 char const** eventname,
986 size_t* dirnamelen) {
988 *eventname =
event->name;
992 const char* filename =
996 if (filename && filename[*dirnamelen])
997 *eventname = filename + *dirnamelen;
1013 if (!filename || !*filename || !(event->mask & IN_ISDIR)) {
1022 nasprintf(&path,
"%s%s/", filename, fanotify_mode ?
"" : event->name);
1042 niceassert(initialized,
"inotifytools_initialize not called yet");
1043 if (!filename || !*filename)
1045 watch* w = watch_from_filename(filename);
1066 niceassert(initialized,
"inotifytools_initialize not called yet");
1067 watch* w = watch_from_wd(wd);
1072 w->filename = strdup(filename);
1090 char const* newname) {
1091 watch* w = watch_from_filename(oldname);
1096 w->filename = strdup(newname);
1122 if (!oldname || !newname)
1124 if (!*oldname || !*newname)
1126 struct replace_filename_data data;
1127 data.old_name = oldname;
1128 data.new_name = newname;
1129 data.old_len = strlen(oldname);
1130 rbwalk(tree_filename, replace_filename, (
void*)&data);
1136int remove_inotify_watch(watch* w) {
1141 int status = inotify_rm_watch(inotify_fd, w->wd);
1143 fprintf(stderr,
"Failed to remove watch on %s: %s\n",
1144 w->filename, strerror(status));
1154watch* create_watch(
int wd,
1155 struct fanotify_event_fid* fid,
1156 const char* filename,
1158 if (wd < 0 || !filename)
1161 watch* w = (watch*)calloc(1,
sizeof(watch));
1163 fprintf(stderr,
"Failed to allocate watch.\n");
1166 w->wd = wd ?: (
unsigned long)fid;
1169 w->filename = strdup(filename);
1170 rbsearch(w, tree_wd);
1172 rbsearch(w, tree_fid);
1174 rbsearch(w, tree_filename);
1191 niceassert(initialized,
"inotifytools_initialize not called yet");
1192 watch* w = watch_from_wd(wd);
1196 if (!remove_inotify_watch(w))
1198 rbdelete(w, tree_wd);
1200 rbdelete(w, tree_fid);
1201 rbdelete(w, tree_filename);
1218 niceassert(initialized,
"inotifytools_initialize not called yet");
1219 watch* w = watch_from_filename(filename);
1223 if (!remove_inotify_watch(w))
1225 rbdelete(w, tree_wd);
1227 rbdelete(w, tree_fid);
1228 rbdelete(w, tree_filename);
1245 static char const* filenames[2];
1246 filenames[0] = filename;
1247 filenames[1] = NULL;
1267 niceassert(initialized,
"inotifytools_initialize not called yet");
1271 for (i = 0; filenames[i]; ++i) {
1273 if (fanotify_mode) {
1274#ifdef LINUX_FANOTIFY
1275 unsigned int flags = FAN_MARK_ADD | fanotify_mark_type;
1277 if (events & IN_DONT_FOLLOW) {
1278 events &= ~IN_DONT_FOLLOW;
1279 flags |= FAN_MARK_DONT_FOLLOW;
1282 wd = fanotify_mark(inotify_fd, flags,
1283 events | FAN_EVENT_ON_CHILD,
1284 AT_FDCWD, filenames[i]);
1288 inotify_add_watch(inotify_fd, filenames[i], events);
1298 "Failed to watch %s: returned wd was %d "
1299 "(expected -1 or >0 )",
1306 const char* filename = filenames[i];
1307 size_t filenamelen = strlen(filename);
1311 if (!isdir(filename)) {
1313 }
else if (filename[filenamelen - 1] ==
'/') {
1314 dirname = strdup(filename);
1316 nasprintf(&dirname,
"%s/", filename);
1321 struct fanotify_event_fid* fid = NULL;
1322#ifdef LINUX_FANOTIFY
1324 fid = (fanotify_event_fid*)calloc(
1325 1,
sizeof(*fid) + MAX_FID_LEN);
1327 fprintf(stderr,
"Failed to allocate fid");
1333 if (statfs(filenames[i], &buf)) {
1335 fprintf(stderr,
"Statfs failed on %s: %s\n",
1336 filenames[i], strerror(errno));
1340 memcpy(&fid->info.fsid, &buf.f_fsid,
1341 sizeof(__kernel_fsid_t));
1345 watch* mnt = dirname ? watch_from_fid(fid) : NULL;
1346 if (dirname && !mnt) {
1347 struct fanotify_event_fid* fsid;
1349 fsid = (fanotify_event_fid*)calloc(
1354 "Failed to allocate fsid");
1358 fsid->info.fsid.val[0] = fid->info.fsid.val[0];
1359 fsid->info.fsid.val[1] = fid->info.fsid.val[1];
1360 fsid->info.hdr.info_type =
1361 FAN_EVENT_INFO_TYPE_FID;
1362 fsid->info.hdr.len =
sizeof(*fsid);
1363 mntid = open(dirname, O_RDONLY);
1368 "Failed to open %s: %s\n",
1369 dirname, strerror(errno));
1374 dirname[filenamelen - 1] = 0;
1375 create_watch(0, fsid, dirname, mntid);
1376 dirname[filenamelen - 1] =
'/';
1379 fid->handle.handle_bytes = MAX_FID_LEN;
1380 ret = name_to_handle_at(AT_FDCWD, filenames[i],
1381 &fid->handle, &mntid, 0);
1382 if (ret || fid->handle.handle_bytes > MAX_FID_LEN) {
1384 fprintf(stderr,
"Encode fid failed on %s: %s\n",
1385 filenames[i], strerror(errno));
1389 fid->info.hdr.info_type = dirname
1390 ? FAN_EVENT_INFO_TYPE_DFID
1391 : FAN_EVENT_INFO_TYPE_FID;
1393 sizeof(*fid) + fid->handle.handle_bytes;
1395 dirf = open(dirname, O_PATH);
1399 "Failed to open %s: %s\n",
1400 dirname, strerror(errno));
1407 create_watch(wd, fid, filename, dirf);
1498 niceassert(initialized,
"inotifytools_initialize not called yet");
1499 niceassert(num_events <= MAX_EVENTS,
"too many events requested");
1505 static struct inotify_event event[2 * MAX_EVENTS];
1506 static struct inotify_event* ret;
1507 static int first_byte = 0;
1508 static ssize_t bytes;
1509 static ssize_t this_bytes;
1511 static struct nstring match_name;
1512 static char match_name_string[MAX_STRLEN + 1];
1516 pid_t event_pid = 0;
1520 if (first_byte != 0 &&
1521 first_byte <= (
int)(bytes -
sizeof(
struct inotify_event))) {
1522 ret = (
struct inotify_event*)((
char*)&
event[0] + first_byte);
1523 if (!fanotify_mode &&
1524 first_byte +
sizeof(*ret) + ret->len > bytes) {
1531 niceassert((
long)((
char*)&event[0] +
1532 sizeof(
struct inotify_event) +
1533 event[0].len) <= (
long)ret,
1534 "extremely unlucky user, death imminent");
1536 bytes = (
char*)&event[0] + bytes - (
char*)ret;
1537 memcpy(&event[0], ret, bytes);
1545 else if (first_byte == 0) {
1549 static unsigned int bytes_to_read;
1551 static fd_set read_fds;
1553 static struct timeval read_timeout;
1554 read_timeout.tv_sec = timeout;
1555 read_timeout.tv_usec = 0;
1556 static struct timeval* read_timeout_ptr;
1557 read_timeout_ptr = (timeout < 0 ? NULL : &read_timeout);
1560 FD_SET(inotify_fd, &read_fds);
1561 rc = select(inotify_fd + 1, &read_fds, NULL, NULL, read_timeout_ptr);
1566 }
else if (rc == 0) {
1573 rc = ioctl(inotify_fd, FIONREAD, &bytes_to_read);
1575 bytes_to_read <
sizeof(
struct inotify_event) * num_events);
1582 this_bytes = read(inotify_fd, (
char*)&event[0] + bytes,
1583 sizeof(
struct inotify_event) * MAX_EVENTS - bytes);
1584 if (this_bytes < 0) {
1588 if (this_bytes == 0) {
1590 "Inotify reported end-of-file. Possibly too many "
1591 "events occurred at once.\n");
1595 ret = (
struct inotify_event*)((
char*)&
event[0] + first_byte);
1596#ifdef LINUX_FANOTIFY
1598 if (fanotify_mode) {
1599 struct fanotify_event_metadata* meta =
1600 (fanotify_event_metadata*)ret;
1601 struct fanotify_event_info_fid* info =
1602 (fanotify_event_info_fid*)(meta + 1);
1603 struct fanotify_event_fid* fid = NULL;
1604 const char* name =
"";
1608 first_byte += meta->event_len;
1610 if (meta->event_len >
sizeof(*meta)) {
1611 switch (info->hdr.info_type) {
1612 case FAN_EVENT_INFO_TYPE_FID:
1613 case FAN_EVENT_INFO_TYPE_DFID:
1614 case FAN_EVENT_INFO_TYPE_DFID_NAME:
1615 fid = (fanotify_event_fid*)info;
1616 fid_len =
sizeof(*fid) +
1617 fid->handle.handle_bytes;
1618 if (info->hdr.info_type ==
1619 FAN_EVENT_INFO_TYPE_DFID_NAME) {
1621 info->hdr.len - fid_len;
1626 fid->handle.f_handle +
1627 fid->handle.handle_bytes;
1637 (name[0] ==
'.' && !name[1]))) {
1638 info->hdr.len -= name_len;
1645 fprintf(stderr,
"No fid in fanotify event.\n");
1648 if (verbosity > 1) {
1650 "fanotify_event: bytes=%zd, first_byte=%d, "
1651 "this_bytes=%zd, event_len=%u, fid_len=%d, "
1652 "name_len=%d, name=%s\n",
1653 bytes, first_byte, this_bytes, meta->event_len,
1654 fid_len, name_len, name);
1657 ret = &
event[MAX_EVENTS];
1658 watch* w = watch_from_fid(fid);
1660 struct fanotify_event_fid* newfid =
1661 (fanotify_event_fid*)calloc(1, info->hdr.len);
1663 fprintf(stderr,
"Failed to allocate fid.\n");
1666 memcpy(newfid, fid, info->hdr.len);
1667 const char* filename =
1668 inotifytools_filename_from_fid(fid);
1670 w = create_watch(0, newfid, filename, 0);
1679 memcpy((
void*)&
id, fid->handle.f_handle,
1681 printf(
"[fid=%x.%x.%lx;name='%s'] %s\n",
1682 fid->info.fsid.val[0],
1683 fid->info.fsid.val[1],
id, name,
1687 ret->wd = w ? w->wd : 0;
1688 ret->mask = (uint32_t)meta->mask;
1689 ret->len = name_len;
1691 memcpy(ret->name, name, name_len);
1692 event_pid = meta->pid;
1694 first_byte +=
sizeof(
struct inotify_event) + ret->len;
1698 bytes += this_bytes;
1699 niceassert(first_byte <= bytes,
1700 "ridiculously long filename, things will "
1701 "almost certainly screw up.");
1702 if (first_byte == bytes) {
1707 if (self_pid && self_pid == event_pid) {
1713 memcpy(&match_name_string, &match_name.
buf, match_name.
len);
1714 match_name_string[match_name.
len] =
'\0';
1715 if (0 == regexec(regex, match_name_string, 0, 0, 0)) {
1724 if (collect_stats) {
1794 char const** exclude_list) {
1795 niceassert(initialized,
"inotifytools_initialize not called yet");
1800 dir = opendir(path);
1803 if (errno == ENOTDIR) {
1811 if (path[strlen(path) - 1] !=
'/') {
1812 nasprintf(&my_path,
"%s/", path);
1814 my_path = (
char*)path;
1817 static struct dirent* ent;
1819 static struct stat my_stat;
1823 if ((0 != strcmp(ent->d_name,
".")) &&
1824 (0 != strcmp(ent->d_name,
".."))) {
1825 nasprintf(&next_file,
"%s%s", my_path, ent->d_name);
1826 if (-1 == lstat(next_file, &my_stat)) {
1829 if (errno != EACCES) {
1831 if (my_path != path)
1836 }
else if (S_ISDIR(my_stat.st_mode) &&
1837 !S_ISLNK(my_stat.st_mode)) {
1839 nasprintf(&next_file,
"%s%s/", my_path,
1841 static unsigned int no_watch;
1842 static char const** exclude_entry;
1845 for (exclude_entry = exclude_list;
1846 exclude_entry && *exclude_entry &&
1849 static int exclude_length;
1851 exclude_length = strlen(*exclude_entry);
1852 if ((*exclude_entry)[exclude_length -
1856 if (strlen(next_file) ==
1857 (
unsigned)(exclude_length +
1859 !strncmp(*exclude_entry, next_file,
1873 if (!status && (EACCES != error) &&
1874 (ENOENT != error) &&
1877 if (my_path != path)
1896 if (my_path != path)
1918static int isdir(
char const* path) {
1919 static struct stat my_stat;
1921 if (-1 == lstat(path, &my_stat)) {
1922 if (errno == ENOENT)
1924 fprintf(stderr,
"Stat failed on %s: %s\n", path,
1929 return S_ISDIR(my_stat.st_mode) && !S_ISLNK(my_stat.st_mode);
1940 rbwalk(tree_filename, get_num, (
void*)&ret);
2038 struct inotify_event* event,
2044 fwrite(out.
buf,
sizeof(
char), out.
len, file);
2101 struct inotify_event* event,
2158 struct inotify_event* event,
2160 const char* eventstr;
2161 static unsigned int i, ind;
2163 static char timestr[MAX_STRLEN];
2166 size_t dirnamelen = 0;
2167 const char* eventname;
2168 const char* filename =
2171 if (!fmt || 0 == strlen(fmt)) {
2175 if (strlen(fmt) > MAX_STRLEN || size > MAX_STRLEN) {
2181 for (i = 0; i < strlen(fmt) && (int)ind < size - 1; ++i) {
2182 if (fmt[i] !=
'%') {
2183 out->
buf[ind++] = fmt[i];
2187 if (i == strlen(fmt) - 1) {
2196 out->
buf[ind++] =
'%';
2202 out->
buf[ind++] =
'\0';
2208 out->
buf[ind++] =
'\n';
2214 if (filename && dirnamelen <= size - ind) {
2215 strncpy(&out->
buf[ind], filename, dirnamelen);
2224 strncpy(&out->
buf[ind], eventname, size - ind);
2225 ind += strlen(eventname);
2232 ind += snprintf(&out->
buf[ind], size - ind,
"%x",
2240 strncpy(&out->
buf[ind], eventstr, size - ind);
2241 ind += strlen(eventstr);
2247 if (!timefmt.empty()) {
2250 if (!strftime(timestr, MAX_STRLEN - 1,
2252 localtime_r(&now, &now_tm))) {
2261 strncpy(&out->
buf[ind], timestr, size - ind);
2262 ind += strlen(timestr);
2268 if (i < strlen(fmt) - 2 && fmt[i + 2] ==
'e') {
2271 strncpy(&out->
buf[ind], eventstr, size - ind);
2272 ind += strlen(eventstr);
2279 if (ind < MAX_STRLEN)
2280 out->
buf[ind++] =
'%';
2281 if (ind < MAX_STRLEN)
2282 out->
buf[ind++] = ch1;
2300 timefmt.set_size(nasprintf(&timefmt.c_str_,
"%s", fmt));
2303void inotifytools_clear_timefmt() {
2317 if (!read_num_from_file(QUEUE_SIZE_PATH, &ret))
2333 if (!read_num_from_file(INSTANCES_PATH, &ret))
2349 if (!read_num_from_file(WATCHES_SIZE_PATH, &ret))
2367static int do_ignore_events_by_regex(
char const* pattern,
2382 regex = (regex_t*)malloc(
sizeof(regex_t));
2385 invert_regexp = invert;
2386 int ret = regcomp(regex, pattern, flags | REG_NOSUB);
2409 return do_ignore_events_by_regex(pattern, flags, 0);
2425 return do_ignore_events_by_regex(pattern, flags, 1);
2428int event_compare(
const char* p1,
const char* p2,
const void* config) {
2432 long sort_event = (long)config;
2433 if (sort_event == -1) {
2436 }
else if (sort_event < 0) {
2437 sort_event = -sort_event;
2440 unsigned int* i1 = stat_ptr((watch*)p1, sort_event);
2441 unsigned int* i2 = stat_ptr((watch*)p2, sort_event);
2442 if (0 == *i1 - *i2) {
2443 return ((watch*)p1)->wd - ((watch*)p2)->wd;
2451struct rbtree* inotifytools_wd_sorted_by_event(
int sort_event) {
2452 struct rbtree* ret =
2453 rbinit(event_compare, (
void*)(uintptr_t)sort_event);
2454 RBLIST* all = rbopenlist(tree_wd);
2455 void const* p = rbreadlist(all);
2457 void const* r = rbsearch(p, ret);
2458 niceassert((
int)(r == p),
2459 "Couldn't insert watch into new tree");
2460 p = rbreadlist(all);
This structure holds string that can contain any character including NULL.