a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross/*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * CDDL HEADER START
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * The contents of this file are subject to the terms of the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Common Development and Distribution License (the "License").
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * You may not use this file except in compliance with the License.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * or http://www.opensolaris.org/os/licensing.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * See the License for the specific language governing permissions
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * and limitations under the License.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * When distributing Covered Code, include this CDDL HEADER in each
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * If applicable, add the following below this CDDL HEADER, with the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * fields enclosed by brackets "[]" replaced with your own identifying
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * information: Portions Copyright [yyyy] [name of copyright owner]
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * CDDL HEADER END
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross/*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross/*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * File Change Notification (FCN)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Common parts shared by SMB1 & SMB2
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross/*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * This command notifies the client when the specified directory
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * has changed, and optionally returns the names of files and
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * directories that changed, and how they changed. The caller
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * specifies a "Completion Filter" to select which kinds of
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * changes they want to know about.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * When a change that's in the CompletionFilter is made to the directory,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * the command completes. The names of the files that have changed since
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * the last time the command was issued are returned to the client.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * If too many files have changed since the last time the command was
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * issued, then zero bytes are returned and an alternate status code
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * is returned in the Status field of the response.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * The CompletionFilter is a mask created as the sum of any of the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * following flags:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_NOTIFY_CHANGE_NAME 0x00000003
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_NOTIFY_CHANGE_SIZE 0x00000008
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_NOTIFY_CHANGE_CREATION 0x00000040
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_NOTIFY_CHANGE_EA 0x00000080
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_NOTIFY_CHANGE_SECURITY 0x00000100
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * The response contains FILE_NOTIFY_INFORMATION structures, as defined
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * below. The NextEntryOffset field of the structure specifies the offset,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * in bytes, from the start of the current entry to the next entry in the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * list. If this is the last entry in the list, this field is zero. Each
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * entry in the list must be longword aligned, so NextEntryOffset must be a
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * multiple of four.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * typedef struct {
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * ULONG NextEntryOffset;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * ULONG Action;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * ULONG FileNameLength;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * WCHAR FileName[1];
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * } FILE_NOTIFY_INFORMATION;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Where Action describes what happened to the file named FileName:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_ACTION_ADDED 0x00000001
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_ACTION_REMOVED 0x00000002
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_ACTION_MODIFIED 0x00000003
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_ACTION_RENAMED_OLD_NAME 0x00000004
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_ACTION_RENAMED_NEW_NAME 0x00000005
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_ACTION_ADDED_STREAM 0x00000006
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_ACTION_REMOVED_STREAM 0x00000007
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_ACTION_MODIFIED_STREAM 0x00000008
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross#include <smbsrv/smb_kproto.h>
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross#include <sys/sdt.h>
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rossstatic void smb_notify_sr(smb_request_t *, uint_t, const char *);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rossstatic uint32_t smb_notify_encode_action(struct smb_request *,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross mbuf_chain_t *, uint32_t, char *);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rossuint32_t
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rosssmb_notify_common(smb_request_t *sr, mbuf_chain_t *mbc,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross uint32_t CompletionFilter)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross{
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_notify_change_req_t *nc;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_node_t *node;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross uint32_t status;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if (sr->fid_ofile == NULL)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross return (NT_STATUS_INVALID_HANDLE);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross node = sr->fid_ofile->f_node;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if (node == NULL || !smb_node_is_dir(node)) {
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Notify change is only valid on directories.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross return (NT_STATUS_INVALID_PARAMETER);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross }
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Prepare to receive event data.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross nc = &sr->sr_ncr;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross nc->nc_flags = CompletionFilter;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross ASSERT(nc->nc_action == 0);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross ASSERT(nc->nc_fname == NULL);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross nc->nc_fname = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Subscribe to events on this node.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_node_fcn_subscribe(node, sr);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Wait for subscribed events to arrive.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Expect SMB_REQ_STATE_EVENT_OCCURRED
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * or SMB_REQ_STATE_CANCELED when signaled.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Note it's possible (though rare) to already
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * have SMB_REQ_STATE_CANCELED here.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross mutex_enter(&sr->sr_mutex);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if (sr->sr_state == SMB_REQ_STATE_ACTIVE)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross sr->sr_state = SMB_REQ_STATE_WAITING_EVENT;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross while (sr->sr_state == SMB_REQ_STATE_WAITING_EVENT) {
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross cv_wait(&nc->nc_cv, &sr->sr_mutex);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross }
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if (sr->sr_state == SMB_REQ_STATE_EVENT_OCCURRED)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross sr->sr_state = SMB_REQ_STATE_ACTIVE;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross mutex_exit(&sr->sr_mutex);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Unsubscribe from events on this node.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_node_fcn_unsubscribe(node, sr);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Why did we wake up?
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross switch (sr->sr_state) {
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross case SMB_REQ_STATE_ACTIVE:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross break;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross case SMB_REQ_STATE_CANCELED:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross status = NT_STATUS_CANCELLED;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross goto out;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross default:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross status = NT_STATUS_INTERNAL_ERROR;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross goto out;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross }
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * We have SMB_REQ_STATE_ACTIVE.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * If we have event data, marshall it now, else just
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * say "many things changed". Note that when we get
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * action FILE_ACTION_SUBDIR_CHANGED, we don't have
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * any event details and only know that some subdir
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * changed, so just report "many things changed".
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross switch (nc->nc_action) {
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross case FILE_ACTION_ADDED:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross case FILE_ACTION_REMOVED:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross case FILE_ACTION_MODIFIED:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross case FILE_ACTION_RENAMED_OLD_NAME:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross case FILE_ACTION_RENAMED_NEW_NAME:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross case FILE_ACTION_ADDED_STREAM:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross case FILE_ACTION_REMOVED_STREAM:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross case FILE_ACTION_MODIFIED_STREAM:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Build the reply
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross status = smb_notify_encode_action(sr, mbc,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross nc->nc_action, nc->nc_fname);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross break;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross case FILE_ACTION_SUBDIR_CHANGED:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross status = NT_STATUS_NOTIFY_ENUM_DIR;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross break;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross case FILE_ACTION_DELETE_PENDING:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross status = NT_STATUS_DELETE_PENDING;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross break;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross default:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross ASSERT(0);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross status = NT_STATUS_INTERNAL_ERROR;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross break;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross }
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rossout:
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross kmem_free(nc->nc_fname, MAXNAMELEN);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross nc->nc_fname = NULL;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross return (status);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross}
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross/*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Encode a FILE_NOTIFY_INFORMATION struct.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * We only ever put one of these in a response, so this
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * does not bother handling appending additional ones.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rossstatic uint32_t
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rosssmb_notify_encode_action(struct smb_request *sr, mbuf_chain_t *mbc,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross uint32_t action, char *fname)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross{
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross uint32_t namelen;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross ASSERT(FILE_ACTION_ADDED <= action &&
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross action <= FILE_ACTION_MODIFIED_STREAM);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if (fname == NULL)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross return (NT_STATUS_INTERNAL_ERROR);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross namelen = smb_wcequiv_strlen(fname);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if (namelen == 0)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross return (NT_STATUS_INTERNAL_ERROR);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if (smb_mbc_encodef(mbc, "%lllU", sr,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross 0, /* NextEntryOffset */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross action, namelen, fname))
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross return (NT_STATUS_NOTIFY_ENUM_DIR);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross return (0);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross}
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross/*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * smb_notify_file_closed
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Cancel any change-notify calls on this open file.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rossvoid
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rosssmb_notify_file_closed(struct smb_ofile *of)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross{
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_session_t *ses;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_request_t *sr;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_slist_t *list;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross SMB_OFILE_VALID(of);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross ses = of->f_session;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross SMB_SESSION_VALID(ses);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross list = &ses->s_req_list;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_slist_enter(list);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross sr = smb_slist_head(list);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross while (sr) {
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross SMB_REQ_VALID(sr);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if (sr->sr_state == SMB_REQ_STATE_WAITING_EVENT &&
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross sr->fid_ofile == of) {
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_request_cancel(sr);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross }
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross sr = smb_slist_next(list, sr);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross }
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_slist_exit(list);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross}
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross/*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * smb_notify_event
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Post an event to the watchers on a given node.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * This makes one exception for RENAME, where we expect a
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * pair of events for the {old,new} directory element names.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * This only delivers an event for the "new" name.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * The event delivery mechanism does not implement delivery of
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * multiple events for one "NT Notify" call. One could do that,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * but modern clients don't actually use the event data. They
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * set a max. received data size of zero, which means we discard
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * the data and send the special "lots changed" error instead.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Given that, there's not really any point in implementing the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * delivery of multiple events. In fact, we don't even need to
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * implement single event delivery, but do so for completeness,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * for debug convenience, and to be nice to older clients that
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * may actually want some event data instead of the error.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Given that we only deliver a single event for an "NT Notify"
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * caller, we want to deliver the "new" name event. (The "old"
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * name event is less important, even ignored by some clients.)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Since we know these are delivered in pairs, we can simply
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * discard the "old" name event, knowing that the "new" name
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * event will be delivered immediately afterwards.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * So, why do event sources post the "old name" event at all?
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * (1) For debugging, so we see both {old,new} names here.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * (2) If in the future someone decides to implement the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * delivery of both {old,new} events, the changes can be
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * mostly isolated to this file.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rossvoid
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rosssmb_notify_event(smb_node_t *node, uint_t action, const char *name)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross{
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_request_t *sr;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_node_fcn_t *fcn;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross SMB_NODE_VALID(node);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross fcn = &node->n_fcn;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if (action == FILE_ACTION_RENAMED_OLD_NAME)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross return; /* see above */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross mutex_enter(&fcn->fcn_mutex);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross sr = list_head(&fcn->fcn_watchers);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross while (sr) {
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_notify_sr(sr, action, name);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross sr = list_next(&fcn->fcn_watchers, sr);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross }
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross mutex_exit(&fcn->fcn_mutex);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross}
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross/*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * What completion filter (masks) apply to each of the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * FILE_ACTION_... events.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rossstatic const uint32_t
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rosssmb_notify_action_mask[] = {
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross 0, /* not used */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* FILE_ACTION_ADDED */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_NAME |
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_LAST_WRITE,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* FILE_ACTION_REMOVED */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_NAME |
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_LAST_WRITE,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* FILE_ACTION_MODIFIED */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_ATTRIBUTES |
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_SIZE |
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_LAST_WRITE |
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_LAST_ACCESS |
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_CREATION |
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_EA |
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_SECURITY,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* FILE_ACTION_RENAMED_OLD_NAME */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_NAME |
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_LAST_WRITE,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* FILE_ACTION_RENAMED_NEW_NAME */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_NAME |
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_LAST_WRITE,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* FILE_ACTION_ADDED_STREAM */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_STREAM_NAME,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* FILE_ACTION_REMOVED_STREAM */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_STREAM_NAME,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* FILE_ACTION_MODIFIED_STREAM */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_STREAM_SIZE |
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_CHANGE_STREAM_WRITE,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* FILE_ACTION_SUBDIR_CHANGED */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross NODE_FLAGS_WATCH_TREE,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /* FILE_ACTION_DELETE_PENDING */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross NODE_FLAGS_WATCH_TREE |
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross FILE_NOTIFY_VALID_MASK,
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross};
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rossstatic const int smb_notify_action_nelm =
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross sizeof (smb_notify_action_mask) /
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross sizeof (smb_notify_action_mask[0]);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross/*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * smb_notify_sr
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Post an event to an smb request waiting on some node.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross *
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Note that node->fcn.mutex is held. This implies a
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * lock order: node->fcn.mutex, then sr_mutex
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rossstatic void
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Rosssmb_notify_sr(smb_request_t *sr, uint_t action, const char *name)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross{
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross smb_notify_change_req_t *ncr;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross uint32_t mask;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross SMB_REQ_VALID(sr);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross ncr = &sr->sr_ncr;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Compute the completion filter mask bits for which
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * we will signal waiting notify requests.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross VERIFY(action < smb_notify_action_nelm);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross mask = smb_notify_action_mask[action];
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross mutex_enter(&sr->sr_mutex);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if (sr->sr_state == SMB_REQ_STATE_WAITING_EVENT &&
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross (ncr->nc_flags & mask) != 0) {
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross sr->sr_state = SMB_REQ_STATE_EVENT_OCCURRED;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross /*
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * Save event data in the sr_ncr field so the
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross * reply handler can return it.
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross */
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross ncr->nc_action = action;
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross if (name != NULL)
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross (void) strlcpy(ncr->nc_fname, name, MAXNAMELEN);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross cv_signal(&ncr->nc_cv);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross }
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross mutex_exit(&sr->sr_mutex);
a90cf9f29973990687fa61de9f1f6ea22e924e40Gordon Ross}