LCOV - code coverage report
Current view: top level - glib/gio/inotify - inotify-path.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 222 231 96.1 %
Date: 2024-04-23 05:16:05 Functions: 24 24 100.0 %
Branches: 81 108 75.0 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 8 -*- */
       2                 :            : 
       3                 :            : /* inotify-path.c - GVFS Monitor based on inotify.
       4                 :            : 
       5                 :            :    Copyright (C) 2006 John McCutchan
       6                 :            :    Copyright (C) 2009 Codethink Limited
       7                 :            : 
       8                 :            :    SPDX-License-Identifier: LGPL-2.1-or-later
       9                 :            : 
      10                 :            :    This library is free software; you can redistribute it and/or
      11                 :            :    modify it under the terms of the GNU Lesser General Public
      12                 :            :    License as published by the Free Software Foundation; either
      13                 :            :    version 2.1 of the License, or (at your option) any later version.
      14                 :            : 
      15                 :            :    This library is distributed in the hope that it will be useful,
      16                 :            :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      18                 :            :    Lesser General Public License for more details.
      19                 :            : 
      20                 :            :    You should have received a copy of the GNU Lesser General Public License
      21                 :            :    along with this library; if not, see <http://www.gnu.org/licenses/>.
      22                 :            : 
      23                 :            :    Authors:
      24                 :            :                  John McCutchan <john@johnmccutchan.com>
      25                 :            :                  Ryan Lortie <desrt@desrt.ca>
      26                 :            : */
      27                 :            : 
      28                 :            : #include "config.h"
      29                 :            : 
      30                 :            : /* Don't put conflicting kernel types in the global namespace: */
      31                 :            : #define __KERNEL_STRICT_NAMES
      32                 :            : 
      33                 :            : #include <sys/inotify.h>
      34                 :            : #include <string.h>
      35                 :            : #include <glib.h>
      36                 :            : #include "inotify-kernel.h"
      37                 :            : #include "inotify-path.h"
      38                 :            : #include "inotify-missing.h"
      39                 :            : 
      40                 :            : #define IP_INOTIFY_DIR_MASK (IN_MODIFY|IN_ATTRIB|IN_MOVED_FROM|IN_MOVED_TO|IN_DELETE|IN_CREATE|IN_DELETE_SELF|IN_UNMOUNT|IN_MOVE_SELF|IN_CLOSE_WRITE)
      41                 :            : 
      42                 :            : #define IP_INOTIFY_FILE_MASK (IN_MODIFY|IN_ATTRIB|IN_CLOSE_WRITE)
      43                 :            : 
      44                 :            : /* Older libcs don't have this */
      45                 :            : #ifndef IN_ONLYDIR
      46                 :            : #define IN_ONLYDIR 0  
      47                 :            : #endif
      48                 :            : 
      49                 :            : typedef struct ip_watched_file_s {
      50                 :            :   gchar *filename;
      51                 :            :   gchar *path;
      52                 :            :   gint32 wd;
      53                 :            : 
      54                 :            :   GList *subs;
      55                 :            : } ip_watched_file_t;
      56                 :            : 
      57                 :            : typedef struct ip_watched_dir_s {
      58                 :            :   char *path;
      59                 :            :   /* TODO: We need to maintain a tree of watched directories
      60                 :            :    * so that we can deliver move/delete events to sub folders.
      61                 :            :    * Or the application could do it...
      62                 :            :    */
      63                 :            :   struct ip_watched_dir_s* parent;
      64                 :            :   GList*         children;
      65                 :            : 
      66                 :            :   /* basename -> ip_watched_file_t
      67                 :            :    * Maps basename to a ip_watched_file_t if the file is currently
      68                 :            :    * being directly watched for changes (ie: 'hardlinks' mode).
      69                 :            :    */
      70                 :            :   GHashTable *files_hash;
      71                 :            : 
      72                 :            :   /* Inotify state */
      73                 :            :   gint32 wd;
      74                 :            :   
      75                 :            :   /* List of inotify subscriptions */
      76                 :            :   GList *subs;
      77                 :            : } ip_watched_dir_t;
      78                 :            : 
      79                 :            : static gboolean     ip_debug_enabled = FALSE;
      80                 :            : #define IP_W if (ip_debug_enabled) g_warning
      81                 :            : 
      82                 :            : /* path -> ip_watched_dir */
      83                 :            : static GHashTable * path_dir_hash = NULL;
      84                 :            : /* inotify_sub * -> ip_watched_dir *
      85                 :            :  *
      86                 :            :  * Each subscription is attached to a watched directory or it is on
      87                 :            :  * the missing list
      88                 :            :  */
      89                 :            : static GHashTable * sub_dir_hash = NULL;
      90                 :            : /* This hash holds GLists of ip_watched_dir_t *'s
      91                 :            :  * We need to hold a list because symbolic links can share
      92                 :            :  * the same wd
      93                 :            :  */
      94                 :            : static GHashTable * wd_dir_hash = NULL;
      95                 :            : /* This hash holds GLists of ip_watched_file_t *'s
      96                 :            :  * We need to hold a list because links can share
      97                 :            :  * the same wd
      98                 :            :  */
      99                 :            : static GHashTable * wd_file_hash = NULL;
     100                 :            : 
     101                 :            : static ip_watched_dir_t *ip_watched_dir_new  (const char       *path,
     102                 :            :                                               int               wd);
     103                 :            : static void              ip_watched_dir_free (ip_watched_dir_t *dir);
     104                 :            : static gboolean          ip_event_callback   (ik_event_t       *event);
     105                 :            : 
     106                 :            : 
     107                 :            : static gboolean (*event_callback)(ik_event_t *event, inotify_sub *sub, gboolean file_event);
     108                 :            : 
     109                 :            : gboolean
     110                 :         57 : _ip_startup (gboolean (*cb)(ik_event_t *event, inotify_sub *sub, gboolean file_event))
     111                 :            : {
     112                 :            :   static gboolean initialized = FALSE;
     113                 :            :   static gboolean result = FALSE;
     114                 :            :   
     115         [ -  + ]:         57 :   if (initialized == TRUE)
     116                 :          0 :     return result;
     117                 :            : 
     118                 :         57 :   event_callback = cb;
     119                 :         57 :   result = _ik_startup (ip_event_callback);
     120                 :            : 
     121         [ -  + ]:         57 :   if (!result)
     122                 :          0 :     return FALSE;
     123                 :            : 
     124                 :         57 :   path_dir_hash = g_hash_table_new (g_str_hash, g_str_equal);
     125                 :         57 :   sub_dir_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
     126                 :         57 :   wd_dir_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
     127                 :         57 :   wd_file_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
     128                 :            :   
     129                 :         57 :   initialized = TRUE;
     130                 :         57 :   return TRUE;
     131                 :            : }
     132                 :            : 
     133                 :            : static void
     134                 :        384 : ip_map_path_dir (const char       *path, 
     135                 :            :                  ip_watched_dir_t *dir)
     136                 :            : {
     137                 :        384 :   g_assert (path && dir);
     138                 :        384 :   g_hash_table_insert (path_dir_hash, dir->path, dir);
     139                 :        384 : }
     140                 :            : 
     141                 :            : static void
     142                 :        637 : ip_map_sub_dir (inotify_sub      *sub, 
     143                 :            :                 ip_watched_dir_t *dir)
     144                 :            : {
     145                 :            :   /* Associate subscription and directory */
     146                 :        637 :   g_assert (dir && sub);
     147                 :        637 :   g_hash_table_insert (sub_dir_hash, sub, dir);
     148                 :        637 :   dir->subs = g_list_prepend (dir->subs, sub);
     149                 :        637 : }
     150                 :            : 
     151                 :            : static void
     152                 :        384 : ip_map_wd_dir (gint32            wd, 
     153                 :            :                ip_watched_dir_t *dir)
     154                 :            : {
     155                 :            :   GList *dir_list;
     156                 :            :   
     157                 :        384 :   g_assert (wd >= 0 && dir);
     158                 :        384 :   dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER (wd));
     159                 :        384 :   dir_list = g_list_prepend (dir_list, dir);
     160                 :        384 :   g_hash_table_replace (wd_dir_hash, GINT_TO_POINTER (dir->wd), dir_list);
     161                 :        384 : }
     162                 :            : 
     163                 :            : static void
     164                 :          1 : ip_map_wd_file (gint32             wd,
     165                 :            :                 ip_watched_file_t *file)
     166                 :            : {
     167                 :            :   GList *file_list;
     168                 :            : 
     169                 :          1 :   g_assert (wd >= 0 && file);
     170                 :          1 :   file_list = g_hash_table_lookup (wd_file_hash, GINT_TO_POINTER (wd));
     171                 :          1 :   file_list = g_list_prepend (file_list, file);
     172                 :          1 :   g_hash_table_replace (wd_file_hash, GINT_TO_POINTER (wd), file_list);
     173                 :          1 : }
     174                 :            : 
     175                 :            : static void
     176                 :          1 : ip_unmap_wd_file (gint32             wd,
     177                 :            :                   ip_watched_file_t *file)
     178                 :            : {
     179                 :          1 :   GList *file_list = g_hash_table_lookup (wd_file_hash, GINT_TO_POINTER (wd));
     180                 :            : 
     181         [ -  + ]:          1 :   if (!file_list)
     182                 :          0 :     return;
     183                 :            : 
     184                 :          1 :   g_assert (wd >= 0 && file);
     185                 :          1 :   file_list = g_list_remove (file_list, file);
     186         [ +  - ]:          1 :   if (file_list == NULL)
     187                 :          1 :     g_hash_table_remove (wd_file_hash, GINT_TO_POINTER (wd));
     188                 :            :   else
     189                 :          0 :     g_hash_table_replace (wd_file_hash, GINT_TO_POINTER (wd), file_list);
     190                 :            : }
     191                 :            : 
     192                 :            : 
     193                 :            : static ip_watched_file_t *
     194                 :          1 : ip_watched_file_new (const gchar *dirname,
     195                 :            :                      const gchar *filename)
     196                 :            : {
     197                 :            :   ip_watched_file_t *file;
     198                 :            : 
     199                 :          1 :   file = g_new0 (ip_watched_file_t, 1);
     200                 :          1 :   file->path = g_strjoin ("/", dirname, filename, NULL);
     201                 :          1 :   file->filename = g_strdup (filename);
     202                 :          1 :   file->wd = -1;
     203                 :            : 
     204                 :          1 :   return file;
     205                 :            : }
     206                 :            : 
     207                 :            : static void
     208                 :          1 : ip_watched_file_free (ip_watched_file_t *file)
     209                 :            : {
     210                 :          1 :   g_assert (file->subs == NULL);
     211                 :          1 :   g_free (file->filename);
     212                 :          1 :   g_free (file->path);
     213                 :          1 :   g_free (file);
     214                 :          1 : }
     215                 :            : 
     216                 :            : static void
     217                 :          1 : ip_watched_file_add_sub (ip_watched_file_t *file,
     218                 :            :                          inotify_sub       *sub)
     219                 :            : {
     220                 :          1 :   file->subs = g_list_prepend (file->subs, sub);
     221                 :          1 : }
     222                 :            : 
     223                 :            : static void
     224                 :          1 : ip_watched_file_start (ip_watched_file_t *file)
     225                 :            : {
     226         [ +  - ]:          1 :   if (file->wd < 0)
     227                 :            :     {
     228                 :            :       gint err;
     229                 :            : 
     230                 :          1 :       file->wd = _ik_watch (file->path,
     231                 :            :                             IP_INOTIFY_FILE_MASK,
     232                 :            :                             &err);
     233                 :            : 
     234         [ +  - ]:          1 :       if (file->wd >= 0)
     235                 :          1 :         ip_map_wd_file (file->wd, file);
     236                 :            :     }
     237                 :          1 : }
     238                 :            : 
     239                 :            : static void
     240                 :          3 : ip_watched_file_stop (ip_watched_file_t *file)
     241                 :            : {
     242         [ +  + ]:          3 :   if (file->wd >= 0)
     243                 :            :     {
     244                 :          1 :       _ik_ignore (file->path, file->wd);
     245                 :          1 :       ip_unmap_wd_file (file->wd, file);
     246                 :          1 :       file->wd = -1;
     247                 :            :     }
     248                 :          3 : }
     249                 :            : 
     250                 :            : gboolean
     251                 :        640 : _ip_start_watching (inotify_sub *sub)
     252                 :            : {
     253                 :            :   gint32 wd;
     254                 :            :   int err;
     255                 :            :   ip_watched_dir_t *dir;
     256                 :            :   
     257                 :        640 :   g_assert (sub);
     258                 :        640 :   g_assert (!sub->cancelled);
     259                 :        640 :   g_assert (sub->dirname);
     260                 :            :   
     261         [ -  + ]:        640 :   IP_W ("Starting to watch %s\n", sub->dirname);
     262                 :        640 :   dir = g_hash_table_lookup (path_dir_hash, sub->dirname);
     263                 :            : 
     264         [ +  + ]:        640 :   if (dir == NULL)
     265                 :            :     {
     266         [ -  + ]:        387 :       IP_W ("Trying to add inotify watch ");
     267                 :        387 :       wd = _ik_watch (sub->dirname, IP_INOTIFY_DIR_MASK|IN_ONLYDIR, &err);
     268         [ +  + ]:        387 :       if (wd < 0)
     269                 :            :         {
     270         [ -  + ]:          3 :           IP_W ("Failed\n");
     271                 :          3 :           return FALSE;
     272                 :            :         }
     273                 :            :       else
     274                 :            :         {
     275                 :            :           /* Create new watched directory and associate it with the
     276                 :            :            * wd hash and path hash
     277                 :            :            */
     278         [ -  + ]:        384 :           IP_W ("Success\n");
     279                 :        384 :           dir = ip_watched_dir_new (sub->dirname, wd);
     280                 :        384 :           ip_map_wd_dir (wd, dir);
     281                 :        384 :           ip_map_path_dir (sub->dirname, dir);
     282                 :            :         }
     283                 :            :     }
     284                 :            :   else
     285         [ -  + ]:        253 :     IP_W ("Already watching\n");
     286                 :            : 
     287         [ +  + ]:        637 :   if (sub->hardlinks)
     288                 :            :     {
     289                 :            :       ip_watched_file_t *file;
     290                 :            : 
     291                 :          1 :       file = g_hash_table_lookup (dir->files_hash, sub->filename);
     292                 :            : 
     293         [ +  - ]:          1 :       if (file == NULL)
     294                 :            :         {
     295                 :          1 :           file = ip_watched_file_new (sub->dirname, sub->filename);
     296                 :          1 :           g_hash_table_insert (dir->files_hash, file->filename, file);
     297                 :            :         }
     298                 :            : 
     299                 :          1 :       ip_watched_file_add_sub (file, sub);
     300                 :          1 :       ip_watched_file_start (file);
     301                 :            :     }
     302                 :            : 
     303                 :        637 :   ip_map_sub_dir (sub, dir);
     304                 :            :   
     305                 :        637 :   return TRUE;
     306                 :            : }
     307                 :            : 
     308                 :            : static void
     309                 :        240 : ip_unmap_path_dir (const char       *path, 
     310                 :            :                    ip_watched_dir_t *dir)
     311                 :            : {
     312                 :        240 :   g_assert (path && dir);
     313                 :        240 :   g_hash_table_remove (path_dir_hash, dir->path);
     314                 :        240 : }
     315                 :            : 
     316                 :            : static void
     317                 :        192 : ip_unmap_wd_dir (gint32            wd, 
     318                 :            :                  ip_watched_dir_t *dir)
     319                 :            : {
     320                 :        192 :   GList *dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER (wd));
     321                 :            :   
     322         [ -  + ]:        192 :   if (!dir_list)
     323                 :          0 :     return;
     324                 :            :   
     325                 :        192 :   g_assert (wd >= 0 && dir);
     326                 :        192 :   dir_list = g_list_remove (dir_list, dir);
     327         [ +  - ]:        192 :   if (dir_list == NULL) 
     328                 :        192 :     g_hash_table_remove (wd_dir_hash, GINT_TO_POINTER (dir->wd));
     329                 :            :   else
     330                 :          0 :     g_hash_table_replace (wd_dir_hash, GINT_TO_POINTER (dir->wd), dir_list);
     331                 :            : }
     332                 :            : 
     333                 :            : static void
     334                 :         59 : ip_unmap_wd (gint32 wd)
     335                 :            : {
     336                 :         59 :   GList *dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER (wd));
     337         [ +  + ]:         59 :   if (!dir_list)
     338                 :         11 :     return;
     339                 :         48 :   g_assert (wd >= 0);
     340                 :         48 :   g_hash_table_remove (wd_dir_hash, GINT_TO_POINTER (wd));
     341                 :         48 :   g_list_free (dir_list);
     342                 :            : }
     343                 :            : 
     344                 :            : static void
     345                 :        440 : ip_unmap_sub_dir (inotify_sub      *sub,
     346                 :            :                   ip_watched_dir_t *dir)
     347                 :            : {
     348                 :        440 :   g_assert (sub && dir);
     349                 :        440 :   g_hash_table_remove (sub_dir_hash, sub);
     350                 :        440 :   dir->subs = g_list_remove (dir->subs, sub);
     351                 :            : 
     352         [ +  + ]:        440 :   if (sub->hardlinks)
     353                 :            :     {
     354                 :            :       ip_watched_file_t *file;
     355                 :            : 
     356                 :          1 :       file = g_hash_table_lookup (dir->files_hash, sub->filename);
     357                 :          1 :       file->subs = g_list_remove (file->subs, sub);
     358                 :            : 
     359         [ +  - ]:          1 :       if (file->subs == NULL)
     360                 :            :         {
     361                 :          1 :           g_hash_table_remove (dir->files_hash, sub->filename);
     362                 :          1 :           ip_watched_file_stop (file);
     363                 :          1 :           ip_watched_file_free (file);
     364                 :            :         }
     365                 :            :     }
     366                 :        440 :  }
     367                 :            : 
     368                 :            : static void
     369                 :         48 : ip_unmap_all_subs (ip_watched_dir_t *dir)
     370                 :            : {
     371         [ +  + ]:        257 :   while (dir->subs != NULL)
     372                 :        209 :     ip_unmap_sub_dir (dir->subs->data, dir);
     373                 :         48 : }
     374                 :            : 
     375                 :            : gboolean
     376                 :        440 : _ip_stop_watching (inotify_sub *sub)
     377                 :            : {
     378                 :        440 :   ip_watched_dir_t *dir = NULL;
     379                 :            :   
     380                 :        440 :   dir = g_hash_table_lookup (sub_dir_hash, sub);
     381         [ +  + ]:        440 :   if (!dir) 
     382                 :        209 :     return TRUE;
     383                 :            :   
     384                 :        231 :   ip_unmap_sub_dir (sub, dir);
     385                 :            :   
     386                 :            :   /* No one is subscribing to this directory any more */
     387         [ +  + ]:        231 :   if (dir->subs == NULL)
     388                 :            :     {
     389                 :        192 :       _ik_ignore (dir->path, dir->wd);
     390                 :        192 :       ip_unmap_wd_dir (dir->wd, dir);
     391                 :        192 :       ip_unmap_path_dir (dir->path, dir);
     392                 :        192 :       ip_watched_dir_free (dir);
     393                 :            :     }
     394                 :            :   
     395                 :        231 :   return TRUE;
     396                 :            : }
     397                 :            : 
     398                 :            : 
     399                 :            : static ip_watched_dir_t *
     400                 :        384 : ip_watched_dir_new (const char *path, 
     401                 :            :                     gint32      wd)
     402                 :            : {
     403                 :        384 :   ip_watched_dir_t *dir = g_new0 (ip_watched_dir_t, 1);
     404                 :            :   
     405                 :        384 :   dir->path = g_strdup (path);
     406                 :        384 :   dir->files_hash = g_hash_table_new (g_str_hash, g_str_equal);
     407                 :        384 :   dir->wd = wd;
     408                 :            :   
     409                 :        384 :   return dir;
     410                 :            : }
     411                 :            : 
     412                 :            : static void
     413                 :        240 : ip_watched_dir_free (ip_watched_dir_t *dir)
     414                 :            : {
     415                 :        240 :   g_assert_cmpint (g_hash_table_size (dir->files_hash), ==, 0);
     416                 :        240 :   g_assert (dir->subs == NULL);
     417                 :        240 :   g_free (dir->path);
     418                 :        240 :   g_hash_table_unref (dir->files_hash);
     419                 :        240 :   g_free (dir);
     420                 :        240 : }
     421                 :            : 
     422                 :            : static void
     423                 :         48 : ip_wd_delete (gpointer data, 
     424                 :            :               gpointer user_data)
     425                 :            : {
     426                 :         48 :   ip_watched_dir_t *dir = data;
     427                 :         48 :   GList *l = NULL;
     428                 :            :   
     429         [ +  + ]:        257 :   for (l = dir->subs; l; l = l->next)
     430                 :            :     {
     431                 :        209 :       inotify_sub *sub = l->data;
     432                 :            :       /* Add subscription to missing list */
     433                 :        209 :       _im_add (sub);
     434                 :            :     }
     435                 :         48 :   ip_unmap_all_subs (dir);
     436                 :            :   /* Unassociate the path and the directory */
     437                 :         48 :   ip_unmap_path_dir (dir->path, dir);
     438                 :         48 :   ip_watched_dir_free (dir);
     439                 :         48 : }
     440                 :            : 
     441                 :            : static gboolean
     442                 :        652 : ip_event_dispatch (GList      *dir_list, 
     443                 :            :                    GList      *file_list,
     444                 :            :                    ik_event_t *event)
     445                 :            : {
     446                 :        652 :   gboolean interesting = FALSE;
     447                 :            : 
     448                 :            :   GList *l;
     449                 :            :   
     450         [ -  + ]:        652 :   if (!event)
     451                 :          0 :     return FALSE;
     452                 :            : 
     453         [ +  + ]:       1063 :   for (l = dir_list; l; l = l->next)
     454                 :            :     {
     455                 :            :       GList *subl;
     456                 :        411 :       ip_watched_dir_t *dir = l->data;
     457                 :            :       
     458         [ +  + ]:       1365 :       for (subl = dir->subs; subl; subl = subl->next)
     459                 :            :         {
     460                 :        954 :           inotify_sub *sub = subl->data;
     461                 :            :           
     462                 :            :           /* If the subscription and the event
     463                 :            :            * contain a filename and they don't
     464                 :            :            * match, we don't deliver this event.
     465                 :            :            */
     466         [ +  + ]:        954 :           if (sub->filename &&
     467         [ +  + ]:        138 :               event->name &&
     468         [ +  + ]:        136 :               strcmp (sub->filename, event->name) &&
     469   [ +  +  +  -  :         56 :               (!event->pair || !event->pair->name || strcmp (sub->filename, event->pair->name)))
                   -  + ]
     470                 :         41 :             continue;
     471                 :            :           
     472                 :            :           /* If the subscription has a filename
     473                 :            :            * but this event doesn't, we don't
     474                 :            :            * deliver this event.
     475                 :            :            */
     476   [ +  +  +  + ]:        913 :           if (sub->filename && !event->name)
     477                 :          2 :             continue;
     478                 :            :           
     479                 :            :           /* If we're also watching the file directly
     480                 :            :            * don't report events that will also be
     481                 :            :            * reported on the file itself.
     482                 :            :            */
     483         [ +  + ]:        911 :           if (sub->hardlinks)
     484                 :            :             {
     485                 :          6 :               event->mask &= ~IP_INOTIFY_FILE_MASK;
     486         [ +  + ]:          6 :               if (!event->mask)
     487                 :          4 :                 continue;
     488                 :            :             }
     489                 :            :           
     490                 :            :           /* FIXME: We might need to synthesize
     491                 :            :            * DELETE/UNMOUNT events when
     492                 :            :            * the filename doesn't match
     493                 :            :            */
     494                 :            :           
     495                 :        907 :           interesting |= event_callback (event, sub, FALSE);
     496                 :            : 
     497         [ +  + ]:        907 :           if (sub->hardlinks)
     498                 :            :             {
     499                 :            :               ip_watched_file_t *file;
     500                 :            : 
     501                 :          2 :               file = g_hash_table_lookup (dir->files_hash, sub->filename);
     502                 :            : 
     503         [ +  - ]:          2 :               if (file != NULL)
     504                 :            :                 {
     505         [ +  - ]:          2 :                   if (event->mask & (IN_MOVED_FROM | IN_DELETE))
     506                 :          2 :                     ip_watched_file_stop (file);
     507                 :            : 
     508         [ -  + ]:          2 :                   if (event->mask & (IN_MOVED_TO | IN_CREATE))
     509                 :          0 :                     ip_watched_file_start (file);
     510                 :            :                 }
     511                 :            :             }
     512                 :            :         }
     513                 :            :     }
     514                 :            : 
     515         [ +  + ]:        655 :   for (l = file_list; l; l = l->next)
     516                 :            :     {
     517                 :          3 :       ip_watched_file_t *file = l->data;
     518                 :            :       GList *subl;
     519                 :            : 
     520         [ +  + ]:          6 :       for (subl = file->subs; subl; subl = subl->next)
     521                 :            :         {
     522                 :          3 :           inotify_sub *sub = subl->data;
     523                 :            : 
     524                 :          3 :           interesting |= event_callback (event, sub, TRUE);
     525                 :            :         }
     526                 :            :     }
     527                 :            : 
     528                 :        652 :   return interesting;
     529                 :            : }
     530                 :            : 
     531                 :            : static gboolean
     532                 :        892 : ip_event_callback (ik_event_t *event)
     533                 :            : {
     534                 :        892 :   gboolean interesting = FALSE;
     535                 :        892 :   GList* dir_list = NULL;
     536                 :        892 :   GList *file_list = NULL;
     537                 :            : 
     538                 :            :   /* We can ignore the IGNORED events. Likewise, if the event queue overflowed,
     539                 :            :    * there is not much we can do to recover. */
     540         [ +  + ]:        892 :   if (event->mask & (IN_IGNORED | IN_Q_OVERFLOW))
     541                 :            :     {
     542                 :        241 :       _ik_event_free (event);
     543                 :        241 :       return TRUE;
     544                 :            :     }
     545                 :            : 
     546                 :        651 :   dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER (event->wd));
     547                 :        651 :   file_list = g_hash_table_lookup (wd_file_hash, GINT_TO_POINTER (event->wd));
     548                 :            : 
     549         [ +  - ]:        651 :   if (event->mask & IP_INOTIFY_DIR_MASK)
     550                 :        651 :     interesting |= ip_event_dispatch (dir_list, file_list, event);
     551                 :            : 
     552                 :            :   /* Only deliver paired events if the wds are separate */
     553   [ +  +  +  + ]:        651 :   if (event->pair && event->pair->wd != event->wd)
     554                 :            :     {
     555                 :          1 :       dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER (event->pair->wd));
     556                 :          1 :       file_list = g_hash_table_lookup (wd_file_hash, GINT_TO_POINTER (event->pair->wd));
     557                 :            : 
     558         [ +  - ]:          1 :       if (event->pair->mask & IP_INOTIFY_DIR_MASK)
     559                 :          1 :         interesting |= ip_event_dispatch (dir_list, file_list, event->pair);
     560                 :            :     }
     561                 :            : 
     562                 :            :   /* We have to manage the missing list
     563                 :            :    * when we get an event that means the
     564                 :            :    * file has been deleted/moved/unmounted.
     565                 :            :    */
     566         [ +  + ]:        651 :   if (event->mask & IN_DELETE_SELF ||
     567         [ +  - ]:        592 :       event->mask & IN_MOVE_SELF ||
     568         [ -  + ]:        592 :       event->mask & IN_UNMOUNT)
     569                 :            :     {
     570                 :            :       /* Add all subscriptions to missing list */
     571                 :         59 :       g_list_foreach (dir_list, ip_wd_delete, NULL);
     572                 :            :       /* Unmap all directories attached to this wd */
     573                 :         59 :       ip_unmap_wd (event->wd);
     574                 :            :     }
     575                 :            :   
     576                 :        651 :   _ik_event_free (event);
     577                 :            : 
     578                 :        651 :   return interesting;
     579                 :            : }
     580                 :            : 
     581                 :            : const char *
     582                 :         77 : _ip_get_path_for_wd (gint32 wd)
     583                 :            : {
     584                 :            :   GList *dir_list;
     585                 :            :   ip_watched_dir_t *dir;
     586                 :            : 
     587                 :         77 :   g_assert (wd >= 0);
     588                 :         77 :   dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER (wd));
     589         [ +  - ]:         77 :   if (dir_list)
     590                 :            :     {
     591                 :         77 :       dir = dir_list->data;
     592         [ +  - ]:         77 :       if (dir)
     593                 :         77 :         return dir->path;
     594                 :            :     }
     595                 :            : 
     596                 :          0 :   return NULL;
     597                 :            : }

Generated by: LCOV version 1.14