Initial commit
[platform/upstream/glib2.0.git] / gio / fen / fen-helper.c
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 "gfile.h"
32 #include "gfilemonitor.h"
33 #else
34 #include "gam_event.h"
35 #include "gam_server.h"
36 #include "gam_protocol.h"
37 #endif
38
39 #ifdef GIO_COMPILATION
40 #define FH_W if (fh_debug_enabled) g_warning
41 static gboolean fh_debug_enabled = FALSE;
42 #else
43 #include "gam_error.h"
44 #define FH_W(...) GAM_DEBUG(DEBUG_INFO, __VA_ARGS__)
45 #endif
46
47 G_LOCK_EXTERN (fen_lock);
48
49 static void default_emit_event_cb (fdata *f, int events);
50 static void default_emit_once_event_cb (fdata *f, int events, gpointer sub);
51 static int default_event_converter (int event);
52
53 static void
54 scan_children_init (node_t *f, gpointer sub)
55 {
56         GDir *dir;
57         GError *err = NULL;
58     node_op_t op = {NULL, NULL, _pre_del_cb, NULL};
59     fdata* pdata;
60     
61     FH_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f);
62     pdata = _node_get_data (f);
63
64     dir = g_dir_open (NODE_NAME(f), 0, &err);
65     if (dir) {
66         const char *basename;
67         
68         while ((basename = g_dir_read_name (dir)))
69         {
70             node_t *childf = NULL;
71             fdata* data;
72             GList *idx;
73
74             childf = _children_find (f, basename);
75             if (childf == NULL) {
76                 gchar *filename;
77             
78                 filename = g_build_filename (NODE_NAME(f), basename, NULL);
79                 childf = _add_node (f, filename);
80                 g_assert (childf);
81                 g_free (filename);
82             }
83             if ((data = _node_get_data (childf)) == NULL) {
84                 data = _fdata_new (childf, FALSE);
85             }
86             
87             if (is_monitoring (data)) {
88                 /* Ignored */
89             } else if (/* !_is_ported (data) && */
90                 _port_add (&data->fobj, &data->len, data)) {
91                 /* Emit created to all other subs */
92                 _fdata_emit_events (data, FN_EVENT_CREATED);
93             }
94             /* Emit created to the new sub */
95 #ifdef GIO_COMPILATION
96             /* _fdata_emit_events_once (data, FN_EVENT_CREATED, sub); */
97 #else
98             gam_server_emit_one_event (NODE_NAME(childf),
99               gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1);
100 #endif
101         }
102         g_dir_close (dir);
103     } else {
104         FH_W (err->message);
105         g_error_free (err);
106     }
107 }
108
109 /**
110  * _fen_add
111  * 
112  * Won't hold a ref, we have a timout callback to clean unused fdata.
113  * If there is no value for a key, add it and return it; else return the old
114  * one.
115  */
116 void
117 _fen_add (const gchar *filename, gpointer sub, gboolean is_mondir)
118 {
119     node_op_t op = {NULL, _add_missing_cb, _pre_del_cb, (gpointer)filename};
120         node_t* f;
121     fdata* data;
122     
123     g_assert (filename);
124     g_assert (sub);
125
126     G_LOCK (fen_lock);
127         f = _find_node_full (filename, &op);
128     FH_W ("[ %s ] f[0x%p] sub[0x%p] %s\n", __func__, f, sub, filename);
129     g_assert (f);
130     data = _node_get_data (f);
131     if (data == NULL) {
132         data = _fdata_new (f, is_mondir);
133     }
134
135     if (is_mondir) {
136         data->mon_dir_num ++;
137     }
138     
139     /* Change to active */
140 #ifdef GIO_COMPILATION
141     if (_port_add (&data->fobj, &data->len, data) ||
142       g_file_test (FN_NAME(data), G_FILE_TEST_EXISTS)) {
143         if (is_mondir) {
144             scan_children_init (f, sub);
145         }
146         _fdata_sub_add (data, sub);
147     } else {
148         _fdata_sub_add (data, sub);
149         _fdata_adjust_deleted (data);
150     }
151 #else
152     if (_port_add (&data->fobj, &data->len, data) ||
153       g_file_test (FN_NAME(data), G_FILE_TEST_EXISTS)) {
154         gam_server_emit_one_event (FN_NAME(data),
155           gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1);
156         if (is_mondir) {
157             scan_children_init (f, sub);
158         }
159         gam_server_emit_one_event (FN_NAME(data),
160           gam_subscription_is_dir (sub), GAMIN_EVENT_ENDEXISTS, sub, 1);
161         _fdata_sub_add (data, sub);
162     } else {
163         _fdata_sub_add (data, sub);
164         gam_server_emit_one_event (FN_NAME(data),
165           gam_subscription_is_dir (sub), GAMIN_EVENT_DELETED, sub, 1);
166         _fdata_adjust_deleted (data);
167         gam_server_emit_one_event (FN_NAME(data),
168           gam_subscription_is_dir (sub), GAMIN_EVENT_ENDEXISTS, sub, 1);
169     }
170 #endif
171     G_UNLOCK (fen_lock);
172 }
173
174 void
175 _fen_remove (const gchar *filename, gpointer sub, gboolean is_mondir)
176 {
177     node_op_t op = {NULL, _add_missing_cb, _pre_del_cb, (gpointer)filename};
178     node_t* f;
179     fdata* data;
180     
181     g_assert (filename);
182     g_assert (sub);
183
184     G_LOCK (fen_lock);
185         f = _find_node (filename);
186     FH_W ("[ %s ] f[0x%p] sub[0x%p] %s\n", __func__, f, sub, filename);
187
188     g_assert (f);
189     data = _node_get_data (f);
190     g_assert (data);
191     
192     if (is_mondir) {
193         data->mon_dir_num --;
194     }
195     _fdata_sub_remove (data, sub);
196     if (FN_IS_PASSIVE(data)) {
197 #ifdef GIO_COMPILATION
198         _pending_remove_node (f, &op);
199 #else
200         _remove_node (f, &op);
201 #endif
202     }
203     G_UNLOCK (fen_lock);
204 }
205
206 static gboolean
207 fen_init_once_func (gpointer data)
208 {
209     FH_W ("%s\n", __func__);
210     if (!_node_class_init ()) {
211         FH_W ("_node_class_init failed.");
212         return FALSE;
213     }
214     if (!_fdata_class_init (default_emit_event_cb,
215           default_emit_once_event_cb,
216           default_event_converter)) {
217         FH_W ("_fdata_class_init failed.");
218         return FALSE;
219     }
220     return TRUE;
221 }
222
223 gboolean
224 _fen_init ()
225 {
226 #ifdef GIO_COMPILATION
227     static GOnce fen_init_once = G_ONCE_INIT;
228     g_once (&fen_init_once, (GThreadFunc)fen_init_once_func, NULL);
229     return (gboolean)fen_init_once.retval;
230 #else
231     return fen_init_once_func (NULL);
232 #endif
233 }
234
235 static void
236 default_emit_once_event_cb (fdata *f, int events, gpointer sub)
237 {
238 #ifdef GIO_COMPILATION
239     GFile* child;
240     fen_sub* _sub = (fen_sub*)sub;
241     child = g_file_new_for_path (FN_NAME(f));
242     g_file_monitor_emit_event (G_FILE_MONITOR (_sub->user_data),
243       child, NULL, events);
244     g_object_unref (child);
245 #else
246     gam_server_emit_one_event (FN_NAME(f),
247       gam_subscription_is_dir (sub), events, sub, 1);
248 #endif
249 }
250
251 static void
252 default_emit_event_cb (fdata *f, int events)
253 {
254     GList* i;
255     fdata* pdata;
256     
257 #ifdef GIO_COMPILATION
258     GFile* child;
259     child = g_file_new_for_path (FN_NAME(f));
260     for (i = f->subs; i; i = i->next) {
261         fen_sub* sub = (fen_sub*)i->data;
262         gboolean file_is_dir = sub->is_mondir;
263         if ((events != G_FILE_MONITOR_EVENT_CHANGED &&
264               events != G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED) ||
265           !file_is_dir) {
266             g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
267               child, NULL, events);
268         }
269     }
270     if ((pdata = _get_parent_data (f)) != NULL) {
271         for (i = pdata->subs; i; i = i->next) {
272             fen_sub* sub = (fen_sub*)i->data;
273             gboolean file_is_dir = sub->is_mondir;
274             g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
275               child, NULL, events);
276         }
277     }
278     g_object_unref (child);
279 #else
280     for (i = f->subs; i; i = i->next) {
281         gboolean file_is_dir = gam_subscription_is_dir (i->data);
282         if (events != GAMIN_EVENT_CHANGED || !file_is_dir) {
283             gam_server_emit_one_event (FN_NAME(f), file_is_dir, events, i->data, 1);
284         }
285     }
286     if ((pdata = _get_parent_data (f)) != NULL) {
287         for (i = pdata->subs; i; i = i->next) {
288             gboolean file_is_dir = gam_subscription_is_dir (i->data);
289             gam_server_emit_one_event (FN_NAME(f), file_is_dir, events, i->data, 1);
290         }
291     }
292 #endif
293 }
294
295 static int
296 default_event_converter (int event)
297 {
298 #ifdef GIO_COMPILATION
299     switch (event) {
300     case FN_EVENT_CREATED:
301         return G_FILE_MONITOR_EVENT_CREATED;
302     case FILE_DELETE:
303     case FILE_RENAME_FROM:
304         return G_FILE_MONITOR_EVENT_DELETED;
305     case UNMOUNTED:
306         return G_FILE_MONITOR_EVENT_UNMOUNTED;
307     case FILE_ATTRIB:
308         return G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED;
309     case MOUNTEDOVER:
310     case FILE_MODIFIED:
311     case FILE_RENAME_TO:
312         return G_FILE_MONITOR_EVENT_CHANGED;
313     default:
314         /* case FILE_ACCESS: */
315         g_assert_not_reached ();
316         return -1;
317     }
318 #else
319     switch (event) {
320     case FN_EVENT_CREATED:
321         return GAMIN_EVENT_CREATED;
322     case FILE_DELETE:
323     case FILE_RENAME_FROM:
324         return GAMIN_EVENT_DELETED;
325     case FILE_ATTRIB:
326     case MOUNTEDOVER:
327     case UNMOUNTED:
328     case FILE_MODIFIED:
329     case FILE_RENAME_TO:
330         return GAMIN_EVENT_CHANGED;
331     default:
332         /* case FILE_ACCESS: */
333         g_assert_not_reached ();
334         return -1;
335     }
336 #endif
337 }