1
0
mirror of https://github.com/samba-team/samba.git synced 2025-08-03 04:22:09 +03:00

r20854: Ok, now I think we're at a point where looking at notify starts to make sense

again :-)

Volker
This commit is contained in:
Volker Lendecke
2007-01-17 16:23:45 +00:00
committed by Gerald (Jerry) Carter
parent b48ea4d777
commit 5533cdeec1
8 changed files with 627 additions and 41 deletions

View File

@ -71,6 +71,7 @@
#define MSG_SMB_FILE_RENAME 3011 #define MSG_SMB_FILE_RENAME 3011
#define MSG_SMB_INJECT_FAULT 3012 #define MSG_SMB_INJECT_FAULT 3012
#define MSG_SMB_BLOCKING_LOCK_CANCEL 3013 #define MSG_SMB_BLOCKING_LOCK_CANCEL 3013
#define MSG_SMB_NOTIFY 3014
/* winbind messages */ /* winbind messages */
#define MSG_WINBIND_FINISHED 4001 #define MSG_WINBIND_FINISHED 4001

View File

@ -434,6 +434,49 @@ struct vfs_fsp_data {
*/ */
}; };
/* the basic packet size, assuming no words or bytes */
#define smb_size 39
struct notify_change {
uint32_t action;
char *name;
};
struct notify_change_request {
struct notify_change_request *prev, *next;
struct files_struct *fsp; /* backpointer for cancel by mid */
char request_buf[smb_size];
uint32 filter;
uint32 max_param_count;
struct notify_mid_map *mid_map;
};
/*
* For NTCancel, we need to find the notify_change_request indexed by
* mid. Separate list here.
*/
struct notify_mid_map {
struct notify_mid_map *prev, *next;
struct notify_change_request *req;
uint16 mid;
};
struct notify_change_buf {
/*
* If no requests are pending, changes are queued here. Simple array,
* we only append.
*/
unsigned num_changes;
struct notify_change *changes;
/*
* If no changes are around requests are queued here. Using a linked
* list, because we have to append at the end and delete from the top.
*/
struct notify_change_request *requests;
};
typedef struct files_struct { typedef struct files_struct {
struct files_struct *next, *prev; struct files_struct *next, *prev;
int fnum; int fnum;
@ -476,6 +519,8 @@ typedef struct files_struct {
struct vfs_fsp_data *vfs_extension; struct vfs_fsp_data *vfs_extension;
FAKE_FILE_HANDLE *fake_file_handle; FAKE_FILE_HANDLE *fake_file_handle;
struct notify_change_buf *notify;
} files_struct; } files_struct;
#include "ntquotas.h" #include "ntquotas.h"
@ -885,9 +930,6 @@ struct bitmap {
unsigned int n; unsigned int n;
}; };
/* the basic packet size, assuming no words or bytes */
#define smb_size 39
/* offsets into message for common items */ /* offsets into message for common items */
#define smb_com 8 #define smb_com 8
#define smb_rcls 9 #define smb_rcls 9
@ -1349,6 +1391,19 @@ struct bitmap {
#define FILE_NOTIFY_CHANGE_SECURITY 0x100 #define FILE_NOTIFY_CHANGE_SECURITY 0x100
#define FILE_NOTIFY_CHANGE_FILE_NAME 0x200 #define FILE_NOTIFY_CHANGE_FILE_NAME 0x200
#define FILE_NOTIFY_CHANGE_NAME \
(FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME)
/* change notify action results */
#define NOTIFY_ACTION_ADDED 1
#define NOTIFY_ACTION_REMOVED 2
#define NOTIFY_ACTION_MODIFIED 3
#define NOTIFY_ACTION_OLD_NAME 4
#define NOTIFY_ACTION_NEW_NAME 5
#define NOTIFY_ACTION_ADDED_STREAM 6
#define NOTIFY_ACTION_REMOVED_STREAM 7
#define NOTIFY_ACTION_MODIFIED_STREAM 8
/* where to find the base of the SMB packet proper */ /* where to find the base of the SMB packet proper */
#define smb_base(buf) (((char *)(buf))+4) #define smb_base(buf) (((char *)(buf))+4)

View File

@ -491,8 +491,11 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)); unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
} }
if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0) if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0) {
notify_fname(conn, fname, FILE_NOTIFY_CHANGE_ATTRIBUTES,
NOTIFY_ACTION_MODIFIED);
return 0; return 0;
}
if((errno != EPERM) && (errno != EACCES)) if((errno != EPERM) && (errno != EACCES))
return -1; return -1;
@ -521,6 +524,8 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
ret = SMB_VFS_FCHMOD(fsp, fsp->fh->fd, unixmode); ret = SMB_VFS_FCHMOD(fsp, fsp->fh->fd, unixmode);
unbecome_root(); unbecome_root();
close_file_fchmod(fsp); close_file_fchmod(fsp);
notify_fname(conn, fname, FILE_NOTIFY_CHANGE_ATTRIBUTES,
NOTIFY_ACTION_MODIFIED);
} }
return( ret ); return( ret );
@ -594,5 +599,8 @@ BOOL set_filetime(connection_struct *conn, const char *fname, time_t mtime)
return False; return False;
} }
notify_fname(conn, fname, FILE_NOTIFY_CHANGE_LAST_WRITE,
NOTIFY_ACTION_MODIFIED);
return(True); return(True);
} }

