1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 8 -*- */ 2 3 /* inotify-helper.c - Gnome VFS Monitor based on inotify. 4 5 Copyright (C) 2005 John McCutchan 6 7 The Gnome Library is free software; you can redistribute it and/or 8 modify it under the terms of the GNU Library General Public License as 9 published by the Free Software Foundation; either version 2 of the 10 License, or (at your option) any later version. 11 12 The Gnome Library is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 Library General Public License for more details. 16 17 You should have received a copy of the GNU Library General Public 18 License along with the Gnome Library; see the file COPYING.LIB. If not, 19 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 20 Boston, MA 02111-1307, USA. 21 22 Authors: 23 John McCutchan <john (at) johnmccutchan.com> 24 */ 25 26 #include "config.h" 27 #include <glib.h> 28 #include "inotify-missing.h" 29 #include "inotify-path.h" 30 31 #define SCAN_MISSING_TIME 4 /* 1/4 Hz */ 32 33 static gboolean im_debug_enabled = FALSE; 34 #define IM_W if (im_debug_enabled) g_warning 35 36 /* We put inotify_sub's that are missing on this list */ 37 static GList *missing_sub_list = NULL; 38 static gboolean im_scan_missing (gpointer user_data); 39 static gboolean scan_missing_running = FALSE; 40 static void (*missing_cb)(inotify_sub *sub) = NULL; 41 42 G_LOCK_EXTERN (inotify_lock); 43 44 /* inotify_lock must be held before calling */ 45 void 46 _im_startup (void (*callback)(inotify_sub *sub)) 47 { 48 static gboolean initialized = FALSE; 49 50 if (!initialized) 51 { 52 missing_cb = callback; 53 initialized = TRUE; 54 } 55 } 56 57 /* inotify_lock must be held before calling */ 58 void 59 _im_add (inotify_sub *sub) 60 { 61 if (g_list_find (missing_sub_list, sub)) 62 { 63 IM_W ("asked to add %s to missing list but it's already on the list!\n", sub->dirname); 64 return; 65 } 66 67 IM_W ("adding %s to missing list\n", sub->dirname); 68 missing_sub_list = g_list_prepend (missing_sub_list, sub); 69 70 /* If the timeout is turned off, we turn it back on */ 71 if (!scan_missing_running) 72 { 73 scan_missing_running = TRUE; 74 g_timeout_add_seconds (SCAN_MISSING_TIME, im_scan_missing, NULL); 75 } 76 } 77 78 /* inotify_lock must be held before calling */ 79 void 80 _im_rm (inotify_sub *sub) 81 { 82 GList *link; 83 84 link = g_list_find (missing_sub_list, sub); 85 86 if (!link) 87 { 88 IM_W ("asked to remove %s from missing list but it isn't on the list!\n", sub->dirname); 89 return; 90 } 91 92 IM_W ("removing %s from missing list\n", sub->dirname); 93 94 missing_sub_list = g_list_remove_link (missing_sub_list, link); 95 g_list_free_1 (link); 96 } 97 98 /* Scans the list of missing subscriptions checking if they 99 * are available yet. 100 */ 101 static gboolean 102 im_scan_missing (gpointer user_data) 103 { 104 GList *nolonger_missing = NULL; 105 GList *l; 106 107 G_LOCK (inotify_lock); 108 109 IM_W ("scanning missing list with %d items\n", g_list_length (missing_sub_list)); 110 for (l = missing_sub_list; l; l = l->next) 111 { 112 inotify_sub *sub = l->data; 113 gboolean not_m = FALSE; 114 115 IM_W ("checking %p\n", sub); 116 g_assert (sub); 117 g_assert (sub->dirname); 118 not_m = _ip_start_watching (sub); 119 120 if (not_m) 121 { 122 missing_cb (sub); 123 IM_W ("removed %s from missing list\n", sub->dirname); 124 /* We have to build a list of list nodes to remove from the 125 * missing_sub_list. We do the removal outside of this loop. 126 */ 127 nolonger_missing = g_list_prepend (nolonger_missing, l); 128 } 129 } 130 131 for (l = nolonger_missing; l ; l = l->next) 132 { 133 GList *llink = l->data; 134 missing_sub_list = g_list_remove_link (missing_sub_list, llink); 135 g_list_free_1 (llink); 136 } 137 138 g_list_free (nolonger_missing); 139 140 /* If the missing list is now empty, we disable the timeout */ 141 if (missing_sub_list == NULL) 142 { 143 scan_missing_running = FALSE; 144 G_UNLOCK (inotify_lock); 145 return FALSE; 146 } 147 else 148 { 149 G_UNLOCK (inotify_lock); 150 return TRUE; 151 } 152 } 153 154 155 /* inotify_lock must be held */ 156 void 157 _im_diag_dump (GIOChannel *ioc) 158 { 159 GList *l; 160 g_io_channel_write_chars (ioc, "missing list:\n", -1, NULL, NULL); 161 for (l = missing_sub_list; l; l = l->next) 162 { 163 inotify_sub *sub = l->data; 164 g_io_channel_write_chars (ioc, sub->dirname, -1, NULL, NULL); 165 g_io_channel_write_chars (ioc, "\n", -1, NULL, NULL); 166 } 167 } 168