|
Packit |
ae235b |
/*
|
|
Packit |
ae235b |
* Copyright © 2015 Canonical Limited
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* This library is free software; you can redistribute it and/or
|
|
Packit |
ae235b |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
ae235b |
* License as published by the Free Software Foundation; either
|
|
Packit |
ae235b |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
ae235b |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
ae235b |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
ae235b |
* Lesser General Public License for more details.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* You should have received a copy of the GNU Lesser General
|
|
Packit |
ae235b |
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* Author: Ryan Lortie <desrt@desrt.ca>
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
#include "config.h"
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
#include <gio/glocalfilemonitor.h>
|
|
Packit |
ae235b |
#include <gio/giomodule.h>
|
|
Packit |
ae235b |
#include "glib-private.h"
|
|
Packit |
ae235b |
#include <glib-unix.h>
|
|
Packit |
ae235b |
#include <fam.h>
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static GMutex fam_lock;
|
|
Packit |
ae235b |
static gboolean fam_initialised;
|
|
Packit |
ae235b |
static FAMConnection fam_connection;
|
|
Packit |
ae235b |
static GSource *fam_source;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
#define G_TYPE_FAM_FILE_MONITOR (g_fam_file_monitor_get_type ())
|
|
Packit |
ae235b |
#define G_FAM_FILE_MONITOR(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
|
|
Packit |
ae235b |
G_TYPE_FAM_FILE_MONITOR, GFamFileMonitor))
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
typedef GLocalFileMonitorClass GFamFileMonitorClass;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
typedef struct
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GLocalFileMonitor parent_instance;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
FAMRequest request;
|
|
Packit |
ae235b |
} GFamFileMonitor;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static GType g_fam_file_monitor_get_type (void);
|
|
Packit |
ae235b |
G_DEFINE_DYNAMIC_TYPE (GFamFileMonitor, g_fam_file_monitor, G_TYPE_LOCAL_FILE_MONITOR)
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_fam_file_monitor_callback (gint fd,
|
|
Packit |
ae235b |
GIOCondition condition,
|
|
Packit |
ae235b |
gpointer user_data)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
gint64 now = g_source_get_time (fam_source);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_lock (&fam_lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
while (FAMPending (&fam_connection))
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
const gchar *child;
|
|
Packit |
ae235b |
FAMEvent ev;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (FAMNextEvent (&fam_connection, &ev) != 1)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
/* The daemon died. We're in a really bad situation now
|
|
Packit |
ae235b |
* because we potentially have a bunch of request structures
|
|
Packit |
ae235b |
* outstanding which no longer make any sense to anyone.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* The best thing that we can do is do nothing. Notification
|
|
Packit |
ae235b |
* won't work anymore for this process.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
g_mutex_unlock (&fam_lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_warning ("Lost connection to FAM (file monitoring) service. Expect no further file monitor events.");
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return FALSE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* We expect ev.filename to be a relative path for children in a
|
|
Packit |
ae235b |
* monitored directory, and an absolute path for a monitored file
|
|
Packit |
ae235b |
* or the directory itself.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
if (ev.filename[0] != '/')
|
|
Packit |
ae235b |
child = ev.filename;
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
child = NULL;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
switch (ev.code)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
case FAMAcknowledge:
|
|
Packit |
ae235b |
g_source_unref (ev.userdata);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
case FAMChanged:
|
|
Packit |
ae235b |
g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CHANGED, child, NULL, NULL, now);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
case FAMDeleted:
|
|
Packit |
ae235b |
g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_DELETED, child, NULL, NULL, now);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
case FAMCreated:
|
|
Packit |
ae235b |
g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CREATED, child, NULL, NULL, now);
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
default:
|
|
Packit |
ae235b |
/* unknown type */
|
|
Packit |
ae235b |
break;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_unlock (&fam_lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return TRUE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_fam_file_monitor_is_supported (void)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_mutex_lock (&fam_lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (!fam_initialised)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
fam_initialised = FAMOpen2 (&fam_connection, "GLib GIO") == 0;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (fam_initialised)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
#ifdef HAVE_FAM_NO_EXISTS
|
|
Packit |
ae235b |
/* This is a gamin extension that avoids sending all the
|
|
Packit |
ae235b |
* Exists event for dir monitors
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
FAMNoExists (&fam_connection);
|
|
Packit |
ae235b |
#endif
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
fam_source = g_unix_fd_source_new (FAMCONNECTION_GETFD (&fam_connection), G_IO_IN);
|
|
Packit |
ae235b |
g_source_set_callback (fam_source, (GSourceFunc) g_fam_file_monitor_callback, NULL, NULL);
|
|
Packit |
ae235b |
g_source_attach (fam_source, GLIB_PRIVATE_CALL(g_get_worker_context) ());
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_unlock (&fam_lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return fam_initialised;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
g_fam_file_monitor_cancel (GFileMonitor *monitor)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GFamFileMonitor *gffm = G_FAM_FILE_MONITOR (monitor);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_lock (&fam_lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_assert (fam_initialised);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
FAMCancelMonitor (&fam_connection, &gffm->request);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_unlock (&fam_lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return TRUE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_fam_file_monitor_start (GLocalFileMonitor *local_monitor,
|
|
Packit |
ae235b |
const gchar *dirname,
|
|
Packit |
ae235b |
const gchar *basename,
|
|
Packit |
ae235b |
const gchar *filename,
|
|
Packit |
ae235b |
GFileMonitorSource *source)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GFamFileMonitor *gffm = G_FAM_FILE_MONITOR (local_monitor);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_lock (&fam_lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_assert (fam_initialised);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_source_ref ((GSource *) source);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (dirname)
|
|
Packit |
ae235b |
FAMMonitorDirectory (&fam_connection, dirname, &gffm->request, source);
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
FAMMonitorFile (&fam_connection, filename, &gffm->request, source);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_mutex_unlock (&fam_lock);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_fam_file_monitor_init (GFamFileMonitor* monitor)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_fam_file_monitor_class_init (GFamFileMonitorClass *class)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (class);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
class->is_supported = g_fam_file_monitor_is_supported;
|
|
Packit |
ae235b |
class->start = g_fam_file_monitor_start;
|
|
Packit |
ae235b |
file_monitor_class->cancel = g_fam_file_monitor_cancel;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static void
|
|
Packit |
ae235b |
g_fam_file_monitor_class_finalize (GFamFileMonitorClass *class)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
void
|
|
Packit |
ae235b |
g_io_module_load (GIOModule *module)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_type_module_use (G_TYPE_MODULE (module));
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_fam_file_monitor_register_type (G_TYPE_MODULE (module));
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
|
|
Packit |
ae235b |
G_TYPE_FAM_FILE_MONITOR, "fam", 10);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_io_extension_point_implement (G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
|
|
Packit |
ae235b |
G_TYPE_FAM_FILE_MONITOR, "fam", 10);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
void
|
|
Packit |
ae235b |
g_io_module_unload (GIOModule *module)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_assert_not_reached ();
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
char **
|
|
Packit |
ae235b |
g_io_module_query (void)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
char *eps[] = {
|
|
Packit |
ae235b |
G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
|
|
Packit |
ae235b |
G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
|
|
Packit |
ae235b |
NULL
|
|
Packit |
ae235b |
};
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return g_strdupv (eps);
|
|
Packit |
ae235b |
}
|