View File

@ -361,6 +361,50 @@ files_struct *file_find_di_next(files_struct *start_fsp)
return NULL; return NULL;
} }
/*
* Same as file_find_di_first/next, but also finds non-fd opens.
*
* Jeremy, do we really need the fsp->fh->fd != -1 ??
*/
struct files_struct *fsp_find_di_first(SMB_DEV_T dev, SMB_INO_T inode)
{
files_struct *fsp;
if (fsp_fi_cache.dev == dev && fsp_fi_cache.inode == inode) {
/* Positive or negative cache hit. */
return fsp_fi_cache.fsp;
}
fsp_fi_cache.dev = dev;
fsp_fi_cache.inode = inode;
for (fsp=Files;fsp;fsp=fsp->next) {
if ((fsp->dev == dev) && (fsp->inode == inode)) {
/* Setup positive cache. */
fsp_fi_cache.fsp = fsp;
return fsp;
}
}
/* Setup negative cache. */
fsp_fi_cache.fsp = NULL;
return NULL;
}
struct files_struct *fsp_find_di_next(files_struct *start_fsp)
{
files_struct *fsp;
for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
if ( (fsp->dev == start_fsp->dev)
&& (fsp->inode == start_fsp->inode) )
return fsp;
}
return NULL;
}
/**************************************************************************** /****************************************************************************
Find a fsp that is open for printing. Find a fsp that is open for printing.
****************************************************************************/ ****************************************************************************/
@ -439,6 +483,8 @@ void file_free(files_struct *fsp)
fsp->fh->ref_count--; fsp->fh->ref_count--;
} }
TALLOC_FREE(fsp->notify);
bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET); bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
files_used--; files_used--;

View File

