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