1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. 14 * Copyright 2022 RackTop Systems, Inc. 15 */ 16 17 /* 18 * Dispatch function for SMB2_QUERY_INFO 19 * 20 * [MS-FSCC 2.4] If a file system does not support ... 21 * an Information Classs, NT_STATUS_INVALID_PARAMETER... 22 */ 23 24 #include <smbsrv/smb2_kproto.h> 25 #include <smbsrv/smb_fsops.h> 26 #include <smbsrv/ntifs.h> 27 28 static uint32_t smb2_qif_all(smb_request_t *, smb_queryinfo_t *); 29 static uint32_t smb2_qif_basic(smb_request_t *, smb_queryinfo_t *); 30 static uint32_t smb2_qif_standard(smb_request_t *, smb_queryinfo_t *); 31 static uint32_t smb2_qif_internal(smb_request_t *, smb_queryinfo_t *); 32 static uint32_t smb2_qif_ea_size(smb_request_t *, smb_queryinfo_t *); 33 static uint32_t smb2_qif_access(smb_request_t *, smb_queryinfo_t *); 34 static uint32_t smb2_qif_name(smb_request_t *, smb_queryinfo_t *); 35 static uint32_t smb2_qif_normalized_name(smb_request_t *, smb_queryinfo_t *); 36 static uint32_t smb2_qif_position(smb_request_t *, smb_queryinfo_t *); 37 static uint32_t smb2_qif_full_ea(smb_request_t *, smb_queryinfo_t *); 38 static uint32_t smb2_qif_mode(smb_request_t *, smb_queryinfo_t *); 39 static uint32_t smb2_qif_alignment(smb_request_t *, smb_queryinfo_t *); 40 static uint32_t smb2_qif_all(smb_request_t *, smb_queryinfo_t *); 41 static uint32_t smb2_qif_altname(smb_request_t *, smb_queryinfo_t *); 42 static uint32_t smb2_qif_stream(smb_request_t *, smb_queryinfo_t *); 43 static uint32_t smb2_qif_pipe(smb_request_t *, smb_queryinfo_t *); 44 static uint32_t smb2_qif_pipe_lcl(smb_request_t *, smb_queryinfo_t *); 45 static uint32_t smb2_qif_pipe_rem(smb_request_t *, smb_queryinfo_t *); 46 static uint32_t smb2_qif_compr(smb_request_t *, smb_queryinfo_t *); 47 static uint32_t smb2_qif_opens(smb_request_t *, smb_queryinfo_t *); 48 static uint32_t smb2_qif_tags(smb_request_t *, smb_queryinfo_t *); 49 static uint32_t smb2_qif_id_info(smb_request_t *, smb_queryinfo_t *); 50 51 52 uint32_t 53 smb2_qinfo_file(smb_request_t *sr, smb_queryinfo_t *qi) 54 { 55 smb_ofile_t *of = sr->fid_ofile; 56 uint_t mask = 0; 57 boolean_t getstd = B_FALSE; 58 boolean_t getname = B_FALSE; 59 uint32_t status; 60 61 /* 62 * Which attributes do we need from the FS? 63 */ 64 switch (qi->qi_InfoClass) { 65 case FileBasicInformation: 66 mask = SMB_AT_BASIC; 67 break; 68 case FileStandardInformation: 69 mask = SMB_AT_STANDARD; 70 getstd = B_TRUE; 71 break; 72 case FileInternalInformation: 73 mask = SMB_AT_NODEID; 74 break; 75 case FileAllInformation: 76 mask = SMB_AT_ALL; 77 getstd = B_TRUE; 78 if (sr->session->dialect < SMB_VERS_3_11) { 79 /* See smb2_qif_all() */ 80 getname = B_TRUE; 81 } 82 break; 83 84 case FileNameInformation: 85 case FileNormalizedNameInformation: 86 getname = B_TRUE; 87 break; 88 89 case FileAlternateNameInformation: 90 mask = SMB_AT_NODEID; 91 getname = B_TRUE; 92 break; 93 94 case FileStreamInformation: 95 mask = SMB_AT_STANDARD; 96 getstd = B_TRUE; 97 break; 98 99 case FileCompressionInformation: 100 mask = SMB_AT_SIZE | SMB_AT_ALLOCSZ; 101 break; 102 103 case FileNetworkOpenInformation: 104 mask = SMB_AT_BASIC | SMB_AT_STANDARD; 105 break; 106 107 case FileIdInformation: 108 mask = SMB_AT_NODEID; 109 break; 110 111 default: 112 break; 113 } 114 115 qi->qi_attr.sa_mask = mask; 116 qi->qi_node = of->f_node; 117 if (mask & SMB_AT_ALL) { 118 status = smb2_ofile_getattr(sr, of, &qi->qi_attr); 119 if (status) 120 return (status); 121 } 122 if (getstd) { 123 status = smb2_ofile_getstd(of, qi); 124 if (status) 125 return (status); 126 } 127 if (getname) { 128 status = smb2_ofile_getname(of, qi); 129 if (status) 130 return (status); 131 } 132 133 switch (qi->qi_InfoClass) { 134 case FileBasicInformation: 135 status = smb2_qif_basic(sr, qi); 136 break; 137 case FileStandardInformation: 138 status = smb2_qif_standard(sr, qi); 139 break; 140 case FileInternalInformation: 141 status = smb2_qif_internal(sr, qi); 142 break; 143 case FileEaInformation: 144 status = smb2_qif_ea_size(sr, qi); 145 break; 146 case FileAccessInformation: 147 status = smb2_qif_access(sr, qi); 148 break; 149 case FileNameInformation: 150 status = smb2_qif_name(sr, qi); 151 break; 152 case FileNormalizedNameInformation: 153 status = smb2_qif_normalized_name(sr, qi); 154 break; 155 case FilePositionInformation: 156 status = smb2_qif_position(sr, qi); 157 break; 158 case FileFullEaInformation: 159 status = smb2_qif_full_ea(sr, qi); 160 break; 161 case FileModeInformation: 162 status = smb2_qif_mode(sr, qi); 163 break; 164 case FileAlignmentInformation: 165 status = smb2_qif_alignment(sr, qi); 166 break; 167 case FileAllInformation: 168 status = smb2_qif_all(sr, qi); 169 break; 170 case FileAlternateNameInformation: 171 status = smb2_qif_altname(sr, qi); 172 break; 173 case FileStreamInformation: 174 status = smb2_qif_stream(sr, qi); 175 break; 176 case FilePipeInformation: 177 status = smb2_qif_pipe(sr, qi); 178 break; 179 case FilePipeLocalInformation: 180 status = smb2_qif_pipe_lcl(sr, qi); 181 break; 182 case FilePipeRemoteInformation: 183 status = smb2_qif_pipe_rem(sr, qi); 184 break; 185 case FileCompressionInformation: 186 status = smb2_qif_compr(sr, qi); 187 break; 188 case FileNetworkOpenInformation: 189 status = smb2_qif_opens(sr, qi); 190 break; 191 case FileAttributeTagInformation: 192 status = smb2_qif_tags(sr, qi); 193 break; 194 case FileIdInformation: 195 status = smb2_qif_id_info(sr, qi); 196 break; 197 default: 198 status = NT_STATUS_INVALID_INFO_CLASS; 199 break; 200 } 201 202 return (status); 203 } 204 205 /* 206 * FileAllInformation 207 * 208 * This returns a concatenation of: 209 * FileBasicInformation 210 * FileStandardInformation 211 * FileInternalInformation 212 * FileEaInformation 213 * FilePositionInformation 214 * FileModeInformation 215 * FileAlignmentInformation 216 * FileNameInformation 217 * 218 * Note: FileNameInformation is all zero on Win2016 and later. 219 */ 220 static uint32_t 221 smb2_qif_all(smb_request_t *sr, smb_queryinfo_t *qi) 222 { 223 uint32_t status; 224 225 status = smb2_qif_basic(sr, qi); 226 if (status) 227 return (status); 228 status = smb2_qif_standard(sr, qi); 229 if (status) 230 return (status); 231 status = smb2_qif_internal(sr, qi); 232 if (status) 233 return (status); 234 status = smb2_qif_ea_size(sr, qi); 235 if (status) 236 return (status); 237 status = smb2_qif_position(sr, qi); 238 if (status) 239 return (status); 240 status = smb2_qif_mode(sr, qi); 241 if (status) 242 return (status); 243 status = smb2_qif_alignment(sr, qi); 244 if (status) 245 return (status); 246 247 /* 248 * MS-SMB2 3.3.5.20.1 says (in a windows behavior note) that 249 * 2012R2 and older fill in the FileNameInformation. 250 * We could let this depend on sr->sr_cfg->skc_version 251 * but doing it based on dialect is a lot easier and 252 * has nearly the same effect. 253 */ 254 if (sr->session->dialect < SMB_VERS_3_11) { 255 /* Win2012r2 and earlier fill it in. (SMB 3.0) */ 256 status = smb2_qif_name(sr, qi); 257 } else { 258 /* Win2016 and later just put zeros (SMB 3.11) */ 259 int rc = smb_mbc_encodef(&sr->raw_data, "10."); 260 status = (rc == 0) ? 0 : NT_STATUS_BUFFER_OVERFLOW; 261 } 262 263 return (status); 264 } 265 266 /* 267 * FileBasicInformation 268 * See also: 269 * case SMB_QUERY_FILE_BASIC_INFO: 270 * case SMB_FILE_BASIC_INFORMATION: 271 */ 272 static uint32_t 273 smb2_qif_basic(smb_request_t *sr, smb_queryinfo_t *qi) 274 { 275 smb_attr_t *sa = &qi->qi_attr; 276 int rc; 277 278 ASSERT((sa->sa_mask & SMB_AT_BASIC) == SMB_AT_BASIC); 279 280 rc = smb_mbc_encodef( 281 &sr->raw_data, "TTTTll", 282 &sa->sa_crtime, /* T */ 283 &sa->sa_vattr.va_atime, /* T */ 284 &sa->sa_vattr.va_mtime, /* T */ 285 &sa->sa_vattr.va_ctime, /* T */ 286 sa->sa_dosattr, /* l */ 287 0); /* reserved */ /* l */ 288 if (rc != 0) 289 return (NT_STATUS_BUFFER_OVERFLOW); 290 291 return (0); 292 } 293 294 /* 295 * FileStandardInformation 296 * See also: 297 * SMB_QUERY_FILE_STANDARD_INFO 298 * SMB_FILE_STANDARD_INFORMATION 299 */ 300 static uint32_t 301 smb2_qif_standard(smb_request_t *sr, smb_queryinfo_t *qi) 302 { 303 smb_attr_t *sa = &qi->qi_attr; 304 int rc; 305 306 ASSERT((sa->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD); 307 308 rc = smb_mbc_encodef( 309 &sr->raw_data, "qqlbbw", 310 sa->sa_allocsz, /* q */ 311 sa->sa_vattr.va_size, /* q */ 312 sa->sa_vattr.va_nlink, /* l */ 313 qi->qi_delete_on_close, /* b */ 314 qi->qi_isdir, /* b */ 315 0); /* reserved */ /* w */ 316 if (rc != 0) 317 return (NT_STATUS_BUFFER_OVERFLOW); 318 319 return (0); 320 } 321 322 /* 323 * FileInternalInformation 324 * See also: 325 * SMB_FILE_INTERNAL_INFORMATION 326 */ 327 static uint32_t 328 smb2_qif_internal(smb_request_t *sr, smb_queryinfo_t *qi) 329 { 330 smb_attr_t *sa = &qi->qi_attr; 331 u_longlong_t nodeid; 332 int rc; 333 334 ASSERT((sa->sa_mask & SMB_AT_NODEID) == SMB_AT_NODEID); 335 nodeid = sa->sa_vattr.va_nodeid; 336 337 if (smb2_aapl_use_file_ids == 0 && 338 (sr->session->s_flags & SMB_SSN_AAPL_CCEXT) != 0) 339 nodeid = 0; 340 341 rc = smb_mbc_encodef( 342 &sr->raw_data, "q", 343 nodeid); /* q */ 344 if (rc != 0) 345 return (NT_STATUS_BUFFER_OVERFLOW); 346 347 return (0); 348 } 349 350 /* 351 * FileEaInformation 352 * See also: 353 * SMB_QUERY_FILE_EA_INFO 354 * SMB_FILE_EA_INFORMATION 355 */ 356 static uint32_t 357 smb2_qif_ea_size(smb_request_t *sr, smb_queryinfo_t *qi) 358 { 359 _NOTE(ARGUNUSED(qi)) 360 int rc; 361 362 rc = smb_mbc_encodef( 363 &sr->raw_data, "l", 0); 364 if (rc != 0) 365 return (NT_STATUS_BUFFER_OVERFLOW); 366 367 return (0); 368 } 369 370 /* 371 * FileFullEaInformation 372 * We could put EAs in a named stream... 373 */ 374 /* ARGSUSED */ 375 static uint32_t 376 smb2_qif_full_ea(smb_request_t *sr, smb_queryinfo_t *qi) 377 { 378 return (NT_STATUS_NO_EAS_ON_FILE); 379 } 380 381 /* 382 * FileAccessInformation 383 */ 384 static uint32_t 385 smb2_qif_access(smb_request_t *sr, smb_queryinfo_t *qi) 386 { 387 _NOTE(ARGUNUSED(qi)) 388 smb_ofile_t *of = sr->fid_ofile; 389 int rc; 390 391 rc = smb_mbc_encodef( 392 &sr->raw_data, "l", 393 of->f_granted_access); 394 if (rc != 0) 395 return (NT_STATUS_BUFFER_OVERFLOW); 396 397 return (0); 398 } 399 400 /* 401 * FileNameInformation 402 * See also: 403 * SMB_QUERY_FILE_NAME_INFO 404 * SMB_FILE_NAME_INFORMATION 405 */ 406 static uint32_t 407 smb2_qif_name(smb_request_t *sr, smb_queryinfo_t *qi) 408 { 409 char *name; 410 uint32_t nlen; 411 int rc; 412 413 /* SMB2 leaves off the leading / */ 414 nlen = qi->qi_namelen; 415 name = qi->qi_name; 416 if (qi->qi_name[0] == '\\') { 417 name++; 418 nlen -= 2; 419 } 420 421 rc = smb_mbc_encodef( 422 &sr->raw_data, "llU", 423 0, /* FileIndex (l) */ 424 nlen, /* l */ 425 name); /* U */ 426 if (rc != 0) 427 return (NT_STATUS_BUFFER_OVERFLOW); 428 429 return (0); 430 } 431 432 /* 433 * FileNormalizedNameInformation 434 */ 435 static uint32_t 436 smb2_qif_normalized_name(smb_request_t *sr, smb_queryinfo_t *qi) 437 { 438 char *name; 439 uint32_t nlen; 440 int rc; 441 442 /* SMB2 leaves off the leading / */ 443 nlen = qi->qi_namelen; 444 name = qi->qi_name; 445 if (qi->qi_name[0] == '\\') { 446 name++; 447 nlen -= 2; 448 } 449 450 rc = smb_mbc_encodef( 451 &sr->raw_data, "lU", 452 nlen, /* l */ 453 name); /* U */ 454 if (rc != 0) 455 return (NT_STATUS_BUFFER_OVERFLOW); 456 457 return (0); 458 } 459 460 /* 461 * FilePositionInformation 462 */ 463 static uint32_t 464 smb2_qif_position(smb_request_t *sr, smb_queryinfo_t *qi) 465 { 466 _NOTE(ARGUNUSED(qi)) 467 smb_ofile_t *of = sr->fid_ofile; 468 uint64_t pos; 469 int rc; 470 471 mutex_enter(&of->f_mutex); 472 pos = of->f_seek_pos; 473 mutex_exit(&of->f_mutex); 474 475 rc = smb_mbc_encodef( 476 &sr->raw_data, "q", pos); 477 if (rc != 0) 478 return (NT_STATUS_BUFFER_OVERFLOW); 479 480 return (0); 481 } 482 483 /* 484 * FileModeInformation [MS-FSA 2.4.24] 485 * XXX: These mode flags are supposed to be on the open handle, 486 * XXX: or I think so. Not yet... (just put zero for now) 487 */ 488 static uint32_t 489 smb2_qif_mode(smb_request_t *sr, smb_queryinfo_t *qi) 490 { 491 _NOTE(ARGUNUSED(qi)) 492 int rc; 493 494 rc = smb_mbc_encodef( 495 &sr->raw_data, "l", 0); 496 if (rc != 0) 497 return (NT_STATUS_BUFFER_OVERFLOW); 498 499 return (0); 500 } 501 502 /* 503 * FileAlignmentInformation 504 */ 505 static uint32_t 506 smb2_qif_alignment(smb_request_t *sr, smb_queryinfo_t *qi) 507 { 508 _NOTE(ARGUNUSED(qi)) 509 int rc; 510 511 rc = smb_mbc_encodef( 512 &sr->raw_data, "l", 0); 513 if (rc != 0) 514 return (NT_STATUS_BUFFER_OVERFLOW); 515 516 return (0); 517 } 518 519 /* 520 * FileAlternateNameInformation 521 * See also: 522 * SMB_QUERY_FILE_ALT_NAME_INFO 523 * SMB_FILE_ALT_NAME_INFORMATION 524 */ 525 static uint32_t 526 smb2_qif_altname(smb_request_t *sr, smb_queryinfo_t *qi) 527 { 528 smb_ofile_t *of = sr->fid_ofile; 529 int rc; 530 531 ASSERT(qi->qi_namelen > 0); 532 ASSERT(qi->qi_attr.sa_mask & SMB_AT_NODEID); 533 534 if (of->f_ftype != SMB_FTYPE_DISK) 535 return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 536 if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0) 537 return (NT_STATUS_OBJECT_NAME_NOT_FOUND); 538 539 /* fill in qi->qi_shortname */ 540 smb_query_shortname(of->f_node, qi); 541 542 rc = smb_mbc_encodef( 543 &sr->raw_data, "%lU", sr, 544 smb_wcequiv_strlen(qi->qi_shortname), 545 qi->qi_shortname); 546 if (rc != 0) 547 return (NT_STATUS_BUFFER_OVERFLOW); 548 549 return (0); 550 } 551 552 /* 553 * FileStreamInformation 554 */ 555 static uint32_t 556 smb2_qif_stream(smb_request_t *sr, smb_queryinfo_t *qi) 557 { 558 smb_ofile_t *of = sr->fid_ofile; 559 smb_attr_t *attr = &qi->qi_attr; 560 uint32_t status; 561 562 ASSERT((attr->sa_mask & SMB_AT_STANDARD) == SMB_AT_STANDARD); 563 if (of->f_ftype != SMB_FTYPE_DISK) { 564 (void) smb_mbc_encodef( 565 &sr->raw_data, "l", 0); 566 return (0); 567 } 568 569 status = smb_query_stream_info(sr, &sr->raw_data, qi); 570 return (status); 571 } 572 573 /* 574 * FilePipeInformation 575 */ 576 static uint32_t 577 smb2_qif_pipe(smb_request_t *sr, smb_queryinfo_t *qi) 578 { 579 _NOTE(ARGUNUSED(qi)) 580 smb_ofile_t *of = sr->fid_ofile; 581 uint32_t pipe_mode; 582 uint32_t nonblock; 583 int rc; 584 585 switch (of->f_ftype) { 586 case SMB_FTYPE_BYTE_PIPE: 587 pipe_mode = 0; /* FILE_PIPE_BYTE_STREAM_MODE */ 588 break; 589 case SMB_FTYPE_MESG_PIPE: 590 pipe_mode = 1; /* FILE_PIPE_MESSAGE_MODE */ 591 break; 592 case SMB_FTYPE_DISK: 593 case SMB_FTYPE_PRINTER: 594 default: 595 return (NT_STATUS_INVALID_PARAMETER); 596 } 597 nonblock = 0; /* XXX todo: Get this from the pipe handle. */ 598 599 rc = smb_mbc_encodef( 600 &sr->raw_data, "ll", 601 pipe_mode, nonblock); 602 if (rc != 0) 603 return (NT_STATUS_BUFFER_OVERFLOW); 604 605 return (0); 606 } 607 608 /* 609 * FilePipeLocalInformation 610 */ 611 /* ARGSUSED */ 612 static uint32_t 613 smb2_qif_pipe_lcl(smb_request_t *sr, smb_queryinfo_t *qi) 614 { 615 return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */ 616 } 617 618 /* 619 * FilePipeRemoteInformation 620 */ 621 /* ARGSUSED */ 622 static uint32_t 623 smb2_qif_pipe_rem(smb_request_t *sr, smb_queryinfo_t *qi) 624 { 625 return (NT_STATUS_INVALID_PARAMETER); /* XXX todo */ 626 } 627 628 /* 629 * FileCompressionInformation 630 * XXX: For now, just say "not compressed". 631 */ 632 static uint32_t 633 smb2_qif_compr(smb_request_t *sr, smb_queryinfo_t *qi) 634 { 635 smb_attr_t *sa = &qi->qi_attr; 636 uint16_t CompressionFormat = 0; /* COMPRESSION_FORMAT_NONE */ 637 int rc; 638 639 ASSERT(sa->sa_mask & SMB_AT_SIZE); 640 641 rc = smb_mbc_encodef( 642 &sr->raw_data, "qw6.", 643 sa->sa_vattr.va_size, /* q */ 644 CompressionFormat); /* w */ 645 if (rc != 0) 646 return (NT_STATUS_BUFFER_OVERFLOW); 647 648 return (0); 649 } 650 651 /* 652 * FileNetworkOpenInformation 653 */ 654 static uint32_t 655 smb2_qif_opens(smb_request_t *sr, smb_queryinfo_t *qi) 656 { 657 smb_attr_t *sa = &qi->qi_attr; 658 int rc; 659 660 rc = smb_mbc_encodef( 661 &sr->raw_data, "TTTTqqll", 662 &sa->sa_crtime, /* T */ 663 &sa->sa_vattr.va_atime, /* T */ 664 &sa->sa_vattr.va_mtime, /* T */ 665 &sa->sa_vattr.va_ctime, /* T */ 666 sa->sa_allocsz, /* q */ 667 sa->sa_vattr.va_size, /* q */ 668 sa->sa_dosattr, /* l */ 669 0); /* reserved */ /* l */ 670 if (rc != 0) 671 return (NT_STATUS_BUFFER_OVERFLOW); 672 673 return (0); 674 } 675 676 /* 677 * FileAttributeTagInformation 678 * 679 * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the 680 * second dword should be the reparse tag. Otherwise 681 * the tag value should be set to zero. 682 * We don't support reparse points, so we set the tag 683 * to zero. 684 */ 685 static uint32_t 686 smb2_qif_tags(smb_request_t *sr, smb_queryinfo_t *qi) 687 { 688 _NOTE(ARGUNUSED(qi)) 689 int rc; 690 691 rc = smb_mbc_encodef( 692 &sr->raw_data, "ll", 0, 0); 693 if (rc != 0) 694 return (NT_STATUS_BUFFER_OVERFLOW); 695 696 return (0); 697 } 698 699 /* 700 * FileIdInformation 701 * 702 * Returns a A FILE_ID_INFORMATION 703 * VolumeSerialNumber (8 bytes) 704 * FileId (16 bytes) 705 * 706 * Take the volume serial from the share root, 707 * and compose the FileId from the nodeid and fsid 708 * of the file (in case we crossed mounts) 709 */ 710 static uint32_t 711 smb2_qif_id_info(smb_request_t *sr, smb_queryinfo_t *qi) 712 { 713 smb_attr_t *sa = &qi->qi_attr; 714 smb_ofile_t *of = sr->fid_ofile; 715 smb_tree_t *tree = sr->tid_tree; 716 vfs_t *f_vfs; // file 717 vfs_t *s_vfs; // share 718 uint64_t nodeid; 719 int rc; 720 721 ASSERT((sa->sa_mask & SMB_AT_NODEID) != 0); 722 if (of->f_ftype != SMB_FTYPE_DISK) 723 return (NT_STATUS_INVALID_INFO_CLASS); 724 725 s_vfs = SMB_NODE_VFS(tree->t_snode); 726 f_vfs = SMB_NODE_VFS(of->f_node); 727 nodeid = (uint64_t)sa->sa_vattr.va_nodeid; 728 729 rc = smb_mbc_encodef( 730 &sr->raw_data, "llqll", 731 s_vfs->vfs_fsid.val[0], /* l */ 732 s_vfs->vfs_fsid.val[1], /* l */ 733 nodeid, /* q */ 734 f_vfs->vfs_fsid.val[0], /* l */ 735 f_vfs->vfs_fsid.val[1]); /* l */ 736 if (rc != 0) 737 return (NT_STATUS_INFO_LENGTH_MISMATCH); 738 739 return (0); 740 } 741