View | Details | Raw Unified
Collapse All | Expand All

(-) server/gam_inotify.c (-7 / +18 lines)
 Lines 88-94    Link Here 
}
}
static void
static void
gam_inotify_add_rm_handler(const char *path, GamSubscription *sub, gboolean added)
gam_inotify_add_rm_handler(const char *path, GamSubscription *sub,
                           pollHandlerMode mode)
{
{
    INotifyData *data;
    INotifyData *data;
    struct inotify_watch_request iwr;
    struct inotify_watch_request iwr;
 Lines 96-102    Link Here 
    G_LOCK(inotify);
    G_LOCK(inotify);
    if (added) {
    if (mode == GAMIN_ACTIVATE) {
	GList *subs;
	GList *subs;
	subs = NULL;
	subs = NULL;
 Lines 116-126    Link Here 
            return;
            return;
        }
        }
	iwr.name = g_strdup(path);
	{
	iwr.mask = 0xffffffff; // all events
	    int file = open(path, O_RDONLY);
        wd = ioctl(fd, INOTIFY_WATCH, &iwr);
	    if (file < 0) {
        g_free(iwr.name);
		G_UNLOCK(inotify);
		return;
	    }
	    iwr.fd = file;
	    iwr.mask = 0xffffffff; // all events
	    wd = ioctl(fd, INOTIFY_WATCH, &iwr);
	    close (file);
	}
        if (wd < 0) {
        if (wd < 0) {
            G_UNLOCK(inotify);
            G_UNLOCK(inotify);
 Lines 136-142    Link Here 
	gam_server_emit_event (path, 0, GAMIN_EVENT_EXISTS, subs, 1);
	gam_server_emit_event (path, 0, GAMIN_EVENT_EXISTS, subs, 1);
	gam_server_emit_event (path, 0, GAMIN_EVENT_ENDEXISTS, subs, 1);
	gam_server_emit_event (path, 0, GAMIN_EVENT_ENDEXISTS, subs, 1);
    } else {
    } else if (mode == GAMIN_DESACTIVATE) {
        data = g_hash_table_lookup(path_hash, path);
        data = g_hash_table_lookup(path_hash, path);
        if (!data) {
        if (!data) {
 Lines 160-165    Link Here 
            g_hash_table_remove(wd_hash, GINT_TO_POINTER(data->wd));
            g_hash_table_remove(wd_hash, GINT_TO_POINTER(data->wd));
            gam_inotify_data_free(data);
            gam_inotify_data_free(data);
        }
        }
    } else {
        GAM_DEBUG(DEBUG_INFO, "Inotify: unimplemented mode request %d\n", mode);
    }
    }
    G_UNLOCK(inotify);
    G_UNLOCK(inotify);
}
}
(-) server/local_inotify.h (-15 / +10 lines)
 Lines 17-27    Link Here 
 * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd.
 * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd.
 */
 */
struct inotify_event {
struct inotify_event {
	__s32 wd;	/* watch descriptor */
	__s32		wd;		/* watch descriptor */
	__u32 mask;	/* watch mask */
	__u32		mask;		/* watch mask */
	__u32 cookie;	/* cookie used for synchronizing two events */
	__u32		cookie;		/* cookie to synchronize two events */
	size_t len;	/* length (including nulls) of name */
	__u32		len;		/* length (including nulls) of name */
	char name[0];	/* stub for possible name */
	char		name[0];	/* stub for possible name */
};
};
/*
/*
 Lines 30-37    Link Here 
 * Pass to the inotify device via the INOTIFY_WATCH ioctl
 * Pass to the inotify device via the INOTIFY_WATCH ioctl
 */
 */
struct inotify_watch_request {
struct inotify_watch_request {
	char *name;		/* directory name */
	int		fd;		/* fd of filename to watch */
	__u32 mask;		/* event mask */
	__u32		mask;		/* event mask */
};
};
/* the following are legal, implemented events */
/* the following are legal, implemented events */
 Lines 67-78    Link Here 
#include <linux/dcache.h>
#include <linux/dcache.h>
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/config.h>
#include <linux/config.h>
#include <asm/atomic.h>
struct inotify_inode_data {
	struct list_head watches;	/* list of watches on this inode */
	spinlock_t lock;		/* lock protecting the struct */
	atomic_t count;			/* ref count */
};
#ifdef CONFIG_INOTIFY
#ifdef CONFIG_INOTIFY
 Lines 82-88    Link Here 
					      const char *);
					      const char *);
extern void inotify_super_block_umount(struct super_block *);
extern void inotify_super_block_umount(struct super_block *);
extern void inotify_inode_is_dead(struct inode *);
extern void inotify_inode_is_dead(struct inode *);
extern __u32 inotify_get_cookie(void);
extern u32 inotify_get_cookie(void);
#else
#else
 Lines 106-112    Link Here 
{
{
}
}
static inline __u32 inotify_get_cookie(void)
static inline u32 inotify_get_cookie(void)
{
{
	return 0;
	return 0;
}
}
(-) server/gam_poll.h (-3 / +10 lines)
 Lines 8-14    Link Here 
G_BEGIN_DECLS
G_BEGIN_DECLS
typedef void (*GamPollHandler) (const char *path, gboolean added);
enum pollHandlerMode {
    GAMIN_ACTIVATE = 1,		/* Activate kernel monitoring */
    GAMIN_DESACTIVATE = 2,	/* Desactivate kernel monitoring */
    GAMIN_FLOWCONTROLSTART = 3,	/* Request flow control start */
    GAMIN_FLOWCONTROLSTOP = 4	/* Request flow control stop */
};
typedef enum pollHandlerMode pollHandlerMode;
typedef void (*GamPollHandler) (const char *path,
				pollHandlerMode mode);
gboolean   gam_poll_init_full             (gboolean start_scan_thread);
gboolean   gam_poll_init_full             (gboolean start_scan_thread);
 Lines 25-32    Link Here 
