~ubuntu-branches/debian/jessie/gamin/jessie

« back to all changes in this revision

Viewing changes to server/gam_inotify.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Banck
  • Date: 2007-03-23 14:43:49 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20070323144349-1inpdk22uaneks9h
Tags: 0.1.8-2
* debian/control: Improve long description. (Closes: #405347)
* debian/patches/14_nfs-fix.patch: Fix gam_server startup for Thunar.
  Thanks to Maximiliano Curia. (Closes: #403247)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Marmot
2
 
 * Copyright (C) 2004 John McCutchan, James Willcox, Corey Bowers
 
1
/* gamin inotify backend
 
2
 * Copyright (C) 2005 John McCutchan
3
3
 *
4
4
 * This library is free software; you can redistribute it and/or
5
5
 * modify it under the terms of the GNU Lesser General Public
14
14
 * You should have received a copy of the GNU Lesser General Public
15
15
 * License along with this library; if not, write to the Free
16
16
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
 
 * TODO:
18
 
 *      Handle removal of subscriptions when we get IGNORE event
19
 
 *      The dnotify/poll hybrid backend produces more events
20
 
 */
21
 
 
22
 
 
23
 
#include <config.h>
24
 
#define _GNU_SOURCE
25
 
#include <fcntl.h>
26
 
#include <sys/ioctl.h>
27
 
#include <signal.h>
28
 
#include <unistd.h>
29
 
#include <stdio.h>
30
 
#include <glib.h>
31
 
#ifdef HAVE_LINUX_INOTIFY_H
 
17
 */
 
18
 
 
19
#include "server_config.h"
 
20
#include <string.h>
 
21
/* Just include the local header to stop all the pain */
 
22
#include "local_inotify.h"
 
23
#if 0
 
24
#ifdef HAVE_SYS_INOTIFY_H
 
25
/* We don't actually include the libc header, because there has been
 
26
 * problems with libc versions that was built without inotify support.
 
27
 * Instead we use the local version.
 
28
 */
 
29
#include "local_inotify.h"
 
30
#elif defined (HAVE_LINUX_INOTIFY_H)
32
31
#include <linux/inotify.h>
33
 
#else
34
 
#include "local_inotify.h"
 
32
#endif
 
33
#endif
 
34
#include "inotify-sub.h"
 
35
#include "inotify-helper.h"
 
36
#include "inotify-diag.h"
 
37
#ifdef GAMIN_DEBUG_API
 
38
#include "gam_debugging.h"
35
39
#endif
36
40
#include "gam_error.h"
 
41
#include "gam_event.h"
 
42
#include "gam_server.h"
 
43
#include "gam_subscription.h"
37
44
#include "gam_inotify.h"
38
 
#include "gam_tree.h"
39
 
#include "gam_event.h"
40
 
#include "gam_server.h"
41
 
#include "gam_event.h"
42
 
 
43
 
typedef struct {
44
 
    char *path;
45
 
    int wd;
46
 
    int refcount;
47
 
    GList *subs;
48
 
} INotifyData;
49
 
 
50
 
static GHashTable *path_hash = NULL;
51
 
static GHashTable *wd_hash = NULL;
52
 
 
53
 
static GList *new_subs = NULL;
54
 
G_LOCK_DEFINE_STATIC(new_subs);
55
 
static GList *removed_subs = NULL;
56
 
G_LOCK_DEFINE_STATIC(removed_subs);
57
 
 
58
 
G_LOCK_DEFINE_STATIC(inotify);
59
 
static GIOChannel *inotify_read_ioc = NULL;
60
 
 
61
 
static gboolean have_consume_idler = FALSE;
62
 
 
63
 
 
64
 
int fd = -1; // the device fd
65
 
 
66
 
static INotifyData *
67
 
gam_inotify_data_new(const char *path, int wd)
68
 
{
69
 
    INotifyData *data;
70
 
 
71
 
    data = g_new0(INotifyData, 1);
72
 
    data->path = g_strdup(path);
73
 
    data->wd = wd;
74
 
    data->refcount = 1;
75
 
    data->subs = NULL;
76
 
 
77
 
    return data;
78
 
}
79
 
 
80
 
static void
81
 
gam_inotify_data_free(INotifyData * data)
82
 
{
83
 
    g_free(data->path);
84
 
    g_free(data);
85
 
}
86
 
 
87
 
static void
88
 
gam_inotify_add_rm_handler(const char *path, GamSubscription *sub, gboolean added)
89
 
{
90
 
    INotifyData *data;
91
 
    struct inotify_watch_request iwr;
92
 
    int wd,r;
93
 
 
94
 
    G_LOCK(inotify);
95
 
 
96
 
    if (added) {
97
 
        GList *subs;
98
 
 
99
 
        subs = NULL;
100
 
        subs = g_list_append(subs, sub);
101
 
 
102
 
        if ((data = g_hash_table_lookup(path_hash, path)) != NULL) {
103
 
            data->refcount++;
104
 
            data->subs = g_list_prepend(data->subs, sub);
105
 
            G_UNLOCK(inotify);
106
 
            gam_debug(DEBUG_INFO, "inotify updated refcount\n");
107
 
            gam_server_emit_event (path, GAMIN_EVENT_EXISTS, subs);
108
 
            gam_server_emit_event (path, GAMIN_EVENT_ENDEXISTS, subs);
109
 
            return;
110
 
        }
111
 
 
112
 
        iwr.dirname = g_strdup(path);
113
 
        iwr.mask = 0xffffffff; // all events
114
 
 
115
 
        wd = ioctl(fd, INOTIFY_WATCH,&iwr);
116
 
        g_free(iwr.dirname);    
117
 
 
118
 
        if (wd < 0) {
119
 
            G_UNLOCK(inotify);
120
 
            return;
121
 
        }
122
 
 
123
 
        data = gam_inotify_data_new(path, wd);
124
 
        data->subs = g_list_prepend(data->subs, sub);
125
 
        g_hash_table_insert(wd_hash, GINT_TO_POINTER(data->wd), data);
126
 
        g_hash_table_insert(path_hash, data->path, data);
127
 
 
128
 
        gam_debug(DEBUG_INFO, "activated INotify for %s\n", path);
129
 
 
130
 
        gam_server_emit_event (path, GAMIN_EVENT_EXISTS, subs);
131
 
        gam_server_emit_event (path, GAMIN_EVENT_ENDEXISTS, subs);
132
 
    } else {
133
 
        data = g_hash_table_lookup(path_hash, path);
134
 
 
135
 
        if (!data) {
136
 
            G_UNLOCK(inotify);
137
 
            return;
138
 
        }
139
 
 
140
 
        if (g_list_find (data->subs, sub)) {
141
 
                data->subs = g_list_remove_all (data->subs, sub);
142
 
        }
143
 
        data->refcount--;
144
 
            gam_debug(DEBUG_INFO, "inotify decremeneted refcount\n");
145
 
 
146
 
        if (data->refcount == 0) {
147
 
            r = ioctl (fd, INOTIFY_IGNORE, &data->wd); 
148
 
            if (r < 0) {
149
 
                gam_debug (DEBUG_INFO, "INOTIFY_IGNORE failed for %s\n", data->path);
150
 
            }
151
 
            gam_debug(DEBUG_INFO, "deactivated INotify for %s\n",
152
 
                      data->path);
153
 
            g_hash_table_remove(path_hash, data->path);
154
 
            g_hash_table_remove(wd_hash, GINT_TO_POINTER(data->wd));
155
 
            gam_inotify_data_free(data);
156
 
        }
157
 
    }
158
 
 
159
 
    G_UNLOCK(inotify);
160
 
}
161
 
 
162
 
 
163
 
static GaminEventType inotify_event_to_gamin_event (int mask) 
164
 
{
165
 
        switch (mask)
 
45
 
 
46
/* Transforms a inotify event to a gamin event. */
 
47
static GaminEventType
 
48
ih_mask_to_EventType (guint32 mask)
 
49
{
 
50
        mask &= ~IN_ISDIR;
 
51
        switch (mask)
 
52
        {
 
53
        case IN_MODIFY:
 
54
                return GAMIN_EVENT_CHANGED;
 
55
        break;
 
56
        case IN_ATTRIB:
 
57
                return GAMIN_EVENT_CHANGED;
 
58
        break;
 
59
        case IN_MOVE_SELF:
 
60
        case IN_MOVED_FROM:
 
61
        case IN_DELETE:
 
62
        case IN_DELETE_SELF:
 
63
                return GAMIN_EVENT_DELETED;
 
64
        break;
 
65
        case IN_CREATE:
 
66
        case IN_MOVED_TO:
 
67
                return GAMIN_EVENT_CREATED;
 
68
        break;
 
69
        case IN_Q_OVERFLOW:
 
70
        case IN_OPEN:
 
71
        case IN_CLOSE_WRITE:
 
72
        case IN_CLOSE_NOWRITE:
 
73
        case IN_UNMOUNT:
 
74
        case IN_ACCESS:
 
75
        case IN_IGNORED:
 
76
        default:
 
77
                return -1;
 
78
        break;
 
79
        }
 
80
}
 
81
 
 
82
static void
 
83
gam_inotify_send_initial_events (const char *pathname, GamSubscription *sub, gboolean is_dir, gboolean was_missing)
 
84
{
 
85
        GaminEventType gevent;
 
86
 
 
87
        if (was_missing) {
 
88
          gevent = GAMIN_EVENT_CREATED;
 
89
        } else {
 
90
          if (g_file_test (pathname, G_FILE_TEST_EXISTS))
 
91
            gevent = GAMIN_EVENT_EXISTS;
 
92
          else
 
93
            gevent = GAMIN_EVENT_DELETED;
 
94
        }
 
95
 
 
96
        gam_server_emit_one_event (pathname, is_dir ? 1 : 0, gevent, sub, 1);
 
97
 
 
98
        if (is_dir) 
166
99
        {
167
 
                case IN_ATTRIB:
168
 
                case IN_MODIFY:
169
 
                        return GAMIN_EVENT_CHANGED;
170
 
                break;
171
 
                case IN_MOVED_TO:
172
 
                case IN_CREATE_SUBDIR:
173
 
                case IN_CREATE_FILE:
174
 
                        return GAMIN_EVENT_CREATED;
175
 
                break;
176
 
                case IN_MOVED_FROM:
177
 
                case IN_DELETE_SUBDIR:
178
 
                case IN_DELETE_FILE:
179
 
                        return GAMIN_EVENT_DELETED;
180
 
                break;
181
 
                default:
182
 
                        return GAMIN_EVENT_UNKNOWN;
183
 
        }
184
 
}
185
 
static void gam_inotify_emit_event (INotifyData *data, struct inotify_event *event)
186
 
{
187
 
        GaminEventType gevent;
188
 
        char *event_path;
189
 
 
190
 
        if (!data||!event)
191
 
                return;
192
 
 
193
 
        gevent = inotify_event_to_gamin_event (event->mask);
194
 
        // we got some event that GAMIN doesn't understand
195
 
        if (gevent == GAMIN_EVENT_UNKNOWN) {
196
 
                gam_debug(DEBUG_INFO, "inotify_emit_event got unknown event %x\n", event->mask);
197
 
                return;
198
 
        }
199
 
 
200
 
        if (event->filename[0] != '\0') {
201
 
                int pathlen = strlen(data->path);
202
 
                gam_debug(DEBUG_INFO, "Got filename with event\n");
203
 
                if (data->path[pathlen-1] == '/') {
204
 
                        event_path = g_strconcat (data->path, event->filename, NULL);
 
100
                GDir *dir;
 
101
                GError *err = NULL;
 
102
                dir = g_dir_open (pathname, 0, &err);
 
103
                if (dir)
 
104
                {
 
105
                        const char *filename;
 
106
 
 
107
                        while ((filename = g_dir_read_name (dir)))
 
108
                        {
 
109
                                gchar *fullname = g_strdup_printf ("%s/%s", pathname, filename);
 
110
                                gboolean file_is_dir = FALSE;
 
111
                                struct stat fsb;
 
112
                                memset(&fsb, 0, sizeof (struct stat));
 
113
                                lstat(fullname, &fsb);
 
114
                                file_is_dir = (fsb.st_mode & S_IFDIR) != 0 ? TRUE : FALSE;
 
115
                                gam_server_emit_one_event (fullname, file_is_dir ? 1 : 0, gevent, sub, 1);
 
116
                                g_free (fullname);
 
117
                        }
 
118
 
 
119
                        g_dir_close (dir);
205
120
                } else {
206
 
                        event_path = g_strconcat (data->path, "/", event->filename, NULL);
207
 
                }
208
 
        } else {
209
 
                gam_debug(DEBUG_INFO, "Got no filename with event\n");
210
 
                event_path = g_strdup (data->path);
211
 
        }
212
 
 
213
 
        gam_debug(DEBUG_INFO, "gam_inotify_emit_event() %s\n", event_path);
214
 
 
215
 
        gam_server_emit_event (event_path, gevent, data->subs);
216
 
}
217
 
 
218
 
static gboolean
219
 
gam_inotify_read_handler(gpointer user_data)
220
 
{
221
 
    struct inotify_event event;
222
 
    INotifyData *data;
223
 
 
224
 
    gam_debug(DEBUG_INFO, "gam_inotify_read_handler()\n");
225
 
    G_LOCK(inotify);
226
 
 
227
 
    if (g_io_channel_read_chars(inotify_read_ioc, (char *)&event, sizeof(struct inotify_event), NULL, NULL) != G_IO_STATUS_NORMAL) {
228
 
        G_UNLOCK(inotify);
229
 
        gam_debug(DEBUG_INFO, "gam_inotify_read_handler failed\n");
230
 
        return FALSE;
231
 
    }
232
 
 
233
 
    /* When we get an ignore event, we 
234
 
     * remove all the subscriptions for this wd
235
 
     */
236
 
    if (event.mask == IN_IGNORED) {
237
 
            GList *l;
238
 
            data = g_hash_table_lookup (wd_hash, GINT_TO_POINTER(event.wd));
239
 
 
240
 
            if (!data) {
241
 
                    G_UNLOCK(inotify);
242
 
                    return TRUE;
243
 
                }
244
 
 
245
 
            l = data->subs;
246
 
            data->subs = NULL;
247
 
            for (l = l; l; l = l->next) {
248
 
                    GamSubscription *sub = l->data;
249
 
                    gam_inotify_remove_subscription (sub);
250
 
            }
251
 
            G_UNLOCK(inotify);
252
 
            return TRUE;
253
 
    }
254
 
 
255
 
    data = g_hash_table_lookup (wd_hash, GINT_TO_POINTER(event.wd));
256
 
 
257
 
    if (!data) {
258
 
        gam_debug(DEBUG_INFO, "Could not find WD %d in hash\n", event.wd);
259
 
        G_UNLOCK(inotify);
260
 
        return TRUE;
261
 
    }
262
 
 
263
 
    gam_inotify_emit_event (data, &event);
264
 
 
265
 
    gam_debug(DEBUG_INFO, "gam_inotify event for %s (%x) %s\n", data->path, event.mask, event.filename);
266
 
 
267
 
    gam_debug(DEBUG_INFO, "gam_inotify_read_handler() done\n");
268
 
 
269
 
    G_UNLOCK(inotify);
270
 
 
271
 
    return TRUE;
272
 
}
273
 
 
274
 
static gboolean
275
 
gam_inotify_consume_subscriptions_real(gpointer data)
276
 
{
277
 
        GList *subs, *l;
 
121
                        GAM_DEBUG (DEBUG_INFO, "unable to open directory %s: %s\n", pathname, err->message);
 
122
                        g_error_free (err);
 
123
                }
 
124
 
 
125
        }
 
126
 
 
127
        if (!was_missing) 
 
128
        {
 
129
                gam_server_emit_one_event (pathname, is_dir ? 1 : 0, GAMIN_EVENT_ENDEXISTS, sub, 1);
 
130
        }
 
131
 
 
132
}
 
133
 
 
134
static void
 
135
gam_inotify_event_callback (const char *fullpath, guint32 mask, void *subdata)
 
136
{
 
137
        GamSubscription *sub = (GamSubscription *)subdata;
 
138
        GaminEventType gevent;
 
139
 
 
140
        gevent = ih_mask_to_EventType (mask);
 
141
 
 
142
        gam_server_emit_one_event (fullpath, gam_subscription_is_dir (sub), gevent, sub, 1);
 
143
}
 
144
 
 
145
static void
 
146
gam_inotify_found_callback (const char *fullpath, void *subdata)
 
147
{
 
148
        GamSubscription *sub = (GamSubscription *)subdata;
 
149
 
 
150
        gam_inotify_send_initial_events (gam_subscription_get_path (sub), sub, gam_subscription_is_dir (sub), TRUE);
 
151
}
 
152
 
 
153
 
 
154
gboolean
 
155
gam_inotify_init (void)
 
156
{
 
157
        gam_server_install_kernel_hooks (GAMIN_K_INOTIFY2, 
 
158
                                         gam_inotify_add_subscription,
 
159
                                         gam_inotify_remove_subscription,
 
160
                                         gam_inotify_remove_all_for,
 
161
                                         NULL, NULL);
278
162
        
279
 
        G_LOCK(new_subs);
280
 
        if (new_subs) {
281
 
                subs = new_subs;
282
 
                new_subs = NULL;
283
 
                G_UNLOCK(new_subs);
284
 
 
285
 
                for (l = subs; l; l = l->next) {
286
 
                        GamSubscription *sub = l->data;
287
 
                        gam_debug(DEBUG_INFO, "called gam_inotify_add_handler()\n");
288
 
                        gam_inotify_add_rm_handler (gam_subscription_get_path (sub), sub, TRUE);
289
 
                }
290
 
 
291
 
        } else { 
292
 
                G_UNLOCK(new_subs);
293
 
        }
294
 
 
295
 
        G_LOCK(removed_subs);
296
 
        if (removed_subs) {
297
 
                subs = removed_subs;
298
 
                removed_subs = NULL;
299
 
                G_UNLOCK(removed_subs);
300
 
 
301
 
                for (l = subs; l; l = l->next) {
302
 
                        GamSubscription *sub = l->data;
303
 
                        gam_debug(DEBUG_INFO, "called gam_inotify_rm_handler()\n");
304
 
                        gam_inotify_add_rm_handler (gam_subscription_get_path (sub), sub, FALSE);
305
 
                }
306
 
        } else {
307
 
                G_UNLOCK(removed_subs);
308
 
        }
309
 
 
310
 
        gam_debug(DEBUG_INFO, "gam_inotify_consume_subscriptions()\n");
311
 
 
312
 
        have_consume_idler = FALSE;
313
 
        return FALSE;
314
 
}
315
 
 
316
 
static void
317
 
gam_inotify_consume_subscriptions(void)
318
 
{
319
 
        GSource *source;
320
 
 
321
 
        if (have_consume_idler)
322
 
                return;
323
 
 
324
 
        have_consume_idler = TRUE;
325
 
 
326
 
        source = g_idle_source_new ();
327
 
        g_source_set_callback (source, gam_inotify_consume_subscriptions_real, NULL, NULL);
328
 
 
329
 
        g_source_attach (source, NULL);
330
 
}
331
 
 
332
 
/**
333
 
 * @defgroup INotify INotify Backend
334
 
 * @ingroup Backends
335
 
 * @brief INotify backend API
336
 
 *
337
 
 * Since version 2.6.X, Linux kernels have included the Linux Inode
338
 
 * Notification system (inotify).  This backend uses inotify to know when
339
 
 * files are changed/created/deleted.  
340
 
 *
341
 
 * @{
342
 
 */
343
 
 
344
 
 
345
 
/**
346
 
 * Initializes the inotify system.  This must be called before
347
 
 * any other functions in this module.
348
 
 *
349
 
 * @returns TRUE if initialization succeeded, FALSE otherwise
350
 
 */
351
 
gboolean
352
 
gam_inotify_init(void)
353
 
{
354
 
    GSource *source;
355
 
 
356
 
    fd = open("/dev/inotify", O_RDONLY);
357
 
 
358
 
    if (fd < 0) {
359
 
        gam_debug(DEBUG_INFO, "Could not open /dev/inotify\n");
360
 
        return FALSE;
361
 
    }
362
 
 
363
 
    inotify_read_ioc = g_io_channel_unix_new(fd);
364
 
 
365
 
    /* For binary data */
366
 
    g_io_channel_set_encoding (inotify_read_ioc, NULL, NULL);
367
 
    /* Non blocking */
368
 
    g_io_channel_set_flags(inotify_read_ioc, G_IO_FLAG_NONBLOCK, NULL);
369
 
 
370
 
    source = g_io_create_watch(inotify_read_ioc,
371
 
                               G_IO_IN | G_IO_HUP | G_IO_ERR);
372
 
    g_source_set_callback(source, gam_inotify_read_handler, NULL, NULL);
373
 
 
374
 
    g_source_attach(source, NULL);
375
 
 
376
 
    path_hash = g_hash_table_new(g_str_hash, g_str_equal);
377
 
    wd_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
378
 
 
379
 
    gam_debug(DEBUG_INFO, "inotify initialized\n");
380
 
 
381
 
    int i = 0; // INOTIFY_DEBUG_INODE|INOTIFY_DEBUG_ERRORS|INOTIFY_DEBUG_EVENTS;
382
 
    ioctl(fd, INOTIFY_SETDEBUG, &i);
383
 
 
384
 
    gam_backend_add_subscription = gam_inotify_add_subscription;
385
 
    gam_backend_remove_subscription = gam_inotify_remove_subscription;
386
 
    gam_backend_remove_all_for = gam_inotify_remove_all_for;
387
 
 
388
 
    return TRUE;
389
 
}
390
 
 
391
 
/**
392
 
 * Adds a subscription to be monitored.
393
 
 *
394
 
 * @param sub a #GamSubscription to be polled
395
 
 * @returns TRUE if adding the subscription succeeded, FALSE otherwise
396
 
 */
397
 
gboolean
398
 
gam_inotify_add_subscription(GamSubscription * sub)
399
 
{
 
163
        return ih_startup (gam_inotify_event_callback,
 
164
                           gam_inotify_found_callback);
 
165
}
 
166
 
 
167
gboolean
 
168
gam_inotify_add_subscription (GamSubscription *sub)
 
169
{
 
170
        ih_sub_t *isub = NULL;
 
171
 
400
172
        gam_listener_add_subscription(gam_subscription_get_listener(sub), sub);
401
 
 
402
 
        G_LOCK(new_subs);
403
 
        new_subs = g_list_prepend(new_subs, sub);
404
 
        G_UNLOCK(new_subs);
405
 
 
406
 
        gam_debug(DEBUG_INFO, "inotify_add_sub\n");
407
 
 
408
 
        gam_inotify_consume_subscriptions();
409
 
    return TRUE;
410
 
}
411
 
 
412
 
/**
413
 
 * Removes a subscription which was being monitored.
414
 
 *
415
 
 * @param sub a #GamSubscription to remove
416
 
 * @returns TRUE if removing the subscription succeeded, FALSE otherwise
417
 
 */
418
 
gboolean
419
 
gam_inotify_remove_subscription(GamSubscription * sub)
420
 
{
421
 
        G_LOCK(new_subs);
422
 
        if (g_list_find(new_subs, sub)) {
423
 
                gam_debug(DEBUG_INFO, "removed sub found on new_subs\n");
424
 
                new_subs = g_list_remove_all (new_subs, sub);
425
 
                G_UNLOCK(new_subs);
426
 
                return TRUE;
427
 
        }
428
 
        G_UNLOCK(new_subs);
429
 
 
430
 
        gam_subscription_cancel (sub);
431
 
        gam_listener_remove_subscription(gam_subscription_get_listener(sub), sub);
432
 
 
433
 
        G_LOCK(removed_subs);
434
 
        removed_subs = g_list_prepend (removed_subs, sub);
435
 
        G_UNLOCK(removed_subs);
436
 
 
437
 
        gam_debug(DEBUG_INFO, "inotify_remove_sub\n");
438
 
        gam_inotify_consume_subscriptions();
439
 
 
440
 
    return TRUE;
441
 
}
442
 
 
443
 
/**
444
 
 * Stop monitoring all subscriptions for a given listener.
445
 
 *
446
 
 * @param listener a #GamListener
447
 
 * @returns TRUE if removing the subscriptions succeeded, FALSE otherwise
448
 
 */
449
 
gboolean
450
 
gam_inotify_remove_all_for(GamListener * listener)
451
 
{
452
 
        GList *subs, *l = NULL;
453
 
 
454
 
        subs = gam_listener_get_subscriptions (listener);
455
 
 
456
 
        for (l = subs; l; l = l->next) {
457
 
                GamSubscription *sub = l->data;
458
 
 
459
 
                g_assert (sub != NULL);
460
 
 
461
 
                gam_inotify_remove_subscription (sub);
462
 
 
463
 
        }
464
 
 
465
 
        if (subs) {
466
 
                g_list_free (subs);
467
 
                gam_inotify_consume_subscriptions();
468
 
                return TRUE;
469
 
        } else {
 
173
        
 
174
        isub = ih_sub_new (gam_subscription_get_path (sub), gam_subscription_is_dir (sub), 0, sub);
 
175
 
 
176
        if (!ih_sub_add (isub))
 
177
        {
 
178
                ih_sub_free (isub);
470
179
                return FALSE;
471
180
        }
472
 
}
473
 
 
474
 
/** @} */
 
181
 
 
182
        gam_inotify_send_initial_events (gam_subscription_get_path (sub), sub, gam_subscription_is_dir (sub), FALSE);
 
183
 
 
184
        return TRUE;
 
185
}
 
186
 
 
187
static gboolean
 
188
gam_inotify_remove_sub_pred (ih_sub_t *sub, void *callerdata)
 
189
{
 
190
        return sub->usersubdata == callerdata;
 
191
}
 
192
 
 
193
gboolean
 
194
gam_inotify_remove_subscription (GamSubscription *sub)
 
195
{
 
196
        ih_sub_foreach_free (sub, gam_inotify_remove_sub_pred);
 
197
 
 
198
        return TRUE;
 
199
}
 
200
 
 
201
static gboolean
 
202
gam_inotify_remove_listener_pred (ih_sub_t *sub, void *callerdata)
 
203
{
 
204
        GamSubscription *gsub = (GamSubscription *)sub->usersubdata;
 
205
 
 
206
        return gam_subscription_get_listener (gsub) == callerdata;
 
207
}
 
208
 
 
209
gboolean
 
210
gam_inotify_remove_all_for (GamListener *listener)
 
211
{
 
212
        ih_sub_foreach_free (listener, gam_inotify_remove_listener_pred);
 
213
 
 
214
        return TRUE;
 
215
}
 
216
 
 
217
void
 
218
gam_inotify_debug (void)
 
219
{
 
220
        id_dump (NULL);
 
221
}
 
222
 
 
223
gboolean
 
224
gam_inotify_is_running (void)
 
225
{
 
226
        return ih_running ();
 
227
}