/* misc */ static void scan_children_init(node_t *f, gpointer sub) { gboolean emit; gint event; FH_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f); #ifdef GIO_COMPILATION emit = FALSE; event = G_FILE_MONITOR_EVENT_CREATED; #else emit = TRUE; event = GAMIN_EVENT_EXISTS; #endif if (!NODE_HAS_FLAG(f, NODE_FLAG_SNAPSHOT_UPDATED)) { /* TODO snapshot should also compare to the sub created timestamp. */ /* GIO initially doesn't emit created/existed events. */ node_create_children_snapshot(f, event, emit); } else { GHashTableIter iter; gpointer value; g_hash_table_iter_init (&iter, f->children); while (g_hash_table_iter_next (&iter, NULL, &value)) { node_t *child = (node_t *)value; #ifdef GIO_COMPILATION /* GIO initially doesn't emit created/existed events. */ /* g_file_monitor_emit_event(G_FILE_MONITOR(sub), child->gfile, NULL, event); */ #else gam_server_emit_one_event(NODE_NAME(child), gam_subscription_is_dir(sub), event, sub, 1); #endif } } }
/* * node_add_event: * */ static void node_add_event (node_t *f, node_event_t *ev) { FN_W ("%s %d\n", __func__, ev->e); /* Clean the events flag early, because all received events need be * processed in this function. */ NODE_CLE_STATE(f, NODE_STATE_HAS_EVENTS); /* * Node the node has been created, so we can delete create event in * optimizing. To reduce the statings, we add it to Port on discoving * it then emit CREATED event. So we don't need to do anything here. */ if (NODE_NEED_MONITOR(f)) { if (HAS_NO_EXCEPTION_EVENTS(ev->e)) { if (NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED) || port_add(f) == 0) { if ((ev->e & FILE_MODIFIED) && NODE_HAS_FLAG(f, NODE_FLAG_DIR)) { if (f->dir_subs) { node_create_children_snapshot(f, FN_EVENT_CREATED, TRUE); } else { g_hash_table_foreach(f->children, foreach_known_children_scan, NULL); } } } else { /* Emit delete event */ ev->e |= FILE_DELETE; node_adjust_deleted(f); } } else { node_adjust_deleted(f); } /* Send events to clients. */ node_emit_events (f, ev); } else { /* Send events to clients. */ node_emit_events (f, ev); node_try_delete(f); } if (ev->pair_data) { node_t *from = ev->pair_data; g_assert(ev->e == FILE_RENAME_TO); if (NODE_NEED_MONITOR(from)) { /* Clean the events flag, since it may block free this node. */ NODE_CLE_STATE(from, NODE_STATE_HAS_EVENTS); node_adjust_deleted(from); } else { node_try_delete(from); } } node_event_delete (ev); }
/* * port_add: * @f: * * Unsafe, need lock fen_lock. * port_add will associate a GSource to @f->source */ gint port_add(node_t *f) { GSource *source = f->source; FK_W ("%s [0x%p] %s\n", __func__, f, NODE_NAME(f)); g_assert(f); g_assert(NODE_HAS_FLAG(f, NODE_FLAG_STAT_UPDATED)); /* if (!NODE_HAS_FLAG(f, NODE_FLAG_STAT_DONE)) { */ /* if (NODE_STAT(f) != 0) { */ /* return errno; */ /* } */ /* } */ /* Try re-use f->pn. f->pn may be used by other request, e.g. f is deleted * for a long time. So if pn is full, we try to open a new one. */ if (!source) { start_over: /* Try the next visible source. */ if (pn_visible_list) { source = (GSource *)pn_visible_list->data; } else { if ((source = psource_new()) != NULL) { g_assert (g_list_find (pn_visible_list, source) == NULL); pn_visible_list = g_list_prepend (pn_visible_list, source); } } } if (port_associate(PGPFD(source)->fd, PORT_SOURCE_FILE, (uintptr_t)FILE_OBJECT(f), CONCERNED_EVENTS, (void *)f) == 0) { f->source = source; NODE_SET_STATE(f, NODE_STATE_ASSOCIATED); NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED); FK_W ("PORT_ASSOCIATE 0x%p OK\n", f); return 0; } else if (errno == EAGAIN) { /* Full, remove it. */ pn_visible_list = g_list_remove (pn_visible_list, source); /* Re-add to port */ goto start_over; } else if (errno == ENOENT) { /* File is not exist */ } else if (errno == ENOTSUP) { /* FS is not supported. Currently we think it no longer make sense to * monitor it, so clean the stat info and return 0 to ignore this * node. If there are requirement, we can consider to add polling * method. */ NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED); return 0; } else { FK_W ("PORT_ASSOCIATE 0x%p %s\n", f, g_strerror (errno)); } /* No matter if associated successfully, stat info is out-of-date, so clean it. */ NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED); return errno; }