2008-03-14 09:58:24 +01:00
|
|
|
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
|
|
/* vim:set expandtab ts=4 shiftwidth=4: */
|
|
|
|
/*
|
2008-03-28 10:30:52 +01:00
|
|
|
* Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
|
|
|
|
* Use is subject to license terms.
|
2008-03-14 09:58:24 +01:00
|
|
|
*
|
|
|
|
* 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, write to the
|
|
|
|
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
|
|
* Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* Authors: Lin Ma <lin.ma@sun.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include <glib.h>
|
|
|
|
#include "fen-data.h"
|
|
|
|
#include "fen-helper.h"
|
|
|
|
#include "fen-kernel.h"
|
|
|
|
#ifdef GIO_COMPILATION
|
|
|
|
#include "gfilemonitor.h"
|
|
|
|
#else
|
|
|
|
#include "gam_event.h"
|
|
|
|
#include "gam_server.h"
|
|
|
|
#include "gam_protocol.h"
|
|
|
|
#endif
|
|
|
|
|
2008-03-20 10:40:28 +01:00
|
|
|
#ifdef GIO_COMPILATION
|
2008-04-21 04:40:40 +02:00
|
|
|
#define FH_W if (fh_debug_enabled) g_warning
|
2008-03-14 09:58:24 +01:00
|
|
|
static gboolean fh_debug_enabled = FALSE;
|
2008-03-20 10:40:28 +01:00
|
|
|
#else
|
2008-04-21 04:40:40 +02:00
|
|
|
#include "gam_error.h"
|
|
|
|
#define FH_W(...) GAM_DEBUG(DEBUG_INFO, __VA_ARGS__)
|
2008-03-20 10:40:28 +01:00
|
|
|
#endif
|
2008-03-14 09:58:24 +01:00
|
|
|
|
|
|
|
G_LOCK_EXTERN (fen_lock);
|
|
|
|
|
|
|
|
static void default_emit_event_cb (fdata *f, int events);
|
|
|
|
static void default_emit_once_event_cb (fdata *f, int events, gpointer sub);
|
|
|
|
static int default_event_converter (int event);
|
|
|
|
|
|
|
|
static void
|
|
|
|
scan_children_init (node_t *f, gpointer sub)
|
|
|
|
{
|
|
|
|
GDir *dir;
|
|
|
|
GError *err = NULL;
|
|
|
|
node_op_t op = {NULL, NULL, pre_del_cb, NULL};
|
|
|
|
fdata* pdata;
|
|
|
|
|
|
|
|
FH_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f);
|
|
|
|
pdata = node_get_data (f);
|
|
|
|
|
|
|
|
dir = g_dir_open (NODE_NAME(f), 0, &err);
|
|
|
|
if (dir) {
|
|
|
|
const char *basename;
|
|
|
|
|
|
|
|
while ((basename = g_dir_read_name (dir)))
|
|
|
|
{
|
|
|
|
node_t *childf = NULL;
|
|
|
|
fdata* data;
|
|
|
|
GList *idx;
|
|
|
|
|
|
|
|
childf = children_find (f, basename);
|
|
|
|
if (childf == NULL) {
|
|
|
|
gchar *filename;
|
|
|
|
|
|
|
|
filename = g_build_filename (NODE_NAME(f), basename, NULL);
|
|
|
|
childf = add_node (f, filename);
|
|
|
|
g_assert (childf);
|
|
|
|
g_free (filename);
|
|
|
|
}
|
|
|
|
if ((data = node_get_data (childf)) == NULL) {
|
|
|
|
data = fdata_new (childf, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_monitoring (data)) {
|
|
|
|
/* Ignored */
|
|
|
|
} else if (/* !is_ported (data) && */
|
|
|
|
port_add (&data->fobj, &data->len, data)) {
|
|
|
|
/* Emit created to all other subs */
|
|
|
|
fdata_emit_events (data, FN_EVENT_CREATED);
|
|
|
|
}
|
|
|
|
/* Emit created to the new sub */
|
|
|
|
#ifdef GIO_COMPILATION
|
|
|
|
/* fdata_emit_events_once (data, FN_EVENT_CREATED, sub); */
|
|
|
|
#else
|
|
|
|
gam_server_emit_one_event (NODE_NAME(childf),
|
|
|
|
gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
g_dir_close (dir);
|
|
|
|
} else {
|
|
|
|
FH_W (err->message);
|
|
|
|
g_error_free (err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* fen_add
|
|
|
|
*
|
|
|
|
* Won't hold a ref, we have a timout callback to clean unused fdata.
|
|
|
|
* If there is no value for a key, add it and return it; else return the old
|
|
|
|
* one.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
fen_add (const gchar *filename, gpointer sub, gboolean is_mondir)
|
|
|
|
{
|
|
|
|
node_op_t op = {NULL, add_missing_cb, pre_del_cb, (gpointer)filename};
|
|
|
|
node_t* f;
|
|
|
|
fdata* data;
|
|
|
|
|
|
|
|
g_assert (filename);
|
|
|
|
g_assert (sub);
|
|
|
|
|
|
|
|
G_LOCK (fen_lock);
|
|
|
|
f = find_node_full (filename, &op);
|
|
|
|
FH_W ("[ %s ] f[0x%p] sub[0x%p] %s\n", __func__, f, sub, filename);
|
|
|
|
g_assert (f);
|
|
|
|
data = node_get_data (f);
|
|
|
|
if (data == NULL) {
|
|
|
|
data = fdata_new (f, is_mondir);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_mondir) {
|
|
|
|
data->mon_dir_num ++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Change to active */
|
|
|
|
#ifdef GIO_COMPILATION
|
|
|
|
if (port_add (&data->fobj, &data->len, data) ||
|
|
|
|
g_file_test (FN_NAME(data), G_FILE_TEST_EXISTS)) {
|
|
|
|
if (is_mondir) {
|
|
|
|
scan_children_init (f, sub);
|
|
|
|
}
|
|
|
|
fdata_sub_add (data, sub);
|
|
|
|
} else {
|
|
|
|
fdata_sub_add (data, sub);
|
|
|
|
fdata_adjust_deleted (data);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (port_add (&data->fobj, &data->len, data) ||
|
|
|
|
g_file_test (FN_NAME(data), G_FILE_TEST_EXISTS)) {
|
|
|
|
gam_server_emit_one_event (FN_NAME(data),
|
|
|
|
gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1);
|
|
|
|
if (is_mondir) {
|
|
|
|
scan_children_init (f, sub);
|
|
|
|
}
|
|
|
|
gam_server_emit_one_event (FN_NAME(data),
|
|
|
|
gam_subscription_is_dir (sub), GAMIN_EVENT_ENDEXISTS, sub, 1);
|
|
|
|
fdata_sub_add (data, sub);
|
|
|
|
} else {
|
|
|
|
fdata_sub_add (data, sub);
|
|
|
|
gam_server_emit_one_event (FN_NAME(data),
|
|
|
|
gam_subscription_is_dir (sub), GAMIN_EVENT_DELETED, sub, 1);
|
|
|
|
fdata_adjust_deleted (data);
|
|
|
|
gam_server_emit_one_event (FN_NAME(data),
|
|
|
|
gam_subscription_is_dir (sub), GAMIN_EVENT_ENDEXISTS, sub, 1);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
G_UNLOCK (fen_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fen_remove (const gchar *filename, gpointer sub, gboolean is_mondir)
|
|
|
|
{
|
|
|
|
node_op_t op = {NULL, add_missing_cb, pre_del_cb, (gpointer)filename};
|
|
|
|
node_t* f;
|
|
|
|
fdata* data;
|
|
|
|
|
|
|
|
g_assert (filename);
|
|
|
|
g_assert (sub);
|
|
|
|
|
|
|
|
G_LOCK (fen_lock);
|
|
|
|
f = find_node (filename);
|
|
|
|
FH_W ("[ %s ] f[0x%p] sub[0x%p] %s\n", __func__, f, sub, filename);
|
|
|
|
|
|
|
|
g_assert (f);
|
|
|
|
data = node_get_data (f);
|
|
|
|
g_assert (data);
|
|
|
|
|
|
|
|
if (is_mondir) {
|
|
|
|
data->mon_dir_num --;
|
|
|
|
}
|
|
|
|
fdata_sub_remove (data, sub);
|
|
|
|
if (FN_IS_PASSIVE(data)) {
|
|
|
|
#ifdef GIO_COMPILATION
|
|
|
|
pending_remove_node (f, &op);
|
|
|
|
#else
|
|
|
|
remove_node (f, &op);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
G_UNLOCK (fen_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
fen_init_once_func (gpointer data)
|
|
|
|
{
|
|
|
|
FH_W ("%s\n", __func__);
|
|
|
|
if (!node_class_init ()) {
|
|
|
|
FH_W ("node_class_init failed.");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (!fdata_class_init (default_emit_event_cb,
|
|
|
|
default_emit_once_event_cb,
|
|
|
|
default_event_converter)) {
|
|
|
|
FH_W ("fdata_class_init failed.");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
fen_init ()
|
|
|
|
{
|
|
|
|
#ifdef GIO_COMPILATION
|
|
|
|
static GOnce fen_init_once = G_ONCE_INIT;
|
|
|
|
g_once (&fen_init_once, (GThreadFunc)fen_init_once_func, NULL);
|
|
|
|
return (gboolean)fen_init_once.retval;
|
|
|
|
#else
|
|
|
|
return fen_init_once_func (NULL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
default_emit_once_event_cb (fdata *f, int events, gpointer sub)
|
|
|
|
{
|
|
|
|
#ifdef GIO_COMPILATION
|
|
|
|
GFile* child;
|
|
|
|
fen_sub* _sub = (fen_sub*)sub;
|
|
|
|
child = g_file_new_for_path (FN_NAME(f));
|
|
|
|
g_file_monitor_emit_event (G_FILE_MONITOR (_sub->user_data),
|
|
|
|
child, NULL, events);
|
|
|
|
g_object_unref (child);
|
|
|
|
#else
|
|
|
|
gam_server_emit_one_event (FN_NAME(f),
|
|
|
|
gam_subscription_is_dir (sub), events, sub, 1);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
default_emit_event_cb (fdata *f, int events)
|
|
|
|
{
|
|
|
|
GList* i;
|
|
|
|
fdata* pdata;
|
|
|
|
|
|
|
|
#ifdef GIO_COMPILATION
|
|
|
|
GFile* child;
|
|
|
|
child = g_file_new_for_path (FN_NAME(f));
|
|
|
|
for (i = f->subs; i; i = i->next) {
|
|
|
|
fen_sub* sub = (fen_sub*)i->data;
|
|
|
|
gboolean file_is_dir = sub->is_mondir;
|
|
|
|
if ((events != G_FILE_MONITOR_EVENT_CHANGED &&
|
|
|
|
events != G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED) ||
|
|
|
|
!file_is_dir) {
|
|
|
|
g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
|
|
|
|
child, NULL, events);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((pdata = get_parent_data (f)) != NULL) {
|
|
|
|
for (i = pdata->subs; i; i = i->next) {
|
|
|
|
fen_sub* sub = (fen_sub*)i->data;
|
|
|
|
gboolean file_is_dir = sub->is_mondir;
|
|
|
|
g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
|
|
|
|
child, NULL, events);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_object_unref (child);
|
|
|
|
#else
|
|
|
|
for (i = f->subs; i; i = i->next) {
|
|
|
|
gboolean file_is_dir = gam_subscription_is_dir (i->data);
|
|
|
|
if (events != GAMIN_EVENT_CHANGED || !file_is_dir) {
|
|
|
|
gam_server_emit_one_event (FN_NAME(f), file_is_dir, events, i->data, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((pdata = get_parent_data (f)) != NULL) {
|
|
|
|
for (i = pdata->subs; i; i = i->next) {
|
|
|
|
gboolean file_is_dir = gam_subscription_is_dir (i->data);
|
|
|
|
gam_server_emit_one_event (FN_NAME(f), file_is_dir, events, i->data, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
default_event_converter (int event)
|
|
|
|
{
|
|
|
|
#ifdef GIO_COMPILATION
|
|
|
|
switch (event) {
|
|
|
|
case FN_EVENT_CREATED:
|
|
|
|
return G_FILE_MONITOR_EVENT_CREATED;
|
|
|
|
case FILE_DELETE:
|
|
|
|
case FILE_RENAME_FROM:
|
|
|
|
return G_FILE_MONITOR_EVENT_DELETED;
|
|
|
|
case UNMOUNTED:
|
|
|
|
return G_FILE_MONITOR_EVENT_UNMOUNTED;
|
|
|
|
case FILE_ATTRIB:
|
|
|
|
return G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED;
|
|
|
|
case MOUNTEDOVER:
|
|
|
|
case FILE_MODIFIED:
|
|
|
|
case FILE_RENAME_TO:
|
|
|
|
return G_FILE_MONITOR_EVENT_CHANGED;
|
|
|
|
default:
|
|
|
|
/* case FILE_ACCESS: */
|
|
|
|
g_assert_not_reached ();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
switch (event) {
|
|
|
|
case FN_EVENT_CREATED:
|
|
|
|
return GAMIN_EVENT_CREATED;
|
|
|
|
case FILE_DELETE:
|
|
|
|
case FILE_RENAME_FROM:
|
|
|
|
return GAMIN_EVENT_DELETED;
|
|
|
|
case FILE_ATTRIB:
|
|
|
|
case MOUNTEDOVER:
|
|
|
|
case UNMOUNTED:
|
|
|
|
case FILE_MODIFIED:
|
|
|
|
case FILE_RENAME_TO:
|
|
|
|
return GAMIN_EVENT_CHANGED;
|
|
|
|
default:
|
|
|
|
/* case FILE_ACCESS: */
|
|
|
|
g_assert_not_reached ();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|