(root)/
glib-2.79.0/
gio/
kqueue/
kqueue-helper.c
       1  /*******************************************************************************
       2    Copyright (c) 2011, 2012 Dmitry Matveev <me@dmitrymatveev.co.uk>
       3  
       4    Permission is hereby granted, free of charge, to any person obtaining a copy
       5    of this software and associated documentation files (the "Software"), to deal
       6    in the Software without restriction, including without limitation the rights
       7    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8    copies of the Software, and to permit persons to whom the Software is
       9    furnished to do so, subject to the following conditions:
      10  
      11    The above copyright notice and this permission notice shall be included in
      12    all copies or substantial portions of the Software.
      13  
      14    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20    THE SOFTWARE.
      21  *******************************************************************************/
      22  
      23  #include "config.h"
      24  #include <sys/types.h>
      25  #include <sys/event.h>
      26  #include <sys/time.h>
      27  #include <sys/socket.h>
      28  #include <sys/stat.h>
      29  #include <gio/glocalfile.h>
      30  #include <gio/glocalfilemonitor.h>
      31  #include <gio/gfile.h>
      32  #include <fcntl.h>
      33  #include <unistd.h>
      34  #include <string.h>
      35  #include <errno.h>
      36  #include <pthread.h>
      37  #include "kqueue-helper.h"
      38  
      39  typedef struct {
      40    kqueue_sub *sub;
      41    GFileMonitorSource *source;
      42    gboolean handle_deleted;
      43  } handle_ctx;
      44  
      45  /**
      46   * handle_created: 
      47   * @udata: a pointer to user data (#handle_context).
      48   * @path: file name of a new file.
      49   * @inode: inode number of a new file.
      50   *
      51   * A callback function for the directory diff calculation routine,
      52   * produces G_FILE_MONITOR_EVENT_CREATED event for a created file.
      53   **/
      54  static void
      55  handle_created (void *udata, const char *path, ino_t inode)
      56  {
      57    handle_ctx *ctx = NULL;
      58    gint64 now;
      59    gchar *fullname;
      60    struct stat st;
      61  
      62    (void) inode;
      63    ctx = (handle_ctx *) udata;
      64    g_assert (udata != NULL);
      65    g_assert (ctx->sub != NULL);
      66    g_assert (ctx->source != NULL);
      67  
      68    now = g_get_monotonic_time ();
      69    g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_CREATED, path,
      70                                        NULL, NULL, now);
      71  
      72    /* Copied from ih_event_callback to report 'CHANGES_DONE_HINT' earlier. */
      73    fullname = g_build_filename (ctx->sub->filename, path, NULL);
      74    if (stat (fullname, &st) != 0 || !S_ISREG (st.st_mode) || st.st_nlink != 1)
      75      g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, path,
      76                                          NULL, NULL, now);
      77    g_free (fullname);
      78  }
      79  
      80  /**
      81   * handle_deleted:
      82   * @udata: a pointer to user data (#handle_context).
      83   * @path: file name of the removed file.
      84   * @inode: inode number of the removed file.
      85   *
      86   * A callback function for the directory diff calculation routine,
      87   * produces G_FILE_MONITOR_EVENT_DELETED event for a deleted file.
      88   **/
      89  static void
      90  handle_deleted (void *udata, const char *path, ino_t inode)
      91  {
      92    handle_ctx *ctx = NULL;
      93  
      94    (void) inode;
      95    ctx = (handle_ctx *) udata;
      96    g_assert (udata != NULL);
      97    g_assert (ctx->sub != NULL);
      98    g_assert (ctx->source != NULL);
      99  
     100    if (!ctx->handle_deleted)
     101      return;
     102  
     103    g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_DELETED, path,
     104                                        NULL, NULL, g_get_monotonic_time ());
     105  }
     106  
     107  /**
     108   * handle_moved:
     109   * @udata: a pointer to user data (#handle_context).
     110   * @from_path: file name of the source file.
     111   * @from_inode: inode number of the source file.
     112   * @to_path: file name of the replaced file.
     113   * @to_inode: inode number of the replaced file.
     114   *
     115   * A callback function for the directory diff calculation routine,
     116   * produces G_FILE_MONITOR_EVENT_RENAMED event on a move.
     117   **/
     118  static void
     119  handle_moved (void       *udata,
     120                const char *from_path,
     121                ino_t       from_inode,
     122                const char *to_path,
     123                ino_t       to_inode)
     124  {
     125    handle_ctx *ctx = NULL;
     126  
     127    (void) from_inode;
     128    (void) to_inode;
     129  
     130    ctx = (handle_ctx *) udata;
     131    g_assert (udata != NULL);
     132    g_assert (ctx->sub != NULL);
     133    g_assert (ctx->source != NULL);
     134  
     135    g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_RENAMED,
     136                                        from_path, to_path, NULL, g_get_monotonic_time ());
     137  }
     138  
     139  /**
     140   * handle_overwritten:
     141   * @data: a pointer to user data (#handle_context).
     142   * @path: file name of the overwritten file.
     143   * @node: inode number of the overwritten file.
     144   *
     145   * A callback function for the directory diff calculation routine,
     146   * produces G_FILE_MONITOR_EVENT_DELETED/CREATED event pair when
     147   * an overwrite occurs in the directory (see dep-list for details).
     148   **/
     149  static void
     150  handle_overwritten (void *udata, const char *path, ino_t inode)
     151  {
     152    handle_ctx *ctx = NULL;
     153  
     154    (void) inode;
     155    ctx = (handle_ctx *) udata;
     156    g_assert (udata != NULL);
     157    g_assert (ctx->sub != NULL);
     158    g_assert (ctx->source != NULL);
     159  
     160    g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_DELETED,
     161                                        path, NULL, NULL, g_get_monotonic_time ());
     162  
     163    g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_CREATED,
     164                                        path, NULL, NULL, g_get_monotonic_time ());
     165  }
     166  
     167  static const traverse_cbs cbs = {
     168    handle_created,
     169    handle_deleted,
     170    handle_moved,
     171    handle_overwritten,
     172    handle_moved,
     173    NULL, /* many added */
     174    NULL, /* many removed */
     175    NULL, /* names updated */
     176  };
     177  
     178  
     179  void
     180  _kh_dir_diff (kqueue_sub *sub, gboolean handle_deleted)
     181  {
     182    dep_list *was;
     183    handle_ctx ctx;
     184  
     185    memset (&ctx, 0, sizeof (handle_ctx));
     186    ctx.sub = sub;
     187    ctx.source = sub->source;
     188    ctx.handle_deleted = handle_deleted;
     189  
     190    was = sub->deps;
     191    sub->deps = dl_listing (sub->filename);
     192  
     193    dl_calculate (was, sub->deps, &cbs, &ctx);
     194  
     195    dl_free (was);
     196  }