| /******************************************************************************* | |
| Copyright (c) 2011, 2012 Dmitry Matveev <me@dmitrymatveev.co.uk> | |
| Permission is hereby granted, free of charge, to any person obtaining a copy | |
| of this software and associated documentation files (the "Software"), to deal | |
| in the Software without restriction, including without limitation the rights | |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| copies of the Software, and to permit persons to whom the Software is | |
| furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in | |
| all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| THE SOFTWARE. | |
| *******************************************************************************/ | |
| #include "config.h" | |
| #include <sys/types.h> | |
| #include <sys/event.h> | |
| #include <sys/time.h> | |
| #include <sys/socket.h> | |
| #include <sys/stat.h> | |
| #include <gio/glocalfile.h> | |
| #include <gio/glocalfilemonitor.h> | |
| #include <gio/gfile.h> | |
| #include <fcntl.h> | |
| #include <unistd.h> | |
| #include <string.h> | |
| #include <errno.h> | |
| #include <pthread.h> | |
| #include "kqueue-helper.h" | |
| typedef struct { | |
| kqueue_sub *sub; | |
| GFileMonitorSource *source; | |
| gboolean handle_deleted; | |
| } handle_ctx; | |
| /** | |
| * handle_created: | |
| * @udata: a pointer to user data (#handle_context). | |
| * @path: file name of a new file. | |
| * @inode: inode number of a new file. | |
| * | |
| * A callback function for the directory diff calculation routine, | |
| * produces G_FILE_MONITOR_EVENT_CREATED event for a created file. | |
| **/ | |
| static void | |
| handle_created (void *udata, const char *path, ino_t inode) | |
| { | |
| handle_ctx *ctx = NULL; | |
| gint64 now; | |
| gchar *fullname; | |
| struct stat st; | |
| (void) inode; | |
| ctx = (handle_ctx *) udata; | |
| g_assert (udata != NULL); | |
| g_assert (ctx->sub != NULL); | |
| g_assert (ctx->source != NULL); | |
| now = g_get_monotonic_time (); | |
| g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_CREATED, path, | |
| NULL, NULL, now); | |
| /* Copied from ih_event_callback to report 'CHANGES_DONE_HINT' earlier. */ | |
| fullname = g_build_filename (ctx->sub->filename, path, NULL); | |
| if (stat (fullname, &st) != 0 || !S_ISREG (st.st_mode) || st.st_nlink != 1) | |
| g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, path, | |
| NULL, NULL, now); | |
| g_free (fullname); | |
| } | |
| /** | |
| * handle_deleted: | |
| * @udata: a pointer to user data (#handle_context). | |
| * @path: file name of the removed file. | |
| * @inode: inode number of the removed file. | |
| * | |
| * A callback function for the directory diff calculation routine, | |
| * produces G_FILE_MONITOR_EVENT_DELETED event for a deleted file. | |
| **/ | |
| static void | |
| handle_deleted (void *udata, const char *path, ino_t inode) | |
| { | |
| handle_ctx *ctx = NULL; | |
| (void) inode; | |
| ctx = (handle_ctx *) udata; | |
| g_assert (udata != NULL); | |
| g_assert (ctx->sub != NULL); | |
| g_assert (ctx->source != NULL); | |
| if (!ctx->handle_deleted) | |
| return; | |
| g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_DELETED, path, | |
| NULL, NULL, g_get_monotonic_time ()); | |
| } | |
| /** | |
| * handle_moved: | |
| * @udata: a pointer to user data (#handle_context). | |
| * @from_path: file name of the source file. | |
| * @from_inode: inode number of the source file. | |
| * @to_path: file name of the replaced file. | |
| * @to_inode: inode number of the replaced file. | |
| * | |
| * A callback function for the directory diff calculation routine, | |
| * produces G_FILE_MONITOR_EVENT_RENAMED event on a move. | |
| **/ | |
| static void | |
| handle_moved (void *udata, | |
| const char *from_path, | |
| ino_t from_inode, | |
| const char *to_path, | |
| ino_t to_inode) | |
| { | |
| handle_ctx *ctx = NULL; | |
| (void) from_inode; | |
| (void) to_inode; | |
| ctx = (handle_ctx *) udata; | |
| g_assert (udata != NULL); | |
| g_assert (ctx->sub != NULL); | |
| g_assert (ctx->source != NULL); | |
| g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_RENAMED, | |
| from_path, to_path, NULL, g_get_monotonic_time ()); | |
| } | |
| /** | |
| * handle_overwritten: | |
| * @data: a pointer to user data (#handle_context). | |
| * @path: file name of the overwritten file. | |
| * @node: inode number of the overwritten file. | |
| * | |
| * A callback function for the directory diff calculation routine, | |
| * produces G_FILE_MONITOR_EVENT_DELETED/CREATED event pair when | |
| * an overwrite occurs in the directory (see dep-list for details). | |
| **/ | |
| static void | |
| handle_overwritten (void *udata, const char *path, ino_t inode) | |
| { | |
| handle_ctx *ctx = NULL; | |
| (void) inode; | |
| ctx = (handle_ctx *) udata; | |
| g_assert (udata != NULL); | |
| g_assert (ctx->sub != NULL); | |
| g_assert (ctx->source != NULL); | |
| g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_DELETED, | |
| path, NULL, NULL, g_get_monotonic_time ()); | |
| g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_CREATED, | |
| path, NULL, NULL, g_get_monotonic_time ()); | |
| } | |
| static const traverse_cbs cbs = { | |
| handle_created, | |
| handle_deleted, | |
| handle_moved, | |
| handle_overwritten, | |
| handle_moved, | |
| NULL, /* many added */ | |
| NULL, /* many removed */ | |
| NULL, /* names updated */ | |
| }; | |
| void | |
| _kh_dir_diff (kqueue_sub *sub, gboolean handle_deleted) | |
| { | |
| dep_list *was; | |
| handle_ctx ctx; | |
| memset (&ctx, 0, sizeof (handle_ctx)); | |
| ctx.sub = sub; | |
| ctx.source = sub->source; | |
| ctx.handle_deleted = handle_deleted; | |
| was = sub->deps; | |
| sub->deps = dl_listing (sub->filename); | |
| dl_calculate (was, sub->deps, &cbs, &ctx); | |
| dl_free (was); | |
| } |