rust/cargo-c: update to 0.10.7+cargo-0.84.0
[oi-userland.git] / components / library / gamin / patches / 01-FEN.patch
blobe68f1262ee21cb1e1f91c200db6e5da4e999db95
1 Solaris FEN support in Gamin
3 https://bugzilla.gnome.org/show_bug.cgi?id=730679
4 http://osdyson.org/issues/172
5 http://hg.osdyson.org/solaris-desktop-spec-files/raw-file/8f7c0cd200a9/patches/gamin-01-all.diff
7 Fixed issues after the initial integration:
8 1) Using freed node_t pointer in node_add function.
9 Mitigation: When a node is removed, we also remove all the events in the
10 event queue that contain a reference to this node to avoid future memory errors.
11 2) A missing call to node_lstat before calling port_add function.
12 When the system is under load, the timing of callbacks might cause that port_add is
13 called on a node which access, change, and modification time was not read/updated.
14 Mitigation: Call node_lstat before port_add in node_add_event function.
16 diff --git a/configure.in b/configure.in
17 index e4b684e..5836bb7 100644
18 --- a/configure.in
19 +++ b/configure.in
20 @@ -42,6 +42,12 @@ if test -z "$ENV_CFLAGS"; then
21 CFLAGS=""
24 +dnl If the user set no CFLAGS, then don't assume the autotools defaults of
25 +dnl "-g -O2". We set default CFLAGS later based on the --disable-debug flag.
26 +if test -z "$ENV_CFLAGS"; then
27 + CFLAGS=""
28 +fi
30 dnl for the spec file
31 RELDATE=`date +'%a %b %e %Y'`
32 AC_SUBST(RELDATE)
33 @@ -279,6 +285,43 @@ if test x$kqueue = xtrue; then
34 backends="${backends}, kqueue"
37 +case "$os" in
38 + solaris*)
39 + AM_CONDITIONAL(ON_SOLARIS, true)
40 + AC_COMPILE_IFELSE([
41 + #include <port.h>
42 + #ifndef PORT_SOURCE_FILE
43 + #error "Please upgrade to Nevada 72 or above to suppoert FEN"
44 + #endif
45 + int main() { return 0; }
46 + ],[have_fen=1],)
47 + if test x$have_fen = x1 ; then
48 + AC_ARG_ENABLE(fen,
49 + AC_HELP_STRING([--disable-fen], [Disable the FEN backend]),
50 + [fen="${enableval}"], [fen=true])
52 + if test x$fen = xyes; then
53 + fen=true
54 + elif test x$fen = xno; then
55 + fen=false
56 + elif test x$fen != xtrue; then
57 + AC_MSG_ERROR(bad value ${enableval} for --disable-fen)
58 + fi
59 + fi
60 + break;
61 + ;;
62 + *)
63 + fen=false
64 + break;
65 + ;;
66 +esac
68 +AM_CONDITIONAL(ENABLE_FEN, test x$fen = xtrue)
69 +if test x$fen = xtrue; then
70 + AC_DEFINE(ENABLE_FEN,1,[Use Solaris FEN as backend])
71 + backends="${backends}, FEN"
72 +fi
74 dnl pthread support for reentrance of the client library.
75 AC_ARG_WITH(threads,
76 [ --with-threads add multithread support(on)])
77 @@ -385,6 +428,14 @@ if test x$dbus_have_struct_cmsgcred = xyes; then
78 AC_DEFINE(HAVE_CMSGCRED,1,[Have cmsgcred structure])
81 +dnl Check for getpeerucred support - Solaris
83 +AC_CHECK_HEADER(ucred.h,
84 + AC_CHECK_LIB(c, getpeerucred,[
85 + AC_DEFINE([HAVE_GETPEERUCRED],[],[Define if has getpeerucred])
86 + AC_DEFINE([HAVE_UCRED_H],[],[Define if <ucred.h> exists])]))
89 #### Abstract sockets
91 AC_MSG_CHECKING(abstract socket namespace)
92 @@ -529,6 +580,16 @@ AC_SUBST(PYTHON_VERSION)
93 AC_SUBST(PYTHON_INCLUDES)
94 AC_SUBST(PYTHON_SITE_PACKAGES)
96 +dnl Check for -lsocket -lnsl
98 +AC_CHECK_FUNC(gethostent, , AC_CHECK_LIB(nsl, gethostent))
99 +AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt))
101 +dnl Check for <sys/mnttab.h>
103 +AC_CHECK_HEADER(sys/mnttab.h,
104 + AC_DEFINE([HAVE_SYS_MNTTAB_H], [], [Define if <sys/mnttab.h> is there]))
106 dnl After all config-related tweaking of CFLAGS, set it to its "build" value
108 AC_MSG_CHECKING(for more compiler warnings)
109 diff --git a/libgamin/Makefile.am b/libgamin/Makefile.am
110 index 35aa740..4f725a2 100644
111 --- a/libgamin/Makefile.am
112 +++ b/libgamin/Makefile.am
113 @@ -39,13 +39,24 @@ CLEANFILES=gam_error.c gam_event.c
115 libgamin_1_la_LIBADD =
117 +if ON_SOLARIS
118 +libgamin_1_la_LDFLAGS = -Wl,-M$(srcdir)/gamin_sym.version \
119 + -version-info @GAMIN_VERSION_INFO@ @THREAD_LIBS@
120 +else
121 libgamin_1_la_LDFLAGS = -Wl,--version-script=$(srcdir)/gamin_sym.version \
122 -version-info @GAMIN_VERSION_INFO@ @THREAD_LIBS@
123 +endif
125 libfam_la_SOURCES = $(libgamin_1_la_SOURCES)
126 libfam_la_LIBADD = $(libgamin_1_la_LIBADD)
127 -libfam_la_LDFLAGS = -Wl,--version-script=$(srcdir)/gamin_sym.version \
129 +if ON_SOLARIS
130 +libfam_la_LDFLAGS = -Wl,-M$(srcdir)/gamin_sym.version \
131 -version-info @FAM_VERSION_INFO@ @THREAD_LIBS@
132 +else
133 +libfam_la_LDFLAGS = -Wl,--version-script=$(srcdir)/gamin_sym.version \
134 + -version-info @FAM_VERSION_INFO@ @THREAD_LIBS@
135 +endif
138 # Compile a program locally to check
139 diff --git a/libgamin/gam_api.c b/libgamin/gam_api.c
140 index 4e87e63..3630213 100644
141 --- a/libgamin/gam_api.c
142 +++ b/libgamin/gam_api.c
143 @@ -14,6 +14,12 @@
144 #include <sys/socket.h>
145 #include <sys/un.h>
146 #include <sys/uio.h>
147 +#if defined(sun)
148 +#include <string.h>
149 +#endif
150 +#if defined(HAVE_UCRED_H)
151 +#include <ucred.h>
152 +#endif defined(HAVE_UCRED_H)
153 #include "fam.h"
154 #include "gam_protocol.h"
155 #include "gam_data.h"
156 @@ -660,6 +666,10 @@ gamin_check_cred(GAMDataPtr conn, int fd)
157 } cmsg;
158 #endif
160 +#if defined(HAVE_GETPEERUCRED)
161 + ucred_t *creds;
162 +#endif
164 s_uid = getuid();
166 #if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
167 @@ -726,11 +736,25 @@ retry:
168 fd, cr_len, (int) sizeof(cr));
169 goto failed;
171 +#elif defined(HAVE_GETPEERUCRED)
172 + if ((creds = (ucred_t *)malloc(ucred_size()))==(ucred_t *)NULL){
173 + GAM_DEBUG(DEBUG_INFO,"Malloc failed for ucreds");
174 + goto failed;
177 + if (getpeerucred(fd, &creds)!=0){
178 + GAM_DEBUG(DEBUG_INFO,"getpeerucred call failed");
179 + goto failed;
181 + c_uid = ucred_getruid(creds);
182 + c_gid = ucred_getrgid(creds);
183 + c_pid = ucred_getpid(creds);
184 + ucred_free(creds);
185 #elif defined(HAVE_CMSGCRED)
186 c_pid = cmsg.cred.cmcred_pid;
187 c_uid = cmsg.cred.cmcred_euid;
188 c_gid = cmsg.cred.cmcred_groups[0];
189 -#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
190 +#else /* !SO_PEERCRED && !HAVE_CMSGCRED && !HAVE_GETPEERUCRED */
191 GAM_DEBUG(DEBUG_INFO,
192 "Socket credentials not supported on this OS\n");
193 goto failed;
194 diff --git a/libgamin/gamin_sym.version b/libgamin/gamin_sym.version
195 index dba5f20..5c6d661 100644
196 --- a/libgamin/gamin_sym.version
197 +++ b/libgamin/gamin_sym.version
198 @@ -2,8 +2,6 @@
199 global:
200 FAMCancelMonitor;
201 FAMClose;
202 - FAMDebugLevel;
203 - FAMDebug;
204 FamErrlist;
205 FAMErrno;
206 FAMMonitorCollection;
207 diff --git a/server/Makefile.am b/server/Makefile.am
208 index 37aed8b..7964d17 100644
209 --- a/server/Makefile.am
210 +++ b/server/Makefile.am
211 @@ -10,7 +10,7 @@ INCLUDES = \
212 -DG_DISABLE_DEPRECATED
214 if GAMIN_DEBUG
215 -INCLUDES += -DGAM_DEBUG_ENABLED
216 +INCLUDES += -DGAM_DEBUG_ENABLED -g
217 endif
220 @@ -68,6 +68,18 @@ if ENABLE_KQUEUE
221 gam_server_SOURCES += gam_kqueue.c gam_kqueue.h
222 endif
224 +if ENABLE_FEN
225 +gam_server_SOURCES += gam_fen.c gam_fen.h \
226 + fen-dump.c \
227 + fen-dump.h \
228 + fen-kernel.c \
229 + fen-kernel.h \
230 + fen-helper.c \
231 + fen-helper.h \
232 + fen-node.c \
233 + fen-node.h
234 +endif
236 if ENABLE_HURD_MACH_NOTIFY
237 gam_server_SOURCES += gam_hurd_mach_notify.c gam_hurd_mach_notify.h
239 diff --git a/server/fen-dump.c b/server/fen-dump.c
240 new file mode 100644
241 index 0000000..98d20eb
242 --- /dev/null
243 +++ b/server/fen-dump.c
244 @@ -0,0 +1,77 @@
245 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
246 +/* vim:set expandtab ts=4 shiftwidth=4: */
247 +/*
248 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
249 + * reserved.
251 + * This library is free software; you can redistribute it and/or
252 + * modify it under the terms of the GNU Lesser General Public
253 + * License as published by the Free Software Foundation; either
254 + * version 2 of the License, or (at your option) any later version.
256 + * This library is distributed in the hope that it will be useful,
257 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
258 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
259 + * Lesser General Public License for more details.
261 + * You should have received a copy of the GNU Lesser General
262 + * Public License along with this library; if not, write to the
263 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
264 + * Boston, MA 02111-1307, USA.
266 + * Authors: Lin Ma <lin.ma@sun.com>
267 + */
269 +#include "config.h"
270 +#include <glib.h>
271 +#include <glib/gprintf.h>
272 +#include "fen-node.h"
273 +#include "fen-dump.h"
275 +G_LOCK_EXTERN (fen_lock);
277 +/*-------------------- node ------------------*/
278 +static void
279 +dump_node (node_t* node, gpointer data)
281 + g_printf ("n:0x%p ds:0x%p s:0x%p %s\n", node, node->dir_subs, node->subs, NODE_NAME(node));
284 +static void
285 +dump_tree (node_t* node)
287 + if (G_TRYLOCK (fen_lock)) {
288 + node_traverse(NULL, dump_node, NULL);
289 + G_UNLOCK (fen_lock);
293 +/* ------------------ fdata port hash --------------------*/
294 +void
295 +dump_hash_cb (gpointer key,
296 + gpointer value,
297 + gpointer user_data)
299 + g_printf ("k:0x%p v:0x%p >\n", key, value);
302 +gboolean
303 +dump_hash (GHashTable* hash, gpointer user_data)
305 + if (G_TRYLOCK (fen_lock)) {
306 + if (g_hash_table_size (hash) > 0) {
307 + g_hash_table_foreach (hash, dump_hash_cb, user_data);
309 + G_UNLOCK (fen_lock);
311 + return TRUE;
314 +/* ------------------ event --------------------*/
315 +void
316 +dump_event (node_event_t* ev, gpointer user_data)
318 + node_t* node = ev->user_data;
319 + g_printf ("ne:0x%p e:%p n:0x%p ds:0x%p s:0x%p s\n", ev, ev->e, node, node->dir_subs, node->subs, NODE_NAME(node));
322 diff --git a/server/fen-dump.h b/server/fen-dump.h
323 new file mode 100644
324 index 0000000..ffac822
325 --- /dev/null
326 +++ b/server/fen-dump.h
327 @@ -0,0 +1,29 @@
328 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
329 +/* vim:set expandtab ts=4 shiftwidth=4: */
330 +/*
331 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
332 + * reserved.
334 + * This library is free software; you can redistribute it and/or
335 + * modify it under the terms of the GNU Lesser General Public
336 + * License as published by the Free Software Foundation; either
337 + * version 2 of the License, or (at your option) any later version.
339 + * This library is distributed in the hope that it will be useful,
340 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
341 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
342 + * Lesser General Public License for more details.
344 + * You should have received a copy of the GNU Lesser General
345 + * Public License along with this library; if not, write to the
346 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
347 + * Boston, MA 02111-1307, USA.
349 + * Authors: Lin Ma <lin.ma@sun.com>
350 + */
352 +#ifndef _FEN_DUMP_H_
353 +#define _FEN_DUMP_H_
356 +#endif /* _FEN_DUMP_H_ */
357 diff --git a/server/fen-helper.c b/server/fen-helper.c
358 new file mode 100644
359 index 0000000..e68e7c3
360 --- /dev/null
361 +++ b/server/fen-helper.c
362 @@ -0,0 +1,197 @@
363 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
364 +/* vim:set expandtab ts=4 shiftwidth=4: */
365 +/*
366 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
367 + * reserved.
369 + * This library is free software; you can redistribute it and/or
370 + * modify it under the terms of the GNU Lesser General Public
371 + * License as published by the Free Software Foundation; either
372 + * version 2 of the License, or (at your option) any later version.
374 + * This library is distributed in the hope that it will be useful,
375 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
376 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
377 + * Lesser General Public License for more details.
379 + * You should have received a copy of the GNU Lesser General
380 + * Public License along with this library; if not, write to the
381 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
382 + * Boston, MA 02111-1307, USA.
384 + * Authors: Lin Ma <lin.ma@sun.com>
385 + */
387 +#include "config.h"
388 +#include <glib.h>
389 +#include "fen-helper.h"
390 +#include "fen-kernel.h"
391 +#ifdef GIO_COMPILATION
392 +#include "gfilemonitor.h"
393 +#else
394 +#include "gam_event.h"
395 +#include "gam_server.h"
396 +#include "gam_protocol.h"
397 +#endif
399 +#ifdef GIO_COMPILATION
400 +#define FH_W if (fh_debug_enabled) g_debug
401 +static gboolean fh_debug_enabled = FALSE;
402 +#else
403 +#include "gam_error.h"
404 +#define FH_W(...) GAM_DEBUG(DEBUG_INFO, __VA_ARGS__)
405 +#endif
407 +G_LOCK_EXTERN (fen_lock);
409 +/* misc */
410 +static void
411 +scan_children_init(node_t *f, gpointer sub)
413 + gboolean emit;
414 + gint event;
416 + FH_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f);
418 +#ifdef GIO_COMPILATION
419 + emit = FALSE;
420 + event = G_FILE_MONITOR_EVENT_CREATED;
421 +#else
422 + emit = TRUE;
423 + event = GAMIN_EVENT_EXISTS;
424 +#endif
426 + if (!NODE_HAS_FLAG(f, NODE_FLAG_SNAPSHOT_UPDATED)) {
427 + /* TODO snapshot should also compare to the sub created timestamp. */
428 + /* GIO initially doesn't emit created/existed events. */
429 + node_create_children_snapshot(f, event, emit);
430 + } else {
431 + GHashTableIter iter;
432 + gpointer value;
434 + g_hash_table_iter_init (&iter, f->children);
435 + while (g_hash_table_iter_next (&iter, NULL, &value)) {
436 + node_t *child = (node_t *)value;
438 +#ifdef GIO_COMPILATION
439 + /* GIO initially doesn't emit created/existed events. */
440 + /* g_file_monitor_emit_event(G_FILE_MONITOR(sub), child->gfile, NULL, event); */
441 +#else
442 + gam_server_emit_one_event(NODE_NAME(child), gam_subscription_is_dir(sub), event, sub, 1);
443 +#endif
448 +/**
449 + * fen_add
450 + *
451 + * Won't hold a ref, we have a timout callback to clean unused node_t.
452 + * If there is no value for a key, add it and return it; else return the old
453 + * one.
454 + */
455 +void
456 +fen_add (const gchar *filename, gpointer sub, gboolean is_mondir)
458 + node_t* f;
460 + g_assert (filename);
461 + g_assert (sub);
463 + G_LOCK (fen_lock);
464 + f = node_find(NULL, filename, TRUE);
465 + FH_W ("%s 0x%p sub[0x%p] %s\n", __func__, f, sub, filename);
466 + g_assert (f);
468 + /* Update timestamp, the events in global queue will compare itself to this
469 + * timestamp to decide if be emitted. TODO, timestamp should be per sub.
470 + */
471 + if (!NODE_IS_ACTIVE(f)) {
472 + g_get_current_time(&f->atv);
475 + if (is_mondir) {
476 + f->dir_subs = g_list_prepend(f->dir_subs, sub);
477 + } else {
478 + f->subs = g_list_prepend(f->subs, sub);
481 + if (NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED) ||
482 + (node_lstat(f) == 0 && port_add(f) == 0)) {
483 +#ifndef GIO_COMPILATION
484 + gam_server_emit_one_event (NODE_NAME(f),
485 + gam_subscription_is_dir (sub), GAMIN_EVENT_EXISTS, sub, 1);
486 +#endif
487 + if (is_mondir) {
488 + scan_children_init (f, sub);
490 + } else {
491 +#ifndef GIO_COMPILATION
492 + gam_server_emit_one_event (NODE_NAME(f),
493 + gam_subscription_is_dir (sub), GAMIN_EVENT_DELETED, sub, 1);
494 +#endif
495 + node_adjust_deleted (f);
497 +#ifndef GIO_COMPILATION
498 + gam_server_emit_one_event (NODE_NAME(f),
499 + gam_subscription_is_dir (sub), GAMIN_EVENT_ENDEXISTS, sub, 1);
500 +#endif
501 + G_UNLOCK (fen_lock);
504 +void
505 +fen_remove (const gchar *filename, gpointer sub, gboolean is_mondir)
507 + node_t* f;
509 + g_assert (filename);
510 + g_assert (sub);
512 + G_LOCK (fen_lock);
513 + f = node_find(NULL, filename, FALSE);
514 + FH_W ("%s 0x%p sub[0x%p] %s\n", __func__, f, sub, filename);
516 + if (f) {
517 + if (is_mondir) {
518 + f->dir_subs = g_list_remove(f->dir_subs, sub);
519 + } else {
520 + f->subs = g_list_remove(f->subs, sub);
523 + if (!NODE_IS_ACTIVE(f)) {
524 + node_try_delete (f);
527 + G_UNLOCK (fen_lock);
530 +/**
531 + * fen_init:
532 + *
533 + * FEN subsystem initializing.
534 + */
535 +gboolean
536 +fen_init ()
538 + static gboolean initialized = FALSE;
539 + static gboolean result = FALSE;
541 + G_LOCK (fen_lock);
542 + if (initialized) {
543 + G_UNLOCK (fen_lock);
544 + return result;
547 + result = node_class_init();
549 + if (!result) {
550 + G_UNLOCK (fen_lock);
551 + return result;
554 + initialized = TRUE;
556 + G_UNLOCK (fen_lock);
557 + return result;
560 diff --git a/server/fen-helper.h b/server/fen-helper.h
561 new file mode 100644
562 index 0000000..25df38f
563 --- /dev/null
564 +++ b/server/fen-helper.h
565 @@ -0,0 +1,33 @@
566 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
567 +/* vim:set expandtab ts=4 shiftwidth=4: */
568 +/*
569 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
570 + * reserved.
572 + * This library is free software; you can redistribute it and/or
573 + * modify it under the terms of the GNU Lesser General Public
574 + * License as published by the Free Software Foundation; either
575 + * version 2 of the License, or (at your option) any later version.
577 + * This library is distributed in the hope that it will be useful,
578 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
579 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
580 + * Lesser General Public License for more details.
582 + * You should have received a copy of the GNU Lesser General
583 + * Public License along with this library; if not, write to the
584 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
585 + * Boston, MA 02111-1307, USA.
587 + * Authors: Lin Ma <lin.ma@sun.com>
588 + */
590 +#ifndef _FEN_HELPER_H_
591 +#define _FEN_HELPER_H_
593 +void fen_add (const gchar *filename, gpointer sub, gboolean is_mondir);
594 +void fen_remove (const gchar *filename, gpointer sub, gboolean is_mondir);
596 +gboolean fen_init ();
598 +#endif /* _FEN_HELPER_H_ */
599 diff --git a/server/fen-kernel.c b/server/fen-kernel.c
600 new file mode 100644
601 index 0000000..8b9c58b
602 --- /dev/null 2019-12-10 11:10:35.000000000 +0000
603 +++ gamin-0.1.10/server/fen-kernel.c 2019-12-10 11:10:23.000742017 +0000
604 @@ -0,0 +1,574 @@
605 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
606 +/* vim:set expandtab ts=4 shiftwidth=4: */
607 +/*
608 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
609 + * reserved.
611 + * This library is free software; you can redistribute it and/or
612 + * modify it under the terms of the GNU Lesser General Public
613 + * License as published by the Free Software Foundation; either
614 + * version 2 of the License, or (at your option) any later version.
616 + * This library is distributed in the hope that it will be useful,
617 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
618 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
619 + * Lesser General Public License for more details.
621 + * You should have received a copy of the GNU Lesser General
622 + * Public License along with this library; if not, write to the
623 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
624 + * Boston, MA 02111-1307, USA.
626 + * Authors: Lin Ma <lin.ma@sun.com>
627 + */
629 +#include "config.h"
630 +#include <rctl.h>
631 +#include <strings.h>
632 +#include <stdio.h>
633 +#include <stdlib.h>
634 +#include <unistd.h>
635 +#include <glib.h>
636 +#include "fen-kernel.h"
637 +#include "fen-dump.h"
639 +#ifdef GIO_COMPILATION
640 +#define FK_W if (fk_debug_enabled) g_debug
641 +static gboolean fk_debug_enabled = FALSE;
642 +#else
643 +#include "gam_error.h"
644 +#define FK_W(...) GAM_DEBUG(DEBUG_INFO, __VA_ARGS__)
645 +#endif
647 +G_GNUC_INTERNAL G_LOCK_DEFINE (fen_lock);
649 +static ulong max_port_events = 512;
650 +static GList *pn_visible_list; /* the queue of ports which don't have the max objs */
651 +static GQueue *g_eventq = NULL;
652 +static timespec_t zero_wait;
653 +static void (*user_process_events_cb) (gpointer, node_event_t*);
654 +static port_event_t *pevents = NULL;
655 +static gint PE_ALLOC = 2048;
656 +static GHashTable *renamed_hash = NULL; /* <parent node, ev> */
658 +typedef struct _PSource {
659 + GSource source; /* Inherit from GSource, must be the first. */
660 + GPollFD gfd;
661 + gboolean pending;
662 + uint_t event_growing_factor;
663 + uint_t pending_events;
664 +} PSource;
666 +#define PGPFD(s) (&((PSource *)(s))->gfd)
667 +#define SLEEP_BASE_TIME 10 /* in milliseconds */
668 +#define EXPECT_INC_EVENTS(pn) (1 << (pn->event_growing_factor))
670 +#define RENAME_EVENTS_INTERVAL 500 /* in milliseconds */
671 +#define PROCESS_PORT_EVENTS_TIME 1000 /* in milliseconds */
672 +guint process_port_event_id = 0;
674 +static gchar* _event_strings(int event);
675 +static const gchar* _event_string (int event);
676 +static GSource *psource_new();
678 +static gboolean port_prepare(GSource *source, gint *timeout_);
679 +static gboolean port_check(GSource *source);
680 +static gboolean port_dispatch(GSource *source, GSourceFunc callback, gpointer user_data);
681 +static GSourceFuncs fen_source_func = {
682 + port_prepare,
683 + port_check,
684 + port_dispatch,
685 + NULL
688 +static gboolean
689 +port_prepare(GSource *source, gint *timeout_)
691 + return FALSE;
694 +static gboolean
695 +port_check(GSource *source)
697 + PSource *pn = (PSource *)source;
698 + uint_t nget;
700 + if (pn->pending) {
701 + pn->pending = FALSE;
702 + g_source_add_poll(source, PGPFD(source));
703 + g_source_unref(source);
704 + return FALSE;
707 + if (!(PGPFD(pn)->revents & G_IO_IN))
708 + return FALSE;
710 + if (port_getn(PGPFD(source)->fd, NULL, 0, &nget, 0) == 0) {
711 + if (nget - pn->pending_events > EXPECT_INC_EVENTS(pn)) {
712 + /* Sleep for a while. */
713 + pn->pending_events = nget;
714 + pn->event_growing_factor ++;
716 + pn->pending = TRUE;
717 + g_source_ref(source);
718 + g_source_remove_poll(source, PGPFD(source));
719 + g_timeout_add(SLEEP_BASE_TIME,
720 + (GSourceFunc)port_check,
721 + (gpointer)pn);
722 + return FALSE;
726 + pn->pending_events = 0;
727 + pn->event_growing_factor = 0;
729 + return TRUE;
732 +static gboolean
733 +port_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
735 + node_t *f;
736 + uint_t nget = 0;
737 + uint_t total = 0;
739 + FK_W ("%s 0x%p fd %d\n", __func__, source, PGPFD(source)->fd);
741 + G_LOCK (fen_lock);
742 + do {
743 + nget = 1;
744 + if (port_getn(PGPFD(source)->fd, pevents, PE_ALLOC, &nget, &zero_wait) == 0) {
745 + int i;
746 + for (i = 0; i < nget; i++) {
747 + f = (node_t *)pevents[i].portev_user;
749 + if (pevents[i].portev_source == PORT_SOURCE_FILE) {
751 + NODE_CLE_STATE(f, NODE_STATE_ASSOCIATED);
752 + NODE_SET_STATE(f, NODE_STATE_HAS_EVENTS);
754 + if (HAS_NO_EXCEPTION_EVENTS(pevents[i].portev_events)) {
755 + /* If the events do not show it's deleted, update
756 + * file timestamp to avoid missing events next time.
757 + */
758 + if (node_lstat(f) != 0 /* || port_add(f) != 0 */) {
759 + /* Included deleted event. */
760 + pevents[i].portev_events |= FILE_DELETE;
764 + /* Queue it and waiting for processing. */
765 + g_queue_push_tail(g_eventq,
766 + node_event_new(pevents[i].portev_events, (gpointer)f));
768 + } else {
769 + FK_W ("[kernel] unknown portev_source %d\n", pevents[i].portev_source);
773 + total += nget;
775 + } else {
776 + FK_W ("[kernel] port_getn %s\n", g_strerror (errno));
777 + break;
779 + } while (nget == PE_ALLOC);
781 + G_UNLOCK (fen_lock);
783 + if (total > 0 && callback) {
784 + FK_W ("[kernel] get total %ld events\n", total);
785 + return callback (user_data);
787 + return TRUE;
790 +static gboolean
791 +process_renamed_hash_cb(gpointer key, gpointer value, gpointer user_data)
793 + node_event_t *ev = value;
795 +#if 0
796 + node_add_event(ev->user_data, ev);
797 +#else
798 + user_process_events_cb(ev->user_data, ev);
799 +#endif
800 + /* Always delete self from hash. */
801 + return TRUE;
804 +static gboolean
805 +port_events_process_cb(gpointer user_data)
807 + node_event_t *ev;
809 + G_LOCK (fen_lock);
811 + /* Processing g_eventq */
812 + while ((ev = (node_event_t*)g_queue_pop_head (g_eventq)) != NULL) {
814 + /* FK_W ("[%s] 0x%p %s\n", __func__, ev, _event_string (ev->e)); */
817 + gchar *log = _event_strings(ev->e);
818 + FK_W ("%s %s %s\n", __func__, NODE_NAME(ev->user_data), log);
819 + g_free(log);
822 +#ifdef GIO_COMPILATION
823 + /* Use the parent node as a hash, because only the dir_subs in the
824 + * parent node should receive MOVE event.
825 + */
826 + if (NODE_PARENT(ev->user_data)) {
827 + if (ev->e == FILE_RENAME_TO) {
828 + g_hash_table_insert(renamed_hash, NODE_PARENT(ev->user_data), ev);
829 + g_time_val_add(&ev->rename_tv, RENAME_EVENTS_INTERVAL);
830 + continue;
832 + if (ev->e == FILE_RENAME_FROM) {
833 + node_event_t *pair_ev;
835 + pair_ev = g_hash_table_lookup(renamed_hash, NODE_PARENT(ev->user_data));
836 + if (pair_ev && node_timeval_lt(&ev->ctv, &pair_ev->rename_tv)) {
837 + g_hash_table_remove(renamed_hash, NODE_PARENT(ev->user_data));
838 + pair_ev->pair_data = ev->user_data;
839 + /* Free ev, exchange pair_ev and ev. */
840 + node_event_delete(ev);
841 + ev = pair_ev;
845 +#endif
847 +#if 0
848 + node_add_event(ev->user_data, ev);
849 +#else
850 + user_process_events_cb(ev->user_data, ev);
851 +#endif
854 + /* Processing the events in renamed_hash. TODO we should delay it and wait
855 + * for more possible pair.
856 + */
857 + g_hash_table_foreach_remove(renamed_hash, process_renamed_hash_cb, NULL);
859 + G_UNLOCK (fen_lock);
861 + process_port_event_id = 0;
862 + return FALSE;
865 +static gboolean
866 +port_events_read_cb(gpointer user_data)
869 + if (process_port_event_id == 0) {
870 + process_port_event_id = g_timeout_add(PROCESS_PORT_EVENTS_TIME,
871 + port_events_process_cb,
872 + NULL);
875 + return TRUE;
879 + * malloc PSource and port_create, start thread at pnode_ref.
880 + * if psource_new succeeded, the PSource will never
881 + * be freed. So PSource can be freed only in psource_new.
882 + * Note pnode_monitor_remove_all can also free PSource, but currently no one
883 + * invork it.
884 + */
885 +static GSource*
886 +psource_new()
888 + GSource *source = NULL;
889 + int fd;
891 + if ((fd = port_create()) >= 0) {
892 + source = g_source_new(&fen_source_func, sizeof(PSource));
893 + PGPFD(source)->fd = fd;
894 + PGPFD(source)->events = G_IO_IN | G_IO_HUP | G_IO_ERR;
895 + g_source_set_callback(source, port_events_read_cb, NULL, NULL);
896 + g_source_attach(source, NULL);
897 + g_source_unref(source);
898 + g_source_add_poll(source, PGPFD(source));
900 + FK_W ("%s 0x%p fd %d\n", __func__, source, PGPFD(source)->fd);
901 + } else {
902 + FK_W ("PORT_CREATE %s\n", g_strerror(errno));
903 + g_return_val_if_reached(NULL);
906 + return source;
909 +/**
910 + * port_add:
911 + * @f:
913 + * Unsafe, need lock fen_lock.
914 + * port_add will associate a GSource to @f->source
915 + */
916 +gint
917 +port_add(node_t *f)
919 + GSource *source = f->source;
921 + FK_W ("%s [0x%p] %s\n", __func__, f, NODE_NAME(f));
923 + g_assert(f);
924 + g_assert(NODE_HAS_FLAG(f, NODE_FLAG_STAT_UPDATED));
926 + /* if (!NODE_HAS_FLAG(f, NODE_FLAG_STAT_DONE)) { */
927 + /* if (NODE_STAT(f) != 0) { */
928 + /* return errno; */
929 + /* } */
930 + /* } */
932 + /* Try re-use f->pn. f->pn may be used by other request, e.g. f is deleted
933 + * for a long time. So if pn is full, we try to open a new one.
934 + */
935 + if (!source) {
936 +start_over:
937 + /* Try the next visible source. */
938 + if (pn_visible_list) {
939 + source = (GSource *)pn_visible_list->data;
940 + } else {
941 + if ((source = psource_new()) != NULL) {
942 + g_assert (g_list_find (pn_visible_list, source) == NULL);
943 + pn_visible_list = g_list_prepend (pn_visible_list, source);
948 + if (port_associate(PGPFD(source)->fd, PORT_SOURCE_FILE, (uintptr_t)FILE_OBJECT(f),
949 + CONCERNED_EVENTS,
950 + (void *)f) == 0) {
951 + f->source = source;
952 + NODE_SET_STATE(f, NODE_STATE_ASSOCIATED);
953 + NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED);
954 + FK_W ("PORT_ASSOCIATE 0x%p OK\n", f);
955 + return 0;
956 + } else if (errno == EAGAIN) {
957 + /* Full, remove it. */
958 + pn_visible_list = g_list_remove (pn_visible_list, source);
959 + /* Re-add to port */
960 + goto start_over;
962 + } else if (errno == ENOENT) {
963 + /* File is not exist */
964 + } else if (errno == ENOTSUP) {
965 + /* FS is not supported. Currently we think it no longer make sense to
966 + * monitor it, so clean the stat info and return 0 to ignore this
967 + * node. If there are requirement, we can consider to add polling
968 + * method.
969 + */
970 + NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED);
971 + return 0;
972 + } else {
973 + FK_W ("PORT_ASSOCIATE 0x%p %s\n", f, g_strerror (errno));
976 + /* No matter if associated successfully, stat info is out-of-date, so clean it. */
977 + NODE_CLE_FLAG(f, NODE_FLAG_STAT_UPDATED);
978 + return errno;
981 +/**
982 + * port_remove
984 + * < private >
985 + * Unsafe, need lock fen_lock.
986 + */
987 +void
988 +port_remove (node_t *f)
990 + /* g_assert(f->source); */
992 + if (NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED)) {
993 + /* Mark unregisted. */
994 + if (port_dissociate(PGPFD(f->source)->fd, PORT_SOURCE_FILE, (uintptr_t)FILE_OBJECT(f)) == 0) {
995 + /*
996 + * Note, we can run foode_delete if dissociating is failed,
997 + * because there may be some pending events (mostly like
998 + * FILE_DELETE) in the port_get. If we delete the foode
999 + * the fnode may be deleted, then port_get will run on an invalid
1000 + * address.
1001 + */
1002 + NODE_CLE_STATE(f, NODE_STATE_ASSOCIATED);
1003 + FK_W ("PORT_DISSOCIATE 0x%p OK\n", f);
1004 + } else if (errno == ENOENT) {
1005 + /* The file has been removed from port, after port_get or before
1006 + * port_get but DELETED event has been generated.
1007 + * Ignored. */
1008 + } else {
1009 + FK_W ("PORT_DISSOCIATE 0x%p %s\n", f, g_strerror (errno));
1010 + g_return_if_reached();
1015 +/**
1016 + * When a node is deleted, we need to remove
1017 + * all events referencing this node from event queue.
1019 + * Unsafe, need lock fen_lock.
1020 + */
1021 +void prune_queue (node_t *f)
1023 + node_event_t* ev;
1024 + GQueue *c = g_queue_copy(g_eventq);
1025 + while (ev = (node_event_t*) g_queue_pop_head(c)) {
1026 + if (ev->user_data == f || ev->pair_data == f)
1027 + g_queue_remove(g_eventq, ev);
1029 + g_queue_free(c);
1032 +/**
1033 + * Get Solaris resouce values.
1035 + */
1037 +extern gboolean
1038 +port_class_init (void (*user_process_events_callback) (gpointer, node_event_t*))
1040 + rctlblk_t *rblk;
1042 + if ((rblk = malloc (rctlblk_size ())) == NULL) {
1043 + FK_W ("[kernel] rblk malloc %s\n", g_strerror (errno));
1044 + return FALSE;
1046 + if (getrctl ("process.max-port-events", NULL, rblk, RCTL_FIRST) == -1) {
1047 + FK_W ("[kernel] getrctl %s\n", g_strerror (errno));
1048 + free (rblk);
1049 + return FALSE;
1050 + } else {
1051 + max_port_events = rctlblk_get_value(rblk);
1052 + FK_W ("max_port_events = %u\n", max_port_events);
1053 + free (rblk);
1055 + renamed_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1056 + NULL, NULL);
1057 + if (renamed_hash == NULL) {
1058 + FK_W ("[kernel] FEN global renamed queue initializing faild\n");
1059 + return FALSE;
1061 + if ((g_eventq = g_queue_new ()) == NULL) {
1062 + FK_W ("[kernel] FEN global event queue initializing faild\n");
1063 + return FALSE;
1065 + if (user_process_events_callback == NULL) {
1066 + FK_W ("[kernel] FEN global no user_process_events_callback\n");
1067 + return FALSE;
1069 + user_process_events_cb = user_process_events_callback;
1070 + memset (&zero_wait, 0, sizeof (timespec_t));
1072 + pevents = g_malloc(PE_ALLOC * sizeof(port_event_t));
1073 + if (pevents == NULL) {
1074 + FK_W ("[kernel] FEN global alloc pevents failed\n");
1075 + return FALSE;
1078 + return TRUE;
1081 +static gchar*
1082 +printevent (const char *pname, int event, const char *tag)
1084 + static gchar *event_string = NULL;
1085 + GString *str;
1087 + if (event_string) {
1088 + g_free(event_string);
1091 + str = g_string_new ("");
1092 + g_string_printf (str, "[%s] [%-20s]", tag, pname);
1093 + if (event & FILE_ACCESS) {
1094 + str = g_string_append (str, " ACCESS");
1096 + if (event & FILE_MODIFIED) {
1097 + str = g_string_append (str, " MODIFIED");
1099 + if (event & FILE_ATTRIB) {
1100 + str = g_string_append (str, " ATTRIB");
1102 + if (event & FILE_DELETE) {
1103 + str = g_string_append (str, " DELETE");
1105 + if (event & FILE_RENAME_TO) {
1106 + str = g_string_append (str, " RENAME_TO");
1108 + if (event & FILE_RENAME_FROM) {
1109 + str = g_string_append (str, " RENAME_FROM");
1111 + if (event & UNMOUNTED) {
1112 + str = g_string_append (str, " UNMOUNTED");
1114 + if (event & MOUNTEDOVER) {
1115 + str = g_string_append (str, " MOUNTEDOVER");
1117 + event_string = str->str;
1118 + g_string_free (str, FALSE);
1119 + return event_string;
1122 +static gchar *
1123 +_event_strings(int event)
1125 + GString *str = g_string_sized_new(80);
1127 + if (event & FILE_DELETE)
1128 + g_string_append(str, " FILE_DELETE");
1130 + if (event & FILE_RENAME_FROM)
1131 + g_string_append(str, " FILE_RENAME_FROM");
1133 + if (event & FILE_MODIFIED)
1134 + g_string_append(str, " FILE_MODIFIED");
1136 + if (event & FILE_RENAME_TO)
1137 + g_string_append(str, " FILE_RENAME_TO");
1139 + if (event & MOUNTEDOVER)
1140 + g_string_append(str, " MOUNTEDOVER");
1142 + if (event & FILE_ATTRIB)
1143 + g_string_append(str, " FILE_ATTRIB");
1145 + if (event & UNMOUNTED)
1146 + g_string_append(str, " UNMOUNTED");
1148 + if (event & FILE_ACCESS)
1149 + g_string_append(str, " FILE_ACCESS");
1151 + return g_string_free(str, FALSE);
1154 +static const gchar *
1155 +_event_string (int event)
1157 + switch (event) {
1158 + case FILE_DELETE:
1159 + return "FILE_DELETE";
1160 + case FILE_RENAME_FROM:
1161 + return "FILE_RENAME_FROM";
1162 + case FILE_MODIFIED:
1163 + return "FILE_MODIFIED";
1164 + case FILE_RENAME_TO:
1165 + return "FILE_RENAME_TO";
1166 + case MOUNTEDOVER:
1167 + return "MOUNTEDOVER";
1168 + case FILE_ATTRIB:
1169 + return "FILE_ATTRIB";
1170 + case UNMOUNTED:
1171 + return "UNMOUNTED";
1172 + case FILE_ACCESS:
1173 + return "FILE_ACCESS";
1174 + default:
1175 + return "EVENT_UNKNOWN";
1179 diff --git a/server/fen-kernel.h b/server/fen-kernel.h
1180 new file mode 100644
1181 index 0000000..6d2c49b
1182 --- /dev/null 2019-12-10 11:10:35.000000000 +0000
1183 +++ gamin-0.1.10/server/fen-kernel.h 2019-12-10 11:10:22.999527865 +0000
1184 @@ -0,0 +1,44 @@
1185 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1186 +/* vim:set expandtab ts=4 shiftwidth=4: */
1187 +/*
1188 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
1189 + * reserved.
1191 + * This library is free software; you can redistribute it and/or
1192 + * modify it under the terms of the GNU Lesser General Public
1193 + * License as published by the Free Software Foundation; either
1194 + * version 2 of the License, or (at your option) any later version.
1196 + * This library is distributed in the hope that it will be useful,
1197 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1198 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1199 + * Lesser General Public License for more details.
1201 + * You should have received a copy of the GNU Lesser General
1202 + * Public License along with this library; if not, write to the
1203 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
1204 + * Boston, MA 02111-1307, USA.
1206 + * Authors: Lin Ma <lin.ma@sun.com>
1207 + */
1209 +#include <sys/types.h>
1210 +#include <errno.h>
1212 +#include "fen-node.h"
1214 +#ifndef _FEN_KERNEL_H_
1215 +#define _FEN_KERNEL_H_
1217 +#define CONCERNED_EVENTS (FILE_MODIFIED | FILE_ATTRIB | FILE_NOFOLLOW)
1218 +#define EXCEPTION_EVENTS (FILE_DELETE | FILE_RENAME_FROM)
1219 +#define HAS_EXCEPTION_EVENTS(e) ((e & EXCEPTION_EVENTS) != 0)
1220 +#define HAS_NO_EXCEPTION_EVENTS(e) ((e & EXCEPTION_EVENTS) == 0)
1222 +gint port_add (node_t* f);
1223 +void port_remove (node_t *f);
1224 +void prune_queue (node_t *f);
1226 +gboolean port_class_init ();
1228 +#endif /* _FEN_KERNEL_H_ */
1229 diff --git a/server/fen-node.c b/server/fen-node.c
1230 new file mode 100644
1231 index 0000000..d4d7ddb
1232 --- /dev/null 2019-12-10 11:10:35.000000000 +0000
1233 +++ gamin-0.1.10/server/fen-node.c 2019-12-10 11:10:23.002327705 +0000
1234 @@ -0,0 +1,643 @@
1235 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1236 +/* vim:set expandtab ts=4 shiftwidth=4: */
1237 +/*
1238 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
1239 + * reserved.
1241 + * This library is free software; you can redistribute it and/or
1242 + * modify it under the terms of the GNU Lesser General Public
1243 + * License as published by the Free Software Foundation; either
1244 + * version 2 of the License, or (at your option) any later version.
1246 + * This library is distributed in the hope that it will be useful,
1247 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1248 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1249 + * Lesser General Public License for more details.
1251 + * You should have received a copy of the GNU Lesser General
1252 + * Public License along with this library; if not, write to the
1253 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
1254 + * Boston, MA 02111-1307, USA.
1256 + * Authors: Lin Ma <lin.ma@sun.com>
1257 + */
1259 +#include "config.h"
1260 +#include <sys/stat.h>
1261 +#include <errno.h>
1262 +#include <strings.h>
1263 +#include <glib.h>
1264 +#include "fen-kernel.h"
1265 +#include "fen-node.h"
1266 +#include "fen-dump.h"
1268 +#ifdef GIO_COMPILATION
1269 +#include "gfilemonitor.h"
1270 +#else
1271 +#include "gam_event.h"
1272 +#include "gam_server.h"
1273 +#include "gam_protocol.h"
1274 +#endif
1276 +#ifdef GIO_COMPILATION
1277 +#define FN_W if (fn_debug_enabled) g_debug
1278 +static gboolean fn_debug_enabled = FALSE;
1279 +#else
1280 +#include "gam_error.h"
1281 +#define FN_W(...) GAM_DEBUG(DEBUG_INFO, __VA_ARGS__)
1282 +#endif
1284 +G_LOCK_EXTERN (fen_lock);
1286 +/* Must continue monitoring if:
1287 + * 1) I'm subscribed,
1288 + * 2) The subscribed children (one of the children has subs) are missing,
1289 + * 3) my parent is subscribed (monitoring directory).
1290 + */
1291 +#define NODE_NEED_MONITOR(f) \
1292 + (NODE_IS_ACTIVE(f) || node_children_num(f) > 0 || NODE_IS_REQUIRED_BY_PARENT(f))
1294 +static int concern_events[] = {
1295 + FILE_DELETE,
1296 + FILE_RENAME_FROM,
1297 + UNMOUNTED,
1298 + MOUNTEDOVER,
1299 +#ifdef GIO_COMPILATION
1300 + FILE_MODIFIED,
1301 + FILE_ATTRIB,
1302 +#else
1303 + FILE_MODIFIED | FILE_ATTRIB,
1304 +#endif
1305 + FILE_RENAME_TO,
1308 +node_t *ROOT = NULL;
1310 +static void node_emit_one_event(node_t *f, GList *subs, node_t *other, int event);
1311 +static void node_emit_events(node_t *f, const node_event_t *ne);
1312 +static int node_event_translate(int event, gboolean pair);
1313 +static void node_add_event (node_t *f, node_event_t *ev);
1314 +static node_t* node_new (node_t* parent, const gchar* basename);
1315 +static void node_delete (node_t* parent);
1316 +static node_t* node_get_child (node_t *f, const gchar *basename);
1317 +static void children_add (node_t *p, node_t *f);
1318 +static void children_remove (node_t *p, node_t *f);
1319 +static gboolean children_remove_cb (gpointer key, gpointer value, gpointer user_data);
1320 +static guint node_children_num (node_t *f);
1322 +gboolean
1323 +node_timeval_lt(const GTimeVal *val1, const GTimeVal *val2)
1325 + if (val1->tv_sec < val2->tv_sec)
1326 + return TRUE;
1328 + if (val1->tv_sec > val2->tv_sec)
1329 + return FALSE;
1331 + /* val1->tv_sec == val2->tv_sec */
1332 + if (val1->tv_usec < val2->tv_usec)
1333 + return TRUE;
1335 + return FALSE;
1338 +void
1339 +node_traverse (node_t* node, void(*traverse_cb)(node_t*, gpointer), gpointer user_data)
1341 + GHashTableIter iter;
1342 + gpointer value;
1344 + g_assert(traverse_cb);
1345 + if (node == NULL) {
1346 + node = ROOT;
1349 + if (node) {
1350 + traverse_cb(node, user_data);
1353 + g_hash_table_iter_init (&iter, node->children);
1354 + while (g_hash_table_iter_next (&iter, NULL, &value)) {
1355 + node_traverse((node_t *)value, traverse_cb, user_data);
1359 +node_t*
1360 +node_find(node_t* node, const gchar* filename, gboolean create_on_missing)
1362 + gchar* str;
1363 + gchar* token;
1364 + gchar* lasts;
1365 + node_t* parent;
1366 + node_t* child;
1368 + g_assert (filename && filename[0] == '/');
1370 + if (node == NULL) {
1371 + node = ROOT;
1374 + FN_W ("%s %s\n", __func__, filename);
1376 + parent = child = node;
1377 + str = g_strdup (filename);
1379 + for (token = strtok_r (str, G_DIR_SEPARATOR_S, &lasts);
1380 + token != NULL && child != NULL;
1381 + token = strtok_r (NULL, G_DIR_SEPARATOR_S, &lasts)) {
1382 + FN_W ("%s %s + %s\n", __func__, NODE_NAME(parent), token);
1383 + child = node_get_child(parent, token);
1384 + if (child) {
1385 + parent = child;
1386 + } else if (create_on_missing) {
1387 + child = node_new (parent, token);
1388 + if (child) {
1389 + children_add (parent, child);
1390 + parent = child;
1391 + continue;
1392 + } else {
1393 + FN_W ("%s create %s failed", __func__, token);
1395 + } else {
1396 + break;
1400 + g_free (str);
1401 + return child;
1404 +gint
1405 +node_lstat(node_t *f)
1407 + struct stat buf;
1409 + g_assert(!NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED));
1411 + if (lstat(NODE_NAME(f), &buf) == 0) {
1412 + FN_W ("%s %s\n", __func__, NODE_NAME(f));
1413 + FILE_OBJECT(f)->fo_atime = buf.st_atim;
1414 + FILE_OBJECT(f)->fo_mtime = buf.st_mtim;
1415 + FILE_OBJECT(f)->fo_ctime = buf.st_ctim;
1416 + NODE_SET_FLAG(f, NODE_FLAG_STAT_UPDATED |
1417 + (S_ISDIR (buf.st_mode) ? NODE_FLAG_DIR : NODE_FLAG_NONE));
1418 + return 0;
1419 + } else {
1420 + FN_W ("%s(lstat) %s %s\n", __func__, NODE_NAME(f), g_strerror (errno));
1422 + return errno;
1425 +void
1426 +node_create_children_snapshot(node_t *f, gint created_event, gboolean emit)
1428 + GDir *dir;
1429 + GError *err = NULL;
1431 + FN_W ("%s %s [0x%p]\n", __func__, NODE_NAME(f), f);
1433 + dir = g_dir_open (NODE_NAME(f), 0, &err);
1434 + if (dir) {
1435 + const char *basename;
1436 + node_t *child = NULL;
1438 + while ((basename = g_dir_read_name (dir))) {
1439 + node_t* data;
1440 + GList *idx;
1442 + child = node_get_child (f, basename);
1443 + if (child == NULL) {
1444 + gchar *filename;
1446 + child = node_new (f, basename);
1447 + children_add (f, child);
1450 + if (f->dir_subs) {
1451 + /* We need monitor the new children, or the existed child which
1452 + * is in the DELETED mode.
1453 + */
1454 + if (!NODE_HAS_STATE(child, NODE_STATE_ASSOCIATED) &&
1455 + node_lstat(child) == 0 && port_add(child) == 0) {
1456 + if (emit) {
1457 + /* Emit the whatever event for the new found file. */
1458 + node_emit_one_event(child, child->dir_subs, NULL, created_event);
1459 + node_emit_one_event(child, child->subs, NULL, created_event);
1460 + node_emit_one_event(child, f->dir_subs, NULL, created_event);
1461 + node_emit_one_event(child, f->subs, NULL, created_event);
1464 + /* else ignore, because it may be deleted. */
1467 + g_dir_close (dir);
1469 + /* We have finished children snapshot. Any other new added subs should
1470 + * directory iterate the snapshot instead of scan directory again.
1471 + */
1472 + NODE_SET_FLAG(f, NODE_FLAG_SNAPSHOT_UPDATED);
1474 + } else {
1475 + FN_W (err->message);
1476 + g_error_free (err);
1480 +/**
1481 + * If all active children nodes are ported, then cancel monitor the parent
1482 + * node. If we know how many children are created, then we can stop accordingly.
1484 + * Unsafe, need lock.
1485 + */
1486 +static void
1487 +foreach_known_children_scan(gpointer key, gpointer value, gpointer user_data)
1489 + node_t* f = (node_t*)value;
1491 + FN_W ("%s 0x%p %s\n", __func__, f, NODE_NAME(f));
1493 + if (!NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED)) {
1494 + if (node_lstat(f) == 0 && port_add(f) == 0) {
1495 + node_emit_one_event(f, f->dir_subs, NULL, FN_EVENT_CREATED);
1496 + node_emit_one_event(f, f->subs, NULL, FN_EVENT_CREATED);
1497 + if (NODE_PARENT(f)) {
1498 + node_emit_one_event(f, NODE_PARENT(f)->dir_subs, NULL, FN_EVENT_CREATED);
1499 + node_emit_one_event(f, NODE_PARENT(f)->subs, NULL, FN_EVENT_CREATED);
1505 +gboolean
1506 +node_try_delete(node_t* node)
1508 + g_assert (node);
1510 + FN_W ("%s 0x%p %s\n", __func__, node, NODE_NAME(node));
1512 + /* Try clean children */
1513 + if (node_children_num (node) > 0) {
1514 + g_hash_table_foreach_remove(node->children, children_remove_cb, NULL);
1516 + if (!NODE_NEED_MONITOR(node)) {
1517 + /* Clean some flags. */
1518 + /* NODE_CLE_FLAG(node, NODE_FLAG_HAS_SNAPSHOT | NODE_FLAG_STAT_DONE); */
1519 + node->flag = 0;
1521 + /* Now we handle the state. */
1522 + if (NODE_HAS_STATE(node, NODE_STATE_ASSOCIATED)) {
1523 + port_remove(node);
1525 + /* Actually ignore the ROOT node. */
1526 + if (node->state == 0 && NODE_PARENT(node)) {
1527 + children_remove(NODE_PARENT(node), node);
1528 + /* Remove the pending events in the queue. */
1529 + prune_queue(node);
1530 + /* Do clean instead of returning TRUE. */
1531 + node_delete (node);
1534 + return FALSE;
1537 +static node_t*
1538 +node_new (node_t* parent, const gchar* basename)
1540 + node_t *f = NULL;
1542 + g_assert (basename && basename[0]);
1544 + if ((f = g_new0(node_t, 1)) != NULL) {
1545 + if (parent) {
1546 + NODE_NAME(f) = g_build_filename(NODE_NAME(parent), basename, NULL);
1547 + } else {
1548 + NODE_NAME(f) = g_strdup(G_DIR_SEPARATOR_S);
1550 + f->basename = g_strdup (basename);
1551 + /* f->children = g_hash_table_new_full (g_str_hash, g_str_equal, */
1552 + /* NULL, (GDestroyNotify)node_delete); */
1553 + f->children = g_hash_table_new_full (g_str_hash, g_str_equal,
1554 + NULL, NULL);
1555 +#ifdef GIO_COMPILATION
1556 + f->gfile = g_file_new_for_path (NODE_NAME(f));
1557 +#endif
1558 + FN_W ("%s 0x%p %s\n", __func__, f, NODE_NAME(f));
1560 + return f;
1563 +static void
1564 +node_delete (node_t *f)
1566 + FN_W ("%s 0x%p %s\n", __func__, f, NODE_NAME(f));
1567 + g_assert(f->state == 0);
1568 + g_assert(!NODE_IS_ACTIVE(f));
1569 + g_assert(g_hash_table_size (f->children) == 0);
1570 + g_assert(NODE_PARENT(f) == NULL);
1571 + g_hash_table_unref(f->children);
1572 +#ifdef GIO_COMPILATION
1573 + g_object_unref (f->gfile);
1574 +#endif
1575 + g_free(f->basename);
1576 + g_free(NODE_NAME(f));
1577 + g_free (f);
1580 +static void
1581 +children_add (node_t *p, node_t *f)
1583 + FN_W ("%s %s %s\n", __func__, NODE_NAME(p), f->basename);
1584 + g_hash_table_insert (p->children, f->basename, f);
1585 + NODE_PARENT(f) = p;
1588 +static void
1589 +children_remove (node_t *p, node_t *f)
1591 + FN_W ("%s %s %s\n", __func__, NODE_NAME(p), f->basename);
1592 + g_hash_table_steal (p->children, f->basename);
1593 + NODE_PARENT(f) = NULL;
1596 +static node_t *
1597 +node_get_child (node_t *f, const gchar *basename)
1599 + if (f->children) {
1600 + return (node_t *) g_hash_table_lookup (f->children, (gpointer)basename);
1602 + return NULL;
1605 +static guint
1606 +node_children_num (node_t *f)
1608 + return g_hash_table_size (f->children);
1611 +/**
1612 + * depth first delete recursively
1613 + */
1614 +static gboolean
1615 +children_remove_cb (gpointer key, gpointer value, gpointer user_data)
1617 + return node_try_delete ((node_t*)value);
1620 +gboolean
1621 +node_class_init()
1623 + ROOT = node_new (NULL, G_DIR_SEPARATOR_S);
1624 + if (ROOT == NULL) {
1625 + FN_W ("[node] Create ROOT node failed.\n");
1626 + return FALSE;
1629 + return port_class_init (node_add_event);
1632 +/**
1633 + * Adjust self on failing to Port
1634 + */
1635 +void
1636 +node_adjust_deleted(node_t* f)
1638 + node_t *ancestor;
1640 + FN_W ("%s %s\n", __func__, NODE_NAME(f));
1642 + for (ancestor = NODE_PARENT(f);
1643 + ancestor != NULL;
1644 + ancestor = NODE_PARENT(ancestor)) {
1645 + /* Stop if we find a node which been already associated or is existed
1646 + * and can be associated.
1647 + */
1648 + if (NODE_HAS_STATE(ancestor, NODE_STATE_ASSOCIATED) ||
1649 + (node_lstat(ancestor) == 0 && port_add(ancestor) == 0)) {
1650 + break;
1654 + /* We assume we shouldn't reach here, because Root is always existed and
1655 + * associated. But given bugster#6955199, if PORT FS has problems on root,
1656 + * we may reach here. So just return ROOT and the whole GIO fen backend will
1657 + * fail.
1658 + */
1659 + /* g_assert(ancestor != NULL); */
1663 +static void
1664 +node_emit_events(node_t *f, const node_event_t *ne)
1666 + gsize num = sizeof(concern_events)/sizeof(int);
1667 + gint i;
1668 + int translated_e;
1669 + node_t *p;
1671 + if (node_timeval_lt(&f->atv, &ne->ctv)) {
1672 + int event = ne->e;
1674 + /* Emit DELETED on the pair_data */
1675 + if (ne->pair_data) {
1676 + node_t *from = ne->pair_data;
1677 + node_emit_one_event(from, from->dir_subs, NULL, node_event_translate(FILE_DELETE, FALSE));
1678 + node_emit_one_event(from, from->subs, NULL, node_event_translate(FILE_DELETE, FALSE));
1681 + for (i = 0; i < num; i++) {
1682 + if (event & concern_events[i]) {
1683 + translated_e = node_event_translate(concern_events[i], FALSE);
1684 + /* Neither GIO or gamin cares about modified events on a
1685 + * directory.
1686 + */
1687 +#ifdef GIO_COMPILATION
1688 + if ((concern_events[i] & FILE_MODIFIED) == 0) {
1689 + node_emit_one_event(f, f->dir_subs, NULL, translated_e);
1691 +#else
1692 + /* Gamin doesn't care about attrib changed events on a directory
1693 + * either.
1694 + */
1695 + if ((concern_events[i] & (FILE_MODIFIED | FILE_ATTRIB)) == 0) {
1696 + node_emit_one_event(f, f->dir_subs, NULL, translated_e);
1698 +#endif
1699 + node_emit_one_event(f, f->subs, NULL, translated_e);
1701 + event &= ~concern_events[i];
1705 + p = NODE_PARENT(f);
1706 + if (p != NULL && node_timeval_lt(&p->atv, &ne->ctv)) {
1707 + int event = ne->e;
1708 + for (i = 0; i < num; i++) {
1709 + if (event & concern_events[i]) {
1710 + translated_e = node_event_translate(concern_events[i], ne->pair_data != NULL);
1711 + node_emit_one_event(f, p->dir_subs, ne->pair_data, translated_e);
1712 + node_emit_one_event(f, p->subs, ne->pair_data, translated_e);
1714 + event &= ~concern_events[i];
1719 +/**
1720 + * node_add_event:
1722 + */
1723 +static void
1724 +node_add_event (node_t *f, node_event_t *ev)
1726 + FN_W ("%s %d\n", __func__, ev->e);
1728 + /* Clean the events flag early, because all received events need be
1729 + * processed in this function.
1730 + */
1731 + NODE_CLE_STATE(f, NODE_STATE_HAS_EVENTS);
1733 + /*
1734 + * Node the node has been created, so we can delete create event in
1735 + * optimizing. To reduce the statings, we add it to Port on discoving
1736 + * it then emit CREATED event. So we don't need to do anything here.
1737 + */
1738 + if (NODE_NEED_MONITOR(f)) {
1739 + if (HAS_NO_EXCEPTION_EVENTS(ev->e)) {
1740 + if (NODE_HAS_STATE(f, NODE_STATE_ASSOCIATED) || (node_lstat(f) == 0 && port_add(f) == 0)) {
1741 + if ((ev->e & FILE_MODIFIED) && NODE_HAS_FLAG(f, NODE_FLAG_DIR)) {
1742 + if (f->dir_subs) {
1743 + node_create_children_snapshot(f, FN_EVENT_CREATED, TRUE);
1744 + } else {
1745 + g_hash_table_foreach(f->children, foreach_known_children_scan, NULL);
1748 + } else {
1749 + /* Emit delete event */
1750 + ev->e |= FILE_DELETE;
1752 + node_adjust_deleted(f);
1755 + } else {
1756 + node_adjust_deleted(f);
1759 + /* Send events to clients. */
1760 + node_emit_events (f, ev);
1762 + } else {
1763 + /* Send events to clients. */
1764 + node_emit_events (f, ev);
1766 + node_try_delete(f);
1769 + if (ev->pair_data) {
1770 + node_t *from = ev->pair_data;
1771 + g_assert(ev->e == FILE_RENAME_TO);
1773 + if (NODE_NEED_MONITOR(from)) {
1774 + /* Clean the events flag, since it may block free this node. */
1775 + NODE_CLE_STATE(from, NODE_STATE_HAS_EVENTS);
1776 + node_adjust_deleted(from);
1777 + } else {
1778 + node_try_delete(from);
1782 + node_event_delete (ev);
1785 +static void
1786 +node_emit_one_event(node_t *f, GList *subs, node_t *other, int event)
1788 + GList* idx;
1790 + FN_W ("%s %s %d\n", __func__, NODE_NAME(f), event);
1792 +#ifdef GIO_COMPILATION
1793 + for (idx = subs; idx; idx = idx->next) {
1794 + g_file_monitor_emit_event(G_FILE_MONITOR(idx->data), f->gfile,
1795 + (other == NULL ? NULL : other->gfile), event);
1797 +#else
1798 + for (idx = subs; idx; idx = idx->next) {
1799 + gam_server_emit_one_event(NODE_NAME(f), gam_subscription_is_dir(idx->data), event, idx->data, 1);
1801 +#endif
1804 +static int
1805 +node_event_translate(int event, gboolean pair)
1807 +#ifdef GIO_COMPILATION
1808 + switch (event) {
1809 + case FILE_DELETE:
1810 + case FILE_RENAME_FROM:
1811 + return G_FILE_MONITOR_EVENT_DELETED;
1812 + case UNMOUNTED:
1813 + return G_FILE_MONITOR_EVENT_UNMOUNTED;
1814 + case FILE_ATTRIB:
1815 + return G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED;
1816 + case MOUNTEDOVER:
1817 + case FILE_MODIFIED:
1818 + return G_FILE_MONITOR_EVENT_CHANGED;
1819 + case FILE_RENAME_TO:
1820 + if (pair) {
1821 + return G_FILE_MONITOR_EVENT_MOVED;
1822 + } else {
1823 + return G_FILE_MONITOR_EVENT_CREATED;
1825 + default:
1826 + /* case FILE_ACCESS: */
1827 + g_assert_not_reached ();
1828 + return -1;
1830 +#else
1831 + switch (event) {
1832 + case FILE_DELETE:
1833 + case FILE_RENAME_FROM:
1834 + return GAMIN_EVENT_DELETED;
1835 + case MOUNTEDOVER:
1836 + case UNMOUNTED:
1837 + return GAMIN_EVENT_CHANGED;
1838 + case FILE_RENAME_TO:
1839 + if (pair) {
1840 + return GAMIN_EVENT_MOVED;
1841 + } else {
1842 + return GAMIN_EVENT_CREATED;
1844 + default:
1845 + if (event & (FILE_ATTRIB | FILE_MODIFIED)) {
1846 + return GAMIN_EVENT_CHANGED;
1848 + /* case FILE_ACCESS: */
1849 + g_assert_not_reached ();
1850 + return -1;
1852 +#endif
1855 +node_event_t*
1856 +node_event_new (int event, gpointer user_data)
1858 + node_event_t *ev;
1860 + if ((ev = g_new (node_event_t, 1)) != NULL) {
1861 + g_assert (ev);
1862 + ev->e = event;
1863 + ev->user_data = user_data;
1864 + ev->pair_data = NULL; /* For renamed file. */
1865 + /* Created timestamp */
1866 + g_get_current_time(&ev->ctv);
1867 + ev->rename_tv = ev->ctv;
1869 + return ev;
1872 +void
1873 +node_event_delete (node_event_t* ev)
1875 + g_free (ev);
1878 diff --git a/server/fen-node.h b/server/fen-node.h
1879 new file mode 100644
1880 index 0000000..7e99032
1881 --- /dev/null
1882 +++ b/server/fen-node.h
1883 @@ -0,0 +1,104 @@
1884 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1885 +/* vim:set expandtab ts=4 shiftwidth=4: */
1886 +/*
1887 + * Copyright (c) 2008, 2010 Oracle and/or its affiliates, Inc. All rights
1888 + * reserved.
1890 + * This library is free software; you can redistribute it and/or
1891 + * modify it under the terms of the GNU Lesser General Public
1892 + * License as published by the Free Software Foundation; either
1893 + * version 2 of the License, or (at your option) any later version.
1895 + * This library is distributed in the hope that it will be useful,
1896 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1897 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1898 + * Lesser General Public License for more details.
1900 + * You should have received a copy of the GNU Lesser General
1901 + * Public License along with this library; if not, write to the
1902 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
1903 + * Boston, MA 02111-1307, USA.
1905 + * Authors: Lin Ma <lin.ma@sun.com>
1906 + */
1908 +#include <port.h>
1909 +#include <gio/gio.h>
1911 +#ifndef _FEN_NODE_H_
1912 +#define _FEN_NODE_H_
1914 +#ifdef GIO_COMPILATION
1915 +#define FN_EVENT_CREATED G_FILE_MONITOR_EVENT_CREATED
1916 +#else
1917 +#define FN_EVENT_CREATED GAMIN_EVENT_CREATED
1918 +#endif
1920 +#define NODE_STATE_NONE 0x00000000
1921 +#define NODE_STATE_ASSOCIATED 0x00000001 /* This is a confilct to NODE_FLAG_STAT_DONE */
1922 +#define NODE_STATE_HAS_EVENTS 0x00000002
1924 +#define NODE_FLAG_NONE 0x00000000
1925 +#define NODE_FLAG_SNAPSHOT_UPDATED 0x00000001
1926 +#define NODE_FLAG_DIR 0x00000002
1927 +#define NODE_FLAG_STAT_UPDATED 0x00000004
1929 +#define NODE_CLE_STATE(f, st) (f->state &= ~(st))
1930 +#define NODE_SET_STATE(f, st) (f->state = ((f->state & ~(st)) | (st)))
1931 +#define NODE_HAS_STATE(f, st) (f->state & (st))
1933 +#define NODE_CLE_FLAG(f, fl) (f->flag &= ~(fl))
1934 +#define NODE_SET_FLAG(f, fl) (f->flag = ((f->flag & ~(fl)) | (fl)))
1935 +#define NODE_HAS_FLAG(f, fl) (f->flag & (fl))
1937 +typedef struct node node_t;
1938 +struct node
1940 + file_obj_t fobj; /* Inherit from file_obj_t, must be the first. */
1941 + GSource *source;
1942 + gchar *basename;
1943 + guint32 state;
1944 + guint32 flag;
1945 + GTimeVal atv; /* Timestamp for the first added sub. */
1947 + /* the parent and children of node */
1948 + node_t *parent;
1949 + GHashTable *children; /* children in basename */
1951 + /* List of subscriptions monitoring this fdata/path */
1952 + GList *subs;
1953 + GList *dir_subs;
1955 +#ifdef GIO_COMPILATION
1956 + GFile* gfile;
1957 +#endif
1960 +#define FILE_OBJECT(f) ((file_obj_t *)(f))
1961 +#define NODE_NAME(f) (FILE_OBJECT(f)->fo_name)
1962 +#define NODE_PARENT(f) (((node_t *)f)->parent)
1963 +#define NODE_IS_ACTIVE(f) (f->dir_subs || f->subs)
1964 +#define NODE_IS_REQUIRED_BY_PARENT(f) (NODE_PARENT(f) && NODE_PARENT(f)->dir_subs)
1966 +gboolean node_timeval_lt(const GTimeVal *val1, const GTimeVal *val2);
1967 +gboolean node_try_delete(node_t* node);
1968 +void node_traverse(node_t* node, void(*traverse_cb)(node_t*, gpointer), gpointer user_data);
1969 +node_t* node_find(node_t* node, const gchar* filename, gboolean create_on_missing);
1970 +gint node_lstat(node_t *f);
1971 +void node_create_children_snapshot(node_t *f, gint created_event, gboolean emit);
1972 +void node_adjust_deleted(node_t *f);
1973 +gboolean node_class_init();
1975 +typedef struct node_event
1977 + int e;
1978 + gpointer user_data;
1979 + gpointer pair_data;
1980 + GTimeVal ctv; /* Created timestamp */
1981 + GTimeVal rename_tv; /* Possible rename timestamp */
1982 +} node_event_t;
1984 +node_event_t* node_event_new (int event, gpointer user_data);
1985 +void node_event_delete (node_event_t* ev);
1987 +#endif /* _FEN_NODE_H_ */
1988 diff --git a/server/gam_channel.c b/server/gam_channel.c
1989 index 56c3ea7..6db1692 100644
1990 --- a/server/gam_channel.c
1991 +++ b/server/gam_channel.c
1992 @@ -7,6 +7,12 @@
1993 #include <sys/stat.h>
1994 #include <sys/un.h>
1995 #include <sys/uio.h>
1996 +#if defined(sun)
1997 +#include <string.h>
1998 +#endif
1999 +#if defined(HAVE_UCRED_H)
2000 +#include <ucred.h>
2001 +#endif defined(HAVE_UCRED_H)
2002 #include "gam_error.h"
2003 #include "gam_connection.h"
2004 #include "gam_channel.h"
2005 @@ -101,6 +107,10 @@ gam_client_conn_check_cred(GIOChannel * source, int fd,
2006 } cmsg;
2007 #endif
2009 +#if defined(HAVE_GETPEERUCRED)
2010 + ucred_t *creds;
2011 +#endif
2013 s_uid = getuid();
2015 #if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
2016 @@ -167,11 +177,25 @@ gam_client_conn_check_cred(GIOChannel * source, int fd,
2017 fd, cr_len, (int) sizeof(cr));
2018 goto failed;
2020 +#elif defined(HAVE_GETPEERUCRED)
2021 + if ((creds = (ucred_t *)malloc(ucred_size()))==(ucred_t *)NULL){
2022 + GAM_DEBUG(DEBUG_INFO,"Malloc failed for ucreds");
2023 + goto failed;
2026 + if (getpeerucred(fd, &creds)!=0){
2027 + GAM_DEBUG(DEBUG_INFO,"getpeerucred call failed");
2028 + goto failed;
2030 + c_uid = ucred_getruid(creds);
2031 + c_gid = ucred_getrgid(creds);
2032 + c_pid = ucred_getpid(creds);
2033 + ucred_free(creds);
2034 #elif defined(HAVE_CMSGCRED)
2035 c_pid = cmsg.cred.cmcred_pid;
2036 c_uid = cmsg.cred.cmcred_euid;
2037 c_gid = cmsg.cred.cmcred_groups[0];
2038 -#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
2039 +#else /* !SO_PEERCRED && !HAVE_CMSGCRED && !HAVE_GETPEERUCRED */
2040 GAM_DEBUG(DEBUG_INFO,
2041 "Socket credentials not supported on this OS\n");
2042 goto failed;
2043 diff --git a/server/gam_fen.c b/server/gam_fen.c
2044 new file mode 100644
2045 index 0000000..21476e1
2046 --- /dev/null
2047 +++ b/server/gam_fen.c
2048 @@ -0,0 +1,140 @@
2049 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2050 +/* vim:set expandtab ts=4 shiftwidth=4: */
2051 +/*
2052 + * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
2053 + * Use is subject to license terms.
2055 + * This library is free software; you can redistribute it and/or
2056 + * modify it under the terms of the GNU Lesser General Public
2057 + * License as published by the Free Software Foundation; either
2058 + * version 2 of the License, or (at your option) any later version.
2060 + * This library is distributed in the hope that it will be useful,
2061 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2062 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2063 + * Lesser General Public License for more details.
2065 + * You should have received a copy of the GNU Lesser General
2066 + * Public License along with this library; if not, write to the
2067 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
2068 + * Boston, MA 02111-1307, USA.
2070 + * Authors: Lin Ma <lin.ma@sun.com>
2071 + */
2073 + * Design:
2074 + * A Solaris port has a resource limit of events (port_max_events) which
2075 + * limits the number of objects (fds) that can be actively associated objects
2076 + * whith the port. The default is (65536), but can be changed.
2078 + * project.max-port-ids identify the max number of ports
2079 + * process.max-port-events identify the max objs of a port
2080 + * process.max-file-descriptor identify the max fds of a process
2082 + * For a user server process, process.max-file-descriptor seems a bottleneck.
2083 + * I will use a port list for monitor fds to avoid process.max-file-descriptor
2084 + * is greater than process.max-port-events.
2085 + */
2086 +#include "config.h"
2087 +#include "gam_error.h"
2088 +#include "gam_fen.h"
2089 +#include "gam_event.h"
2090 +#include "gam_server.h"
2091 +#include "gam_protocol.h"
2092 +#include <glib.h>
2093 +#include "fen-helper.h"
2095 +/**
2096 + * Initializes the FEN system. This must be called before
2097 + * any other functions in this module.
2099 + * @returns TRUE if initialization succeeded, FALSE otherwise
2100 + */
2102 +gboolean
2103 +gam_fen_init (void)
2105 + if (!fen_init ())
2106 + return FALSE;
2108 + gam_server_install_kernel_hooks (GAMIN_K_FEN,
2109 + gam_fen_add_subscription,
2110 + gam_fen_remove_subscription,
2111 + gam_fen_remove_all_for,
2112 + NULL, NULL);
2113 + return TRUE;
2116 +/**
2117 + * Adds a subscription to be monitored.
2119 + * @param sub a #GamSubscription to be polled
2120 + * @returns TRUE if adding the subscription succeeded, FALSE otherwise
2121 + */
2123 +gboolean
2124 +gam_fen_add_subscription (GamSubscription *sub)
2126 + g_debug ("[ %s ] sub[0x%p]\n", __func__, sub);
2128 + gam_listener_add_subscription (gam_subscription_get_listener (sub), sub);
2129 + fen_add (gam_subscription_get_path(sub),
2130 + sub,
2131 + gam_subscription_is_dir (sub));
2132 + return TRUE;
2135 +/**
2136 + * Removes a subscription which was being monitored.
2138 + * @param sub a #GamSubscription to remove
2139 + * @returns TRUE if removing the subscription succeeded, FALSE otherwise
2140 + */
2142 +gboolean
2143 +gam_fen_remove_subscription (GamSubscription *sub)
2145 + g_debug ("[ %s ] sub[0x%p]\n", __func__, sub);
2147 + fen_remove (gam_subscription_get_path(sub),
2148 + sub,
2149 + gam_subscription_is_dir (sub));
2150 + /* free subscription */
2151 + gam_subscription_cancel(sub);
2152 + gam_subscription_free(sub);
2153 + return TRUE;
2156 +/**
2157 + * Stop monitoring all subscriptions for a given listener.
2159 + * @param listener a #GamListener
2160 + * @returns TRUE if removing the subscriptions succeeded, FALSE otherwise
2161 + */
2163 +gboolean
2164 +gam_fen_remove_all_for (GamListener *listener)
2166 + GList *subs;
2167 + GList *idx;
2168 + gboolean success = TRUE;
2170 + subs = gam_listener_get_subscriptions (listener);
2172 + if (subs == NULL)
2173 + return FALSE;
2175 + for (idx = subs; idx != NULL; idx = idx->next) {
2176 + GamSubscription *sub = (GamSubscription *)idx->data;
2177 + g_assert (sub);
2178 + if (!gam_fen_remove_subscription (sub))
2179 + success = FALSE;
2182 + if (subs) {
2183 + g_list_free (subs);
2184 + return TRUE;
2185 + } else {
2186 + return FALSE;
2189 diff --git a/server/gam_fen.h b/server/gam_fen.h
2190 new file mode 100644
2191 index 0000000..47e952d
2192 --- /dev/null
2193 +++ b/server/gam_fen.h
2194 @@ -0,0 +1,40 @@
2195 +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2196 +/* vim:set expandtab ts=4 shiftwidth=4: */
2197 +/*
2198 + * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
2199 + * Use is subject to license terms.
2201 + * This library is free software; you can redistribute it and/or
2202 + * modify it under the terms of the GNU Lesser General Public
2203 + * License as published by the Free Software Foundation; either
2204 + * version 2 of the License, or (at your option) any later version.
2206 + * This library is distributed in the hope that it will be useful,
2207 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2208 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2209 + * Lesser General Public License for more details.
2211 + * You should have received a copy of the GNU Lesser General
2212 + * Public License along with this library; if not, write to the
2213 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
2214 + * Boston, MA 02111-1307, USA.
2216 + * Authors: Lin Ma <lin.ma@sun.com>
2217 + */
2219 +#ifndef __GAM_FEN_H__
2220 +#define __GAM_FEN_H__
2222 +#include <glib.h>
2223 +#include "gam_subscription.h"
2225 +G_BEGIN_DECLS
2227 +gboolean gam_fen_init (void);
2228 +gboolean gam_fen_add_subscription (GamSubscription *sub);
2229 +gboolean gam_fen_remove_subscription (GamSubscription *sub);
2230 +gboolean gam_fen_remove_all_for (GamListener *listener);
2232 +G_END_DECLS
2234 +#endif /* __GAM_FEN_H__ */
2235 diff --git a/server/gam_fs.c b/server/gam_fs.c
2236 index c8ca704..1d2f2c8 100644
2237 --- a/server/gam_fs.c
2238 +++ b/server/gam_fs.c
2239 @@ -7,9 +7,20 @@
2240 #include <string.h>
2241 #include <errno.h>
2242 #include <glib.h>
2243 +#ifdef HAVE_SYS_MNTTAB_H
2244 +#include <sys/mnttab.h>
2245 +#endif
2246 #include "gam_error.h"
2247 #include "gam_fs.h"
2249 +#ifdef HAVE_SYS_MNTTAB_H
2250 +#define MTAB MNTTAB
2251 +#define MTABDEL "\t"
2252 +#else
2253 +#define MTAB "/etc/mtab"
2254 +#define MTABDEL "\t"
2255 +#endif
2257 #define DEFAULT_POLL_TIMEOUT 0
2259 typedef struct _gam_fs_properties {
2260 @@ -119,7 +130,7 @@ gam_fs_scan_mtab (void)
2261 gam_fs *fs = NULL;
2262 int i;
2264 - g_file_get_contents ("/etc/mtab", &contents, &len, NULL);
2265 + g_file_get_contents (MTAB, &contents, &len, NULL);
2266 if (contents == NULL)
2267 return;
2269 @@ -133,7 +144,7 @@ gam_fs_scan_mtab (void)
2270 if (line[0] == '\0')
2271 continue;
2273 - words = g_strsplit (line, " ", 0);
2274 + words = g_strsplit (line, MTABDEL, 0);
2276 if (words == NULL)
2277 continue;
2278 @@ -176,19 +187,25 @@ gam_fs_init (void)
2279 gam_fs_set ("ext2", GFS_MT_DEFAULT, 0);
2280 gam_fs_set ("reiser4", GFS_MT_DEFAULT, 0);
2281 gam_fs_set ("reiserfs", GFS_MT_DEFAULT, 0);
2282 + gam_fs_set ("zfs", GFS_MT_DEFAULT, 0);
2283 + gam_fs_set ("ufs", GFS_MT_DEFAULT, 0);
2284 gam_fs_set ("novfs", GFS_MT_POLL, 30);
2285 +#ifdef ENABLE_FEN
2286 + gam_fs_set ("nfs", GFS_MT_DEFAULT, 0);
2287 +#else
2288 gam_fs_set ("nfs", GFS_MT_POLL, 5);
2289 - if (stat("/etc/mtab", &mtab_sbuf) != 0)
2290 +#endif
2291 + if (stat(MTAB, &mtab_sbuf) != 0)
2293 - GAM_DEBUG(DEBUG_INFO, "Could not stat /etc/mtab\n");
2294 + GAM_DEBUG(DEBUG_INFO, "Could not stat %s\n",MTAB);
2296 gam_fs_scan_mtab ();
2297 } else {
2298 struct stat sbuf;
2300 - if (stat("/etc/mtab", &sbuf) != 0)
2301 + if (stat(MTAB, &sbuf) != 0)
2303 - GAM_DEBUG(DEBUG_INFO, "Could not stat /etc/mtab\n");
2304 + GAM_DEBUG(DEBUG_INFO, "Could not stat %s\n",MTAB);
2307 /* /etc/mtab has changed */
2308 diff --git a/server/gam_fs.h b/server/gam_fs.h
2309 index bc2d538..94e70fd 100644
2310 --- a/server/gam_fs.h
2311 +++ b/server/gam_fs.h
2312 @@ -8,6 +8,7 @@ typedef enum {
2313 #if !defined(ENABLE_DNOTIFY) && \
2314 !defined(ENABLE_INOTIFY) && \
2315 !defined(ENABLE_KQUEUE) && \
2316 + !defined(ENABLE_FEN) && \
2317 !defined(ENABLE_HURD_MACH_NOTIFY)
2318 GFS_MT_DEFAULT = GFS_MT_POLL,
2319 #else
2320 diff --git a/server/gam_server.c b/server/gam_server.c
2321 index f92a691..e5da29f 100644
2322 --- a/server/gam_server.c
2323 +++ b/server/gam_server.c
2324 @@ -45,6 +45,9 @@
2325 #ifdef ENABLE_HURD_MACH_NOTIFY
2326 #include "gam_hurd_mach_notify.h"
2327 #endif
2328 +#ifdef ENABLE_FEN
2329 +#include "gam_fen.h"
2330 +#endif
2331 #include "gam_excludes.h"
2332 #include "gam_fs.h"
2333 #include "gam_conf.h"
2334 @@ -162,6 +165,12 @@ gam_init_subscriptions(void)
2335 return(TRUE);
2337 #endif
2338 +#ifdef ENABLE_FEN
2339 + if (gam_fen_init()) {
2340 + GAM_DEBUG(DEBUG_INFO, "Using fen as backend\n");
2341 + return(TRUE);
2343 +#endif
2346 if (gam_poll_basic_init()) {
2347 @@ -627,6 +636,10 @@ main(int argc, const char *argv[])
2348 signal(SIGQUIT, gam_exit);
2349 signal(SIGTERM, gam_exit);
2350 signal(SIGPIPE, SIG_IGN);
2351 +#ifdef ENABLE_FEN
2352 + signal(SIGUSR1, SIG_IGN);
2353 + signal(SIGUSR2, SIG_IGN);
2354 +#endif
2356 if (!gam_init_subscriptions()) {
2357 GAM_DEBUG(DEBUG_INFO, "Could not initialize the subscription system.\n");
2358 diff --git a/server/gam_server.h b/server/gam_server.h
2359 index bc99e09..313dd84 100644
2360 --- a/server/gam_server.h
2361 +++ b/server/gam_server.h
2362 @@ -16,7 +16,8 @@ typedef enum {
2363 GAMIN_K_INOTIFY = 2,
2364 GAMIN_K_KQUEUE = 3,
2365 GAMIN_K_MACH = 4,
2366 - GAMIN_K_INOTIFY2 = 5
2367 + GAMIN_K_INOTIFY2 = 5,
2368 + GAMIN_K_FEN = 6
2369 } GamKernelHandler;
2371 typedef enum {
2372 diff --git a/tests/testing.c b/tests/testing.c
2373 index 9926c0a..4c08740 100644
2374 --- a/tests/testing.c
2375 +++ b/tests/testing.c
2376 @@ -1,3 +1,4 @@
2377 +#include "config.h"
2378 #include <stdio.h>
2379 #include <stdlib.h>
2380 #include <unistd.h>
2381 @@ -31,6 +32,11 @@ static struct testState {
2383 #define IS_BLANK(p) ((*(p) == ' ') || (*(p) == '\t') || \
2384 (*(p) == '\n') || (*(p) == '\r'))
2385 +#ifdef ENABLE_FEN
2386 +#define KILLCMD "pkill"
2387 +#else
2388 +#define KILLCMD "killall"
2389 +#endif
2391 static int
2392 scanCommand(char *line, char **command, char **arg, char **arg2)
2393 @@ -268,7 +274,7 @@ processCommand(char *line, int no)
2394 * okay, it's heavy but that's the simplest way since we do not have
2395 * the pid(s) of the servers running.
2397 - ret = system("killall gam_server");
2398 + ret = system(KILLCMD" gam_server");
2399 if (ret < 0) {
2400 fprintf(stderr, "kill line %d: failed to killall gam_server\n",
2401 no);