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