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