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 329914Samw@Sun.COM /* 339914Samw@Sun.COM * NT_RENAME InformationLevels: 349914Samw@Sun.COM * 359914Samw@Sun.COM * SMB_NT_RENAME_MOVE_CLUSTER_INFO Server returns invalid parameter. 369914Samw@Sun.COM * SMB_NT_RENAME_SET_LINK_INFO Create a hard link to a file. 379914Samw@Sun.COM * SMB_NT_RENAME_RENAME_FILE In-place rename of a file. 389914Samw@Sun.COM * SMB_NT_RENAME_MOVE_FILE Move (rename) a file. 399914Samw@Sun.COM */ 409914Samw@Sun.COM #define SMB_NT_RENAME_MOVE_CLUSTER_INFO 0x0102 419914Samw@Sun.COM #define SMB_NT_RENAME_SET_LINK_INFO 0x0103 429914Samw@Sun.COM #define SMB_NT_RENAME_RENAME_FILE 0x0104 439914Samw@Sun.COM #define SMB_NT_RENAME_MOVE_FILE 0x0105 449914Samw@Sun.COM 457961SNatalie.Li@Sun.COM static int smb_do_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *); 469914Samw@Sun.COM static int smb_make_link(smb_request_t *, smb_fqi_t *, smb_fqi_t *); 47*10001SJoyce.McIntosh@Sun.COM static int smb_rename_check_attr(smb_request_t *, smb_node_t *, uint16_t); 489914Samw@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) { 1109914Samw@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 * 1219914Samw@Sun.COM * Common code for renaming a file. 1225331Samw * 1239914Samw@Sun.COM * If the source and destination are identical, we go through all 1249914Samw@Sun.COM * the checks but we don't actually do the rename. If the source 1259914Samw@Sun.COM * and destination files differ only in case, we do a case-sensitive 1269914Samw@Sun.COM * rename. Otherwise, we do a full case-insensitive rename. 1275331Samw * 1289914Samw@Sun.COM * Returns errno values. 1295331Samw */ 1305331Samw static int 1319914Samw@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 1399914Samw@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*10001SJoyce.McIntosh@Sun.COM if ((rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr)) != 0) 1459914Samw@Sun.COM goto rename_cleanup_nodes; 1469914Samw@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); 1709914Samw@Sun.COM rc = EPIPE; /* = ERRbadshare */ 1719914Samw@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); 1789914Samw@Sun.COM rc = EACCES; 1799914Samw@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); 1869914Samw@Sun.COM goto rename_cleanup_nodes; 1875331Samw } 1885331Samw 1895331Samw /* 1905331Samw * Because the fqm parameter to smbd_fs_query() was 0, 1919914Samw@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); 1999914Samw@Sun.COM goto rename_cleanup_nodes; 2005331Samw } 2015331Samw 2025331Samw rc = smb_fsop_rename(sr, sr->user_cr, 2039914Samw@Sun.COM src_fqi->fq_dnode, src_fqi->fq_od_name, 2049914Samw@Sun.COM dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 2055772Sas200622 2065772Sas200622 smb_node_end_crit(src_node); 2079914Samw@Sun.COM if (rc == 0) 2089914Samw@Sun.COM smb_node_notify_change(dst_fqi->fq_dnode); 2099914Samw@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); 2159914Samw@Sun.COM goto rename_cleanup_nodes; 2165331Samw } 2175331Samw 2185331Samw /* 2199914Samw@Sun.COM * On success of FQM_PATH_MUST_NOT_EXIST only dst_fqi->fq_dnode 2209914Samw@Sun.COM * is valid (dst_fqi->fq_fnode is NULL). 2215331Samw */ 2225331Samw 2235331Samw /* 2249914Samw@Sun.COM * If the source name is mangled but the source and destination 2259914Samw@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, 2359914Samw@Sun.COM src_fqi->fq_dnode, src_fqi->fq_od_name, 2369914Samw@Sun.COM dst_fqi->fq_dnode, dstname); 2375331Samw 2385772Sas200622 smb_node_end_crit(src_node); 2395772Sas200622 2409914Samw@Sun.COM if (rc == 0) 2419914Samw@Sun.COM smb_node_notify_change(dst_fqi->fq_dnode); 2429914Samw@Sun.COM 2439914Samw@Sun.COM rename_cleanup_nodes: 2445772Sas200622 smb_node_release(src_node); 2459914Samw@Sun.COM smb_node_release(src_fqi->fq_dnode); 2465772Sas200622 2479914Samw@Sun.COM if (dst_fqi->fq_dnode) 2489914Samw@Sun.COM smb_node_release(dst_fqi->fq_dnode); 2499914Samw@Sun.COM 2509914Samw@Sun.COM SMB_NULL_FQI_NODES(*src_fqi); 2519914Samw@Sun.COM SMB_NULL_FQI_NODES(*dst_fqi); 2525331Samw return (rc); 2535331Samw } 2549914Samw@Sun.COM 2559914Samw@Sun.COM /* 2569914Samw@Sun.COM * smb_com_nt_rename 2579914Samw@Sun.COM * 2589914Samw@Sun.COM * Rename a file. Files OldFileName must exist and NewFileName must not. 2599914Samw@Sun.COM * Both pathnames must be relative to the Tid specified in the request. 2609914Samw@Sun.COM * Open files may be renamed. 2619914Samw@Sun.COM * 2629914Samw@Sun.COM * Multiple files may be renamed in response to a single request as Rename 2639914Samw@Sun.COM * File supports wildcards in the file name (last component of the path). 2649914Samw@Sun.COM * NOTE: we don't support rename with wildcards. 2659914Samw@Sun.COM * 2669914Samw@Sun.COM * SearchAttributes indicates the attributes that the target file(s) must 2679914Samw@Sun.COM * have. If SearchAttributes is zero then only normal files are renamed. 2689914Samw@Sun.COM * If the system file or hidden attributes are specified then the rename 2699914Samw@Sun.COM * is inclusive - both the specified type(s) of files and normal files are 2709914Samw@Sun.COM * renamed. The encoding of SearchAttributes is described in section 3.10 2719914Samw@Sun.COM * - File Attribute Encoding. 2729914Samw@Sun.COM * 2739914Samw@Sun.COM * Client Request Description 2749914Samw@Sun.COM * ================================= ================================== 2759914Samw@Sun.COM * UCHAR WordCount; Count of parameter words = 4 2769914Samw@Sun.COM * USHORT SearchAttributes; 2779914Samw@Sun.COM * USHORT InformationLevel; 0x0103 Create a hard link 2789914Samw@Sun.COM * 0x0104 In-place rename 2799914Samw@Sun.COM * 0x0105 Move (rename) a file 2809914Samw@Sun.COM * ULONG ClusterCount Servers should ignore this value 2819914Samw@Sun.COM * USHORT ByteCount; Count of data bytes; min = 4 2829914Samw@Sun.COM * UCHAR Buffer[]; Buffer containing: 2839914Samw@Sun.COM * UCHAR BufferFormat1 0x04 2849914Samw@Sun.COM * UCHAR OldFileName[] OldFileName 2859914Samw@Sun.COM * UCHAR BufferFormat1 0x04 2869914Samw@Sun.COM * UCHAR OldFileName[] NewFileName 2879914Samw@Sun.COM * 2889914Samw@Sun.COM * Server Response Description 2899914Samw@Sun.COM * ================================= ================================== 2909914Samw@Sun.COM * UCHAR WordCount; Count of parameter words = 0 2919914Samw@Sun.COM * UCHAR ByteCount; Count of data bytes = 0 2929914Samw@Sun.COM */ 2939914Samw@Sun.COM smb_sdrc_t 2949914Samw@Sun.COM smb_pre_nt_rename(smb_request_t *sr) 2959914Samw@Sun.COM { 2969914Samw@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 2979914Samw@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 2989914Samw@Sun.COM uint32_t clusters; 2999914Samw@Sun.COM int rc; 3009914Samw@Sun.COM 3019914Samw@Sun.COM rc = smbsr_decode_vwv(sr, "wwl", &src_fqi->fq_sattr, 3029914Samw@Sun.COM &sr->arg.dirop.info_level, &clusters); 3039914Samw@Sun.COM if (rc == 0) { 3049914Samw@Sun.COM rc = smbsr_decode_data(sr, "%SS", sr, 3059914Samw@Sun.COM &src_fqi->fq_path.pn_path, &dst_fqi->fq_path.pn_path); 3069914Samw@Sun.COM 3079914Samw@Sun.COM dst_fqi->fq_sattr = 0; 3089914Samw@Sun.COM } 3099914Samw@Sun.COM 3109914Samw@Sun.COM DTRACE_SMB_2(op__NtRename__start, smb_request_t *, sr, 3119914Samw@Sun.COM struct dirop *, &sr->arg.dirop); 3129914Samw@Sun.COM 3139914Samw@Sun.COM return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3149914Samw@Sun.COM } 3159914Samw@Sun.COM 3169914Samw@Sun.COM void 3179914Samw@Sun.COM smb_post_nt_rename(smb_request_t *sr) 3189914Samw@Sun.COM { 3199914Samw@Sun.COM DTRACE_SMB_1(op__NtRename__done, smb_request_t *, sr); 3209914Samw@Sun.COM } 3219914Samw@Sun.COM 3229914Samw@Sun.COM smb_sdrc_t 3239914Samw@Sun.COM smb_com_nt_rename(smb_request_t *sr) 3249914Samw@Sun.COM { 3259914Samw@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 3269914Samw@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 3279914Samw@Sun.COM int rc; 3289914Samw@Sun.COM 3299914Samw@Sun.COM if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 3309914Samw@Sun.COM smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 3319914Samw@Sun.COM ERRDOS, ERROR_ACCESS_DENIED); 3329914Samw@Sun.COM return (SDRC_ERROR); 3339914Samw@Sun.COM } 3349914Samw@Sun.COM 3359914Samw@Sun.COM if (smb_convert_wildcards(src_fqi->fq_path.pn_path) != 0) { 3369914Samw@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD, 3379914Samw@Sun.COM ERRDOS, ERROR_BAD_PATHNAME); 3389914Samw@Sun.COM return (SDRC_ERROR); 3399914Samw@Sun.COM } 3409914Samw@Sun.COM 3419914Samw@Sun.COM switch (sr->arg.dirop.info_level) { 3429914Samw@Sun.COM case SMB_NT_RENAME_SET_LINK_INFO: 3439914Samw@Sun.COM rc = smb_make_link(sr, src_fqi, dst_fqi); 3449914Samw@Sun.COM break; 3459914Samw@Sun.COM case SMB_NT_RENAME_RENAME_FILE: 3469914Samw@Sun.COM case SMB_NT_RENAME_MOVE_FILE: 3479914Samw@Sun.COM rc = smb_do_rename(sr, src_fqi, dst_fqi); 3489914Samw@Sun.COM break; 3499914Samw@Sun.COM case SMB_NT_RENAME_MOVE_CLUSTER_INFO: 3509914Samw@Sun.COM rc = EINVAL; 3519914Samw@Sun.COM break; 3529914Samw@Sun.COM default: 3539914Samw@Sun.COM rc = EACCES; 3549914Samw@Sun.COM break; 3559914Samw@Sun.COM } 3569914Samw@Sun.COM 3579914Samw@Sun.COM if (rc != 0) { 3589914Samw@Sun.COM smb_rename_set_error(sr, rc); 3599914Samw@Sun.COM return (SDRC_ERROR); 3609914Samw@Sun.COM } 3619914Samw@Sun.COM 3629914Samw@Sun.COM rc = smbsr_encode_empty_result(sr); 3639914Samw@Sun.COM return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3649914Samw@Sun.COM } 3659914Samw@Sun.COM 3669914Samw@Sun.COM /* 3679914Samw@Sun.COM * smb_make_link 3689914Samw@Sun.COM * 3699914Samw@Sun.COM * Common code for creating a hard link (adding an additional name 3709914Samw@Sun.COM * for a file. 3719914Samw@Sun.COM * 3729914Samw@Sun.COM * If the source and destination are identical, we go through all 3739914Samw@Sun.COM * the checks but we don't create a link. 3749914Samw@Sun.COM * 3759914Samw@Sun.COM * Returns errno values. 3769914Samw@Sun.COM */ 3779914Samw@Sun.COM static int 3789914Samw@Sun.COM smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 3799914Samw@Sun.COM { 3809914Samw@Sun.COM smb_node_t *src_fnode; 3819914Samw@Sun.COM DWORD status; 3829914Samw@Sun.COM int rc; 3839914Samw@Sun.COM int count; 3849914Samw@Sun.COM 3859914Samw@Sun.COM if ((rc = smbd_fs_query(sr, src_fqi, FQM_PATH_MUST_EXIST)) != 0) 3869914Samw@Sun.COM return (rc); 3879914Samw@Sun.COM 3889914Samw@Sun.COM src_fnode = src_fqi->fq_fnode; 3899914Samw@Sun.COM 390*10001SJoyce.McIntosh@Sun.COM if ((rc = smb_rename_check_attr(sr, src_fnode, src_fqi->fq_sattr)) != 0) 3919914Samw@Sun.COM goto link_cleanup_nodes; 3929914Samw@Sun.COM 3939914Samw@Sun.COM /* 3949914Samw@Sun.COM * Break the oplock before access checks. If a client 3959914Samw@Sun.COM * has a file open, this will force a flush or close, 3969914Samw@Sun.COM * which may affect the outcome of any share checking. 3979914Samw@Sun.COM */ 3989914Samw@Sun.COM (void) smb_oplock_break(src_fnode, sr->session, B_FALSE); 3999914Samw@Sun.COM 4009914Samw@Sun.COM for (count = 0; count <= 3; count++) { 4019914Samw@Sun.COM if (count) { 4029914Samw@Sun.COM smb_node_end_crit(src_fnode); 4039914Samw@Sun.COM delay(MSEC_TO_TICK(400)); 4049914Samw@Sun.COM } 4059914Samw@Sun.COM 4069914Samw@Sun.COM smb_node_start_crit(src_fnode, RW_READER); 4079914Samw@Sun.COM status = smb_node_rename_check(src_fnode); 4089914Samw@Sun.COM 4099914Samw@Sun.COM if (status != NT_STATUS_SHARING_VIOLATION) 4109914Samw@Sun.COM break; 4119914Samw@Sun.COM } 4129914Samw@Sun.COM 4139914Samw@Sun.COM if (status == NT_STATUS_SHARING_VIOLATION) { 4149914Samw@Sun.COM smb_node_end_crit(src_fnode); 4159914Samw@Sun.COM rc = EPIPE; /* = ERRbadshare */ 4169914Samw@Sun.COM goto link_cleanup_nodes; 4179914Samw@Sun.COM } 4189914Samw@Sun.COM 4199914Samw@Sun.COM status = smb_range_check(sr, src_fnode, 0, UINT64_MAX, B_TRUE); 4209914Samw@Sun.COM 4219914Samw@Sun.COM if (status != NT_STATUS_SUCCESS) { 4229914Samw@Sun.COM smb_node_end_crit(src_fnode); 4239914Samw@Sun.COM rc = EACCES; 4249914Samw@Sun.COM goto link_cleanup_nodes; 4259914Samw@Sun.COM } 4269914Samw@Sun.COM 4279914Samw@Sun.COM if (utf8_strcasecmp(src_fqi->fq_path.pn_path, 4289914Samw@Sun.COM dst_fqi->fq_path.pn_path) == 0) { 4299914Samw@Sun.COM smb_node_end_crit(src_fnode); 4309914Samw@Sun.COM rc = 0; 4319914Samw@Sun.COM goto link_cleanup_nodes; 4329914Samw@Sun.COM } 4339914Samw@Sun.COM 4349914Samw@Sun.COM rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST); 4359914Samw@Sun.COM if (rc != 0) { 4369914Samw@Sun.COM smb_node_end_crit(src_fnode); 4379914Samw@Sun.COM goto link_cleanup_nodes; 4389914Samw@Sun.COM } 4399914Samw@Sun.COM 4409914Samw@Sun.COM /* 4419914Samw@Sun.COM * On success of FQM_PATH_MUST_NOT_EXIST only dst_fqi->fq_dnode 4429914Samw@Sun.COM * is valid (dst_fqi->fq_fnode is NULL). 4439914Samw@Sun.COM */ 4449914Samw@Sun.COM rc = smb_fsop_link(sr, sr->user_cr, dst_fqi->fq_dnode, src_fnode, 4459914Samw@Sun.COM dst_fqi->fq_last_comp); 4469914Samw@Sun.COM 4479914Samw@Sun.COM smb_node_end_crit(src_fnode); 4489914Samw@Sun.COM 4499914Samw@Sun.COM if (rc == 0) 4509914Samw@Sun.COM smb_node_notify_change(dst_fqi->fq_dnode); 4519914Samw@Sun.COM 4529914Samw@Sun.COM link_cleanup_nodes: 4539914Samw@Sun.COM smb_node_release(src_fnode); 4549914Samw@Sun.COM smb_node_release(src_fqi->fq_dnode); 4559914Samw@Sun.COM 4569914Samw@Sun.COM if (dst_fqi->fq_dnode) 4579914Samw@Sun.COM smb_node_release(dst_fqi->fq_dnode); 4589914Samw@Sun.COM 4599914Samw@Sun.COM SMB_NULL_FQI_NODES(*src_fqi); 4609914Samw@Sun.COM SMB_NULL_FQI_NODES(*dst_fqi); 4619914Samw@Sun.COM return (rc); 4629914Samw@Sun.COM } 4639914Samw@Sun.COM 4649914Samw@Sun.COM static int 465*10001SJoyce.McIntosh@Sun.COM smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr) 4669914Samw@Sun.COM { 467*10001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 4689914Samw@Sun.COM 469*10001SJoyce.McIntosh@Sun.COM if (smb_node_getattr(sr, node, &attr) != 0) 470*10001SJoyce.McIntosh@Sun.COM return (EIO); 471*10001SJoyce.McIntosh@Sun.COM 472*10001SJoyce.McIntosh@Sun.COM if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) && 473*10001SJoyce.McIntosh@Sun.COM !(SMB_SEARCH_HIDDEN(sattr))) 4749914Samw@Sun.COM return (ESRCH); 4759914Samw@Sun.COM 476*10001SJoyce.McIntosh@Sun.COM if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) && 477*10001SJoyce.McIntosh@Sun.COM !(SMB_SEARCH_SYSTEM(sattr))) 4789914Samw@Sun.COM return (ESRCH); 4799914Samw@Sun.COM 4809914Samw@Sun.COM return (0); 4819914Samw@Sun.COM } 4829914Samw@Sun.COM 4839914Samw@Sun.COM /* 4849914Samw@Sun.COM * The following values are based on observed WFWG, Windows 9x, Windows NT 4859914Samw@Sun.COM * and Windows 2000 behaviour. 4869914Samw@Sun.COM * 4879914Samw@Sun.COM * ERROR_FILE_EXISTS doesn't work for Windows 98 clients. 4889914Samw@Sun.COM * 4899914Samw@Sun.COM * Windows 95 clients don't see the problem because the target is deleted 4909914Samw@Sun.COM * before the rename request. 4919914Samw@Sun.COM */ 4929914Samw@Sun.COM static void 4939914Samw@Sun.COM smb_rename_set_error(smb_request_t *sr, int errnum) 4949914Samw@Sun.COM { 4959914Samw@Sun.COM static struct { 4969914Samw@Sun.COM int errnum; 4979914Samw@Sun.COM uint16_t errcode; 4989914Samw@Sun.COM uint32_t status32; 4999914Samw@Sun.COM } rc_map[] = { 5009914Samw@Sun.COM { EEXIST, ERROR_ALREADY_EXISTS, NT_STATUS_OBJECT_NAME_COLLISION }, 5019914Samw@Sun.COM { EPIPE, ERROR_SHARING_VIOLATION, NT_STATUS_SHARING_VIOLATION }, 5029914Samw@Sun.COM { ENOENT, ERROR_FILE_NOT_FOUND, NT_STATUS_OBJECT_NAME_NOT_FOUND }, 5039914Samw@Sun.COM { ESRCH, ERROR_FILE_NOT_FOUND, NT_STATUS_NO_SUCH_FILE }, 5049914Samw@Sun.COM { EINVAL, ERROR_INVALID_PARAMETER, NT_STATUS_INVALID_PARAMETER }, 505*10001SJoyce.McIntosh@Sun.COM { EACCES, ERROR_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED }, 506*10001SJoyce.McIntosh@Sun.COM { EIO, ERROR_INTERNAL_ERROR, NT_STATUS_INTERNAL_ERROR } 5079914Samw@Sun.COM }; 5089914Samw@Sun.COM 5099914Samw@Sun.COM int i; 5109914Samw@Sun.COM 5119914Samw@Sun.COM if (errnum == 0) 5129914Samw@Sun.COM return; 5139914Samw@Sun.COM 5149914Samw@Sun.COM for (i = 0; i < sizeof (rc_map)/sizeof (rc_map[0]); ++i) { 5159914Samw@Sun.COM if (rc_map[i].errnum == errnum) { 5169914Samw@Sun.COM smbsr_error(sr, rc_map[i].status32, 5179914Samw@Sun.COM ERRDOS, rc_map[i].errcode); 5189914Samw@Sun.COM return; 5199914Samw@Sun.COM } 5209914Samw@Sun.COM } 5219914Samw@Sun.COM 5229914Samw@Sun.COM smbsr_errno(sr, errnum); 5239914Samw@Sun.COM } 524