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