void       gam_poll_scan_directory        (const char *path);
void       gam_poll_scan_directory        (const char *path);
void       gam_poll_add_missing		  (GamNode *node);
void       gam_poll_remove_missing        (GamNode *node);
void       gam_poll_consume_subscriptions (void);
void       gam_poll_consume_subscriptions (void);
						 
						 
G_END_DECLS
G_END_DECLS
(-) server/gam_poll.c (-120 / +281 lines)
 Lines 63-68    Link Here 
static GamTree *tree = NULL;
static GamTree *tree = NULL;
static GList *new_subs = NULL;
static GList *new_subs = NULL;
static GList *missing_resources = NULL;
static GList *missing_resources = NULL;
static GList *busy_resources = NULL;
static GList *all_resources = NULL;
static GList *all_resources = NULL;
static GamPollHandler dir_handler = NULL;
static GamPollHandler dir_handler = NULL;
static GamPollHandler file_handler = NULL;
static GamPollHandler file_handler = NULL;
 Lines 78-97    Link Here 
    return(errno);
    return(errno);
}
}
/**
 * gam_poll_add_missing:
 * @node: a missing node
 *
 * Add a missing node to the list for polling its creation.
 */
static void
gam_poll_add_missing(GamNode *node) {
    GAM_DEBUG(DEBUG_INFO, "Poll adding missing node %s\n",
              gam_node_get_path(node));
    if (g_list_find(missing_resources, node) == NULL) {
	missing_resources = g_list_prepend(missing_resources, node);
    } else {
	GAM_DEBUG(DEBUG_INFO, "  already registered\n");
    }
}
/**
 * gam_poll_remove_missing:
 * @node: a missing node
 *
 * Remove a missing node from the list.
 */
static void
gam_poll_remove_missing(GamNode *node) {
    GAM_DEBUG(DEBUG_INFO, "Poll removing missing node %s\n",
              gam_node_get_path(node));
    missing_resources = g_list_remove_all(missing_resources, node);
}
/**
 * gam_poll_add_busy:
 * @node: a busy node
 *
 * Add a busy node to the list for polling its creation.
 */
static void
gam_poll_add_busy(GamNode *node) {
    GAM_DEBUG(DEBUG_INFO, "Poll adding busy node %s\n",
              gam_node_get_path(node));
    if (g_list_find(busy_resources, node) == NULL) {
	busy_resources = g_list_prepend(busy_resources, node);
    } else {
	GAM_DEBUG(DEBUG_INFO, "  already registered\n");
    }
}
/**
 * gam_poll_remove_busy:
 * @node: a busy node
 *
 * Remove a busy node from the list.
 */
static void
gam_poll_remove_busy(GamNode *node) {
    GAM_DEBUG(DEBUG_INFO, "Poll removing busy node %s\n",
              gam_node_get_path(node));
    busy_resources = g_list_remove_all(busy_resources, node);
}
/**
 * trigger_dir_handler:
 * @path: path to the directory
 * @mode: type of kernel monitoring action
 *
 * Interface to the kernel monitoring layer for directories
 */
static void
static void
trigger_dir_handler(const char *path, gboolean added)
trigger_dir_handler(const char *path, pollHandlerMode mode)
{
{
    if (dir_handler != NULL)
    if (dir_handler != NULL)
        (*dir_handler) (path, added);
        (*dir_handler) (path, mode);
}
}
/**
 * trigger_file_handler:
 * @path: path to the file
 * @mode: type of kernel monitoring action
 *
 * Interface to the kernel monitoring layer for files
 */
static void
static void
trigger_file_handler(const char *path, gboolean added)
trigger_file_handler(const char *path, pollHandlerMode mode)
{
{
    if (file_handler != NULL)
    if (file_handler != NULL)
        (*file_handler) (path, added);
        (*file_handler) (path, mode);
}
}
/**
 * node_add_subscription:
 * @node: the node tree pointer
 * @sub: the pointer to the subscription
 *
 * register a subscription for this node
 *
 * Returns 0 in case of success and -1 in case of failure
 */
static int
static int
node_add_subscription(GamNode * node, GamSubscription * sub)
node_add_subscription(GamNode * node, GamSubscription * sub)
{
{
 Lines 114-126    Link Here 
    }
    }
    if (gam_node_is_dir(node))
    if (gam_node_is_dir(node))
        trigger_dir_handler(node->path, TRUE);
        trigger_dir_handler(node->path, GAMIN_ACTIVATE);
    else
    else
        trigger_file_handler(node->path, TRUE);
        trigger_file_handler(node->path, GAMIN_ACTIVATE);
    return(0);
    return(0);
}
}
/**
 * node_remove_subscription:
 * @node: the node tree pointer
 * @sub: the pointer to the subscription
 *
 * Removes a subscription for this node
 *
 * Returns 0 in case of success and -1 in case of failure
 */
static int
static int
node_remove_subscription(GamNode * node, GamSubscription * sub)
node_remove_subscription(GamNode * node, GamSubscription * sub)
{
{
 Lines 145-168    Link Here 
    /* DNotify makes our life miserable here */
    /* DNotify makes our life miserable here */
    if (gam_subscription_is_dir(sub)) {
    if (gam_subscription_is_dir(sub)) {
	if (gam_node_is_dir(node))
	if (gam_node_is_dir(node))
	    trigger_dir_handler(path, FALSE);
	    trigger_dir_handler(path, GAMIN_DESACTIVATE);
	else {
	else {
	    char *dir;
	    char *dir;
	    dir = g_path_get_dirname(path);
	    dir = g_path_get_dirname(path);
	    trigger_file_handler(dir, FALSE);
	    trigger_file_handler(dir, GAMIN_DESACTIVATE);
	    g_free(dir);
	    g_free(dir);
	}
	}
    } else {
    } else {
	if (gam_node_is_dir(node))
	if (gam_node_is_dir(node))
	    trigger_dir_handler(path, FALSE);
	    trigger_dir_handler(path, GAMIN_DESACTIVATE);
	else
	else
	    trigger_file_handler(path, FALSE);
	    trigger_file_handler(path, GAMIN_DESACTIVATE);
    }
    }
    return(0);
    return(0);
}
}
/**
 * gam_poll_data_new:
 * @path: the path
 *
 * Creates a new data block for that path
 *
 * Returns the pointer to the block or NULL in case of failure
 */
