summaryrefslogtreecommitdiff
path: root/source3/smbd/notify.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd/notify.c')
-rw-r--r--source3/smbd/notify.c226
1 files changed, 48 insertions, 178 deletions
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c
index 2c762bd759..ce7680b49a 100644
--- a/source3/smbd/notify.c
+++ b/source3/smbd/notify.c
@@ -3,6 +3,7 @@
change notify handling
Copyright (C) Andrew Tridgell 2000
Copyright (C) Jeremy Allison 1994-1998
+ 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
@@ -24,22 +25,6 @@
static struct cnotify_fns *cnotify;
static struct notify_mid_map *notify_changes_by_mid;
-/****************************************************************************
- This is the structure to queue to implement NT change
- notify. It consists of smb_size bytes stored from the
- transact command (to keep the mid, tid etc around).
- Plus the fid to examine and notify private data.
-*****************************************************************************/
-
-struct change_notify {
- struct change_notify *next, *prev;
- files_struct *fsp;
- uint32 flags;
- uint32 max_param_count;
- char request_buf[smb_size];
- void *change_data;
-};
-
/*
* For NTCancel, we need to find the notify_change_request indexed by
* mid. Separate list here.
@@ -51,9 +36,7 @@ struct notify_mid_map {
uint16 mid;
};
-static struct change_notify *change_notify_list;
-
-static BOOL notify_marshall_changes(unsigned num_changes,
+static BOOL notify_marshall_changes(int num_changes,
struct notify_change *changes,
prs_struct *ps)
{
@@ -132,12 +115,17 @@ static void change_notify_reply_packet(const char *request_buf,
}
void change_notify_reply(const char *request_buf, uint32 max_param_count,
- unsigned num_changes, struct notify_change *changes)
+ int num_changes, struct notify_change *changes)
{
char *outbuf = NULL;
prs_struct ps;
size_t buflen = smb_size+38+max_param_count;
+ if (num_changes == -1) {
+ change_notify_reply_packet(request_buf, NT_STATUS_OK);
+ return;
+ }
+
if (!prs_init(&ps, 0, NULL, False)
|| !notify_marshall_changes(num_changes, changes, &ps)) {
change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY);
@@ -170,19 +158,6 @@ void change_notify_reply(const char *request_buf, uint32 max_param_count,
prs_mem_free(&ps);
}
-/****************************************************************************
- Remove an entry from the list and free it, also closing any
- directory handle if necessary.
-*****************************************************************************/
-
-static void change_notify_remove(struct change_notify *cnbp)
-{
- cnotify->remove_notify(cnbp->change_data);
- DLIST_REMOVE(change_notify_list, cnbp);
- ZERO_STRUCTP(cnbp);
- SAFE_FREE(cnbp);
-}
-
NTSTATUS change_notify_add_request(const char *inbuf, uint32 max_param_count,
uint32 filter, struct files_struct *fsp)
{
@@ -202,6 +177,10 @@ NTSTATUS change_notify_add_request(const char *inbuf, uint32 max_param_count,
request->max_param_count = max_param_count;
request->filter = filter;
request->fsp = fsp;
+
+ request->backend_data = cnotify->notify_add(NULL, smbd_event_context(),
+ fsp, &request->filter);
+
DLIST_ADD_END(fsp->notify->requests, request,
struct notify_change_request *);
@@ -240,6 +219,7 @@ static void change_notify_remove_request(struct notify_change_request *remove_re
DLIST_REMOVE(fsp->notify->requests, req);
DLIST_REMOVE(notify_changes_by_mid, req->mid_map);
SAFE_FREE(req->mid_map);
+ TALLOC_FREE(req->backend_data);
SAFE_FREE(req);
}
@@ -283,141 +263,6 @@ void remove_pending_change_notify_requests_by_fid(files_struct *fsp,
}
}
-/****************************************************************************
- Delete entries by filename and cnum from the change notify pending queue.
- Always send reply.
-*****************************************************************************/
-
-void remove_pending_change_notify_requests_by_filename(files_struct *fsp, NTSTATUS status)
-{
- struct change_notify *cnbp, *next;
-
- for (cnbp=change_notify_list; cnbp; cnbp=next) {
- next=cnbp->next;
- /*
- * We know it refers to the same directory if the connection number and
- * the filename are identical.
- */
- if((cnbp->fsp->conn == fsp->conn) && strequal(cnbp->fsp->fsp_name,fsp->fsp_name)) {
- change_notify_reply_packet(cnbp->request_buf, status);
- change_notify_remove(cnbp);
- }
- }
-}
-
-/****************************************************************************
- Set the current change notify timeout to the lowest value across all service
- values.
-****************************************************************************/
-
-void set_change_notify_timeout(int val)
-{
- if (val > 0) {
- cnotify->select_time = MIN(cnotify->select_time, val);
- }
-}
-
-/****************************************************************************
- Longest time to sleep for before doing a change notify scan.
-****************************************************************************/
-
-int change_notify_timeout(void)
-{
- return cnotify->select_time;
-}
-
-/****************************************************************************
- Process the change notify queue. Note that this is only called as root.
- Returns True if there are still outstanding change notify requests on the
- queue.
-*****************************************************************************/
-
-BOOL process_pending_change_notify_queue(time_t t)
-{
- struct change_notify *cnbp, *next;
- uint16 vuid;
-
- for (cnbp=change_notify_list; cnbp; cnbp=next) {
- next=cnbp->next;
-
- vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(cnbp->request_buf,smb_uid);
-
- if (cnbp->fsp->notify->num_changes != 0) {
- DEBUG(10,("process_pending_change_notify_queue: %s "
- "has %d changes!\n", cnbp->fsp->fsp_name,
- cnbp->fsp->notify->num_changes));
- change_notify_reply(cnbp->request_buf,
- cnbp->max_param_count,
- cnbp->fsp->notify->num_changes,
- cnbp->fsp->notify->changes);
- change_notify_remove(cnbp);
- continue;
- }
-
- if (cnotify->check_notify(cnbp->fsp->conn, vuid,
- cnbp->fsp->fsp_name, cnbp->flags,
- cnbp->change_data, t)) {
- DEBUG(10,("process_pending_change_notify_queue: dir "
- "%s changed !\n", cnbp->fsp->fsp_name ));
- change_notify_reply(cnbp->request_buf,
- cnbp->max_param_count,
- cnbp->fsp->notify->num_changes,
- cnbp->fsp->notify->changes);
- change_notify_remove(cnbp);
- }
- }
-
- return (change_notify_list != NULL);
-}
-
-/****************************************************************************
- Now queue an entry on the notify change list.
- We only need to save smb_size bytes from this incoming packet
- as we will always by returning a 'read the directory yourself'
- error.
-****************************************************************************/
-
-BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn,
- uint32 flags, uint32 max_param_count)
-{
- struct change_notify *cnbp;
-
- if((cnbp = SMB_MALLOC_P(struct change_notify)) == NULL) {
- DEBUG(0,("change_notify_set: malloc fail !\n" ));
- return False;
- }
-
- ZERO_STRUCTP(cnbp);
-
- memcpy(cnbp->request_buf, inbuf, smb_size);
- cnbp->fsp = fsp;
- cnbp->flags = flags;
- cnbp->max_param_count = max_param_count;
- cnbp->change_data = cnotify->register_notify(conn, fsp->fsp_name,
- flags);
-
- if (!cnbp->change_data) {
- SAFE_FREE(cnbp);
- return False;
- }
-
- DLIST_ADD(change_notify_list, cnbp);
-
- /* Push the MID of this packet on the signing queue. */
- srv_defer_sign_response(SVAL(inbuf,smb_mid));
-
- return True;
-}
-
-int change_notify_fd(void)
-{
- if (cnotify) {
- return cnotify->notification_fd;
- }
-
- return -1;
-}
-
/* notify message definition
Offset Data length.
@@ -571,7 +416,7 @@ void notify_fname(connection_struct *conn, const char *path,
TALLOC_FREE(parent);
}
-static void notify_fsp(files_struct *fsp, struct notify_message *msg)
+void notify_fsp(files_struct *fsp, uint32 action, char *name)
{
struct notify_change *change, *changes;
@@ -582,8 +427,7 @@ static void notify_fsp(files_struct *fsp, struct notify_message *msg)
return;
}
- if ((fsp->notify->requests != NULL)
- && (fsp->notify->requests->filter & msg->filter)) {
+ if (fsp->notify->requests != NULL) {
/*
* Someone is waiting for the change, trigger the reply
* immediately.
@@ -594,8 +438,18 @@ static void notify_fsp(files_struct *fsp, struct notify_message *msg)
struct notify_change_request *req = fsp->notify->requests;
struct notify_change onechange;
- onechange.action = msg->action;
- onechange.name = msg->name;
+ if (name == NULL) {
+ /*
+ * Catch-all change, possibly from notify_hash.c
+ */
+ change_notify_reply(req->request_buf,
+ req->max_param_count,
+ -1, NULL);
+ return;
+ }
+
+ onechange.action = action;
+ onechange.name = name;
change_notify_reply(req->request_buf, req->max_param_count,
1, &onechange);
@@ -609,6 +463,19 @@ static void notify_fsp(files_struct *fsp, struct notify_message *msg)
* apply here. Do we have to store them?
*/
+ if ((fsp->notify->num_changes > 30) || (name == NULL)) {
+ /*
+ * W2k3 seems to store at most 30 changes.
+ */
+ TALLOC_FREE(fsp->notify->changes);
+ fsp->notify->num_changes = -1;
+ return;
+ }
+
+ if (fsp->notify->num_changes == -1) {
+ return;
+ }
+
if (!(changes = TALLOC_REALLOC_ARRAY(
fsp->notify, fsp->notify->changes,
struct notify_change, fsp->notify->num_changes+1))) {
@@ -620,11 +487,11 @@ static void notify_fsp(files_struct *fsp, struct notify_message *msg)
change = &(fsp->notify->changes[fsp->notify->num_changes]);
- if (!(change->name = talloc_strdup(changes, msg->name))) {
+ if (!(change->name = talloc_strdup(changes, name))) {
DEBUG(0, ("talloc_strdup failed\n"));
return;
}
- change->action = msg->action;
+ change->action = action;
fsp->notify->num_changes += 1;
return;
@@ -645,7 +512,10 @@ static void notify_message_callback(int msgtype, struct process_id pid,
for(fsp = fsp_find_di_first(msg.dev, msg.inode); fsp;
fsp = fsp_find_di_next(fsp)) {
- notify_fsp(fsp, &msg);
+ if ((fsp->notify->requests != NULL)
+ && (fsp->notify->requests->filter & msg.filter)) {
+ notify_fsp(fsp, msg.action, msg.name);
+ }
}
}
@@ -659,11 +529,11 @@ BOOL init_change_notify(void)
#if HAVE_KERNEL_CHANGE_NOTIFY
if (cnotify == NULL && lp_kernel_change_notify())
- cnotify = kernel_notify_init();
+ cnotify = kernel_notify_init(smbd_event_context());
#endif
#if HAVE_FAM_CHANGE_NOTIFY
if (cnotify == NULL && lp_fam_change_notify())
- cnotify = fam_notify_init();
+ cnotify = fam_notify_init(smbd_event_context());
#endif
if (!cnotify) cnotify = hash_notify_init();