@ -22,6 +22,7 @@
#include "includes.h" #include "includes.h"
static struct cnotify_fns *cnotify; static struct cnotify_fns *cnotify;
static struct notify_mid_map *notify_changes_by_mid;
/**************************************************************************** /****************************************************************************
This is the structure to queue to implement NT change This is the structure to queue to implement NT change
@ -33,24 +34,76 @@ static struct cnotify_fns *cnotify;
struct change_notify { struct change_notify {
struct change_notify *next, *prev; struct change_notify *next, *prev;
files_struct *fsp; files_struct *fsp;
connection_struct *conn;
uint32 flags; uint32 flags;
uint32 max_param_count;
char request_buf[smb_size]; char request_buf[smb_size];
void *change_data; void *change_data;
}; };
static struct change_notify *change_notify_list; static struct change_notify *change_notify_list;
static BOOL notify_marshall_changes(unsigned num_changes,
struct notify_change *changes,
prs_struct *ps)
{
int i;
UNISTR uni_name;
for (i=0; i<num_changes; i++) {
struct notify_change *c = &changes[i];
size_t namelen;
uint32 u32_tmp; /* Temp arg to prs_uint32 to avoid
* signed/unsigned issues */
namelen = convert_string_allocate(
NULL, CH_UNIX, CH_UTF16LE, c->name, strlen(c->name)+1,
&uni_name.buffer, True);
if ((namelen == -1) || (uni_name.buffer == NULL)) {
goto fail;
}
namelen -= 2; /* Dump NULL termination */
/*
* Offset to next entry, only if there is one
*/
u32_tmp = (i == num_changes-1) ? 0 : namelen + 12;
if (!prs_uint32("offset", ps, 1, &u32_tmp)) goto fail;
u32_tmp = c->action;
if (!prs_uint32("action", ps, 1, &u32_tmp)) goto fail;
u32_tmp = namelen;
if (!prs_uint32("namelen", ps, 1, &u32_tmp)) goto fail;
if (!prs_unistr("name", ps, 1, &uni_name)) goto fail;
/*
* Not NULL terminated, decrease by the 2 UCS2 \0 chars
*/
prs_set_offset(ps, prs_offset(ps)-2);
SAFE_FREE(uni_name.buffer);
}
return True;
fail:
SAFE_FREE(uni_name.buffer);
return False;
}
/**************************************************************************** /****************************************************************************
Setup the common parts of the return packet and send it. Setup the common parts of the return packet and send it.
*****************************************************************************/ *****************************************************************************/
static void change_notify_reply_packet(char *inbuf, NTSTATUS error_code) void change_notify_reply_packet(const char *request_buf, NTSTATUS error_code)
{ {
char outbuf[smb_size+38]; char outbuf[smb_size+38];
memset(outbuf, '\0', sizeof(outbuf)); memset(outbuf, '\0', sizeof(outbuf));
construct_reply_common(inbuf, outbuf); construct_reply_common(request_buf, outbuf);
ERROR_NT(error_code); ERROR_NT(error_code);
@ -65,6 +118,45 @@ static void change_notify_reply_packet(char *inbuf, NTSTATUS error_code)
exit_server_cleanly("change_notify_reply_packet: send_smb failed."); exit_server_cleanly("change_notify_reply_packet: send_smb failed.");
} }
void change_notify_reply(const char *request_buf, uint32 max_param_count,
unsigned num_changes, struct notify_change *changes)
{
char *outbuf = NULL;
prs_struct ps;
size_t buflen = smb_size+38+max_param_count;
if (!prs_init(&ps, 0, NULL, False)
|| !notify_marshall_changes(num_changes, changes, &ps)) {
change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY);
goto done;
}
if (prs_offset(&ps) > max_param_count) {
/*
* We exceed what the client is willing to accept. Send
* nothing.
*/
change_notify_reply_packet(request_buf, NT_STATUS_OK);
goto done;
}
if (!(outbuf = SMB_MALLOC_ARRAY(char, buflen))) {
change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY);
goto done;
}
construct_reply_common(request_buf, outbuf);
if (send_nt_replies(outbuf, buflen, NT_STATUS_OK, prs_data_p(&ps),
prs_offset(&ps), NULL, 0) == -1) {
exit_server("change_notify_reply_packet: send_smb failed.");
}
done:
SAFE_FREE(outbuf);
prs_mem_free(&ps);
}
/**************************************************************************** /****************************************************************************
Remove an entry from the list and free it, also closing any Remove an entry from the list and free it, also closing any
directory handle if necessary. directory handle if necessary.
@ -78,38 +170,104 @@ static void change_notify_remove(struct change_notify *cnbp)
SAFE_FREE(cnbp); SAFE_FREE(cnbp);
} }
/**************************************************************************** NTSTATUS change_notify_add_request(const char *inbuf, uint32 max_param_count,
Delete entries by fnum from the change notify pending queue. uint32 filter, struct files_struct *fsp)
*****************************************************************************/
void remove_pending_change_notify_requests_by_fid(files_struct *fsp, NTSTATUS status)
{ {
struct change_notify *cnbp, *next; struct notify_change_request *request = NULL;
struct notify_mid_map *map = NULL;
for (cnbp=change_notify_list; cnbp; cnbp=next) { if (!(request = SMB_MALLOC_P(struct notify_change_request))
next=cnbp->next; || !(map = SMB_MALLOC_P(struct notify_mid_map))) {
if (cnbp->fsp->fnum == fsp->fnum) { SAFE_FREE(request);
change_notify_reply_packet(cnbp->request_buf,status); return NT_STATUS_NO_MEMORY;
change_notify_remove(cnbp); }
request->mid_map = map;
map->req = request;
memcpy(request->request_buf, inbuf, sizeof(request->request_buf));
request->max_param_count = max_param_count;
request->filter = filter;
request->fsp = fsp;
DLIST_ADD_END(fsp->notify->requests, request,
struct notify_change_request *);
map->mid = SVAL(inbuf, smb_mid);
DLIST_ADD(notify_changes_by_mid, map);
/* Push the MID of this packet on the signing queue. */
srv_defer_sign_response(SVAL(inbuf,smb_mid));
return NT_STATUS_OK;
}
static void change_notify_remove_request(struct notify_change_request *remove_req)
{
files_struct *fsp;
struct notify_change_request *req;
/*
* Paranoia checks, the fsp referenced must must have the request in
* its list of pending requests
*/
fsp = remove_req->fsp;
SMB_ASSERT(fsp->notify != NULL);
for (req = fsp->notify->requests; req; req = req->next) {
if (req == remove_req) {
break;
} }
} }
if (req == NULL) {
smb_panic("notify_req not found in fsp's requests\n");
}
DLIST_REMOVE(fsp->notify->requests, req);
DLIST_REMOVE(notify_changes_by_mid, req->mid_map);
SAFE_FREE(req->mid_map);
SAFE_FREE(req);
} }
/**************************************************************************** /****************************************************************************
Delete entries by mid from the change notify pending queue. Always send reply. Delete entries by mid from the change notify pending queue. Always send reply.
*****************************************************************************/ *****************************************************************************/
void remove_pending_change_notify_requests_by_mid(int mid) void remove_pending_change_notify_requests_by_mid(uint16 mid)
{ {
struct change_notify *cnbp, *next; struct notify_mid_map *map;
for (cnbp=change_notify_list; cnbp; cnbp=next) { for (map = notify_changes_by_mid; map; map = map->next) {
next=cnbp->next; if (map->mid == mid) {
if(SVAL(cnbp->request_buf,smb_mid) == mid) { break;
change_notify_reply_packet(cnbp->request_buf,NT_STATUS_CANCELLED);
change_notify_remove(cnbp);
} }
} }
if (map == NULL) {
return;
}
change_notify_reply_packet(map->req->request_buf, NT_STATUS_CANCELLED);
change_notify_remove_request(map->req);
}
/****************************************************************************
Delete entries by fnum from the change notify pending queue.
*****************************************************************************/
void remove_pending_change_notify_requests_by_fid(files_struct *fsp,
NTSTATUS status)
{
if (fsp->notify == NULL) {
return;
}
while (fsp->notify->requests != NULL) {
change_notify_reply_packet(
fsp->notify->requests->request_buf, status);
change_notify_remove_request(fsp->notify->requests);
}
} }
/**************************************************************************** /****************************************************************************
@ -128,7 +286,7 @@ void remove_pending_change_notify_requests_by_filename(files_struct *fsp, NTSTAT
* the filename are identical. * the filename are identical.
*/ */
if((cnbp->fsp->conn == fsp->conn) && strequal(cnbp->fsp->fsp_name,fsp->fsp_name)) { if((cnbp->fsp->conn == fsp->conn) && strequal(cnbp->fsp->fsp_name,fsp->fsp_name)) {
change_notify_reply_packet(cnbp->request_buf,status); change_notify_reply_packet(cnbp->request_buf, status);
change_notify_remove(cnbp); change_notify_remove(cnbp);
} }
} }
@ -171,9 +329,27 @@ BOOL process_pending_change_notify_queue(time_t t)
vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(cnbp->request_buf,smb_uid); vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(cnbp->request_buf,smb_uid);
if (cnotify->check_notify(cnbp->conn, vuid, cnbp->fsp->fsp_name, cnbp->flags, cnbp->change_data, t)) { if (cnbp->fsp->notify->num_changes != 0) {
DEBUG(10,("process_pending_change_notify_queue: dir %s changed !\n", cnbp->fsp->fsp_name )); DEBUG(10,("process_pending_change_notify_queue: %s "
change_notify_reply_packet(cnbp->request_buf,STATUS_NOTIFY_ENUM_DIR); "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); change_notify_remove(cnbp);
} }
} }
@ -188,22 +364,24 @@ BOOL process_pending_change_notify_queue(time_t t)
error. error.
****************************************************************************/ ****************************************************************************/
BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn, uint32 flags) BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn,
uint32 flags, uint32 max_param_count)
{ {
struct change_notify *cnbp; struct change_notify *cnbp;
if((cnbp = SMB_MALLOC_P(struct change_notify)) == NULL) { if((cnbp = SMB_MALLOC_P(struct change_notify)) == NULL) {
DEBUG(0,("change_notify_set: malloc fail !\n" )); DEBUG(0,("change_notify_set: malloc fail !\n" ));
return -1; return False;
} }
ZERO_STRUCTP(cnbp); ZERO_STRUCTP(cnbp);
memcpy(cnbp->request_buf, inbuf, smb_size); memcpy(cnbp->request_buf, inbuf, smb_size);
cnbp->fsp = fsp; cnbp->fsp = fsp;
cnbp->conn = conn;
cnbp->flags = flags; cnbp->flags = flags;
cnbp->change_data = cnotify->register_notify(conn, fsp->fsp_name, flags); cnbp->max_param_count = max_param_count;
cnbp->change_data = cnotify->register_notify(conn, fsp->fsp_name,
flags);
if (!cnbp->change_data) { if (!cnbp->change_data) {
SAFE_FREE(cnbp); SAFE_FREE(cnbp);
@ -227,6 +405,237 @@ int change_notify_fd(void)
return -1; return -1;
} }
/* notify message definition
Offset Data length.
0 SMB_DEV_T dev 8
8 SMB_INO_T inode 8
16 uint32 filter 4
20 uint32 action 4
24.. name
*/
#define MSG_NOTIFY_MESSAGE_SIZE 25 /* Includes at least the '\0' terminator */
struct notify_message {
SMB_DEV_T dev;
SMB_INO_T inode;
uint32 filter;
uint32 action;
char *name;
};
static DATA_BLOB notify_message_to_buf(const struct notify_message *msg)
{
DATA_BLOB result;
size_t len;
len = strlen(msg->name);
result = data_blob(NULL, MSG_NOTIFY_MESSAGE_SIZE + len);
if (!result.data) {
return result;
}
SDEV_T_VAL(result.data, 0, msg->dev);
SINO_T_VAL(result.data, 8, msg->inode);
SIVAL(result.data, 16, msg->filter);
SIVAL(result.data, 20, msg->action);
memcpy(result.data+24, msg->name, len+1);
return result;
}
static BOOL buf_to_notify_message(void *buf, size_t len,
struct notify_message *msg)
{
if (len < MSG_NOTIFY_MESSAGE_SIZE) {
DEBUG(0, ("Got invalid notify message of len %d\n",
(int)len));
return False;
}
msg->dev = DEV_T_VAL(buf, 0);
msg->inode = INO_T_VAL(buf, 8);
msg->filter = IVAL(buf, 16);
msg->action = IVAL(buf, 20);
msg->name = ((char *)buf)+24;
return True;
}
void notify_action(connection_struct *conn, const char *parent,
const char *name, uint32 filter, uint32_t action)
{
struct share_mode_lock *lck;
SMB_STRUCT_STAT sbuf;
int i;
struct notify_message msg;
DATA_BLOB blob;
struct process_id *pids;
int num_pids;
DEBUG(10, ("notify_action: parent=%s, name=%s, action=%u\n",
parent, name, (unsigned)action));
if (SMB_VFS_STAT(conn, parent, &sbuf) != 0) {
/*
* Not 100% critical, ignore failure
*/
return;
}
if (!(lck = get_share_mode_lock(NULL, sbuf.st_dev, sbuf.st_ino,
NULL, NULL))) {
return;
}
msg.dev = sbuf.st_dev;
msg.inode = sbuf.st_ino;
msg.filter = filter;
msg.action = action;
msg.name = CONST_DISCARD(char *, name);
blob = notify_message_to_buf(&msg);
if (blob.data == NULL) {
DEBUG(0, ("notify_message_to_buf failed\n"));
return;
}
pids = NULL;
num_pids = 0;
become_root_uid_only();
for (i=0; i<lck->num_share_modes; i++) {
struct share_mode_entry *e = &lck->share_modes[i];
int j;
struct process_id *tmp;
for (j=0; j<num_pids; j++) {
if (procid_equal(&e->pid, &pids[j])) {
break;
}
}
if (j < num_pids) {
/*
* Already sent to that process, skip it
*/
continue;
}
message_send_pid(lck->share_modes[i].pid, MSG_SMB_NOTIFY,
blob.data, blob.length, True);
if (!(tmp = TALLOC_REALLOC_ARRAY(lck, pids, struct process_id,
num_pids+1))) {
DEBUG(0, ("realloc failed\n"));
break;
}
pids = tmp;
pids[num_pids] = e->pid;
num_pids += 1;
}
unbecome_root_uid_only();
data_blob_free(&blob);
TALLOC_FREE(lck);
}
void notify_fname(connection_struct *conn, const char *path,
uint32 filter, uint32 action)
{
char *parent;
const char *name;
if (!parent_dirname_talloc(tmp_talloc_ctx(), path, &parent, &name)) {
return;
}
notify_action(conn, parent, name, filter, action);
TALLOC_FREE(parent);
}
static void notify_fsp(files_struct *fsp, struct notify_message *msg)
{
struct notify_change *change, *changes;
if (fsp->notify == NULL) {
/*
* Nobody is waiting, don't queue
*/
return;
}
if ((fsp->notify->requests != NULL)
&& (fsp->notify->requests->filter & msg->filter)) {
/*
* Someone is waiting for the change, trigger the reply
* immediately.
*
* TODO: do we have to walk the lists of requests pending?
*/
struct notify_change_request *req = fsp->notify->requests;
struct notify_change onechange;
onechange.action = msg->action;
onechange.name = msg->name;
change_notify_reply(req->request_buf, req->max_param_count,
1, &onechange);
change_notify_remove_request(req);
return;
}
/*
* Someone has triggered a notify previously, queue the change for
* later. TODO: Limit the number of changes queued, test how filters
* apply here. Do we have to store them?
*/
if (!(changes = TALLOC_REALLOC_ARRAY(
fsp->notify, fsp->notify->changes,
struct notify_change, fsp->notify->num_changes+1))) {
DEBUG(0, ("talloc_realloc failed\n"));
return;
}
fsp->notify->changes = changes;
change = &(fsp->notify->changes[fsp->notify->num_changes]);
if (!(change->name = talloc_strdup(changes, msg->name))) {
DEBUG(0, ("talloc_strdup failed\n"));
return;
}
change->action = msg->action;
fsp->notify->num_changes += 1;
return;
}
static void notify_message_callback(int msgtype, struct process_id pid,
void *buf, size_t len)
{
struct notify_message msg;
files_struct *fsp;
if (!buf_to_notify_message(buf, len, &msg)) {
return;
}
DEBUG(10, ("Received notify_message for 0x%x/%.0f: %d\n",
(unsigned)msg.dev, (double)msg.inode, msg.action));
for(fsp = fsp_find_di_first(msg.dev, msg.inode); fsp;
fsp = fsp_find_di_next(fsp)) {
notify_fsp(fsp, &msg);
}
}
/**************************************************************************** /****************************************************************************
Initialise the change notify subsystem. Initialise the change notify subsystem.
****************************************************************************/ ****************************************************************************/
@ -250,5 +659,7 @@ BOOL init_change_notify(void)
return False; return False;
} }
message_register(MSG_SMB_NOTIFY, notify_message_callback);
return True; return True;
} }

