xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_rename.c (revision 10966:37e5dcdf36d3)
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 <sys/synch.h>
27*10966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
285331Samw #include <smbsrv/smb_fsops.h>
295772Sas200622 #include <sys/nbmlock.h>
305331Samw 
319914Samw@Sun.COM /*
329914Samw@Sun.COM  * NT_RENAME InformationLevels:
339914Samw@Sun.COM  *
349914Samw@Sun.COM  * SMB_NT_RENAME_MOVE_CLUSTER_INFO	Server returns invalid parameter.
359914Samw@Sun.COM  * SMB_NT_RENAME_SET_LINK_INFO		Create a hard link to a file.
369914Samw@Sun.COM  * SMB_NT_RENAME_RENAME_FILE		In-place rename of a file.
379914Samw@Sun.COM  * SMB_NT_RENAME_MOVE_FILE		Move (rename) a file.
389914Samw@Sun.COM  */
399914Samw@Sun.COM #define	SMB_NT_RENAME_MOVE_CLUSTER_INFO	0x0102
409914Samw@Sun.COM #define	SMB_NT_RENAME_SET_LINK_INFO	0x0103
419914Samw@Sun.COM #define	SMB_NT_RENAME_RENAME_FILE	0x0104
429914Samw@Sun.COM #define	SMB_NT_RENAME_MOVE_FILE		0x0105
439914Samw@Sun.COM 
44*10966SJordan.Brown@Sun.COM /*
45*10966SJordan.Brown@Sun.COM  * SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag
46*10966SJordan.Brown@Sun.COM  */
47*10966SJordan.Brown@Sun.COM #define	SMB_RENAME_FLAG_OVERWRITE	0x001
48*10966SJordan.Brown@Sun.COM 
49*10966SJordan.Brown@Sun.COM static int smb_common_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *);
509914Samw@Sun.COM static int smb_make_link(smb_request_t *, smb_fqi_t *, smb_fqi_t *);
51*10966SJordan.Brown@Sun.COM static int smb_rename_check_stream(smb_fqi_t *, smb_fqi_t *);
5210001SJoyce.McIntosh@Sun.COM static int smb_rename_check_attr(smb_request_t *, smb_node_t *, uint16_t);
539914Samw@Sun.COM static void smb_rename_set_error(smb_request_t *, int);
545331Samw 
55*10966SJordan.Brown@Sun.COM static int smb_rename_lookup_src(smb_request_t *);
56*10966SJordan.Brown@Sun.COM static void smb_rename_release_src(smb_request_t *);
57*10966SJordan.Brown@Sun.COM 
585331Samw /*
595331Samw  * smb_com_rename
605331Samw  *
615331Samw  * Rename a file. Files OldFileName must exist and NewFileName must not.
625331Samw  * Both pathnames must be relative to the Tid specified in the request.
635331Samw  * Open files may be renamed.
645331Samw  *
655331Samw  * Multiple files may be renamed in response to a single request as Rename
665331Samw  * File supports wildcards in the file name (last component of the path).
675331Samw  * NOTE: we don't support rename with wildcards.
685331Samw  *
695331Samw  * SearchAttributes indicates the attributes that the target file(s) must
705331Samw  * have. If SearchAttributes is zero then only normal files are renamed.
715331Samw  * If the system file or hidden attributes are specified then the rename
725331Samw  * is inclusive - both the specified type(s) of files and normal files are
73*10966SJordan.Brown@Sun.COM  * renamed.
745331Samw  */
756030Sjb150015 smb_sdrc_t
766139Sjb150015 smb_pre_rename(smb_request_t *sr)
776139Sjb150015 {
787961SNatalie.Li@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
797961SNatalie.Li@Sun.COM 	smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
806139Sjb150015 	int rc;
816139Sjb150015 
829343SAfshin.Ardakani@Sun.COM 	if ((rc = smbsr_decode_vwv(sr, "w", &src_fqi->fq_sattr)) == 0) {
839343SAfshin.Ardakani@Sun.COM 		rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->fq_path.pn_path,
849343SAfshin.Ardakani@Sun.COM 		    &dst_fqi->fq_path.pn_path);
856139Sjb150015 
869343SAfshin.Ardakani@Sun.COM 		dst_fqi->fq_sattr = 0;
876139Sjb150015 	}
886139Sjb150015 
896139Sjb150015 	DTRACE_SMB_2(op__Rename__start, smb_request_t *, sr,
906139Sjb150015 	    struct dirop *, &sr->arg.dirop);
916139Sjb150015 
926139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
936139Sjb150015 }
946139Sjb150015 
956139Sjb150015 void
966139Sjb150015 smb_post_rename(smb_request_t *sr)
976139Sjb150015 {
986139Sjb150015 	DTRACE_SMB_1(op__Rename__done, smb_request_t *, sr);
996139Sjb150015 }
1006139Sjb150015 
1016139Sjb150015 smb_sdrc_t
1026139Sjb150015 smb_com_rename(smb_request_t *sr)
1035331Samw {
1047961SNatalie.Li@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
1057961SNatalie.Li@Sun.COM 	smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
1065331Samw 	int rc;
1075331Samw 
1085331Samw 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
1095772Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
1105331Samw 		    ERRDOS, ERROR_ACCESS_DENIED);
1116139Sjb150015 		return (SDRC_ERROR);
1125331Samw 	}
1135331Samw 
114*10966SJordan.Brown@Sun.COM 	rc = smb_common_rename(sr, src_fqi, dst_fqi);
1155331Samw 
1165331Samw 	if (rc != 0) {
1179914Samw@Sun.COM 		smb_rename_set_error(sr, rc);
1186139Sjb150015 		return (SDRC_ERROR);
1195331Samw 	}
1205331Samw 
1216030Sjb150015 	rc = smbsr_encode_empty_result(sr);
1226139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1235331Samw }
1245331Samw 
1255331Samw /*
1269914Samw@Sun.COM  * smb_com_nt_rename
1279914Samw@Sun.COM  *
1289914Samw@Sun.COM  * Rename a file. Files OldFileName must exist and NewFileName must not.
1299914Samw@Sun.COM  * Both pathnames must be relative to the Tid specified in the request.
1309914Samw@Sun.COM  * Open files may be renamed.
1319914Samw@Sun.COM  *
1329914Samw@Sun.COM  * SearchAttributes indicates the attributes that the target file(s) must
1339914Samw@Sun.COM  * have. If SearchAttributes is zero then only normal files are renamed.
1349914Samw@Sun.COM  * If the system file or hidden attributes are specified then the rename
1359914Samw@Sun.COM  * is inclusive - both the specified type(s) of files and normal files are
136*10966SJordan.Brown@Sun.COM  * renamed.
1379914Samw@Sun.COM  */
1389914Samw@Sun.COM smb_sdrc_t
1399914Samw@Sun.COM smb_pre_nt_rename(smb_request_t *sr)
1409914Samw@Sun.COM {
1419914Samw@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
1429914Samw@Sun.COM 	smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
1439914Samw@Sun.COM 	uint32_t clusters;
1449914Samw@Sun.COM 	int rc;
1459914Samw@Sun.COM 
1469914Samw@Sun.COM 	rc = smbsr_decode_vwv(sr, "wwl", &src_fqi->fq_sattr,
1479914Samw@Sun.COM 	    &sr->arg.dirop.info_level, &clusters);
1489914Samw@Sun.COM 	if (rc == 0) {
1499914Samw@Sun.COM 		rc = smbsr_decode_data(sr, "%SS", sr,
1509914Samw@Sun.COM 		    &src_fqi->fq_path.pn_path, &dst_fqi->fq_path.pn_path);
1519914Samw@Sun.COM 
1529914Samw@Sun.COM 		dst_fqi->fq_sattr = 0;
1539914Samw@Sun.COM 	}
1549914Samw@Sun.COM 
1559914Samw@Sun.COM 	DTRACE_SMB_2(op__NtRename__start, smb_request_t *, sr,
1569914Samw@Sun.COM 	    struct dirop *, &sr->arg.dirop);
1579914Samw@Sun.COM 
1589914Samw@Sun.COM 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1599914Samw@Sun.COM }
1609914Samw@Sun.COM 
1619914Samw@Sun.COM void
1629914Samw@Sun.COM smb_post_nt_rename(smb_request_t *sr)
1639914Samw@Sun.COM {
1649914Samw@Sun.COM 	DTRACE_SMB_1(op__NtRename__done, smb_request_t *, sr);
1659914Samw@Sun.COM }
1669914Samw@Sun.COM 
1679914Samw@Sun.COM smb_sdrc_t
1689914Samw@Sun.COM smb_com_nt_rename(smb_request_t *sr)
1699914Samw@Sun.COM {
1709914Samw@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
1719914Samw@Sun.COM 	smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
1729914Samw@Sun.COM 	int rc;
1739914Samw@Sun.COM 
1749914Samw@Sun.COM 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
1759914Samw@Sun.COM 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
1769914Samw@Sun.COM 		    ERRDOS, ERROR_ACCESS_DENIED);
1779914Samw@Sun.COM 		return (SDRC_ERROR);
1789914Samw@Sun.COM 	}
1799914Samw@Sun.COM 
1809914Samw@Sun.COM 	if (smb_convert_wildcards(src_fqi->fq_path.pn_path) != 0) {
1819914Samw@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
1829914Samw@Sun.COM 		    ERRDOS, ERROR_BAD_PATHNAME);
1839914Samw@Sun.COM 		return (SDRC_ERROR);
1849914Samw@Sun.COM 	}
1859914Samw@Sun.COM 
1869914Samw@Sun.COM 	switch (sr->arg.dirop.info_level) {
1879914Samw@Sun.COM 	case SMB_NT_RENAME_SET_LINK_INFO:
1889914Samw@Sun.COM 		rc = smb_make_link(sr, src_fqi, dst_fqi);
1899914Samw@Sun.COM 		break;
1909914Samw@Sun.COM 	case SMB_NT_RENAME_RENAME_FILE:
1919914Samw@Sun.COM 	case SMB_NT_RENAME_MOVE_FILE:
192*10966SJordan.Brown@Sun.COM 		rc = smb_common_rename(sr, src_fqi, dst_fqi);
1939914Samw@Sun.COM 		break;
1949914Samw@Sun.COM 	case SMB_NT_RENAME_MOVE_CLUSTER_INFO:
1959914Samw@Sun.COM 		rc = EINVAL;
1969914Samw@Sun.COM 		break;
1979914Samw@Sun.COM 	default:
1989914Samw@Sun.COM 		rc = EACCES;
1999914Samw@Sun.COM 		break;
2009914Samw@Sun.COM 	}
2019914Samw@Sun.COM 
2029914Samw@Sun.COM 	if (rc != 0) {
2039914Samw@Sun.COM 		smb_rename_set_error(sr, rc);
2049914Samw@Sun.COM 		return (SDRC_ERROR);
2059914Samw@Sun.COM 	}
2069914Samw@Sun.COM 
2079914Samw@Sun.COM 	rc = smbsr_encode_empty_result(sr);
2089914Samw@Sun.COM 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
2099914Samw@Sun.COM }
2109914Samw@Sun.COM 
2119914Samw@Sun.COM /*
212*10966SJordan.Brown@Sun.COM  * smb_nt_transact_rename
213*10966SJordan.Brown@Sun.COM  *
214*10966SJordan.Brown@Sun.COM  * Windows servers return SUCCESS without renaming file.
215*10966SJordan.Brown@Sun.COM  * The only check required is to check that the handle (fid) is valid.
216*10966SJordan.Brown@Sun.COM  */
217*10966SJordan.Brown@Sun.COM smb_sdrc_t
218*10966SJordan.Brown@Sun.COM smb_nt_transact_rename(smb_request_t *sr, smb_xa_t *xa)
219*10966SJordan.Brown@Sun.COM {
220*10966SJordan.Brown@Sun.COM 	if (smb_mbc_decodef(&xa->req_param_mb, "w", &sr->smb_fid) != 0)
221*10966SJordan.Brown@Sun.COM 		return (SDRC_ERROR);
222*10966SJordan.Brown@Sun.COM 
223*10966SJordan.Brown@Sun.COM 	smbsr_lookup_file(sr);
224*10966SJordan.Brown@Sun.COM 	if (sr->fid_ofile == NULL) {
225*10966SJordan.Brown@Sun.COM 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
226*10966SJordan.Brown@Sun.COM 		return (SDRC_ERROR);
227*10966SJordan.Brown@Sun.COM 	}
228*10966SJordan.Brown@Sun.COM 	smbsr_release_file(sr);
229*10966SJordan.Brown@Sun.COM 
230*10966SJordan.Brown@Sun.COM 	return (SDRC_SUCCESS);
231*10966SJordan.Brown@Sun.COM }
232*10966SJordan.Brown@Sun.COM 
233*10966SJordan.Brown@Sun.COM /*
234*10966SJordan.Brown@Sun.COM  * smb_trans2_rename
235*10966SJordan.Brown@Sun.COM  *
236*10966SJordan.Brown@Sun.COM  * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo
237*10966SJordan.Brown@Sun.COM  * and Trans2_Set_PathInfo.
238*10966SJordan.Brown@Sun.COM  * If the new filename (dst_fqi) already exists it may be overwritten
239*10966SJordan.Brown@Sun.COM  * if flags == 1.
240*10966SJordan.Brown@Sun.COM  */
241*10966SJordan.Brown@Sun.COM int
242*10966SJordan.Brown@Sun.COM smb_trans2_rename(smb_request_t *sr, smb_node_t *node, char *fname, int flags)
243*10966SJordan.Brown@Sun.COM {
244*10966SJordan.Brown@Sun.COM 	int rc;
245*10966SJordan.Brown@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
246*10966SJordan.Brown@Sun.COM 	smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
247*10966SJordan.Brown@Sun.COM 
248*10966SJordan.Brown@Sun.COM 	sr->arg.dirop.flags = flags ? SMB_RENAME_FLAG_OVERWRITE : 0;
249*10966SJordan.Brown@Sun.COM 	sr->arg.dirop.info_level = SMB_NT_RENAME_RENAME_FILE;
250*10966SJordan.Brown@Sun.COM 
251*10966SJordan.Brown@Sun.COM 	src_fqi->fq_sattr = SMB_SEARCH_ATTRIBUTES;
252*10966SJordan.Brown@Sun.COM 	src_fqi->fq_fnode = node;
253*10966SJordan.Brown@Sun.COM 	src_fqi->fq_dnode = node->n_dnode;
254*10966SJordan.Brown@Sun.COM 
255*10966SJordan.Brown@Sun.COM 	dst_fqi->fq_path.pn_path = fname;
256*10966SJordan.Brown@Sun.COM 	dst_fqi->fq_dnode = node->n_dnode;
257*10966SJordan.Brown@Sun.COM 	(void) strlcpy(dst_fqi->fq_last_comp, fname, MAXNAMELEN);
258*10966SJordan.Brown@Sun.COM 
259*10966SJordan.Brown@Sun.COM 	rc = smb_common_rename(sr, src_fqi, dst_fqi);
260*10966SJordan.Brown@Sun.COM 	if (rc != 0) {
261*10966SJordan.Brown@Sun.COM 		smb_rename_set_error(sr, rc);
262*10966SJordan.Brown@Sun.COM 		return (-1);
263*10966SJordan.Brown@Sun.COM 	}
264*10966SJordan.Brown@Sun.COM 
265*10966SJordan.Brown@Sun.COM 	return (0);
266*10966SJordan.Brown@Sun.COM }
267*10966SJordan.Brown@Sun.COM 
268*10966SJordan.Brown@Sun.COM /*
269*10966SJordan.Brown@Sun.COM  * smb_common_rename
270*10966SJordan.Brown@Sun.COM  *
271*10966SJordan.Brown@Sun.COM  * Common code for renaming a file.
272*10966SJordan.Brown@Sun.COM  *
273*10966SJordan.Brown@Sun.COM  * If the source and destination are identical, we go through all
274*10966SJordan.Brown@Sun.COM  * the checks but we don't actually do the rename.  If the source
275*10966SJordan.Brown@Sun.COM  * and destination files differ only in case, we do a case-sensitive
276*10966SJordan.Brown@Sun.COM  * rename.  Otherwise, we do a full case-insensitive rename.
277*10966SJordan.Brown@Sun.COM  *
278*10966SJordan.Brown@Sun.COM  * Returns errno values.
279*10966SJordan.Brown@Sun.COM  */
280*10966SJordan.Brown@Sun.COM static int
281*10966SJordan.Brown@Sun.COM smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
282*10966SJordan.Brown@Sun.COM {
283*10966SJordan.Brown@Sun.COM 	smb_node_t *src_fnode, *src_dnode, *dst_fnode, *dst_dnode;
284*10966SJordan.Brown@Sun.COM 	smb_node_t *tnode;
285*10966SJordan.Brown@Sun.COM 	int rc, count;
286*10966SJordan.Brown@Sun.COM 	DWORD status;
287*10966SJordan.Brown@Sun.COM 	char *new_name, *path;
288*10966SJordan.Brown@Sun.COM 
289*10966SJordan.Brown@Sun.COM 	path = dst_fqi->fq_path.pn_path;
290*10966SJordan.Brown@Sun.COM 
291*10966SJordan.Brown@Sun.COM 	/* Check if attempting to rename a stream - not yet supported */
292*10966SJordan.Brown@Sun.COM 	rc = smb_rename_check_stream(src_fqi, dst_fqi);
293*10966SJordan.Brown@Sun.COM 	if (rc != 0)
294*10966SJordan.Brown@Sun.COM 		return (rc);
295*10966SJordan.Brown@Sun.COM 
296*10966SJordan.Brown@Sun.COM 	/* The source node may already have been provided */
297*10966SJordan.Brown@Sun.COM 	if (src_fqi->fq_fnode) {
298*10966SJordan.Brown@Sun.COM 		smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
299*10966SJordan.Brown@Sun.COM 		smb_node_ref(src_fqi->fq_fnode);
300*10966SJordan.Brown@Sun.COM 		smb_node_ref(src_fqi->fq_dnode);
301*10966SJordan.Brown@Sun.COM 	} else {
302*10966SJordan.Brown@Sun.COM 		/* lookup and validate src node */
303*10966SJordan.Brown@Sun.COM 		rc = smb_rename_lookup_src(sr);
304*10966SJordan.Brown@Sun.COM 		if (rc != 0)
305*10966SJordan.Brown@Sun.COM 			return (rc);
306*10966SJordan.Brown@Sun.COM 	}
307*10966SJordan.Brown@Sun.COM 
308*10966SJordan.Brown@Sun.COM 	src_fnode = src_fqi->fq_fnode;
309*10966SJordan.Brown@Sun.COM 	src_dnode = src_fqi->fq_dnode;
310*10966SJordan.Brown@Sun.COM 
311*10966SJordan.Brown@Sun.COM 	/* Find destination dnode and last_comp */
312*10966SJordan.Brown@Sun.COM 	if (dst_fqi->fq_dnode) {
313*10966SJordan.Brown@Sun.COM 		smb_node_ref(dst_fqi->fq_dnode);
314*10966SJordan.Brown@Sun.COM 	} else {
315*10966SJordan.Brown@Sun.COM 		tnode = sr->tid_tree->t_snode;
316*10966SJordan.Brown@Sun.COM 		rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
317*10966SJordan.Brown@Sun.COM 		    &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
318*10966SJordan.Brown@Sun.COM 		if (rc != 0) {
319*10966SJordan.Brown@Sun.COM 			smb_rename_release_src(sr);
320*10966SJordan.Brown@Sun.COM 			return (rc);
321*10966SJordan.Brown@Sun.COM 		}
322*10966SJordan.Brown@Sun.COM 	}
323*10966SJordan.Brown@Sun.COM 
324*10966SJordan.Brown@Sun.COM 	dst_dnode = dst_fqi->fq_dnode;
325*10966SJordan.Brown@Sun.COM 	new_name = dst_fqi->fq_last_comp;
326*10966SJordan.Brown@Sun.COM 
327*10966SJordan.Brown@Sun.COM 	/* If exact name match in same directory, we're done */
328*10966SJordan.Brown@Sun.COM 	if ((src_dnode == dst_dnode) &&
329*10966SJordan.Brown@Sun.COM 	    (strcmp(src_fnode->od_name, new_name) == 0)) {
330*10966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
331*10966SJordan.Brown@Sun.COM 		smb_node_release(dst_dnode);
332*10966SJordan.Brown@Sun.COM 		return (0);
333*10966SJordan.Brown@Sun.COM 	}
334*10966SJordan.Brown@Sun.COM 
335*10966SJordan.Brown@Sun.COM 	/* Lookup destination node */
336*10966SJordan.Brown@Sun.COM 	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
337*10966SJordan.Brown@Sun.COM 	    dst_dnode, new_name, &dst_fqi->fq_fnode);
338*10966SJordan.Brown@Sun.COM 
339*10966SJordan.Brown@Sun.COM 	/*
340*10966SJordan.Brown@Sun.COM 	 * Handle case where changing case of the same directory entry.
341*10966SJordan.Brown@Sun.COM 	 *
342*10966SJordan.Brown@Sun.COM 	 * If we found the dst node in the same directory as the src node,
343*10966SJordan.Brown@Sun.COM 	 * and their names differ only in case:
344*10966SJordan.Brown@Sun.COM 	 *
345*10966SJordan.Brown@Sun.COM 	 * If the tree is case sensitive (or mixed):
346*10966SJordan.Brown@Sun.COM 	 *  Do case sensitive lookup to see if exact match exists.
347*10966SJordan.Brown@Sun.COM 	 *  If the exact match is the same node as src_node we're done.
348*10966SJordan.Brown@Sun.COM 	 *
349*10966SJordan.Brown@Sun.COM 	 * If the tree is case insensitive:
350*10966SJordan.Brown@Sun.COM 	 *  There is currently no way to tell if the case is different
351*10966SJordan.Brown@Sun.COM 	 *  or not, so do the rename (unless the specified new name was
352*10966SJordan.Brown@Sun.COM 	 *  mangled).
353*10966SJordan.Brown@Sun.COM 	 */
354*10966SJordan.Brown@Sun.COM 	if ((rc == 0) &&
355*10966SJordan.Brown@Sun.COM 	    (src_dnode == dst_dnode) &&
356*10966SJordan.Brown@Sun.COM 	    (smb_strcasecmp(src_fnode->od_name,
357*10966SJordan.Brown@Sun.COM 	    dst_fqi->fq_fnode->od_name, 0) == 0)) {
358*10966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_fnode);
359*10966SJordan.Brown@Sun.COM 		dst_fqi->fq_fnode = NULL;
360*10966SJordan.Brown@Sun.COM 
361*10966SJordan.Brown@Sun.COM 		if (smb_tree_has_feature(sr->tid_tree,
362*10966SJordan.Brown@Sun.COM 		    SMB_TREE_NO_CASESENSITIVE)) {
363*10966SJordan.Brown@Sun.COM 			if (smb_strcasecmp(src_fnode->od_name,
364*10966SJordan.Brown@Sun.COM 			    dst_fqi->fq_last_comp, 0) != 0) {
365*10966SJordan.Brown@Sun.COM 				smb_rename_release_src(sr);
366*10966SJordan.Brown@Sun.COM 				smb_node_release(dst_dnode);
367*10966SJordan.Brown@Sun.COM 				return (0);
368*10966SJordan.Brown@Sun.COM 			}
369*10966SJordan.Brown@Sun.COM 		} else {
370*10966SJordan.Brown@Sun.COM 			rc = smb_fsop_lookup(sr, sr->user_cr,
371*10966SJordan.Brown@Sun.COM 			    SMB_CASE_SENSITIVE, tnode, dst_dnode, new_name,
372*10966SJordan.Brown@Sun.COM 			    &dst_fqi->fq_fnode);
373*10966SJordan.Brown@Sun.COM 
374*10966SJordan.Brown@Sun.COM 			if ((rc == 0) &&
375*10966SJordan.Brown@Sun.COM 			    (dst_fqi->fq_fnode == src_fnode)) {
376*10966SJordan.Brown@Sun.COM 				smb_rename_release_src(sr);
377*10966SJordan.Brown@Sun.COM 				smb_node_release(dst_fqi->fq_fnode);
378*10966SJordan.Brown@Sun.COM 				smb_node_release(dst_dnode);
379*10966SJordan.Brown@Sun.COM 				return (0);
380*10966SJordan.Brown@Sun.COM 			}
381*10966SJordan.Brown@Sun.COM 		}
382*10966SJordan.Brown@Sun.COM 	}
383*10966SJordan.Brown@Sun.COM 
384*10966SJordan.Brown@Sun.COM 	if ((rc != 0) && (rc != ENOENT)) {
385*10966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
386*10966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_dnode);
387*10966SJordan.Brown@Sun.COM 		return (rc);
388*10966SJordan.Brown@Sun.COM 	}
389*10966SJordan.Brown@Sun.COM 
390*10966SJordan.Brown@Sun.COM 	if (dst_fqi->fq_fnode) {
391*10966SJordan.Brown@Sun.COM 		dst_fnode = dst_fqi->fq_fnode;
392*10966SJordan.Brown@Sun.COM 
393*10966SJordan.Brown@Sun.COM 		if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) {
394*10966SJordan.Brown@Sun.COM 			smb_rename_release_src(sr);
395*10966SJordan.Brown@Sun.COM 			smb_node_release(dst_fnode);
396*10966SJordan.Brown@Sun.COM 			smb_node_release(dst_dnode);
397*10966SJordan.Brown@Sun.COM 			return (EEXIST);
398*10966SJordan.Brown@Sun.COM 		}
399*10966SJordan.Brown@Sun.COM 
400*10966SJordan.Brown@Sun.COM 		(void) smb_oplock_break(dst_fnode, sr->session, B_FALSE);
401*10966SJordan.Brown@Sun.COM 
402*10966SJordan.Brown@Sun.COM 		for (count = 0; count <= 3; count++) {
403*10966SJordan.Brown@Sun.COM 			if (count) {
404*10966SJordan.Brown@Sun.COM 				smb_node_end_crit(dst_fnode);
405*10966SJordan.Brown@Sun.COM 				delay(MSEC_TO_TICK(400));
406*10966SJordan.Brown@Sun.COM 			}
407*10966SJordan.Brown@Sun.COM 
408*10966SJordan.Brown@Sun.COM 			smb_node_start_crit(dst_fnode, RW_READER);
409*10966SJordan.Brown@Sun.COM 			status = smb_node_delete_check(dst_fnode);
410*10966SJordan.Brown@Sun.COM 
411*10966SJordan.Brown@Sun.COM 			if (status != NT_STATUS_SHARING_VIOLATION)
412*10966SJordan.Brown@Sun.COM 				break;
413*10966SJordan.Brown@Sun.COM 		}
414*10966SJordan.Brown@Sun.COM 
415*10966SJordan.Brown@Sun.COM 		if (status != NT_STATUS_SHARING_VIOLATION)
416*10966SJordan.Brown@Sun.COM 			status = smb_range_check(sr, dst_fnode,
417*10966SJordan.Brown@Sun.COM 			    0, UINT64_MAX, B_TRUE);
418*10966SJordan.Brown@Sun.COM 
419*10966SJordan.Brown@Sun.COM 		if (status != NT_STATUS_SUCCESS) {
420*10966SJordan.Brown@Sun.COM 			smb_rename_release_src(sr);
421*10966SJordan.Brown@Sun.COM 			smb_node_end_crit(dst_fnode);
422*10966SJordan.Brown@Sun.COM 			smb_node_release(dst_fnode);
423*10966SJordan.Brown@Sun.COM 			smb_node_release(dst_dnode);
424*10966SJordan.Brown@Sun.COM 			return (EACCES);
425*10966SJordan.Brown@Sun.COM 		}
426*10966SJordan.Brown@Sun.COM 
427*10966SJordan.Brown@Sun.COM 		if (smb_maybe_mangled_name(new_name)) {
428*10966SJordan.Brown@Sun.COM 			(void) strlcpy(new_name, dst_fnode->od_name,
429*10966SJordan.Brown@Sun.COM 			    MAXNAMELEN);
430*10966SJordan.Brown@Sun.COM 		}
431*10966SJordan.Brown@Sun.COM 	}
432*10966SJordan.Brown@Sun.COM 
433*10966SJordan.Brown@Sun.COM 	rc = smb_fsop_rename(sr, sr->user_cr,
434*10966SJordan.Brown@Sun.COM 	    src_dnode, src_fnode->od_name,
435*10966SJordan.Brown@Sun.COM 	    dst_dnode, new_name);
436*10966SJordan.Brown@Sun.COM 
437*10966SJordan.Brown@Sun.COM 	smb_rename_release_src(sr);
438*10966SJordan.Brown@Sun.COM 
439*10966SJordan.Brown@Sun.COM 	if (rc == 0)
440*10966SJordan.Brown@Sun.COM 		smb_node_notify_change(dst_dnode);
441*10966SJordan.Brown@Sun.COM 
442*10966SJordan.Brown@Sun.COM 	if (dst_fqi->fq_fnode) {
443*10966SJordan.Brown@Sun.COM 		smb_node_end_crit(dst_fnode);
444*10966SJordan.Brown@Sun.COM 		smb_node_release(dst_fnode);
445*10966SJordan.Brown@Sun.COM 	}
446*10966SJordan.Brown@Sun.COM 	smb_node_release(dst_dnode);
447*10966SJordan.Brown@Sun.COM 
448*10966SJordan.Brown@Sun.COM 	return (rc);
449*10966SJordan.Brown@Sun.COM }
450*10966SJordan.Brown@Sun.COM 
451*10966SJordan.Brown@Sun.COM /*
452*10966SJordan.Brown@Sun.COM  * smb_rename_check_stream
453*10966SJordan.Brown@Sun.COM  *
454*10966SJordan.Brown@Sun.COM  * For a stream rename the dst path must begin with ':', or "\\:".
455*10966SJordan.Brown@Sun.COM  * We don't yet support stream rename, Return EACCES.
456*10966SJordan.Brown@Sun.COM  *
457*10966SJordan.Brown@Sun.COM  * If not a stream rename, in accordance with the above rule,
458*10966SJordan.Brown@Sun.COM  * it is not valid for either the src or dst to be a stream.
459*10966SJordan.Brown@Sun.COM  * Return EINVAL.
460*10966SJordan.Brown@Sun.COM  */
461*10966SJordan.Brown@Sun.COM static int
462*10966SJordan.Brown@Sun.COM smb_rename_check_stream(smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
463*10966SJordan.Brown@Sun.COM {
464*10966SJordan.Brown@Sun.COM 	smb_node_t *src_fnode = src_fqi->fq_fnode;
465*10966SJordan.Brown@Sun.COM 	char *src_path = src_fqi->fq_path.pn_path;
466*10966SJordan.Brown@Sun.COM 	char *dst_path = dst_fqi->fq_path.pn_path;
467*10966SJordan.Brown@Sun.COM 
468*10966SJordan.Brown@Sun.COM 	/* We do not yet support named stream rename - ACCESS DENIED */
469*10966SJordan.Brown@Sun.COM 	if ((dst_path[0] == ':') ||
470*10966SJordan.Brown@Sun.COM 	    ((dst_path[0] == '\\') && (dst_path[1] == ':'))) {
471*10966SJordan.Brown@Sun.COM 		return (EACCES);
472*10966SJordan.Brown@Sun.COM 	}
473*10966SJordan.Brown@Sun.COM 
474*10966SJordan.Brown@Sun.COM 	/*
475*10966SJordan.Brown@Sun.COM 	 * If not stream rename (above) neither src or dst can be
476*10966SJordan.Brown@Sun.COM 	 * a named stream.
477*10966SJordan.Brown@Sun.COM 	 */
478*10966SJordan.Brown@Sun.COM 
479*10966SJordan.Brown@Sun.COM 	if (smb_is_stream_name(dst_path))
480*10966SJordan.Brown@Sun.COM 		return (EINVAL);
481*10966SJordan.Brown@Sun.COM 
482*10966SJordan.Brown@Sun.COM 	if (src_fqi->fq_fnode) {
483*10966SJordan.Brown@Sun.COM 		if (SMB_IS_STREAM(src_fnode))
484*10966SJordan.Brown@Sun.COM 			return (EINVAL);
485*10966SJordan.Brown@Sun.COM 	} else {
486*10966SJordan.Brown@Sun.COM 		if (smb_is_stream_name(src_path))
487*10966SJordan.Brown@Sun.COM 			return (EINVAL);
488*10966SJordan.Brown@Sun.COM 	}
489*10966SJordan.Brown@Sun.COM 
490*10966SJordan.Brown@Sun.COM 	return (0);
491*10966SJordan.Brown@Sun.COM }
492*10966SJordan.Brown@Sun.COM 
493*10966SJordan.Brown@Sun.COM 
494*10966SJordan.Brown@Sun.COM /*
4959914Samw@Sun.COM  * smb_make_link
4969914Samw@Sun.COM  *
497*10966SJordan.Brown@Sun.COM  * Creating a hard link (adding an additional name) for a file.
4989914Samw@Sun.COM  *
4999914Samw@Sun.COM  * If the source and destination are identical, we go through all
5009914Samw@Sun.COM  * the checks but we don't create a link.
5019914Samw@Sun.COM  *
502*10966SJordan.Brown@Sun.COM  * If the file is a symlink we create the hardlink on the target
503*10966SJordan.Brown@Sun.COM  * of the symlink (i.e. use SMB_FOLLOW_LINKS when looking up src).
504*10966SJordan.Brown@Sun.COM  * If the target of the symlink does not exist we fail with ENOENT.
505*10966SJordan.Brown@Sun.COM  *
5069914Samw@Sun.COM  * Returns errno values.
5079914Samw@Sun.COM  */
5089914Samw@Sun.COM static int
5099914Samw@Sun.COM smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
5109914Samw@Sun.COM {
511*10966SJordan.Brown@Sun.COM 	smb_node_t *tnode;
512*10966SJordan.Brown@Sun.COM 	char *path;
513*10966SJordan.Brown@Sun.COM 	int rc;
514*10966SJordan.Brown@Sun.COM 
515*10966SJordan.Brown@Sun.COM 	/* Cannnot create link on named stream */
516*10966SJordan.Brown@Sun.COM 	if (smb_is_stream_name(src_fqi->fq_path.pn_path) ||
517*10966SJordan.Brown@Sun.COM 	    smb_is_stream_name(dst_fqi->fq_path.pn_path)) {
518*10966SJordan.Brown@Sun.COM 		return (EINVAL);
519*10966SJordan.Brown@Sun.COM 	}
520*10966SJordan.Brown@Sun.COM 
521*10966SJordan.Brown@Sun.COM 	/* lookup and validate src node */
522*10966SJordan.Brown@Sun.COM 	rc = smb_rename_lookup_src(sr);
523*10966SJordan.Brown@Sun.COM 	if (rc != 0)
524*10966SJordan.Brown@Sun.COM 		return (rc);
525*10966SJordan.Brown@Sun.COM 
526*10966SJordan.Brown@Sun.COM 	/* if src and dest paths match we're done */
527*10966SJordan.Brown@Sun.COM 	if (smb_strcasecmp(src_fqi->fq_path.pn_path,
528*10966SJordan.Brown@Sun.COM 	    dst_fqi->fq_path.pn_path, 0) == 0) {
529*10966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
530*10966SJordan.Brown@Sun.COM 		return (0);
531*10966SJordan.Brown@Sun.COM 	}
532*10966SJordan.Brown@Sun.COM 
533*10966SJordan.Brown@Sun.COM 	/* find the destination dnode and last_comp */
534*10966SJordan.Brown@Sun.COM 	tnode = sr->tid_tree->t_snode;
535*10966SJordan.Brown@Sun.COM 	path = dst_fqi->fq_path.pn_path;
536*10966SJordan.Brown@Sun.COM 	rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
537*10966SJordan.Brown@Sun.COM 	    &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
538*10966SJordan.Brown@Sun.COM 	if (rc != 0) {
539*10966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
540*10966SJordan.Brown@Sun.COM 		return (rc);
541*10966SJordan.Brown@Sun.COM 	}
542*10966SJordan.Brown@Sun.COM 
543*10966SJordan.Brown@Sun.COM 	/* If name match in same directory, we're done */
544*10966SJordan.Brown@Sun.COM 	if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) &&
545*10966SJordan.Brown@Sun.COM 	    (smb_strcasecmp(src_fqi->fq_fnode->od_name,
546*10966SJordan.Brown@Sun.COM 	    dst_fqi->fq_last_comp, 0) == 0)) {
547*10966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
548*10966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_dnode);
549*10966SJordan.Brown@Sun.COM 		return (0);
550*10966SJordan.Brown@Sun.COM 	}
551*10966SJordan.Brown@Sun.COM 
552*10966SJordan.Brown@Sun.COM 	/* Lookup the destination node. It MUST NOT exist. */
553*10966SJordan.Brown@Sun.COM 	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
554*10966SJordan.Brown@Sun.COM 	    dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode);
555*10966SJordan.Brown@Sun.COM 	if (rc == 0) {
556*10966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_fnode);
557*10966SJordan.Brown@Sun.COM 		rc = EEXIST;
558*10966SJordan.Brown@Sun.COM 	}
559*10966SJordan.Brown@Sun.COM 	if (rc != ENOENT) {
560*10966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
561*10966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_dnode);
562*10966SJordan.Brown@Sun.COM 		return (rc);
563*10966SJordan.Brown@Sun.COM 	}
564*10966SJordan.Brown@Sun.COM 
565*10966SJordan.Brown@Sun.COM 	rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode,
566*10966SJordan.Brown@Sun.COM 	    dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
567*10966SJordan.Brown@Sun.COM 
568*10966SJordan.Brown@Sun.COM 	smb_rename_release_src(sr);
569*10966SJordan.Brown@Sun.COM 	if (rc == 0)
570*10966SJordan.Brown@Sun.COM 		smb_node_notify_change(dst_fqi->fq_dnode);
571*10966SJordan.Brown@Sun.COM 	smb_node_release(dst_fqi->fq_dnode);
572*10966SJordan.Brown@Sun.COM 	return (rc);
573*10966SJordan.Brown@Sun.COM }
574*10966SJordan.Brown@Sun.COM 
575*10966SJordan.Brown@Sun.COM /*
576*10966SJordan.Brown@Sun.COM  * smb_rename_lookup_src
577*10966SJordan.Brown@Sun.COM  *
578*10966SJordan.Brown@Sun.COM  * Lookup the src node, checking for sharing violations and
579*10966SJordan.Brown@Sun.COM  * breaking any existing oplock.
580*10966SJordan.Brown@Sun.COM  * Populate sr->arg.dirop.fqi
581*10966SJordan.Brown@Sun.COM  *
582*10966SJordan.Brown@Sun.COM  * Upon success, the dnode and fnode will have holds and the
583*10966SJordan.Brown@Sun.COM  * fnode will be in a critical section. These should be
584*10966SJordan.Brown@Sun.COM  * released using smb_rename_release_src().
585*10966SJordan.Brown@Sun.COM  *
586*10966SJordan.Brown@Sun.COM  * Returns errno values.
587*10966SJordan.Brown@Sun.COM  */
588*10966SJordan.Brown@Sun.COM static int
589*10966SJordan.Brown@Sun.COM smb_rename_lookup_src(smb_request_t *sr)
590*10966SJordan.Brown@Sun.COM {
591*10966SJordan.Brown@Sun.COM 	smb_node_t *src_node, *tnode;
5929914Samw@Sun.COM 	DWORD status;
5939914Samw@Sun.COM 	int rc;
5949914Samw@Sun.COM 	int count;
59510504SKeyur.Desai@Sun.COM 	char *path;
5969914Samw@Sun.COM 
597*10966SJordan.Brown@Sun.COM 	struct dirop *dirop = &sr->arg.dirop;
598*10966SJordan.Brown@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
59910504SKeyur.Desai@Sun.COM 
600*10966SJordan.Brown@Sun.COM 	if (smb_is_stream_name(src_fqi->fq_path.pn_path))
601*10966SJordan.Brown@Sun.COM 		return (EINVAL);
602*10966SJordan.Brown@Sun.COM 
603*10966SJordan.Brown@Sun.COM 	/* Lookup the source node */
604*10966SJordan.Brown@Sun.COM 	tnode = sr->tid_tree->t_snode;
60510504SKeyur.Desai@Sun.COM 	path = src_fqi->fq_path.pn_path;
60610504SKeyur.Desai@Sun.COM 	rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
60710504SKeyur.Desai@Sun.COM 	    &src_fqi->fq_dnode, src_fqi->fq_last_comp);
60810504SKeyur.Desai@Sun.COM 	if (rc != 0)
6099914Samw@Sun.COM 		return (rc);
6109914Samw@Sun.COM 
611*10966SJordan.Brown@Sun.COM 	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
61210504SKeyur.Desai@Sun.COM 	    src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
61310504SKeyur.Desai@Sun.COM 	if (rc != 0) {
61410504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
61510504SKeyur.Desai@Sun.COM 		return (rc);
61610504SKeyur.Desai@Sun.COM 	}
6179914Samw@Sun.COM 
618*10966SJordan.Brown@Sun.COM 	/* Not valid to create hardlink for directory */
619*10966SJordan.Brown@Sun.COM 	if ((dirop->info_level == SMB_NT_RENAME_SET_LINK_INFO) &&
620*10966SJordan.Brown@Sun.COM 	    (smb_node_is_dir(src_fqi->fq_fnode))) {
621*10966SJordan.Brown@Sun.COM 		smb_node_release(src_fqi->fq_fnode);
622*10966SJordan.Brown@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
623*10966SJordan.Brown@Sun.COM 		return (EISDIR);
624*10966SJordan.Brown@Sun.COM 	}
625*10966SJordan.Brown@Sun.COM 
626*10966SJordan.Brown@Sun.COM 	src_node = src_fqi->fq_fnode;
627*10966SJordan.Brown@Sun.COM 
628*10966SJordan.Brown@Sun.COM 	rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr);
62910504SKeyur.Desai@Sun.COM 	if (rc != 0) {
63010504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_fnode);
63110504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
63210504SKeyur.Desai@Sun.COM 		return (rc);
63310504SKeyur.Desai@Sun.COM 	}
6349914Samw@Sun.COM 
6359914Samw@Sun.COM 	/*
6369914Samw@Sun.COM 	 * Break the oplock before access checks. If a client
6379914Samw@Sun.COM 	 * has a file open, this will force a flush or close,
6389914Samw@Sun.COM 	 * which may affect the outcome of any share checking.
6399914Samw@Sun.COM 	 */
640*10966SJordan.Brown@Sun.COM 	(void) smb_oplock_break(src_node, sr->session, B_FALSE);
6419914Samw@Sun.COM 
6429914Samw@Sun.COM 	for (count = 0; count <= 3; count++) {
6439914Samw@Sun.COM 		if (count) {
644*10966SJordan.Brown@Sun.COM 			smb_node_end_crit(src_node);
6459914Samw@Sun.COM 			delay(MSEC_TO_TICK(400));
6469914Samw@Sun.COM 		}
6479914Samw@Sun.COM 
648*10966SJordan.Brown@Sun.COM 		smb_node_start_crit(src_node, RW_READER);
6499914Samw@Sun.COM 
650*10966SJordan.Brown@Sun.COM 		status = smb_node_rename_check(src_node);
6519914Samw@Sun.COM 		if (status != NT_STATUS_SHARING_VIOLATION)
6529914Samw@Sun.COM 			break;
6539914Samw@Sun.COM 	}
6549914Samw@Sun.COM 
6559914Samw@Sun.COM 	if (status == NT_STATUS_SHARING_VIOLATION) {
656*10966SJordan.Brown@Sun.COM 		smb_node_end_crit(src_node);
65710504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_fnode);
65810504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
65910504SKeyur.Desai@Sun.COM 		return (EPIPE); /* = ERRbadshare */
6609914Samw@Sun.COM 	}
6619914Samw@Sun.COM 
662*10966SJordan.Brown@Sun.COM 	status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE);
6639914Samw@Sun.COM 	if (status != NT_STATUS_SUCCESS) {
664*10966SJordan.Brown@Sun.COM 		smb_node_end_crit(src_node);
66510504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_fnode);
66610504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
66710504SKeyur.Desai@Sun.COM 		return (EACCES);
6689914Samw@Sun.COM 	}
6699914Samw@Sun.COM 
670*10966SJordan.Brown@Sun.COM 	return (0);
671*10966SJordan.Brown@Sun.COM }
6729914Samw@Sun.COM 
673*10966SJordan.Brown@Sun.COM /*
674*10966SJordan.Brown@Sun.COM  * smb_rename_release_src
675*10966SJordan.Brown@Sun.COM  */
676*10966SJordan.Brown@Sun.COM static void
677*10966SJordan.Brown@Sun.COM smb_rename_release_src(smb_request_t *sr)
678*10966SJordan.Brown@Sun.COM {
679*10966SJordan.Brown@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
68010504SKeyur.Desai@Sun.COM 
681*10966SJordan.Brown@Sun.COM 	smb_node_end_crit(src_fqi->fq_fnode);
68210504SKeyur.Desai@Sun.COM 	smb_node_release(src_fqi->fq_fnode);
6839914Samw@Sun.COM 	smb_node_release(src_fqi->fq_dnode);
6849914Samw@Sun.COM }
6859914Samw@Sun.COM 
686*10966SJordan.Brown@Sun.COM 
6879914Samw@Sun.COM static int
68810001SJoyce.McIntosh@Sun.COM smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr)
6899914Samw@Sun.COM {
69010001SJoyce.McIntosh@Sun.COM 	smb_attr_t attr;
6919914Samw@Sun.COM 
69210001SJoyce.McIntosh@Sun.COM 	if (smb_node_getattr(sr, node, &attr) != 0)
69310001SJoyce.McIntosh@Sun.COM 		return (EIO);
69410001SJoyce.McIntosh@Sun.COM 
69510001SJoyce.McIntosh@Sun.COM 	if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) &&
69610001SJoyce.McIntosh@Sun.COM 	    !(SMB_SEARCH_HIDDEN(sattr)))
6979914Samw@Sun.COM 		return (ESRCH);
6989914Samw@Sun.COM 
69910001SJoyce.McIntosh@Sun.COM 	if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) &&
70010001SJoyce.McIntosh@Sun.COM 	    !(SMB_SEARCH_SYSTEM(sattr)))
7019914Samw@Sun.COM 		return (ESRCH);
7029914Samw@Sun.COM 
7039914Samw@Sun.COM 	return (0);
7049914Samw@Sun.COM }
7059914Samw@Sun.COM 
7069914Samw@Sun.COM /*
7079914Samw@Sun.COM  * The following values are based on observed WFWG, Windows 9x, Windows NT
7089914Samw@Sun.COM  * and Windows 2000 behaviour.
7099914Samw@Sun.COM  *
7109914Samw@Sun.COM  * ERROR_FILE_EXISTS doesn't work for Windows 98 clients.
7119914Samw@Sun.COM  *
7129914Samw@Sun.COM  * Windows 95 clients don't see the problem because the target is deleted
7139914Samw@Sun.COM  * before the rename request.
7149914Samw@Sun.COM  */
7159914Samw@Sun.COM static void
7169914Samw@Sun.COM smb_rename_set_error(smb_request_t *sr, int errnum)
7179914Samw@Sun.COM {
7189914Samw@Sun.COM 	static struct {
7199914Samw@Sun.COM 		int errnum;
7209914Samw@Sun.COM 		uint16_t errcode;
7219914Samw@Sun.COM 		uint32_t status32;
7229914Samw@Sun.COM 	} rc_map[] = {
7239914Samw@Sun.COM 	{ EEXIST, ERROR_ALREADY_EXISTS,	NT_STATUS_OBJECT_NAME_COLLISION },
7249914Samw@Sun.COM 	{ EPIPE,  ERROR_SHARING_VIOLATION, NT_STATUS_SHARING_VIOLATION },
7259914Samw@Sun.COM 	{ ENOENT, ERROR_FILE_NOT_FOUND,	NT_STATUS_OBJECT_NAME_NOT_FOUND },
7269914Samw@Sun.COM 	{ ESRCH,  ERROR_FILE_NOT_FOUND,	NT_STATUS_NO_SUCH_FILE },
7279914Samw@Sun.COM 	{ EINVAL, ERROR_INVALID_PARAMETER, NT_STATUS_INVALID_PARAMETER },
72810001SJoyce.McIntosh@Sun.COM 	{ EACCES, ERROR_ACCESS_DENIED,	NT_STATUS_ACCESS_DENIED },
729*10966SJordan.Brown@Sun.COM 	{ EISDIR, ERROR_ACCESS_DENIED,	NT_STATUS_FILE_IS_A_DIRECTORY },
73010001SJoyce.McIntosh@Sun.COM 	{ EIO,    ERROR_INTERNAL_ERROR,	NT_STATUS_INTERNAL_ERROR }
7319914Samw@Sun.COM 	};
7329914Samw@Sun.COM 
7339914Samw@Sun.COM 	int i;
7349914Samw@Sun.COM 
7359914Samw@Sun.COM 	if (errnum == 0)
7369914Samw@Sun.COM 		return;
7379914Samw@Sun.COM 
7389914Samw@Sun.COM 	for (i = 0; i < sizeof (rc_map)/sizeof (rc_map[0]); ++i) {
7399914Samw@Sun.COM 		if (rc_map[i].errnum == errnum) {
7409914Samw@Sun.COM 			smbsr_error(sr, rc_map[i].status32,
7419914Samw@Sun.COM 			    ERRDOS, rc_map[i].errcode);
7429914Samw@Sun.COM 			return;
7439914Samw@Sun.COM 		}
7449914Samw@Sun.COM 	}
7459914Samw@Sun.COM 
7469914Samw@Sun.COM 	smbsr_errno(sr, errnum);
7479914Samw@Sun.COM }
748