1 /* Gamin
2  * Copyright (C) 2003 James Willcox, Corey Bowers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 
19 
20 #include "server_config.h"
21 #include <string.h>
22 #include <glib.h>
23 #include "gam_event.h"
24 #include "gam_node.h"
25 #include "gam_error.h"
26 #include "gam_server.h"
27 
28 /**
29  * Create a new node
30  *
31  * @param path the path the node will represent
32  * @param sub an initial GamSubscription for the node, could be NULL
33  * @param is_dir whether the node is a directory or not
34  * @returns the new node
35  */
36 GamNode *
gam_node_new(const char * path,GamSubscription * sub,gboolean is_dir)37 gam_node_new(const char *path, GamSubscription * sub, gboolean is_dir)
38 {
39     GamNode *node;
40     node = g_new0(GamNode, 1);
41 
42     node->path = g_strdup(path);
43     if (sub)
44         node->subs = g_list_prepend(NULL, sub);
45     else
46         node->subs = NULL;
47 
48     node->is_dir = is_dir;
49     node->flags = 0;
50 	node->checks = 0;
51 
52     node->poll_time = gam_fs_get_poll_timeout (path);
53     node->mon_type = gam_fs_get_mon_type (path);
54 	GAM_DEBUG(DEBUG_INFO, "g_n_n: node for %s using %s with poll timeout of %d\n", path, node->mon_type == GFS_MT_KERNEL ? "kernel" : "poll", node->poll_time);
55     return node;
56 }
57 
58 /**
59  * Frees a node
60  *
61  * @param node the node
62  */
63 void
gam_node_free(GamNode * node)64 gam_node_free(GamNode * node)
65 {
66     g_assert(node != NULL);
67     g_assert(node->subs == NULL);
68 
69     g_free(node->path);
70     g_free(node);
71 }
72 
73 /**
74  * Retrieves the parent of a given node
75  *
76  * @param node the node
77  * @returns the parent, or NULL if node has no parent
78  */
79 GamNode *
gam_node_parent(GamNode * node)80 gam_node_parent(GamNode * node)
81 {
82     GamNode *ret = NULL;
83 
84     g_assert(node);
85 
86     if (node->node && node->node->parent)
87         ret = (GamNode *) node->node->parent->data;
88 
89     return ret;
90 }
91 
92 /**
93  * Returns whether a node is a directory or not
94  *
95  * @param node the node
96  * @returns TRUE if the node is a directory, FALSE otherwise
97  */
98 gboolean
gam_node_is_dir(GamNode * node)99 gam_node_is_dir(GamNode * node)
100 {
101     g_assert(node);
102     return(node->is_dir);
103 }
104 
105 /**
106  * Sets whether a node is a directory
107  *
108  * @param node the node
109  * @param is_dir whether the node is a directory
110  */
111 void
gam_node_set_is_dir(GamNode * node,gboolean is_dir)112 gam_node_set_is_dir(GamNode * node, gboolean is_dir)
113 {
114     g_assert(node);
115     node->is_dir = is_dir;
116 }
117 
118 /**
119  * Returns the path associated with a node
120  *
121  * @param node the node
122  * @returns the path.  The caller must keep a reference to node until
123  * it has finished with the string.  If it must keep it longer, it
124  * should makes its own copy.  The returned string must not be freed.
125  */
126 const char *
gam_node_get_path(GamNode * node)127 gam_node_get_path(GamNode * node)
128 {
129     g_assert(node);
130     return node->path;
131 }
132 
133 /**
134  * Returns the list of subscriptions to a node
135  *
136  * @param node the node
137  * @returns the list of #GamSubscription to the node
138  */
139 GList *
gam_node_get_subscriptions(GamNode * node)140 gam_node_get_subscriptions(GamNode * node)
141 {
142     g_assert(node);
143     return node->subs;
144 }
145 
146 /**
147  * Returns whether a node has any directory subscriptions
148  *
149  * @param node the node
150  * @returns TRUE if the node has directory subscriptions, FALSE otherwise
151  */
152 gboolean
gam_node_has_dir_subscriptions(GamNode * node)153 gam_node_has_dir_subscriptions(GamNode * node)
154 {
155     GList *s;
156 
157     g_assert (node);
158     if (!(node->is_dir))
159         return(FALSE);
160     for (s = node->subs;s != NULL;s = s->next) {
161         if (gam_subscription_is_dir((GamSubscription *) s->data))
162 	    return(TRUE);
163     }
164     return(FALSE);
165 }
166 
167 /**
168  * Adds a subscription to a node
169  *
170  * @param node the node
171  * @param sub the subscription
172  * @returns TRUE on success, FALSE otherwise
173  */
174 gboolean
gam_node_add_subscription(GamNode * node,GamSubscription * sub)175 gam_node_add_subscription(GamNode * node, GamSubscription * sub)
176 {
177     g_assert(node);
178     g_assert(sub);
179     g_assert(!g_list_find(node->subs, sub));
180 
181     node->subs = g_list_prepend(node->subs, sub);
182 
183     return TRUE;
184 }
185 
186 /**
187  * Removes a subscription from a node
188  *
189  * @param node the node
190  * @param sub the subscription to remove
191  * @returns TRUE if the subscription was removed, FALSE otherwise
192  */
193 gboolean
gam_node_remove_subscription(GamNode * node,GamSubscription * sub)194 gam_node_remove_subscription(GamNode * node, GamSubscription * sub)
195 {
196     g_assert(node);
197     g_assert(g_list_find (node->subs, sub));
198 
199     node->subs = g_list_remove_all(node->subs, sub);
200 
201     return TRUE;
202 }
203 
204 /**
205  * Sets the GNode associated with a node.  Should only be used by MdTree
206  *
207  * @param node the node
208  * @param gnode the GNode
209  */
210 void
gam_node_set_node(GamNode * node,GNode * gnode)211 gam_node_set_node(GamNode * node, GNode * gnode)
212 {
213     g_assert(node);
214     node->node = gnode;
215 }
216 
217 /**
218  * Gets the GNode associated with a node.  Should only be used by MdTree
219  *
220  * @param node the node
221  * @returns the GNode
222  */
223 GNode *
gam_node_get_node(GamNode * node)224 gam_node_get_node(GamNode * node)
225 {
226     g_assert(node);
227     return node->node;
228 }
229 
230 /**
231  * Set a flag on a node
232  *
233  * @param node the node
234  * @param flag the flag to set
235  */
236 void
gam_node_set_flag(GamNode * node,int flag)237 gam_node_set_flag(GamNode * node, int flag)
238 {
239     g_assert(node);
240     /* Make sure we set exactly one flag.  */
241     g_assert((flag & (flag - 1)) == 0);
242     node->flags |= flag;
243 }
244 
245 /**
246  * Clears a flag from a node
247  *
248  * @param node the node
249  * @param flag the flag
250  */
251 void
gam_node_unset_flag(GamNode * node,int flag)252 gam_node_unset_flag(GamNode * node, int flag)
253 {
254     g_assert(node);
255     /* Make sure we clear exactly one flag.  */
256     g_assert((flag & (flag - 1)) == 0);
257     node->flags &= ~flag;
258 }
259 
260 /**
261  * Checks whether a flag is set on a node
262  *
263  * @param node the node
264  * @param flag the flag
265  * @returns TRUE if the flag is set, FALSE otherwise
266  */
267 gboolean
gam_node_has_flag(GamNode * node,int flag)268 gam_node_has_flag(GamNode * node, int flag)
269 {
270     g_assert(node);
271     /* Check exactly one flag.  */
272     g_assert((flag & (flag - 1)) == 0);
273     return node->flags & flag;
274 }
275 
276 /**
277  * Set a pflag on a node
278  *
279  * @param node the node
280  * @param flag the flag to set
281  */
282 void
gam_node_set_pflag(GamNode * node,int flag)283 gam_node_set_pflag(GamNode * node, int flag)
284 {
285     g_assert(node);
286     /* Make sure we set exactly one flag.  */
287     g_assert((flag & (flag - 1)) == 0);
288     node->pflags |= flag;
289 }
290 
291 /**
292  * Clears a pflag from a node
293  *
294  * @param node the node
295  * @param flag the flag
296  */
297 void
gam_node_unset_pflag(GamNode * node,int flag)298 gam_node_unset_pflag(GamNode * node, int flag)
299 {
300     g_assert(node);
301     /* Make sure we clear exactly one flag.  */
302     g_assert((flag & (flag - 1)) == 0);
303     node->pflags &= ~flag;
304 }
305 
306 /**
307  * Checks whether a pflag is set on a node
308  *
309  * @param node the node
310  * @param flag the flag
311  * @returns TRUE if the flag is set, FALSE otherwise
312  */
313 gboolean
gam_node_has_pflag(GamNode * node,int flag)314 gam_node_has_pflag(GamNode * node, int flag)
315 {
316     g_assert(node);
317     /* Check exactly one flag.  */
318     g_assert((flag & (flag - 1)) == 0);
319     return node->pflags & flag;
320 }
321 
322 /**
323  * Set the pflags on a node
324  *
325  * @param node the node
326  * @param flags the flags
327  */
328 void
gam_node_set_pflags(GamNode * node,int flags)329 gam_node_set_pflags(GamNode * node, int flags)
330 {
331     g_assert(node);
332     node->pflags = flags;
333 }
334 
335 
336 /**
337  * Checks whether some pflags are set on a node
338  *
339  * @param node the node
340  * @param flags the flags
341  * @returns TRUE if the flag is set, FALSE otherwise
342  */
343 gboolean
gam_node_has_pflags(GamNode * node,int flags)344 gam_node_has_pflags(GamNode * node, int flags)
345 {
346     g_assert(node);
347     return node->pflags & flags;
348 }
349 
350 void
gam_node_emit_event(GamNode * node,GaminEventType event)351 gam_node_emit_event (GamNode *node, GaminEventType event)
352 {
353 	GList *l;
354 	GamNode *parent;
355 	GList *subs;
356 	int is_dir_node = gam_node_is_dir(node);
357 
358 #ifdef VERBOSE_POLL
359 	GAM_DEBUG(DEBUG_INFO, "Poll: emit events %d for %s\n", event, gam_node_get_path(node));
360 #endif
361 	subs = gam_node_get_subscriptions(node);
362 
363 	if (subs)
364 		subs = g_list_copy(subs);
365 
366 	parent = gam_node_parent(node);
367 	if (parent) {
368 		GList *parent_subs = gam_node_get_subscriptions(parent);
369 
370 		for (l = parent_subs; l; l = l->next) {
371 			if (!g_list_find(subs, l->data))
372 				subs = g_list_prepend(subs, l->data);
373 		}
374 	}
375 
376 	gam_server_emit_event(gam_node_get_path(node), is_dir_node, event, subs, 0);
377 
378 	g_list_free(subs);
379 }
380 
381 /** @} */
382