Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux dirs creation/deletion reporting which fixes #4 and #10 #11

Merged
merged 1 commit into from
Jul 19, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
91 changes: 53 additions & 38 deletions dmon.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@
// watches directories for file or directory changes.
//
// clang-format off
// Usage:
// Usage:
// define DMON_IMPL and include this file to use it:
// #define DMON_IMPL
// #include "dmon.h"
//
// dmon_init():
// Call this once at the start of your program.
// dmon_init():
// Call this once at the start of your program.
// This will start a low-priority monitoring thread
// dmon_deinit():
// dmon_deinit():
// Call this when your work with dmon is finished, usually on program terminate
// This will free resources and stop the monitoring thread
// dmon_watch:
// Watch for directories
// You can watch multiple directories by calling this function multiple times
// rootdir: root directory to monitor
// watch_cb: callback function to receive events.
// NOTE that this function is called from another thread, so you should
// watch_cb: callback function to receive events.
// NOTE that this function is called from another thread, so you should
// beware of data races in your application when accessing data within this
// callback
// flags: watch flags, see dmon_watch_flags_t
Expand All @@ -35,12 +35,12 @@
//
// Configuration:
// You can customize some low-level functionality like malloc and logging by overriding macros:
//
// DMON_MALLOC, DMON_FREE, DMON_REALLOC:
//
// DMON_MALLOC, DMON_FREE, DMON_REALLOC:
// define these macros to override memory allocations
// default is 'malloc', 'free' and 'realloc'
// DMON_ASSERT:
// define this to provide your own assert
// DMON_ASSERT:
// define this to provide your own assert
// default is 'assert'
// DMON_LOG_ERROR:
// define this to provide your own logging mechanism
Expand All @@ -60,9 +60,9 @@
//
// TODO:
// - DMON_WATCHFLAGS_FOLLOW_SYMLINKS does not resolve files
// - implement DMON_WATCHFLAGS_OUTOFSCOPE_LINKS
// - implement DMON_WATCHFLAGS_OUTOFSCOPE_LINKS
// - implement DMON_WATCHFLAGS_IGNORE_DIRECTORIES
//
//
// History:
// 1.0.0 First version. working Win32/Linux backends
// 1.1.0 MacOS backend
Expand All @@ -86,9 +86,9 @@

typedef struct { uint32_t id; } dmon_watch_id;

