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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 #include <sys/synch.h> 27 #include <smbsrv/smb_kproto.h> 28 #include <smbsrv/smb_fsops.h> 29 #include <sys/nbmlock.h> 30 31 /* 32 * NT_RENAME InformationLevels: 33 * 34 * SMB_NT_RENAME_MOVE_CLUSTER_INFO Server returns invalid parameter. 35 * SMB_NT_RENAME_SET_LINK_INFO Create a hard link to a file. 36 * SMB_NT_RENAME_RENAME_FILE In-place rename of a file. 37 * SMB_NT_RENAME_MOVE_FILE Move (rename) a file. 38 */ 39 #define SMB_NT_RENAME_MOVE_CLUSTER_INFO 0x0102 40 #define SMB_NT_RENAME_SET_LINK_INFO 0x0103 41 #define SMB_NT_RENAME_RENAME_FILE 0x0104 42 #define SMB_NT_RENAME_MOVE_FILE 0x0105 43 44 /* 45 * SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag 46 */ 47 #define SMB_RENAME_FLAG_OVERWRITE 0x001 48 49 static int smb_common_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *); 50 static int smb_make_link(smb_request_t *, smb_fqi_t *, smb_fqi_t *); 51 static int smb_rename_check_stream(smb_fqi_t *, smb_fqi_t *); 52 static int smb_rename_check_attr(smb_request_t *, smb_node_t *, uint16_t); 53 static void smb_rename_set_error(smb_request_t *, int); 54 55 static int smb_rename_lookup_src(smb_request_t *); 56 static void smb_rename_release_src(smb_request_t *); 57 58 /* 59 * smb_com_rename 60 * 61 * Rename a file. Files OldFileName must exist and NewFileName must not. 62 * Both pathnames must be relative to the Tid specified in the request. 63 * Open files may be renamed. 64 * 65 * Multiple files may be renamed in response to a single request as Rename 66 * File supports wildcards in the file name (last component of the path). 67 * NOTE: we don't support rename with wildcards. 68 * 69 * SearchAttributes indicates the attributes that the target file(s) must 70 * have. If SearchAttributes is zero then only normal files are renamed. 71 * If the system file or hidden attributes are specified then the rename 72 * is inclusive - both the specified type(s) of files and normal files are 73 * renamed. 74 */ 75 smb_sdrc_t 76 smb_pre_rename(smb_request_t *sr) 77 { 78 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 79 smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 80 int rc; 81 82 if ((rc = smbsr_decode_vwv(sr, "w", &src_fqi->fq_sattr)) == 0) { 83 rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->fq_path.pn_path, 84 &dst_fqi->fq_path.pn_path); 85 86 dst_fqi->fq_sattr = 0; 87 } 88 89 DTRACE_SMB_2(op__Rename__start, smb_request_t *, sr, 90 struct dirop *, &sr->arg.dirop); 91 92 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 93 } 94 95 void 96 smb_post_rename(smb_request_t *sr) 97 { 98 DTRACE_SMB_1(op__Rename__done, smb_request_t *, sr); 99 } 100 101 smb_sdrc_t 102 smb_com_rename(smb_request_t *sr) 103 { 104 int rc; 105 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 106 smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 107 smb_pathname_t *src_pn = &src_fqi->fq_path; 108 smb_pathname_t *dst_pn = &dst_fqi->fq_path; 109 110 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 111 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 112 ERRDOS, ERROR_ACCESS_DENIED); 113 return (SDRC_ERROR); 114 } 115 116 smb_pathname_init(sr, src_pn, src_pn->pn_path); 117 smb_pathname_init(sr, dst_pn, dst_pn->pn_path); 118 if (!smb_pathname_validate(sr, src_pn) || 119 !smb_pathname_validate(sr, dst_pn)) { 120 return (SDRC_ERROR); 121 } 122 123 rc = smb_common_rename(sr, src_fqi, dst_fqi); 124 125 if (rc != 0) { 126 smb_rename_set_error(sr, rc); 127 return (SDRC_ERROR); 128 } 129 130 rc = smbsr_encode_empty_result(sr); 131 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 132 } 133 134 /* 135 * smb_com_nt_rename 136 * 137 * Rename a file. Files OldFileName must exist and NewFileName must not. 138 * Both pathnames must be relative to the Tid specified in the request. 139 * Open files may be renamed. 140 * 141 * SearchAttributes indicates the attributes that the target file(s) must 142 * have. If SearchAttributes is zero then only normal files are renamed. 143 * If the system file or hidden attributes are specified then the rename 144 * is inclusive - both the specified type(s) of files and normal files are 145 * renamed. 146 */ 147 smb_sdrc_t 148 smb_pre_nt_rename(smb_request_t *sr) 149 { 150 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 151 smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 152 uint32_t clusters; 153 int rc; 154 155 rc = smbsr_decode_vwv(sr, "wwl", &src_fqi->fq_sattr, 156 &sr->arg.dirop.info_level, &clusters); 157 if (rc == 0) { 158 rc = smbsr_decode_data(sr, "%SS", sr, 159 &src_fqi->fq_path.pn_path, &dst_fqi->fq_path.pn_path); 160 161 dst_fqi->fq_sattr = 0; 162 } 163 164 DTRACE_SMB_2(op__NtRename__start, smb_request_t *, sr, 165 struct dirop *, &sr->arg.dirop); 166 167 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 168 } 169 170 void 171 smb_post_nt_rename(smb_request_t *sr) 172 { 173 DTRACE_SMB_1(op__NtRename__done, smb_request_t *, sr); 174 } 175 176 smb_sdrc_t 177 smb_com_nt_rename(smb_request_t *sr) 178 { 179 int rc; 180 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 181 smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 182 smb_pathname_t *src_pn = &src_fqi->fq_path; 183 smb_pathname_t *dst_pn = &dst_fqi->fq_path; 184 185 if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 186 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 187 ERRDOS, ERROR_ACCESS_DENIED); 188 return (SDRC_ERROR); 189 } 190 191 smb_pathname_init(sr, src_pn, src_pn->pn_path); 192 smb_pathname_init(sr, dst_pn, dst_pn->pn_path); 193 if (!smb_pathname_validate(sr, src_pn) || 194 !smb_pathname_validate(sr, dst_pn)) { 195 return (SDRC_ERROR); 196 } 197 198 if (smb_contains_wildcards(src_pn->pn_path)) { 199 smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD, 200 ERRDOS, ERROR_BAD_PATHNAME); 201 return (SDRC_ERROR); 202 } 203 204 switch (sr->arg.dirop.info_level) { 205 case SMB_NT_RENAME_SET_LINK_INFO: 206 rc = smb_make_link(sr, src_fqi, dst_fqi); 207 break; 208 case SMB_NT_RENAME_RENAME_FILE: 209 case SMB_NT_RENAME_MOVE_FILE: 210 rc = smb_common_rename(sr, src_fqi, dst_fqi); 211 break; 212 case SMB_NT_RENAME_MOVE_CLUSTER_INFO: 213 rc = EINVAL; 214 break; 215 default: 216 rc = EACCES; 217 break; 218 } 219 220 if (rc != 0) { 221 smb_rename_set_error(sr, rc); 222 return (SDRC_ERROR); 223 } 224 225 rc = smbsr_encode_empty_result(sr); 226 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 227 } 228 229 /* 230 * smb_nt_transact_rename 231 * 232 * Windows servers return SUCCESS without renaming file. 233 * The only check required is to check that the handle (fid) is valid. 234 */ 235 smb_sdrc_t 236 smb_nt_transact_rename(smb_request_t *sr, smb_xa_t *xa) 237 { 238 if (smb_mbc_decodef(&xa->req_param_mb, "w", &sr->smb_fid) != 0) 239 return (SDRC_ERROR); 240 241 smbsr_lookup_file(sr); 242 if (sr->fid_ofile == NULL) { 243 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 244 return (SDRC_ERROR); 245 } 246 smbsr_release_file(sr); 247 248 return (SDRC_SUCCESS); 249 } 250 251 /* 252 * smb_trans2_rename 253 * 254 * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo 255 * and Trans2_Set_PathInfo. 256 * If the new filename (dst_fqi) already exists it may be overwritten 257 * if flags == 1. 258 */ 259 int 260 smb_trans2_rename(smb_request_t *sr, smb_node_t *node, char *fname, int flags) 261 { 262 int rc = 0; 263 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 264 smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 265 smb_pathname_t *dst_pn = &dst_fqi->fq_path; 266 char *path; 267 int len; 268 269 sr->arg.dirop.flags = flags ? SMB_RENAME_FLAG_OVERWRITE : 0; 270 sr->arg.dirop.info_level = SMB_NT_RENAME_RENAME_FILE; 271 272 src_fqi->fq_sattr = SMB_SEARCH_ATTRIBUTES; 273 src_fqi->fq_fnode = node; 274 src_fqi->fq_dnode = node->n_dnode; 275 276 /* costruct and validate the dst pathname */ 277 path = smb_srm_zalloc(sr, MAXPATHLEN); 278 if (src_fqi->fq_path.pn_pname) { 279 (void) snprintf(path, MAXPATHLEN, "%s\\%s", 280 src_fqi->fq_path.pn_pname, fname); 281 } else { 282 rc = smb_node_getshrpath(node->n_dnode, sr->tid_tree, 283 path, MAXPATHLEN); 284 if (rc != 0) { 285 smb_rename_set_error(sr, rc); 286 return (-1); 287 } 288 len = strlen(path); 289 (void) snprintf(path + len, MAXPATHLEN - len, "\\%s", fname); 290 } 291 292 smb_pathname_init(sr, dst_pn, path); 293 if (!smb_pathname_validate(sr, dst_pn)) 294 return (-1); 295 296 dst_fqi->fq_dnode = node->n_dnode; 297 (void) strlcpy(dst_fqi->fq_last_comp, dst_pn->pn_fname, MAXNAMELEN); 298 299 rc = smb_common_rename(sr, src_fqi, dst_fqi); 300 if (rc != 0) { 301 smb_rename_set_error(sr, rc); 302 return (-1); 303 } 304 305 return (0); 306 } 307 308 /* 309 * smb_common_rename 310 * 311 * Common code for renaming a file. 312 * 313 * If the source and destination are identical, we go through all 314 * the checks but we don't actually do the rename. If the source 315 * and destination files differ only in case, we do a case-sensitive 316 * rename. Otherwise, we do a full case-insensitive rename. 317 * 318 * Returns errno values. 319 */ 320 static int 321 smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 322 { 323 smb_node_t *src_fnode, *src_dnode, *dst_dnode; 324 smb_node_t *dst_fnode = 0; 325 smb_node_t *tnode = 0; 326 int rc, count; 327 DWORD status; 328 char *new_name, *path; 329 330 path = dst_fqi->fq_path.pn_path; 331 332 /* Check if attempting to rename a stream - not yet supported */ 333 rc = smb_rename_check_stream(src_fqi, dst_fqi); 334 if (rc != 0) 335 return (rc); 336 337 /* The source node may already have been provided */ 338 if (src_fqi->fq_fnode) { 339 smb_node_start_crit(src_fqi->fq_fnode, RW_READER); 340 smb_node_ref(src_fqi->fq_fnode); 341 smb_node_ref(src_fqi->fq_dnode); 342 } else { 343 /* lookup and validate src node */ 344 rc = smb_rename_lookup_src(sr); 345 if (rc != 0) 346 return (rc); 347 } 348 349 src_fnode = src_fqi->fq_fnode; 350 src_dnode = src_fqi->fq_dnode; 351 tnode = sr->tid_tree->t_snode; 352 353 /* Find destination dnode and last_comp */ 354 if (dst_fqi->fq_dnode) { 355 smb_node_ref(dst_fqi->fq_dnode); 356 } else { 357 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 358 &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 359 if (rc != 0) { 360 smb_rename_release_src(sr); 361 return (rc); 362 } 363 } 364 365 dst_dnode = dst_fqi->fq_dnode; 366 new_name = dst_fqi->fq_last_comp; 367 368 /* If exact name match in same directory, we're done */ 369 if ((src_dnode == dst_dnode) && 370 (strcmp(src_fnode->od_name, new_name) == 0)) { 371 smb_rename_release_src(sr); 372 smb_node_release(dst_dnode); 373 return (0); 374 } 375 376 /* Lookup destination node */ 377 rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, 378 dst_dnode, new_name, &dst_fqi->fq_fnode); 379 380 /* If the destination node doesn't already exist, validate new_name. */ 381 if (rc == ENOENT) { 382 if (smb_is_invalid_filename(new_name)) { 383 smb_rename_release_src(sr); 384 smb_node_release(dst_dnode); 385 return (EILSEQ); /* NT_STATUS_OBJECT_NAME_INVALID */ 386 } 387 } 388 389 /* 390 * Handle case where changing case of the same directory entry. 391 * 392 * If we found the dst node in the same directory as the src node, 393 * and their names differ only in case: 394 * 395 * If the tree is case sensitive (or mixed): 396 * Do case sensitive lookup to see if exact match exists. 397 * If the exact match is the same node as src_node we're done. 398 * 399 * If the tree is case insensitive: 400 * There is currently no way to tell if the case is different 401 * or not, so do the rename (unless the specified new name was 402 * mangled). 403 */ 404 if ((rc == 0) && 405 (src_dnode == dst_dnode) && 406 (smb_strcasecmp(src_fnode->od_name, 407 dst_fqi->fq_fnode->od_name, 0) == 0)) { 408 smb_node_release(dst_fqi->fq_fnode); 409 dst_fqi->fq_fnode = NULL; 410 411 if (smb_tree_has_feature(sr->tid_tree, 412 SMB_TREE_NO_CASESENSITIVE)) { 413 if (smb_strcasecmp(src_fnode->od_name, 414 dst_fqi->fq_last_comp, 0) != 0) { 415 smb_rename_release_src(sr); 416 smb_node_release(dst_dnode); 417 return (0); 418 } 419 } else { 420 rc = smb_fsop_lookup(sr, sr->user_cr, 421 SMB_CASE_SENSITIVE, tnode, dst_dnode, new_name, 422 &dst_fqi->fq_fnode); 423 424 if ((rc == 0) && 425 (dst_fqi->fq_fnode == src_fnode)) { 426 smb_rename_release_src(sr); 427 smb_node_release(dst_fqi->fq_fnode); 428 smb_node_release(dst_dnode); 429 return (0); 430 } 431 } 432 } 433 434 if ((rc != 0) && (rc != ENOENT)) { 435 smb_rename_release_src(sr); 436 smb_node_release(dst_fqi->fq_dnode); 437 return (rc); 438 } 439 440 if (dst_fqi->fq_fnode) { 441 /* 442 * Destination already exists. Do delete checks. 443 */ 444 dst_fnode = dst_fqi->fq_fnode; 445 446 if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) { 447 smb_rename_release_src(sr); 448 smb_node_release(dst_fnode); 449 smb_node_release(dst_dnode); 450 return (EEXIST); 451 } 452 453 (void) smb_oplock_break(sr, dst_fnode, 454 SMB_OPLOCK_BREAK_TO_NONE | SMB_OPLOCK_BREAK_BATCH); 455 456 /* 457 * Wait (a little) for the oplock break to be 458 * responded to by clients closing handles. 459 * Hold node->n_lock as reader to keep new 460 * ofiles from showing up after we check. 461 */ 462 smb_node_rdlock(dst_fnode); 463 for (count = 0; count <= 12; count++) { 464 status = smb_node_delete_check(dst_fnode); 465 if (status != NT_STATUS_SHARING_VIOLATION) 466 break; 467 smb_node_unlock(dst_fnode); 468 delay(MSEC_TO_TICK(100)); 469 smb_node_rdlock(dst_fnode); 470 } 471 if (status != NT_STATUS_SUCCESS) { 472 smb_node_unlock(dst_fnode); 473 smb_rename_release_src(sr); 474 smb_node_release(dst_fnode); 475 smb_node_release(dst_dnode); 476 return (EACCES); 477 } 478 479 /* 480 * Note, the combination of these two: 481 * smb_node_rdlock(node); 482 * nbl_start_crit(node->vp, RW_READER); 483 * is equivalent to this call: 484 * smb_node_start_crit(node, RW_READER) 485 * 486 * Cleanup after this point should use: 487 * smb_node_end_crit(dst_fnode) 488 */ 489 nbl_start_crit(dst_fnode->vp, RW_READER); 490 491 /* 492 * This checks nbl_share_conflict, nbl_lock_conflict 493 */ 494 status = smb_nbl_conflict(dst_fnode, 0, UINT64_MAX, NBL_REMOVE); 495 if (status != NT_STATUS_SUCCESS) { 496 smb_node_end_crit(dst_fnode); 497 smb_rename_release_src(sr); 498 smb_node_release(dst_fnode); 499 smb_node_release(dst_dnode); 500 return (EACCES); 501 } 502 503 new_name = dst_fnode->od_name; 504 } 505 506 rc = smb_fsop_rename(sr, sr->user_cr, 507 src_dnode, src_fnode->od_name, 508 dst_dnode, new_name); 509 510 if (rc == 0) { 511 /* 512 * Note that renames in the same directory are normally 513 * delivered in {old,new} pairs, and clients expect them 514 * in that order, if both events are delivered. 515 */ 516 int a_src, a_dst; /* action codes */ 517 if (src_dnode == dst_dnode) { 518 a_src = FILE_ACTION_RENAMED_OLD_NAME; 519 a_dst = FILE_ACTION_RENAMED_NEW_NAME; 520 } else { 521 a_src = FILE_ACTION_REMOVED; 522 a_dst = FILE_ACTION_ADDED; 523 } 524 smb_node_notify_change(src_dnode, a_src, src_fnode->od_name); 525 smb_node_notify_change(dst_dnode, a_dst, new_name); 526 } 527 528 smb_rename_release_src(sr); 529 530 if (dst_fqi->fq_fnode) { 531 smb_node_end_crit(dst_fnode); 532 smb_node_release(dst_fnode); 533 } 534 smb_node_release(dst_dnode); 535 536 return (rc); 537 } 538 539 /* 540 * smb_rename_check_stream 541 * 542 * For a stream rename the dst path must begin with ':', or "\\:". 543 * We don't yet support stream rename, Return EACCES. 544 * 545 * If not a stream rename, in accordance with the above rule, 546 * it is not valid for either the src or dst to be a stream. 547 * Return EINVAL. 548 */ 549 static int 550 smb_rename_check_stream(smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 551 { 552 smb_node_t *src_fnode = src_fqi->fq_fnode; 553 char *src_path = src_fqi->fq_path.pn_path; 554 char *dst_path = dst_fqi->fq_path.pn_path; 555 556 /* We do not yet support named stream rename - ACCESS DENIED */ 557 if ((dst_path[0] == ':') || 558 ((dst_path[0] == '\\') && (dst_path[1] == ':'))) { 559 return (EACCES); 560 } 561 562 /* 563 * If not stream rename (above) neither src or dst can be 564 * a named stream. 565 */ 566 567 if (smb_is_stream_name(dst_path)) 568 return (EINVAL); 569 570 if (src_fqi->fq_fnode) { 571 if (SMB_IS_STREAM(src_fnode)) 572 return (EINVAL); 573 } else { 574 if (smb_is_stream_name(src_path)) 575 return (EINVAL); 576 } 577 578 return (0); 579 } 580 581 582 /* 583 * smb_make_link 584 * 585 * Creating a hard link (adding an additional name) for a file. 586 * 587 * If the source and destination are identical, we go through all 588 * the checks but we don't create a link. 589 * 590 * If the file is a symlink we create the hardlink on the target 591 * of the symlink (i.e. use SMB_FOLLOW_LINKS when looking up src). 592 * If the target of the symlink does not exist we fail with ENOENT. 593 * 594 * Returns errno values. 595 */ 596 static int 597 smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 598 { 599 smb_node_t *tnode; 600 char *path; 601 int rc; 602 603 /* Cannnot create link on named stream */ 604 if (smb_is_stream_name(src_fqi->fq_path.pn_path) || 605 smb_is_stream_name(dst_fqi->fq_path.pn_path)) { 606 return (EINVAL); 607 } 608 609 /* lookup and validate src node */ 610 rc = smb_rename_lookup_src(sr); 611 if (rc != 0) 612 return (rc); 613 614 /* if src and dest paths match we're done */ 615 if (smb_strcasecmp(src_fqi->fq_path.pn_path, 616 dst_fqi->fq_path.pn_path, 0) == 0) { 617 smb_rename_release_src(sr); 618 return (0); 619 } 620 621 /* find the destination dnode and last_comp */ 622 tnode = sr->tid_tree->t_snode; 623 path = dst_fqi->fq_path.pn_path; 624 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 625 &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 626 if (rc != 0) { 627 smb_rename_release_src(sr); 628 return (rc); 629 } 630 631 /* If name match in same directory, we're done */ 632 if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) && 633 (smb_strcasecmp(src_fqi->fq_fnode->od_name, 634 dst_fqi->fq_last_comp, 0) == 0)) { 635 smb_rename_release_src(sr); 636 smb_node_release(dst_fqi->fq_dnode); 637 return (0); 638 } 639 640 if (smb_is_invalid_filename(dst_fqi->fq_last_comp)) { 641 smb_rename_release_src(sr); 642 smb_node_release(dst_fqi->fq_dnode); 643 return (EILSEQ); /* NT_STATUS_INVALID_OBJECT_NAME */ 644 } 645 646 /* Lookup the destination node. It MUST NOT exist. */ 647 rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, 648 dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode); 649 if (rc == 0) { 650 smb_node_release(dst_fqi->fq_fnode); 651 rc = EEXIST; 652 } 653 if (rc != ENOENT) { 654 smb_rename_release_src(sr); 655 smb_node_release(dst_fqi->fq_dnode); 656 return (rc); 657 } 658 659 rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode, 660 dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 661 662 if (rc == 0) { 663 smb_node_notify_change(dst_fqi->fq_dnode, 664 FILE_ACTION_ADDED, dst_fqi->fq_last_comp); 665 } 666 667 smb_rename_release_src(sr); 668 smb_node_release(dst_fqi->fq_dnode); 669 return (rc); 670 } 671 672 /* 673 * smb_rename_lookup_src 674 * 675 * Lookup the src node, checking for sharing violations and 676 * breaking any existing BATCH oplock. 677 * Populate sr->arg.dirop.fqi 678 * 679 * Upon success, the dnode and fnode will have holds and the 680 * fnode will be in a critical section. These should be 681 * released using smb_rename_release_src(). 682 * 683 * Returns errno values. 684 */ 685 static int 686 smb_rename_lookup_src(smb_request_t *sr) 687 { 688 smb_node_t *src_node, *tnode; 689 DWORD status; 690 int rc; 691 int count; 692 char *path; 693 694 struct dirop *dirop = &sr->arg.dirop; 695 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 696 697 if (smb_is_stream_name(src_fqi->fq_path.pn_path)) 698 return (EINVAL); 699 700 /* Lookup the source node */ 701 tnode = sr->tid_tree->t_snode; 702 path = src_fqi->fq_path.pn_path; 703 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 704 &src_fqi->fq_dnode, src_fqi->fq_last_comp); 705 if (rc != 0) 706 return (rc); 707 708 rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, 709 src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode); 710 if (rc != 0) { 711 smb_node_release(src_fqi->fq_dnode); 712 return (rc); 713 } 714 715 /* Not valid to create hardlink for directory */ 716 if ((dirop->info_level == SMB_NT_RENAME_SET_LINK_INFO) && 717 (smb_node_is_dir(src_fqi->fq_fnode))) { 718 smb_node_release(src_fqi->fq_fnode); 719 smb_node_release(src_fqi->fq_dnode); 720 return (EISDIR); 721 } 722 723 src_node = src_fqi->fq_fnode; 724 725 rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr); 726 if (rc != 0) { 727 smb_node_release(src_fqi->fq_fnode); 728 smb_node_release(src_fqi->fq_dnode); 729 return (rc); 730 } 731 732 /* 733 * Break BATCH oplock before ofile checks. If a client 734 * has a file open, this will force a flush or close, 735 * which may affect the outcome of any share checking. 736 */ 737 (void) smb_oplock_break(sr, src_node, 738 SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH); 739 740 /* 741 * Wait (a little) for the oplock break to be 742 * responded to by clients closing handles. 743 * Hold node->n_lock as reader to keep new 744 * ofiles from showing up after we check. 745 */ 746 smb_node_rdlock(src_node); 747 for (count = 0; count <= 12; count++) { 748 status = smb_node_rename_check(src_node); 749 if (status != NT_STATUS_SHARING_VIOLATION) 750 break; 751 smb_node_unlock(src_node); 752 delay(MSEC_TO_TICK(100)); 753 smb_node_rdlock(src_node); 754 } 755 if (status != NT_STATUS_SUCCESS) { 756 smb_node_unlock(src_node); 757 smb_node_release(src_fqi->fq_fnode); 758 smb_node_release(src_fqi->fq_dnode); 759 return (EPIPE); /* = ERRbadshare */ 760 } 761 762 /* 763 * Note, the combination of these two: 764 * smb_node_rdlock(node); 765 * nbl_start_crit(node->vp, RW_READER); 766 * is equivalent to this call: 767 * smb_node_start_crit(node, RW_READER) 768 * 769 * Cleanup after this point should use: 770 * smb_node_end_crit(src_node) 771 */ 772 nbl_start_crit(src_node->vp, RW_READER); 773 774 /* 775 * This checks nbl_share_conflict, nbl_lock_conflict 776 */ 777 status = smb_nbl_conflict(src_node, 0, UINT64_MAX, NBL_RENAME); 778 if (status != NT_STATUS_SUCCESS) { 779 smb_node_end_crit(src_node); 780 smb_node_release(src_fqi->fq_fnode); 781 smb_node_release(src_fqi->fq_dnode); 782 if (status == NT_STATUS_SHARING_VIOLATION) 783 return (EPIPE); /* = ERRbadshare */ 784 return (EACCES); 785 } 786 787 /* NB: Caller expects holds on src_fqi fnode, dnode */ 788 return (0); 789 } 790 791 /* 792 * smb_rename_release_src 793 */ 794 static void 795 smb_rename_release_src(smb_request_t *sr) 796 { 797 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 798 799 smb_node_end_crit(src_fqi->fq_fnode); 800 smb_node_release(src_fqi->fq_fnode); 801 smb_node_release(src_fqi->fq_dnode); 802 } 803 804 805 static int 806 smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr) 807 { 808 smb_attr_t attr; 809 810 bzero(&attr, sizeof (attr)); 811 attr.sa_mask = SMB_AT_DOSATTR; 812 if (smb_node_getattr(sr, node, zone_kcred(), NULL, &attr) != 0) 813 return (EACCES); 814 815 if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) && 816 !(SMB_SEARCH_HIDDEN(sattr))) 817 return (ESRCH); 818 819 if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) && 820 !(SMB_SEARCH_SYSTEM(sattr))) 821 return (ESRCH); 822 823 return (0); 824 } 825 826 /* 827 * The following values are based on observed WFWG, Windows 9x, Windows NT 828 * and Windows 2000 behaviour. 829 * 830 * ERROR_FILE_EXISTS doesn't work for Windows 98 clients. 831 * 832 * Windows 95 clients don't see the problem because the target is deleted 833 * before the rename request. 834 */ 835 static void 836 smb_rename_set_error(smb_request_t *sr, int errnum) 837 { 838 static struct { 839 int errnum; 840 uint16_t errcode; 841 uint32_t status32; 842 } rc_map[] = { 843 { EEXIST, ERROR_ALREADY_EXISTS, NT_STATUS_OBJECT_NAME_COLLISION }, 844 { EPIPE, ERROR_SHARING_VIOLATION, NT_STATUS_SHARING_VIOLATION }, 845 { ENOENT, ERROR_FILE_NOT_FOUND, NT_STATUS_OBJECT_NAME_NOT_FOUND }, 846 { ESRCH, ERROR_FILE_NOT_FOUND, NT_STATUS_NO_SUCH_FILE }, 847 { EINVAL, ERROR_INVALID_PARAMETER, NT_STATUS_INVALID_PARAMETER }, 848 { EACCES, ERROR_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED }, 849 { EISDIR, ERROR_ACCESS_DENIED, NT_STATUS_FILE_IS_A_DIRECTORY }, 850 { EIO, ERROR_INTERNAL_ERROR, NT_STATUS_INTERNAL_ERROR } 851 }; 852 853 int i; 854 855 if (errnum == 0) 856 return; 857 858 for (i = 0; i < sizeof (rc_map)/sizeof (rc_map[0]); ++i) { 859 if (rc_map[i].errnum == errnum) { 860 smbsr_error(sr, rc_map[i].status32, 861 ERRDOS, rc_map[i].errcode); 862 return; 863 } 864 } 865 866 smbsr_errno(sr, errnum); 867 } 868