Merge branch 'g-clear-pointer-no-side-effects' into 'master'
[glib.git] / gio / fam / gfamfilemonitor.c
blobd9518a6217defc475396e69f6567149db43e3d76
1 /*
2 * Copyright © 2015 Canonical Limited
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General
15 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 * Author: Ryan Lortie <desrt@desrt.ca>
20 #include "config.h"
22 #include <gio/glocalfilemonitor.h>
23 #include <gio/giomodule.h>
24 #include "glib-private.h"
25 #include <glib-unix.h>
26 #include <fam.h>
28 static GMutex fam_lock;
29 static gboolean fam_initialised;
30 static FAMConnection fam_connection;
31 static GSource *fam_source;
33 #define G_TYPE_FAM_FILE_MONITOR (g_fam_file_monitor_get_type ())
34 #define G_FAM_FILE_MONITOR(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
35 G_TYPE_FAM_FILE_MONITOR, GFamFileMonitor))
37 typedef GLocalFileMonitorClass GFamFileMonitorClass;
39 typedef struct
41 GLocalFileMonitor parent_instance;
43 FAMRequest request;
44 } GFamFileMonitor;
46 static GType g_fam_file_monitor_get_type (void);
47 G_DEFINE_DYNAMIC_TYPE (GFamFileMonitor, g_fam_file_monitor, G_TYPE_LOCAL_FILE_MONITOR)
49 static gboolean
50 g_fam_file_monitor_callback (gint fd,
51 GIOCondition condition,
52 gpointer user_data)
54 gint64 now = g_source_get_time (fam_source);
56 g_mutex_lock (&fam_lock);
58 while (FAMPending (&fam_connection))
60 const gchar *child;
61 FAMEvent ev;
63 if (FAMNextEvent (&fam_connection, &ev) != 1)
65 /* The daemon died. We're in a really bad situation now
66 * because we potentially have a bunch of request structures
67 * outstanding which no longer make any sense to anyone.
69 * The best thing that we can do is do nothing. Notification
70 * won't work anymore for this process.
72 g_mutex_unlock (&fam_lock);
74 g_warning ("Lost connection to FAM (file monitoring) service. Expect no further file monitor events.");
76 return FALSE;
79 /* We expect ev.filename to be a relative path for children in a
80 * monitored directory, and an absolute path for a monitored file
81 * or the directory itself.
83 if (ev.filename[0] != '/')
84 child = ev.filename;
85 else
86 child = NULL;
88 switch (ev.code)
90 case FAMAcknowledge:
91 g_source_unref (ev.userdata);
92 break;
94 case FAMChanged:
95 g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CHANGED, child, NULL, NULL, now);
96 break;
98 case FAMDeleted:
99 g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_DELETED, child, NULL, NULL, now);
100 break;
102 case FAMCreated:
103 g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CREATED, child, NULL, NULL, now);
104 break;
106 default:
107 /* unknown type */
108 break;
112 g_mutex_unlock (&fam_lock);
114 return TRUE;
117 static gboolean
118 g_fam_file_monitor_is_supported (void)
120 g_mutex_lock (&fam_lock);
122 if (!fam_initialised)
124 fam_initialised = FAMOpen2 (&fam_connection, "GLib GIO") == 0;
126 if (fam_initialised)
128 #ifdef HAVE_FAM_NO_EXISTS
129 /* This is a gamin extension that avoids sending all the
130 * Exists event for dir monitors
132 FAMNoExists (&fam_connection);
133 #endif
135 fam_source = g_unix_fd_source_new (FAMCONNECTION_GETFD (&fam_connection), G_IO_IN);
136 g_source_set_callback (fam_source, (GSourceFunc) g_fam_file_monitor_callback, NULL, NULL);
137 g_source_attach (fam_source, GLIB_PRIVATE_CALL(g_get_worker_context) ());
141 g_mutex_unlock (&fam_lock);
143 return fam_initialised;
146 static gboolean
147 g_fam_file_monitor_cancel (GFileMonitor *monitor)
149 GFamFileMonitor *gffm = G_FAM_FILE_MONITOR (monitor);
151 g_mutex_lock (&fam_lock);
153 g_assert (fam_initialised);
155 FAMCancelMonitor (&fam_connection, &gffm->request);
157 g_mutex_unlock (&fam_lock);
159 return TRUE;
162 static void
163 g_fam_file_monitor_start (GLocalFileMonitor *local_monitor,
164 const gchar *dirname,
165 const gchar *basename,
166 const gchar *filename,
167 GFileMonitorSource *source)
169 GFamFileMonitor *gffm = G_FAM_FILE_MONITOR (local_monitor);
171 g_mutex_lock (&fam_lock);
173 g_assert (fam_initialised);
175 g_source_ref ((GSource *) source);
177 if (dirname)
178 FAMMonitorDirectory (&fam_connection, dirname, &gffm->request, source);
179 else
180 FAMMonitorFile (&fam_connection, filename, &gffm->request, source);
182 g_mutex_unlock (&fam_lock);
185 static void
186 g_fam_file_monitor_init (GFamFileMonitor* monitor)
190 static void
191 g_fam_file_monitor_class_init (GFamFileMonitorClass *class)
193 GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (class);
195 class->is_supported = g_fam_file_monitor_is_supported;
196 class->start = g_fam_file_monitor_start;
197 file_monitor_class->cancel = g_fam_file_monitor_cancel;
200 static void
201 g_fam_file_monitor_class_finalize (GFamFileMonitorClass *class)
205 void
206 g_io_module_load (GIOModule *module)
208 g_type_module_use (G_TYPE_MODULE (module));
210 g_fam_file_monitor_register_type (G_TYPE_MODULE (module));
212 g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
213 G_TYPE_FAM_FILE_MONITOR, "fam", 10);
215 g_io_extension_point_implement (G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
216 G_TYPE_FAM_FILE_MONITOR, "fam", 10);
219 void
220 g_io_module_unload (GIOModule *module)
222 g_assert_not_reached ();
225 char **
226 g_io_module_query (void)
228 char *eps[] = {
229 G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
230 G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
231 NULL
234 return g_strdupv (eps);