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