mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
file monitors: rewrite FAM file monitor
Completely rewrite the FAM file monitor. Major changes: - now runs in the worker thread - dispatches events in a threadsafe way via GFileMonitorSource - uses unix fd source instead of a GIOChannel - is now simple enough to fit into one short file
This commit is contained in:
parent
21ab660cf8
commit
d682df186e
@ -5,15 +5,7 @@ module_flags = -export_dynamic -avoid-version -module -no-undefined -export-symb
|
||||
giomodule_LTLIBRARIES = libgiofam.la
|
||||
giomoduledir = $(GIO_MODULE_DIR)
|
||||
|
||||
libgiofam_la_SOURCES = \
|
||||
fam-helper.c \
|
||||
fam-helper.h \
|
||||
fam-module.c \
|
||||
gfamdirectorymonitor.c \
|
||||
gfamdirectorymonitor.h \
|
||||
gfamfilemonitor.c \
|
||||
gfamfilemonitor.h \
|
||||
$(NULL)
|
||||
libgiofam_la_SOURCES = gfamfilemonitor.c
|
||||
|
||||
libgiofam_la_CFLAGS = \
|
||||
-DG_LOG_DOMAIN=\"GLib-GIO\" \
|
||||
|
@ -1,274 +0,0 @@
|
||||
/* GIO - GLib Input, Output and Streaming Library
|
||||
*
|
||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
||||
* John McCutchan <john@johnmccutchan.com>
|
||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <fam.h>
|
||||
#include <gio/gfilemonitor.h>
|
||||
#include <gio/gfile.h>
|
||||
|
||||
#include "fam-helper.h"
|
||||
|
||||
static FAMConnection* fam_connection = NULL;
|
||||
static gint fam_watch_id = 0;
|
||||
G_LOCK_DEFINE_STATIC(fam_connection);
|
||||
|
||||
struct _fam_sub
|
||||
{
|
||||
gchar *pathname;
|
||||
gboolean directory;
|
||||
gpointer user_data;
|
||||
gboolean cancelled;
|
||||
FAMRequest request;
|
||||
};
|
||||
|
||||
/* This uses int as the argument type because the
|
||||
real type differs between implementations:
|
||||
gamin has "typedef enum FAMCodes {....} FAMCodes;"
|
||||
fam has "enum FAMCodes { ... }".
|
||||
*/
|
||||
static GFileMonitorEvent
|
||||
fam_event_to_file_monitor_event (int code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case FAMChanged:
|
||||
return G_FILE_MONITOR_EVENT_CHANGED;
|
||||
break;
|
||||
case FAMDeleted:
|
||||
return G_FILE_MONITOR_EVENT_DELETED;
|
||||
break;
|
||||
case FAMCreated:
|
||||
return G_FILE_MONITOR_EVENT_CREATED;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fam_do_iter_unlocked (void)
|
||||
{
|
||||
while (fam_connection != NULL && FAMPending (fam_connection))
|
||||
{
|
||||
FAMEvent ev;
|
||||
fam_sub* sub = NULL;
|
||||
gboolean cancelled;
|
||||
|
||||
if (FAMNextEvent (fam_connection, &ev) != 1)
|
||||
{
|
||||
FAMClose (fam_connection);
|
||||
g_free (fam_connection);
|
||||
g_source_remove (fam_watch_id);
|
||||
fam_watch_id = 0;
|
||||
fam_connection = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sub = (fam_sub*)ev.userdata;
|
||||
cancelled = sub->cancelled;
|
||||
if (ev.code == FAMAcknowledge && cancelled)
|
||||
{
|
||||
_fam_sub_free (sub);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cancelled)
|
||||
continue;
|
||||
|
||||
if (sub->directory)
|
||||
{
|
||||
GFileMonitor* monitor = G_FILE_MONITOR (sub->user_data);
|
||||
GFileMonitorEvent eflags = fam_event_to_file_monitor_event (ev.code);
|
||||
gchar* path = NULL;
|
||||
GFile *child, *parent;
|
||||
|
||||
/* unsupported event */
|
||||
if (eflags == -1)
|
||||
continue;
|
||||
|
||||
if (ev.filename[0] == '/')
|
||||
path = g_strdup (ev.filename);
|
||||
else
|
||||
path = g_strdup_printf ("%s/%s", sub->pathname, ev.filename);
|
||||
|
||||
child = g_file_new_for_path (path);
|
||||
parent = g_file_get_parent (child);
|
||||
g_file_monitor_emit_event (monitor, child, NULL, eflags);
|
||||
g_free (path);
|
||||
g_object_unref (child);
|
||||
g_object_unref (parent);
|
||||
}
|
||||
else
|
||||
{
|
||||
GFile *child;
|
||||
GFileMonitor* monitor = G_FILE_MONITOR (sub->user_data);
|
||||
GFileMonitorEvent eflags = fam_event_to_file_monitor_event (ev.code);
|
||||
gchar* path = NULL;
|
||||
|
||||
if (eflags == -1)
|
||||
continue;
|
||||
path = g_strdup (ev.filename);
|
||||
child = g_file_new_for_path (path);
|
||||
g_file_monitor_emit_event (monitor, child, NULL, eflags);
|
||||
g_free (path);
|
||||
g_object_unref (child);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fam_callback (GIOChannel *source,
|
||||
GIOCondition condition,
|
||||
gpointer data)
|
||||
{
|
||||
gboolean res;
|
||||
G_LOCK (fam_connection);
|
||||
|
||||
res = fam_do_iter_unlocked ();
|
||||
|
||||
G_UNLOCK (fam_connection);
|
||||
return res;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_fam_sub_startup (void)
|
||||
{
|
||||
GIOChannel *ioc;
|
||||
|
||||
G_LOCK (fam_connection);
|
||||
|
||||
if (fam_connection == NULL)
|
||||
{
|
||||
fam_connection = g_new0 (FAMConnection, 1);
|
||||
if (FAMOpen2 (fam_connection, "gvfs user") != 0)
|
||||
{
|
||||
g_warning ("FAMOpen failed, FAMErrno=%d\n", FAMErrno);
|
||||
g_free (fam_connection);
|
||||
fam_connection = NULL;
|
||||
G_UNLOCK (fam_connection);
|
||||
return FALSE;
|
||||
}
|
||||
#ifdef HAVE_FAM_NO_EXISTS
|
||||
/* This is a gamin extension that avoids sending all the Exists event for dir monitors */
|
||||
FAMNoExists (fam_connection);
|
||||
#endif
|
||||
ioc = g_io_channel_unix_new (FAMCONNECTION_GETFD(fam_connection));
|
||||
fam_watch_id = g_io_add_watch (ioc,
|
||||
G_IO_IN | G_IO_HUP | G_IO_ERR,
|
||||
fam_callback, fam_connection);
|
||||
g_io_channel_unref (ioc);
|
||||
}
|
||||
|
||||
G_UNLOCK (fam_connection);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_fam_sub_shutdown (void)
|
||||
{
|
||||
G_LOCK (fam_connection);
|
||||
|
||||
if (fam_connection != NULL)
|
||||
{
|
||||
FAMClose (fam_connection);
|
||||
g_free (fam_connection);
|
||||
g_source_remove (fam_watch_id);
|
||||
fam_watch_id = 0;
|
||||
fam_connection = NULL;
|
||||
}
|
||||
|
||||
G_UNLOCK (fam_connection);
|
||||
}
|
||||
|
||||
fam_sub*
|
||||
_fam_sub_add (const gchar *pathname,
|
||||
gboolean directory,
|
||||
gpointer user_data)
|
||||
{
|
||||
fam_sub *sub;
|
||||
|
||||
if (!_fam_sub_startup ())
|
||||
return NULL;
|
||||
|
||||
G_LOCK (fam_connection);
|
||||
/* We need to queue up incoming messages to avoid blocking on write
|
||||
* if there are many monitors being canceled */
|
||||
fam_do_iter_unlocked ();
|
||||
|
||||
if (fam_connection == NULL)
|
||||
{
|
||||
G_UNLOCK (fam_connection);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sub = g_new0 (fam_sub, 1);
|
||||
sub->pathname = g_strdup (pathname);
|
||||
sub->directory = directory;
|
||||
sub->user_data = user_data;
|
||||
|
||||
if (directory)
|
||||
FAMMonitorDirectory (fam_connection, pathname, &sub->request, sub);
|
||||
else
|
||||
FAMMonitorFile (fam_connection, pathname, &sub->request, sub);
|
||||
|
||||
G_UNLOCK (fam_connection);
|
||||
|
||||
return sub;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_fam_sub_cancel (fam_sub* sub)
|
||||
{
|
||||
if (sub->cancelled)
|
||||
return TRUE;
|
||||
|
||||
sub->cancelled = TRUE;
|
||||
|
||||
G_LOCK (fam_connection);
|
||||
/* We need to queue up incoming messages to avoid blocking on write
|
||||
* if there are many monitors being canceled */
|
||||
fam_do_iter_unlocked ();
|
||||
|
||||
if (fam_connection == NULL)
|
||||
{
|
||||
G_UNLOCK (fam_connection);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
FAMCancelMonitor (fam_connection, &sub->request);
|
||||
|
||||
G_UNLOCK (fam_connection);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_fam_sub_free (fam_sub* sub)
|
||||
{
|
||||
g_free (sub->pathname);
|
||||
g_free (sub);
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
/* GIO - GLib Input, Output and Streaming Library
|
||||
*
|
||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
||||
* John McCutchan <john@johnmccutchan.com>
|
||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
||||
*/
|
||||
|
||||
#ifndef __FAM_HELPER_H__
|
||||
#define __FAM_HELPER_H__
|
||||
|
||||
typedef struct _fam_sub fam_sub;
|
||||
|
||||
gboolean _fam_sub_startup (void);
|
||||
void _fam_sub_shutdown (void);
|
||||
fam_sub* _fam_sub_add (const gchar* pathname,
|
||||
gboolean directory,
|
||||
gpointer user_data);
|
||||
gboolean _fam_sub_cancel (fam_sub* sub);
|
||||
void _fam_sub_free (fam_sub* sub);
|
||||
|
||||
#endif /* __FAM_HELPER_H__ */
|
@ -1,54 +0,0 @@
|
||||
/* GIO - GLib Input, Output and Streaming Library
|
||||
*
|
||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
||||
* Copyright (C) 2007 Sebastian Dröge.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
||||
* John McCutchan <john@johnmccutchan.com>
|
||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
||||
*/
|
||||
|
||||
#include <gio/giomodule.h>
|
||||
#include "gfamdirectorymonitor.h"
|
||||
#include "gfamfilemonitor.h"
|
||||
#include "fam-helper.h"
|
||||
|
||||
void
|
||||
g_io_module_load (GIOModule *module)
|
||||
{
|
||||
g_fam_file_monitor_register (module);
|
||||
g_fam_directory_monitor_register (module);
|
||||
}
|
||||
|
||||
void
|
||||
g_io_module_unload (GIOModule *module)
|
||||
{
|
||||
_fam_sub_shutdown ();
|
||||
}
|
||||
|
||||
char **
|
||||
g_io_module_query (void)
|
||||
{
|
||||
char *eps[] = {
|
||||
G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME,
|
||||
G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
|
||||
G_NFS_DIRECTORY_MONITOR_EXTENSION_POINT_NAME,
|
||||
G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
|
||||
NULL
|
||||
};
|
||||
return g_strdupv (eps);
|
||||
}
|
||||
|
@ -1,155 +0,0 @@
|
||||
/* GIO - GLib Input, Output and Streaming Library
|
||||
*
|
||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
||||
* Copyright (C) 2007 Sebastian Dröge.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
||||
* John McCutchan <john@johnmccutchan.com>
|
||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gfamdirectorymonitor.h"
|
||||
#include <gio/giomodule.h>
|
||||
|
||||
#include "fam-helper.h"
|
||||
|
||||
struct _GFamDirectoryMonitor
|
||||
{
|
||||
GLocalDirectoryMonitor parent_instance;
|
||||
fam_sub *sub;
|
||||
};
|
||||
|
||||
static gboolean g_fam_directory_monitor_cancel (GFileMonitor* monitor);
|
||||
|
||||
G_DEFINE_DYNAMIC_TYPE (GFamDirectoryMonitor, g_fam_directory_monitor, G_TYPE_LOCAL_DIRECTORY_MONITOR)
|
||||
|
||||
static void
|
||||
g_fam_directory_monitor_finalize (GObject *object)
|
||||
{
|
||||
GFamDirectoryMonitor *fam_monitor = G_FAM_DIRECTORY_MONITOR (object);
|
||||
fam_sub *sub = fam_monitor->sub;
|
||||
|
||||
if (sub) {
|
||||
if (!_fam_sub_cancel (sub))
|
||||
g_warning ("Unexpected error cancelling fam monitor");
|
||||
|
||||
fam_monitor->sub = NULL;
|
||||
}
|
||||
|
||||
if (G_OBJECT_CLASS (g_fam_directory_monitor_parent_class)->finalize)
|
||||
(*G_OBJECT_CLASS (g_fam_directory_monitor_parent_class)->finalize) (object);
|
||||
}
|
||||
|
||||
static GObject *
|
||||
g_fam_directory_monitor_constructor (GType type,
|
||||
guint n_construct_properties,
|
||||
GObjectConstructParam *construct_properties)
|
||||
{
|
||||
GObject *obj;
|
||||
GFamDirectoryMonitorClass *klass;
|
||||
GObjectClass *parent_class;
|
||||
GFamDirectoryMonitor *fam_monitor;
|
||||
const gchar *dirname = NULL;
|
||||
fam_sub *sub = NULL;
|
||||
|
||||
klass = G_FAM_DIRECTORY_MONITOR_CLASS (g_type_class_peek (G_TYPE_FAM_DIRECTORY_MONITOR));
|
||||
parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
|
||||
obj = parent_class->constructor (type,
|
||||
n_construct_properties,
|
||||
construct_properties);
|
||||
|
||||
fam_monitor = G_FAM_DIRECTORY_MONITOR (obj);
|
||||
|
||||
dirname = G_LOCAL_DIRECTORY_MONITOR (obj)->dirname;
|
||||
g_assert (dirname != NULL);
|
||||
|
||||
sub = _fam_sub_add (dirname, TRUE, fam_monitor);
|
||||
/* FIXME: what to do about errors here? we can't return NULL or another
|
||||
* kind of error and an assertion is probably too hard */
|
||||
g_assert (sub != NULL);
|
||||
|
||||
fam_monitor->sub = sub;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void
|
||||
g_fam_directory_monitor_class_finalize (GFamDirectoryMonitorClass *klass)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
g_fam_directory_monitor_is_supported (void)
|
||||
{
|
||||
return _fam_sub_startup ();
|
||||
}
|
||||
|
||||
static void
|
||||
g_fam_directory_monitor_class_init (GFamDirectoryMonitorClass* klass)
|
||||
{
|
||||
GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
|
||||
GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (klass);
|
||||
GLocalDirectoryMonitorClass *local_directory_monitor_class = G_LOCAL_DIRECTORY_MONITOR_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = g_fam_directory_monitor_finalize;
|
||||
gobject_class->constructor = g_fam_directory_monitor_constructor;
|
||||
file_monitor_class->cancel = g_fam_directory_monitor_cancel;
|
||||
|
||||
local_directory_monitor_class->mount_notify = FALSE;
|
||||
local_directory_monitor_class->is_supported = g_fam_directory_monitor_is_supported;
|
||||
}
|
||||
|
||||
static void
|
||||
g_fam_directory_monitor_init (GFamDirectoryMonitor* monitor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
g_fam_directory_monitor_cancel (GFileMonitor* monitor)
|
||||
{
|
||||
GFamDirectoryMonitor *fam_monitor = G_FAM_DIRECTORY_MONITOR (monitor);
|
||||
fam_sub *sub = fam_monitor->sub;
|
||||
|
||||
if (sub) {
|
||||
if (!_fam_sub_cancel (sub))
|
||||
g_warning ("Unexpected error cancelling fam monitor");
|
||||
|
||||
fam_monitor->sub = NULL;
|
||||
}
|
||||
|
||||
if (G_FILE_MONITOR_CLASS (g_fam_directory_monitor_parent_class)->cancel)
|
||||
(*G_FILE_MONITOR_CLASS (g_fam_directory_monitor_parent_class)->cancel) (monitor);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
g_fam_directory_monitor_register (GIOModule *module)
|
||||
{
|
||||
g_fam_directory_monitor_register_type (G_TYPE_MODULE (module));
|
||||
g_io_extension_point_implement (G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME,
|
||||
G_TYPE_FAM_DIRECTORY_MONITOR,
|
||||
"fam",
|
||||
10);
|
||||
g_io_extension_point_implement (G_NFS_DIRECTORY_MONITOR_EXTENSION_POINT_NAME,
|
||||
G_TYPE_FAM_DIRECTORY_MONITOR,
|
||||
"fam",
|
||||
10);
|
||||
}
|
||||
|
@ -1,52 +0,0 @@
|
||||
/* GIO - GLib Input, Output and Streaming Library
|
||||
*
|
||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
||||
* Copyright (C) 2007 Sebastian Dröge.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
||||
* John McCutchan <john@johnmccutchan.com>
|
||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
||||
*/
|
||||
|
||||
#ifndef __G_FAM_DIRECTORY_MONITOR_H__
|
||||
#define __G_FAM_DIRECTORY_MONITOR_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <string.h>
|
||||
#include <gio/glocaldirectorymonitor.h>
|
||||
#include <gio/giomodule.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_FAM_DIRECTORY_MONITOR (g_fam_directory_monitor_get_type ())
|
||||
#define G_FAM_DIRECTORY_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_FAM_DIRECTORY_MONITOR, GFamDirectoryMonitor))
|
||||
#define G_FAM_DIRECTORY_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), G_TYPE_FAM_DIRECTORY_MONITOR, GFamDirectoryMonitorClass))
|
||||
#define G_IS_FAM_DIRECTORY_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_FAM_DIRECTORY_MONITOR))
|
||||
#define G_IS_FAM_DIRECTORY_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FAM_DIRECTORY_MONITOR))
|
||||
|
||||
typedef struct _GFamDirectoryMonitor GFamDirectoryMonitor;
|
||||
typedef struct _GFamDirectoryMonitorClass GFamDirectoryMonitorClass;
|
||||
|
||||
struct _GFamDirectoryMonitorClass {
|
||||
GLocalDirectoryMonitorClass parent_class;
|
||||
};
|
||||
|
||||
GType g_fam_directory_monitor_get_type (void);
|
||||
void g_fam_directory_monitor_register (GIOModule *module);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_FAM_DIRECTORY_MONITOR_H__ */
|
@ -1,7 +1,5 @@
|
||||
/* GIO - GLib Input, Output and Streaming Library
|
||||
*
|
||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
||||
* Copyright (C) 2007 Sebastian Dröge.
|
||||
/*
|
||||
* Copyright © 2015 Canonical Limited
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -16,138 +14,224 @@
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
||||
* John McCutchan <john@johnmccutchan.com>
|
||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
||||
* Author: Ryan Lortie <desrt@desrt.ca>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gfamfilemonitor.h"
|
||||
#include <gio/glocalfilemonitor.h>
|
||||
#include <gio/giomodule.h>
|
||||
#include "glib-private.h"
|
||||
#include <glib-unix.h>
|
||||
#include <fam.h>
|
||||
|
||||
#include "fam-helper.h"
|
||||
static GMutex fam_lock;
|
||||
static gboolean fam_initialised;
|
||||
static FAMConnection fam_connection;
|
||||
static GSource *fam_source;
|
||||
|
||||
struct _GFamFileMonitor
|
||||
#define G_TYPE_FAM_FILE_MONITOR (g_fam_file_monitor_get_type ())
|
||||
#define G_FAM_FILE_MONITOR(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
|
||||
G_TYPE_FAM_FILE_MONITOR, GFamFileMonitor))
|
||||
|
||||
typedef GLocalFileMonitorClass GFamFileMonitorClass;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GLocalFileMonitor parent_instance;
|
||||
fam_sub *sub;
|
||||
};
|
||||
|
||||
static gboolean g_fam_file_monitor_cancel (GFileMonitor* monitor);
|
||||
FAMRequest request;
|
||||
} GFamFileMonitor;
|
||||
|
||||
static GType g_fam_file_monitor_get_type (void);
|
||||
G_DEFINE_DYNAMIC_TYPE (GFamFileMonitor, g_fam_file_monitor, G_TYPE_LOCAL_FILE_MONITOR)
|
||||
|
||||
static void
|
||||
g_fam_file_monitor_finalize (GObject *object)
|
||||
static gboolean
|
||||
g_fam_file_monitor_callback (gint fd,
|
||||
GIOCondition condition,
|
||||
gpointer user_data)
|
||||
{
|
||||
GFamFileMonitor *fam_monitor = G_FAM_FILE_MONITOR (object);
|
||||
fam_sub *sub = fam_monitor->sub;
|
||||
gint64 now = g_source_get_time (fam_source);
|
||||
|
||||
if (sub) {
|
||||
if (!_fam_sub_cancel (sub))
|
||||
g_warning ("Unexpected error cancelling fam monitor");
|
||||
fam_monitor->sub = NULL;
|
||||
}
|
||||
g_mutex_lock (&fam_lock);
|
||||
|
||||
if (G_OBJECT_CLASS (g_fam_file_monitor_parent_class)->finalize)
|
||||
(*G_OBJECT_CLASS (g_fam_file_monitor_parent_class)->finalize) (object);
|
||||
}
|
||||
while (FAMPending (&fam_connection))
|
||||
{
|
||||
const gchar *child;
|
||||
FAMEvent ev;
|
||||
|
||||
static GObject *
|
||||
g_fam_file_monitor_constructor (GType type,
|
||||
guint n_construct_properties,
|
||||
GObjectConstructParam *construct_properties)
|
||||
{
|
||||
GObject *obj;
|
||||
GFamFileMonitorClass *klass;
|
||||
GObjectClass *parent_class;
|
||||
GFamFileMonitor *fam_monitor;
|
||||
const gchar *filename = NULL;
|
||||
fam_sub *sub = NULL;
|
||||
|
||||
klass = G_FAM_FILE_MONITOR_CLASS (g_type_class_peek (G_TYPE_FAM_FILE_MONITOR));
|
||||
parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
|
||||
obj = parent_class->constructor (type,
|
||||
n_construct_properties,
|
||||
construct_properties);
|
||||
if (FAMNextEvent (&fam_connection, &ev) != 1)
|
||||
{
|
||||
/* The daemon died. We're in a really bad situation now
|
||||
* because we potentially have a bunch of request structures
|
||||
* outstanding which no longer make any sense to anyone.
|
||||
*
|
||||
* The best thing that we can do is do nothing. Notification
|
||||
* won't work anymore for this process.
|
||||
*/
|
||||
g_mutex_unlock (&fam_lock);
|
||||
|
||||
fam_monitor = G_FAM_FILE_MONITOR (obj);
|
||||
g_warning ("Lost connection to FAM (file monitoring) service. Expect no further file monitor events.");
|
||||
|
||||
filename = G_LOCAL_FILE_MONITOR (obj)->filename;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_assert (filename != NULL);
|
||||
/* We expect ev.filename to be a relative path for children in a
|
||||
* monitored directory, and an absolute path for a monitored file
|
||||
* or the directory itself.
|
||||
*/
|
||||
if (ev.filename[0] != '/')
|
||||
child = ev.filename;
|
||||
else
|
||||
child = NULL;
|
||||
|
||||
sub = _fam_sub_add (filename, FALSE, fam_monitor);
|
||||
/* FIXME: what to do about errors here? we can't return NULL or another
|
||||
* kind of error and an assertion is probably too hard */
|
||||
g_assert (sub != NULL);
|
||||
switch (ev.code)
|
||||
{
|
||||
case FAMAcknowledge:
|
||||
g_source_unref (ev.userdata);
|
||||
break;
|
||||
|
||||
fam_monitor->sub = sub;
|
||||
case FAMChanged:
|
||||
g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CHANGED, child, NULL, NULL, now);
|
||||
break;
|
||||
|
||||
return obj;
|
||||
}
|
||||
case FAMDeleted:
|
||||
g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_DELETED, child, NULL, NULL, now);
|
||||
break;
|
||||
|
||||
static void
|
||||
g_fam_file_monitor_class_finalize (GFamFileMonitorClass *klass)
|
||||
{
|
||||
case FAMCreated:
|
||||
g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CREATED, child, NULL, NULL, now);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* unknown type */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_mutex_unlock (&fam_lock);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
g_fam_file_monitor_is_supported (void)
|
||||
{
|
||||
return _fam_sub_startup ();
|
||||
g_mutex_lock (&fam_lock);
|
||||
|
||||
if (!fam_initialised)
|
||||
{
|
||||
fam_initialised = FAMOpen2 (&fam_connection, "GLib GIO") == 0;
|
||||
|
||||
if (fam_initialised)
|
||||
{
|
||||
#ifdef HAVE_FAM_NO_EXISTS
|
||||
/* This is a gamin extension that avoids sending all the
|
||||
* Exists event for dir monitors
|
||||
*/
|
||||
FAMNoExists (&fam_connection);
|
||||
#endif
|
||||
|
||||
fam_source = g_unix_fd_source_new (FAMCONNECTION_GETFD (&fam_connection), G_IO_IN);
|
||||
g_source_set_callback (fam_source, (GSourceFunc) g_fam_file_monitor_callback, NULL, NULL);
|
||||
g_source_attach (fam_source, GLIB_PRIVATE_CALL(g_get_worker_context) ());
|
||||
}
|
||||
}
|
||||
|
||||
g_mutex_unlock (&fam_lock);
|
||||
|
||||
g_print ("II %d\n", fam_initialised);
|
||||
|
||||
return fam_initialised;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
g_fam_file_monitor_cancel (GFileMonitor *monitor)
|
||||
{
|
||||
GFamFileMonitor *gffm = G_FAM_FILE_MONITOR (monitor);
|
||||
|
||||
g_mutex_lock (&fam_lock);
|
||||
|
||||
g_assert (fam_initialised);
|
||||
|
||||
FAMCancelMonitor (&fam_connection, &gffm->request);
|
||||
|
||||
g_mutex_unlock (&fam_lock);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
g_fam_file_monitor_class_init (GFamFileMonitorClass* klass)
|
||||
g_fam_file_monitor_start (GLocalFileMonitor *local_monitor,
|
||||
const gchar *dirname,
|
||||
const gchar *basename,
|
||||
const gchar *filename,
|
||||
GFileMonitorSource *source)
|
||||
{
|
||||
GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
|
||||
GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (klass);
|
||||
GLocalFileMonitorClass *local_file_monitor_class = G_LOCAL_FILE_MONITOR_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = g_fam_file_monitor_finalize;
|
||||
gobject_class->constructor = g_fam_file_monitor_constructor;
|
||||
file_monitor_class->cancel = g_fam_file_monitor_cancel;
|
||||
GFamFileMonitor *gffm = G_FAM_FILE_MONITOR (local_monitor);
|
||||
|
||||
local_file_monitor_class->is_supported = g_fam_file_monitor_is_supported;
|
||||
g_mutex_lock (&fam_lock);
|
||||
|
||||
g_assert (fam_initialised);
|
||||
|
||||
g_source_ref ((GSource *) source);
|
||||
|
||||
if (dirname)
|
||||
FAMMonitorDirectory (&fam_connection, dirname, &gffm->request, source);
|
||||
else
|
||||
FAMMonitorFile (&fam_connection, filename, &gffm->request, source);
|
||||
|
||||
g_mutex_unlock (&fam_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
g_fam_file_monitor_init (GFamFileMonitor* monitor)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static gboolean
|
||||
g_fam_file_monitor_cancel (GFileMonitor* monitor)
|
||||
static void
|
||||
g_fam_file_monitor_class_init (GFamFileMonitorClass *class)
|
||||
{
|
||||
GFamFileMonitor *fam_monitor = G_FAM_FILE_MONITOR (monitor);
|
||||
fam_sub *sub = fam_monitor->sub;
|
||||
GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (class);
|
||||
|
||||
if (sub) {
|
||||
if (!_fam_sub_cancel (sub))
|
||||
g_warning ("Unexpected error cancelling fam monitor");
|
||||
fam_monitor->sub = NULL;
|
||||
}
|
||||
class->is_supported = g_fam_file_monitor_is_supported;
|
||||
class->start = g_fam_file_monitor_start;
|
||||
file_monitor_class->cancel = g_fam_file_monitor_cancel;
|
||||
}
|
||||
|
||||
if (G_FILE_MONITOR_CLASS (g_fam_file_monitor_parent_class)->cancel)
|
||||
(*G_FILE_MONITOR_CLASS (g_fam_file_monitor_parent_class)->cancel) (monitor);
|
||||
|
||||
return TRUE;
|
||||
static void
|
||||
g_fam_file_monitor_class_finalize (GFamFileMonitorClass *class)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
g_fam_file_monitor_register (GIOModule *module)
|
||||
g_io_module_load (GIOModule *module)
|
||||
{
|
||||
g_type_module_use (G_TYPE_MODULE (module));
|
||||
|
||||
g_fam_file_monitor_register_type (G_TYPE_MODULE (module));
|
||||
|
||||
g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
|
||||
G_TYPE_FAM_FILE_MONITOR,
|
||||
"fam",
|
||||
10);
|
||||
G_TYPE_FAM_FILE_MONITOR, "fam", 10);
|
||||
|
||||
g_io_extension_point_implement (G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
|
||||
G_TYPE_FAM_FILE_MONITOR,
|
||||
"fam",
|
||||
10);
|
||||
G_TYPE_FAM_FILE_MONITOR, "fam", 10);
|
||||
}
|
||||
|
||||
void
|
||||
g_io_module_unload (GIOModule *module)
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
char **
|
||||
g_io_module_query (void)
|
||||
{
|
||||
char *eps[] = {
|
||||
G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
|
||||
G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
|
||||
NULL
|
||||
};
|
||||
|
||||
return g_strdupv (eps);
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
/* GIO - GLib Input, Output and Streaming Library
|
||||
*
|
||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
||||
* Copyright (C) 2007 Sebastian Dröge.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General
|
||||
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Alexander Larsson <alexl@redhat.com>
|
||||
* John McCutchan <john@johnmccutchan.com>
|
||||
* Sebastian Dröge <slomo@circular-chaos.org>
|
||||
*/
|
||||
|
||||
#ifndef __G_FAM_FILE_MONITOR_H__
|
||||
#define __G_FAM_FILE_MONITOR_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <string.h>
|
||||
#include <gio/gfilemonitor.h>
|
||||
#include <gio/glocalfilemonitor.h>
|
||||
#include <gio/giomodule.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define G_TYPE_FAM_FILE_MONITOR (g_fam_file_monitor_get_type ())
|
||||
#define G_FAM_FILE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_FAM_FILE_MONITOR, GFamFileMonitor))
|
||||
#define G_FAM_FILE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), G_TYPE_FAM_FILE_MONITOR, GFamFileMonitorClass))
|
||||
#define G_IS_FAM_FILE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_FAM_FILE_MONITOR))
|
||||
#define G_IS_FAM_FILE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FAM_FILE_MONITOR))
|
||||
|
||||
typedef struct _GFamFileMonitor GFamFileMonitor;
|
||||
typedef struct _GFamFileMonitorClass GFamFileMonitorClass;
|
||||
|
||||
struct _GFamFileMonitorClass {
|
||||
GLocalFileMonitorClass parent_class;
|
||||
};
|
||||
|
||||
GType g_fam_file_monitor_get_type (void);
|
||||
void g_fam_file_monitor_register (GIOModule *module);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_FAM_FILE_MONITOR_H__ */
|
Loading…
Reference in New Issue
Block a user