summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
Diffstat (limited to 'source3')
-rw-r--r--source3/smbd/notify_fam.c166
1 files changed, 90 insertions, 76 deletions
diff --git a/source3/smbd/notify_fam.c b/source3/smbd/notify_fam.c
index 89bbddae24..3fa6dad162 100644
--- a/source3/smbd/notify_fam.c
+++ b/source3/smbd/notify_fam.c
@@ -21,7 +21,7 @@
#include "includes.h"
-#if 0
+#ifdef HAVE_FAM_CHANGE_NOTIFY
#include <fam.h>
@@ -44,23 +44,30 @@ typedef enum FAMCodes FAMCodes;
* http://sourceforge.net/projects/bsdfam/
*/
-static void *fam_notify_add(TALLOC_CTX *mem_ctx,
- struct event_context *event_ctx,
- files_struct *fsp, uint32 *filter);
-
/* ------------------------------------------------------------------------- */
-struct fam_notify_ctx {
- struct fam_notify_ctx *prev, *next;
+struct fam_watch_context {
+ struct fam_watch_context *prev, *next;
FAMConnection *fam_connection;
struct FAMRequest fr;
- files_struct *fsp;
- char *path;
- uint32 filter;
+ struct sys_notify_context *sys_ctx;
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev);
+ void *private_data;
+ uint32_t mask; /* the inotify mask */
+ uint32_t filter; /* the windows completion filter */
+ const char *path;
};
-static struct fam_notify_ctx *fam_notify_list;
+
+/*
+ * We want one FAM connection per smbd, not one per tcon.
+ */
static FAMConnection fam_connection;
+static BOOL fam_connection_initialized = False;
+
+static struct fam_watch_context *fam_notify_list;
static void fam_handler(struct event_context *event_ctx,
struct fd_event *fd_event,
uint16 flags,
@@ -84,7 +91,7 @@ static NTSTATUS fam_open_connection(FAMConnection *fam_conn,
SAFE_FREE(name);
if (res < 0) {
- DEBUG(5, ("FAM file change notifications not available\n"));
+ DEBUG(10, ("FAM file change notifications not available\n"));
/*
* No idea how to get NT_STATUS from a FAM result
*/
@@ -107,9 +114,9 @@ static NTSTATUS fam_open_connection(FAMConnection *fam_conn,
static void fam_reopen(FAMConnection *fam_conn,
struct event_context *event_ctx,
- struct fam_notify_ctx *notify_list)
+ struct fam_watch_context *notify_list)
{
- struct fam_notify_ctx *ctx;
+ struct fam_watch_context *ctx;
DEBUG(5, ("Re-opening FAM connection\n"));
@@ -132,8 +139,8 @@ static void fam_handler(struct event_context *event_ctx,
{
FAMConnection *fam_conn = (FAMConnection *)private_data;
FAMEvent fam_event;
- struct fam_notify_ctx *ctx;
- char *name;
+ struct fam_watch_context *ctx;
+ struct notify_event ne;
if (FAMPending(fam_conn) == 0) {
DEBUG(10, ("fam_handler called but nothing pending\n"));
@@ -141,13 +148,23 @@ static void fam_handler(struct event_context *event_ctx,
}
if (FAMNextEvent(fam_conn, &fam_event) != 1) {
- DEBUG(10, ("FAMNextEvent returned an error\n"));
+ DEBUG(5, ("FAMNextEvent returned an error\n"));
TALLOC_FREE(fd_event);
fam_reopen(fam_conn, event_ctx, fam_notify_list);
return;
}
- if ((fam_event.code != FAMCreated) && (fam_event.code != FAMDeleted)) {
+ DEBUG(10, ("Got FAMCode %d for %s\n", fam_event.code,
+ fam_event.filename));
+
+ switch (fam_event.code) {
+ case FAMCreated:
+ ne.action = NOTIFY_ACTION_ADDED;
+ break;
+ case FAMDeleted:
+ ne.action = NOTIFY_ACTION_REMOVED;
+ break;
+ default:
DEBUG(10, ("Ignoring code FAMCode %d for file %s\n",
(int)fam_event.code, fam_event.filename));
return;
@@ -165,17 +182,14 @@ static void fam_handler(struct event_context *event_ctx,
return;
}
- if ((name = strrchr_m(fam_event.filename, '\\')) == NULL) {
- name = fam_event.filename;
+ if ((ne.path = strrchr_m(fam_event.filename, '\\')) == NULL) {
+ ne.path = fam_event.filename;
}
- notify_fsp(ctx->fsp,
- fam_event.code == FAMCreated
- ? NOTIFY_ACTION_ADDED : NOTIFY_ACTION_REMOVED,
- name);
+ ctx->callback(ctx->sys_ctx, ctx->private_data, &ne);
}
-static int fam_notify_ctx_destructor(struct fam_notify_ctx *ctx)
+static int fam_watch_context_destructor(struct fam_watch_context *ctx)
{
if (FAMCONNECTION_GETFD(ctx->fam_connection) != -1) {
FAMCancelMonitor(&fam_connection, &ctx->fr);
@@ -184,86 +198,86 @@ static int fam_notify_ctx_destructor(struct fam_notify_ctx *ctx)
return 0;
}
-static void *fam_notify_add(TALLOC_CTX *mem_ctx,
- struct event_context *event_ctx,
- files_struct *fsp, uint32 *filter)
+/*
+ add a watch. The watch is removed when the caller calls
+ talloc_free() on *handle
+*/
+NTSTATUS fam_watch(struct sys_notify_context *ctx,
+ struct notify_entry *e,
+ void (*callback)(struct sys_notify_context *ctx,
+ void *private_data,
+ struct notify_event *ev),
+ void *private_data,
+ void *handle_p)
{
- struct fam_notify_ctx *ctx;
-
- if ((*filter & FILE_NOTIFY_CHANGE_FILE_NAME) == 0) {
- DEBUG(10, ("filter = %u, no FILE_NOTIFY_CHANGE_FILE_NAME\n",
- *filter));
- return NULL;
+ const uint32 fam_mask = (FILE_NOTIFY_CHANGE_FILE_NAME|
+ FILE_NOTIFY_CHANGE_DIR_NAME);
+ struct fam_watch_context *watch;
+ void **handle = (void **)handle_p;
+
+ if ((e->filter & fam_mask) == 0) {
+ DEBUG(10, ("filter = %u, ignoring in FAM\n", e->filter));
+ return NT_STATUS_OK;
}
- if (!(ctx = TALLOC_P(mem_ctx, struct fam_notify_ctx))) {
- return NULL;
+ if (!fam_connection_initialized) {
+ if (!NT_STATUS_IS_OK(fam_open_connection(&fam_connection,
+ ctx->ev))) {
+ /*
+ * Just let smbd do all the work itself
+ */
+ return NT_STATUS_OK;
+ }
+ fam_connection_initialized = True;
}
- ctx->fsp = fsp;
- ctx->fam_connection = &fam_connection;
+ if (!(watch = TALLOC_P(ctx, struct fam_watch_context))) {
+ return NT_STATUS_NO_MEMORY;
+ }
- /*
- * The FAM module in this early state will only take care of
- * FAMCreated and FAMDeleted events
- */
+ watch->fam_connection = &fam_connection;
- ctx->filter = FILE_NOTIFY_CHANGE_FILE_NAME;
+ watch->callback = callback;
+ watch->private_data = private_data;
+ watch->sys_ctx = ctx;
- if (!(ctx->path = talloc_asprintf(ctx, "%s/%s", fsp->conn->connectpath,
- fsp->fsp_name))) {
+ if (!(watch->path = talloc_strdup(watch, e->path))) {
DEBUG(0, ("talloc_asprintf failed\n"));
- TALLOC_FREE(ctx);
- return NULL;
+ TALLOC_FREE(watch);
+ return NT_STATUS_NO_MEMORY;
}
/*
- * Leave the rest to smbd itself
+ * The FAM module in this early state will only take care of
+ * FAMCreated and FAMDeleted events, Leave the rest to
+ * notify_internal.c
*/
- *filter &= ~FILE_NOTIFY_CHANGE_FILE_NAME;
+ watch->filter = fam_mask;
+ e->filter &= ~fam_mask;
- DLIST_ADD(fam_notify_list, ctx);
- talloc_set_destructor(ctx, fam_notify_ctx_destructor);
+ DLIST_ADD(fam_notify_list, watch);
+ talloc_set_destructor(watch, fam_watch_context_destructor);
/*
* Only directories monitored so far
*/
- if (FAMCONNECTION_GETFD(ctx->fam_connection) != -1) {
- FAMMonitorDirectory(ctx->fam_connection, ctx->path, &ctx->fr,
- NULL);
+ if (FAMCONNECTION_GETFD(watch->fam_connection) != -1) {
+ FAMMonitorDirectory(watch->fam_connection, watch->path,
+ &watch->fr, NULL);
}
else {
/*
* If the re-open is successful, this will establish the
* FAMMonitor from the list
*/
- fam_reopen(ctx->fam_connection, event_ctx, fam_notify_list);
+ fam_reopen(watch->fam_connection, ctx->ev, fam_notify_list);
}
- return ctx;
-}
-
-static struct cnotify_fns global_fam_notify =
-{
- fam_notify_add,
-};
+ *handle = (void *)watch;
-struct cnotify_fns *fam_notify_init(struct event_context *event_ctx)
-{
-
- ZERO_STRUCT(fam_connection);
- FAMCONNECTION_GETFD(&fam_connection) = -1;
-
- if (!NT_STATUS_IS_OK(fam_open_connection(&fam_connection,
- event_ctx))) {
- DEBUG(0, ("FAM file change notifications not available\n"));
- return NULL;
- }
-
- DEBUG(10, ("enabling FAM change notifications\n"));
- return &global_fam_notify;
+ return NT_STATUS_OK;
}
#endif /* HAVE_FAM_CHANGE_NOTIFY */