]>
Commit | Line | Data |
---|---|---|
99960865 | 1 | Index: server/gam_debugging.h |
2 | =================================================================== | |
3 | RCS file: /cvs/gnome/gamin/server/gam_debugging.h,v | |
4 | retrieving revision 1.2 | |
5 | diff -u -r1.2 gam_debugging.h | |
6 | --- server/gam_debugging.h 23 Mar 2005 09:50:11 -0000 1.2 | |
7 | +++ server/gam_debugging.h 14 Apr 2005 16:44:34 -0000 | |
8 | @@ -12,7 +12,12 @@ | |
9 | GAMDnotifyDelete=2, | |
10 | GAMDnotifyChange=3, | |
11 | GAMDnotifyFlowOn=4, | |
12 | - GAMDnotifyFlowOff=5 | |
13 | + GAMDnotifyFlowOff=5, | |
14 | + GAMinotifyCreate=6, | |
15 | + GAMinotifyDelete=7, | |
16 | + GAMinotifyChange=8, | |
17 | + GAMinotifyFlowOn=9, | |
18 | + GAMinotifyFlowOff=10 | |
19 | } GAMDebugEvent; | |
20 | ||
21 | void gam_debug_add(GamConnDataPtr conn, const char *value, int options); | |
22 | Index: server/gam_inotify.c | |
23 | =================================================================== | |
24 | RCS file: /cvs/gnome/gamin/server/gam_inotify.c,v | |
25 | retrieving revision 1.17 | |
26 | diff -u -r1.17 gam_inotify.c | |
27 | --- server/gam_inotify.c 7 Apr 2005 09:11:17 -0000 1.17 | |
28 | +++ server/gam_inotify.c 14 Apr 2005 16:44:34 -0000 | |
29 | @@ -1,5 +1,8 @@ | |
30 | -/* | |
31 | - * Copyright (C) 2004 John McCutchan, James Willcox, Corey Bowers | |
32 | +/* gamin inotify backend | |
33 | + * Copyright (C) 2005 John McCutchan | |
34 | + * | |
35 | + * Based off of code, | |
36 | + * Copyright (C) 2003 James Willcox, Corey Bowers | |
37 | * | |
38 | * This library is free software; you can redistribute it and/or | |
39 | * modify it under the terms of the GNU Lesser General Public | |
40 | @@ -14,261 +17,404 @@ | |
41 | * You should have received a copy of the GNU Lesser General Public | |
42 | * License along with this library; if not, write to the Free | |
43 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
44 | - * TODO: | |
45 | - * - *properly* Handle removal of subscriptions when we get IGNORE event | |
46 | - * - this backend does not produce the same events as the dnotify/poll backend. | |
47 | - * for example, the dp backend allows for watching non-exist files/folders, | |
48 | - * and be notified when they are created. there are more places where | |
49 | - * the events are not consistent. | |
50 | */ | |
51 | ||
52 | ||
53 | #include <config.h> | |
54 | #define _GNU_SOURCE | |
55 | #include <fcntl.h> | |
56 | -#include <sys/ioctl.h> | |
57 | #include <signal.h> | |
58 | #include <unistd.h> | |
59 | +#include <sys/ioctl.h> | |
60 | #include <stdio.h> | |
61 | -#include <string.h> | |
62 | #include <glib.h> | |
63 | +#include "gam_error.h" | |
64 | +#include "gam_poll.h" | |
65 | #ifdef HAVE_LINUX_INOTIFY_H | |
66 | #include <linux/inotify.h> | |
67 | #else | |
68 | #include "local_inotify.h" | |
69 | #endif | |
70 | -#include "gam_error.h" | |
71 | #include "gam_inotify.h" | |
72 | #include "gam_tree.h" | |
73 | #include "gam_event.h" | |
74 | #include "gam_server.h" | |
75 | #include "gam_event.h" | |
76 | +#ifdef GAMIN_DEBUG_API | |
77 | +#include "gam_debugging.h" | |
78 | +#endif | |
79 | + | |
80 | +#define MIN_POLL_TIME 1.0 | |
81 | ||
82 | typedef struct { | |
83 | char *path; | |
84 | - char *path_file; | |
85 | int wd; | |
86 | int refcount; | |
87 | GList *subs; | |
88 | -} INotifyData; | |
89 | + int busy; | |
90 | + | |
91 | + gboolean dirty; | |
92 | + GTimer *poll_timer; | |
93 | +} inotify_data_t; | |
94 | ||
95 | static GHashTable *path_hash = NULL; | |
96 | static GHashTable *wd_hash = NULL; | |
97 | - | |
98 | -static GList *new_subs = NULL; | |
99 | - | |
100 | -G_LOCK_DEFINE_STATIC(new_subs); | |
101 | -static GList *removed_subs = NULL; | |
102 | - | |
103 | -G_LOCK_DEFINE_STATIC(removed_subs); | |
104 | +static GList *dirty_list = NULL; | |
105 | ||
106 | G_LOCK_DEFINE_STATIC(inotify); | |
107 | + | |
108 | static GIOChannel *inotify_read_ioc = NULL; | |
109 | ||
110 | static gboolean have_consume_idler = FALSE; | |
111 | ||
112 | -int fd = -1; // the device fd | |
113 | +static int inotify_device_fd = -1; | |
114 | + | |
115 | +static guint should_poll_mask = IN_MODIFY|IN_ATTRIB|IN_CLOSE_WRITE|IN_MOVED_FROM|IN_MOVED_TO|IN_DELETE_SUBDIR|IN_DELETE_FILE|IN_CREATE_SUBDIR|IN_CREATE_FILE|IN_DELETE_SELF|IN_UNMOUNT; | |
116 | + | |
117 | +static void print_mask(int mask) | |
118 | +{ | |
119 | + if (mask & IN_ACCESS) | |
120 | + { | |
121 | + GAM_DEBUG(DEBUG_INFO, "ACCESS\n"); | |
122 | + } | |
123 | + if (mask & IN_MODIFY) | |
124 | + { | |
125 | + GAM_DEBUG(DEBUG_INFO, "MODIFY\n"); | |
126 | + } | |
127 | + if (mask & IN_ATTRIB) | |
128 | + { | |
129 | + GAM_DEBUG(DEBUG_INFO, "ATTRIB\n"); | |
130 | + } | |
131 | + if (mask & IN_CLOSE_WRITE) | |
132 | + { | |
133 | + GAM_DEBUG(DEBUG_INFO, "CLOSE_WRITE\n"); | |
134 | + } | |
135 | + if (mask & IN_CLOSE_NOWRITE) | |
136 | + { | |
137 | + GAM_DEBUG(DEBUG_INFO, "CLOSE_WRITE\n"); | |
138 | + } | |
139 | + if (mask & IN_OPEN) | |
140 | + { | |
141 | + GAM_DEBUG(DEBUG_INFO, "OPEN\n"); | |
142 | + } | |
143 | + if (mask & IN_MOVED_FROM) | |
144 | + { | |
145 | + GAM_DEBUG(DEBUG_INFO, "MOVE_FROM\n"); | |
146 | + } | |
147 | + if (mask & IN_MOVED_TO) | |
148 | + { | |
149 | + GAM_DEBUG(DEBUG_INFO, "MOVE_TO\n"); | |
150 | + } | |
151 | + if (mask & IN_DELETE_SUBDIR) | |
152 | + { | |
153 | + GAM_DEBUG(DEBUG_INFO, "DELETE_SUBDIR\n"); | |
154 | + } | |
155 | + if (mask & IN_DELETE_FILE) | |
156 | + { | |
157 | + GAM_DEBUG(DEBUG_INFO, "DELETE_FILE\n"); | |
158 | + } | |
159 | + if (mask & IN_CREATE_SUBDIR) | |
160 | + { | |
161 | + GAM_DEBUG(DEBUG_INFO, "CREATE_SUBDIR\n"); | |
162 | + } | |
163 | + if (mask & IN_CREATE_FILE) | |
164 | + { | |
165 | + GAM_DEBUG(DEBUG_INFO, "CREATE_FILE\n"); | |
166 | + } | |
167 | + if (mask & IN_DELETE_SELF) | |
168 | + { | |
169 | + GAM_DEBUG(DEBUG_INFO, "DELETE_SELF\n"); | |
170 | + } | |
171 | + if (mask & IN_UNMOUNT) | |
172 | + { | |
173 | + GAM_DEBUG(DEBUG_INFO, "UNMOUNT\n"); | |
174 | + } | |
175 | + if (mask & IN_Q_OVERFLOW) | |
176 | + { | |
177 | + GAM_DEBUG(DEBUG_INFO, "Q_OVERFLOW\n"); | |
178 | + } | |
179 | + if (mask & IN_IGNORED) | |
180 | + { | |
181 | + GAM_DEBUG(DEBUG_INFO, "IGNORED\n"); | |
182 | + } | |
183 | +} | |
184 | ||
185 | -static INotifyData * | |
186 | -gam_inotify_data_new(const char *path, char *path_file, int wd) | |
187 | +static inotify_data_t * | |
188 | +gam_inotify_data_new(const char *path, int wd) | |
189 | { | |
190 | - INotifyData *data; | |
191 | + inotify_data_t *data; | |
192 | ||
193 | - data = g_new0(INotifyData, 1); | |
194 | + data = g_new0(inotify_data_t, 1); | |
195 | data->path = g_strdup(path); | |
196 | - data->path_file = path_file; | |
197 | data->wd = wd; | |
198 | + data->busy = 0; | |
199 | data->refcount = 1; | |
200 | - data->subs = NULL; | |
201 | + data->dirty = FALSE; | |
202 | + data->poll_timer = g_timer_new (); | |
203 | ||
204 | return data; | |
205 | } | |
206 | ||
207 | static void | |
208 | -gam_inotify_data_free(INotifyData * data) | |
209 | +gam_inotify_data_free(inotify_data_t * data) | |
210 | { | |
211 | + if (data->refcount != 0) | |
212 | + GAM_DEBUG(DEBUG_INFO, "gam_inotify_data_free called with reffed data.\n"); | |
213 | g_free(data->path); | |
214 | - g_free(data->path_file); | |
215 | + g_timer_destroy (data->poll_timer); | |
216 | g_free(data); | |
217 | } | |
218 | ||
219 | static void | |
220 | -gam_inotify_add_rm_handler(const char *path, GamSubscription * sub, | |
221 | - pollHandlerMode mode) | |
222 | +gam_inotify_directory_handler_internal(const char *path, pollHandlerMode mode) | |
223 | { | |
224 | - INotifyData *data; | |
225 | + inotify_data_t *data; | |
226 | + int path_fd; | |
227 | + int path_wd; | |
228 | struct inotify_watch_request iwr; | |
229 | - struct stat st; | |
230 | - char *path_file; | |
231 | - char *path_t; | |
232 | - int wd, r; | |
233 | ||
234 | + | |
235 | + switch (mode) { | |
236 | + case GAMIN_ACTIVATE: | |
237 | + GAM_DEBUG(DEBUG_INFO, "Adding %s to inotify\n", path); | |
238 | + break; | |
239 | + case GAMIN_DESACTIVATE: | |
240 | + GAM_DEBUG(DEBUG_INFO, "Removing %s from inotify\n", path); | |
241 | + break; | |
242 | + case GAMIN_FLOWCONTROLSTART: | |
243 | + GAM_DEBUG(DEBUG_INFO, "Start flow control for %s\n", path); | |
244 | + break; | |
245 | + case GAMIN_FLOWCONTROLSTOP: | |
246 | + GAM_DEBUG(DEBUG_INFO, "Stop flow control for %s\n", path); | |
247 | + break; | |
248 | + default: | |
249 | + gam_error(DEBUG_INFO, "Unknown inotify operation %d for %s\n", | |
250 | + mode, path); | |
251 | + return; | |
252 | + } | |
253 | G_LOCK(inotify); | |
254 | ||
255 | if (mode == GAMIN_ACTIVATE) { | |
256 | - GList *subs; | |
257 | - | |
258 | - subs = NULL; | |
259 | - subs = g_list_append(subs, sub); | |
260 | - | |
261 | if ((data = g_hash_table_lookup(path_hash, path)) != NULL) { | |
262 | data->refcount++; | |
263 | - data->subs = g_list_prepend(data->subs, sub); | |
264 | + GAM_DEBUG(DEBUG_INFO, " found incremented refcount: %d\n", | |
265 | + data->refcount); | |
266 | G_UNLOCK(inotify); | |
267 | +#ifdef GAMIN_DEBUG_API | |
268 | + gam_debug_report(GAMinotifyChange, path, data->refcount); | |
269 | +#endif | |
270 | GAM_DEBUG(DEBUG_INFO, "inotify updated refcount\n"); | |
271 | - /* | |
272 | - * hum might need some work to check if the path is a dir, | |
273 | - * setting 0 and forcing to bypass checks right now. | |
274 | - */ | |
275 | - gam_server_emit_event(path, 0, GAMIN_EVENT_EXISTS, subs, 1); | |
276 | - gam_server_emit_event(path, 0, GAMIN_EVENT_ENDEXISTS, subs, 1); | |
277 | return; | |
278 | } | |
279 | ||
280 | - { | |
281 | - if (stat(path, &st)) { | |
282 | - G_UNLOCK(inotify); | |
283 | - return; | |
284 | - } | |
285 | - | |
286 | - path_t = g_strdup(path); | |
287 | - path_file = NULL; | |
288 | - | |
289 | - if (S_ISREG(st.st_mode)) { | |
290 | - char *ch; | |
291 | - | |
292 | - ch = strrchr(path_t, '/'); | |
293 | - if (!ch) { | |
294 | - g_free(path_t); | |
295 | - G_UNLOCK(inotify); | |
296 | - return; | |
297 | - } | |
298 | - path_file = g_strdup(++ch); | |
299 | - *ch = '\0'; | |
300 | - } | |
301 | - | |
302 | - | |
303 | - int file_fd = open(path_t, O_RDONLY); | |
304 | + path_fd = open(path, O_RDONLY); | |
305 | ||
306 | - g_free(path_t); | |
307 | - if (file_fd < 0) { | |
308 | - G_UNLOCK(inotify); | |
309 | - return; | |
310 | - } | |
311 | - | |
312 | - iwr.fd = file_fd; | |
313 | - iwr.mask = 0xffffffff; // all events | |
314 | - wd = ioctl(fd, INOTIFY_WATCH, &iwr); | |
315 | - close(file_fd); | |
316 | - } | |
317 | - | |
318 | - if (wd < 0) { | |
319 | + if (path_fd < 0) { | |
320 | G_UNLOCK(inotify); | |
321 | return; | |
322 | } | |
323 | ||
324 | - data = gam_inotify_data_new(path, path_file, wd); | |
325 | - path_file = NULL; | |
326 | - data->subs = g_list_prepend(data->subs, sub); | |
327 | + iwr.fd = path_fd; | |
328 | + iwr.mask = should_poll_mask; | |
329 | + path_wd = ioctl (inotify_device_fd, INOTIFY_WATCH, &iwr); | |
330 | + close (path_fd); | |
331 | + | |
332 | + data = gam_inotify_data_new(path, path_wd); | |
333 | g_hash_table_insert(wd_hash, GINT_TO_POINTER(data->wd), data); | |
334 | g_hash_table_insert(path_hash, data->path, data); | |
335 | ||
336 | - GAM_DEBUG(DEBUG_INFO, "added inotify watch for %s\n", path); | |
337 | - | |
338 | - gam_server_emit_event(path, 0, GAMIN_EVENT_EXISTS, subs, 1); | |
339 | - gam_server_emit_event(path, 0, GAMIN_EVENT_ENDEXISTS, subs, 1); | |
340 | + GAM_DEBUG(DEBUG_INFO, "activated inotify for %s\n", path); | |
341 | +#ifdef GAMIN_DEBUG_API | |
342 | + gam_debug_report(GAMinotifyCreate, path, 0); | |
343 | +#endif | |
344 | } else if (mode == GAMIN_DESACTIVATE) { | |
345 | - data = g_hash_table_lookup(path_hash, path); | |
346 | + char *dir = (char *) path; | |
347 | ||
348 | - if (!data) { | |
349 | - G_UNLOCK(inotify); | |
350 | - return; | |
351 | - } | |
352 | + data = g_hash_table_lookup(path_hash, path); | |
353 | + | |
354 | + if (!data) { | |
355 | + dir = g_path_get_dirname(path); | |
356 | + data = g_hash_table_lookup(path_hash, dir); | |
357 | + | |
358 | + if (!data) { | |
359 | + GAM_DEBUG(DEBUG_INFO, " not found !!!\n"); | |
360 | + | |
361 | + if (dir != NULL) | |
362 | + g_free(dir); | |
363 | + | |
364 | + G_UNLOCK(inotify); | |
365 | + return; | |
366 | + } | |
367 | + GAM_DEBUG(DEBUG_INFO, " not found using parent\n"); | |
368 | + } | |
369 | ||
370 | - if (g_list_find(data->subs, sub)) { | |
371 | - data->subs = g_list_remove_all(data->subs, sub); | |
372 | - } | |
373 | data->refcount--; | |
374 | GAM_DEBUG(DEBUG_INFO, "inotify decremeneted refcount for %s\n", | |
375 | path); | |
376 | ||
377 | if (data->refcount == 0) { | |
378 | - r = ioctl(fd, INOTIFY_IGNORE, &data->wd); | |
379 | - if (r < 0) { | |
380 | - GAM_DEBUG(DEBUG_INFO, | |
381 | - "INOTIFY_IGNORE failed for %s (wd = %d)\n", | |
382 | - data->path, data->wd); | |
383 | + int wd = data->wd; | |
384 | + | |
385 | + GAM_DEBUG(DEBUG_INFO, "removed inotify watch for %s\n", data->path); | |
386 | + | |
387 | + g_hash_table_remove(path_hash, data->path); | |
388 | + g_hash_table_remove(wd_hash, GINT_TO_POINTER(data->wd)); | |
389 | + gam_inotify_data_free(data); | |
390 | + | |
391 | + if (ioctl (inotify_device_fd, INOTIFY_IGNORE, &wd) < 0) { | |
392 | + GAM_DEBUG (DEBUG_INFO, "INOTIFY_IGNORE failed for %s (wd = %d)\n", data->path, data->wd); | |
393 | + } | |
394 | +#ifdef GAMIN_DEBUG_API | |
395 | + gam_debug_report(GAMinotifyDelete, dir, 0); | |
396 | +#endif | |
397 | + } else { | |
398 | + GAM_DEBUG(DEBUG_INFO, " found decremented refcount: %d\n", | |
399 | + data->refcount); | |
400 | +#ifdef GAMIN_DEBUG_API | |
401 | + gam_debug_report(GAMinotifyChange, dir, data->refcount); | |
402 | +#endif | |
403 | + } | |
404 | + if ((dir != path) && (dir != NULL)) | |
405 | + g_free(dir); | |
406 | + } else if ((mode == GAMIN_FLOWCONTROLSTART) || | |
407 | + (mode == GAMIN_FLOWCONTROLSTOP)) { | |
408 | + char *dir = (char *) path; | |
409 | + | |
410 | + data = g_hash_table_lookup(path_hash, path); | |
411 | + if (!data) { | |
412 | + dir = g_path_get_dirname(path); | |
413 | + data = g_hash_table_lookup(path_hash, dir); | |
414 | + | |
415 | + if (!data) { | |
416 | + GAM_DEBUG(DEBUG_INFO, " not found !!!\n"); | |
417 | + | |
418 | + if (dir != NULL) | |
419 | + g_free(dir); | |
420 | + G_UNLOCK(inotify); | |
421 | + return; | |
422 | } | |
423 | - GAM_DEBUG(DEBUG_INFO, "removed inotify watch for %s\n", | |
424 | - data->path); | |
425 | - g_hash_table_remove(path_hash, data->path); | |
426 | - g_hash_table_remove(wd_hash, GINT_TO_POINTER(data->wd)); | |
427 | - gam_inotify_data_free(data); | |
428 | + GAM_DEBUG(DEBUG_INFO, " not found using parent\n"); | |
429 | } | |
430 | + if (data != NULL) { | |
431 | + if (mode == GAMIN_FLOWCONTROLSTART) { | |
432 | + if (data->wd >= 0) { | |
433 | + if (ioctl (inotify_device_fd, INOTIFY_IGNORE, &data->wd) < 0) { | |
434 | + GAM_DEBUG (DEBUG_INFO, "INOTIFY_IGNORE failed for %s (wd = %d)\n", data->path, data->wd); | |
435 | + } | |
436 | + g_hash_table_remove(wd_hash, GINT_TO_POINTER(data->wd)); | |
437 | + data->wd = -1; | |
438 | + GAM_DEBUG(DEBUG_INFO, "deactivated inotify for %s\n", | |
439 | + data->path); | |
440 | +#ifdef GAMIN_DEBUG_API | |
441 | + gam_debug_report(GAMinotifyFlowOn, dir, 0); | |
442 | +#endif | |
443 | + } | |
444 | + data->busy++; | |
445 | + } else { | |
446 | + if (data->busy > 0) { | |
447 | + data->busy--; | |
448 | + if (data->busy == 0) { | |
449 | + path_fd = open(data->path, O_RDONLY); | |
450 | + if (path_fd < 0) { | |
451 | + G_UNLOCK(inotify); | |
452 | + GAM_DEBUG(DEBUG_INFO, | |
453 | + "Failed to reactivate inotify for %s\n", | |
454 | + data->path); | |
455 | + | |
456 | + if ((dir != path) && (dir != NULL)) | |
457 | + g_free(dir); | |
458 | + return; | |
459 | + } | |
460 | + | |
461 | + iwr.fd = path_fd; | |
462 | + iwr.mask = 0xffffffff; | |
463 | + path_wd = ioctl (inotify_device_fd, INOTIFY_WATCH, &iwr); | |
464 | + close (path_fd); | |
465 | + | |
466 | + data->wd = path_wd; | |
467 | + | |
468 | + g_hash_table_insert(wd_hash, GINT_TO_POINTER(data->wd), | |
469 | + data); | |
470 | + GAM_DEBUG(DEBUG_INFO, "Reactivated inotify for %s\n", | |
471 | + data->path); | |
472 | +#ifdef GAMIN_DEBUG_API | |
473 | + gam_debug_report(GAMinotifyFlowOff, path, 0); | |
474 | +#endif | |
475 | + } | |
476 | + } | |
477 | + } | |
478 | + } | |
479 | + if ((dir != path) && (dir != NULL)) | |
480 | + g_free(dir); | |
481 | } else { | |
482 | - GAM_DEBUG(DEBUG_INFO, "Inotify: unimplemented mode request %d\n", | |
483 | - mode); | |
484 | + GAM_DEBUG(DEBUG_INFO, "Unimplemented operation\n"); | |
485 | } | |
486 | + | |
487 | G_UNLOCK(inotify); | |
488 | } | |
489 | ||
490 | -static GaminEventType | |
491 | -inotify_event_to_gamin_event(int mask) | |
492 | +static void | |
493 | +gam_inotify_directory_handler(const char *path, pollHandlerMode mode) | |
494 | { | |
495 | - switch (mask) { | |
496 | - case IN_ATTRIB: | |
497 | - case IN_MODIFY: | |
498 | - return GAMIN_EVENT_CHANGED; | |
499 | - break; | |
500 | - case IN_MOVED_TO: | |
501 | - case IN_CREATE_SUBDIR: | |
502 | - case IN_CREATE_FILE: | |
503 | - return GAMIN_EVENT_CREATED; | |
504 | - break; | |
505 | - case IN_MOVED_FROM: | |
506 | - case IN_DELETE_SUBDIR: | |
507 | - case IN_DELETE_FILE: | |
508 | - return GAMIN_EVENT_DELETED; | |
509 | - break; | |
510 | - default: | |
511 | - return GAMIN_EVENT_UNKNOWN; | |
512 | + GAM_DEBUG(DEBUG_INFO, "gam_inotify_directory_handler %s : %d\n", | |
513 | + path, mode); | |
514 | + | |
515 | + if ((mode == GAMIN_DESACTIVATE) || | |
516 | + (g_file_test(path, G_FILE_TEST_IS_DIR))) { | |
517 | + gam_inotify_directory_handler_internal(path, mode); | |
518 | + } else { | |
519 | + char *dir; | |
520 | + | |
521 | + dir = g_path_get_dirname(path); | |
522 | + GAM_DEBUG(DEBUG_INFO, " not a dir using parent %s\n", dir); | |
523 | + gam_inotify_directory_handler_internal(dir, mode); | |
524 | + g_free(dir); | |
525 | } | |
526 | } | |
527 | ||
528 | static void | |
529 | -gam_inotify_emit_event(INotifyData * data, struct inotify_event *event) | |
530 | +gam_inotify_file_handler(const char *path, pollHandlerMode mode) | |
531 | { | |
532 | - GaminEventType gevent; | |
533 | - char *event_path; | |
534 | - | |
535 | - if (!data || !event) | |
536 | - return; | |
537 | - gevent = inotify_event_to_gamin_event(event->mask); | |
538 | + GAM_DEBUG(DEBUG_INFO, "gam_inotify_file_handler %s : %d\n", path, mode); | |
539 | + | |
540 | + if (g_file_test(path, G_FILE_TEST_IS_DIR)) { | |
541 | + gam_inotify_directory_handler_internal(path, mode); | |
542 | + } else { | |
543 | + char *dir; | |
544 | ||
545 | - // gamins event vocabulary is very small compared to inotify | |
546 | - // so we often will receieve events that have no equivelant | |
547 | - // in gamin | |
548 | - if (gevent == GAMIN_EVENT_UNKNOWN) { | |
549 | - return; | |
550 | + dir = g_path_get_dirname(path); | |
551 | + GAM_DEBUG(DEBUG_INFO, " not a dir using parent %s\n", dir); | |
552 | + gam_inotify_directory_handler_internal(dir, mode); | |
553 | + g_free(dir); | |
554 | } | |
555 | - if (event->name[0] != '\0' && !data->path_file) { | |
556 | - int pathlen = strlen(data->path); | |
557 | +} | |
558 | ||
559 | - if (data->path[pathlen - 1] == '/') { | |
560 | - event_path = g_strconcat(data->path, event->name, NULL); | |
561 | - } else { | |
562 | - event_path = g_strconcat(data->path, "/", event->name, NULL); | |
563 | - } | |
564 | - } else { | |
565 | - event_path = g_strdup(data->path); | |
566 | - } | |
567 | +/* Must be called with inotify lock locked */ | |
568 | +static void | |
569 | +gam_inotify_dirty_list_cleaner () | |
570 | +{ | |
571 | + GList *l; | |
572 | + | |
573 | + /* Here we walk the old dirty list and create a new one. | |
574 | + * if we don't poll a node on the old list, we add it to the new one */ | |
575 | + | |
576 | + l = dirty_list; | |
577 | + dirty_list = NULL; | |
578 | ||
579 | - GAM_DEBUG(DEBUG_INFO, "inotify emitting event %s for %s\n", | |
580 | - gam_event_to_string(gevent), event_path); | |
581 | + for (l = l; l; l = l->next) { | |
582 | + inotify_data_t *data = l->data; | |
583 | ||
584 | - gam_server_emit_event(event_path, 0, gevent, data->subs, 1); | |
585 | + g_assert (data->dirty); | |
586 | + | |
587 | + if (g_timer_elapsed (data->poll_timer, NULL) >= MIN_POLL_TIME) { | |
588 | + data->dirty = FALSE; | |
589 | + gam_poll_scan_directory (data->path); | |
590 | + } else { | |
591 | + dirty_list = g_list_append (dirty_list, data); | |
592 | + } | |
593 | + } | |
594 | ||
595 | - g_free(event_path); | |
596 | + g_list_free (l); | |
597 | } | |
598 | ||
599 | static gboolean | |
600 | @@ -276,71 +422,76 @@ | |
601 | { | |
602 | char *buffer; | |
603 | int buffer_size; | |
604 | + int events; | |
605 | gsize buffer_i, read_size; | |
606 | ||
607 | G_LOCK(inotify); | |
608 | ||
609 | - if (ioctl(fd, FIONREAD, &buffer_size) < 0) { | |
610 | - G_UNLOCK(inotify); | |
611 | - GAM_DEBUG(DEBUG_INFO, "inotify FIONREAD < 0. kaboom!\n"); | |
612 | - return FALSE; | |
613 | +#if 0 | |
614 | + gam_inotify_dirty_list_cleaner (); | |
615 | +#endif | |
616 | + | |
617 | + if (ioctl(inotify_device_fd, FIONREAD, &buffer_size) < 0) { | |
618 | + G_UNLOCK(inotify); | |
619 | + GAM_DEBUG(DEBUG_INFO, "inotify FIONREAD < 0. kaboom!\n"); | |
620 | + return FALSE; | |
621 | } | |
622 | ||
623 | buffer = g_malloc(buffer_size); | |
624 | ||
625 | - if (g_io_channel_read_chars | |
626 | - (inotify_read_ioc, (char *) buffer, buffer_size, &read_size, | |
627 | - NULL) != G_IO_STATUS_NORMAL) { | |
628 | - G_UNLOCK(inotify); | |
629 | - GAM_DEBUG(DEBUG_INFO, | |
630 | - "inotify failed to read events from inotify fd.\n"); | |
631 | - g_free(buffer); | |
632 | - return FALSE; | |
633 | + if (g_io_channel_read_chars(inotify_read_ioc, (char *)buffer, buffer_size, &read_size, NULL) != G_IO_STATUS_NORMAL) { | |
634 | + G_UNLOCK(inotify); | |
635 | + GAM_DEBUG(DEBUG_INFO, "inotify failed to read events from inotify fd.\n"); | |
636 | + g_free (buffer); | |
637 | + return FALSE; | |
638 | } | |
639 | ||
640 | buffer_i = 0; | |
641 | + events = 0; | |
642 | while (buffer_i < read_size) { | |
643 | - struct inotify_event *event; | |
644 | - gsize event_size; | |
645 | - INotifyData *data; | |
646 | - | |
647 | - event = (struct inotify_event *) &buffer[buffer_i]; | |
648 | - event_size = sizeof(struct inotify_event) + event->len; | |
649 | - | |
650 | - data = g_hash_table_lookup(wd_hash, GINT_TO_POINTER(event->wd)); | |
651 | - if (!data) { | |
652 | - GAM_DEBUG(DEBUG_INFO, "inotify can't find wd %d\n", event->wd); | |
653 | - GAM_DEBUG(DEBUG_INFO, | |
654 | - "weird things have happened to inotify.\n"); | |
655 | - } else { | |
656 | - /* Do the shit with the event */ | |
657 | - if (event->mask == IN_IGNORED) { | |
658 | - GList *l; | |
659 | - | |
660 | - l = data->subs; | |
661 | - data->subs = NULL; | |
662 | - for (l = l; l; l = l->next) { | |
663 | - GamSubscription *sub = l->data; | |
664 | - | |
665 | - gam_inotify_remove_subscription(sub); | |
666 | - } | |
667 | - } else { | |
668 | - if (data->path_file) { | |
669 | - if (event->name[0] != '\0') { | |
670 | - int pathlen = strlen(data->path_file); | |
671 | - | |
672 | - if (strcmp(data->path_file, event->name)) { | |
673 | - buffer_i += event_size; | |
674 | - continue; | |
675 | - } | |
676 | - } | |
677 | - } | |
678 | - gam_inotify_emit_event(data, event); | |
679 | - } | |
680 | - } | |
681 | + struct inotify_event *event; | |
682 | + gsize event_size; | |
683 | + inotify_data_t *data; | |
684 | + | |
685 | + event = (struct inotify_event *)&buffer[buffer_i]; | |
686 | + event_size = sizeof(struct inotify_event) + event->len; | |
687 | + | |
688 | + data = g_hash_table_lookup (wd_hash, GINT_TO_POINTER(event->wd)); | |
689 | + if (!data) { | |
690 | + GAM_DEBUG(DEBUG_INFO, "inotify can't find wd %d\n", event->wd); | |
691 | + } else { | |
692 | + if (event->mask == IN_IGNORED || event->mask == IN_UNMOUNT) { | |
693 | + GList *l; | |
694 | + | |
695 | + l = data->subs; | |
696 | + data->subs = NULL; | |
697 | + for (l = l; l; l = l->next) { | |
698 | + GamSubscription *sub = l->data; | |
699 | + gam_inotify_remove_subscription (sub); | |
700 | + } | |
701 | + } else if (event->mask != IN_Q_OVERFLOW) { | |
702 | + if (event->mask & should_poll_mask) { | |
703 | + GAM_DEBUG(DEBUG_INFO, "inotify requesting poll for %s\n", data->path); | |
704 | + GAM_DEBUG(DEBUG_INFO, "poll was requested for event = "); | |
705 | + print_mask (event->mask); | |
706 | + gam_poll_scan_directory (data->path); | |
707 | +#if 0 | |
708 | + /* if node isn't dirty */ | |
709 | + if (!data->dirty) { | |
710 | + /* Put this node on the dirty list */ | |
711 | + data->dirty = TRUE; | |
712 | + g_timer_start(data->poll_timer); | |
713 | + dirty_list = g_list_append (dirty_list, data); | |
714 | + } | |
715 | +#endif | |
716 | + } | |
717 | + } | |
718 | + } | |
719 | ||
720 | buffer_i += event_size; | |
721 | + events++; | |
722 | } | |
723 | + GAM_DEBUG(DEBUG_INFO, "inotify recieved %d events\n", events); | |
724 | ||
725 | g_free(buffer); | |
726 | G_UNLOCK(inotify); | |
727 | @@ -348,48 +499,12 @@ | |
728 | return TRUE; | |
729 | } | |
730 | ||
731 | + | |
732 | static gboolean | |
733 | gam_inotify_consume_subscriptions_real(gpointer data) | |
734 | { | |
735 | - GList *subs, *l; | |
736 | - | |
737 | - G_LOCK(new_subs); | |
738 | - if (new_subs) { | |
739 | - subs = new_subs; | |
740 | - new_subs = NULL; | |
741 | - G_UNLOCK(new_subs); | |
742 | - | |
743 | - for (l = subs; l; l = l->next) { | |
744 | - GamSubscription *sub = l->data; | |
745 | - | |
746 | - GAM_DEBUG(DEBUG_INFO, "called gam_inotify_add_handler()\n"); | |
747 | - gam_inotify_add_rm_handler(gam_subscription_get_path(sub), sub, | |
748 | - TRUE); | |
749 | - } | |
750 | - | |
751 | - } else { | |
752 | - G_UNLOCK(new_subs); | |
753 | - } | |
754 | - | |
755 | - G_LOCK(removed_subs); | |
756 | - if (removed_subs) { | |
757 | - subs = removed_subs; | |
758 | - removed_subs = NULL; | |
759 | - G_UNLOCK(removed_subs); | |
760 | - | |
761 | - for (l = subs; l; l = l->next) { | |
762 | - GamSubscription *sub = l->data; | |
763 | - | |
764 | - GAM_DEBUG(DEBUG_INFO, "called gam_inotify_rm_handler()\n"); | |
765 | - gam_inotify_add_rm_handler(gam_subscription_get_path(sub), sub, | |
766 | - FALSE); | |
767 | - } | |
768 | - } else { | |
769 | - G_UNLOCK(removed_subs); | |
770 | - } | |
771 | - | |
772 | - GAM_DEBUG(DEBUG_INFO, "gam_inotify_consume_subscriptions()\n"); | |
773 | - | |
774 | + GAM_DEBUG(DEBUG_INFO, "gam_inotify_consume_subscriptions_real()\n"); | |
775 | + gam_poll_consume_subscriptions(); | |
776 | have_consume_idler = FALSE; | |
777 | return FALSE; | |
778 | } | |
779 | @@ -402,30 +517,31 @@ | |
780 | if (have_consume_idler) | |
781 | return; | |
782 | ||
783 | + GAM_DEBUG(DEBUG_INFO, "gam_inotify_consume_subscriptions()\n"); | |
784 | have_consume_idler = TRUE; | |
785 | - | |
786 | source = g_idle_source_new(); | |
787 | g_source_set_callback(source, gam_inotify_consume_subscriptions_real, | |
788 | NULL, NULL); | |
789 | - | |
790 | g_source_attach(source, NULL); | |
791 | } | |
792 | ||
793 | /** | |
794 | - * @defgroup inotify inotify backend | |
795 | + * @defgroup inotify inotify Backend | |
796 | * @ingroup Backends | |
797 | * @brief inotify backend API | |
798 | * | |
799 | * Since version 2.6.X, Linux kernels have included the Linux Inode | |
800 | * Notification system (inotify). This backend uses inotify to know when | |
801 | - * files are changed/created/deleted. | |
802 | + * files are changed/created/deleted. Since inotify can't watch files/dirs that | |
803 | + * don't exist we still have to cache stat() information. For this, | |
804 | + * we can just use the code in the polling backend. | |
805 | * | |
806 | * @{ | |
807 | */ | |
808 | ||
809 | ||
810 | /** | |
811 | - * Initializes the inotify system. This must be called before | |
812 | + * Initializes the inotify backend. This must be called before | |
813 | * any other functions in this module. | |
814 | * | |
815 | * @returns TRUE if initialization succeeded, FALSE otherwise | |
816 | @@ -435,14 +551,16 @@ | |
817 | { | |
818 | GSource *source; | |
819 | ||
820 | - fd = open("/dev/inotify", O_RDONLY); | |
821 | + inotify_device_fd = open("/dev/inotify", O_RDONLY); | |
822 | ||
823 | - if (fd < 0) { | |
824 | - GAM_DEBUG(DEBUG_INFO, "Could not open /dev/inotify\n"); | |
825 | - return FALSE; | |
826 | + if (inotify_device_fd < 0) { | |
827 | + GAM_DEBUG(DEBUG_INFO, "Could not open /dev/inotify\n"); | |
828 | + return FALSE; | |
829 | } | |
830 | ||
831 | - inotify_read_ioc = g_io_channel_unix_new(fd); | |
832 | + g_return_val_if_fail(gam_poll_init_full(FALSE), FALSE); | |
833 | + | |
834 | + inotify_read_ioc = g_io_channel_unix_new(inotify_device_fd); | |
835 | ||
836 | /* For binary data */ | |
837 | g_io_channel_set_encoding(inotify_read_ioc, NULL, NULL); | |
838 | @@ -450,13 +568,15 @@ | |
839 | g_io_channel_set_flags(inotify_read_ioc, G_IO_FLAG_NONBLOCK, NULL); | |
840 | ||
841 | source = g_io_create_watch(inotify_read_ioc, | |
842 | - G_IO_IN | G_IO_HUP | G_IO_ERR); | |
843 | + G_IO_IN | G_IO_HUP | G_IO_ERR); | |
844 | g_source_set_callback(source, gam_inotify_read_handler, NULL, NULL); | |
845 | ||
846 | g_source_attach(source, NULL); | |
847 | ||
848 | path_hash = g_hash_table_new(g_str_hash, g_str_equal); | |
849 | wd_hash = g_hash_table_new(g_direct_hash, g_direct_equal); | |
850 | + gam_poll_set_directory_handler(gam_inotify_directory_handler); | |
851 | + gam_poll_set_file_handler(gam_inotify_file_handler); | |
852 | ||
853 | GAM_DEBUG(DEBUG_INFO, "inotify initialized\n"); | |
854 | ||
855 | @@ -476,15 +596,14 @@ | |
856 | gboolean | |
857 | gam_inotify_add_subscription(GamSubscription * sub) | |
858 | { | |
859 | - gam_listener_add_subscription(gam_subscription_get_listener(sub), sub); | |
860 | - | |
861 | - G_LOCK(new_subs); | |
862 | - new_subs = g_list_prepend(new_subs, sub); | |
863 | - G_UNLOCK(new_subs); | |
864 | - | |
865 | - GAM_DEBUG(DEBUG_INFO, "inotify_add_sub\n"); | |
866 | + GAM_DEBUG(DEBUG_INFO, "gam_inotify_add_subscription\n"); | |
867 | + if (!gam_poll_add_subscription(sub)) { | |
868 | + return FALSE; | |
869 | + } | |
870 | ||
871 | gam_inotify_consume_subscriptions(); | |
872 | + | |
873 | + GAM_DEBUG(DEBUG_INFO, "gam_inotify_add_subscription: done\n"); | |
874 | return TRUE; | |
875 | } | |
876 | ||
877 | @@ -497,26 +616,15 @@ | |
878 | gboolean | |
879 | gam_inotify_remove_subscription(GamSubscription * sub) | |
880 | { | |
881 | - G_LOCK(new_subs); | |
882 | - if (g_list_find(new_subs, sub)) { | |
883 | - GAM_DEBUG(DEBUG_INFO, "removed sub found on new_subs\n"); | |
884 | - new_subs = g_list_remove_all(new_subs, sub); | |
885 | - G_UNLOCK(new_subs); | |
886 | - return TRUE; | |
887 | - } | |
888 | - G_UNLOCK(new_subs); | |
889 | - | |
890 | - gam_subscription_cancel(sub); | |
891 | - gam_listener_remove_subscription(gam_subscription_get_listener(sub), | |
892 | - sub); | |
893 | - | |
894 | - G_LOCK(removed_subs); | |
895 | - removed_subs = g_list_prepend(removed_subs, sub); | |
896 | - G_UNLOCK(removed_subs); | |
897 | + GAM_DEBUG(DEBUG_INFO, "gam_inotify_remove_subscription\n"); | |
898 | + | |
899 | + if (!gam_poll_remove_subscription(sub)) { | |
900 | + return FALSE; | |
901 | + } | |
902 | ||
903 | - GAM_DEBUG(DEBUG_INFO, "inotify_remove_sub\n"); | |
904 | gam_inotify_consume_subscriptions(); | |
905 | ||
906 | + GAM_DEBUG(DEBUG_INFO, "gam_inotify_remove_subscription: done\n"); | |
907 | return TRUE; | |
908 | } | |
909 | ||
910 | @@ -529,26 +637,13 @@ | |
911 | gboolean | |
912 | gam_inotify_remove_all_for(GamListener * listener) | |
913 | { | |
914 | - GList *subs, *l = NULL; | |
915 | - | |
916 | - subs = gam_listener_get_subscriptions(listener); | |
917 | - | |
918 | - for (l = subs; l; l = l->next) { | |
919 | - GamSubscription *sub = l->data; | |
920 | - | |
921 | - g_assert(sub != NULL); | |
922 | - | |
923 | - gam_inotify_remove_subscription(sub); | |
924 | - | |
925 | - } | |
926 | - | |
927 | - if (subs) { | |
928 | - g_list_free(subs); | |
929 | - gam_inotify_consume_subscriptions(); | |
930 | - return TRUE; | |
931 | - } else { | |
932 | + if (!gam_poll_remove_all_for(listener)) { | |
933 | return FALSE; | |
934 | } | |
935 | + | |
936 | + gam_inotify_consume_subscriptions(); | |
937 | + | |
938 | + return TRUE; | |
939 | } | |
940 | ||
941 | /** @} */ | |
942 | Index: server/gam_inotify.h | |
943 | =================================================================== | |
944 | RCS file: /cvs/gnome/gamin/server/gam_inotify.h,v | |
945 | retrieving revision 1.1 | |
946 | diff -u -r1.1 gam_inotify.h | |
947 | --- server/gam_inotify.h 27 Jul 2004 10:24:43 -0000 1.1 | |
948 | +++ server/gam_inotify.h 14 Apr 2005 16:44:34 -0000 | |
949 | @@ -1,6 +1,5 @@ | |
950 | - | |
951 | -#ifndef __MD_INOTIFY_H__ | |
952 | -#define __MD_INOTIFY_H__ | |
953 | +#ifndef __GAM_INOTIFY_H__ | |
954 | +#define __GAM_INOTIFY_H__ | |
955 | ||
956 | #include <glib.h> | |
957 | #include "gam_poll.h" | |
958 | @@ -15,4 +14,4 @@ | |
959 | ||
960 | G_END_DECLS | |
961 | ||
962 | -#endif /* __MD_INOTIFY_H__ */ | |
963 | +#endif /* __GAM_INOTIFY_H__ */ | |
964 |