Home | History | Annotate | Download | only in fen
      1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
      2 /* vim:set expandtab ts=4 shiftwidth=4: */
      3 /*
      4  * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
      5  * Use is subject to license terms.
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Lesser General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Lesser General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Lesser General
     18  * Public License along with this library; if not, write to the
     19  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
     20  * Boston, MA 02111-1307, USA.
     21  *
     22  * Authors: Lin Ma <lin.ma (at) sun.com>
     23  */
     24 
     25 #include "config.h"
     26 #include <glib.h>
     27 #include "fen-data.h"
     28 #include "fen-helper.h"
     29 #include "fen-kernel.h"
     30 #ifdef GIO_COMPILATION
     31 #include "gfilemonitor.h"
     32 #else
     33 #include "gam_event.h"
     34 #include "gam_server.h"
     35 #include "gam_protocol.h"
     36 #endif
     37 
     38 #ifdef GIO_COMPILATION
     39 #define FH_W if (fh_debug_enabled) g_warning
     40 static gboolean fh_debug_enabled = FALSE;
     41 #else
     42 #include "gam_error.h"
     43 #define FH_W(...) GAM_DEBUG(DEBUG_INFO, __VA_ARGS__)
     44 #endif
     45 
     46 G_LOCK_EXTERN (fen_lock);
     47 
     48 static void default_emit_event_cb (fdata *f, int events);
     49 static void default_emit_once_event_cb (fdata *f, int events, gpointer sub);
     50 static int default_event_converter (int event);
     51 
     52 static void
     53 scan_children_init (node_t *f, gpointer sub)
     54 {
     55 	GDir *dir;
     56 	GError *err = NULL;
     57     node_op_t op = {NULL, NULL, pre_del_cb, NULL};
     58     fdata* pdata;
     59 
     60     FH_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f);
     61     pdata = node_get_data (f);
     62 
     63     dir = g_dir_open (NODE_NAME(f), 0, &err);
     64     if (dir) {
     65         const char *basename;
     66 
     67         while ((basename = g_dir_read_name (dir)))
     68         {
     69             node_t *childf = NULL;
     70             fdata* data;
     71             GList *idx;
     72 
     73             childf = children_find (f, basename);
     74             if (childf == NULL) {
     75                 gchar *filename;
     76 
     77                 filename = g_build_filename (NODE_NAME(f), basename, NULL);
     78                 childf = add_node (f, filename);
     79                 g_assert (childf);
     80                 g_free (filename);
     81             }
     82             if ((data = node_get_data (childf)) == NULL) {
     83                 data = fdata_new (childf, FALSE);
     84             }
     85 
     86             if (is_monitoring (data)) {
     87                 /* Ignored */
     88             } else if (/* !is_ported (data) && */
     89                 port_add (&data->fobj, &data->len, data)) {
     90                 /* Emit created to all other subs */
     91                 fdata_emit_events (data, FN_EVENT_CREATED);
     92             }
     93             /* Emit created to the new sub */
     94 #ifdef GIO_COMPILATION
     95             /* fdata_emit_events_once (data, FN_EVENT_CREATED, sub); */
     96 #else
     97             gam_server_emit_one_event (NODE_NAME(childf),
     98               gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1);
     99 #endif
    100         }
    101         g_dir_close (dir);
    102     } else {
    103         FH_W (err->message);
    104         g_error_free (err);
    105     }
    106 }
    107 
    108 /**
    109  * fen_add
    110  *
    111  * Won't hold a ref, we have a timout callback to clean unused fdata.
    112  * If there is no value for a key, add it and return it; else return the old
    113  * one.
    114  */
    115 void
    116 fen_add (const gchar *filename, gpointer sub, gboolean is_mondir)
    117 {
    118     node_op_t op = {NULL, add_missing_cb, pre_del_cb, (gpointer)filename};
    119 	node_t* f;
    120     fdata* data;
    121 
    122     g_assert (filename);
    123     g_assert (sub);
    124 
    125     G_LOCK (fen_lock);
    126 	f = find_node_full (filename, &op);
    127     FH_W ("[ %s ] f[0x%p] sub[0x%p] %s\n", __func__, f, sub, filename);
    128     g_assert (f);
    129     data = node_get_data (f);
    130     if (data == NULL) {
    131         data = fdata_new (f, is_mondir);
    132     }
    133 
    134     if (is_mondir) {
    135         data->mon_dir_num ++;
    136     }
    137 
    138     /* Change to active */
    139 #ifdef GIO_COMPILATION
    140     if (port_add (&data->fobj, &data->len, data) ||
    141       g_file_test (FN_NAME(data), G_FILE_TEST_EXISTS)) {
    142         if (is_mondir) {
    143             scan_children_init (f, sub);
    144         }
    145         fdata_sub_add (data, sub);
    146     } else {
    147         fdata_sub_add (data, sub);
    148         fdata_adjust_deleted (data);
    149     }
    150 #else
    151     if (port_add (&data->fobj, &data->len, data) ||
    152       g_file_test (FN_NAME(data), G_FILE_TEST_EXISTS)) {
    153         gam_server_emit_one_event (FN_NAME(data),
    154           gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1);
    155         if (is_mondir) {
    156             scan_children_init (f, sub);
    157         }
    158         gam_server_emit_one_event (FN_NAME(data),
    159           gam_subscription_is_dir (sub), GAMIN_EVENT_ENDEXISTS, sub, 1);
    160         fdata_sub_add (data, sub);
    161     } else {
    162         fdata_sub_add (data, sub);
    163         gam_server_emit_one_event (FN_NAME(data),
    164           gam_subscription_is_dir (sub), GAMIN_EVENT_DELETED, sub, 1);
    165         fdata_adjust_deleted (data);
    166         gam_server_emit_one_event (FN_NAME(data),
    167           gam_subscription_is_dir (sub), GAMIN_EVENT_ENDEXISTS, sub, 1);
    168     }
    169 #endif
    170     G_UNLOCK (fen_lock);
    171 }
    172 
    173 void
    174 fen_remove (const gchar *filename, gpointer sub, gboolean is_mondir)
    175 {
    176     node_op_t op = {NULL, add_missing_cb, pre_del_cb, (gpointer)filename};
    177     node_t* f;
    178     fdata* data;
    179 
    180     g_assert (filename);
    181     g_assert (sub);
    182 
    183     G_LOCK (fen_lock);
    184 	f = find_node (filename);
    185     FH_W ("[ %s ] f[0x%p] sub[0x%p] %s\n", __func__, f, sub, filename);
    186 
    187     g_assert (f);
    188     data = node_get_data (f);
    189     g_assert (data);
    190 
    191     if (is_mondir) {
    192         data->mon_dir_num --;
    193     }
    194     fdata_sub_remove (data, sub);
    195     if (FN_IS_PASSIVE(data)) {
    196 #ifdef GIO_COMPILATION
    197         pending_remove_node (f, &op);
    198 #else
    199         remove_node (f, &op);
    200 #endif
    201     }
    202     G_UNLOCK (fen_lock);
    203 }
    204 
    205 static gboolean
    206 fen_init_once_func (gpointer data)
    207 {
    208     FH_W ("%s\n", __func__);
    209     if (!node_class_init ()) {
    210         FH_W ("node_class_init failed.");
    211         return FALSE;
    212     }
    213     if (!fdata_class_init (default_emit_event_cb,
    214           default_emit_once_event_cb,
    215           default_event_converter)) {
    216         FH_W ("fdata_class_init failed.");
    217         return FALSE;
    218     }
    219     return TRUE;
    220 }
    221 
    222 gboolean
    223 fen_init ()
    224 {
    225 #ifdef GIO_COMPILATION
    226     static GOnce fen_init_once = G_ONCE_INIT;
    227     g_once (&fen_init_once, (GThreadFunc)fen_init_once_func, NULL);
    228     return (gboolean)fen_init_once.retval;
    229 #else
    230     return fen_init_once_func (NULL);
    231 #endif
    232 }
    233 
    234 static void
    235 default_emit_once_event_cb (fdata *f, int events, gpointer sub)
    236 {
    237 #ifdef GIO_COMPILATION
    238     GFile* child;
    239     fen_sub* _sub = (fen_sub*)sub;
    240     child = g_file_new_for_path (FN_NAME(f));
    241     g_file_monitor_emit_event (G_FILE_MONITOR (_sub->user_data),
    242       child, NULL, events);
    243     g_object_unref (child);
    244 #else
    245     gam_server_emit_one_event (FN_NAME(f),
    246       gam_subscription_is_dir (sub), events, sub, 1);
    247 #endif
    248 }
    249 
    250 static void
    251 default_emit_event_cb (fdata *f, int events)
    252 {
    253     GList* i;
    254     fdata* pdata;
    255 
    256 #ifdef GIO_COMPILATION
    257     GFile* child;
    258     child = g_file_new_for_path (FN_NAME(f));
    259     for (i = f->subs; i; i = i->next) {
    260         fen_sub* sub = (fen_sub*)i->data;
    261         gboolean file_is_dir = sub->is_mondir;
    262         if ((events != G_FILE_MONITOR_EVENT_CHANGED &&
    263               events != G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED) ||
    264           !file_is_dir) {
    265             g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
    266               child, NULL, events);
    267         }
    268     }
    269     if ((pdata = get_parent_data (f)) != NULL) {
    270         for (i = pdata->subs; i; i = i->next) {
    271             fen_sub* sub = (fen_sub*)i->data;
    272             gboolean file_is_dir = sub->is_mondir;
    273             g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
    274               child, NULL, events);
    275         }
    276     }
    277     g_object_unref (child);
    278 #else
    279     for (i = f->subs; i; i = i->next) {
    280         gboolean file_is_dir = gam_subscription_is_dir (i->data);
    281         if (events != GAMIN_EVENT_CHANGED || !file_is_dir) {
    282             gam_server_emit_one_event (FN_NAME(f), file_is_dir, events, i->data, 1);
    283         }
    284     }
    285     if ((pdata = get_parent_data (f)) != NULL) {
    286         for (i = pdata->subs; i; i = i->next) {
    287             gboolean file_is_dir = gam_subscription_is_dir (i->data);
    288             gam_server_emit_one_event (FN_NAME(f), file_is_dir, events, i->data, 1);
    289         }
    290     }
    291 #endif
    292 }
    293 
    294 static int
    295 default_event_converter (int event)
    296 {
    297 #ifdef GIO_COMPILATION
    298     switch (event) {
    299     case FN_EVENT_CREATED:
    300         return G_FILE_MONITOR_EVENT_CREATED;
    301     case FILE_DELETE:
    302     case FILE_RENAME_FROM:
    303         return G_FILE_MONITOR_EVENT_DELETED;
    304     case UNMOUNTED:
    305         return G_FILE_MONITOR_EVENT_UNMOUNTED;
    306     case FILE_ATTRIB:
    307         return G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED;
    308     case MOUNTEDOVER:
    309     case FILE_MODIFIED:
    310     case FILE_RENAME_TO:
    311         return G_FILE_MONITOR_EVENT_CHANGED;
    312     default:
    313         /* case FILE_ACCESS: */
    314         g_assert_not_reached ();
    315         return -1;
    316     }
    317 #else
    318     switch (event) {
    319     case FN_EVENT_CREATED:
    320         return GAMIN_EVENT_CREATED;
    321     case FILE_DELETE:
    322     case FILE_RENAME_FROM:
    323         return GAMIN_EVENT_DELETED;
    324     case FILE_ATTRIB:
    325     case MOUNTEDOVER:
    326     case UNMOUNTED:
    327     case FILE_MODIFIED:
    328     case FILE_RENAME_TO:
    329         return GAMIN_EVENT_CHANGED;
    330     default:
    331         /* case FILE_ACCESS: */
    332         g_assert_not_reached ();
    333         return -1;
    334     }
    335 #endif
    336 }
    337