• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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