static GamPollData *
static GamPollData *
gam_poll_data_new(const char *path)
gam_poll_data_new(const char *path)
{
{
 Lines 189-201    Link Here 
    return data;
    return data;
}
}
/**
 * gam_poll_data_destroy:
 * @data: pointer to the data block
 *
 * Destroys a data block.
 */
static void
gam_poll_data_destroy(GamPollData * data)
{
    if (data != NULL) {
	if (data->path != NULL)
	    g_free(data->path);
	g_free(data);
    }
}
static void
static void
gam_poll_emit_event(GamNode * node, GaminEventType event,
gam_poll_emit_event(GamNode * node, GaminEventType event)
                    GList * exist_subs)
{
{
    GList *l;
    GList *l;
    GamNode *parent;
    GamNode *parent;
    GamPollData *data;
    GList *subs;
    GList *subs;
    int is_dir_node = gam_node_is_dir(node);
    int is_dir_node = gam_node_is_dir(node);
 Lines 215-258    Link Here 
        }
        }
    }
    }
    if (exist_subs) {
    gam_server_emit_event(gam_node_get_path(node), is_dir_node, event, subs, 0);
        data = gam_node_get_data(node);
        for (l = subs; l; l = l->next) {
            GamSubscription *sub = l->data;
            GaminEventType new_event = event;
	    GList *tmp;
            if (g_list_find(exist_subs, sub)) {
                if ((data) && (!(data->flags & MON_MISSING)))
                    new_event = GAMIN_EVENT_EXISTS;
                else
                    continue;
            }
            tmp = g_list_prepend(NULL, sub);
            gam_server_emit_event(gam_node_get_path(node), is_dir_node,
                                  new_event, tmp, 0);
	    g_list_free(tmp);
        }
    } else {
        
        gam_server_emit_event(gam_node_get_path(node), is_dir_node, event,
	                      subs, 0);
    }
    g_list_free(subs);
    g_list_free(subs);
}
}
static void
gam_poll_data_destroy(GamPollData * data)
{
    g_free(data->path);
    g_free(data);
}
/**
/**
 * gam_poll_delist_node:
 * gam_poll_delist_node:
 * @node: the node to delist
 * @node: the node to delist
 Lines 263-278    Link Here 
static void
static void
gam_poll_delist_node(GamNode * node) {
gam_poll_delist_node(GamNode * node) {
    GList *subs;
    GList *subs;
    const char *path;
    GAM_DEBUG(DEBUG_INFO, "gam_poll_delist_node %s\n",
    path = gam_node_get_path(node);
              gam_node_get_path(node));
    GAM_DEBUG(DEBUG_INFO, "gam_poll_delist_node %s\n", path);
    if (gam_exclude_check(path))
        return;
    subs = gam_node_get_subscriptions(node);
    subs = gam_node_get_subscriptions(node);
    while (subs != NULL) {
    while (subs != NULL) {
	if (gam_node_is_dir(node))
	if (gam_node_is_dir(node))
	    trigger_dir_handler(gam_node_get_path(node), FALSE);
	    trigger_dir_handler(path, GAMIN_DESACTIVATE);
	else
	else
	    trigger_file_handler(gam_node_get_path(node), FALSE);
	    trigger_file_handler(path, GAMIN_DESACTIVATE);
	subs = subs->next;
	subs = subs->next;
    }
    }
}
}
 Lines 287-306    Link Here 
static void
static void
gam_poll_relist_node(GamNode * node) {
gam_poll_relist_node(GamNode * node) {
    GList *subs;
    GList *subs;
    const char *path;
    GAM_DEBUG(DEBUG_INFO, "gam_poll_relist_node %s\n",
    path = gam_node_get_path(node);
              gam_node_get_path(node));
    GAM_DEBUG(DEBUG_INFO, "gam_poll_relist_node %s\n", path);
    if (gam_exclude_check(path))
        return;
    subs = gam_node_get_subscriptions(node);
    subs = gam_node_get_subscriptions(node);
    while (subs != NULL) {
    while (subs != NULL) {
	if (gam_node_is_dir(node))
	if (gam_node_is_dir(node))
	    trigger_dir_handler(gam_node_get_path(node), TRUE);
	    trigger_dir_handler(path, GAMIN_ACTIVATE);
	else
	else
	    trigger_file_handler(gam_node_get_path(node), TRUE);
	    trigger_file_handler(path, GAMIN_ACTIVATE);
	subs = subs->next;
	subs = subs->next;
    }
    }
}
}
/**
 * gam_poll_flowon_node:
 * @node: the node to delist
 *
 * This function is called when kernel monitoring flow control for a
 * node should be started
 */
static void
gam_poll_flowon_node(GamNode * node) {
    const char *path;
    path = gam_node_get_path(node);
    GAM_DEBUG(DEBUG_INFO, "gam_poll_flowon_node %s\n",path);
    if (gam_exclude_check(path))
        return;
    if (gam_node_is_dir(node))
	trigger_dir_handler(path, GAMIN_FLOWCONTROLSTART);
    else
	trigger_file_handler(path, GAMIN_FLOWCONTROLSTART);
}
/**
 * gam_poll_flowoff_node:
 * @node: the node to delist
 *
 * This function is called when kernel monitoring flow control for a
 * node should be started
 */
