summaryrefslogtreecommitdiff
path: root/source3/smbd/notify_hash.c
diff options
context:
space:
mode:
authorVolker Lendecke <vlendec@samba.org>2007-01-21 11:49:00 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:17:21 -0500
commitd5206610cd67f88e2cc7d5b2b434e320e81c29d5 (patch)
tree5b085416bd4403cea107f73a1e874199fd1284b1 /source3/smbd/notify_hash.c
parent57881f749495825f61f8affce921eee46fc7b728 (diff)
downloadsamba-d5206610cd67f88e2cc7d5b2b434e320e81c29d5.tar.gz
samba-d5206610cd67f88e2cc7d5b2b434e320e81c29d5.tar.bz2
samba-d5206610cd67f88e2cc7d5b2b434e320e81c29d5.zip
r20931: This changes the notify infrastructure from a polling-based to an event-driven
based approach. The only remaining hook into the backend is now void *(*notify_add)(TALLOC_CTX *mem_ctx, struct event_context *event_ctx, files_struct *fsp, uint32 *filter); (Should we put this through the VFS, so that others can more easily plug in?) The trick here is that the backend can pick filter bits that the main smbd should not handle anymore. Thanks to tridge for this idea. The backend can notify the main smbd process via void notify_fsp(files_struct *fsp, uint32 action, char *name); The core patch is not big, what makes this more than 1800 lines are the individual backends that are considerably changed but can be reviewed one by one. Based on this I'll continue with inotify now. Volker (This used to be commit 9cd6a8a82792b7b6967141565d043b6337836a5d)
Diffstat (limited to 'source3/smbd/notify_hash.c')
-rw-r--r--source3/smbd/notify_hash.c191
1 files changed, 111 insertions, 80 deletions
diff --git a/source3/smbd/notify_hash.c b/source3/smbd/notify_hash.c
index 0787a3eec5..773a7565c5 100644
--- a/source3/smbd/notify_hash.c
+++ b/source3/smbd/notify_hash.c
@@ -3,6 +3,7 @@
change notify handling - hash based implementation
Copyright (C) Jeremy Allison 1994-1998
Copyright (C) Andrew Tridgell 2000
+ Copyright (C) Volker Lendecke 2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,16 +22,26 @@
#include "includes.h"
-struct change_data {
+struct hash_change_data {
time_t last_check_time; /* time we last checked this entry */
- struct timespec modify_time; /* Info from the directory we're monitoring. */
- struct timespec status_time; /* Info from the directory we're monitoring. */
- time_t total_time; /* Total time of all directory entries - don't care if it wraps. */
- unsigned int num_entries; /* Zero or the number of files in the directory. */
+ struct timespec modify_time; /* Info from the directory we're
+ * monitoring. */
+ struct timespec status_time; /* Info from the directory we're
+ * monitoring. */
+ time_t total_time; /* Total time of all directory entries - don't care
+ * if it wraps. */
+ unsigned int num_entries; /* Zero or the number of files in the
+ * directory. */
unsigned int mode_sum;
unsigned char name_hash[16];
};
+struct hash_notify_ctx {
+ struct hash_change_data *data;
+ files_struct *fsp;
+ char *path;
+ uint32 filter;
+};
/* Compare struct timespec. */
#define TIMESTAMP_NEQ(x, y) (((x).tv_sec != (y).tv_sec) || ((x).tv_nsec != (y).tv_nsec))
@@ -40,7 +51,8 @@ struct change_data {
*****************************************************************************/
static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
- struct change_data *data, struct change_data *old_data)
+ struct hash_change_data *data,
+ struct hash_change_data *old_data)
{
SMB_STRUCT_STAT st;
pstring full_name;
@@ -71,7 +83,8 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
}
if (S_ISDIR(st.st_mode) &&
- (flags & ~(FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) == 0)
+ (flags & ~(FILE_NOTIFY_CHANGE_FILE_NAME
+ | FILE_NOTIFY_CHANGE_DIR_NAME)) == 0)
{
/* This is the case of a client wanting to know only when
* the contents of a directory changes. Since any file
@@ -81,11 +94,6 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
return True;
}
- if (lp_change_notify_timeout(SNUM(conn)) <= 0) {
- /* It change notify timeout has been disabled, never scan the directory. */
- return True;
- }
-
/*
* If we are to watch for changes that are only stored
* in inodes of files, not in the directory inode, we must
@@ -138,10 +146,13 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
* If requested hash the names.
*/
- if (flags & (FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_FILE)) {
+ if (flags & (FILE_NOTIFY_CHANGE_DIR_NAME
+ |FILE_NOTIFY_CHANGE_FILE_NAME
+ |FILE_NOTIFY_CHANGE_FILE)) {
int i;
unsigned char tmp_hash[16];
- mdfour(tmp_hash, (const unsigned char *)fname, strlen(fname));
+ mdfour(tmp_hash, (const unsigned char *)fname,
+ strlen(fname));
for (i=0;i<16;i++)
data->name_hash[i] ^= tmp_hash[i];
}
@@ -150,7 +161,8 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
* If requested sum the mode_t's.
*/
- if (flags & (FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_SECURITY))
+ if (flags & (FILE_NOTIFY_CHANGE_ATTRIBUTES
+ |FILE_NOTIFY_CHANGE_SECURITY))
data->mode_sum += st.st_mode;
}
@@ -159,77 +171,111 @@ static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags,
return True;
}
-/****************************************************************************
- Register a change notify request.
-*****************************************************************************/
-
-static void *hash_register_notify(connection_struct *conn, char *path, uint32 flags)
+static void hash_change_notify_handler(struct event_context *event_ctx,
+ struct timed_event *te,
+ const struct timeval *now,
+ void *private_data)
{
- struct change_data data;
+ struct hash_change_data *new_data;
+ struct hash_notify_ctx *ctx =
+ talloc_get_type_abort(private_data,
+ struct hash_notify_ctx);
- if (!notify_hash(conn, path, flags, &data, NULL))
- return NULL;
+ TALLOC_FREE(te);
- data.last_check_time = time(NULL);
+ if (!(new_data = TALLOC_P(ctx, struct hash_change_data))) {
+ DEBUG(0, ("talloc failed\n"));
+ /*
+ * No new timed event;
+ */
+ return;
+ }
- return (void *)memdup(&data, sizeof(data));
+ if (!notify_hash(ctx->fsp->conn, ctx->fsp->fsp_name,
+ ctx->filter, new_data, ctx->data)
+ || TIMESTAMP_NEQ(new_data->modify_time, ctx->data->modify_time)
+ || TIMESTAMP_NEQ(new_data->status_time, ctx->data->status_time)
+ || new_data->total_time != ctx->data->total_time
+ || new_data->num_entries != ctx->data->num_entries
+ || new_data->mode_sum != ctx->data->mode_sum
+ || (memcmp(new_data->name_hash, ctx->data->name_hash,
+ sizeof(new_data->name_hash)))) {
+ notify_fsp(ctx->fsp, 0, NULL);
+ }
+
+ TALLOC_FREE(ctx->data);
+ ctx->data = new_data;
+
+ event_add_timed(
+ event_ctx, ctx,
+ timeval_current_ofs(
+ lp_change_notify_timeout(SNUM(ctx->fsp->conn)), 0),
+ "hash_change_notify_handler",
+ hash_change_notify_handler, ctx);
}
-/****************************************************************************
- Check if a change notify should be issued.
- A time of zero means instantaneous check - don't modify the last check time.
-*****************************************************************************/
-static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t)
+
+static void *hash_notify_add(TALLOC_CTX *mem_ctx,
+ struct event_context *event_ctx,
+ files_struct *fsp,
+ uint32 *filter)
{
- struct change_data *data = (struct change_data *)datap;
- struct change_data data2;
- int cnto = lp_change_notify_timeout(SNUM(conn));
+ struct hash_notify_ctx *ctx;
+ int timeout = lp_change_notify_timeout(SNUM(fsp->conn));
+ pstring fullpath;
- if (t && cnto <= 0) {
- /* Change notify turned off on this share.
- * Only scan when (t==0) - we think something changed. */
- return False;
+ if (timeout <= 0) {
+ /* It change notify timeout has been disabled, never scan the
+ * directory. */
+ return NULL;
}
- if (t && t < data->last_check_time + cnto) {
- return False;
+ pstrcpy(fullpath, fsp->fsp_name);
+ if (!canonicalize_path(fsp->conn, fullpath)) {
+ DEBUG(0, ("failed to canonicalize path '%s'\n", fullpath));
+ return NULL;
}
- if (!change_to_user(conn,vuid))
- return True;
- if (!set_current_service(conn,FLAG_CASELESS_PATHNAMES,True)) {
- change_to_root_user();
- return True;
+ if (*fullpath != '/') {
+ DEBUG(0, ("canonicalized path '%s' into `%s`\n", fsp->fsp_name,
+ fullpath));
+ DEBUGADD(0, ("but expected an absolute path\n"));
+ return NULL;
+ }
+
+ if (!(ctx = TALLOC_P(mem_ctx, struct hash_notify_ctx))) {
+ DEBUG(0, ("talloc failed\n"));
+ return NULL;
}
- if (!notify_hash(conn, path, flags, &data2, data) ||
- TIMESTAMP_NEQ(data2.modify_time, data->modify_time) ||
- TIMESTAMP_NEQ(data2.status_time, data->status_time) ||
- data2.total_time != data->total_time ||
- data2.num_entries != data->num_entries ||
- data2.mode_sum != data->mode_sum ||
- memcmp(data2.name_hash, data->name_hash, sizeof(data2.name_hash))) {
- change_to_root_user();
- return True;
+ if (!(ctx->path = talloc_strdup(ctx, fullpath))) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ TALLOC_FREE(ctx);
+ return NULL;
}
- if (t) {
- data->last_check_time = t;
+ if (!(ctx->data = TALLOC_P(ctx, struct hash_change_data))) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(ctx);
+ return NULL;
}
- change_to_root_user();
+ ctx->fsp = fsp;
- return False;
-}
+ /*
+ * Don't change the Samba filter, hash can only be a very bad attempt
+ * anyway.
+ */
+ ctx->filter = *filter;
-/****************************************************************************
- Remove a change notify data structure.
-*****************************************************************************/
+ notify_hash(fsp->conn, ctx->path, ctx->filter, ctx->data, NULL);
-static void hash_remove_notify(void *datap)
-{
- free(datap);
+ event_add_timed(event_ctx, ctx, timeval_current_ofs(timeout, 0),
+ "hash_change_notify_handler",
+ hash_change_notify_handler, ctx);
+
+ return (void *)ctx;
}
/****************************************************************************
@@ -240,22 +286,7 @@ struct cnotify_fns *hash_notify_init(void)
{
static struct cnotify_fns cnotify;
- cnotify.register_notify = hash_register_notify;
- cnotify.check_notify = hash_check_notify;
- cnotify.remove_notify = hash_remove_notify;
- cnotify.select_time = 60; /* Start with 1 minute default. */
- cnotify.notification_fd = -1;
+ cnotify.notify_add = hash_notify_add;
return &cnotify;
}
-
-/*
- change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
- change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR);
-
- chain_size = 0;
- file_chain_reset();
-
- uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID :
- SVAL(cnbp->request_buf,smb_uid);
-*/