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_fnode, *dst_dnode; 324 smb_node_t *tnode; 325 int rc, count; 326 DWORD status; 327 char *new_name, *path; 328 329 path = dst_fqi->fq_path.pn_path; 330 331 /* Check if attempting to rename a stream - not yet supported */ 332 rc = smb_rename_check_stream(src_fqi, dst_fqi); 333 if (rc != 0) 334 return (rc); 335 336 /* The source node may already have been provided */ 337 if (src_fqi->fq_fnode) { 338 smb_node_start_crit(src_fqi->fq_fnode, RW_READER); 339 smb_node_ref(src_fqi->fq_fnode); 340 smb_node_ref(src_fqi->fq_dnode); 341 } else { 342 /* lookup and validate src node */ 343 rc = smb_rename_lookup_src(sr); 344 if (rc != 0) 345 return (rc); 346 } 347 348 src_fnode = src_fqi->fq_fnode; 349 src_dnode = src_fqi->fq_dnode; 350 tnode = sr->tid_tree->t_snode; 351 352 /* Find destination dnode and last_comp */ 353 if (dst_fqi->fq_dnode) { 354 smb_node_ref(dst_fqi->fq_dnode); 355 } else { 356 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 357 &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 358 if (rc != 0) { 359 smb_rename_release_src(sr); 360 return (rc); 361 } 362 } 363 364 dst_dnode = dst_fqi->fq_dnode; 365 new_name = dst_fqi->fq_last_comp; 366 367 /* If exact name match in same directory, we're done */ 368 if ((src_dnode == dst_dnode) && 369 (strcmp(src_fnode->od_name, new_name) == 0)) { 370 smb_rename_release_src(sr); 371 smb_node_release(dst_dnode); 372 return (0); 373 } 374 375 /* Lookup destination node */ 376 rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, 377 dst_dnode, new_name, &dst_fqi->fq_fnode); 378 379 /* If the destination node doesn't already exist, validate new_name. */ 380 if (rc == ENOENT) { 381 if (smb_is_invalid_filename(new_name)) { 382 smb_rename_release_src(sr); 383 smb_node_release(dst_dnode); 384 return (EILSEQ); /* NT_STATUS_OBJECT_NAME_INVALID */ 385 } 386 } 387 388 /* 389 * Handle case where changing case of the same directory entry. 390 * 391 * If we found the dst node in the same directory as the src node, 392 * and their names differ only in case: 393 * 394 * If the tree is case sensitive (or mixed): 395 * Do case sensitive lookup to see if exact match exists. 396 * If the exact match is the same node as src_node we're done. 397 * 398 * If the tree is case insensitive: 399 * There is currently no way to tell if the case is different 400 * or not, so do the rename (unless the specified new name was 401 * mangled). 402 */ 403 if ((rc == 0) && 404 (src_dnode == dst_dnode) && 405 (smb_strcasecmp(src_fnode->od_name, 406 dst_fqi->fq_fnode->od_name, 0) == 0)) { 407 smb_node_release(dst_fqi->fq_fnode); 408 dst_fqi->fq_fnode = NULL; 409 410 if (smb_tree_has_feature(sr->tid_tree, 411 SMB_TREE_NO_CASESENSITIVE)) { 412 if (smb_strcasecmp(src_fnode->od_name, 413 dst_fqi->fq_last_comp, 0) != 0) { 414 smb_rename_release_src(sr); 415 smb_node_release(dst_dnode); 416 return (0); 417 } 418 } else { 419 rc = smb_fsop_lookup(sr, sr->user_cr, 420 SMB_CASE_SENSITIVE, tnode, dst_dnode, new_name, 421 &dst_fqi->fq_fnode); 422 423 if ((rc == 0) && 424 (dst_fqi->fq_fnode == src_fnode)) { 425 smb_rename_release_src(sr); 426 smb_node_release(dst_fqi->fq_fnode); 427 smb_node_release(dst_dnode); 428 return (0); 429 } 430 } 431 } 432 433 if ((rc != 0) && (rc != ENOENT)) { 434 smb_rename_release_src(sr); 435 smb_node_release(dst_fqi->fq_dnode); 436 return (rc); 437 } 438 439 if (dst_fqi->fq_fnode) { 440 /* 441 * Destination already exists. Do delete checks. 442 */ 443 dst_fnode = dst_fqi->fq_fnode; 444 445 if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) { 446 smb_rename_release_src(sr); 447 smb_node_release(dst_fnode); 448 smb_node_release(dst_dnode); 449 return (EEXIST); 450 } 451 452 (void) smb_oplock_break(sr, dst_fnode, 453 SMB_OPLOCK_BREAK_TO_NONE | SMB_OPLOCK_BREAK_BATCH); 454 455 /* 456 * Wait (a little) for the oplock break to be 457 * responded to by clients closing handles. 458 * Hold node->n_lock as reader to keep new 459 * ofiles from showing up after we check. 460 */ 461 smb_node_rdlock(dst_fnode); 462 for (count = 0; count <= 12; count++) { 463 status = smb_node_delete_check(dst_fnode); 464 if (status != NT_STATUS_SHARING_VIOLATION) 465 break; 466 smb_node_unlock(dst_fnode); 467 delay(MSEC_TO_TICK(100)); 468 smb_node_rdlock(dst_fnode); 469 } 470 if (status != NT_STATUS_SUCCESS) { 471 smb_node_unlock(dst_fnode); 472 smb_rename_release_src(sr); 473 smb_node_release(dst_fnode); 474 smb_node_release(dst_dnode); 475 return (EACCES); 476 } 477 478 /* 479 * Note, the combination of these two: 480 * smb_node_rdlock(node); 481 * nbl_start_crit(node->vp, RW_READER); 482 * is equivalent to this call: 483 * smb_node_start_crit(node, RW_READER) 484 * 485 * Cleanup after this point should use: 486 * smb_node_end_crit(dst_fnode) 487 */ 488 nbl_start_crit(dst_fnode->vp, RW_READER); 489 490 /* 491 * This checks nbl_share_conflict, nbl_lock_conflict 492 */ 493 status = smb_nbl_conflict(dst_fnode, 0, UINT64_MAX, NBL_REMOVE); 494 if (status != NT_STATUS_SUCCESS) { 495 smb_node_end_crit(dst_fnode); 496 smb_rename_release_src(sr); 497 smb_node_release(dst_fnode); 498 smb_node_release(dst_dnode); 499 return (EACCES); 500 } 501 502 new_name = dst_fnode->od_name; 503 } 504 505 rc = smb_fsop_rename(sr, sr->user_cr, 506 src_dnode, src_fnode->od_name, 507 dst_dnode, new_name); 508 509 if (rc == 0) { 510 /* 511 * Note that renames in the same directory are normally 512 * delivered in {old,new} pairs, and clients expect them 513 * in that order, if both events are delivered. 514 */ 515 int a_src, a_dst; /* action codes */ 516 if (src_dnode == dst_dnode) { 517 a_src = FILE_ACTION_RENAMED_OLD_NAME; 518 a_dst = FILE_ACTION_RENAMED_NEW_NAME; 519 } else { 520 a_src = FILE_ACTION_REMOVED; 521 a_dst = FILE_ACTION_ADDED; 522 } 523 smb_node_notify_change(src_dnode, a_src, src_fnode->od_name); 524 smb_node_notify_change(dst_dnode, a_dst, new_name); 525 } 526 527 smb_rename_release_src(sr); 528 529 if (dst_fqi->fq_fnode) { 530 smb_node_end_crit(dst_fnode); 531 smb_node_release(dst_fnode); 532 } 533 smb_node_release(dst_dnode); 534 535 return (rc); 536 } 537 538 /* 539 * smb_rename_check_stream 540 * 541 * For a stream rename the dst path must begin with ':', or "\\:". 542 * We don't yet support stream rename, Return EACCES. 543 * 544 * If not a stream rename, in accordance with the above rule, 545 * it is not valid for either the src or dst to be a stream. 546 * Return EINVAL. 547 */ 548 static int 549 smb_rename_check_stream(smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 550 { 551 smb_node_t *src_fnode = src_fqi->fq_fnode; 552 char *src_path = src_fqi->fq_path.pn_path; 553 char *dst_path = dst_fqi->fq_path.pn_path; 554 555 /* We do not yet support named stream rename - ACCESS DENIED */ 556 if ((dst_path[0] == ':') || 557 ((dst_path[0] == '\\') && (dst_path[1] == ':'))) { 558 return (EACCES); 559 } 560 561 /* 562 * If not stream rename (above) neither src or dst can be 563 * a named stream. 564 */ 565 566 if (smb_is_stream_name(dst_path)) 567 return (EINVAL); 568 569 if (src_fqi->fq_fnode) { 570 if (SMB_IS_STREAM(src_fnode)) 571 return (EINVAL); 572 } else { 573 if (smb_is_stream_name(src_path)) 574 return (EINVAL); 575 } 576 577 return (0); 578 } 579 580 581 /* 582 * smb_make_link 583 * 584 * Creating a hard link (adding an additional name) for a file. 585 * 586 * If the source and destination are identical, we go through all 587 * the checks but we don't create a link. 588 * 589 * If the file is a symlink we create the hardlink on the target 590 * of the symlink (i.e. use SMB_FOLLOW_LINKS when looking up src). 591 * If the target of the symlink does not exist we fail with ENOENT. 592 * 593 * Returns errno values. 594 */ 595 static int 596 smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 597 { 598 smb_node_t *tnode; 599 char *path; 600 int rc; 601 602 /* Cannnot create link on named stream */ 603 if (smb_is_stream_name(src_fqi->fq_path.pn_path) || 604 smb_is_stream_name(dst_fqi->fq_path.pn_path)) { 605 return (EINVAL); 606 } 607 608 /* lookup and validate src node */ 609 rc = smb_rename_lookup_src(sr); 610 if (rc != 0) 611 return (rc); 612 613 /* if src and dest paths match we're done */ 614 if (smb_strcasecmp(src_fqi->fq_path.pn_path, 615 dst_fqi->fq_path.pn_path, 0) == 0) { 616 smb_rename_release_src(sr); 617 return (0); 618 } 619 620 /* find the destination dnode and last_comp */ 621 tnode = sr->tid_tree->t_snode; 622 path = dst_fqi->fq_path.pn_path; 623 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 624 &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 625 if (rc != 0) { 626 smb_rename_release_src(sr); 627 return (rc); 628 } 629 630 /* If name match in same directory, we're done */ 631 if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) && 632 (smb_strcasecmp(src_fqi->fq_fnode->od_name, 633 dst_fqi->fq_last_comp, 0) == 0)) { 634 smb_rename_release_src(sr); 635 smb_node_release(dst_fqi->fq_dnode); 636 return (0); 637 } 638 639 if (smb_is_invalid_filename(dst_fqi->fq_last_comp)) { 640 smb_rename_release_src(sr); 641 smb_node_release(dst_fqi->fq_dnode); 642 return (EILSEQ); /* NT_STATUS_INVALID_OBJECT_NAME */ 643 } 644 645 /* Lookup the destination node. It MUST NOT exist. */ 646 rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, 647 dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode); 648 if (rc == 0) { 649 smb_node_release(dst_fqi->fq_fnode); 650 rc = EEXIST; 651 } 652 if (rc != ENOENT) { 653 smb_rename_release_src(sr); 654 smb_node_release(dst_fqi->fq_dnode); 655 return (rc); 656 } 657 658 rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode, 659 dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 660 661 if (rc == 0) { 662 smb_node_notify_change(dst_fqi->fq_dnode, 663 FILE_ACTION_ADDED, dst_fqi->fq_last_comp); 664 } 665 666 smb_rename_release_src(sr); 667 smb_node_release(dst_fqi->fq_dnode); 668 return (rc); 669 } 670 671 /* 672 * smb_rename_lookup_src 673 * 674 * Lookup the src node, checking for sharing violations and 675 * breaking any existing BATCH oplock. 676 * Populate sr->arg.dirop.fqi 677 * 678 * Upon success, the dnode and fnode will have holds and the 679 * fnode will be in a critical section. These should be 680 * released using smb_rename_release_src(). 681 * 682 * Returns errno values. 683 */ 684 static int 685 smb_rename_lookup_src(smb_request_t *sr) 686 { 687 smb_node_t *src_node, *tnode; 688 DWORD status; 689 int rc; 690 int count; 691 char *path; 692 693 struct dirop *dirop = &sr->arg.dirop; 694 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 695 696 if (smb_is_stream_name(src_fqi->fq_path.pn_path)) 697 return (EINVAL); 698 699 /* Lookup the source node */ 700 tnode = sr->tid_tree->t_snode; 701 path = src_fqi->fq_path.pn_path; 702 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 703 &src_fqi->fq_dnode, src_fqi->fq_last_comp); 704 if (rc != 0) 705 return (rc); 706 707 rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, 708 src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode); 709 if (rc != 0) { 710 smb_node_release(src_fqi->fq_dnode); 711 return (rc); 712 } 713 714 /* Not valid to create hardlink for directory */ 715 if ((dirop->info_level == SMB_NT_RENAME_SET_LINK_INFO) && 716 (smb_node_is_dir(src_fqi->fq_fnode))) { 717 smb_node_release(src_fqi->fq_fnode); 718 smb_node_release(src_fqi->fq_dnode); 719 return (EISDIR); 720 } 721 722 src_node = src_fqi->fq_fnode; 723 724 rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr); 725 if (rc != 0) { 726 smb_node_release(src_fqi->fq_fnode); 727 smb_node_release(src_fqi->fq_dnode); 728 return (rc); 729 } 730 731 /* 732 * Break BATCH oplock before ofile checks. If a client 733 * has a file open, this will force a flush or close, 734 * which may affect the outcome of any share checking. 735 */ 736 (void) smb_oplock_break(sr, src_node, 737 SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH); 738 739 /* 740 * Wait (a little) for the oplock break to be 741 * responded to by clients closing handles. 742 * Hold node->n_lock as reader to keep new 743 * ofiles from showing up after we check. 744 */ 745 smb_node_rdlock(src_node); 746 for (count = 0; count <= 12; count++) { 747 status = smb_node_rename_check(src_node); 748 if (status != NT_STATUS_SHARING_VIOLATION) 749 break; 750 smb_node_unlock(src_node); 751 delay(MSEC_TO_TICK(100)); 752 smb_node_rdlock(src_node); 753 } 754 if (status != NT_STATUS_SUCCESS) { 755 smb_node_unlock(src_node); 756 smb_node_release(src_fqi->fq_fnode); 757 smb_node_release(src_fqi->fq_dnode); 758 return (EPIPE); /* = ERRbadshare */ 759 } 760 761 /* 762 * Note, the combination of these two: 763 * smb_node_rdlock(node); 764 * nbl_start_crit(node->vp, RW_READER); 765 * is equivalent to this call: 766 * smb_node_start_crit(node, RW_READER) 767 * 768 * Cleanup after this point should use: 769 * smb_node_end_crit(src_node) 770 */ 771 nbl_start_crit(src_node->vp, RW_READER); 772 773 /* 774 * This checks nbl_share_conflict, nbl_lock_conflict 775 */ 776 status = smb_nbl_conflict(src_node, 0, UINT64_MAX, NBL_RENAME); 777 if (status != NT_STATUS_SUCCESS) { 778 smb_node_end_crit(src_node); 779 smb_node_release(src_fqi->fq_fnode); 780 smb_node_release(src_fqi->fq_dnode); 781 if (status == NT_STATUS_SHARING_VIOLATION) 782 return (EPIPE); /* = ERRbadshare */ 783 return (EACCES); 784 } 785 786 /* NB: Caller expects holds on src_fqi fnode, dnode */ 787 return (0); 788 } 789 790 /* 791 * smb_rename_release_src 792 */ 793 static void 794 smb_rename_release_src(smb_request_t *sr) 795 { 796 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 797 798 smb_node_end_crit(src_fqi->fq_fnode); 799 smb_node_release(src_fqi->fq_fnode); 800 smb_node_release(src_fqi->fq_dnode); 801 } 802 803 804 static int 805 smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr) 806 { 807 smb_attr_t attr; 808 809 bzero(&attr, sizeof (attr)); 810 attr.sa_mask = SMB_AT_DOSATTR; 811 if (smb_node_getattr(sr, node, kcred, NULL, &attr) != 0) 812 return (EACCES); 813 814 if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) && 815 !(SMB_SEARCH_HIDDEN(sattr))) 816 return (ESRCH); 817 818 if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) && 819 !(SMB_SEARCH_SYSTEM(sattr))) 820 return (ESRCH); 821 822 return (0); 823 } 824 825 /* 826 * The following values are based on observed WFWG, Windows 9x, Windows NT 827 * and Windows 2000 behaviour. 828 * 829 * ERROR_FILE_EXISTS doesn't work for Windows 98 clients. 830 * 831 * Windows 95 clients don't see the problem because the target is deleted 832 * before the rename request. 833 */ 834 static void 835 smb_rename_set_error(smb_request_t *sr, int errnum) 836 { 837 static struct { 838 int errnum; 839 uint16_t errcode; 840 uint32_t status32; 841 } rc_map[] = { 842 { EEXIST, ERROR_ALREADY_EXISTS, NT_STATUS_OBJECT_NAME_COLLISION }, 843 { EPIPE, ERROR_SHARING_VIOLATION, NT_STATUS_SHARING_VIOLATION }, 844 { ENOENT, ERROR_FILE_NOT_FOUND, NT_STATUS_OBJECT_NAME_NOT_FOUND }, 845 { ESRCH, ERROR_FILE_NOT_FOUND, NT_STATUS_NO_SUCH_FILE }, 846 { EINVAL, ERROR_INVALID_PARAMETER, NT_STATUS_INVALID_PARAMETER }, 847 { EACCES, ERROR_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED }, 848 { EISDIR, ERROR_ACCESS_DENIED, NT_STATUS_FILE_IS_A_DIRECTORY }, 849 { EIO, ERROR_INTERNAL_ERROR, NT_STATUS_INTERNAL_ERROR } 850 }; 851 852 int i; 853 854 if (errnum == 0) 855 return; 856 857 for (i = 0; i < sizeof (rc_map)/sizeof (rc_map[0]); ++i) { 858 if (rc_map[i].errnum == errnum) { 859 smbsr_error(sr, rc_map[i].status32, 860 ERRDOS, rc_map[i].errcode); 861 return; 862 } 863 } 864 865 smbsr_errno(sr, errnum); 866 } 867