static void
gam_poll_flowoff_node(GamNode * node) {
    const char *path;
    path = gam_node_get_path(node);
    GAM_DEBUG(DEBUG_INFO, "gam_poll_flowoff_node %s\n", path);
    if (gam_exclude_check(path))
        return;
    if (gam_node_is_dir(node))
	trigger_dir_handler(path, GAMIN_FLOWCONTROLSTOP);
    else
	trigger_file_handler(path, GAMIN_FLOWCONTROLSTOP);
}
static GaminEventType
static GaminEventType
poll_file(GamNode * node)
poll_file(GamNode * node)
 Lines 350-355    Link Here 
            /* deleted */
            /* deleted */
            data->flags = MON_MISSING;
            data->flags = MON_MISSING;
	    gam_poll_remove_busy(node);
	    if (gam_node_get_subscriptions(node) != NULL) {
	    if (gam_node_get_subscriptions(node) != NULL) {
		gam_poll_delist_node(node);
		gam_poll_delist_node(node);
	        gam_poll_add_missing(node);
	        gam_poll_add_missing(node);
 Lines 398-404    Link Here 
    /*
    /*
     * load control, switch back to poll on very busy resources
     * load control, switch back to poll on very busy resources
     * and back when no update has happened in 10 seconds
     * and back when no update has happened in 5 seconds
     */
     */
    if (current_time == data->lasttime) {
    if (current_time == data->lasttime) {
	if (!(data->flags & MON_BUSY)) {
	if (!(data->flags & MON_BUSY)) {
 Lines 416-439    Link Here 
    }
    }
    if ((data->checks >= 4) && (!(data->flags & MON_BUSY))) {
    if ((data->checks >= 4) && (!(data->flags & MON_BUSY))) {
	if (gam_node_get_subscriptions(node) != NULL) {
	if ((gam_node_get_subscriptions(node) != NULL) &&
	    (!gam_exclude_check(data->path))) {
	    GAM_DEBUG(DEBUG_INFO, "switching %s back to polling\n", path);
	    GAM_DEBUG(DEBUG_INFO, "switching %s back to polling\n", path);
	    data->flags |= MON_BUSY;
	    data->flags |= MON_BUSY;
	    data->checks = 0;
	    data->checks = 0;
	    gam_poll_add_missing(node);
	    gam_poll_add_busy(node);
	    gam_poll_delist_node(node);
	    gam_poll_flowon_node(node);
	    /*
	     * DNotify can be nasty here, we will miss events for parent dir
	     * if we are not careful about it
	     */
	    if (!gam_node_is_dir(node)) {
	        GamNode *parent = gam_node_parent(node);
		if ((parent != NULL) &&
		    (gam_node_get_subscriptions(parent) != NULL)) {
		    gam_poll_add_busy(parent);
		    /* gam_poll_flowon_node(parent); */
		}
	    }
	}
	}
    }
    }
    if ((event == 0) && (data->flags & MON_BUSY) && (data->checks > 10)) {
    if ((event == 0) && (data->flags & MON_BUSY) && (data->checks > 5)) {
	if ((gam_node_get_subscriptions(node) != NULL) &&
	if ((gam_node_get_subscriptions(node) != NULL) &&
	    (!gam_exclude_check(data->path))) {
	    (!gam_exclude_check(data->path))) {
	    GAM_DEBUG(DEBUG_INFO, "switching %s back to kernel monitoring\n",
	    GAM_DEBUG(DEBUG_INFO, "switching %s back to kernel monitoring\n",
	              path);
	              path);
	    data->flags &= ~MON_BUSY;
	    data->flags &= ~MON_BUSY;
	    data->checks = 0;
	    data->checks = 0;
	    gam_poll_remove_missing(node);
	    gam_poll_remove_busy(node);
	    gam_poll_relist_node(node);
	    gam_poll_flowoff_node(node);
	}
	}
    }
    }
 Lines 466-472    Link Here 
    event = poll_file(dir_node);
    event = poll_file(dir_node);
    if (event != 0)
    if (event != 0)
	gam_poll_emit_event(dir_node, event, NULL);
	gam_poll_emit_event(dir_node, event);
    dir = g_dir_open(dpath, 0, NULL);
    dir = g_dir_open(dpath, 0, NULL);
 Lines 523-529    Link Here 
	}
	}
        if (fevent != 0) {
        if (fevent != 0) {
            gam_poll_emit_event(node, fevent, NULL);
            gam_poll_emit_event(node, fevent);
        } else {
        } else {
	    GamPollData *data;
	    GamPollData *data;
 Lines 562-567    Link Here 
	    if (missing_resources != NULL) {
	    if (missing_resources != NULL) {
		gam_poll_remove_missing (child);
		gam_poll_remove_missing (child);
	    }
	    }
	    if (busy_resources != NULL) {
		gam_poll_remove_busy (child);
	    }
	    gam_tree_remove(tree, child);
	    gam_tree_remove(tree, child);
	} else {
	} else {
	    remove_dir = FALSE;
	    remove_dir = FALSE;
 Lines 579-586    Link Here 
    static int in_poll_callback = 0;
    static int in_poll_callback = 0;
#ifdef VERBOSE_POLL
#ifdef VERBOSE_POLL
    GAM_DEBUG(DEBUG_INFO, "gam_poll_scan_callback(): %d, %d items\n",
    GAM_DEBUG(DEBUG_INFO, "gam_poll_scan_callback(): %d, %d missing, %d busy\n",
              in_poll_callback, g_list_length(missing_resources));
              in_poll_callback, g_list_length(missing_resources),
	      g_list_length(busy_resources));
#endif
#endif
    if (in_poll_callback)
    if (in_poll_callback)
	return(TRUE);
	return(TRUE);
 Lines 620-626    Link Here 
	    GaminEventType event;
	    GaminEventType event;
	    event = poll_file(node);
	    event = poll_file(node);
	    gam_poll_emit_event(node, event, NULL);
	    gam_poll_emit_event(node, event);
	}
	}
	/*
	/*
 Lines 635-640    Link Here 
	}
	}
    }
    }
    for (idx = 0;;idx++) {
	GamPollData *data;
	GamNode *node;
	
	/*
	 * do not simply walk the list as it may be modified in the callback
	 */
	node = (GamNode *) g_list_nth_data(busy_resources, idx);
	
	if (node == NULL) {
#ifdef VERBOSE_POLL
	    GAM_DEBUG(DEBUG_INFO, "  node %d == NULL\n", idx);
#endif
	    break;
	} 
	data = gam_node_get_data(node);
	if (data == NULL) {
#ifdef VERBOSE_POLL
	    GAM_DEBUG(DEBUG_INFO, "  data %d == NULL\n", idx);
#endif
	    break;
	} 
#ifdef VERBOSE_POLL
	GAM_DEBUG(DEBUG_INFO, "Checking busy file %s", data->path);
#endif
	if (node->is_dir) {
	    gam_poll_scan_directory_internal(node);
	} else {
	    GaminEventType event;
	    event = poll_file(node);
	    gam_poll_emit_event(node, event);
	}
	/*
	 * if the resource exists again and is not in a special monitoring
	 * mode then switch back to dnotify for monitoring.
	 */
	if ((data->flags == 0) && (!gam_exclude_check(data->path))) {
	    gam_poll_remove_busy(node);
	    if (gam_node_get_subscriptions(node) != NULL) {
		gam_poll_flowoff_node(node);
	    }
	}
    }
    in_poll_callback = 0;
    in_poll_callback = 0;
    return(TRUE);
    return(TRUE);
}
}
 Lines 656-665    Link Here 
        parent = gam_node_parent(node);
        parent = gam_node_parent(node);
        if (missing_resources != NULL) {
        if (missing_resources != NULL) {
		gam_poll_remove_missing(node);
	    gam_poll_remove_missing(node);
        }
        if (busy_resources != NULL) {
	    gam_poll_remove_busy(node);
        }
        }
        if (all_resources != NULL) {
        if (all_resources != NULL) {
                all_resources = g_list_remove (all_resources, node);
	    all_resources = g_list_remove (all_resources, node);
        }
        }
	gam_tree_remove(tree, node);
	gam_tree_remove(tree, node);
        prune_tree(parent);
        prune_tree(parent);
 Lines 741-797    Link Here 
    return(TRUE);
    return(TRUE);
}
}
/**
 * @defgroup Polling Polling Backend
 * @ingroup Backends
 * @brief Polling backend API
 *
 * This is the default backend used in Gamin.  It basically just calls
 * stat() on files/directories every so often to see when things change.  The
 * statting happens in a separate thread, controllable with arguments to
 * #gam_poll_init_full().
 *
 * @{
 */
