doc: Clarify documentation regarding g_file_replace and etags
[platform/upstream/glib.git] / gio / fen / fen-node.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, 2010 Oracle and/or its affiliates, Inc. All rights
5  * reserved.
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, see <http://www.gnu.org/licenses/>.
19  *
20  * Authors: Lin Ma <lin.ma@sun.com>
21  */
22
23 #include "config.h"
24 #include <sys/stat.h>
25 #include <errno.h>
26 #include <strings.h>
27 #include <glib.h>
28 #include "fen-kernel.h"
29 #include "fen-node.h"
30 #include "fen-dump.h"
31
32 #ifdef GIO_COMPILATION
33 #include <gio/gfilemonitor.h>
34 #else
35 #include "gam_event.h"
36 #include "gam_server.h"
37 #include "gam_protocol.h"
38 #endif
39
40 #ifdef GIO_COMPILATION
41 #define FN_W if (FALSE) g_debug
42 #else
43 #include "gam_error.h"
44 #define FN_W(...) GAM_DEBUG(DEBUG_INFO, __VA_ARGS__)
45 #endif
46
47 G_LOCK_EXTERN (fen_lock);
48
49 /* Must continue monitoring if:
50  * 1) I'm subscribed,
51  * 2) The subscribed children (one of the children has subs) are missing,
52  * 3) my parent is subscribed (monitoring directory).
53  */
54 #define NODE_NEED_MONITOR(f)                                            \
55     (NODE_IS_ACTIVE(f) || node_children_num(f) > 0 || NODE_IS_REQUIRED_BY_PARENT(f))
56
57 static int concern_events[] = {
58     FILE_DELETE,
59     FILE_RENAME_FROM,
60     UNMOUNTED,
61     MOUNTEDOVER,
62 #ifdef GIO_COMPILATION
63     FILE_MODIFIED,
64     FILE_ATTRIB,
65 #else
66     FILE_MODIFIED | FILE_ATTRIB,
67 #endif
68     FILE_RENAME_TO,
69 };
70
71 node_t *ROOT = NULL;
72
73 static void node_emit_one_event(node_t *f, GList *subs, node_t *other, int event);
74 static void node_emit_events(node_t *f, const node_event_t *ne);
75 static int node_event_translate(int event, gboolean pair);
76 static void node_add_event (node_t *f, node_event_t *ev);
77 static node_t* node_new (node_t* parent, const gchar* basename);
78 static void node_delete (node_t* parent);
79 static node_t* node_get_child (node_t *f, const gchar *basename);
80 static void children_add (node_t *p, node_t *f);
81 static void children_remove (node_t *p, node_t *f);
82 static gboolean children_remove_cb (gpointer key, gpointer value, gpointer user_data);
83 static guint node_children_num (node_t *f);
84
85 gboolean
86 node_timeval_lt(const GTimeVal *val1, const GTimeVal *val2)
87 {
88     if (val1->tv_sec < val2->tv_sec)
89         return TRUE;
90   
91     if (val1->tv_sec > val2->tv_sec)
92         return FALSE;
93   
94     /* val1->tv_sec == val2->tv_sec */
95     if (val1->tv_usec < val2->tv_usec)
96         return TRUE;
97   
98     return FALSE;
99 }
100
101 void
102 node_traverse (node_t* node, void(*traverse_cb)(node_t*, gpointer), gpointer user_data)
103 {
104     GHashTableIter iter;
105     gpointer value;
106
107     g_assert(traverse_cb);
108     if (node == NULL) {
109         node = ROOT;
110     }
111
112     if (node) {
113         traverse_cb(node, user_data);
114     }
115
116     g_hash_table_iter_init (&iter, node->children);
117     while (g_hash_table_iter_next (&iter, NULL, &value)) {
118         node_traverse((node_t *)value, traverse_cb, user_data);
119     }
120 }
121
122 node_t*
123 node_find(node_t* node, const gchar* filename, gboolean create_on_missing)
124 {
125     gchar* str;
126     gchar* token;
127     gchar* lasts;
128     node_t* parent;
129     node_t* child;
130     
131     g_assert (filename && filename[0] == '/');
132
133     if (node == NULL) {
134         node = ROOT;
135     }
136     
137     FN_W ("%s %s\n", __func__, filename);
138
139     parent = child = node;
140     str = g_strdup (filename);
141     
142     for (token = strtok_r (str, G_DIR_SEPARATOR_S, &lasts);
143          token != NULL && child != NULL;
144          token = strtok_r (NULL, G_DIR_SEPARATOR_S, &lasts)) {
145         child = node_get_child(parent, token);
146         if (child) {
147             parent = child;
148         } else if (create_on_missing) {
149             child = node_new (parent, token);
150             if (child) {
151                 children_add (parent, child);
152                 parent = child;
153                 continue;
154             } else {
155                 FN_W ("%s create %s failed", __func__, token);
156             }
157         } else {
158             break;
159         }
160     }
161     
162     g_free (str);
163     return child;
164 }
165
166 gint
167 node_lstat(node_t *f)
168 {
169     struct stat buf;
170
171     g_assert(!NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED));
172
173     if (lstat(NODE_NAME(f), &buf) == 0) {
174         FN_W ("%s %s\n", __func__, NODE_NAME(f));
175         FILE_OBJECT(f)->fo_atime = buf.st_atim;
176         FILE_OBJECT(f)->fo_mtime = buf.st_mtim;
177         FILE_OBJECT(f)->fo_ctime = buf.st_ctim;
178         NODE_SET_FLAG(f, NODE_FLAG_STAT_UPDATED |
179           (S_ISDIR (buf.st_mode) ? NODE_FLAG_DIR : NODE_FLAG_NONE));
180         return 0;
181     } else {
182         FN_W ("%s(lstat) %s %s\n", __func__, NODE_NAME(f), g_strerror (errno));
183     }
184     return errno;
185 }
186
187 void
188 node_create_children_snapshot(node_t *f, gint created_event, gboolean emit)
189 {
190         GDir *dir;
191         GError *err = NULL;
192     
193     FN_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f);
194
195     dir = g_dir_open (NODE_NAME(f), 0, &err);
196     if (dir) {
197         const char *basename;
198         node_t *child = NULL;
199         
200         while ((basename = g_dir_read_name (dir))) {
201             node_t* data;
202             GList *idx;
203
204             child = node_get_child (f, basename);
205             if (child == NULL) {
206                 gchar *filename;
207             
208                 child = node_new (f, basename);
209                 children_add (f, child);
210             }
211
212             if (f->dir_subs) {
213                 /* We need monitor the new children, or the existed child which
214                  * is in the DELETED mode.
215                  */
216                 if (!NODE_HAS_STATE(child, NODE_STATE_ASSOCIATED) &&
217                   node_lstat(child) == 0 && port_add(child) == 0) {
218                     if (emit) {
219                         /* Emit the whatever event for the new found file. */
220                         node_emit_one_event(child, child->dir_subs, NULL, created_event);
221                         node_emit_one_event(child, child->subs, NULL, created_event);
222                         node_emit_one_event(child, f->dir_subs, NULL, created_event);
223                         node_emit_one_event(child, f->subs, NULL, created_event);
224                     }
225                 }
226                 /* else ignore, because it may be deleted. */
227             }
228         }
229         g_dir_close (dir);
230
231         /* We have finished children snapshot. Any other new added subs should
232          * directory iterate the snapshot instead of scan directory again.
233          */
234         NODE_SET_FLAG(f, NODE_FLAG_SNAPSHOT_UPDATED);
235
236     } else {
237         FN_W (err->message);
238         g_error_free (err);
239     }
240 }
241
242 /*
243  * If all active children nodes are ported, then cancel monitor the parent
244  * node. If we know how many children are created, then we can stop accordingly.
245  *
246  * Unsafe, need lock. 
247  */
248 static void
249 foreach_known_children_scan(gpointer key, gpointer value, gpointer user_data)
250 {
251     node_t* f = (node_t*)value;
252     
253     FN_W ("%s 0x%p %s\n", __func__, f, NODE_NAME(f));
254
255     if (!NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED)) {
256         if (node_lstat(f) == 0 && port_add(f) == 0) {
257             node_emit_one_event(f, f->dir_subs, NULL, FN_EVENT_CREATED);
258             node_emit_one_event(f, f->subs, NULL, FN_EVENT_CREATED);
259             if (NODE_PARENT(f)) {
260                 node_emit_one_event(f, NODE_PARENT(f)->dir_subs, NULL, FN_EVENT_CREATED);
261                 node_emit_one_event(f, NODE_PARENT(f)->subs, NULL, FN_EVENT_CREATED);
262             }
263         }
264     }
265 }
266
267 gboolean
268 node_try_delete(node_t* node)
269 {
270     g_assert (node);
271
272     FN_W ("%s 0x%p %s\n", __func__, node, NODE_NAME(node));
273
274     /* Try clean children */
275     if (node_children_num (node) > 0) {
276         g_hash_table_foreach_remove(node->children, children_remove_cb, NULL);
277     }
278     if (!NODE_NEED_MONITOR(node)) {
279         /* Clean some flags. */
280         /* NODE_CLE_FLAG(node, NODE_FLAG_HAS_SNAPSHOT | NODE_FLAG_STAT_DONE); */
281
282         /* Now we handle the state. */
283         if (NODE_HAS_STATE(node, NODE_STATE_ASSOCIATED)) {
284             port_remove(node);
285         }
286         /* Actually ignore the ROOT node. */
287         if (node->state == 0 && NODE_PARENT(node)) {
288             children_remove(NODE_PARENT(node), node);
289             /* Do clean instead of returning TRUE. */
290             node_delete (node);
291         }
292         /* else, we have events, clean event queue? */
293     }
294     return FALSE;
295 }
296
297 static node_t*
298 node_new (node_t* parent, const gchar* basename)
299 {
300         node_t *f = NULL;
301
302     g_assert (basename && basename[0]);
303
304     if ((f = g_new0(node_t, 1)) != NULL) {
305         if (parent) {
306             NODE_NAME(f) = g_build_filename(NODE_NAME(parent), basename, NULL);
307         } else {
308             NODE_NAME(f) = g_strdup(G_DIR_SEPARATOR_S);
309         }
310         f->basename = g_strdup (basename);
311         /* f->children = g_hash_table_new_full (g_str_hash, g_str_equal, */
312         /*   NULL, (GDestroyNotify)node_delete); */
313         f->children = g_hash_table_new_full (g_str_hash, g_str_equal,
314           NULL, NULL);
315 #ifdef GIO_COMPILATION
316         f->gfile = g_file_new_for_path (NODE_NAME(f));
317 #endif
318         FN_W ("%s 0x%p %s\n", __func__, f, NODE_NAME(f));
319     }
320         return f;
321 }
322
323 static void
324 node_delete (node_t *f)
325 {
326     FN_W ("%s 0x%p %s\n", __func__, f, NODE_NAME(f));
327     /* Clean flags. */
328     f->flag = 0;
329     g_assert(f->state == 0);
330     g_assert(!NODE_IS_ACTIVE(f));
331     g_assert(g_hash_table_size (f->children) == 0);
332     g_assert(NODE_PARENT(f) == NULL);
333     g_hash_table_unref(f->children);
334 #ifdef GIO_COMPILATION
335     g_object_unref (f->gfile);
336 #endif
337     g_free(f->basename);
338     g_free(NODE_NAME(f));
339     g_free (f);
340 }
341
342 static void
343 children_add (node_t *p, node_t *f)
344 {
345     FN_W ("%s %s %s\n", __func__, NODE_NAME(p), f->basename);
346     g_hash_table_insert (p->children, f->basename, f);
347     NODE_PARENT(f) = p;
348 }
349
350 static void
351 children_remove (node_t *p, node_t *f)
352 {
353     FN_W ("%s %s %s\n", __func__, NODE_NAME(p), f->basename);
354     g_hash_table_steal (p->children, f->basename);
355     NODE_PARENT(f) = NULL;
356 }
357
358 static node_t *
359 node_get_child (node_t *f, const gchar *basename)
360 {
361     if (f->children) {
362         return (node_t *) g_hash_table_lookup (f->children, (gpointer)basename);
363     }
364     return NULL;
365 }
366
367 static guint
368 node_children_num (node_t *f)
369 {
370     return g_hash_table_size (f->children);
371 }
372
373 /*
374  * depth first delete recursively
375  */
376 static gboolean
377 children_remove_cb (gpointer key, gpointer value, gpointer user_data)
378 {
379     return node_try_delete ((node_t*)value);
380 }
381
382 gboolean
383 node_class_init()
384 {
385     ROOT = node_new (NULL, G_DIR_SEPARATOR_S);
386     if (ROOT == NULL) {
387         FN_W ("[node] Create ROOT node failed.\n");
388         return FALSE;
389     }
390
391     return port_class_init (node_add_event);
392 }
393
394 /*
395  * Adjust self on failing to Port
396  */
397 void
398 node_adjust_deleted(node_t* f)
399 {
400     node_t *ancestor;
401
402     FN_W ("%s %s\n", __func__, NODE_NAME(f));
403
404     for (ancestor = NODE_PARENT(f);
405          ancestor != NULL;
406          ancestor = NODE_PARENT(ancestor)) {
407         /* Stop if we find a node which been already associated or is existed
408          * and can be associated.
409          */
410         if (NODE_HAS_STATE(ancestor, NODE_STATE_ASSOCIATED) ||
411           (node_lstat(ancestor) == 0 && port_add(ancestor) == 0)) {
412             break;
413         }
414     }
415
416     /* We assume we shouldn't reach here, because Root is always existed and
417      * associated. But given bugster#6955199, if PORT FS has problems on root,
418      * we may reach here. So just return ROOT and the whole GIO fen backend will
419      * fail.
420      */
421     /* g_assert(ancestor != NULL); */
422 }
423
424
425 static void
426 node_emit_events(node_t *f, const node_event_t *ne)
427 {
428     gsize num = sizeof(concern_events)/sizeof(int);
429     gint i;
430     int translated_e;
431     node_t *p;
432
433     if (node_timeval_lt(&f->atv, &ne->ctv)) {
434         int event = ne->e;
435
436         /* Emit DELETED on the pair_data */
437         if (ne->pair_data) {
438             node_t *from = ne->pair_data;
439             node_emit_one_event(from, from->dir_subs, NULL, node_event_translate(FILE_DELETE, FALSE));
440             node_emit_one_event(from, from->subs, NULL, node_event_translate(FILE_DELETE, FALSE));
441         }
442
443         for (i = 0; i < num; i++) {
444             if (event & concern_events[i]) {
445                 translated_e = node_event_translate(concern_events[i], FALSE);
446                 /* Neither GIO or gamin cares about modified events on a
447                  * directory.
448                  */
449 #ifdef GIO_COMPILATION
450                 if ((concern_events[i] & FILE_MODIFIED) == 0) {
451                     node_emit_one_event(f, f->dir_subs, NULL, translated_e);
452                 }
453 #else
454                 /* Gamin doesn't care about attrib changed events on a directory
455                  * either.
456                  */
457                 if ((concern_events[i] & (FILE_MODIFIED | FILE_ATTRIB)) == 0) {
458                     node_emit_one_event(f, f->dir_subs, NULL, translated_e);
459                 }
460 #endif
461                 node_emit_one_event(f, f->subs, NULL, translated_e);
462             }
463             event &= ~concern_events[i];
464         }
465     }
466
467     p = NODE_PARENT(f);
468     if (p != NULL && node_timeval_lt(&p->atv, &ne->ctv)) {
469         int event = ne->e;
470         for (i = 0; i < num; i++) {
471             if (event & concern_events[i]) {
472                 translated_e = node_event_translate(concern_events[i], ne->pair_data != NULL);
473                 node_emit_one_event(f, p->dir_subs, ne->pair_data, translated_e);
474                 node_emit_one_event(f, p->subs, ne->pair_data, translated_e);
475             }
476             event &= ~concern_events[i];
477         }
478     }
479 }
480
481 /*
482  * node_add_event:
483  *
484  */
485 static void
486 node_add_event (node_t *f, node_event_t *ev)
487 {
488     FN_W ("%s %d\n", __func__, ev->e);
489
490     /* Clean the events flag early, because all received events need be
491      * processed in this function.
492      */
493     NODE_CLE_STATE(f, NODE_STATE_HAS_EVENTS);
494
495     /*
496      * Node the node has been created, so we can delete create event in
497      * optimizing. To reduce the statings, we add it to Port on discoving
498      * it then emit CREATED event. So we don't need to do anything here.
499      */
500     if (NODE_NEED_MONITOR(f)) {
501         if (HAS_NO_EXCEPTION_EVENTS(ev->e)) {
502             if (NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED) || port_add(f) == 0) {
503                 if ((ev->e & FILE_MODIFIED) && NODE_HAS_FLAG(f, NODE_FLAG_DIR)) {
504                     if (f->dir_subs) {
505                         node_create_children_snapshot(f, FN_EVENT_CREATED, TRUE);
506                     } else {
507                         g_hash_table_foreach(f->children, foreach_known_children_scan, NULL);
508                     }
509                 }
510             } else {
511                 /* Emit delete event */
512                 ev->e |= FILE_DELETE;
513
514                 node_adjust_deleted(f);
515             }
516
517         } else {
518             node_adjust_deleted(f);
519         }
520
521         /* Send events to clients. */
522         node_emit_events (f, ev);
523         
524     } else {
525         /* Send events to clients. */
526         node_emit_events (f, ev);
527
528         node_try_delete(f);
529     }
530
531     if (ev->pair_data) {
532         node_t *from = ev->pair_data;
533         g_assert(ev->e == FILE_RENAME_TO);
534
535         if (NODE_NEED_MONITOR(from)) {
536             /* Clean the events flag, since it may block free this node. */
537             NODE_CLE_STATE(from, NODE_STATE_HAS_EVENTS);
538             node_adjust_deleted(from);
539         } else {
540             node_try_delete(from);
541         }
542     }
543
544     node_event_delete (ev);
545 }
546
547 static void
548 node_emit_one_event(node_t *f, GList *subs, node_t *other, int event)
549 {
550     GList* idx;
551     
552     FN_W ("%s %s %d\n", __func__, NODE_NAME(f), event);
553
554 #ifdef GIO_COMPILATION
555     for (idx = subs; idx; idx = idx->next) {
556         g_file_monitor_emit_event(G_FILE_MONITOR(idx->data), f->gfile,
557           (other == NULL ? NULL : other->gfile), event);
558     }
559 #else
560     for (idx = subs; idx; idx = idx->next) {
561         gam_server_emit_one_event(NODE_NAME(f), gam_subscription_is_dir(idx->data), event, idx->data, 1);
562     }
563 #endif
564 }
565
566 static int
567 node_event_translate(int event, gboolean pair)
568 {
569 #ifdef GIO_COMPILATION
570     switch (event) {
571     case FILE_DELETE:
572     case FILE_RENAME_FROM:
573         return G_FILE_MONITOR_EVENT_DELETED;
574     case UNMOUNTED:
575         return G_FILE_MONITOR_EVENT_UNMOUNTED;
576     case FILE_ATTRIB:
577         return G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED;
578     case MOUNTEDOVER:
579     case FILE_MODIFIED:
580         return G_FILE_MONITOR_EVENT_CHANGED;
581     case FILE_RENAME_TO:
582         if (pair) {
583             return G_FILE_MONITOR_EVENT_MOVED;
584         } else {
585             return G_FILE_MONITOR_EVENT_CREATED;
586         }
587     default:
588         /* case FILE_ACCESS: */
589         g_assert_not_reached ();
590         return -1;
591     }
592 #else
593     switch (event) {
594     case FILE_DELETE:
595     case FILE_RENAME_FROM:
596         return GAMIN_EVENT_DELETED;
597     case MOUNTEDOVER:
598     case UNMOUNTED:
599         return GAMIN_EVENT_CHANGED;
600     case FILE_RENAME_TO:
601         if (pair) {
602             return GAMIN_EVENT_MOVED;
603         } else {
604             return GAMIN_EVENT_CREATED;
605         }
606     default:
607         if (event & (FILE_ATTRIB | FILE_MODIFIED)) {
608             return GAMIN_EVENT_CHANGED;
609         }
610         /* case FILE_ACCESS: */
611         g_assert_not_reached ();
612         return -1;
613     }
614 #endif
615 }
616
617 node_event_t*
618 node_event_new (int event, gpointer user_data)
619 {
620     node_event_t *ev;
621     
622     if ((ev = g_new (node_event_t, 1)) != NULL) {
623         g_assert (ev);
624         ev->e = event;
625         ev->user_data = user_data;
626         ev->pair_data = NULL;   /* For renamed file. */
627         /* Created timestamp */
628         g_get_current_time(&ev->ctv);
629         ev->rename_tv = ev->ctv;
630     }
631     return ev;
632 }
633
634 void
635 node_event_delete (node_event_t* ev)
636 {
637     g_free (ev);
638 }