/* * Adjust self on failing to Port */ void node_adjust_deleted(node_t* f) { node_t *ancestor; FN_W ("%s %s\n", __func__, NODE_NAME(f)); for (ancestor = NODE_PARENT(f); ancestor != NULL; ancestor = NODE_PARENT(ancestor)) { /* Stop if we find a node which been already associated or is existed * and can be associated. */ if (NODE_HAS_STATE(ancestor, NODE_STATE_ASSOCIATED) || (node_lstat(ancestor) == 0 && port_add(ancestor) == 0)) { break; } } /* We assume we shouldn't reach here, because Root is always existed and * associated. But given bugster#6955199, if PORT FS has problems on root, * we may reach here. So just return ROOT and the whole GIO fen backend will * fail. */ /* g_assert(ancestor != NULL); */ }
static gboolean port_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) { node_t *f; uint_t nget = 0; uint_t total = 0; FK_W ("%s 0x%p fd %d\n", __func__, source, PGPFD(source)->fd); G_LOCK (fen_lock); do { nget = 1; if (port_getn(PGPFD(source)->fd, pevents, PE_ALLOC, &nget, &zero_wait) == 0) { int i; for (i = 0; i < nget; i++) { f = (node_t *)pevents[i].portev_user; if (pevents[i].portev_source == PORT_SOURCE_FILE) { NODE_CLE_STATE(f, NODE_STATE_ASSOCIATED); NODE_SET_STATE(f, NODE_STATE_HAS_EVENTS); if (HAS_NO_EXCEPTION_EVENTS(pevents[i].portev_events)) { /* If the events do not show it's deleted, update * file timestamp to avoid missing events next time. */ if (node_lstat(f) != 0 /* || port_add(f) != 0 */) { /* Included deleted event. */ pevents[i].portev_events |= FILE_DELETE; } } /* Queue it and waiting for processing. */ g_queue_push_tail(g_eventq, node_event_new(pevents[i].portev_events, (gpointer)f)); } else { FK_W ("[kernel] unknown portev_source %d\n", pevents[i].portev_source); } } total += nget; } else { FK_W ("[kernel] port_getn %s\n", g_strerror (errno)); break; } } while (nget == PE_ALLOC); G_UNLOCK (fen_lock); if (total > 0 && callback) { FK_W ("[kernel] get total %ld events\n", total); return callback (user_data); } return TRUE; }
void node_create_children_snapshot(node_t *f, gint created_event, gboolean emit) { GDir *dir; GError *err = NULL; FN_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f); dir = g_dir_open (NODE_NAME(f), 0, &err); if (dir) { const char *basename; node_t *child = NULL; while ((basename = g_dir_read_name (dir))) { node_t* data; GList *idx; child = node_get_child (f, basename); if (child == NULL) { gchar *filename; child = node_new (f, basename); children_add (f, child); } if (f->dir_subs) { /* We need monitor the new children, or the existed child which * is in the DELETED mode. */ if (!NODE_HAS_STATE(child, NODE_STATE_ASSOCIATED) && node_lstat(child) == 0 && port_add(child) == 0) { if (emit) { /* Emit the whatever event for the new found file. */ node_emit_one_event(child, child->dir_subs, NULL, created_event); node_emit_one_event(child, child->subs, NULL, created_event); node_emit_one_event(child, f->dir_subs, NULL, created_event); node_emit_one_event(child, f->subs, NULL, created_event); } } /* else ignore, because it may be deleted. */ } } g_dir_close (dir); /* We have finished children snapshot. Any other new added subs should * directory iterate the snapshot instead of scan directory again. */ NODE_SET_FLAG(f, NODE_FLAG_SNAPSHOT_UPDATED); } else { FN_W (err->message); g_error_free (err); } }
/** * fen_add * * Won't hold a ref, we have a timout callback to clean unused node_t. * If there is no value for a key, add it and return it; else return the old * one. */ void fen_add (const gchar *filename, gpointer sub, gboolean is_mondir) { node_t* f; g_assert (filename); g_assert (sub); G_LOCK (fen_lock); f = node_find(NULL, filename, TRUE); FH_W ("%s 0x%p sub[0x%p] %s\n", __func__, f, sub, filename); g_assert (f); /* Update timestamp, the events in global queue will compare itself to this * timestamp to decide if be emitted. TODO, timestamp should be per sub. */ if (!NODE_IS_ACTIVE(f)) { g_get_current_time(&f->atv); } if (is_mondir) { f->dir_subs = g_list_prepend(f->dir_subs, sub); } else { f->subs = g_list_prepend(f->subs, sub); } if (NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED) || (node_lstat(f) == 0 && port_add(f) == 0)) { #ifndef GIO_COMPILATION gam_server_emit_one_event (NODE_NAME(f), gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1); #endif if (is_mondir) { scan_children_init (f, sub); } } else { #ifndef GIO_COMPILATION gam_server_emit_one_event (NODE_NAME(f), gam_subscription_is_dir (sub), GAMIN_EVENT_DELETED, sub, 1); #endif node_adjust_deleted (f); } #ifndef GIO_COMPILATION gam_server_emit_one_event (NODE_NAME(f), gam_subscription_is_dir (sub), GAMIN_EVENT_ENDEXISTS, sub, 1); #endif G_UNLOCK (fen_lock); }
/* * If all active children nodes are ported, then cancel monitor the parent * node. If we know how many children are created, then we can stop accordingly. * * Unsafe, need lock. */ static void foreach_known_children_scan(gpointer key, gpointer value, gpointer user_data) { node_t* f = (node_t*)value; FN_W ("%s 0x%p %s\n", __func__, f, NODE_NAME(f)); if (!NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED)) { if (node_lstat(f) == 0 && port_add(f) == 0) { node_emit_one_event(f, f->dir_subs, NULL, FN_EVENT_CREATED); node_emit_one_event(f, f->subs, NULL, FN_EVENT_CREATED); if (NODE_PARENT(f)) { node_emit_one_event(f, NODE_PARENT(f)->dir_subs, NULL, FN_EVENT_CREATED); node_emit_one_event(f, NODE_PARENT(f)->subs, NULL, FN_EVENT_CREATED); } } } }