15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 228934SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #include <smbsrv/nterror.h> 275331Samw #include <sys/synch.h> 285331Samw #include <smbsrv/smb_incl.h> 295331Samw #include <smbsrv/smb_fsops.h> 305772Sas200622 #include <sys/nbmlock.h> 315331Samw 32*9914Samw@Sun.COM /* 33*9914Samw@Sun.COM * NT_RENAME InformationLevels: 34*9914Samw@Sun.COM * 35*9914Samw@Sun.COM * SMB_NT_RENAME_MOVE_CLUSTER_INFO Server returns invalid parameter. 36*9914Samw@Sun.COM * SMB_NT_RENAME_SET_LINK_INFO Create a hard link to a file. 37*9914Samw@Sun.COM * SMB_NT_RENAME_RENAME_FILE In-place rename of a file. 38*9914Samw@Sun.COM * SMB_NT_RENAME_MOVE_FILE Move (rename) a file. 39*9914Samw@Sun.COM */ 40*9914Samw@Sun.COM #define SMB_NT_RENAME_MOVE_CLUSTER_INFO 0x0102 41*9914Samw@Sun.COM #define SMB_NT_RENAME_SET_LINK_INFO 0x0103 42*9914Samw@Sun.COM #define SMB_NT_RENAME_RENAME_FILE 0x0104 43*9914Samw@Sun.COM #define SMB_NT_RENAME_MOVE_FILE 0x0105 44*9914Samw@Sun.COM 457961SNatalie.Li@Sun.COM static int smb_do_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *); 46*9914Samw@Sun.COM static int smb_make_link(smb_request_t *, smb_fqi_t *, smb_fqi_t *); 47*9914Samw@Sun.COM static int smb_rename_check_attr(smb_node_t *, uint16_t); 48*9914Samw@Sun.COM static void smb_rename_set_error(smb_request_t *, int); 495331Samw 505331Samw /* 515331Samw * smb_com_rename 525331Samw * 535331Samw * Rename a file. Files OldFileName must exist and NewFileName must not. 545331Samw * Both pathnames must be relative to the Tid specified in the request. 555331Samw * Open files may be renamed. 565331Samw * 575331Samw * Multiple files may be renamed in response to a single request as Rename 585331Samw * File supports wildcards in the file name (last component of the path). 595331Samw * NOTE: we don't support rename with wildcards. 605331Samw * 615331Samw * SearchAttributes indicates the attributes that the target file(s) must 625331Samw * have. If SearchAttributes is zero then only normal files are renamed. 635331Samw * If the system file or hidden attributes are specified then the rename 645331Samw * is inclusive - both the specified type(s) of files and normal files are 655331Samw * renamed. The encoding of SearchAttributes is described in section 3.10 665331Samw * - File Attribute Encoding. 675331Samw */ 686030Sjb150015 smb_sdrc_t 696139Sjb150015 smb_pre_rename(smb_request_t *sr) 706139Sjb150015 { 717961SNatalie.Li@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 727961SNatalie.Li@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 736139Sjb150015 int rc; 746139Sjb150015 759343SAfshin.Ardakani@Sun.COM if ((rc = smbsr_decode_vwv(sr, "w", &src_fqi->fq_sattr)) == 0) { 769343SAfshin.Ardakani@Sun.COM rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->fq_path.pn_path, 779343SAfshin.Ardakani@Sun.COM &dst_fqi->fq_path.pn_path); 786139Sjb150015 799343SAfshin.Ardakani@Sun.COM dst_fqi->fq_sattr = 0; 806139Sjb150015 } 816139Sjb150015 826139Sjb150015 DTRACE_SMB_2(op__Rename__start, smb_request_t *, sr, 836139Sjb150015 struct dirop *, &sr->arg.dirop); 846139Sjb150015 856139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 866139Sjb150015 } 876139Sjb150015 886139Sjb150015 void 896139Sjb150015 smb_post_rename(smb_request_t *sr) 906139Sjb150015 { 916139Sjb150015 DTRACE_SMB_1(op__Rename__done, smb_request_t *, sr); 926139Sjb150015 } 936139Sjb150015 946139Sjb150015 smb_sdrc_t 956139Sjb150015 smb_com_rename(smb_request_t *sr) 965331Samw { 977961SNatalie.Li@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 987961SNatalie.Li@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 995331Samw int rc; 1005331Samw 1015331Samw if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 1025772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 1035331Samw ERRDOS, ERROR_ACCESS_DENIED); 1046139Sjb150015 return (SDRC_ERROR); 1055331Samw } 1065331Samw 1075331Samw rc = smb_do_rename(sr, src_fqi, dst_fqi); 1085331Samw 1095331Samw if (rc != 0) { 110*9914Samw@Sun.COM smb_rename_set_error(sr, rc); 1116139Sjb150015 return (SDRC_ERROR); 1125331Samw } 1135331Samw 1146030Sjb150015 rc = smbsr_encode_empty_result(sr); 1156139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1165331Samw } 1175331Samw 1185331Samw /* 1195331Samw * smb_do_rename 1205331Samw * 121*9914Samw@Sun.COM * Common code for renaming a file. 1225331Samw * 123*9914Samw@Sun.COM * If the source and destination are identical, we go through all 124*9914Samw@Sun.COM * the checks but we don't actually do the rename. If the source 125*9914Samw@Sun.COM * and destination files differ only in case, we do a case-sensitive 126*9914Samw@Sun.COM * rename. Otherwise, we do a full case-insensitive rename. 1275331Samw * 128*9914Samw@Sun.COM * Returns errno values. 1295331Samw */ 1305331Samw static int 131*9914Samw@Sun.COM smb_do_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 1325331Samw { 1337961SNatalie.Li@Sun.COM smb_node_t *src_node; 1345331Samw char *dstname; 1355331Samw DWORD status; 1365331Samw int rc; 1375331Samw int count; 1385331Samw 139*9914Samw@Sun.COM if ((rc = smbd_fs_query(sr, src_fqi, FQM_PATH_MUST_EXIST)) != 0) 1405331Samw return (rc); 1415331Samw 1429343SAfshin.Ardakani@Sun.COM src_node = src_fqi->fq_fnode; 1435331Samw 144*9914Samw@Sun.COM if ((rc = smb_rename_check_attr(src_node, src_fqi->fq_sattr)) != 0) 145*9914Samw@Sun.COM goto rename_cleanup_nodes; 146*9914Samw@Sun.COM 1475331Samw /* 1485331Samw * Break the oplock before access checks. If a client 1495331Samw * has a file open, this will force a flush or close, 1505331Samw * which may affect the outcome of any share checking. 1515331Samw */ 1529021Samw@Sun.COM (void) smb_oplock_break(src_node, sr->session, B_FALSE); 1535331Samw 1545772Sas200622 for (count = 0; count <= 3; count++) { 1555772Sas200622 if (count) { 1565772Sas200622 smb_node_end_crit(src_node); 1575772Sas200622 delay(MSEC_TO_TICK(400)); 1585772Sas200622 } 1595772Sas200622 1605772Sas200622 smb_node_start_crit(src_node, RW_READER); 1615772Sas200622 1625772Sas200622 status = smb_node_rename_check(src_node); 1635772Sas200622 1645772Sas200622 if (status != NT_STATUS_SHARING_VIOLATION) 1655772Sas200622 break; 1665772Sas200622 } 1675772Sas200622 1685772Sas200622 if (status == NT_STATUS_SHARING_VIOLATION) { 1695772Sas200622 smb_node_end_crit(src_node); 170*9914Samw@Sun.COM rc = EPIPE; /* = ERRbadshare */ 171*9914Samw@Sun.COM goto rename_cleanup_nodes; 1725772Sas200622 } 1735772Sas200622 1747348SJose.Borrego@Sun.COM status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE); 1755772Sas200622 1765331Samw if (status != NT_STATUS_SUCCESS) { 1775772Sas200622 smb_node_end_crit(src_node); 178*9914Samw@Sun.COM rc = EACCES; 179*9914Samw@Sun.COM goto rename_cleanup_nodes; 1805331Samw } 1815331Samw 1829343SAfshin.Ardakani@Sun.COM if (utf8_strcasecmp(src_fqi->fq_path.pn_path, 1839343SAfshin.Ardakani@Sun.COM dst_fqi->fq_path.pn_path) == 0) { 1845331Samw if ((rc = smbd_fs_query(sr, dst_fqi, 0)) != 0) { 1855772Sas200622 smb_node_end_crit(src_node); 186*9914Samw@Sun.COM goto rename_cleanup_nodes; 1875331Samw } 1885331Samw 1895331Samw /* 1905331Samw * Because the fqm parameter to smbd_fs_query() was 0, 191*9914Samw@Sun.COM * dst_fqi->fq_fnode may be NULL. 1925331Samw */ 1939343SAfshin.Ardakani@Sun.COM if (dst_fqi->fq_fnode) 1949343SAfshin.Ardakani@Sun.COM smb_node_release(dst_fqi->fq_fnode); 1955331Samw 1969343SAfshin.Ardakani@Sun.COM rc = strcmp(src_fqi->fq_od_name, dst_fqi->fq_last_comp); 1975331Samw if (rc == 0) { 1985772Sas200622 smb_node_end_crit(src_node); 199*9914Samw@Sun.COM goto rename_cleanup_nodes; 2005331Samw } 2015331Samw 2025331Samw rc = smb_fsop_rename(sr, sr->user_cr, 203*9914Samw@Sun.COM src_fqi->fq_dnode, src_fqi->fq_od_name, 204*9914Samw@Sun.COM dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 2055772Sas200622 2065772Sas200622 smb_node_end_crit(src_node); 207*9914Samw@Sun.COM if (rc == 0) 208*9914Samw@Sun.COM smb_node_notify_change(dst_fqi->fq_dnode); 209*9914Samw@Sun.COM goto rename_cleanup_nodes; 2105331Samw } 2115331Samw 2125331Samw rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST); 2135331Samw if (rc != 0) { 2145772Sas200622 smb_node_end_crit(src_node); 215*9914Samw@Sun.COM goto rename_cleanup_nodes; 2165331Samw } 2175331Samw 2185331Samw /* 219*9914Samw@Sun.COM * On success of FQM_PATH_MUST_NOT_EXIST only dst_fqi->fq_dnode 220*9914Samw@Sun.COM * is valid (dst_fqi->fq_fnode is NULL). 2215331Samw */ 2225331Samw 2235331Samw /* 224*9914Samw@Sun.COM * If the source name is mangled but the source and destination 225*9914Samw@Sun.COM * on-disk names are identical, we'll use the on-disk name. 2265331Samw */ 2279343SAfshin.Ardakani@Sun.COM if ((smb_maybe_mangled_name(src_fqi->fq_last_comp)) && 2289343SAfshin.Ardakani@Sun.COM (strcmp(src_fqi->fq_last_comp, dst_fqi->fq_last_comp) == 0)) { 2299343SAfshin.Ardakani@Sun.COM dstname = src_fqi->fq_od_name; 2305331Samw } else { 2319343SAfshin.Ardakani@Sun.COM dstname = dst_fqi->fq_last_comp; 2325331Samw } 2335331Samw 2345331Samw rc = smb_fsop_rename(sr, sr->user_cr, 235*9914Samw@Sun.COM src_fqi->fq_dnode, src_fqi->fq_od_name, 236*9914Samw@Sun.COM dst_fqi->fq_dnode, dstname); 2375331Samw 2385772Sas200622 smb_node_end_crit(src_node); 2395772Sas200622 240*9914Samw@Sun.COM if (rc == 0) 241*9914Samw@Sun.COM smb_node_notify_change(dst_fqi->fq_dnode); 242*9914Samw@Sun.COM 243*9914Samw@Sun.COM rename_cleanup_nodes: 2445772Sas200622 smb_node_release(src_node); 245*9914Samw@Sun.COM smb_node_release(src_fqi->fq_dnode); 2465772Sas200622 247*9914Samw@Sun.COM if (dst_fqi->fq_dnode) 248*9914Samw@Sun.COM smb_node_release(dst_fqi->fq_dnode); 249*9914Samw@Sun.COM 250*9914Samw@Sun.COM SMB_NULL_FQI_NODES(*src_fqi); 251*9914Samw@Sun.COM SMB_NULL_FQI_NODES(*dst_fqi); 2525331Samw return (rc); 2535331Samw } 254*9914Samw@Sun.COM 255*9914Samw@Sun.COM /* 256*9914Samw@Sun.COM * smb_com_nt_rename 257*9914Samw@Sun.COM * 258*9914Samw@Sun.COM * Rename a file. Files OldFileName must exist and NewFileName must not. 259*9914Samw@Sun.COM * Both pathnames must be relative to the Tid specified in the request. 260*9914Samw@Sun.COM * Open files may be renamed. 261*9914Samw@Sun.COM * 262*9914Samw@Sun.COM * Multiple files may be renamed in response to a single request as Rename 263*9914Samw@Sun.COM * File supports wildcards in the file name (last component of the path). 264*9914Samw@Sun.COM * NOTE: we don't support rename with wildcards. 265*9914Samw@Sun.COM * 266*9914Samw@Sun.COM * SearchAttributes indicates the attributes that the target file(s) must 267*9914Samw@Sun.COM * have. If SearchAttributes is zero then only normal files are renamed. 268*9914Samw@Sun.COM * If the system file or hidden attributes are specified then the rename 269*9914Samw@Sun.COM * is inclusive - both the specified type(s) of files and normal files are 270*9914Samw@Sun.COM * renamed. The encoding of SearchAttributes is described in section 3.10 271*9914Samw@Sun.COM * - File Attribute Encoding. 272*9914Samw@Sun.COM * 273*9914Samw@Sun.COM * Client Request Description 274*9914Samw@Sun.COM * ================================= ================================== 275*9914Samw@Sun.COM * UCHAR WordCount; Count of parameter words = 4 276*9914Samw@Sun.COM * USHORT SearchAttributes; 277*9914Samw@Sun.COM * USHORT InformationLevel; 0x0103 Create a hard link 278*9914Samw@Sun.COM * 0x0104 In-place rename 279*9914Samw@Sun.COM * 0x0105 Move (rename) a file 280*9914Samw@Sun.COM * ULONG ClusterCount Servers should ignore this value 281*9914Samw@Sun.COM * USHORT ByteCount; Count of data bytes; min = 4 282*9914Samw@Sun.COM * UCHAR Buffer[]; Buffer containing: 283*9914Samw@Sun.COM * UCHAR BufferFormat1 0x04 284*9914Samw@Sun.COM * UCHAR OldFileName[] OldFileName 285*9914Samw@Sun.COM * UCHAR BufferFormat1 0x04 286*9914Samw@Sun.COM * UCHAR OldFileName[] NewFileName 287*9914Samw@Sun.COM * 288*9914Samw@Sun.COM * Server Response Description 289*9914Samw@Sun.COM * ================================= ================================== 290*9914Samw@Sun.COM * UCHAR WordCount; Count of parameter words = 0 291*9914Samw@Sun.COM * UCHAR ByteCount; Count of data bytes = 0 292*9914Samw@Sun.COM */ 293*9914Samw@Sun.COM smb_sdrc_t 294*9914Samw@Sun.COM smb_pre_nt_rename(smb_request_t *sr) 295*9914Samw@Sun.COM { 296*9914Samw@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 297*9914Samw@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 298*9914Samw@Sun.COM uint32_t clusters; 299*9914Samw@Sun.COM int rc; 300*9914Samw@Sun.COM 301*9914Samw@Sun.COM rc = smbsr_decode_vwv(sr, "wwl", &src_fqi->fq_sattr, 302*9914Samw@Sun.COM &sr->arg.dirop.info_level, &clusters); 303*9914Samw@Sun.COM if (rc == 0) { 304*9914Samw@Sun.COM rc = smbsr_decode_data(sr, "%SS", sr, 305*9914Samw@Sun.COM &src_fqi->fq_path.pn_path, &dst_fqi->fq_path.pn_path); 306*9914Samw@Sun.COM 307*9914Samw@Sun.COM dst_fqi->fq_sattr = 0; 308*9914Samw@Sun.COM } 309*9914Samw@Sun.COM 310*9914Samw@Sun.COM DTRACE_SMB_2(op__NtRename__start, smb_request_t *, sr, 311*9914Samw@Sun.COM struct dirop *, &sr->arg.dirop); 312*9914Samw@Sun.COM 313*9914Samw@Sun.COM return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 314*9914Samw@Sun.COM } 315*9914Samw@Sun.COM 316*9914Samw@Sun.COM void 317*9914Samw@Sun.COM smb_post_nt_rename(smb_request_t *sr) 318*9914Samw@Sun.COM { 319*9914Samw@Sun.COM DTRACE_SMB_1(op__NtRename__done, smb_request_t *, sr); 320*9914Samw@Sun.COM } 321*9914Samw@Sun.COM 322*9914Samw@Sun.COM smb_sdrc_t 323*9914Samw@Sun.COM smb_com_nt_rename(smb_request_t *sr) 324*9914Samw@Sun.COM { 325*9914Samw@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 326*9914Samw@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 327*9914Samw@Sun.COM int rc; 328*9914Samw@Sun.COM 329*9914Samw@Sun.COM if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 330*9914Samw@Sun.COM smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 331*9914Samw@Sun.COM ERRDOS, ERROR_ACCESS_DENIED); 332*9914Samw@Sun.COM return (SDRC_ERROR); 333*9914Samw@Sun.COM } 334*9914Samw@Sun.COM 335*9914Samw@Sun.COM if (smb_convert_wildcards(src_fqi->fq_path.pn_path) != 0) { 336*9914Samw@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD, 337*9914Samw@Sun.COM ERRDOS, ERROR_BAD_PATHNAME); 338*9914Samw@Sun.COM return (SDRC_ERROR); 339*9914Samw@Sun.COM } 340*9914Samw@Sun.COM 341*9914Samw@Sun.COM switch (sr->arg.dirop.info_level) { 342*9914Samw@Sun.COM case SMB_NT_RENAME_SET_LINK_INFO: 343*9914Samw@Sun.COM rc = smb_make_link(sr, src_fqi, dst_fqi); 344*9914Samw@Sun.COM break; 345*9914Samw@Sun.COM case SMB_NT_RENAME_RENAME_FILE: 346*9914Samw@Sun.COM case SMB_NT_RENAME_MOVE_FILE: 347*9914Samw@Sun.COM rc = smb_do_rename(sr, src_fqi, dst_fqi); 348*9914Samw@Sun.COM break; 349*9914Samw@Sun.COM case SMB_NT_RENAME_MOVE_CLUSTER_INFO: 350*9914Samw@Sun.COM rc = EINVAL; 351*9914Samw@Sun.COM break; 352*9914Samw@Sun.COM default: 353*9914Samw@Sun.COM rc = EACCES; 354*9914Samw@Sun.COM break; 355*9914Samw@Sun.COM } 356*9914Samw@Sun.COM 357*9914Samw@Sun.COM if (rc != 0) { 358*9914Samw@Sun.COM smb_rename_set_error(sr, rc); 359*9914Samw@Sun.COM return (SDRC_ERROR); 360*9914Samw@Sun.COM } 361*9914Samw@Sun.COM 362*9914Samw@Sun.COM rc = smbsr_encode_empty_result(sr); 363*9914Samw@Sun.COM return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 364*9914Samw@Sun.COM } 365*9914Samw@Sun.COM 366*9914Samw@Sun.COM /* 367*9914Samw@Sun.COM * smb_make_link 368*9914Samw@Sun.COM * 369*9914Samw@Sun.COM * Common code for creating a hard link (adding an additional name 370*9914Samw@Sun.COM * for a file. 371*9914Samw@Sun.COM * 372*9914Samw@Sun.COM * If the source and destination are identical, we go through all 373*9914Samw@Sun.COM * the checks but we don't create a link. 374*9914Samw@Sun.COM * 375*9914Samw@Sun.COM * Returns errno values. 376*9914Samw@Sun.COM */ 377*9914Samw@Sun.COM static int 378*9914Samw@Sun.COM smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 379*9914Samw@Sun.COM { 380*9914Samw@Sun.COM smb_node_t *src_fnode; 381*9914Samw@Sun.COM DWORD status; 382*9914Samw@Sun.COM int rc; 383*9914Samw@Sun.COM int count; 384*9914Samw@Sun.COM 385*9914Samw@Sun.COM if ((rc = smbd_fs_query(sr, src_fqi, FQM_PATH_MUST_EXIST)) != 0) 386*9914Samw@Sun.COM return (rc); 387*9914Samw@Sun.COM 388*9914Samw@Sun.COM src_fnode = src_fqi->fq_fnode; 389*9914Samw@Sun.COM 390*9914Samw@Sun.COM if ((rc = smb_rename_check_attr(src_fnode, src_fqi->fq_sattr)) != 0) 391*9914Samw@Sun.COM goto link_cleanup_nodes; 392*9914Samw@Sun.COM 393*9914Samw@Sun.COM /* 394*9914Samw@Sun.COM * Break the oplock before access checks. If a client 395*9914Samw@Sun.COM * has a file open, this will force a flush or close, 396*9914Samw@Sun.COM * which may affect the outcome of any share checking. 397*9914Samw@Sun.COM */ 398*9914Samw@Sun.COM (void) smb_oplock_break(src_fnode, sr->session, B_FALSE); 399*9914Samw@Sun.COM 400*9914Samw@Sun.COM for (count = 0; count <= 3; count++) { 401*9914Samw@Sun.COM if (count) { 402*9914Samw@Sun.COM smb_node_end_crit(src_fnode); 403*9914Samw@Sun.COM delay(MSEC_TO_TICK(400)); 404*9914Samw@Sun.COM } 405*9914Samw@Sun.COM 406*9914Samw@Sun.COM smb_node_start_crit(src_fnode, RW_READER); 407*9914Samw@Sun.COM status = smb_node_rename_check(src_fnode); 408*9914Samw@Sun.COM 409*9914Samw@Sun.COM if (status != NT_STATUS_SHARING_VIOLATION) 410*9914Samw@Sun.COM break; 411*9914Samw@Sun.COM } 412*9914Samw@Sun.COM 413*9914Samw@Sun.COM if (status == NT_STATUS_SHARING_VIOLATION) { 414*9914Samw@Sun.COM smb_node_end_crit(src_fnode); 415*9914Samw@Sun.COM rc = EPIPE; /* = ERRbadshare */ 416*9914Samw@Sun.COM goto link_cleanup_nodes; 417*9914Samw@Sun.COM } 418*9914Samw@Sun.COM 419*9914Samw@Sun.COM status = smb_range_check(sr, src_fnode, 0, UINT64_MAX, B_TRUE); 420*9914Samw@Sun.COM 421*9914Samw@Sun.COM if (status != NT_STATUS_SUCCESS) { 422*9914Samw@Sun.COM smb_node_end_crit(src_fnode); 423*9914Samw@Sun.COM rc = EACCES; 424*9914Samw@Sun.COM goto link_cleanup_nodes; 425*9914Samw@Sun.COM } 426*9914Samw@Sun.COM 427*9914Samw@Sun.COM if (utf8_strcasecmp(src_fqi->fq_path.pn_path, 428*9914Samw@Sun.COM dst_fqi->fq_path.pn_path) == 0) { 429*9914Samw@Sun.COM smb_node_end_crit(src_fnode); 430*9914Samw@Sun.COM rc = 0; 431*9914Samw@Sun.COM goto link_cleanup_nodes; 432*9914Samw@Sun.COM } 433*9914Samw@Sun.COM 434*9914Samw@Sun.COM rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST); 435*9914Samw@Sun.COM if (rc != 0) { 436*9914Samw@Sun.COM smb_node_end_crit(src_fnode); 437*9914Samw@Sun.COM goto link_cleanup_nodes; 438*9914Samw@Sun.COM } 439*9914Samw@Sun.COM 440*9914Samw@Sun.COM /* 441*9914Samw@Sun.COM * On success of FQM_PATH_MUST_NOT_EXIST only dst_fqi->fq_dnode 442*9914Samw@Sun.COM * is valid (dst_fqi->fq_fnode is NULL). 443*9914Samw@Sun.COM */ 444*9914Samw@Sun.COM rc = smb_fsop_link(sr, sr->user_cr, dst_fqi->fq_dnode, src_fnode, 445*9914Samw@Sun.COM dst_fqi->fq_last_comp); 446*9914Samw@Sun.COM 447*9914Samw@Sun.COM smb_node_end_crit(src_fnode); 448*9914Samw@Sun.COM 449*9914Samw@Sun.COM if (rc == 0) 450*9914Samw@Sun.COM smb_node_notify_change(dst_fqi->fq_dnode); 451*9914Samw@Sun.COM 452*9914Samw@Sun.COM link_cleanup_nodes: 453*9914Samw@Sun.COM smb_node_release(src_fnode); 454*9914Samw@Sun.COM smb_node_release(src_fqi->fq_dnode); 455*9914Samw@Sun.COM 456*9914Samw@Sun.COM if (dst_fqi->fq_dnode) 457*9914Samw@Sun.COM smb_node_release(dst_fqi->fq_dnode); 458*9914Samw@Sun.COM 459*9914Samw@Sun.COM SMB_NULL_FQI_NODES(*src_fqi); 460*9914Samw@Sun.COM SMB_NULL_FQI_NODES(*dst_fqi); 461*9914Samw@Sun.COM return (rc); 462*9914Samw@Sun.COM } 463*9914Samw@Sun.COM 464*9914Samw@Sun.COM static int 465*9914Samw@Sun.COM smb_rename_check_attr(smb_node_t *node, uint16_t sattr) 466*9914Samw@Sun.COM { 467*9914Samw@Sun.COM uint16_t dosattr = smb_node_get_dosattr(node); 468*9914Samw@Sun.COM 469*9914Samw@Sun.COM if ((dosattr & FILE_ATTRIBUTE_HIDDEN) && !(SMB_SEARCH_HIDDEN(sattr))) 470*9914Samw@Sun.COM return (ESRCH); 471*9914Samw@Sun.COM 472*9914Samw@Sun.COM if ((dosattr & FILE_ATTRIBUTE_SYSTEM) && !(SMB_SEARCH_SYSTEM(sattr))) 473*9914Samw@Sun.COM return (ESRCH); 474*9914Samw@Sun.COM 475*9914Samw@Sun.COM return (0); 476*9914Samw@Sun.COM } 477*9914Samw@Sun.COM 478*9914Samw@Sun.COM /* 479*9914Samw@Sun.COM * The following values are based on observed WFWG, Windows 9x, Windows NT 480*9914Samw@Sun.COM * and Windows 2000 behaviour. 481*9914Samw@Sun.COM * 482*9914Samw@Sun.COM * ERROR_FILE_EXISTS doesn't work for Windows 98 clients. 483*9914Samw@Sun.COM * 484*9914Samw@Sun.COM * Windows 95 clients don't see the problem because the target is deleted 485*9914Samw@Sun.COM * before the rename request. 486*9914Samw@Sun.COM */ 487*9914Samw@Sun.COM static void 488*9914Samw@Sun.COM smb_rename_set_error(smb_request_t *sr, int errnum) 489*9914Samw@Sun.COM { 490*9914Samw@Sun.COM static struct { 491*9914Samw@Sun.COM int errnum; 492*9914Samw@Sun.COM uint16_t errcode; 493*9914Samw@Sun.COM uint32_t status32; 494*9914Samw@Sun.COM } rc_map[] = { 495*9914Samw@Sun.COM { EEXIST, ERROR_ALREADY_EXISTS, NT_STATUS_OBJECT_NAME_COLLISION }, 496*9914Samw@Sun.COM { EPIPE, ERROR_SHARING_VIOLATION, NT_STATUS_SHARING_VIOLATION }, 497*9914Samw@Sun.COM { ENOENT, ERROR_FILE_NOT_FOUND, NT_STATUS_OBJECT_NAME_NOT_FOUND }, 498*9914Samw@Sun.COM { ESRCH, ERROR_FILE_NOT_FOUND, NT_STATUS_NO_SUCH_FILE }, 499*9914Samw@Sun.COM { EINVAL, ERROR_INVALID_PARAMETER, NT_STATUS_INVALID_PARAMETER }, 500*9914Samw@Sun.COM { EACCES, ERROR_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED } 501*9914Samw@Sun.COM }; 502*9914Samw@Sun.COM 503*9914Samw@Sun.COM int i; 504*9914Samw@Sun.COM 505*9914Samw@Sun.COM if (errnum == 0) 506*9914Samw@Sun.COM return; 507*9914Samw@Sun.COM 508*9914Samw@Sun.COM for (i = 0; i < sizeof (rc_map)/sizeof (rc_map[0]); ++i) { 509*9914Samw@Sun.COM if (rc_map[i].errnum == errnum) { 510*9914Samw@Sun.COM smbsr_error(sr, rc_map[i].status32, 511*9914Samw@Sun.COM ERRDOS, rc_map[i].errcode); 512*9914Samw@Sun.COM return; 513*9914Samw@Sun.COM } 514*9914Samw@Sun.COM } 515*9914Samw@Sun.COM 516*9914Samw@Sun.COM smbsr_errno(sr, errnum); 517*9914Samw@Sun.COM } 518