1a90cf9f2SGordon Ross /* 2a90cf9f2SGordon Ross * CDDL HEADER START 3a90cf9f2SGordon Ross * 4a90cf9f2SGordon Ross * The contents of this file are subject to the terms of the 5a90cf9f2SGordon Ross * Common Development and Distribution License (the "License"). 6a90cf9f2SGordon Ross * You may not use this file except in compliance with the License. 7a90cf9f2SGordon Ross * 8a90cf9f2SGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9a90cf9f2SGordon Ross * or http://www.opensolaris.org/os/licensing. 10a90cf9f2SGordon Ross * See the License for the specific language governing permissions 11a90cf9f2SGordon Ross * and limitations under the License. 12a90cf9f2SGordon Ross * 13a90cf9f2SGordon Ross * When distributing Covered Code, include this CDDL HEADER in each 14a90cf9f2SGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15a90cf9f2SGordon Ross * If applicable, add the following below this CDDL HEADER, with the 16a90cf9f2SGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying 17a90cf9f2SGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner] 18a90cf9f2SGordon Ross * 19a90cf9f2SGordon Ross * CDDL HEADER END 20a90cf9f2SGordon Ross */ 21a90cf9f2SGordon Ross 22a90cf9f2SGordon Ross /* 23a90cf9f2SGordon Ross * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 244b69ad09SGordon Ross * Copyright 2020 Tintri by DDN, Inc. All rights reserved. 256cd18732SGordon Ross * Copyright 2022 RackTop Systems, Inc. 26a90cf9f2SGordon Ross */ 27a90cf9f2SGordon Ross 28a90cf9f2SGordon Ross /* 29a90cf9f2SGordon Ross * File Change Notification (FCN) 30a90cf9f2SGordon Ross * Common parts shared by SMB1 & SMB2 31a90cf9f2SGordon Ross */ 32a90cf9f2SGordon Ross 33a90cf9f2SGordon Ross /* 34a90cf9f2SGordon Ross * This command notifies the client when the specified directory 35a90cf9f2SGordon Ross * has changed, and optionally returns the names of files and 36a90cf9f2SGordon Ross * directories that changed, and how they changed. The caller 37a90cf9f2SGordon Ross * specifies a "Completion Filter" to select which kinds of 38a90cf9f2SGordon Ross * changes they want to know about. 39a90cf9f2SGordon Ross * 40a90cf9f2SGordon Ross * When a change that's in the CompletionFilter is made to the directory, 41a90cf9f2SGordon Ross * the command completes. The names of the files that have changed since 42a90cf9f2SGordon Ross * the last time the command was issued are returned to the client. 43a90cf9f2SGordon Ross * If too many files have changed since the last time the command was 44a90cf9f2SGordon Ross * issued, then zero bytes are returned and an alternate status code 45a90cf9f2SGordon Ross * is returned in the Status field of the response. 46a90cf9f2SGordon Ross * 47a90cf9f2SGordon Ross * The CompletionFilter is a mask created as the sum of any of the 48a90cf9f2SGordon Ross * following flags: 49a90cf9f2SGordon Ross * 50a90cf9f2SGordon Ross * FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 51a90cf9f2SGordon Ross * FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 52a90cf9f2SGordon Ross * FILE_NOTIFY_CHANGE_NAME 0x00000003 53a90cf9f2SGordon Ross * FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004 54a90cf9f2SGordon Ross * FILE_NOTIFY_CHANGE_SIZE 0x00000008 55a90cf9f2SGordon Ross * FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010 56a90cf9f2SGordon Ross * FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020 57a90cf9f2SGordon Ross * FILE_NOTIFY_CHANGE_CREATION 0x00000040 58a90cf9f2SGordon Ross * FILE_NOTIFY_CHANGE_EA 0x00000080 59a90cf9f2SGordon Ross * FILE_NOTIFY_CHANGE_SECURITY 0x00000100 60a90cf9f2SGordon Ross * FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200 61a90cf9f2SGordon Ross * FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400 62a90cf9f2SGordon Ross * FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800 63a90cf9f2SGordon Ross * 64a90cf9f2SGordon Ross * 65a90cf9f2SGordon Ross * The response contains FILE_NOTIFY_INFORMATION structures, as defined 66a90cf9f2SGordon Ross * below. The NextEntryOffset field of the structure specifies the offset, 67a90cf9f2SGordon Ross * in bytes, from the start of the current entry to the next entry in the 68a90cf9f2SGordon Ross * list. If this is the last entry in the list, this field is zero. Each 69a90cf9f2SGordon Ross * entry in the list must be longword aligned, so NextEntryOffset must be a 70a90cf9f2SGordon Ross * multiple of four. 71a90cf9f2SGordon Ross * 72a90cf9f2SGordon Ross * typedef struct { 73a90cf9f2SGordon Ross * ULONG NextEntryOffset; 74a90cf9f2SGordon Ross * ULONG Action; 75a90cf9f2SGordon Ross * ULONG FileNameLength; 76a90cf9f2SGordon Ross * WCHAR FileName[1]; 77a90cf9f2SGordon Ross * } FILE_NOTIFY_INFORMATION; 78a90cf9f2SGordon Ross * 79a90cf9f2SGordon Ross * Where Action describes what happened to the file named FileName: 80a90cf9f2SGordon Ross * 81a90cf9f2SGordon Ross * FILE_ACTION_ADDED 0x00000001 82a90cf9f2SGordon Ross * FILE_ACTION_REMOVED 0x00000002 83a90cf9f2SGordon Ross * FILE_ACTION_MODIFIED 0x00000003 84a90cf9f2SGordon Ross * FILE_ACTION_RENAMED_OLD_NAME 0x00000004 85a90cf9f2SGordon Ross * FILE_ACTION_RENAMED_NEW_NAME 0x00000005 86a90cf9f2SGordon Ross * FILE_ACTION_ADDED_STREAM 0x00000006 87a90cf9f2SGordon Ross * FILE_ACTION_REMOVED_STREAM 0x00000007 88a90cf9f2SGordon Ross * FILE_ACTION_MODIFIED_STREAM 0x00000008 89bfe5e737SGordon Ross * 90bfe5e737SGordon Ross * The internal interface between SMB1 and/or SMB2 protocol handlers 91bfe5e737SGordon Ross * and this module has some sophistication to allow for: 92bfe5e737SGordon Ross * (1) code sharing between SMB1 and SMB2(+) 93bfe5e737SGordon Ross * (2) efficient handling of non-blocking scenarios 94bfe5e737SGordon Ross * (3) long blocking calls without tying up a thread 95bfe5e737SGordon Ross * 96bfe5e737SGordon Ross * The interface has three calls (like a three act play) 97bfe5e737SGordon Ross * 98bfe5e737SGordon Ross * smb_notify_act1: 99bfe5e737SGordon Ross * Validate parameters, setup ofile buffer. 100bfe5e737SGordon Ross * If data already available, return it, all done. 101bfe5e737SGordon Ross * (In the "all done" case, skip act2 & act3.) 102bfe5e737SGordon Ross * If no data available, return a special error 103bfe5e737SGordon Ross * ("STATUS_PENDING") to tell the caller they must 104bfe5e737SGordon Ross * proceed with calls to act2 & act3. 105bfe5e737SGordon Ross * 106bfe5e737SGordon Ross * smb_notify_act2: 107bfe5e737SGordon Ross * Arrange wakeup after event delivery or cancellation. 108bfe5e737SGordon Ross * Return leaving the SR with no worker thread. 109bfe5e737SGordon Ross * 110bfe5e737SGordon Ross * smb_notify_act3: 111bfe5e737SGordon Ross * New taskq work thread runs this after the wakeup 112bfe5e737SGordon Ross * or cancellation arranged in act2 happens. This 113bfe5e737SGordon Ross * returns the notification data and retires the SR. 114bfe5e737SGordon Ross * 115bfe5e737SGordon Ross * In the SMB2 notify handler, we call act1 during the initial 116bfe5e737SGordon Ross * synchronous handling of the request. If that returns anything 117bfe5e737SGordon Ross * other than STATUS_PENDING, that request is fully complete. 118bfe5e737SGordon Ross * If act1 returns STATUS_PENDING, SMB2 calls act2 as it's 119bfe5e737SGordon Ross * "go async" handler, which arranges to call act3 later. 120bfe5e737SGordon Ross * 121bfe5e737SGordon Ross * In the SMB1 notify handler there is not separate sync. & async 122bfe5e737SGordon Ross * handler so act1 and (if necessary) act2 are both called during 123bfe5e737SGordon Ross * the initial handling of the request. 124bfe5e737SGordon Ross * 125bfe5e737SGordon Ross * About notify event buffering: 126bfe5e737SGordon Ross * 127bfe5e737SGordon Ross * An important (and poorly documented) feature of SMB notify is 128bfe5e737SGordon Ross * that once a notify call has happened on a given directory handle, 129bfe5e737SGordon Ross * the system CONTINUES to post events to the notify event buffer 130bfe5e737SGordon Ross * for the handle, even when SMB notify calls are NOT running. 131bfe5e737SGordon Ross * When the client next comes back with a notify call, we return 132bfe5e737SGordon Ross * any events that were posted while they were "away". This is 133bfe5e737SGordon Ross * how clients track directory changes without missing events. 134bfe5e737SGordon Ross * 135bfe5e737SGordon Ross * About simultaneous notify calls: 136bfe5e737SGordon Ross * 137bfe5e737SGordon Ross * Note that SMB "notify" calls are destructive to events, much like 138bfe5e737SGordon Ross * reading data from a pipe. It therefore makes little sense to 139bfe5e737SGordon Ross * allow multiple simultaneous callers. However, we permit it 140bfe5e737SGordon Ross * (like Windows does) as follows: When multiple notify calls 141bfe5e737SGordon Ross * are waiting for events, the next event wakes them all, and 142bfe5e737SGordon Ross * only the last one out clears the event buffer. They all get 143bfe5e737SGordon Ross * whatever events are pending at the time they woke up. 144bfe5e737SGordon Ross * 145bfe5e737SGordon Ross * About NT_STATUS_NOTIFY_ENUM_DIR 146bfe5e737SGordon Ross * 147bfe5e737SGordon Ross * One more caution about NT_STATUS_NOTIFY_ENUM_DIR: Some clients 148bfe5e737SGordon Ross * are stupid about re-reading the directory almost continuously when 149bfe5e737SGordon Ross * there are changes happening in the directory. We want to bound 150bfe5e737SGordon Ross * the rate of such directory re-reading, so before returning an 151bfe5e737SGordon Ross * NT_STATUS_NOTIFY_ENUM_DIR, we delay just a little. The length 152bfe5e737SGordon Ross * of the delay can be adjusted via smb_notify_enum_dir_delay, 153bfe5e737SGordon Ross * though it's not expected that should need to be changed. 154a90cf9f2SGordon Ross */ 155a90cf9f2SGordon Ross 156a90cf9f2SGordon Ross #include <smbsrv/smb_kproto.h> 157a90cf9f2SGordon Ross #include <sys/sdt.h> 158a90cf9f2SGordon Ross 159bfe5e737SGordon Ross /* 160bfe5e737SGordon Ross * Length of the short delay we impose before returning 161bfe5e737SGordon Ross * NT_STATUS_NOTIFY_ENUM_DIR (See above) 162bfe5e737SGordon Ross */ 163bfe5e737SGordon Ross int smb_notify_enum_dir_delay = 100; /* mSec. */ 164bfe5e737SGordon Ross 165bfe5e737SGordon Ross static uint32_t smb_notify_get_events(smb_request_t *); 166bfe5e737SGordon Ross static void smb_notify_cancel(smb_request_t *); 167bfe5e737SGordon Ross static void smb_notify_wakeup(smb_request_t *); 168bfe5e737SGordon Ross static void smb_notify_dispatch2(smb_request_t *); 169bfe5e737SGordon Ross static void smb_notify_encode_action(smb_ofile_t *, 170bfe5e737SGordon Ross uint32_t, const char *); 171bfe5e737SGordon Ross 172a90cf9f2SGordon Ross 1735677e049SGordon Ross /* 174bfe5e737SGordon Ross * smb_notify_act1() 1755677e049SGordon Ross * 176bfe5e737SGordon Ross * Check for events and consume, non-blocking. 177bfe5e737SGordon Ross * Special return STATUS_PENDING means: 178bfe5e737SGordon Ross * No events; caller must call "act2" next. 179bfe5e737SGordon Ross * 180bfe5e737SGordon Ross * See overall design notes, top of file. 1815677e049SGordon Ross */ 182a90cf9f2SGordon Ross uint32_t 183bfe5e737SGordon Ross smb_notify_act1(smb_request_t *sr, uint32_t buflen, uint32_t filter) 184a90cf9f2SGordon Ross { 185bfe5e737SGordon Ross smb_ofile_t *of; 186a90cf9f2SGordon Ross smb_node_t *node; 187bfe5e737SGordon Ross smb_notify_t *nc; 188a90cf9f2SGordon Ross uint32_t status; 189a90cf9f2SGordon Ross 190a90cf9f2SGordon Ross /* 191bfe5e737SGordon Ross * Validate parameters 192a90cf9f2SGordon Ross */ 193bfe5e737SGordon Ross if ((of = sr->fid_ofile) == NULL) 194bfe5e737SGordon Ross return (NT_STATUS_INVALID_HANDLE); 195bfe5e737SGordon Ross nc = &of->f_notify; 196bfe5e737SGordon Ross node = of->f_node; 197bfe5e737SGordon Ross if (node == NULL || !smb_node_is_dir(node)) { 198bfe5e737SGordon Ross /* Notify change is only valid on directories. */ 199a90cf9f2SGordon Ross return (NT_STATUS_INVALID_PARAMETER); 200a90cf9f2SGordon Ross } 201a90cf9f2SGordon Ross 2026cd18732SGordon Ross if ((of->f_granted_access & FILE_LIST_DIRECTORY) == 0) 2036cd18732SGordon Ross return (NT_STATUS_ACCESS_DENIED); 2046cd18732SGordon Ross 205bfe5e737SGordon Ross mutex_enter(&of->f_mutex); 206a90cf9f2SGordon Ross 207a90cf9f2SGordon Ross /* 2084b69ad09SGordon Ross * It's possible this ofile has started closing, in which case 2094b69ad09SGordon Ross * we must not subscribe it for events etc. 2104b69ad09SGordon Ross */ 2114b69ad09SGordon Ross if (of->f_state != SMB_OFILE_STATE_OPEN) { 2124b69ad09SGordon Ross mutex_exit(&of->f_mutex); 2134b69ad09SGordon Ross return (NT_STATUS_FILE_CLOSED); 2144b69ad09SGordon Ross } 2154b69ad09SGordon Ross 2164b69ad09SGordon Ross /* 217bfe5e737SGordon Ross * On the first FCN call with this ofile, subscribe to 218bfe5e737SGordon Ross * events on the node. The corresponding unsubscribe 219bfe5e737SGordon Ross * happens in smb_ofile_delete(). 220a90cf9f2SGordon Ross */ 221bfe5e737SGordon Ross if (nc->nc_subscribed == B_FALSE) { 222bfe5e737SGordon Ross nc->nc_subscribed = B_TRUE; 223bfe5e737SGordon Ross smb_node_fcn_subscribe(node); 224bfe5e737SGordon Ross /* In case this happened before we subscribed. */ 225bfe5e737SGordon Ross if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 226bfe5e737SGordon Ross nc->nc_events |= FILE_NOTIFY_CHANGE_EV_DELETE; 227bfe5e737SGordon Ross } 228bfe5e737SGordon Ross /* 229bfe5e737SGordon Ross * Windows only lets you set these on the first call, 230bfe5e737SGordon Ross * so we may as well do the same. 231bfe5e737SGordon Ross */ 232bfe5e737SGordon Ross nc->nc_buffer.max_bytes = buflen; 233bfe5e737SGordon Ross nc->nc_filter = filter; 234bfe5e737SGordon Ross } 235bfe5e737SGordon Ross /* 236bfe5e737SGordon Ross * If we already have events, consume them. 237bfe5e737SGordon Ross */ 238bfe5e737SGordon Ross sr->raw_data.max_bytes = buflen; 239bfe5e737SGordon Ross if (nc->nc_events != 0) { 240bfe5e737SGordon Ross status = smb_notify_get_events(sr); 241bfe5e737SGordon Ross } else { 242bfe5e737SGordon Ross /* Caller will come back for act2 */ 243bfe5e737SGordon Ross status = NT_STATUS_PENDING; 244bfe5e737SGordon Ross } 245bfe5e737SGordon Ross 246bfe5e737SGordon Ross mutex_exit(&of->f_mutex); 247a90cf9f2SGordon Ross 248a90cf9f2SGordon Ross /* 249bfe5e737SGordon Ross * See: About NT_STATUS_NOTIFY_ENUM_DIR (above) 250bfe5e737SGordon Ross */ 251bfe5e737SGordon Ross if (status == NT_STATUS_NOTIFY_ENUM_DIR && 252bfe5e737SGordon Ross smb_notify_enum_dir_delay > 0) 253bfe5e737SGordon Ross delay(MSEC_TO_TICK(smb_notify_enum_dir_delay)); 254bfe5e737SGordon Ross 255bfe5e737SGordon Ross return (status); 256bfe5e737SGordon Ross } 257bfe5e737SGordon Ross 258bfe5e737SGordon Ross /* 259bfe5e737SGordon Ross * smb_notify_act2() 260bfe5e737SGordon Ross * 261bfe5e737SGordon Ross * Prepare to wait for events after act1 found that none were pending. 262bfe5e737SGordon Ross * Assume the wait may be for a very long time. (hours, days...) 263bfe5e737SGordon Ross * Special return STATUS_PENDING means the SR will later be 264bfe5e737SGordon Ross * scheduled again on a new worker thread, and this thread 265bfe5e737SGordon Ross * MUST NOT touch it any longer (return SDRC_SR_KEPT). 266bfe5e737SGordon Ross * 267bfe5e737SGordon Ross * See overall design notes, top of file. 268bfe5e737SGordon Ross */ 269bfe5e737SGordon Ross uint32_t 270bfe5e737SGordon Ross smb_notify_act2(smb_request_t *sr) 271bfe5e737SGordon Ross { 272bfe5e737SGordon Ross smb_ofile_t *of; 273bfe5e737SGordon Ross smb_notify_t *nc; 274bfe5e737SGordon Ross uint32_t status; 275bfe5e737SGordon Ross 276bfe5e737SGordon Ross /* 277bfe5e737SGordon Ross * Sanity checks. 278bfe5e737SGordon Ross */ 279bfe5e737SGordon Ross if ((of = sr->fid_ofile) == NULL) 280bfe5e737SGordon Ross return (NT_STATUS_INVALID_HANDLE); 281bfe5e737SGordon Ross nc = &of->f_notify; 282bfe5e737SGordon Ross 283bfe5e737SGordon Ross mutex_enter(&of->f_mutex); 284bfe5e737SGordon Ross 285bfe5e737SGordon Ross /* 286bfe5e737SGordon Ross * Prepare for a potentially long wait for events. 287bfe5e737SGordon Ross * Normally transition from ACTIVE to WAITING_FCN1. 288bfe5e737SGordon Ross * 289bfe5e737SGordon Ross * Note we hold both of->f_mutex, sr->sr_mutex here, 290bfe5e737SGordon Ross * taken in that order. 291a90cf9f2SGordon Ross */ 292a90cf9f2SGordon Ross mutex_enter(&sr->sr_mutex); 293bfe5e737SGordon Ross switch (sr->sr_state) { 294bfe5e737SGordon Ross case SMB_REQ_STATE_ACTIVE: 295bfe5e737SGordon Ross /* 296bfe5e737SGordon Ross * This sr has no worker thread until smb_notify_act3 297bfe5e737SGordon Ross * or smb_notify_cancel (later, via taskq_dispatch). 298bfe5e737SGordon Ross */ 299bfe5e737SGordon Ross sr->sr_state = SMB_REQ_STATE_WAITING_FCN1; 3005677e049SGordon Ross sr->cancel_method = smb_notify_cancel; 301bfe5e737SGordon Ross sr->sr_worker = NULL; 302bfe5e737SGordon Ross list_insert_tail(&nc->nc_waiters, sr); 303bfe5e737SGordon Ross status = NT_STATUS_PENDING; 304bfe5e737SGordon Ross break; 305bfe5e737SGordon Ross 306bfe5e737SGordon Ross case SMB_REQ_STATE_CANCELLED: 307bfe5e737SGordon Ross status = NT_STATUS_CANCELLED; 308bfe5e737SGordon Ross break; 309bfe5e737SGordon Ross default: 310bfe5e737SGordon Ross status = NT_STATUS_INTERNAL_ERROR; 311bfe5e737SGordon Ross break; 3125677e049SGordon Ross } 313bfe5e737SGordon Ross mutex_exit(&sr->sr_mutex); 314bfe5e737SGordon Ross 315bfe5e737SGordon Ross /* 316bfe5e737SGordon Ross * In case we missed any events before setting 317bfe5e737SGordon Ross * state FCN1, schedule our own wakeup. 318bfe5e737SGordon Ross */ 319bfe5e737SGordon Ross if (status == NT_STATUS_PENDING && nc->nc_events != 0) { 320bfe5e737SGordon Ross smb_notify_wakeup(sr); 321a90cf9f2SGordon Ross } 322bfe5e737SGordon Ross 323bfe5e737SGordon Ross mutex_exit(&of->f_mutex); 324bfe5e737SGordon Ross 325bfe5e737SGordon Ross /* Note: Never NT_STATUS_NOTIFY_ENUM_DIR here. */ 326bfe5e737SGordon Ross ASSERT(status != NT_STATUS_NOTIFY_ENUM_DIR); 327bfe5e737SGordon Ross 328bfe5e737SGordon Ross return (status); 329bfe5e737SGordon Ross } 330bfe5e737SGordon Ross 331bfe5e737SGordon Ross /* 332bfe5e737SGordon Ross * smb_notify_act3() 333bfe5e737SGordon Ross * 334bfe5e737SGordon Ross * This runs via the 2nd taskq_dispatch call, after we've either 335bfe5e737SGordon Ross * seen a change notify event, or the request has been cancelled. 336bfe5e737SGordon Ross * Complete it here. This returns to SMB1 or SMB2 code to send 337bfe5e737SGordon Ross * the response and free the request. 338bfe5e737SGordon Ross * 339bfe5e737SGordon Ross * See overall design notes, top of file. 340bfe5e737SGordon Ross */ 341bfe5e737SGordon Ross uint32_t 342bfe5e737SGordon Ross smb_notify_act3(smb_request_t *sr) 343bfe5e737SGordon Ross { 344bfe5e737SGordon Ross smb_ofile_t *of; 345bfe5e737SGordon Ross smb_notify_t *nc; 346bfe5e737SGordon Ross uint32_t status; 347bfe5e737SGordon Ross 348bfe5e737SGordon Ross of = sr->fid_ofile; 349bfe5e737SGordon Ross ASSERT(of != NULL); 350bfe5e737SGordon Ross nc = &of->f_notify; 351bfe5e737SGordon Ross 352bfe5e737SGordon Ross mutex_enter(&of->f_mutex); 353bfe5e737SGordon Ross 354bfe5e737SGordon Ross mutex_enter(&sr->sr_mutex); 355bfe5e737SGordon Ross ASSERT3P(sr->sr_worker, ==, NULL); 356bfe5e737SGordon Ross sr->sr_worker = curthread; 3575677e049SGordon Ross sr->cancel_method = NULL; 3585677e049SGordon Ross 359bfe5e737SGordon Ross list_remove(&nc->nc_waiters, sr); 360bfe5e737SGordon Ross 3615677e049SGordon Ross switch (sr->sr_state) { 362bfe5e737SGordon Ross case SMB_REQ_STATE_WAITING_FCN2: 363bfe5e737SGordon Ross /* 364bfe5e737SGordon Ross * Got smb_notify_wakeup. 365bfe5e737SGordon Ross */ 366a90cf9f2SGordon Ross sr->sr_state = SMB_REQ_STATE_ACTIVE; 3675677e049SGordon Ross status = 0; 3685677e049SGordon Ross break; 3695677e049SGordon Ross 3705677e049SGordon Ross case SMB_REQ_STATE_CANCEL_PENDING: 371bfe5e737SGordon Ross /* 372bfe5e737SGordon Ross * Got smb_notify_cancel 373bfe5e737SGordon Ross */ 3745677e049SGordon Ross sr->sr_state = SMB_REQ_STATE_CANCELLED; 3755677e049SGordon Ross status = NT_STATUS_CANCELLED; 3765677e049SGordon Ross break; 3775677e049SGordon Ross default: 3785677e049SGordon Ross status = NT_STATUS_INTERNAL_ERROR; 3795677e049SGordon Ross break; 3805677e049SGordon Ross } 381a90cf9f2SGordon Ross mutex_exit(&sr->sr_mutex); 382a90cf9f2SGordon Ross 383bfe5e737SGordon Ross if (status == 0) 384bfe5e737SGordon Ross status = smb_notify_get_events(sr); 385bfe5e737SGordon Ross 386bfe5e737SGordon Ross mutex_exit(&of->f_mutex); 387a90cf9f2SGordon Ross 388a90cf9f2SGordon Ross /* 389bfe5e737SGordon Ross * See: About NT_STATUS_NOTIFY_ENUM_DIR (above) 390a90cf9f2SGordon Ross */ 391bfe5e737SGordon Ross if (status == NT_STATUS_NOTIFY_ENUM_DIR && 392bfe5e737SGordon Ross smb_notify_enum_dir_delay > 0) 393bfe5e737SGordon Ross delay(MSEC_TO_TICK(smb_notify_enum_dir_delay)); 394a90cf9f2SGordon Ross 395bfe5e737SGordon Ross return (status); 396a90cf9f2SGordon Ross } 397a90cf9f2SGordon Ross 398bfe5e737SGordon Ross static uint32_t 399bfe5e737SGordon Ross smb_notify_get_events(smb_request_t *sr) 400bfe5e737SGordon Ross { 401bfe5e737SGordon Ross smb_ofile_t *of; 402bfe5e737SGordon Ross smb_notify_t *nc; 403bfe5e737SGordon Ross uint32_t status; 404bfe5e737SGordon Ross int len; 405bfe5e737SGordon Ross 406bfe5e737SGordon Ross of = sr->fid_ofile; 407bfe5e737SGordon Ross ASSERT(of != NULL); 408bfe5e737SGordon Ross ASSERT(MUTEX_HELD(&of->f_mutex)); 409bfe5e737SGordon Ross nc = &of->f_notify; 410bfe5e737SGordon Ross 411bfe5e737SGordon Ross DTRACE_PROBE2(notify__get__events, 412a5a9a6bbSGordon Ross smb_request_t *, sr, 413bfe5e737SGordon Ross uint32_t, nc->nc_events); 414bfe5e737SGordon Ross 415bfe5e737SGordon Ross /* 416bfe5e737SGordon Ross * Special events which override other events 417bfe5e737SGordon Ross */ 418bfe5e737SGordon Ross if (nc->nc_events & FILE_NOTIFY_CHANGE_EV_CLOSED) { 419bfe5e737SGordon Ross status = NT_STATUS_NOTIFY_CLEANUP; 420bfe5e737SGordon Ross goto out; 421bfe5e737SGordon Ross } 422bfe5e737SGordon Ross if (nc->nc_events & FILE_NOTIFY_CHANGE_EV_DELETE) { 423bfe5e737SGordon Ross status = NT_STATUS_DELETE_PENDING; 424bfe5e737SGordon Ross goto out; 425bfe5e737SGordon Ross } 426bfe5e737SGordon Ross if (nc->nc_events & FILE_NOTIFY_CHANGE_EV_SUBDIR) { 427bfe5e737SGordon Ross status = NT_STATUS_NOTIFY_ENUM_DIR; 428bfe5e737SGordon Ross goto out; 429bfe5e737SGordon Ross } 430bfe5e737SGordon Ross if (nc->nc_events & FILE_NOTIFY_CHANGE_EV_OVERFLOW) { 431bfe5e737SGordon Ross status = NT_STATUS_NOTIFY_ENUM_DIR; 432bfe5e737SGordon Ross goto out; 433bfe5e737SGordon Ross } 434bfe5e737SGordon Ross 435bfe5e737SGordon Ross /* 436bfe5e737SGordon Ross * Normal events (FILE_NOTIFY_VALID_MASK) 437bfe5e737SGordon Ross * 438bfe5e737SGordon Ross * At this point there should be some, or else 439bfe5e737SGordon Ross * some sort of bug woke us up for nothing. 440bfe5e737SGordon Ross */ 441bfe5e737SGordon Ross if ((nc->nc_events & FILE_NOTIFY_VALID_MASK) == 0) { 442bfe5e737SGordon Ross status = NT_STATUS_INTERNAL_ERROR; 443bfe5e737SGordon Ross goto out; 444bfe5e737SGordon Ross } 445bfe5e737SGordon Ross 446bfe5e737SGordon Ross /* 447bfe5e737SGordon Ross * Many Windows clients call change notify with a 448bfe5e737SGordon Ross * zero-length buffer, expecting all events to be 449bfe5e737SGordon Ross * reported as _ENUM_DIR. Testing max_bytes here 450bfe5e737SGordon Ross * because ROOM_FOR check below says "yes" if both 451bfe5e737SGordon Ross * max_bytes and the amount we ask for are zero. 452bfe5e737SGordon Ross */ 453bfe5e737SGordon Ross if (nc->nc_buffer.max_bytes <= 0) { 454bfe5e737SGordon Ross status = NT_STATUS_NOTIFY_ENUM_DIR; 455bfe5e737SGordon Ross goto out; 456bfe5e737SGordon Ross } 457bfe5e737SGordon Ross 458bfe5e737SGordon Ross /* 459bfe5e737SGordon Ross * Client gave us a non-zero output buffer, and 460bfe5e737SGordon Ross * there was no overflow event (checked above) 461bfe5e737SGordon Ross * so there should be some event data. 462bfe5e737SGordon Ross */ 463bfe5e737SGordon Ross if ((len = nc->nc_buffer.chain_offset) <= 0) { 464bfe5e737SGordon Ross status = NT_STATUS_INTERNAL_ERROR; 465bfe5e737SGordon Ross goto out; 466bfe5e737SGordon Ross } 467bfe5e737SGordon Ross 468bfe5e737SGordon Ross /* 469bfe5e737SGordon Ross * If the current SR has a smaller output buffer 470bfe5e737SGordon Ross * then what was setup by some previous notify, 471bfe5e737SGordon Ross * we could have more data than will fit. 472bfe5e737SGordon Ross */ 473bfe5e737SGordon Ross if (!MBC_ROOM_FOR(&sr->raw_data, len)) { 474bfe5e737SGordon Ross /* Would overflow caller's buffer. */ 475bfe5e737SGordon Ross status = NT_STATUS_NOTIFY_ENUM_DIR; 476bfe5e737SGordon Ross goto out; 477bfe5e737SGordon Ross } 478bfe5e737SGordon Ross 479bfe5e737SGordon Ross /* 480bfe5e737SGordon Ross * Copy the event data to sr->raw_data. In the copy, 481bfe5e737SGordon Ross * zap the NextEntryOffset in the last entry, and 482bfe5e737SGordon Ross * trim any extra bytes at the tail. 483bfe5e737SGordon Ross */ 484bfe5e737SGordon Ross (void) smb_mbc_copy(&sr->raw_data, &nc->nc_buffer, 0, len); 485bfe5e737SGordon Ross (void) smb_mbc_poke(&sr->raw_data, nc->nc_last_off, "l", 0); 486bfe5e737SGordon Ross smb_mbuf_trim(sr->raw_data.chain, len); 487bfe5e737SGordon Ross status = 0; 488bfe5e737SGordon Ross 489a90cf9f2SGordon Ross out: 490bfe5e737SGordon Ross /* 491bfe5e737SGordon Ross * If there are no other SRs waiting on this ofile, 492bfe5e737SGordon Ross * mark all events consumed, except for those that 493bfe5e737SGordon Ross * remain until the ofile is closed. That means 494bfe5e737SGordon Ross * clear all bits EXCEPT: _EV_CLOSED, _EV_DELETE 495bfe5e737SGordon Ross * 496bfe5e737SGordon Ross * If there are other waiters (rare) all will get 497bfe5e737SGordon Ross * the currently pending events, and then the 498bfe5e737SGordon Ross * the last one out will clear the events. 499bfe5e737SGordon Ross */ 500bfe5e737SGordon Ross if (list_is_empty(&nc->nc_waiters)) { 501bfe5e737SGordon Ross nc->nc_buffer.chain_offset = 0; 502bfe5e737SGordon Ross nc->nc_events &= (FILE_NOTIFY_CHANGE_EV_CLOSED | 503bfe5e737SGordon Ross FILE_NOTIFY_CHANGE_EV_DELETE); 504bfe5e737SGordon Ross } 505bfe5e737SGordon Ross 506a90cf9f2SGordon Ross return (status); 507a90cf9f2SGordon Ross } 508a90cf9f2SGordon Ross 509a90cf9f2SGordon Ross /* 510bfe5e737SGordon Ross * Called by common code after a transition from 511bfe5e737SGordon Ross * state WAITING_FCN1 to state CANCEL_PENDING. 512a90cf9f2SGordon Ross */ 513bfe5e737SGordon Ross static void 514bfe5e737SGordon Ross smb_notify_cancel(smb_request_t *sr) 515a90cf9f2SGordon Ross { 516bfe5e737SGordon Ross ASSERT3U(sr->sr_state, ==, SMB_REQ_STATE_CANCEL_PENDING); 517bfe5e737SGordon Ross smb_notify_dispatch2(sr); 518a90cf9f2SGordon Ross } 519a90cf9f2SGordon Ross 520a90cf9f2SGordon Ross /* 521bfe5e737SGordon Ross * Called after ofile event delivery to take a waiting smb request 522bfe5e737SGordon Ross * from state FCN1 to state FCN2. This may be called many times 523bfe5e737SGordon Ross * (as events are delivered) but it must (exactly once) schedule 524bfe5e737SGordon Ross * the taskq job to run smb_notify_act3(). Only the event that 525bfe5e737SGordon Ross * takes us from state FCN1 to FCN2 schedules the taskq job. 526a90cf9f2SGordon Ross */ 527bfe5e737SGordon Ross static void 528bfe5e737SGordon Ross smb_notify_wakeup(smb_request_t *sr) 529a90cf9f2SGordon Ross { 530bfe5e737SGordon Ross boolean_t do_disp = B_FALSE; 531a90cf9f2SGordon Ross 532a90cf9f2SGordon Ross SMB_REQ_VALID(sr); 533a90cf9f2SGordon Ross 534bfe5e737SGordon Ross mutex_enter(&sr->sr_mutex); 535bfe5e737SGordon Ross if (sr->sr_state == SMB_REQ_STATE_WAITING_FCN1) { 536bfe5e737SGordon Ross sr->sr_state = SMB_REQ_STATE_WAITING_FCN2; 537bfe5e737SGordon Ross do_disp = B_TRUE; 538a90cf9f2SGordon Ross } 539bfe5e737SGordon Ross mutex_exit(&sr->sr_mutex); 540a90cf9f2SGordon Ross 541bfe5e737SGordon Ross if (do_disp) { 542bfe5e737SGordon Ross smb_notify_dispatch2(sr); 543bfe5e737SGordon Ross } 544bfe5e737SGordon Ross } 545a90cf9f2SGordon Ross 546a90cf9f2SGordon Ross /* 547bfe5e737SGordon Ross * smb_notify_dispatch2() 548bfe5e737SGordon Ross * Schedule a 2nd taskq call to finish up a change notify request; 549bfe5e737SGordon Ross * (smb_notify_act3) either completing it or cancelling it. 550a90cf9f2SGordon Ross */ 551bfe5e737SGordon Ross static void 552bfe5e737SGordon Ross smb_notify_dispatch2(smb_request_t *sr) 553a90cf9f2SGordon Ross { 554bfe5e737SGordon Ross void (*tq_func)(void *); 555*9788d6deSGordon Ross taskqid_t tqid; 556a90cf9f2SGordon Ross 557bfe5e737SGordon Ross /* 558bfe5e737SGordon Ross * Both of these call smb_notify_act3(), returning 559bfe5e737SGordon Ross * to version-specific code to send the response. 560bfe5e737SGordon Ross */ 561bfe5e737SGordon Ross if (sr->session->dialect >= SMB_VERS_2_BASE) 562bfe5e737SGordon Ross tq_func = smb2_change_notify_finish; 563bfe5e737SGordon Ross else 564bfe5e737SGordon Ross tq_func = smb_nt_transact_notify_finish; 565a90cf9f2SGordon Ross 566*9788d6deSGordon Ross tqid = taskq_dispatch(sr->sr_server->sv_worker_pool, 567bfe5e737SGordon Ross tq_func, sr, TQ_SLEEP); 568*9788d6deSGordon Ross VERIFY(tqid != TASKQID_INVALID); 569a90cf9f2SGordon Ross } 570a90cf9f2SGordon Ross 571a90cf9f2SGordon Ross 572a90cf9f2SGordon Ross /* 573a90cf9f2SGordon Ross * What completion filter (masks) apply to each of the 574a90cf9f2SGordon Ross * FILE_ACTION_... events. 575a90cf9f2SGordon Ross */ 576a90cf9f2SGordon Ross static const uint32_t 577a90cf9f2SGordon Ross smb_notify_action_mask[] = { 578a90cf9f2SGordon Ross 0, /* not used */ 579a90cf9f2SGordon Ross 580a90cf9f2SGordon Ross /* FILE_ACTION_ADDED */ 581a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_NAME | 582a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_LAST_WRITE, 583a90cf9f2SGordon Ross 584a90cf9f2SGordon Ross /* FILE_ACTION_REMOVED */ 585a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_NAME | 586a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_LAST_WRITE, 587a90cf9f2SGordon Ross 588a90cf9f2SGordon Ross /* FILE_ACTION_MODIFIED */ 589a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_ATTRIBUTES | 590a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_SIZE | 591a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_LAST_WRITE | 592a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_LAST_ACCESS | 593a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_CREATION | 594a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_EA | 595a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_SECURITY, 596a90cf9f2SGordon Ross 597a90cf9f2SGordon Ross /* FILE_ACTION_RENAMED_OLD_NAME */ 598a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_NAME | 599a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_LAST_WRITE, 600a90cf9f2SGordon Ross 601a90cf9f2SGordon Ross /* FILE_ACTION_RENAMED_NEW_NAME */ 602a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_NAME | 603a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_LAST_WRITE, 604a90cf9f2SGordon Ross 605a90cf9f2SGordon Ross /* FILE_ACTION_ADDED_STREAM */ 606a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_STREAM_NAME, 607a90cf9f2SGordon Ross 608a90cf9f2SGordon Ross /* FILE_ACTION_REMOVED_STREAM */ 609a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_STREAM_NAME, 610a90cf9f2SGordon Ross 611a90cf9f2SGordon Ross /* FILE_ACTION_MODIFIED_STREAM */ 612a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_STREAM_SIZE | 613a90cf9f2SGordon Ross FILE_NOTIFY_CHANGE_STREAM_WRITE, 614a90cf9f2SGordon Ross 615a90cf9f2SGordon Ross /* FILE_ACTION_SUBDIR_CHANGED */ 616bfe5e737SGordon Ross FILE_NOTIFY_CHANGE_EV_SUBDIR, 617a90cf9f2SGordon Ross 618a90cf9f2SGordon Ross /* FILE_ACTION_DELETE_PENDING */ 619bfe5e737SGordon Ross FILE_NOTIFY_CHANGE_EV_DELETE, 620bfe5e737SGordon Ross 621bfe5e737SGordon Ross /* FILE_ACTION_HANDLE_CLOSED */ 622bfe5e737SGordon Ross FILE_NOTIFY_CHANGE_EV_CLOSED, 623a90cf9f2SGordon Ross }; 624a90cf9f2SGordon Ross static const int smb_notify_action_nelm = 625a90cf9f2SGordon Ross sizeof (smb_notify_action_mask) / 626a90cf9f2SGordon Ross sizeof (smb_notify_action_mask[0]); 627a90cf9f2SGordon Ross 628a90cf9f2SGordon Ross /* 629bfe5e737SGordon Ross * smb_notify_ofile 630a90cf9f2SGordon Ross * 631bfe5e737SGordon Ross * Post an event to the change notify buffer for this ofile, 632bfe5e737SGordon Ross * subject to the mask that selects subscribed event types. 633bfe5e737SGordon Ross * If an SR is waiting for events and we've delivered some, 634bfe5e737SGordon Ross * wake the SR. 635bfe5e737SGordon Ross */ 636bfe5e737SGordon Ross void 637bfe5e737SGordon Ross smb_notify_ofile(smb_ofile_t *of, uint_t action, const char *name) 638bfe5e737SGordon Ross { 639bfe5e737SGordon Ross smb_notify_t *nc; 640bfe5e737SGordon Ross smb_request_t *sr; 641bfe5e737SGordon Ross uint32_t filter, events; 642bfe5e737SGordon Ross 643bfe5e737SGordon Ross SMB_OFILE_VALID(of); 644bfe5e737SGordon Ross 645bfe5e737SGordon Ross mutex_enter(&of->f_mutex); 646bfe5e737SGordon Ross nc = &of->f_notify; 647bfe5e737SGordon Ross 648bfe5e737SGordon Ross /* 649bfe5e737SGordon Ross * Compute the filter & event bits for this action, 650bfe5e737SGordon Ross * which determine whether we'll post the event. 651bfe5e737SGordon Ross * Note: always sensitive to: delete, closed. 652bfe5e737SGordon Ross */ 653bfe5e737SGordon Ross filter = nc->nc_filter | 654bfe5e737SGordon Ross FILE_NOTIFY_CHANGE_EV_DELETE | 655bfe5e737SGordon Ross FILE_NOTIFY_CHANGE_EV_CLOSED; 656bfe5e737SGordon Ross VERIFY(action < smb_notify_action_nelm); 657bfe5e737SGordon Ross events = smb_notify_action_mask[action]; 658bfe5e737SGordon Ross if ((filter & events) == 0) 659bfe5e737SGordon Ross goto unlock_out; 660bfe5e737SGordon Ross 661bfe5e737SGordon Ross /* 662bfe5e737SGordon Ross * OK, we're going to post this event. 663bfe5e737SGordon Ross */ 664bfe5e737SGordon Ross switch (action) { 665bfe5e737SGordon Ross case FILE_ACTION_ADDED: 666bfe5e737SGordon Ross case FILE_ACTION_REMOVED: 667bfe5e737SGordon Ross case FILE_ACTION_MODIFIED: 668bfe5e737SGordon Ross case FILE_ACTION_RENAMED_OLD_NAME: 669bfe5e737SGordon Ross case FILE_ACTION_RENAMED_NEW_NAME: 670bfe5e737SGordon Ross case FILE_ACTION_ADDED_STREAM: 671bfe5e737SGordon Ross case FILE_ACTION_REMOVED_STREAM: 672bfe5e737SGordon Ross case FILE_ACTION_MODIFIED_STREAM: 673bfe5e737SGordon Ross /* 674bfe5e737SGordon Ross * Append this event to the buffer. 675bfe5e737SGordon Ross * Also keep track of events seen. 676bfe5e737SGordon Ross */ 677bfe5e737SGordon Ross smb_notify_encode_action(of, action, name); 678bfe5e737SGordon Ross nc->nc_events |= events; 679bfe5e737SGordon Ross break; 680bfe5e737SGordon Ross 681bfe5e737SGordon Ross case FILE_ACTION_SUBDIR_CHANGED: 682bfe5e737SGordon Ross case FILE_ACTION_DELETE_PENDING: 683bfe5e737SGordon Ross case FILE_ACTION_HANDLE_CLOSED: 684bfe5e737SGordon Ross /* 685bfe5e737SGordon Ross * These are "internal" events, and therefore 686bfe5e737SGordon Ross * are not appended to the response buffer. 687bfe5e737SGordon Ross * Just record the event flags and wakeup. 688bfe5e737SGordon Ross */ 689bfe5e737SGordon Ross nc->nc_events |= events; 690bfe5e737SGordon Ross break; 691bfe5e737SGordon Ross 692bfe5e737SGordon Ross default: 693bfe5e737SGordon Ross ASSERT(0); /* bogus action */ 694bfe5e737SGordon Ross break; 695bfe5e737SGordon Ross } 696bfe5e737SGordon Ross 697bfe5e737SGordon Ross sr = list_head(&nc->nc_waiters); 698bfe5e737SGordon Ross while (sr != NULL) { 699bfe5e737SGordon Ross smb_notify_wakeup(sr); 700bfe5e737SGordon Ross sr = list_next(&nc->nc_waiters, sr); 701bfe5e737SGordon Ross } 702bfe5e737SGordon Ross 703bfe5e737SGordon Ross unlock_out: 704bfe5e737SGordon Ross mutex_exit(&of->f_mutex); 705bfe5e737SGordon Ross } 706bfe5e737SGordon Ross 707bfe5e737SGordon Ross /* 708bfe5e737SGordon Ross * Encode a FILE_NOTIFY_INFORMATION struct. 709a90cf9f2SGordon Ross */ 710a90cf9f2SGordon Ross static void 711bfe5e737SGordon Ross smb_notify_encode_action(smb_ofile_t *of, 712bfe5e737SGordon Ross uint32_t action, const char *fname) 713a90cf9f2SGordon Ross { 714bfe5e737SGordon Ross smb_notify_t *nc = &of->f_notify; 715bfe5e737SGordon Ross mbuf_chain_t *mbc; 716bfe5e737SGordon Ross uint32_t namelen, totlen; 717a90cf9f2SGordon Ross 718bfe5e737SGordon Ross ASSERT(nc != NULL); 719bfe5e737SGordon Ross ASSERT(FILE_ACTION_ADDED <= action && 720bfe5e737SGordon Ross action <= FILE_ACTION_MODIFIED_STREAM); 721bfe5e737SGordon Ross ASSERT(fname != NULL); 722bfe5e737SGordon Ross ASSERT(MUTEX_HELD(&of->f_mutex)); 723bfe5e737SGordon Ross 724bfe5e737SGordon Ross /* Once we've run out of room, stop trying to append. */ 725bfe5e737SGordon Ross if ((nc->nc_events & FILE_NOTIFY_CHANGE_EV_OVERFLOW) != 0) 726bfe5e737SGordon Ross return; 727bfe5e737SGordon Ross 728bfe5e737SGordon Ross if (fname == NULL) 729bfe5e737SGordon Ross return; 730bfe5e737SGordon Ross namelen = smb_wcequiv_strlen(fname); 731bfe5e737SGordon Ross if (namelen == 0) 732bfe5e737SGordon Ross return; 733a90cf9f2SGordon Ross 734a90cf9f2SGordon Ross /* 735bfe5e737SGordon Ross * Layout is: 3 DWORDS, Unicode string, pad(4). 736a90cf9f2SGordon Ross */ 737bfe5e737SGordon Ross mbc = &nc->nc_buffer; 738bfe5e737SGordon Ross totlen = (12 + namelen + 3) & ~3; 739bfe5e737SGordon Ross if (MBC_ROOM_FOR(mbc, totlen) == 0) { 740bfe5e737SGordon Ross nc->nc_events |= FILE_NOTIFY_CHANGE_EV_OVERFLOW; 741bfe5e737SGordon Ross return; 742a90cf9f2SGordon Ross } 743bfe5e737SGordon Ross 744bfe5e737SGordon Ross /* 745bfe5e737SGordon Ross * Keep track of where this entry starts (nc_last_off) 746bfe5e737SGordon Ross * because after we put all entries, we need to zap 747bfe5e737SGordon Ross * the NextEntryOffset field in the last one. 748bfe5e737SGordon Ross */ 749bfe5e737SGordon Ross nc->nc_last_off = mbc->chain_offset; 750bfe5e737SGordon Ross 751bfe5e737SGordon Ross /* 752bfe5e737SGordon Ross * Encode this entry, then 4-byte alignment padding. 753bfe5e737SGordon Ross * 754bfe5e737SGordon Ross * Note that smb_mbc_encodef with a "U" code puts a 755bfe5e737SGordon Ross * Unicode string with a null termination. We don't 756bfe5e737SGordon Ross * want a null, but do want alignment padding. We 757bfe5e737SGordon Ross * get that by encoding with "U.." at the end of the 758bfe5e737SGordon Ross * encoding string, which gets us two bytes for the 759bfe5e737SGordon Ross * Unicode NULL, and two more zeros for the "..". 760bfe5e737SGordon Ross * We then "back up" the chain_offset (finger) so it's 761bfe5e737SGordon Ross * correctly 4-byte aligned. We will sometimes have 762bfe5e737SGordon Ross * written a couple more bytes than needed, but we'll 763bfe5e737SGordon Ross * just overwrite those with the next entry. At the 764bfe5e737SGordon Ross * end, we trim the mbuf chain to the correct length. 765bfe5e737SGordon Ross */ 766bfe5e737SGordon Ross (void) smb_mbc_encodef(mbc, "lllU..", 767bfe5e737SGordon Ross totlen, /* NextEntryOffset */ 768bfe5e737SGordon Ross action, namelen, fname); 769bfe5e737SGordon Ross mbc->chain_offset = nc->nc_last_off + totlen; 770a90cf9f2SGordon Ross } 771