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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Trans2 Set File/Path Information Levels: 28 * 29 * SMB_INFO_STANDARD 30 * SMB_INFO_SET_EAS 31 * SMB_SET_FILE_BASIC_INFO 32 * SMB_SET_FILE_DISPOSITION_INFO 33 * SMB_SET_FILE_END_OF_FILE_INFO 34 * SMB_SET_FILE_ALLOCATION_INFO 35 * 36 * Supported Passthrough levels: 37 * SMB_FILE_BASIC_INFORMATION 38 * SMB_FILE_DISPOSITION_INFORMATION 39 * SMB_FILE_END_OF_FILE_INFORMATION 40 * SMB_FILE_ALLOCATION_INFORMATION 41 * 42 * Internal levels representing non trans2 requests 43 * SMB_SET_INFORMATION 44 * SMB_SET_INFORMATION2 45 */ 46 47 /* 48 * Setting timestamps: 49 * The behaviour when the time field is set to -1 is not documented 50 * but is generally treated like 0, meaning that that server file 51 * system assigned value need not be changed. 52 * 53 * Setting attributes - FILE_ATTRIBUTE_NORMAL: 54 * SMB_SET_INFORMATION - 55 * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set 56 * do NOT change the file's attributes. 57 * SMB_SET_BASIC_INFO - 58 * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set 59 * clear (0) the file's attributes. 60 * - if the specified attributes are 0 do NOT change the file's 61 * attributes. 62 */ 63 64 #include <smbsrv/smb_incl.h> 65 #include <smbsrv/smb_fsops.h> 66 67 typedef struct smb_setinfo { 68 uint16_t si_infolev; 69 smb_xa_t *si_xa; 70 smb_node_t *si_node; 71 } smb_setinfo_t; 72 73 /* 74 * These functions all return 0 (success) or -1 (error). 75 * They set error details in the sr when appropriate. 76 */ 77 static int smb_set_by_fid(smb_request_t *, smb_xa_t *, uint16_t); 78 static int smb_set_by_path(smb_request_t *, smb_xa_t *, uint16_t, char *); 79 static int smb_set_fileinfo(smb_request_t *, smb_setinfo_t *); 80 static int smb_set_information(smb_request_t *, smb_setinfo_t *); 81 static int smb_set_information2(smb_request_t *, smb_setinfo_t *); 82 static int smb_set_standard_info(smb_request_t *, smb_setinfo_t *); 83 static int smb_set_basic_info(smb_request_t *, smb_setinfo_t *); 84 static int smb_set_disposition_info(smb_request_t *, smb_setinfo_t *); 85 static int smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *); 86 static int smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *); 87 88 /* 89 * smb_com_trans2_set_file_information 90 */ 91 smb_sdrc_t 92 smb_com_trans2_set_file_information(smb_request_t *sr, smb_xa_t *xa) 93 { 94 uint16_t infolev; 95 96 if (smb_mbc_decodef(&xa->req_param_mb, "ww", 97 &sr->smb_fid, &infolev) != 0) 98 return (SDRC_ERROR); 99 100 if (smb_set_by_fid(sr, xa, infolev) != 0) 101 return (SDRC_ERROR); 102 103 return (SDRC_SUCCESS); 104 } 105 106 /* 107 * smb_com_trans2_set_path_information 108 */ 109 smb_sdrc_t 110 smb_com_trans2_set_path_information(smb_request_t *sr, smb_xa_t *xa) 111 { 112 uint16_t infolev; 113 char *path; 114 115 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 116 smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST, 117 ERRDOS, ERROR_INVALID_FUNCTION); 118 return (SDRC_ERROR); 119 } 120 121 if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u", 122 sr, &infolev, &path) != 0) 123 return (SDRC_ERROR); 124 125 if (smb_set_by_path(sr, xa, infolev, path) != 0) 126 return (SDRC_ERROR); 127 128 return (SDRC_SUCCESS); 129 } 130 131 /* 132 * smb_com_set_information (aka setattr) 133 */ 134 smb_sdrc_t 135 smb_pre_set_information(smb_request_t *sr) 136 { 137 DTRACE_SMB_1(op__SetInformation__start, smb_request_t *, sr); 138 return (SDRC_SUCCESS); 139 } 140 141 void 142 smb_post_set_information(smb_request_t *sr) 143 { 144 DTRACE_SMB_1(op__SetInformation__done, smb_request_t *, sr); 145 } 146 147 smb_sdrc_t 148 smb_com_set_information(smb_request_t *sr) 149 { 150 uint16_t infolev = SMB_SET_INFORMATION; 151 char *path; 152 153 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 154 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 155 ERRDOS, ERROR_ACCESS_DENIED); 156 return (SDRC_ERROR); 157 } 158 159 if (smbsr_decode_data(sr, "%S", sr, &path) != 0) 160 return (SDRC_ERROR); 161 162 if (smb_set_by_path(sr, NULL, infolev, path) != 0) 163 return (SDRC_ERROR); 164 165 if (smbsr_encode_empty_result(sr) != 0) 166 return (SDRC_ERROR); 167 168 return (SDRC_SUCCESS); 169 } 170 171 /* 172 * smb_com_set_information2 (aka setattre) 173 */ 174 smb_sdrc_t 175 smb_pre_set_information2(smb_request_t *sr) 176 { 177 DTRACE_SMB_1(op__SetInformation2__start, smb_request_t *, sr); 178 return (SDRC_SUCCESS); 179 } 180 181 void 182 smb_post_set_information2(smb_request_t *sr) 183 { 184 DTRACE_SMB_1(op__SetInformation2__done, smb_request_t *, sr); 185 } 186 187 smb_sdrc_t 188 smb_com_set_information2(smb_request_t *sr) 189 { 190 uint16_t infolev = SMB_SET_INFORMATION2; 191 192 if (smbsr_decode_vwv(sr, "w", &sr->smb_fid) != 0) 193 return (SDRC_ERROR); 194 195 if (smb_set_by_fid(sr, NULL, infolev) != 0) 196 return (SDRC_ERROR); 197 198 if (smbsr_encode_empty_result(sr) != 0) 199 return (SDRC_ERROR); 200 201 return (SDRC_SUCCESS); 202 } 203 204 /* 205 * smb_set_by_fid 206 * 207 * Common code for setting file information by open file id. 208 * Use the id to identify the node object and invoke smb_set_fileinfo 209 * for that node. 210 * 211 * Setting attributes on a named pipe by id is handled by simply 212 * returning success. 213 */ 214 static int 215 smb_set_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev) 216 { 217 int rc; 218 smb_setinfo_t sinfo; 219 220 if (SMB_TREE_IS_READONLY(sr)) { 221 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 222 ERRDOS, ERROR_ACCESS_DENIED); 223 return (-1); 224 } 225 226 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) 227 return (0); 228 229 smbsr_lookup_file(sr); 230 if (sr->fid_ofile == NULL) { 231 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 232 return (-1); 233 } 234 235 if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) { 236 smbsr_release_file(sr); 237 return (0); 238 } 239 240 sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 241 242 sinfo.si_xa = xa; 243 sinfo.si_infolev = infolev; 244 sinfo.si_node = sr->fid_ofile->f_node; 245 rc = smb_set_fileinfo(sr, &sinfo); 246 247 smbsr_release_file(sr); 248 return (rc); 249 } 250 251 /* 252 * smb_set_by_path 253 * 254 * Common code for setting file information by file name. 255 * Use the file name to identify the node object and invoke 256 * smb_set_fileinfo for that node. 257 * 258 * Setting attributes on a named pipe by name is an error and 259 * is handled in the calling functions so that they can return 260 * the appropriate error status code (which differs by caller). 261 */ 262 static int 263 smb_set_by_path(smb_request_t *sr, smb_xa_t *xa, 264 uint16_t infolev, char *path) 265 { 266 int rc; 267 smb_setinfo_t sinfo; 268 smb_node_t *node, *dnode; 269 char *name; 270 271 if (SMB_TREE_IS_READONLY(sr)) { 272 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 273 ERRDOS, ERROR_ACCESS_DENIED); 274 return (-1); 275 } 276 277 name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 278 rc = smb_pathname_reduce(sr, sr->user_cr, path, 279 sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode, name); 280 if (rc == 0) { 281 rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS, 282 sr->tid_tree->t_snode, dnode, name, &node); 283 smb_node_release(dnode); 284 } 285 kmem_free(name, MAXNAMELEN); 286 287 if (rc != 0) { 288 smbsr_errno(sr, rc); 289 return (-1); 290 } 291 292 /* Break any conflicting oplock for subsequent attribute setting */ 293 if (smb_oplock_conflict(node, sr->session, NULL)) { 294 (void) smb_oplock_break(node, sr->session, B_FALSE); 295 } 296 297 sinfo.si_xa = xa; 298 sinfo.si_infolev = infolev; 299 sinfo.si_node = node; 300 rc = smb_set_fileinfo(sr, &sinfo); 301 302 smb_node_release(node); 303 return (rc); 304 } 305 306 /* 307 * smb_set_fileinfo 308 */ 309 static int 310 smb_set_fileinfo(smb_request_t *sr, smb_setinfo_t *sinfo) 311 { 312 switch (sinfo->si_infolev) { 313 case SMB_SET_INFORMATION: 314 return (smb_set_information(sr, sinfo)); 315 316 case SMB_SET_INFORMATION2: 317 return (smb_set_information2(sr, sinfo)); 318 319 case SMB_INFO_STANDARD: 320 return (smb_set_standard_info(sr, sinfo)); 321 322 case SMB_INFO_SET_EAS: 323 /* EAs not supported */ 324 return (0); 325 326 case SMB_SET_FILE_BASIC_INFO: 327 case SMB_FILE_BASIC_INFORMATION: 328 return (smb_set_basic_info(sr, sinfo)); 329 330 case SMB_SET_FILE_DISPOSITION_INFO: 331 case SMB_FILE_DISPOSITION_INFORMATION: 332 return (smb_set_disposition_info(sr, sinfo)); 333 334 case SMB_SET_FILE_END_OF_FILE_INFO: 335 case SMB_FILE_END_OF_FILE_INFORMATION: 336 return (smb_set_eof_info(sr, sinfo)); 337 338 case SMB_SET_FILE_ALLOCATION_INFO: 339 case SMB_FILE_ALLOCATION_INFORMATION: 340 return (smb_set_alloc_info(sr, sinfo)); 341 342 default: 343 break; 344 } 345 346 smbsr_error(sr, NT_STATUS_INVALID_INFO_CLASS, 347 ERRDOS, ERROR_INVALID_PARAMETER); 348 return (-1); 349 } 350 351 /* 352 * smb_set_information 353 * 354 * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the 355 * target is not a directory. 356 * 357 * For compatibility with Windows Servers, if the specified 358 * attributes have ONLY FILE_ATTRIBUTE_NORMAL set do NOT change 359 * the file's attributes. 360 */ 361 static int 362 smb_set_information(smb_request_t *sr, smb_setinfo_t *sinfo) 363 { 364 int rc; 365 uint16_t attributes; 366 smb_node_t *node = sinfo->si_node; 367 smb_attr_t attr; 368 uint32_t mtime; 369 370 if (smbsr_decode_vwv(sr, "wl10.", &attributes, &mtime) != 0) 371 return (-1); 372 373 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) && 374 (!smb_node_is_dir(node))) { 375 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 376 ERRDOS, ERROR_INVALID_PARAMETER); 377 return (-1); 378 } 379 380 bzero(&attr, sizeof (smb_attr_t)); 381 if (attributes != FILE_ATTRIBUTE_NORMAL) { 382 attr.sa_dosattr = attributes; 383 attr.sa_mask |= SMB_AT_DOSATTR; 384 } 385 386 if (mtime != 0 && mtime != UINT_MAX) { 387 attr.sa_vattr.va_mtime.tv_sec = 388 smb_time_local_to_gmt(sr, mtime); 389 attr.sa_mask |= SMB_AT_MTIME; 390 } 391 392 rc = smb_node_setattr(sr, node, sr->user_cr, NULL, &attr); 393 if (rc != 0) { 394 smbsr_errno(sr, rc); 395 return (-1); 396 } 397 398 return (0); 399 } 400 401 /* 402 * smb_set_information2 403 */ 404 static int 405 smb_set_information2(smb_request_t *sr, smb_setinfo_t *sinfo) 406 { 407 int rc; 408 uint32_t crtime, atime, mtime; 409 smb_attr_t attr; 410 411 if (smbsr_decode_vwv(sr, "yyy", &crtime, &atime, &mtime) != 0) 412 return (-1); 413 414 bzero(&attr, sizeof (smb_attr_t)); 415 if (mtime != 0 && mtime != UINT_MAX) { 416 attr.sa_vattr.va_mtime.tv_sec = 417 smb_time_local_to_gmt(sr, mtime); 418 attr.sa_mask |= SMB_AT_MTIME; 419 } 420 421 if (crtime != 0 && crtime != UINT_MAX) { 422 attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime); 423 attr.sa_mask |= SMB_AT_CRTIME; 424 } 425 426 if (atime != 0 && atime != UINT_MAX) { 427 attr.sa_vattr.va_atime.tv_sec = 428 smb_time_local_to_gmt(sr, atime); 429 attr.sa_mask |= SMB_AT_ATIME; 430 } 431 432 rc = smb_node_setattr(sr, sinfo->si_node, sr->user_cr, 433 sr->fid_ofile, &attr); 434 if (rc != 0) { 435 smbsr_errno(sr, rc); 436 return (-1); 437 } 438 439 return (0); 440 } 441 442 /* 443 * smb_set_standard_info 444 * 445 * Sets standard file/path information. 446 */ 447 static int 448 smb_set_standard_info(smb_request_t *sr, smb_setinfo_t *sinfo) 449 { 450 smb_attr_t attr; 451 uint32_t crtime, atime, mtime; 452 smb_node_t *node = sinfo->si_node; 453 int rc; 454 455 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "yyy", 456 &crtime, &atime, &mtime) != 0) { 457 return (-1); 458 } 459 460 bzero(&attr, sizeof (smb_attr_t)); 461 if (mtime != 0 && mtime != (uint32_t)-1) { 462 attr.sa_vattr.va_mtime.tv_sec = 463 smb_time_local_to_gmt(sr, mtime); 464 attr.sa_mask |= SMB_AT_MTIME; 465 } 466 467 if (crtime != 0 && crtime != (uint32_t)-1) { 468 attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime); 469 attr.sa_mask |= SMB_AT_CRTIME; 470 } 471 472 if (atime != 0 && atime != (uint32_t)-1) { 473 attr.sa_vattr.va_atime.tv_sec = 474 smb_time_local_to_gmt(sr, atime); 475 attr.sa_mask |= SMB_AT_ATIME; 476 } 477 478 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr); 479 if (rc != 0) { 480 smbsr_errno(sr, rc); 481 return (-1); 482 } 483 484 return (0); 485 } 486 487 /* 488 * smb_set_basic_info 489 * 490 * Sets basic file/path information. 491 * 492 * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the 493 * target is not a directory. 494 * 495 * For compatibility with windows servers: 496 * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set 497 * clear (0) the file's attributes. 498 * - if the specified attributes are 0 do NOT change the file's attributes. 499 */ 500 static int 501 smb_set_basic_info(smb_request_t *sr, smb_setinfo_t *sinfo) 502 { 503 int rc; 504 uint64_t crtime, atime, mtime, ctime; 505 uint16_t attributes; 506 smb_attr_t attr; 507 smb_node_t *node = sinfo->si_node; 508 509 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "qqqqw", 510 &crtime, &atime, &mtime, &ctime, &attributes) != 0) { 511 return (-1); 512 } 513 514 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) && 515 (!smb_node_is_dir(node))) { 516 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 517 ERRDOS, ERROR_INVALID_PARAMETER); 518 return (-1); 519 } 520 521 bzero(&attr, sizeof (smb_attr_t)); 522 if (ctime != 0 && ctime != (uint64_t)-1) { 523 smb_time_nt_to_unix(ctime, &attr.sa_vattr.va_ctime); 524 attr.sa_mask |= SMB_AT_CTIME; 525 } 526 527 if (crtime != 0 && crtime != (uint64_t)-1) { 528 smb_time_nt_to_unix(crtime, &attr.sa_crtime); 529 attr.sa_mask |= SMB_AT_CRTIME; 530 } 531 532 if (mtime != 0 && mtime != (uint64_t)-1) { 533 smb_time_nt_to_unix(mtime, &attr.sa_vattr.va_mtime); 534 attr.sa_mask |= SMB_AT_MTIME; 535 } 536 537 if (atime != 0 && atime != (uint64_t)-1) { 538 smb_time_nt_to_unix(atime, &attr.sa_vattr.va_atime); 539 attr.sa_mask |= SMB_AT_ATIME; 540 } 541 542 if (attributes != 0) { 543 attr.sa_dosattr = attributes; 544 attr.sa_mask |= SMB_AT_DOSATTR; 545 } 546 547 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr); 548 if (rc != 0) { 549 smbsr_errno(sr, rc); 550 return (-1); 551 } 552 553 return (0); 554 } 555 556 /* 557 * smb_set_eof_info 558 */ 559 static int 560 smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *sinfo) 561 { 562 int rc; 563 smb_attr_t attr; 564 uint64_t eof; 565 smb_node_t *node = sinfo->si_node; 566 567 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &eof) != 0) 568 return (-1); 569 570 if (smb_node_is_dir(node)) { 571 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 572 ERRDOS, ERROR_INVALID_PARAMETER); 573 return (-1); 574 } 575 576 bzero(&attr, sizeof (smb_attr_t)); 577 attr.sa_mask = SMB_AT_SIZE; 578 attr.sa_vattr.va_size = (u_offset_t)eof; 579 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr); 580 if (rc != 0) { 581 smbsr_errno(sr, rc); 582 return (-1); 583 } 584 585 return (0); 586 } 587 588 /* 589 * smb_set_alloc_info 590 */ 591 static int 592 smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *sinfo) 593 { 594 int rc; 595 smb_attr_t attr; 596 uint64_t allocsz; 597 smb_node_t *node = sinfo->si_node; 598 599 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &allocsz) != 0) 600 return (-1); 601 602 if (smb_node_is_dir(node)) { 603 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 604 ERRDOS, ERROR_INVALID_PARAMETER); 605 return (-1); 606 } 607 608 bzero(&attr, sizeof (smb_attr_t)); 609 attr.sa_mask = SMB_AT_ALLOCSZ; 610 attr.sa_allocsz = (u_offset_t)allocsz; 611 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr); 612 if (rc != 0) { 613 smbsr_errno(sr, rc); 614 return (-1); 615 } 616 617 return (0); 618 } 619 620 /* 621 * smb_set_disposition_info 622 * 623 * Set/Clear DELETE_ON_CLOSE flag for an open file. 624 * File should have been opened with DELETE access otherwise 625 * the operation is not permitted. 626 * 627 * NOTE: The node should be marked delete-on-close upon the receipt 628 * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set. 629 * It is different than both SmbNtCreateAndX and SmbNtTransact, which 630 * set delete-on-close on the ofile and defer setting the flag on the 631 * node until the file is closed. 632 * 633 * Observation of Windows 2000 indicates the following: 634 * 635 * 1) If a file is not opened with delete-on-close create options and 636 * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo) 637 * using that open file handle, any subsequent open requests will fail 638 * with DELETE_PENDING. 639 * 640 * 2) If a file is opened with delete-on-close create options and the 641 * client attempts to unset delete-on-close via Trans2SetFileInfo 642 * (SetDispositionInfo) prior to the file close, any subsequent open 643 * requests will still fail with DELETE_PENDING after the file is closed. 644 * 645 * 3) If a file is opened with delete-on-close create options and that 646 * file handle (not the last open handle and the only file handle 647 * with delete-on-close set) is closed. Any subsequent open requests 648 * will fail with DELETE_PENDING. Unsetting delete-on-close via 649 * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the 650 * node delete-on-close flag, which will result in the file not being 651 * removed even after the last file handle is closed. 652 */ 653 static int 654 smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *sinfo) 655 { 656 unsigned char mark_delete; 657 uint32_t flags = 0; 658 659 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "b", &mark_delete) != 0) 660 return (-1); 661 662 if ((sr->fid_ofile == NULL) || 663 !(smb_ofile_granted_access(sr->fid_ofile) & DELETE)) { 664 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 665 ERRDOS, ERROR_ACCESS_DENIED); 666 return (-1); 667 } 668 669 if (mark_delete) { 670 if (SMB_TREE_SUPPORTS_CATIA(sr)) 671 flags |= SMB_CATIA; 672 673 if (smb_node_set_delete_on_close(sinfo->si_node, 674 sr->user_cr, flags)) { 675 smbsr_error(sr, NT_STATUS_CANNOT_DELETE, 676 ERRDOS, ERROR_ACCESS_DENIED); 677 return (-1); 678 } 679 } else { 680 smb_node_reset_delete_on_close(sinfo->si_node); 681 } 682 return (0); 683 } 684