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>
22 #include <gio/glocalfilemonitor.h>
23 #include <gio/giomodule.h>
24 #include "glib-private.h"
25 #include <glib-unix.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
;
41 GLocalFileMonitor parent_instance
;
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
)
50 g_fam_file_monitor_callback (gint fd
,
51 GIOCondition condition
,
54 gint64 now
= g_source_get_time (fam_source
);
56 g_mutex_lock (&fam_lock
);
58 while (FAMPending (&fam_connection
))
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.");
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] != '/')
91 g_source_unref (ev
.userdata
);
95 g_file_monitor_source_handle_event (ev
.userdata
, G_FILE_MONITOR_EVENT_CHANGED
, child
, NULL
, NULL
, now
);
99 g_file_monitor_source_handle_event (ev
.userdata
, G_FILE_MONITOR_EVENT_DELETED
, child
, NULL
, NULL
, now
);
103 g_file_monitor_source_handle_event (ev
.userdata
, G_FILE_MONITOR_EVENT_CREATED
, child
, NULL
, NULL
, now
);
112 g_mutex_unlock (&fam_lock
);
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;
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
);
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
;
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
);
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
);
178 FAMMonitorDirectory (&fam_connection
, dirname
, &gffm
->request
, source
);
180 FAMMonitorFile (&fam_connection
, filename
, &gffm
->request
, source
);
182 g_mutex_unlock (&fam_lock
);
186 g_fam_file_monitor_init (GFamFileMonitor
* monitor
)
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
;
201 g_fam_file_monitor_class_finalize (GFamFileMonitorClass
*class)
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);
220 g_io_module_unload (GIOModule
*module
)
222 g_assert_not_reached ();
226 g_io_module_query (void)
229 G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME
,
230 G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME
,
234 return g_strdupv (eps
);