View File

@ -1800,14 +1800,15 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf,
{ {
uint16 *setup = *ppsetup; uint16 *setup = *ppsetup;
files_struct *fsp; files_struct *fsp;
uint32 flags; uint32 filter;
NTSTATUS status;
if(setup_count < 6) { if(setup_count < 6) {
return ERROR_DOS(ERRDOS,ERRbadfunc); return ERROR_DOS(ERRDOS,ERRbadfunc);
} }
fsp = file_fsp((char *)setup,4); fsp = file_fsp((char *)setup,4);
flags = IVAL(setup, 0); filter = IVAL(setup, 0);
DEBUG(3,("call_nt_transact_notify_change\n")); DEBUG(3,("call_nt_transact_notify_change\n"));
@ -1815,16 +1816,56 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf,
return ERROR_DOS(ERRDOS,ERRbadfid); return ERROR_DOS(ERRDOS,ERRbadfid);
} }
DEBUG(3,("call_nt_transact_notify_change: notify change called on "
"directory name = %s\n", fsp->fsp_name ));
if((!fsp->is_directory) || (conn != fsp->conn)) { if((!fsp->is_directory) || (conn != fsp->conn)) {
return ERROR_DOS(ERRDOS,ERRbadfid); return ERROR_DOS(ERRDOS,ERRbadfid);
} }
if (!change_notify_set(inbuf, fsp, conn, flags)) { if (fsp->notify == NULL) {
return(UNIXERROR(ERRDOS,ERRbadfid)); if (!(fsp->notify = TALLOC_ZERO_P(
NULL, struct notify_change_buf))) {
return ERROR_NT(NT_STATUS_NO_MEMORY);
}
} }
DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \ if (fsp->notify->num_changes > 0) {
name = %s\n", fsp->fsp_name ));
/*
* We've got changes pending, respond immediately
*/
/*
* TODO: write a torture test to check the filtering behaviour
* here.
*/
SMB_ASSERT(fsp->notify->requests == NULL);
change_notify_reply(inbuf, max_param_count,
fsp->notify->num_changes,
fsp->notify->changes);
TALLOC_FREE(fsp->notify->changes);
fsp->notify->num_changes = 0;
/*
* change_notify_reply() above has independently sent its
* results
*/
return -1;
}
/*
* No changes pending, queue the request
*/
status = change_notify_add_request(inbuf, max_param_count, filter,
fsp);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
return -1; return -1;
} }

