xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_rename.c (revision 10504:ee04788f8605)
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