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 *); 4710001SJoyce.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 { 133*10504SKeyur.Desai@Sun.COM smb_node_t *src_node, *tnode; 1345331Samw char *dstname; 1355331Samw DWORD status; 1365331Samw int rc; 1375331Samw int count; 138*10504SKeyur.Desai@Sun.COM char *path; 1395331Samw 140*10504SKeyur.Desai@Sun.COM tnode = sr->tid_tree->t_snode; 141*10504SKeyur.Desai@Sun.COM 142*10504SKeyur.Desai@Sun.COM /* Lookup the source node. It MUST exist. */ 143*10504SKeyur.Desai@Sun.COM path = src_fqi->fq_path.pn_path; 144*10504SKeyur.Desai@Sun.COM rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 145*10504SKeyur.Desai@Sun.COM &src_fqi->fq_dnode, src_fqi->fq_last_comp); 146*10504SKeyur.Desai@Sun.COM if (rc != 0) 1475331Samw return (rc); 1485331Samw 149*10504SKeyur.Desai@Sun.COM rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode, 150*10504SKeyur.Desai@Sun.COM src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode); 151*10504SKeyur.Desai@Sun.COM if (rc != 0) { 152*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 153*10504SKeyur.Desai@Sun.COM return (rc); 154*10504SKeyur.Desai@Sun.COM } 1555331Samw 156*10504SKeyur.Desai@Sun.COM src_node = src_fqi->fq_fnode; 157*10504SKeyur.Desai@Sun.COM rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr); 158*10504SKeyur.Desai@Sun.COM if (rc != 0) { 159*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 160*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 161*10504SKeyur.Desai@Sun.COM return (rc); 162*10504SKeyur.Desai@Sun.COM } 1639914Samw@Sun.COM 1645331Samw /* 1655331Samw * Break the oplock before access checks. If a client 1665331Samw * has a file open, this will force a flush or close, 1675331Samw * which may affect the outcome of any share checking. 1685331Samw */ 1699021Samw@Sun.COM (void) smb_oplock_break(src_node, sr->session, B_FALSE); 1705331Samw 1715772Sas200622 for (count = 0; count <= 3; count++) { 1725772Sas200622 if (count) { 1735772Sas200622 smb_node_end_crit(src_node); 1745772Sas200622 delay(MSEC_TO_TICK(400)); 1755772Sas200622 } 1765772Sas200622 1775772Sas200622 smb_node_start_crit(src_node, RW_READER); 1785772Sas200622 1795772Sas200622 status = smb_node_rename_check(src_node); 1805772Sas200622 1815772Sas200622 if (status != NT_STATUS_SHARING_VIOLATION) 1825772Sas200622 break; 1835772Sas200622 } 1845772Sas200622 1855772Sas200622 if (status == NT_STATUS_SHARING_VIOLATION) { 1865772Sas200622 smb_node_end_crit(src_node); 187*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 188*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 189*10504SKeyur.Desai@Sun.COM return (EPIPE); /* = ERRbadshare */ 1905772Sas200622 } 1915772Sas200622 1927348SJose.Borrego@Sun.COM status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE); 1935772Sas200622 1945331Samw if (status != NT_STATUS_SUCCESS) { 1955772Sas200622 smb_node_end_crit(src_node); 196*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 197*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 198*10504SKeyur.Desai@Sun.COM return (EACCES); 199*10504SKeyur.Desai@Sun.COM } 200*10504SKeyur.Desai@Sun.COM 201*10504SKeyur.Desai@Sun.COM /* Lookup destination node. */ 202*10504SKeyur.Desai@Sun.COM path = dst_fqi->fq_path.pn_path; 203*10504SKeyur.Desai@Sun.COM rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 204*10504SKeyur.Desai@Sun.COM &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 205*10504SKeyur.Desai@Sun.COM if (rc != 0) { 206*10504SKeyur.Desai@Sun.COM smb_node_end_crit(src_node); 207*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 208*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 209*10504SKeyur.Desai@Sun.COM return (rc); 210*10504SKeyur.Desai@Sun.COM } 211*10504SKeyur.Desai@Sun.COM 212*10504SKeyur.Desai@Sun.COM rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode, 213*10504SKeyur.Desai@Sun.COM dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode); 214*10504SKeyur.Desai@Sun.COM if ((rc != 0) && (rc != ENOENT)) { 215*10504SKeyur.Desai@Sun.COM smb_node_end_crit(src_node); 216*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 217*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 218*10504SKeyur.Desai@Sun.COM smb_node_release(dst_fqi->fq_dnode); 219*10504SKeyur.Desai@Sun.COM return (rc); 2205331Samw } 2215331Samw 2229343SAfshin.Ardakani@Sun.COM if (utf8_strcasecmp(src_fqi->fq_path.pn_path, 2239343SAfshin.Ardakani@Sun.COM dst_fqi->fq_path.pn_path) == 0) { 2245331Samw 2259343SAfshin.Ardakani@Sun.COM if (dst_fqi->fq_fnode) 2269343SAfshin.Ardakani@Sun.COM smb_node_release(dst_fqi->fq_fnode); 2275331Samw 228*10504SKeyur.Desai@Sun.COM rc = strcmp(src_fqi->fq_fnode->od_name, dst_fqi->fq_last_comp); 2295331Samw if (rc == 0) { 2305772Sas200622 smb_node_end_crit(src_node); 231*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 232*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 233*10504SKeyur.Desai@Sun.COM smb_node_release(dst_fqi->fq_dnode); 234*10504SKeyur.Desai@Sun.COM return (0); 2355331Samw } 2365331Samw 2375331Samw rc = smb_fsop_rename(sr, sr->user_cr, 238*10504SKeyur.Desai@Sun.COM src_fqi->fq_dnode, src_fqi->fq_fnode->od_name, 2399914Samw@Sun.COM dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 2405772Sas200622 2415772Sas200622 smb_node_end_crit(src_node); 2429914Samw@Sun.COM if (rc == 0) 2439914Samw@Sun.COM smb_node_notify_change(dst_fqi->fq_dnode); 244*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 245*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 246*10504SKeyur.Desai@Sun.COM smb_node_release(dst_fqi->fq_dnode); 247*10504SKeyur.Desai@Sun.COM return (rc); 2485331Samw } 2495331Samw 250*10504SKeyur.Desai@Sun.COM /* dst node must not exist */ 251*10504SKeyur.Desai@Sun.COM if (dst_fqi->fq_fnode) { 2525772Sas200622 smb_node_end_crit(src_node); 253*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 254*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 255*10504SKeyur.Desai@Sun.COM smb_node_release(dst_fqi->fq_fnode); 256*10504SKeyur.Desai@Sun.COM smb_node_release(dst_fqi->fq_dnode); 257*10504SKeyur.Desai@Sun.COM return (EEXIST); 2585331Samw } 2595331Samw 2605331Samw /* 2619914Samw@Sun.COM * If the source name is mangled but the source and destination 2629914Samw@Sun.COM * on-disk names are identical, we'll use the on-disk name. 2635331Samw */ 2649343SAfshin.Ardakani@Sun.COM if ((smb_maybe_mangled_name(src_fqi->fq_last_comp)) && 2659343SAfshin.Ardakani@Sun.COM (strcmp(src_fqi->fq_last_comp, dst_fqi->fq_last_comp) == 0)) { 266*10504SKeyur.Desai@Sun.COM dstname = src_fqi->fq_fnode->od_name; 2675331Samw } else { 2689343SAfshin.Ardakani@Sun.COM dstname = dst_fqi->fq_last_comp; 2695331Samw } 2705331Samw 2715331Samw rc = smb_fsop_rename(sr, sr->user_cr, 272*10504SKeyur.Desai@Sun.COM src_fqi->fq_dnode, src_fqi->fq_fnode->od_name, 2739914Samw@Sun.COM dst_fqi->fq_dnode, dstname); 2745331Samw 2755772Sas200622 smb_node_end_crit(src_node); 2769914Samw@Sun.COM if (rc == 0) 2779914Samw@Sun.COM smb_node_notify_change(dst_fqi->fq_dnode); 278*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 2799914Samw@Sun.COM smb_node_release(src_fqi->fq_dnode); 280*10504SKeyur.Desai@Sun.COM smb_node_release(dst_fqi->fq_dnode); 2815331Samw return (rc); 2825331Samw } 2839914Samw@Sun.COM 2849914Samw@Sun.COM /* 2859914Samw@Sun.COM * smb_com_nt_rename 2869914Samw@Sun.COM * 2879914Samw@Sun.COM * Rename a file. Files OldFileName must exist and NewFileName must not. 2889914Samw@Sun.COM * Both pathnames must be relative to the Tid specified in the request. 2899914Samw@Sun.COM * Open files may be renamed. 2909914Samw@Sun.COM * 2919914Samw@Sun.COM * Multiple files may be renamed in response to a single request as Rename 2929914Samw@Sun.COM * File supports wildcards in the file name (last component of the path). 2939914Samw@Sun.COM * NOTE: we don't support rename with wildcards. 2949914Samw@Sun.COM * 2959914Samw@Sun.COM * SearchAttributes indicates the attributes that the target file(s) must 2969914Samw@Sun.COM * have. If SearchAttributes is zero then only normal files are renamed. 2979914Samw@Sun.COM * If the system file or hidden attributes are specified then the rename 2989914Samw@Sun.COM * is inclusive - both the specified type(s) of files and normal files are 2999914Samw@Sun.COM * renamed. The encoding of SearchAttributes is described in section 3.10 3009914Samw@Sun.COM * - File Attribute Encoding. 3019914Samw@Sun.COM * 3029914Samw@Sun.COM * Client Request Description 3039914Samw@Sun.COM * ================================= ================================== 3049914Samw@Sun.COM * UCHAR WordCount; Count of parameter words = 4 3059914Samw@Sun.COM * USHORT SearchAttributes; 3069914Samw@Sun.COM * USHORT InformationLevel; 0x0103 Create a hard link 3079914Samw@Sun.COM * 0x0104 In-place rename 3089914Samw@Sun.COM * 0x0105 Move (rename) a file 3099914Samw@Sun.COM * ULONG ClusterCount Servers should ignore this value 3109914Samw@Sun.COM * USHORT ByteCount; Count of data bytes; min = 4 3119914Samw@Sun.COM * UCHAR Buffer[]; Buffer containing: 3129914Samw@Sun.COM * UCHAR BufferFormat1 0x04 3139914Samw@Sun.COM * UCHAR OldFileName[] OldFileName 3149914Samw@Sun.COM * UCHAR BufferFormat1 0x04 3159914Samw@Sun.COM * UCHAR OldFileName[] NewFileName 3169914Samw@Sun.COM * 3179914Samw@Sun.COM * Server Response Description 3189914Samw@Sun.COM * ================================= ================================== 3199914Samw@Sun.COM * UCHAR WordCount; Count of parameter words = 0 3209914Samw@Sun.COM * UCHAR ByteCount; Count of data bytes = 0 3219914Samw@Sun.COM */ 3229914Samw@Sun.COM smb_sdrc_t 3239914Samw@Sun.COM smb_pre_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 uint32_t clusters; 3289914Samw@Sun.COM int rc; 3299914Samw@Sun.COM 3309914Samw@Sun.COM rc = smbsr_decode_vwv(sr, "wwl", &src_fqi->fq_sattr, 3319914Samw@Sun.COM &sr->arg.dirop.info_level, &clusters); 3329914Samw@Sun.COM if (rc == 0) { 3339914Samw@Sun.COM rc = smbsr_decode_data(sr, "%SS", sr, 3349914Samw@Sun.COM &src_fqi->fq_path.pn_path, &dst_fqi->fq_path.pn_path); 3359914Samw@Sun.COM 3369914Samw@Sun.COM dst_fqi->fq_sattr = 0; 3379914Samw@Sun.COM } 3389914Samw@Sun.COM 3399914Samw@Sun.COM DTRACE_SMB_2(op__NtRename__start, smb_request_t *, sr, 3409914Samw@Sun.COM struct dirop *, &sr->arg.dirop); 3419914Samw@Sun.COM 3429914Samw@Sun.COM return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3439914Samw@Sun.COM } 3449914Samw@Sun.COM 3459914Samw@Sun.COM void 3469914Samw@Sun.COM smb_post_nt_rename(smb_request_t *sr) 3479914Samw@Sun.COM { 3489914Samw@Sun.COM DTRACE_SMB_1(op__NtRename__done, smb_request_t *, sr); 3499914Samw@Sun.COM } 3509914Samw@Sun.COM 3519914Samw@Sun.COM smb_sdrc_t 3529914Samw@Sun.COM smb_com_nt_rename(smb_request_t *sr) 3539914Samw@Sun.COM { 3549914Samw@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 3559914Samw@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 3569914Samw@Sun.COM int rc; 3579914Samw@Sun.COM 3589914Samw@Sun.COM if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 3599914Samw@Sun.COM smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 3609914Samw@Sun.COM ERRDOS, ERROR_ACCESS_DENIED); 3619914Samw@Sun.COM return (SDRC_ERROR); 3629914Samw@Sun.COM } 3639914Samw@Sun.COM 3649914Samw@Sun.COM if (smb_convert_wildcards(src_fqi->fq_path.pn_path) != 0) { 3659914Samw@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD, 3669914Samw@Sun.COM ERRDOS, ERROR_BAD_PATHNAME); 3679914Samw@Sun.COM return (SDRC_ERROR); 3689914Samw@Sun.COM } 3699914Samw@Sun.COM 3709914Samw@Sun.COM switch (sr->arg.dirop.info_level) { 3719914Samw@Sun.COM case SMB_NT_RENAME_SET_LINK_INFO: 3729914Samw@Sun.COM rc = smb_make_link(sr, src_fqi, dst_fqi); 3739914Samw@Sun.COM break; 3749914Samw@Sun.COM case SMB_NT_RENAME_RENAME_FILE: 3759914Samw@Sun.COM case SMB_NT_RENAME_MOVE_FILE: 3769914Samw@Sun.COM rc = smb_do_rename(sr, src_fqi, dst_fqi); 3779914Samw@Sun.COM break; 3789914Samw@Sun.COM case SMB_NT_RENAME_MOVE_CLUSTER_INFO: 3799914Samw@Sun.COM rc = EINVAL; 3809914Samw@Sun.COM break; 3819914Samw@Sun.COM default: 3829914Samw@Sun.COM rc = EACCES; 3839914Samw@Sun.COM break; 3849914Samw@Sun.COM } 3859914Samw@Sun.COM 3869914Samw@Sun.COM if (rc != 0) { 3879914Samw@Sun.COM smb_rename_set_error(sr, rc); 3889914Samw@Sun.COM return (SDRC_ERROR); 3899914Samw@Sun.COM } 3909914Samw@Sun.COM 3919914Samw@Sun.COM rc = smbsr_encode_empty_result(sr); 3929914Samw@Sun.COM return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 3939914Samw@Sun.COM } 3949914Samw@Sun.COM 3959914Samw@Sun.COM /* 3969914Samw@Sun.COM * smb_make_link 3979914Samw@Sun.COM * 3989914Samw@Sun.COM * Common code for creating a hard link (adding an additional name 3999914Samw@Sun.COM * for a file. 4009914Samw@Sun.COM * 4019914Samw@Sun.COM * If the source and destination are identical, we go through all 4029914Samw@Sun.COM * the checks but we don't create a link. 4039914Samw@Sun.COM * 4049914Samw@Sun.COM * Returns errno values. 4059914Samw@Sun.COM */ 4069914Samw@Sun.COM static int 4079914Samw@Sun.COM smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 4089914Samw@Sun.COM { 409*10504SKeyur.Desai@Sun.COM smb_node_t *src_fnode, *tnode; 4109914Samw@Sun.COM DWORD status; 4119914Samw@Sun.COM int rc; 4129914Samw@Sun.COM int count; 413*10504SKeyur.Desai@Sun.COM char *path; 4149914Samw@Sun.COM 415*10504SKeyur.Desai@Sun.COM tnode = sr->tid_tree->t_snode; 416*10504SKeyur.Desai@Sun.COM 417*10504SKeyur.Desai@Sun.COM /* Lookup the source node. It MUST exist. */ 418*10504SKeyur.Desai@Sun.COM path = src_fqi->fq_path.pn_path; 419*10504SKeyur.Desai@Sun.COM rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 420*10504SKeyur.Desai@Sun.COM &src_fqi->fq_dnode, src_fqi->fq_last_comp); 421*10504SKeyur.Desai@Sun.COM if (rc != 0) 4229914Samw@Sun.COM return (rc); 4239914Samw@Sun.COM 424*10504SKeyur.Desai@Sun.COM rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode, 425*10504SKeyur.Desai@Sun.COM src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode); 426*10504SKeyur.Desai@Sun.COM if (rc != 0) { 427*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 428*10504SKeyur.Desai@Sun.COM return (rc); 429*10504SKeyur.Desai@Sun.COM } 4309914Samw@Sun.COM 431*10504SKeyur.Desai@Sun.COM src_fnode = src_fqi->fq_fnode; 432*10504SKeyur.Desai@Sun.COM rc = smb_rename_check_attr(sr, src_fnode, src_fqi->fq_sattr); 433*10504SKeyur.Desai@Sun.COM if (rc != 0) { 434*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 435*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 436*10504SKeyur.Desai@Sun.COM return (rc); 437*10504SKeyur.Desai@Sun.COM } 4389914Samw@Sun.COM 4399914Samw@Sun.COM /* 4409914Samw@Sun.COM * Break the oplock before access checks. If a client 4419914Samw@Sun.COM * has a file open, this will force a flush or close, 4429914Samw@Sun.COM * which may affect the outcome of any share checking. 4439914Samw@Sun.COM */ 4449914Samw@Sun.COM (void) smb_oplock_break(src_fnode, sr->session, B_FALSE); 4459914Samw@Sun.COM 4469914Samw@Sun.COM for (count = 0; count <= 3; count++) { 4479914Samw@Sun.COM if (count) { 4489914Samw@Sun.COM smb_node_end_crit(src_fnode); 4499914Samw@Sun.COM delay(MSEC_TO_TICK(400)); 4509914Samw@Sun.COM } 4519914Samw@Sun.COM 4529914Samw@Sun.COM smb_node_start_crit(src_fnode, RW_READER); 4539914Samw@Sun.COM status = smb_node_rename_check(src_fnode); 4549914Samw@Sun.COM 4559914Samw@Sun.COM if (status != NT_STATUS_SHARING_VIOLATION) 4569914Samw@Sun.COM break; 4579914Samw@Sun.COM } 4589914Samw@Sun.COM 4599914Samw@Sun.COM if (status == NT_STATUS_SHARING_VIOLATION) { 4609914Samw@Sun.COM smb_node_end_crit(src_fnode); 461*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 462*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 463*10504SKeyur.Desai@Sun.COM return (EPIPE); /* = ERRbadshare */ 4649914Samw@Sun.COM } 4659914Samw@Sun.COM 4669914Samw@Sun.COM status = smb_range_check(sr, src_fnode, 0, UINT64_MAX, B_TRUE); 4679914Samw@Sun.COM if (status != NT_STATUS_SUCCESS) { 4689914Samw@Sun.COM smb_node_end_crit(src_fnode); 469*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 470*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 471*10504SKeyur.Desai@Sun.COM return (EACCES); 4729914Samw@Sun.COM } 4739914Samw@Sun.COM 4749914Samw@Sun.COM if (utf8_strcasecmp(src_fqi->fq_path.pn_path, 4759914Samw@Sun.COM dst_fqi->fq_path.pn_path) == 0) { 4769914Samw@Sun.COM smb_node_end_crit(src_fnode); 477*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 478*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 479*10504SKeyur.Desai@Sun.COM return (0); 4809914Samw@Sun.COM } 4819914Samw@Sun.COM 482*10504SKeyur.Desai@Sun.COM /* Lookup the destination node. It MUST NOT exist. */ 483*10504SKeyur.Desai@Sun.COM path = dst_fqi->fq_path.pn_path; 484*10504SKeyur.Desai@Sun.COM rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 485*10504SKeyur.Desai@Sun.COM &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 4869914Samw@Sun.COM if (rc != 0) { 4879914Samw@Sun.COM smb_node_end_crit(src_fnode); 488*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 489*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 490*10504SKeyur.Desai@Sun.COM return (rc); 4919914Samw@Sun.COM } 4929914Samw@Sun.COM 493*10504SKeyur.Desai@Sun.COM rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode, 494*10504SKeyur.Desai@Sun.COM dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode); 495*10504SKeyur.Desai@Sun.COM if (rc == 0) { 496*10504SKeyur.Desai@Sun.COM smb_node_release(dst_fqi->fq_fnode); 497*10504SKeyur.Desai@Sun.COM rc = EEXIST; 498*10504SKeyur.Desai@Sun.COM } 499*10504SKeyur.Desai@Sun.COM if (rc != ENOENT) { 500*10504SKeyur.Desai@Sun.COM smb_node_end_crit(src_fnode); 501*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 502*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 503*10504SKeyur.Desai@Sun.COM smb_node_release(dst_fqi->fq_dnode); 504*10504SKeyur.Desai@Sun.COM return (rc); 505*10504SKeyur.Desai@Sun.COM } 506*10504SKeyur.Desai@Sun.COM 5079914Samw@Sun.COM rc = smb_fsop_link(sr, sr->user_cr, dst_fqi->fq_dnode, src_fnode, 5089914Samw@Sun.COM dst_fqi->fq_last_comp); 5099914Samw@Sun.COM 5109914Samw@Sun.COM smb_node_end_crit(src_fnode); 5119914Samw@Sun.COM if (rc == 0) 5129914Samw@Sun.COM smb_node_notify_change(dst_fqi->fq_dnode); 513*10504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 5149914Samw@Sun.COM smb_node_release(src_fqi->fq_dnode); 515*10504SKeyur.Desai@Sun.COM smb_node_release(dst_fqi->fq_dnode); 5169914Samw@Sun.COM return (rc); 5179914Samw@Sun.COM } 5189914Samw@Sun.COM 5199914Samw@Sun.COM static int 52010001SJoyce.McIntosh@Sun.COM smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr) 5219914Samw@Sun.COM { 52210001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 5239914Samw@Sun.COM 52410001SJoyce.McIntosh@Sun.COM if (smb_node_getattr(sr, node, &attr) != 0) 52510001SJoyce.McIntosh@Sun.COM return (EIO); 52610001SJoyce.McIntosh@Sun.COM 52710001SJoyce.McIntosh@Sun.COM if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) && 52810001SJoyce.McIntosh@Sun.COM !(SMB_SEARCH_HIDDEN(sattr))) 5299914Samw@Sun.COM return (ESRCH); 5309914Samw@Sun.COM 53110001SJoyce.McIntosh@Sun.COM if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) && 53210001SJoyce.McIntosh@Sun.COM !(SMB_SEARCH_SYSTEM(sattr))) 5339914Samw@Sun.COM return (ESRCH); 5349914Samw@Sun.COM 5359914Samw@Sun.COM return (0); 5369914Samw@Sun.COM } 5379914Samw@Sun.COM 5389914Samw@Sun.COM /* 5399914Samw@Sun.COM * The following values are based on observed WFWG, Windows 9x, Windows NT 5409914Samw@Sun.COM * and Windows 2000 behaviour. 5419914Samw@Sun.COM * 5429914Samw@Sun.COM * ERROR_FILE_EXISTS doesn't work for Windows 98 clients. 5439914Samw@Sun.COM * 5449914Samw@Sun.COM * Windows 95 clients don't see the problem because the target is deleted 5459914Samw@Sun.COM * before the rename request. 5469914Samw@Sun.COM */ 5479914Samw@Sun.COM static void 5489914Samw@Sun.COM smb_rename_set_error(smb_request_t *sr, int errnum) 5499914Samw@Sun.COM { 5509914Samw@Sun.COM static struct { 5519914Samw@Sun.COM int errnum; 5529914Samw@Sun.COM uint16_t errcode; 5539914Samw@Sun.COM uint32_t status32; 5549914Samw@Sun.COM } rc_map[] = { 5559914Samw@Sun.COM { EEXIST, ERROR_ALREADY_EXISTS, NT_STATUS_OBJECT_NAME_COLLISION }, 5569914Samw@Sun.COM { EPIPE, ERROR_SHARING_VIOLATION, NT_STATUS_SHARING_VIOLATION }, 5579914Samw@Sun.COM { ENOENT, ERROR_FILE_NOT_FOUND, NT_STATUS_OBJECT_NAME_NOT_FOUND }, 5589914Samw@Sun.COM { ESRCH, ERROR_FILE_NOT_FOUND, NT_STATUS_NO_SUCH_FILE }, 5599914Samw@Sun.COM { EINVAL, ERROR_INVALID_PARAMETER, NT_STATUS_INVALID_PARAMETER }, 56010001SJoyce.McIntosh@Sun.COM { EACCES, ERROR_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED }, 56110001SJoyce.McIntosh@Sun.COM { EIO, ERROR_INTERNAL_ERROR, NT_STATUS_INTERNAL_ERROR } 5629914Samw@Sun.COM }; 5639914Samw@Sun.COM 5649914Samw@Sun.COM int i; 5659914Samw@Sun.COM 5669914Samw@Sun.COM if (errnum == 0) 5679914Samw@Sun.COM return; 5689914Samw@Sun.COM 5699914Samw@Sun.COM for (i = 0; i < sizeof (rc_map)/sizeof (rc_map[0]); ++i) { 5709914Samw@Sun.COM if (rc_map[i].errnum == errnum) { 5719914Samw@Sun.COM smbsr_error(sr, rc_map[i].status32, 5729914Samw@Sun.COM ERRDOS, rc_map[i].errcode); 5739914Samw@Sun.COM return; 5749914Samw@Sun.COM } 5759914Samw@Sun.COM } 5769914Samw@Sun.COM 5779914Samw@Sun.COM smbsr_errno(sr, errnum); 5789914Samw@Sun.COM } 579