• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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
scan_children_init(node_t * f,gpointer sub)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
fen_add(const gchar * filename,gpointer sub,gboolean is_mondir)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
fen_remove(const gchar * filename,gpointer sub,gboolean is_mondir)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
fen_init_once_func(gpointer data)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
fen_init()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
default_emit_once_event_cb(fdata * f,int events,gpointer sub)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
default_emit_event_cb(fdata * f,int events)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
default_event_converter(int event)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