}
NTSTATUS change_notify_add_request(const char *inbuf, uint32 max_param_count,
- uint32 filter, struct files_struct *fsp)
+ uint32 filter, BOOL recursive,
+ struct files_struct *fsp)
{
struct notify_change_request *request = NULL;
struct notify_mid_map *map = NULL;
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);
+ request->backend_data = NULL;
DLIST_ADD_END(fsp->notify->requests, request,
struct notify_change_request *);
return;
}
+ {
+ char *fullpath;
+
+ if (asprintf(&fullpath, "%s/%s/%s", conn->connectpath,
+ parent, name) != -1) {
+ notify_trigger(conn->notify_ctx, action, filter,
+ fullpath);
+ SAFE_FREE(fullpath);
+ }
+ return;
+ }
+
if (!(lck = get_share_mode_lock(NULL, sbuf.st_dev, sbuf.st_ino,
NULL, NULL))) {
return;
void notify_fname(connection_struct *conn, uint32 action, uint32 filter,
const char *path)
{
- char *parent;
- const char *name;
+ char *fullpath;
- if (!parent_dirname_talloc(tmp_talloc_ctx(), path, &parent, &name)) {
+ if (asprintf(&fullpath, "%s/%s", conn->connectpath, path) == -1) {
+ DEBUG(0, ("asprintf failed\n"));
return;
}
- notify_action(conn, parent, name, filter, action);
- TALLOC_FREE(parent);
+ notify_trigger(conn->notify_ctx, action, filter, fullpath);
+ SAFE_FREE(fullpath);
}
-void notify_fsp(files_struct *fsp, uint32 action, char *name)
+void notify_fsp(files_struct *fsp, uint32 action, const char *name)
{
struct notify_change *change, *changes;
+ char *name2;
if (fsp->notify == NULL) {
/*
return;
}
- if (fsp->notify->requests != NULL) {
- /*
- * 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;
-
- if (name == NULL) {
- /*
- * Catch-all change, possibly from notify_hash.c
- */
- change_notify_reply(req->request_buf,
- req->max_param_count,
- -1, NULL);
+ if (!(name2 = talloc_strdup(fsp->notify, name))) {
+ DEBUG(0, ("talloc_strdup failed\n"));
return;
}
- onechange.action = action;
- onechange.name = name;
-
- change_notify_reply(req->request_buf, req->max_param_count,
- 1, &onechange);
- change_notify_remove_request(req);
- return;
- }
+ string_replace(name2, '/', '\\');
/*
* Someone has triggered a notify previously, queue the change for
* W2k3 seems to store at most 30 changes.
*/
TALLOC_FREE(fsp->notify->changes);
+ TALLOC_FREE(name2);
fsp->notify->num_changes = -1;
return;
}
fsp->notify, fsp->notify->changes,
struct notify_change, fsp->notify->num_changes+1))) {
DEBUG(0, ("talloc_realloc failed\n"));
+ TALLOC_FREE(name2);
return;
}
change = &(fsp->notify->changes[fsp->notify->num_changes]);
- if (!(change->name = talloc_strdup(changes, name))) {
- DEBUG(0, ("talloc_strdup failed\n"));
- return;
- }
+ change->name = talloc_move(changes, &name2);
change->action = action;
fsp->notify->num_changes += 1;
+ if (fsp->notify->requests == NULL) {
+ /*
+ * Nobody is waiting, so don't send anything. The ot
+ */
+ return;
+ }
+
+ if (action == NOTIFY_ACTION_OLD_NAME) {
+ /*
+ * We have to send the two rename events in one reply. So hold
+ * the first part back.
+ */
return;
+ }
+
+ /*
+ * Someone is waiting for the change, trigger the reply immediately.
+ *
+ * TODO: do we have to walk the lists of requests pending?
+ */
+
+ change_notify_reply(fsp->notify->requests->request_buf,
+ fsp->notify->requests->max_param_count,
+ fsp->notify->num_changes,
+ fsp->notify->changes);
+
+ change_notify_remove_request(fsp->notify->requests);
+
+ TALLOC_FREE(fsp->notify->changes);
+ fsp->notify->num_changes = 0;
}
static void notify_message_callback(int msgtype, struct process_id pid,
don't allow a directory to be opened.
****************************************************************************/
+static void notify_callback(void *private_data, const struct notify_event *e)
+{
+ files_struct *fsp = (files_struct *)private_data;
+ DEBUG(10, ("notify_callback called for %s\n", fsp->fsp_name));
+ notify_fsp(fsp, e->action, e->path);
+}
+
static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf,
char *outbuf, int length,
int bufsize,
files_struct *fsp;
uint32 filter;
NTSTATUS status;
+ BOOL recursive;
if(setup_count < 6) {
return ERROR_DOS(ERRDOS,ERRbadfunc);
fsp = file_fsp((char *)setup,4);
filter = IVAL(setup, 0);
+ recursive = (SVAL(setup, 6) != 0) ? True : False;
DEBUG(3,("call_nt_transact_notify_change\n"));
return ERROR_DOS(ERRDOS,ERRbadfid);
}
- DEBUG(3,("call_nt_transact_notify_change: notify change called on "
- "directory name = %s\n", fsp->fsp_name ));
+ {
+ char *filter_string;
+
+ if (!(filter_string = notify_filter_string(NULL, filter))) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ DEBUG(3,("call_nt_transact_notify_change: notify change "
+ "called on %s, filter = %s, recursive = %d\n",
+ fsp->fsp_name, filter_string, recursive));
+
+ TALLOC_FREE(filter_string);
+ }
if((!fsp->is_directory) || (conn != fsp->conn)) {
return ERROR_DOS(ERRDOS,ERRbadfid);
}
if (fsp->notify == NULL) {
+ char *fullpath;
+ struct notify_entry e;
+
if (!(fsp->notify = TALLOC_ZERO_P(
NULL, struct notify_change_buf))) {
return ERROR_NT(NT_STATUS_NO_MEMORY);
}
+
+ if (asprintf(&fullpath, "%s/%s", fsp->conn->connectpath,
+ fsp->fsp_name) == -1) {
+ DEBUG(0, ("asprintf failed\n"));
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ e.path = fullpath;
+ e.filter = filter;
+ e.subdir_filter = 0;
+ if (recursive) {
+ e.subdir_filter = filter;
+ }
+
+ status = notify_add(fsp->conn->notify_ctx, &e, notify_callback,
+ fsp);
+ SAFE_FREE(fullpath);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("notify_add returned %s\n",
+ nt_errstr(status)));
+ return ERROR_NT(status);
+ }
}
if (fsp->notify->num_changes != 0) {
* here.
*/
- SMB_ASSERT(fsp->notify->requests == NULL);
-
change_notify_reply(inbuf, max_param_count,
fsp->notify->num_changes,
fsp->notify->changes);
*/
status = change_notify_add_request(inbuf, max_param_count, filter,
- fsp);
+ recursive, fsp);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}