/**
 * gam_poll_add_missing:
 * @node: a missing node
 *
 * Add a missing node to the list for polling its creation.
 */
void
gam_poll_add_missing(GamNode *node) {
#if 0
    fprintf(stderr, "Adding %s to polling\n", gam_node_get_path(node));
#endif
    GAM_DEBUG(DEBUG_INFO, "Poll adding missing node %s\n",
              gam_node_get_path(node));
    if (g_list_find(missing_resources, node) == NULL) {
	missing_resources = g_list_prepend(missing_resources, node);
    } else {
	GAM_DEBUG(DEBUG_INFO, "  already registered\n");
    }
}
/**
 * gam_poll_remove_missing:
 * @node: a missing node
 *
 * Remove a missing node from the list.
 */
void
gam_poll_remove_missing(GamNode *node) {
#if 0
    fprintf(stderr, "Removing %s from polling\n", gam_node_get_path(node));
#endif
    GAM_DEBUG(DEBUG_INFO, "Poll removing missing node %s\n",
              gam_node_get_path(node));
    missing_resources = g_list_remove_all(missing_resources, node);
}
/**
/**
 * Initializes the polling system.  This must be called before
 * Initializes the polling system.  This must be called before
 * any other functions in this module.
 * any other functions in this module.
 Lines 889-894    Link Here 
                if (missing_resources != NULL) {
                if (missing_resources != NULL) {
                    gam_poll_remove_missing(node);
                    gam_poll_remove_missing(node);
                }
                }
                if (busy_resources != NULL) {
                    gam_poll_remove_busy(node);
                }
                if (all_resources != NULL) {
                if (all_resources != NULL) {
                    all_resources = g_list_remove(all_resources, node);
                    all_resources = g_list_remove(all_resources, node);
                }
                }
 Lines 912-917    Link Here 
                if (missing_resources != NULL) {
                if (missing_resources != NULL) {
                    gam_poll_remove_missing(node);
                    gam_poll_remove_missing(node);
                }
                }
                if (busy_resources != NULL) {
                    gam_poll_remove_busy(node);
                }
                if (all_resources != NULL) {
                if (all_resources != NULL) {
                    all_resources = g_list_remove(all_resources, node);
                    all_resources = g_list_remove(all_resources, node);
                }
                }
(-) server/gam_dnotify.c (-17 / +99 lines)
 Lines 42-47    Link Here 
    char *path;
    char *path;
    int fd;
    int fd;
    int refcount;
    int refcount;
    int busy;
} DNotifyData;
} DNotifyData;
static GHashTable *path_hash = NULL;
static GHashTable *path_hash = NULL;
 Lines 65-70    Link Here 
    data = g_new0(DNotifyData, 1);
    data = g_new0(DNotifyData, 1);
    data->path = g_strdup(path);
    data->path = g_strdup(path);
    data->fd = fd;
    data->fd = fd;
    data->busy = 0;
    data->refcount = 1;
    data->refcount = 1;
    return data;
    return data;
 Lines 78-97    Link Here 
}
}
static void
static void
gam_dnotify_directory_handler_internal(const char *path, gboolean added)
gam_dnotify_directory_handler_internal(const char *path, pollHandlerMode mode)
{
{
    DNotifyData *data;
    DNotifyData *data;
    int fd;
    int fd;
    if (added) {
    switch (mode) {
	GAM_DEBUG(DEBUG_INFO, "Adding %s to dnotify\n", path);
        case GAMIN_ACTIVATE:
    } else {
	    GAM_DEBUG(DEBUG_INFO, "Adding %s to dnotify\n", path);
        GAM_DEBUG(DEBUG_INFO, "Removing %s from dnotify\n", path);
	    break;
        case GAMIN_DESACTIVATE:
	    GAM_DEBUG(DEBUG_INFO, "Removing %s from dnotify\n", path);
	    break;
	case GAMIN_FLOWCONTROLSTART:
	    GAM_DEBUG(DEBUG_INFO, "Start flow control for %s\n", path);
	    break;
	case GAMIN_FLOWCONTROLSTOP:
	    GAM_DEBUG(DEBUG_INFO, "Stop flow control for %s\n", path);
	    break;
	default:
	    gam_error(DEBUG_INFO, "Unknown DNotify operation %d for %s\n",
	              mode, path);
	    return;
    }
    }
    G_LOCK(dnotify);
    G_LOCK(dnotify);
    if (added) {
    if (mode == GAMIN_ACTIVATE) {
        if ((data = g_hash_table_lookup(path_hash, path)) != NULL) {
        if ((data = g_hash_table_lookup(path_hash, path)) != NULL) {
            data->refcount++;
            data->refcount++;
 Lines 123-130    Link Here 
#ifdef GAMIN_DEBUG_API
#ifdef GAMIN_DEBUG_API
        gam_debug_report(GAMDnotifyCreate, path, 0);
        gam_debug_report(GAMDnotifyCreate, path, 0);
#endif
#endif
    } else {
    } else if (mode == GAMIN_DESACTIVATE) {
	char *dir = path;
	char *dir = (char *) path;
        data = g_hash_table_lookup(path_hash, path);
        data = g_hash_table_lookup(path_hash, path);
 Lines 165-206    Link Here 
	}
	}
	if ((dir != path) && (dir != NULL))
	if ((dir != path) && (dir != NULL))
	    g_free(dir);
	    g_free(dir);
    } else if ((mode == GAMIN_FLOWCONTROLSTART) ||
               (mode == GAMIN_FLOWCONTROLSTOP)) {
	char *dir = (char *) path;
	data = g_hash_table_lookup(path_hash, path);
	if (!data) {
	    dir = g_path_get_dirname(path);
	    data = g_hash_table_lookup(path_hash, dir);
            if (!data) {
		GAM_DEBUG(DEBUG_INFO, "  not found !!!\n");
		if (dir != NULL)
		    g_free(dir);
		G_UNLOCK(dnotify);
		return;
	    }
	    GAM_DEBUG(DEBUG_INFO, "  not found using parent\n");
        }
        if (data != NULL) {
	    if (mode == GAMIN_FLOWCONTROLSTART) {
		if (data->fd >= 0) {
		    close(data->fd);
		    g_hash_table_remove(fd_hash, GINT_TO_POINTER(data->fd));
		    data->fd = -1;
		    GAM_DEBUG(DEBUG_INFO, "deactivated DNotify for %s\n",
			      data->path);
#ifdef GAMIN_DEBUG_API
		    gam_debug_report(GAMDnotifyFlowOn, dir, 0);
#endif
		}
		data->busy++;
	    } else {
	        if (data->busy > 0) {
		    data->busy--;
		    if (data->busy == 0) {
			fd = open(data->path, O_RDONLY);
			if (fd < 0) {
			    G_UNLOCK(dnotify);
			    GAM_DEBUG(DEBUG_INFO,
			              "Failed to reactivate DNotify for %s\n",
				      data->path);
			    if ((dir != path) && (dir != NULL))
				g_free(dir);
			    return;
			}
			data->fd = fd;
			g_hash_table_insert(fd_hash, GINT_TO_POINTER(data->fd),
			                    data);
			fcntl(fd, F_SETSIG, SIGRTMIN);
			fcntl(fd, F_NOTIFY,
			      DN_MODIFY | DN_CREATE | DN_DELETE | DN_RENAME |
			      DN_ATTRIB | DN_MULTISHOT);
			GAM_DEBUG(DEBUG_INFO, "Reactivated DNotify for %s\n",
			          data->path);
#ifdef GAMIN_DEBUG_API
			gam_debug_report(GAMDnotifyFlowOff, path, 0);
#endif
		    }
		}
	    }
	}
	if ((dir != path) && (dir != NULL))
	    g_free(dir);
    } else {
	GAM_DEBUG(DEBUG_INFO, "Unimplemented operation\n");
    }
    }
    G_UNLOCK(dnotify);
    G_UNLOCK(dnotify);
}
}
static void
static void
gam_dnotify_directory_handler(const char *path, gboolean added)
gam_dnotify_directory_handler(const char *path, pollHandlerMode mode)
{
{
    GAM_DEBUG(DEBUG_INFO, "gam_dnotify_directory_handler %s : %d\n",
    GAM_DEBUG(DEBUG_INFO, "gam_dnotify_directory_handler %s : %d\n",
              path, added);
              path, mode);
    if ((!added) || (g_file_test(path, G_FILE_TEST_IS_DIR))) {
    if ((mode == GAMIN_DESACTIVATE) ||
	gam_dnotify_directory_handler_internal(path, added);
        (g_file_test(path, G_FILE_TEST_IS_DIR))) {
	gam_dnotify_directory_handler_internal(path, mode);
    } else {
    } else {
	char *dir;
	char *dir;
	dir = g_path_get_dirname(path);
	dir = g_path_get_dirname(path);
	GAM_DEBUG(DEBUG_INFO, " not a dir using parent %s\n", dir);
	GAM_DEBUG(DEBUG_INFO, " not a dir using parent %s\n", dir);
	gam_dnotify_directory_handler_internal(dir, added);
	gam_dnotify_directory_handler_internal(dir, mode);
	g_free(dir);
	g_free(dir);
    }
    }
}
}
static void
static void
gam_dnotify_file_handler(const char *path, gboolean added)
gam_dnotify_file_handler(const char *path, pollHandlerMode mode)
{
{
    GAM_DEBUG(DEBUG_INFO, "gam_dnotify_file_handler %s : %d\n", path, added);
    GAM_DEBUG(DEBUG_INFO, "gam_dnotify_file_handler %s : %d\n", path, mode);
    
    
    if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
    if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
	gam_dnotify_directory_handler_internal(path, added);
	gam_dnotify_directory_handler_internal(path, mode);
    } else {
    } else {
	char *dir;
	char *dir;
	dir = g_path_get_dirname(path);
	dir = g_path_get_dirname(path);
	GAM_DEBUG(DEBUG_INFO, " not a dir using parent %s\n", dir);
	GAM_DEBUG(DEBUG_INFO, " not a dir using parent %s\n", dir);
	gam_dnotify_directory_handler_internal(dir, added);
	gam_dnotify_directory_handler_internal(dir, mode);
	g_free(dir);
	g_free(dir);
    }
    }
}
}
(-) server/gam_debugging.c (+2 lines)
 Lines 53-58    Link Here 
        case GAMDnotifyCreate:
        case GAMDnotifyCreate:
        case GAMDnotifyDelete:
        case GAMDnotifyDelete:
        case GAMDnotifyChange:
        case GAMDnotifyChange:
        case GAMDnotifyFlowOn:
        case GAMDnotifyFlowOff:
	    connlist = gamDebugNotify;
	    connlist = gamDebugNotify;
	    break;
	    break;
    }
    }
(-) server/gam_debugging.h (-1 / +3 lines)
 Lines 10-16    Link Here 
typedef enum {
typedef enum {
    GAMDnotifyCreate=1,
    GAMDnotifyCreate=1,
    GAMDnotifyDelete=2,
    GAMDnotifyDelete=2,
    GAMDnotifyChange=3
    GAMDnotifyChange=3,
    GAMDnotifyFlowOn=4,
    GAMDnotifyFlowOff=5
} GAMDebugEvent;
} GAMDebugEvent;
void gam_debug_add(GamConnDataPtr conn, const char *value, int options);
void gam_debug_add(GamConnDataPtr conn, const char *value, int options);
(-) libgamin/gam_api.c (-14 / +38 lines)
 Lines 13-18    Link Here 
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/un.h>
#include <sys/uio.h>
#include "fam.h"
#include "fam.h"
#include "gam_protocol.h"
#include "gam_protocol.h"
#include "gam_data.h"
#include "gam_data.h"
 Lines 181-187    Link Here 
    snprintf(path, MAXPATHLEN, "/tmp/fam-%s", user);
    snprintf(path, MAXPATHLEN, "/tmp/fam-%s", user);
    path[MAXPATHLEN] = 0;
    path[MAXPATHLEN] = 0;
    ret = strdup(path);
    ret = strdup(path);
    free(user);
    return (ret);
    return (ret);
}
}
 Lines 421-429    Link Here 
{
{
    char data[2] = { 0, 0 };
    char data[2] = { 0, 0 };
    int written;
    int written;
#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
    struct {
	    struct cmsghdr hdr;
	    struct cmsgcred cred;
    } cmsg;
    struct iovec iov;
    struct msghdr msg;
    iov.iov_base = &data[0];
    iov.iov_len = 1;
    memset (&msg, 0, sizeof (msg));
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;
    msg.msg_control = &cmsg;
    msg.msg_controllen = sizeof (cmsg);
    memset (&cmsg, 0, sizeof (cmsg));
    cmsg.hdr.cmsg_len = sizeof (cmsg);
    cmsg.hdr.cmsg_level = SOL_SOCKET;
    cmsg.hdr.cmsg_type = SCM_CREDS;
#endif
retry:
retry:
#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
    written = sendmsg(fd, &msg, 0);
#else
    written = write(fd, &data[0], 1);
    written = write(fd, &data[0], 1);
#endif
    if (written < 0) {
    if (written < 0) {
        if (errno == EINTR)
        if (errno == EINTR)
            goto retry;
            goto retry;
 Lines 616-623    Link Here 
    gid_t c_gid;
    gid_t c_gid;
#ifdef HAVE_CMSGCRED
#ifdef HAVE_CMSGCRED
    char cmsgmem[CMSG_SPACE(sizeof(struct cmsgcred))];
    struct {
    struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
	    struct cmsghdr hdr;
	    struct cmsgcred cred;
    } cmsg;
#endif
#endif
    s_uid = getuid();
    s_uid = getuid();
 Lines 642-650    Link Here 
    msg.msg_iovlen = 1;
    msg.msg_iovlen = 1;
#ifdef HAVE_CMSGCRED
#ifdef HAVE_CMSGCRED
    memset(cmsgmem, 0, sizeof(cmsgmem));
    memset(&cmsg, 0, sizeof(cmsg));
    msg.msg_control = cmsgmem;
    msg.msg_control = &cmsg;
    msg.msg_controllen = sizeof(cmsgmem);
    msg.msg_controllen = sizeof(cmsg);
#endif
#endif
retry:
retry:
 Lines 661-667    Link Here 
        goto failed;
        goto failed;
    }
    }
#ifdef HAVE_CMSGCRED
#ifdef HAVE_CMSGCRED
    if (cmsg->cmsg_len < sizeof(cmsgmem) || cmsg->cmsg_type != SCM_CREDS) {
    if (cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS) {
        GAM_DEBUG(DEBUG_INFO,
        GAM_DEBUG(DEBUG_INFO,
                  "Message from recvmsg() was not SCM_CREDS\n");
                  "Message from recvmsg() was not SCM_CREDS\n");
        goto failed;
        goto failed;
 Lines 687-699    Link Here 
            goto failed;
            goto failed;
        }
        }
#elif defined(HAVE_CMSGCRED)
#elif defined(HAVE_CMSGCRED)
        struct cmsgcred *cred;
        c_pid = cmsg.cred.cmcred_pid;
        c_uid = cmsg.cred.cmcred_euid;
        cred = (struct cmsgcred *) CMSG_DATA(cmsg);
        c_gid = cmsg.cred.cmcred_groups[0];
        c_pid = cred->cmcred_pid;
        c_uid = cred->cmcred_euid;
        c_gid = cred->cmcred_groups[0];
#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
        GAM_DEBUG(DEBUG_INFO,
        GAM_DEBUG(DEBUG_INFO,
                  "Socket credentials not supported on this OS\n");
                  "Socket credentials not supported on this OS\n");
(-) server/gam_channel.c (-13 / +13 lines)
 Lines 6-11    Link Here 
#include <sys/socket.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/un.h>
#include <sys/uio.h>
#include "gam_error.h"
#include "gam_error.h"
#include "gam_connection.h"
#include "gam_connection.h"
#include "gam_channel.h"
#include "gam_channel.h"
 Lines 49-56    Link Here 
    gid_t c_gid;
    gid_t c_gid;
#ifdef HAVE_CMSGCRED
#ifdef HAVE_CMSGCRED
    char cmsgmem[CMSG_SPACE(sizeof(struct cmsgcred))];
    struct {
    struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
	    struct cmsghdr hdr;
	    struct cmsgcred cred;
    } cmsg;
#endif
#endif
    s_uid = getuid();
    s_uid = getuid();
 Lines 75-83    Link Here 
    msg.msg_iovlen = 1;
    msg.msg_iovlen = 1;
#ifdef HAVE_CMSGCRED
#ifdef HAVE_CMSGCRED
    memset(cmsgmem, 0, sizeof(cmsgmem));
    memset(&cmsg, 0, sizeof(cmsg));
    msg.msg_control = cmsgmem;
    msg.msg_control = &cmsg;
    msg.msg_controllen = sizeof(cmsgmem);
    msg.msg_controllen = sizeof(cmsg);
#endif
#endif
  retry:
  retry:
 Lines 94-100    Link Here 
        goto failed;
        goto failed;
    }
    }
#ifdef HAVE_CMSGCRED
#ifdef HAVE_CMSGCRED
    if (cmsg->cmsg_len < sizeof(cmsgmem) || cmsg->cmsg_type != SCM_CREDS) {
    if (cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS) {
        GAM_DEBUG(DEBUG_INFO,
        GAM_DEBUG(DEBUG_INFO,
                  "Message from recvmsg() was not SCM_CREDS\n");
                  "Message from recvmsg() was not SCM_CREDS\n");
        goto failed;
        goto failed;
 Lines 120-132    Link Here 
            goto failed;
            goto failed;
        }
        }
#elif defined(HAVE_CMSGCRED)
#elif defined(HAVE_CMSGCRED)
        struct cmsgcred *cred;
	c_pid = cmsg.cred.cmcred_pid;
	c_uid = cmsg.cred.cmcred_euid;
        cred = (struct cmsgcred *) CMSG_DATA(cmsg);
	c_gid = cmsg.cred.cmcred_groups[0];
        c_pid = cred->cmcred_pid;
        c_uid = cred->cmcred_euid;
        c_gid = cred->cmcred_groups[0];
#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
        GAM_DEBUG(DEBUG_INFO,
        GAM_DEBUG(DEBUG_INFO,
                  "Socket credentials not supported on this OS\n");
                  "Socket credentials not supported on this OS\n");
 Lines 305-310    Link Here 
        gam_client_id = g_getenv("GAM_CLIENT_ID");
        gam_client_id = g_getenv("GAM_CLIENT_ID");
        if (gam_client_id == NULL) {
        if (gam_client_id == NULL) {
            GAM_DEBUG(DEBUG_INFO, "Error getting GAM_CLIENT_ID\n");
            GAM_DEBUG(DEBUG_INFO, "Error getting GAM_CLIENT_ID\n");
	    gam_client_id = "";
        }
        }
    } else {
    } else {
        gam_client_id = session;
        gam_client_id = session;
(-) configure.in (-2 / +2 lines)
 Lines 149-155    Link Here 
AM_CONDITIONAL(GAMIN_DEBUG, test x$debug = xyes)
AM_CONDITIONAL(GAMIN_DEBUG, test x$debug = xyes)
debug_api=no
debug_api=no
if test "`hostname`" == "paphio" -a "`pwd`" == "/u/veillard/gamin"
if test "`hostname`" = "paphio" -a "`pwd`" = "/u/veillard/gamin"
then
then
    debug_api=yes
    debug_api=yes
fi
fi
 Lines 403-409    Link Here 
AC_SUBST(PYTHON_VERSION)
AC_SUBST(PYTHON_VERSION)
AC_SUBST(PYTHON_SUBDIR)
AC_SUBST(PYTHON_SUBDIR)
AC_SUBST(PYTHON_INCLUDES)
AC_SUBST(PYTHON_INCLUDES)
AC_SUBST(PYTHON_PYTHON_SITE_PACKAGES)
AC_SUBST(PYTHON_SITE_PACKAGES)
dnl ==========================================================================
dnl ==========================================================================