diff options
Diffstat (limited to 'source3/smbd/notify.c')
-rw-r--r-- | source3/smbd/notify.c | 165 |
1 files changed, 91 insertions, 74 deletions
diff --git a/source3/smbd/notify.c b/source3/smbd/notify.c index d9a28eb698..73e25b7c92 100644 --- a/source3/smbd/notify.c +++ b/source3/smbd/notify.c @@ -24,6 +24,26 @@ #include "smbd/globals.h" #include "../librpc/gen_ndr/ndr_notify.h" +struct notify_change_buf { + /* + * If no requests are pending, changes are queued here. Simple array, + * we only append. + */ + + /* + * num_changes == -1 means that we have got a catch-all change, when + * asked we just return NT_STATUS_OK without specific changes. + */ + int 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; +}; + struct notify_change_request { struct notify_change_request *prev, *next; struct files_struct *fsp; /* backpointer for cancel by mid */ @@ -39,6 +59,23 @@ struct notify_change_request { static void notify_fsp(files_struct *fsp, uint32 action, const char *name); +bool change_notify_fsp_has_changes(struct files_struct *fsp) +{ + if (fsp == NULL) { + return false; + } + + if (fsp->notify == NULL) { + return false; + } + + if (fsp->notify->num_changes == 0) { + return false; + } + + return true; +} + /* * For NTCancel, we need to find the notify_change_request indexed by * mid. Separate list here. @@ -174,41 +211,73 @@ static void notify_callback(void *private_data, const struct notify_event *e) notify_fsp(fsp, e->action, e->path); } +static void sys_notify_callback(struct sys_notify_context *ctx, + void *private_data, + struct notify_event *e) +{ + files_struct *fsp = (files_struct *)private_data; + DEBUG(10, ("sys_notify_callback called for %s\n", fsp_str_dbg(fsp))); + notify_fsp(fsp, e->action, e->path); +} + NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter, bool recursive) { char *fullpath; - struct notify_entry e; - NTSTATUS status; + size_t len; + uint32_t subdir_filter; + NTSTATUS status = NT_STATUS_NOT_IMPLEMENTED; - SMB_ASSERT(fsp->notify == NULL); + if (fsp->notify != NULL) { + DEBUG(1, ("change_notify_create: fsp->notify != NULL, " + "fname = %s\n", fsp->fsp_name->base_name)); + return NT_STATUS_INVALID_PARAMETER; + } - if (!(fsp->notify = TALLOC_ZERO_P(NULL, struct notify_change_buf))) { + if (!(fsp->notify = talloc_zero(NULL, struct notify_change_buf))) { DEBUG(0, ("talloc failed\n")); return NT_STATUS_NO_MEMORY; } /* Do notify operations on the base_name. */ - if (asprintf(&fullpath, "%s/%s", fsp->conn->connectpath, - fsp->fsp_name->base_name) == -1) { - DEBUG(0, ("asprintf failed\n")); + fullpath = talloc_asprintf( + talloc_tos(), "%s/%s", fsp->conn->connectpath, + fsp->fsp_name->base_name); + if (fullpath == NULL) { + DEBUG(0, ("talloc_asprintf failed\n")); TALLOC_FREE(fsp->notify); return NT_STATUS_NO_MEMORY; } - ZERO_STRUCT(e); - e.path = fullpath; - e.dir_fd = fsp->fh->fd; - e.dir_id = fsp->file_id; - e.filter = filter; - e.subdir_filter = 0; - if (recursive) { - e.subdir_filter = filter; + /* + * Avoid /. at the end of the path name. notify can't deal with it. + */ + len = strlen(fullpath); + if (len > 1 && fullpath[len-1] == '.' && fullpath[len-2] == '/') { + fullpath[len-2] = '\0'; } - status = notify_add(fsp->conn->notify_ctx, &e, notify_callback, fsp); - SAFE_FREE(fullpath); + subdir_filter = recursive ? filter : 0; + if (fsp->conn->sconn->sys_notify_ctx != NULL) { + void *sys_notify_handle = NULL; + + status = SMB_VFS_NOTIFY_WATCH( + fsp->conn, fsp->conn->sconn->sys_notify_ctx, + fullpath, &filter, &subdir_filter, + sys_notify_callback, fsp, &sys_notify_handle); + + if (NT_STATUS_IS_OK(status)) { + talloc_steal(fsp->notify, sys_notify_handle); + } + } + + if ((filter != 0) || (subdir_filter != 0)) { + status = notify_add(fsp->conn->sconn->notify_ctx, + fullpath, filter, subdir_filter, + notify_callback, fsp); + } + TALLOC_FREE(fullpath); return status; } @@ -345,60 +414,22 @@ void remove_pending_change_notify_requests_by_fid(files_struct *fsp, } } -static void notify_parent_dir(connection_struct *conn, - uint32 action, uint32 filter, - const char *path) -{ - struct smb_filename smb_fname_parent; - char *parent; - const char *name; - char *oldwd; - - if (!parent_dirname(talloc_tos(), path, &parent, &name)) { - return; - } - - ZERO_STRUCT(smb_fname_parent); - smb_fname_parent.base_name = parent; - - oldwd = vfs_GetWd(parent, conn); - if (oldwd == NULL) { - goto done; - } - if (vfs_ChDir(conn, conn->connectpath) == -1) { - goto done; - } - - if (SMB_VFS_STAT(conn, &smb_fname_parent) == -1) { - goto chdir_done; - } - - notify_onelevel(conn->notify_ctx, action, filter, - SMB_VFS_FILE_ID_CREATE(conn, &smb_fname_parent.st), - name); -chdir_done: - vfs_ChDir(conn, oldwd); -done: - TALLOC_FREE(parent); -} - void notify_fname(connection_struct *conn, uint32 action, uint32 filter, const char *path) { + struct notify_context *notify_ctx = conn->sconn->notify_ctx; char *fullpath; if (path[0] == '.' && path[1] == '/') { path += 2; } - notify_parent_dir(conn, action, filter, path); - fullpath = talloc_asprintf(talloc_tos(), "%s/%s", conn->connectpath, path); if (fullpath == NULL) { DEBUG(0, ("asprintf failed\n")); return; } - notify_trigger(conn->notify_ctx, action, filter, fullpath); + notify_trigger(notify_ctx, action, filter, fullpath); TALLOC_FREE(fullpath); } @@ -448,7 +479,7 @@ static void notify_fsp(files_struct *fsp, uint32 action, const char *name) return; } - if (!(changes = TALLOC_REALLOC_ARRAY( + if (!(changes = talloc_realloc( fsp->notify, fsp->notify->changes, struct notify_change, fsp->notify->num_changes+1))) { DEBUG(0, ("talloc_realloc failed\n")); @@ -538,31 +569,17 @@ char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32 filter) return result; } -struct sys_notify_context *sys_notify_context_create(connection_struct *conn, - TALLOC_CTX *mem_ctx, +struct sys_notify_context *sys_notify_context_create(TALLOC_CTX *mem_ctx, struct event_context *ev) { struct sys_notify_context *ctx; - if (!(ctx = TALLOC_P(mem_ctx, struct sys_notify_context))) { + if (!(ctx = talloc(mem_ctx, struct sys_notify_context))) { DEBUG(0, ("talloc failed\n")); return NULL; } ctx->ev = ev; - ctx->conn = conn; ctx->private_data = NULL; return ctx; } - -NTSTATUS sys_notify_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) -{ - return SMB_VFS_NOTIFY_WATCH(ctx->conn, ctx, e, callback, private_data, - handle); -} - |