View File

@ -309,6 +309,8 @@ static NTSTATUS open_file(files_struct *fsp,
fsp); fsp);
} }
notify_action(conn, parent_dir, name, -1,
NOTIFY_ACTION_ADDED);
} }
} else { } else {
@ -1945,6 +1947,9 @@ static NTSTATUS mkdir_internal(connection_struct *conn, const char *name,
change_dir_owner_to_parent(conn, parent_dir, name, psbuf); change_dir_owner_to_parent(conn, parent_dir, name, psbuf);
} }
notify_action(conn, parent_dir, dirname, FILE_NOTIFY_CHANGE_DIR_NAME,
NOTIFY_ACTION_ADDED);
return NT_STATUS_OK; return NT_STATUS_OK;
} }

View File

@ -1857,6 +1857,8 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
if (SMB_VFS_UNLINK(conn,directory) == 0) { if (SMB_VFS_UNLINK(conn,directory) == 0) {
count++; count++;
notify_fname(conn, directory, -1,
NOTIFY_ACTION_REMOVED);
} }
} else { } else {
struct smb_Dir *dir_hnd = NULL; struct smb_Dir *dir_hnd = NULL;
@ -1913,9 +1915,14 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_IS_OK(status)) {
continue; continue;
} }
if (SMB_VFS_UNLINK(conn,fname) == 0) if (SMB_VFS_UNLINK(conn,fname) == 0) {
count++; count++;
DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname)); DEBUG(3,("unlink_internals: succesful unlink "
"[%s]\n",fname));
notify_action(conn, directory, dname,
-1, NOTIFY_ACTION_REMOVED);
}
} }
CloseDir(dir_hnd); CloseDir(dir_hnd);
} }
@ -3779,6 +3786,18 @@ BOOL rmdir_internals(connection_struct *conn, const char *directory)
return False; return False;
} }
{
char *parent_dir;
const char *dirname;
if (parent_dirname_talloc(tmp_talloc_ctx(), directory,
&parent_dir, &dirname)) {
notify_action(conn, parent_dir, dirname, -1,
NOTIFY_ACTION_REMOVED);
TALLOC_FREE(parent_dir); /* Not strictly necessary */
}
}
return True; return True;
} }