// Pass these flags to `dmon_watch`
// Pass these flags to `dmon_watch`
typedef enum dmon_watch_flags_t {
DMON_WATCHFLAGS_RECURSIVE = 0x1, // monitor all child directories
DMON_WATCHFLAGS_RECURSIVE = 0x1, // monitor all child directories
DMON_WATCHFLAGS_FOLLOW_SYMLINKS = 0x2, // resolve symlinks (linux only)
DMON_WATCHFLAGS_OUTOFSCOPE_LINKS = 0x4, // TODO: not implemented yet
DMON_WATCHFLAGS_IGNORE_DIRECTORIES = 0x8 // TODO: not implemented yet
Expand Down Expand Up @@ -197,7 +197,7 @@ DMON_API_DECL void dmon_unwatch(dmon_watch_id id);
# include <stdio.h>
# define DMON_LOG_DEBUG(s) do { puts(s); } while(0)
# else
# define DMON_LOG_DEBUG(s)
# define DMON_LOG_DEBUG(s)
# endif
#endif

Expand Down Expand Up @@ -230,7 +230,7 @@ DMON_API_DECL void dmon_unwatch(dmon_watch_id id);
#endif

#ifndef dmon__min
# define dmon__min(a, b) ((a) < (b) ? (a) : (b))
# define dmon__min(a, b) ((a) < (b) ? (a) : (b))
#endif

#ifndef dmon__max
Expand Down Expand Up @@ -364,7 +364,7 @@ typedef void (dmon__watch_cb)(dmon_watch_id, dmon_action, const char*, const cha
typedef struct dmon__win32_event {
char filepath[DMON_MAX_PATH];
DWORD action;
dmon_watch_id watch_id;
dmon_watch_id watch_id;
bool skip;
} dmon__win32_event;

Expand Down Expand Up @@ -789,42 +789,42 @@ _DMON_PRIVATE void dmon__inotify_process_events(void)
}

// remove redundant modify events on a single file
if (ev->mask == IN_MODIFY) {
if (ev->mask & IN_MODIFY) {
for (int j = i + 1; j < c; j++) {
dmon__inotify_event* check_ev = &_dmon.events[j];
if (check_ev->mask == IN_MODIFY && strcmp(ev->filepath, check_ev->filepath) == 0) {
if (check_ev->mask & IN_MODIFY && strcmp(ev->filepath, check_ev->filepath) == 0) {
ev->skip = true;
break;
}
}
} else if (ev->mask == IN_CREATE) {
} else if (ev->mask & IN_CREATE) {
bool loop_break = false;
for (int j = i + 1; j < c && !loop_break; j++) {
dmon__inotify_event* check_ev = &_dmon.events[j];
if (check_ev->mask == IN_MOVED_FROM && strcmp(ev->filepath, check_ev->filepath) == 0) {
if (check_ev->mask & IN_MOVED_FROM && strcmp(ev->filepath, check_ev->filepath) == 0) {
// there is a case where some programs (like gedit):
// when we save, it creates a temp file, and moves it to the file being modified
// search for these cases and remove all of them
for (int k = j + 1; k < c; k++) {
dmon__inotify_event* third_ev = &_dmon.events[k];
if (third_ev->mask == IN_MOVED_TO && check_ev->cookie == third_ev->cookie) {
if (third_ev->mask & IN_MOVED_TO && check_ev->cookie == third_ev->cookie) {
third_ev->mask = IN_MODIFY; // change to modified
ev->skip = check_ev->skip = true;
loop_break = true;
break;
}
}
} else if (check_ev->mask == IN_MODIFY && strcmp(ev->filepath, check_ev->filepath) == 0) {
} else if (check_ev->mask & IN_MODIFY && strcmp(ev->filepath, check_ev->filepath) == 0) {
// Another case is that file is copied. CREATE and MODIFY happens sequentially
// so we ignore MODIFY event
check_ev->skip = true;
}
}
} else if (ev->mask == IN_MOVED_FROM) {
} else if (ev->mask & IN_MOVED_FROM) {
bool move_valid = false;
for (int j = i + 1; j < c; j++) {
dmon__inotify_event* check_ev = &_dmon.events[j];
if (check_ev->mask == IN_MOVED_TO && ev->cookie == check_ev->cookie) {
if (check_ev->mask & IN_MOVED_TO && ev->cookie == check_ev->cookie) {
move_valid = true;
break;
}
Expand All @@ -836,11 +836,11 @@ _DMON_PRIVATE void dmon__inotify_process_events(void)
if (!move_valid) {
ev->mask = IN_DELETE;
}
} else if (ev->mask == IN_MOVED_TO) {
} else if (ev->mask & IN_MOVED_TO) {
bool move_valid = false;
for (int j = 0; j < i; j++) {
dmon__inotify_event* check_ev = &_dmon.events[j];
if (check_ev->mask == IN_MOVED_FROM && ev->cookie == check_ev->cookie) {
if (check_ev->mask & IN_MOVED_FROM && ev->cookie == check_ev->cookie) {
move_valid = true;
break;
}
Expand All @@ -867,26 +867,41 @@ _DMON_PRIVATE void dmon__inotify_process_events(void)
continue;
}

switch (ev->mask) {
case IN_CREATE:
if (ev->mask & IN_CREATE) {
if (ev->mask & IN_ISDIR) {
if (watch->watch_flags & DMON_WATCHFLAGS_RECURSIVE) {
char watchdir[DMON_MAX_PATH];
dmon__strcpy(watchdir, sizeof(watchdir), ev->filepath);
dmon__strcat(watchdir, sizeof(watchdir), "/");
uint32_t mask = IN_MOVED_TO | IN_CREATE
| IN_MOVED_FROM | IN_DELETE | IN_MODIFY;
int wd = inotify_add_watch(watch->fd, watchdir, mask);
_DMON_UNUSED(wd);
DMON_ASSERT(wd != -1);

dmon__watch_subdir subdir;
dmon__strcpy(subdir.rootdir, sizeof(subdir.rootdir), watchdir);
stb_sb_push(watch->subdirs, subdir);
stb_sb_push(watch->wds, wd);
}
}
watch->watch_cb(ev->watch_id, DMON_ACTION_CREATE, watch->rootdir, ev->filepath, NULL, watch->user_data);
break;
case IN_MODIFY:
}
else if (ev->mask & IN_MODIFY) {
watch->watch_cb(ev->watch_id, DMON_ACTION_MODIFY, watch->rootdir, ev->filepath, NULL, watch->user_data);
break;
case IN_MOVED_FROM: {
}
else if (ev->mask & IN_MOVED_FROM) {
for (int j = i + 1; j < c; j++) {
dmon__inotify_event* check_ev = &_dmon.events[j];
if (check_ev->mask == IN_MOVED_TO && ev->cookie == check_ev->cookie) {
if (check_ev->mask & IN_MOVED_TO && ev->cookie == check_ev->cookie) {
watch->watch_cb(check_ev->watch_id, DMON_ACTION_MOVE, watch->rootdir,
check_ev->filepath, ev->filepath, watch->user_data);
break;
}
}
} break;
case IN_DELETE:
}
else if (ev->mask & IN_DELETE) {
watch->watch_cb(ev->watch_id, DMON_ACTION_DELETE, watch->rootdir, ev->filepath, NULL, watch->user_data);
break;
}
}

Expand Down Expand Up @@ -1396,7 +1411,7 @@ _DMON_PRIVATE void dmon__fsevent_callback(ConstFSEventStreamRef stream_ref, void
dmon__strcpy(abs_filepath, sizeof(abs_filepath), filepath);

// normalize path (TODO: have to recheck this to be consistent with other platforms)
dmon__tolower(abs_filepath, sizeof(abs_filepath),
dmon__tolower(abs_filepath, sizeof(abs_filepath),
dmon__unixpath(abs_filepath, sizeof(abs_filepath), abs_filepath));

// strip the root dir
Expand Down