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.c165
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);
-}
-