smb_nt_transact_notify_change.c revision 7f667e74610492ddbce8ce60f52ece95d2401949
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* File Change Notification (FCN)
*/
/*
* SMB: nt_transact_notify_change
*
* Client Setup Words Description
* ================================== =================================
*
* ULONG CompletionFilter; Specifies operation to monitor
* USHORT Fid; Fid of directory to monitor
* BOOLEAN WatchTree; TRUE = watch all subdirectories too
* UCHAR Reserved; MBZ
*
* This command notifies the client when the directory specified by Fid is
* modified. It also returns the name(s) of the file(s) that changed. The
* command completes once the directory has been modified based on the
* supplied CompletionFilter. The command is a "single shot" and therefore
* needs to be reissued to watch for more directory changes.
*
* A directory file must be opened before this command may be used. Once
* the directory is open, this command may be used to begin watching files
* and subdirectories in the specified directory for changes. The first
* time the command is issued, the MaxParameterCount field in the transact
* header determines the size of the buffer that will be used at the server
* to buffer directory change information between issuances of the notify
* change commands.
*
* When a change that is in the CompletionFilter is made to the directory,
* the command completes. The names of the files that have changed since
* the last time the command was issued are returned to the client. The
* ParameterCount field of the response indicates the number of bytes that
* are being returned. If too many files have changed since the last time
* the command was issued, then zero bytes are returned and an alternate
* status code is returned in the Status field of the response.
*
* The CompletionFilter is a mask created as the sum of any of the
* following flags:
*
* FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
* FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
* FILE_NOTIFY_CHANGE_NAME 0x00000003
* FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
* FILE_NOTIFY_CHANGE_SIZE 0x00000008
* FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
* FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020
* FILE_NOTIFY_CHANGE_CREATION 0x00000040
* FILE_NOTIFY_CHANGE_EA 0x00000080
* FILE_NOTIFY_CHANGE_SECURITY 0x00000100
* FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
* FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
* FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
*
* Server Response Description
* ================================== ================================
* ParameterCount # of bytes of change data
* Parameters[ ParameterCount ] FILE_NOTIFY_INFORMATION
* structures
*
* The response contains FILE_NOTIFY_INFORMATION structures, as defined
* below. The NextEntryOffset field of the structure specifies the offset,
* in bytes, from the start of the current entry to the next entry in the
* list. If this is the last entry in the list, this field is zero. Each
* entry in the list must be longword aligned, so NextEntryOffset must be a
* multiple of four.
*
* typedef struct {
* ULONG NextEntryOffset;
* ULONG Action;
* ULONG FileNameLength;
* WCHAR FileName[1];
* } FILE_NOTIFY_INFORMATION;
*
* Where Action describes what happened to the file named FileName:
*
* FILE_ACTION_ADDED 0x00000001
* FILE_ACTION_REMOVED 0x00000002
* FILE_ACTION_MODIFIED 0x00000003
* FILE_ACTION_RENAMED_OLD_NAME 0x00000004
* FILE_ACTION_RENAMED_NEW_NAME 0x00000005
* FILE_ACTION_ADDED_STREAM 0x00000006
* FILE_ACTION_REMOVED_STREAM 0x00000007
* FILE_ACTION_MODIFIED_STREAM 0x00000008
*/
#include <smbsrv/smb_incl.h>
static void smb_notify_change_daemon(smb_thread_t *, void *);
static smb_slist_t smb_ncr_list;
static smb_slist_t smb_nce_list;
static smb_thread_t smb_thread_notify_daemon;
/*
* smb_notify_init
*
* This function is not multi-thread safe. The caller must make sure only one
* thread makes the call.
*/
int
smb_notify_init(void)
{
int rc;
return (0);
if (rc) {
return (rc);
}
return (0);
}
/*
* smb_notify_fini
*
* This function is not multi-thread safe. The caller must make sure only one
* thread makes the call.
*/
void
smb_notify_fini(void)
{
if (!smb_notify_initialized)
return;
}
/*
* smb_nt_transact_notify_change
*
* This function is responsible for processing NOTIFY CHANGE requests.
* Requests are stored in a global queue. This queue is processed when
* a monitored directory is changed or client cancels one of its already
* sent requests.
*/
{
unsigned char WatchTree;
return (SDRC_NOT_IMPLEMENTED);
return (SDRC_ERROR);
}
/*
* Notify change requests are only valid on directories.
*/
return (SDRC_ERROR);
}
case SMB_REQ_STATE_ACTIVE:
node->waiting_event++;
if (WatchTree)
/*
* Monitor events system-wide.
*
* XXX: smb_node_ref() and smb_node_release()
* take &node->n_lock. May need alternate forms
* of these routines if node->n_lock is taken
* around calls to smb_fem_fcn_install() and
* smb_fem_fcn_uninstall().
*/
return (SDRC_SR_KEPT);
} else {
/* node already changed, reply immediately */
if (--node->waiting_event == 0)
return (SDRC_SUCCESS);
}
case SMB_REQ_STATE_CANCELED:
return (SDRC_ERROR);
default:
ASSERT(0);
return (SDRC_SUCCESS);
}
}
/*
* smb_reply_notify_change_request
*
* This function sends appropriate response to an already queued NOTIFY CHANGE
* request. If node is changed (reply == NODE_FLAGS_CHANGED), a normal reply is
* sent.
* If client cancels the request or session dropped, an NT_STATUS_CANCELED
* is sent in reply.
*/
void
{
if (--node->waiting_event == 0) {
}
/* many things changed */
/* setup the NT transact reply */
/* Pad to 4 bytes */
/* Param off from hdr */
"b3.llllllllbCw#.C#.C",
n_param, /* Total Parameter Bytes */
n_data, /* Total Data Bytes */
n_param, /* Total Parameter Bytes this buffer */
param_off, /* Param offset from header start */
0, /* Param displacement */
n_data, /* Total Data Bytes this buffer */
data_off, /* Data offset from header start */
0, /* Data displacement */
n_setup, /* suwcnt */
total_bytes, /* Total data bytes */
&xa->rep_param_mb,
&xa->rep_data_mb);
break;
case SMB_REQ_STATE_CANCELED:
(short)0, 0L, (short)0, 0L);
break;
default:
ASSERT(0);
}
/* Setup the header */
/* send the reply */
}
/*
* smb_process_session_notify_change_queue
*
* This function traverses notify change request queue and sends
* cancel replies to all of requests that are related to a specific
* session.
*/
void
{
while (sr) {
sr);
break;
default:
ASSERT(0);
break;
}
}
}
if (sig)
}
/*
* smb_process_file_notify_change_queue
*
* This function traverses notify change request queue and sends
* cancel replies to all of requests that are related to the
* specified file.
*/
void
{
while (sr) {
&smb_ncr_list, sr);
break;
default:
ASSERT(0);
break;
}
}
}
if (sig)
}
/*
* smb_reply_specific_cancel_request
*
* This function searches global request list for a specific request. If found,
* moves the request to event queue and kicks the notify change daemon.
*/
void
{
while (sr) {
&smb_ncr_list, sr);
break;
default:
ASSERT(0);
break;
}
}
}
if (sig)
}
/*
* smb_process_node_notify_change_queue
*
* This function searches notify change request queue and sends
* 'NODE MODIFIED' reply to all requests which are related to a
* specific node.
* WatchTree flag: We handle this flag in a special manner just
* for DAVE clients. When something is changed, we notify all
* requests which came from DAVE clients on the same volume which
* has been modified. We don't care about the tree that they wanted
* us to monitor. any change in any part of the volume will lead
* to notifying all notify change requests from DAVE clients on the
* different parts of the volume hierarchy.
*/
void
{
return;
while (sr) {
&smb_ncr_list, sr);
break;
default:
ASSERT(0);
break;
}
}
}
if (sig)
}
/*
* Change notification is required if:
* - the request node matches the specified node
* or
* - the request is from a Mac client, the watch-tree flag
* is set and it is monitoring a tree on the same volume.
*/
static boolean_t
{
return (B_TRUE);
return (B_TRUE);
return (B_FALSE);
}
/*
* smb_notify_change_daemon
*
* This function processes notify change event list and send appropriate
* responses to the requests. This function executes in the system as an
* indivdual thread.
*/
static void
{
while (smb_thread_continue(thread)) {
while (sr) {
}
}
}
}