xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_rename.c (revision 11337:1f8fe42c7b83)
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>
2710966SJordan.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 
4410966SJordan.Brown@Sun.COM /*
4510966SJordan.Brown@Sun.COM  * SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag
4610966SJordan.Brown@Sun.COM  */
4710966SJordan.Brown@Sun.COM #define	SMB_RENAME_FLAG_OVERWRITE	0x001
4810966SJordan.Brown@Sun.COM 
4910966SJordan.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 *);
5110966SJordan.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 
5510966SJordan.Brown@Sun.COM static int smb_rename_lookup_src(smb_request_t *);
5610966SJordan.Brown@Sun.COM static void smb_rename_release_src(smb_request_t *);
5710966SJordan.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
7310966SJordan.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 
11410966SJordan.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
13610966SJordan.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 
180*11337SWilliam.Krier@Sun.COM 	smb_convert_wildcards(src_fqi->fq_path.pn_path);
181*11337SWilliam.Krier@Sun.COM 	if (smb_contains_wildcards(src_fqi->fq_path.pn_path)) {
1829914Samw@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
1839914Samw@Sun.COM 		    ERRDOS, ERROR_BAD_PATHNAME);
1849914Samw@Sun.COM 		return (SDRC_ERROR);
1859914Samw@Sun.COM 	}
1869914Samw@Sun.COM 
1879914Samw@Sun.COM 	switch (sr->arg.dirop.info_level) {
1889914Samw@Sun.COM 	case SMB_NT_RENAME_SET_LINK_INFO:
1899914Samw@Sun.COM 		rc = smb_make_link(sr, src_fqi, dst_fqi);
1909914Samw@Sun.COM 		break;
1919914Samw@Sun.COM 	case SMB_NT_RENAME_RENAME_FILE:
1929914Samw@Sun.COM 	case SMB_NT_RENAME_MOVE_FILE:
19310966SJordan.Brown@Sun.COM 		rc = smb_common_rename(sr, src_fqi, dst_fqi);
1949914Samw@Sun.COM 		break;
1959914Samw@Sun.COM 	case SMB_NT_RENAME_MOVE_CLUSTER_INFO:
1969914Samw@Sun.COM 		rc = EINVAL;
1979914Samw@Sun.COM 		break;
1989914Samw@Sun.COM 	default:
1999914Samw@Sun.COM 		rc = EACCES;
2009914Samw@Sun.COM 		break;
2019914Samw@Sun.COM 	}
2029914Samw@Sun.COM 
2039914Samw@Sun.COM 	if (rc != 0) {
2049914Samw@Sun.COM 		smb_rename_set_error(sr, rc);
2059914Samw@Sun.COM 		return (SDRC_ERROR);
2069914Samw@Sun.COM 	}
2079914Samw@Sun.COM 
2089914Samw@Sun.COM 	rc = smbsr_encode_empty_result(sr);
2099914Samw@Sun.COM 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
2109914Samw@Sun.COM }
2119914Samw@Sun.COM 
2129914Samw@Sun.COM /*
21310966SJordan.Brown@Sun.COM  * smb_nt_transact_rename
21410966SJordan.Brown@Sun.COM  *
21510966SJordan.Brown@Sun.COM  * Windows servers return SUCCESS without renaming file.
21610966SJordan.Brown@Sun.COM  * The only check required is to check that the handle (fid) is valid.
21710966SJordan.Brown@Sun.COM  */
21810966SJordan.Brown@Sun.COM smb_sdrc_t
21910966SJordan.Brown@Sun.COM smb_nt_transact_rename(smb_request_t *sr, smb_xa_t *xa)
22010966SJordan.Brown@Sun.COM {
22110966SJordan.Brown@Sun.COM 	if (smb_mbc_decodef(&xa->req_param_mb, "w", &sr->smb_fid) != 0)
22210966SJordan.Brown@Sun.COM 		return (SDRC_ERROR);
22310966SJordan.Brown@Sun.COM 
22410966SJordan.Brown@Sun.COM 	smbsr_lookup_file(sr);
22510966SJordan.Brown@Sun.COM 	if (sr->fid_ofile == NULL) {
22610966SJordan.Brown@Sun.COM 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
22710966SJordan.Brown@Sun.COM 		return (SDRC_ERROR);
22810966SJordan.Brown@Sun.COM 	}
22910966SJordan.Brown@Sun.COM 	smbsr_release_file(sr);
23010966SJordan.Brown@Sun.COM 
23110966SJordan.Brown@Sun.COM 	return (SDRC_SUCCESS);
23210966SJordan.Brown@Sun.COM }
23310966SJordan.Brown@Sun.COM 
23410966SJordan.Brown@Sun.COM /*
23510966SJordan.Brown@Sun.COM  * smb_trans2_rename
23610966SJordan.Brown@Sun.COM  *
23710966SJordan.Brown@Sun.COM  * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo
23810966SJordan.Brown@Sun.COM  * and Trans2_Set_PathInfo.
23910966SJordan.Brown@Sun.COM  * If the new filename (dst_fqi) already exists it may be overwritten
24010966SJordan.Brown@Sun.COM  * if flags == 1.
24110966SJordan.Brown@Sun.COM  */
24210966SJordan.Brown@Sun.COM int
24310966SJordan.Brown@Sun.COM smb_trans2_rename(smb_request_t *sr, smb_node_t *node, char *fname, int flags)
24410966SJordan.Brown@Sun.COM {
24510966SJordan.Brown@Sun.COM 	int rc;
24610966SJordan.Brown@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
24710966SJordan.Brown@Sun.COM 	smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
24810966SJordan.Brown@Sun.COM 
24910966SJordan.Brown@Sun.COM 	sr->arg.dirop.flags = flags ? SMB_RENAME_FLAG_OVERWRITE : 0;
25010966SJordan.Brown@Sun.COM 	sr->arg.dirop.info_level = SMB_NT_RENAME_RENAME_FILE;
25110966SJordan.Brown@Sun.COM 
25210966SJordan.Brown@Sun.COM 	src_fqi->fq_sattr = SMB_SEARCH_ATTRIBUTES;
25310966SJordan.Brown@Sun.COM 	src_fqi->fq_fnode = node;
25410966SJordan.Brown@Sun.COM 	src_fqi->fq_dnode = node->n_dnode;
25510966SJordan.Brown@Sun.COM 
25610966SJordan.Brown@Sun.COM 	dst_fqi->fq_path.pn_path = fname;
25710966SJordan.Brown@Sun.COM 	dst_fqi->fq_dnode = node->n_dnode;
25810966SJordan.Brown@Sun.COM 	(void) strlcpy(dst_fqi->fq_last_comp, fname, MAXNAMELEN);
25910966SJordan.Brown@Sun.COM 
26010966SJordan.Brown@Sun.COM 	rc = smb_common_rename(sr, src_fqi, dst_fqi);
26110966SJordan.Brown@Sun.COM 	if (rc != 0) {
26210966SJordan.Brown@Sun.COM 		smb_rename_set_error(sr, rc);
26310966SJordan.Brown@Sun.COM 		return (-1);
26410966SJordan.Brown@Sun.COM 	}
26510966SJordan.Brown@Sun.COM 
26610966SJordan.Brown@Sun.COM 	return (0);
26710966SJordan.Brown@Sun.COM }
26810966SJordan.Brown@Sun.COM 
26910966SJordan.Brown@Sun.COM /*
27010966SJordan.Brown@Sun.COM  * smb_common_rename
27110966SJordan.Brown@Sun.COM  *
27210966SJordan.Brown@Sun.COM  * Common code for renaming a file.
27310966SJordan.Brown@Sun.COM  *
27410966SJordan.Brown@Sun.COM  * If the source and destination are identical, we go through all
27510966SJordan.Brown@Sun.COM  * the checks but we don't actually do the rename.  If the source
27610966SJordan.Brown@Sun.COM  * and destination files differ only in case, we do a case-sensitive
27710966SJordan.Brown@Sun.COM  * rename.  Otherwise, we do a full case-insensitive rename.
27810966SJordan.Brown@Sun.COM  *
27910966SJordan.Brown@Sun.COM  * Returns errno values.
28010966SJordan.Brown@Sun.COM  */
28110966SJordan.Brown@Sun.COM static int
28210966SJordan.Brown@Sun.COM smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
28310966SJordan.Brown@Sun.COM {
28410966SJordan.Brown@Sun.COM 	smb_node_t *src_fnode, *src_dnode, *dst_fnode, *dst_dnode;
28510966SJordan.Brown@Sun.COM 	smb_node_t *tnode;
28610966SJordan.Brown@Sun.COM 	int rc, count;
28710966SJordan.Brown@Sun.COM 	DWORD status;
28810966SJordan.Brown@Sun.COM 	char *new_name, *path;
28910966SJordan.Brown@Sun.COM 
29010966SJordan.Brown@Sun.COM 	path = dst_fqi->fq_path.pn_path;
29110966SJordan.Brown@Sun.COM 
29210966SJordan.Brown@Sun.COM 	/* Check if attempting to rename a stream - not yet supported */
29310966SJordan.Brown@Sun.COM 	rc = smb_rename_check_stream(src_fqi, dst_fqi);
29410966SJordan.Brown@Sun.COM 	if (rc != 0)
29510966SJordan.Brown@Sun.COM 		return (rc);
29610966SJordan.Brown@Sun.COM 
29710966SJordan.Brown@Sun.COM 	/* The source node may already have been provided */
29810966SJordan.Brown@Sun.COM 	if (src_fqi->fq_fnode) {
29910966SJordan.Brown@Sun.COM 		smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
30010966SJordan.Brown@Sun.COM 		smb_node_ref(src_fqi->fq_fnode);
30110966SJordan.Brown@Sun.COM 		smb_node_ref(src_fqi->fq_dnode);
30210966SJordan.Brown@Sun.COM 	} else {
30310966SJordan.Brown@Sun.COM 		/* lookup and validate src node */
30410966SJordan.Brown@Sun.COM 		rc = smb_rename_lookup_src(sr);
30510966SJordan.Brown@Sun.COM 		if (rc != 0)
30610966SJordan.Brown@Sun.COM 			return (rc);
30710966SJordan.Brown@Sun.COM 	}
30810966SJordan.Brown@Sun.COM 
30910966SJordan.Brown@Sun.COM 	src_fnode = src_fqi->fq_fnode;
31010966SJordan.Brown@Sun.COM 	src_dnode = src_fqi->fq_dnode;
31110966SJordan.Brown@Sun.COM 
31210966SJordan.Brown@Sun.COM 	/* Find destination dnode and last_comp */
31310966SJordan.Brown@Sun.COM 	if (dst_fqi->fq_dnode) {
31410966SJordan.Brown@Sun.COM 		smb_node_ref(dst_fqi->fq_dnode);
31510966SJordan.Brown@Sun.COM 	} else {
31610966SJordan.Brown@Sun.COM 		tnode = sr->tid_tree->t_snode;
31710966SJordan.Brown@Sun.COM 		rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
31810966SJordan.Brown@Sun.COM 		    &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
31910966SJordan.Brown@Sun.COM 		if (rc != 0) {
32010966SJordan.Brown@Sun.COM 			smb_rename_release_src(sr);
32110966SJordan.Brown@Sun.COM 			return (rc);
32210966SJordan.Brown@Sun.COM 		}
32310966SJordan.Brown@Sun.COM 	}
32410966SJordan.Brown@Sun.COM 
32510966SJordan.Brown@Sun.COM 	dst_dnode = dst_fqi->fq_dnode;
32610966SJordan.Brown@Sun.COM 	new_name = dst_fqi->fq_last_comp;
32710966SJordan.Brown@Sun.COM 
32810966SJordan.Brown@Sun.COM 	/* If exact name match in same directory, we're done */
32910966SJordan.Brown@Sun.COM 	if ((src_dnode == dst_dnode) &&
33010966SJordan.Brown@Sun.COM 	    (strcmp(src_fnode->od_name, new_name) == 0)) {
33110966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
33210966SJordan.Brown@Sun.COM 		smb_node_release(dst_dnode);
33310966SJordan.Brown@Sun.COM 		return (0);
33410966SJordan.Brown@Sun.COM 	}
33510966SJordan.Brown@Sun.COM 
33610966SJordan.Brown@Sun.COM 	/* Lookup destination node */
33710966SJordan.Brown@Sun.COM 	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
33810966SJordan.Brown@Sun.COM 	    dst_dnode, new_name, &dst_fqi->fq_fnode);
33910966SJordan.Brown@Sun.COM 
340*11337SWilliam.Krier@Sun.COM 	/* If the destination node doesn't already exist, validate new_name. */
341*11337SWilliam.Krier@Sun.COM 	if (rc == ENOENT) {
342*11337SWilliam.Krier@Sun.COM 		if (smb_is_invalid_filename(new_name)) {
343*11337SWilliam.Krier@Sun.COM 			smb_rename_release_src(sr);
344*11337SWilliam.Krier@Sun.COM 			smb_node_release(dst_dnode);
345*11337SWilliam.Krier@Sun.COM 			return (EILSEQ); /* NT_STATUS_OBJECT_NAME_INVALID */
346*11337SWilliam.Krier@Sun.COM 		}
347*11337SWilliam.Krier@Sun.COM 	}
348*11337SWilliam.Krier@Sun.COM 
34910966SJordan.Brown@Sun.COM 	/*
35010966SJordan.Brown@Sun.COM 	 * Handle case where changing case of the same directory entry.
35110966SJordan.Brown@Sun.COM 	 *
35210966SJordan.Brown@Sun.COM 	 * If we found the dst node in the same directory as the src node,
35310966SJordan.Brown@Sun.COM 	 * and their names differ only in case:
35410966SJordan.Brown@Sun.COM 	 *
35510966SJordan.Brown@Sun.COM 	 * If the tree is case sensitive (or mixed):
35610966SJordan.Brown@Sun.COM 	 *  Do case sensitive lookup to see if exact match exists.
35710966SJordan.Brown@Sun.COM 	 *  If the exact match is the same node as src_node we're done.
35810966SJordan.Brown@Sun.COM 	 *
35910966SJordan.Brown@Sun.COM 	 * If the tree is case insensitive:
36010966SJordan.Brown@Sun.COM 	 *  There is currently no way to tell if the case is different
36110966SJordan.Brown@Sun.COM 	 *  or not, so do the rename (unless the specified new name was
36210966SJordan.Brown@Sun.COM 	 *  mangled).
36310966SJordan.Brown@Sun.COM 	 */
36410966SJordan.Brown@Sun.COM 	if ((rc == 0) &&
36510966SJordan.Brown@Sun.COM 	    (src_dnode == dst_dnode) &&
36610966SJordan.Brown@Sun.COM 	    (smb_strcasecmp(src_fnode->od_name,
36710966SJordan.Brown@Sun.COM 	    dst_fqi->fq_fnode->od_name, 0) == 0)) {
36810966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_fnode);
36910966SJordan.Brown@Sun.COM 		dst_fqi->fq_fnode = NULL;
37010966SJordan.Brown@Sun.COM 
37110966SJordan.Brown@Sun.COM 		if (smb_tree_has_feature(sr->tid_tree,
37210966SJordan.Brown@Sun.COM 		    SMB_TREE_NO_CASESENSITIVE)) {
37310966SJordan.Brown@Sun.COM 			if (smb_strcasecmp(src_fnode->od_name,
37410966SJordan.Brown@Sun.COM 			    dst_fqi->fq_last_comp, 0) != 0) {
37510966SJordan.Brown@Sun.COM 				smb_rename_release_src(sr);
37610966SJordan.Brown@Sun.COM 				smb_node_release(dst_dnode);
37710966SJordan.Brown@Sun.COM 				return (0);
37810966SJordan.Brown@Sun.COM 			}
37910966SJordan.Brown@Sun.COM 		} else {
38010966SJordan.Brown@Sun.COM 			rc = smb_fsop_lookup(sr, sr->user_cr,
38110966SJordan.Brown@Sun.COM 			    SMB_CASE_SENSITIVE, tnode, dst_dnode, new_name,
38210966SJordan.Brown@Sun.COM 			    &dst_fqi->fq_fnode);
38310966SJordan.Brown@Sun.COM 
38410966SJordan.Brown@Sun.COM 			if ((rc == 0) &&
38510966SJordan.Brown@Sun.COM 			    (dst_fqi->fq_fnode == src_fnode)) {
38610966SJordan.Brown@Sun.COM 				smb_rename_release_src(sr);
38710966SJordan.Brown@Sun.COM 				smb_node_release(dst_fqi->fq_fnode);
38810966SJordan.Brown@Sun.COM 				smb_node_release(dst_dnode);
38910966SJordan.Brown@Sun.COM 				return (0);
39010966SJordan.Brown@Sun.COM 			}
39110966SJordan.Brown@Sun.COM 		}
39210966SJordan.Brown@Sun.COM 	}
39310966SJordan.Brown@Sun.COM 
39410966SJordan.Brown@Sun.COM 	if ((rc != 0) && (rc != ENOENT)) {
39510966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
39610966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_dnode);
39710966SJordan.Brown@Sun.COM 		return (rc);
39810966SJordan.Brown@Sun.COM 	}
39910966SJordan.Brown@Sun.COM 
40010966SJordan.Brown@Sun.COM 	if (dst_fqi->fq_fnode) {
40110966SJordan.Brown@Sun.COM 		dst_fnode = dst_fqi->fq_fnode;
40210966SJordan.Brown@Sun.COM 
40310966SJordan.Brown@Sun.COM 		if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) {
40410966SJordan.Brown@Sun.COM 			smb_rename_release_src(sr);
40510966SJordan.Brown@Sun.COM 			smb_node_release(dst_fnode);
40610966SJordan.Brown@Sun.COM 			smb_node_release(dst_dnode);
40710966SJordan.Brown@Sun.COM 			return (EEXIST);
40810966SJordan.Brown@Sun.COM 		}
40910966SJordan.Brown@Sun.COM 
41010966SJordan.Brown@Sun.COM 		(void) smb_oplock_break(dst_fnode, sr->session, B_FALSE);
41110966SJordan.Brown@Sun.COM 
41210966SJordan.Brown@Sun.COM 		for (count = 0; count <= 3; count++) {
41310966SJordan.Brown@Sun.COM 			if (count) {
41410966SJordan.Brown@Sun.COM 				smb_node_end_crit(dst_fnode);
41510966SJordan.Brown@Sun.COM 				delay(MSEC_TO_TICK(400));
41610966SJordan.Brown@Sun.COM 			}
41710966SJordan.Brown@Sun.COM 
41810966SJordan.Brown@Sun.COM 			smb_node_start_crit(dst_fnode, RW_READER);
41910966SJordan.Brown@Sun.COM 			status = smb_node_delete_check(dst_fnode);
42010966SJordan.Brown@Sun.COM 
42110966SJordan.Brown@Sun.COM 			if (status != NT_STATUS_SHARING_VIOLATION)
42210966SJordan.Brown@Sun.COM 				break;
42310966SJordan.Brown@Sun.COM 		}
42410966SJordan.Brown@Sun.COM 
42510966SJordan.Brown@Sun.COM 		if (status != NT_STATUS_SHARING_VIOLATION)
42610966SJordan.Brown@Sun.COM 			status = smb_range_check(sr, dst_fnode,
42710966SJordan.Brown@Sun.COM 			    0, UINT64_MAX, B_TRUE);
42810966SJordan.Brown@Sun.COM 
42910966SJordan.Brown@Sun.COM 		if (status != NT_STATUS_SUCCESS) {
43010966SJordan.Brown@Sun.COM 			smb_rename_release_src(sr);
43110966SJordan.Brown@Sun.COM 			smb_node_end_crit(dst_fnode);
43210966SJordan.Brown@Sun.COM 			smb_node_release(dst_fnode);
43310966SJordan.Brown@Sun.COM 			smb_node_release(dst_dnode);
43410966SJordan.Brown@Sun.COM 			return (EACCES);
43510966SJordan.Brown@Sun.COM 		}
43610966SJordan.Brown@Sun.COM 
437*11337SWilliam.Krier@Sun.COM 		new_name = dst_fnode->od_name;
43810966SJordan.Brown@Sun.COM 	}
43910966SJordan.Brown@Sun.COM 
44010966SJordan.Brown@Sun.COM 	rc = smb_fsop_rename(sr, sr->user_cr,
44110966SJordan.Brown@Sun.COM 	    src_dnode, src_fnode->od_name,
44210966SJordan.Brown@Sun.COM 	    dst_dnode, new_name);
44310966SJordan.Brown@Sun.COM 
44410966SJordan.Brown@Sun.COM 	smb_rename_release_src(sr);
44510966SJordan.Brown@Sun.COM 
44610966SJordan.Brown@Sun.COM 	if (rc == 0)
44710966SJordan.Brown@Sun.COM 		smb_node_notify_change(dst_dnode);
44810966SJordan.Brown@Sun.COM 
44910966SJordan.Brown@Sun.COM 	if (dst_fqi->fq_fnode) {
45010966SJordan.Brown@Sun.COM 		smb_node_end_crit(dst_fnode);
45110966SJordan.Brown@Sun.COM 		smb_node_release(dst_fnode);
45210966SJordan.Brown@Sun.COM 	}
45310966SJordan.Brown@Sun.COM 	smb_node_release(dst_dnode);
45410966SJordan.Brown@Sun.COM 
45510966SJordan.Brown@Sun.COM 	return (rc);
45610966SJordan.Brown@Sun.COM }
45710966SJordan.Brown@Sun.COM 
45810966SJordan.Brown@Sun.COM /*
45910966SJordan.Brown@Sun.COM  * smb_rename_check_stream
46010966SJordan.Brown@Sun.COM  *
46110966SJordan.Brown@Sun.COM  * For a stream rename the dst path must begin with ':', or "\\:".
46210966SJordan.Brown@Sun.COM  * We don't yet support stream rename, Return EACCES.
46310966SJordan.Brown@Sun.COM  *
46410966SJordan.Brown@Sun.COM  * If not a stream rename, in accordance with the above rule,
46510966SJordan.Brown@Sun.COM  * it is not valid for either the src or dst to be a stream.
46610966SJordan.Brown@Sun.COM  * Return EINVAL.
46710966SJordan.Brown@Sun.COM  */
46810966SJordan.Brown@Sun.COM static int
46910966SJordan.Brown@Sun.COM smb_rename_check_stream(smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
47010966SJordan.Brown@Sun.COM {
47110966SJordan.Brown@Sun.COM 	smb_node_t *src_fnode = src_fqi->fq_fnode;
47210966SJordan.Brown@Sun.COM 	char *src_path = src_fqi->fq_path.pn_path;
47310966SJordan.Brown@Sun.COM 	char *dst_path = dst_fqi->fq_path.pn_path;
47410966SJordan.Brown@Sun.COM 
47510966SJordan.Brown@Sun.COM 	/* We do not yet support named stream rename - ACCESS DENIED */
47610966SJordan.Brown@Sun.COM 	if ((dst_path[0] == ':') ||
47710966SJordan.Brown@Sun.COM 	    ((dst_path[0] == '\\') && (dst_path[1] == ':'))) {
47810966SJordan.Brown@Sun.COM 		return (EACCES);
47910966SJordan.Brown@Sun.COM 	}
48010966SJordan.Brown@Sun.COM 
48110966SJordan.Brown@Sun.COM 	/*
48210966SJordan.Brown@Sun.COM 	 * If not stream rename (above) neither src or dst can be
48310966SJordan.Brown@Sun.COM 	 * a named stream.
48410966SJordan.Brown@Sun.COM 	 */
48510966SJordan.Brown@Sun.COM 
48610966SJordan.Brown@Sun.COM 	if (smb_is_stream_name(dst_path))
48710966SJordan.Brown@Sun.COM 		return (EINVAL);
48810966SJordan.Brown@Sun.COM 
48910966SJordan.Brown@Sun.COM 	if (src_fqi->fq_fnode) {
49010966SJordan.Brown@Sun.COM 		if (SMB_IS_STREAM(src_fnode))
49110966SJordan.Brown@Sun.COM 			return (EINVAL);
49210966SJordan.Brown@Sun.COM 	} else {
49310966SJordan.Brown@Sun.COM 		if (smb_is_stream_name(src_path))
49410966SJordan.Brown@Sun.COM 			return (EINVAL);
49510966SJordan.Brown@Sun.COM 	}
49610966SJordan.Brown@Sun.COM 
49710966SJordan.Brown@Sun.COM 	return (0);
49810966SJordan.Brown@Sun.COM }
49910966SJordan.Brown@Sun.COM 
50010966SJordan.Brown@Sun.COM 
50110966SJordan.Brown@Sun.COM /*
5029914Samw@Sun.COM  * smb_make_link
5039914Samw@Sun.COM  *
50410966SJordan.Brown@Sun.COM  * Creating a hard link (adding an additional name) for a file.
5059914Samw@Sun.COM  *
5069914Samw@Sun.COM  * If the source and destination are identical, we go through all
5079914Samw@Sun.COM  * the checks but we don't create a link.
5089914Samw@Sun.COM  *
50910966SJordan.Brown@Sun.COM  * If the file is a symlink we create the hardlink on the target
51010966SJordan.Brown@Sun.COM  * of the symlink (i.e. use SMB_FOLLOW_LINKS when looking up src).
51110966SJordan.Brown@Sun.COM  * If the target of the symlink does not exist we fail with ENOENT.
51210966SJordan.Brown@Sun.COM  *
5139914Samw@Sun.COM  * Returns errno values.
5149914Samw@Sun.COM  */
5159914Samw@Sun.COM static int
5169914Samw@Sun.COM smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
5179914Samw@Sun.COM {
51810966SJordan.Brown@Sun.COM 	smb_node_t *tnode;
51910966SJordan.Brown@Sun.COM 	char *path;
52010966SJordan.Brown@Sun.COM 	int rc;
52110966SJordan.Brown@Sun.COM 
52210966SJordan.Brown@Sun.COM 	/* Cannnot create link on named stream */
52310966SJordan.Brown@Sun.COM 	if (smb_is_stream_name(src_fqi->fq_path.pn_path) ||
52410966SJordan.Brown@Sun.COM 	    smb_is_stream_name(dst_fqi->fq_path.pn_path)) {
52510966SJordan.Brown@Sun.COM 		return (EINVAL);
52610966SJordan.Brown@Sun.COM 	}
52710966SJordan.Brown@Sun.COM 
52810966SJordan.Brown@Sun.COM 	/* lookup and validate src node */
52910966SJordan.Brown@Sun.COM 	rc = smb_rename_lookup_src(sr);
53010966SJordan.Brown@Sun.COM 	if (rc != 0)
53110966SJordan.Brown@Sun.COM 		return (rc);
53210966SJordan.Brown@Sun.COM 
53310966SJordan.Brown@Sun.COM 	/* if src and dest paths match we're done */
53410966SJordan.Brown@Sun.COM 	if (smb_strcasecmp(src_fqi->fq_path.pn_path,
53510966SJordan.Brown@Sun.COM 	    dst_fqi->fq_path.pn_path, 0) == 0) {
53610966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
53710966SJordan.Brown@Sun.COM 		return (0);
53810966SJordan.Brown@Sun.COM 	}
53910966SJordan.Brown@Sun.COM 
54010966SJordan.Brown@Sun.COM 	/* find the destination dnode and last_comp */
54110966SJordan.Brown@Sun.COM 	tnode = sr->tid_tree->t_snode;
54210966SJordan.Brown@Sun.COM 	path = dst_fqi->fq_path.pn_path;
54310966SJordan.Brown@Sun.COM 	rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
54410966SJordan.Brown@Sun.COM 	    &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
54510966SJordan.Brown@Sun.COM 	if (rc != 0) {
54610966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
54710966SJordan.Brown@Sun.COM 		return (rc);
54810966SJordan.Brown@Sun.COM 	}
54910966SJordan.Brown@Sun.COM 
55010966SJordan.Brown@Sun.COM 	/* If name match in same directory, we're done */
55110966SJordan.Brown@Sun.COM 	if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) &&
55210966SJordan.Brown@Sun.COM 	    (smb_strcasecmp(src_fqi->fq_fnode->od_name,
55310966SJordan.Brown@Sun.COM 	    dst_fqi->fq_last_comp, 0) == 0)) {
55410966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
55510966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_dnode);
55610966SJordan.Brown@Sun.COM 		return (0);
55710966SJordan.Brown@Sun.COM 	}
55810966SJordan.Brown@Sun.COM 
559*11337SWilliam.Krier@Sun.COM 	if (smb_is_invalid_filename(dst_fqi->fq_last_comp)) {
560*11337SWilliam.Krier@Sun.COM 		smb_rename_release_src(sr);
561*11337SWilliam.Krier@Sun.COM 		smb_node_release(dst_fqi->fq_dnode);
562*11337SWilliam.Krier@Sun.COM 		return (EILSEQ); /* NT_STATUS_INVALID_OBJECT_NAME */
563*11337SWilliam.Krier@Sun.COM 	}
564*11337SWilliam.Krier@Sun.COM 
56510966SJordan.Brown@Sun.COM 	/* Lookup the destination node. It MUST NOT exist. */
56610966SJordan.Brown@Sun.COM 	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
56710966SJordan.Brown@Sun.COM 	    dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode);
56810966SJordan.Brown@Sun.COM 	if (rc == 0) {
56910966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_fnode);
57010966SJordan.Brown@Sun.COM 		rc = EEXIST;
57110966SJordan.Brown@Sun.COM 	}
57210966SJordan.Brown@Sun.COM 	if (rc != ENOENT) {
57310966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
57410966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_dnode);
57510966SJordan.Brown@Sun.COM 		return (rc);
57610966SJordan.Brown@Sun.COM 	}
57710966SJordan.Brown@Sun.COM 
57810966SJordan.Brown@Sun.COM 	rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode,
57910966SJordan.Brown@Sun.COM 	    dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
58010966SJordan.Brown@Sun.COM 
58110966SJordan.Brown@Sun.COM 	smb_rename_release_src(sr);
58210966SJordan.Brown@Sun.COM 	if (rc == 0)
58310966SJordan.Brown@Sun.COM 		smb_node_notify_change(dst_fqi->fq_dnode);
58410966SJordan.Brown@Sun.COM 	smb_node_release(dst_fqi->fq_dnode);
58510966SJordan.Brown@Sun.COM 	return (rc);
58610966SJordan.Brown@Sun.COM }
58710966SJordan.Brown@Sun.COM 
58810966SJordan.Brown@Sun.COM /*
58910966SJordan.Brown@Sun.COM  * smb_rename_lookup_src
59010966SJordan.Brown@Sun.COM  *
59110966SJordan.Brown@Sun.COM  * Lookup the src node, checking for sharing violations and
59210966SJordan.Brown@Sun.COM  * breaking any existing oplock.
59310966SJordan.Brown@Sun.COM  * Populate sr->arg.dirop.fqi
59410966SJordan.Brown@Sun.COM  *
59510966SJordan.Brown@Sun.COM  * Upon success, the dnode and fnode will have holds and the
59610966SJordan.Brown@Sun.COM  * fnode will be in a critical section. These should be
59710966SJordan.Brown@Sun.COM  * released using smb_rename_release_src().
59810966SJordan.Brown@Sun.COM  *
59910966SJordan.Brown@Sun.COM  * Returns errno values.
60010966SJordan.Brown@Sun.COM  */
60110966SJordan.Brown@Sun.COM static int
60210966SJordan.Brown@Sun.COM smb_rename_lookup_src(smb_request_t *sr)
60310966SJordan.Brown@Sun.COM {
60410966SJordan.Brown@Sun.COM 	smb_node_t *src_node, *tnode;
6059914Samw@Sun.COM 	DWORD status;
6069914Samw@Sun.COM 	int rc;
6079914Samw@Sun.COM 	int count;
60810504SKeyur.Desai@Sun.COM 	char *path;
6099914Samw@Sun.COM 
61010966SJordan.Brown@Sun.COM 	struct dirop *dirop = &sr->arg.dirop;
61110966SJordan.Brown@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
61210504SKeyur.Desai@Sun.COM 
61310966SJordan.Brown@Sun.COM 	if (smb_is_stream_name(src_fqi->fq_path.pn_path))
61410966SJordan.Brown@Sun.COM 		return (EINVAL);
61510966SJordan.Brown@Sun.COM 
61610966SJordan.Brown@Sun.COM 	/* Lookup the source node */
61710966SJordan.Brown@Sun.COM 	tnode = sr->tid_tree->t_snode;
61810504SKeyur.Desai@Sun.COM 	path = src_fqi->fq_path.pn_path;
61910504SKeyur.Desai@Sun.COM 	rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
62010504SKeyur.Desai@Sun.COM 	    &src_fqi->fq_dnode, src_fqi->fq_last_comp);
62110504SKeyur.Desai@Sun.COM 	if (rc != 0)
6229914Samw@Sun.COM 		return (rc);
6239914Samw@Sun.COM 
62410966SJordan.Brown@Sun.COM 	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
62510504SKeyur.Desai@Sun.COM 	    src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
62610504SKeyur.Desai@Sun.COM 	if (rc != 0) {
62710504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
62810504SKeyur.Desai@Sun.COM 		return (rc);
62910504SKeyur.Desai@Sun.COM 	}
6309914Samw@Sun.COM 
63110966SJordan.Brown@Sun.COM 	/* Not valid to create hardlink for directory */
63210966SJordan.Brown@Sun.COM 	if ((dirop->info_level == SMB_NT_RENAME_SET_LINK_INFO) &&
63310966SJordan.Brown@Sun.COM 	    (smb_node_is_dir(src_fqi->fq_fnode))) {
63410966SJordan.Brown@Sun.COM 		smb_node_release(src_fqi->fq_fnode);
63510966SJordan.Brown@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
63610966SJordan.Brown@Sun.COM 		return (EISDIR);
63710966SJordan.Brown@Sun.COM 	}
63810966SJordan.Brown@Sun.COM 
63910966SJordan.Brown@Sun.COM 	src_node = src_fqi->fq_fnode;
64010966SJordan.Brown@Sun.COM 
64110966SJordan.Brown@Sun.COM 	rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr);
64210504SKeyur.Desai@Sun.COM 	if (rc != 0) {
64310504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_fnode);
64410504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
64510504SKeyur.Desai@Sun.COM 		return (rc);
64610504SKeyur.Desai@Sun.COM 	}
6479914Samw@Sun.COM 
6489914Samw@Sun.COM 	/*
6499914Samw@Sun.COM 	 * Break the oplock before access checks. If a client
6509914Samw@Sun.COM 	 * has a file open, this will force a flush or close,
6519914Samw@Sun.COM 	 * which may affect the outcome of any share checking.
6529914Samw@Sun.COM 	 */
65310966SJordan.Brown@Sun.COM 	(void) smb_oplock_break(src_node, sr->session, B_FALSE);
6549914Samw@Sun.COM 
6559914Samw@Sun.COM 	for (count = 0; count <= 3; count++) {
6569914Samw@Sun.COM 		if (count) {
65710966SJordan.Brown@Sun.COM 			smb_node_end_crit(src_node);
6589914Samw@Sun.COM 			delay(MSEC_TO_TICK(400));
6599914Samw@Sun.COM 		}
6609914Samw@Sun.COM 
66110966SJordan.Brown@Sun.COM 		smb_node_start_crit(src_node, RW_READER);
6629914Samw@Sun.COM 
66310966SJordan.Brown@Sun.COM 		status = smb_node_rename_check(src_node);
6649914Samw@Sun.COM 		if (status != NT_STATUS_SHARING_VIOLATION)
6659914Samw@Sun.COM 			break;
6669914Samw@Sun.COM 	}
6679914Samw@Sun.COM 
6689914Samw@Sun.COM 	if (status == NT_STATUS_SHARING_VIOLATION) {
66910966SJordan.Brown@Sun.COM 		smb_node_end_crit(src_node);
67010504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_fnode);
67110504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
67210504SKeyur.Desai@Sun.COM 		return (EPIPE); /* = ERRbadshare */
6739914Samw@Sun.COM 	}
6749914Samw@Sun.COM 
67510966SJordan.Brown@Sun.COM 	status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE);
6769914Samw@Sun.COM 	if (status != NT_STATUS_SUCCESS) {
67710966SJordan.Brown@Sun.COM 		smb_node_end_crit(src_node);
67810504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_fnode);
67910504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
68010504SKeyur.Desai@Sun.COM 		return (EACCES);
6819914Samw@Sun.COM 	}
6829914Samw@Sun.COM 
68310966SJordan.Brown@Sun.COM 	return (0);
68410966SJordan.Brown@Sun.COM }
6859914Samw@Sun.COM 
68610966SJordan.Brown@Sun.COM /*
68710966SJordan.Brown@Sun.COM  * smb_rename_release_src
68810966SJordan.Brown@Sun.COM  */
68910966SJordan.Brown@Sun.COM static void
69010966SJordan.Brown@Sun.COM smb_rename_release_src(smb_request_t *sr)
69110966SJordan.Brown@Sun.COM {
69210966SJordan.Brown@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
69310504SKeyur.Desai@Sun.COM 
69410966SJordan.Brown@Sun.COM 	smb_node_end_crit(src_fqi->fq_fnode);
69510504SKeyur.Desai@Sun.COM 	smb_node_release(src_fqi->fq_fnode);
6969914Samw@Sun.COM 	smb_node_release(src_fqi->fq_dnode);
6979914Samw@Sun.COM }
6989914Samw@Sun.COM 
69910966SJordan.Brown@Sun.COM 
7009914Samw@Sun.COM static int
70110001SJoyce.McIntosh@Sun.COM smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr)
7029914Samw@Sun.COM {
70310001SJoyce.McIntosh@Sun.COM 	smb_attr_t attr;
7049914Samw@Sun.COM 
70510001SJoyce.McIntosh@Sun.COM 	if (smb_node_getattr(sr, node, &attr) != 0)
70610001SJoyce.McIntosh@Sun.COM 		return (EIO);
70710001SJoyce.McIntosh@Sun.COM 
70810001SJoyce.McIntosh@Sun.COM 	if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) &&
70910001SJoyce.McIntosh@Sun.COM 	    !(SMB_SEARCH_HIDDEN(sattr)))
7109914Samw@Sun.COM 		return (ESRCH);
7119914Samw@Sun.COM 
71210001SJoyce.McIntosh@Sun.COM 	if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) &&
71310001SJoyce.McIntosh@Sun.COM 	    !(SMB_SEARCH_SYSTEM(sattr)))
7149914Samw@Sun.COM 		return (ESRCH);
7159914Samw@Sun.COM 
7169914Samw@Sun.COM 	return (0);
7179914Samw@Sun.COM }
7189914Samw@Sun.COM 
7199914Samw@Sun.COM /*
7209914Samw@Sun.COM  * The following values are based on observed WFWG, Windows 9x, Windows NT
7219914Samw@Sun.COM  * and Windows 2000 behaviour.
7229914Samw@Sun.COM  *
7239914Samw@Sun.COM  * ERROR_FILE_EXISTS doesn't work for Windows 98 clients.
7249914Samw@Sun.COM  *
7259914Samw@Sun.COM  * Windows 95 clients don't see the problem because the target is deleted
7269914Samw@Sun.COM  * before the rename request.
7279914Samw@Sun.COM  */
7289914Samw@Sun.COM static void
7299914Samw@Sun.COM smb_rename_set_error(smb_request_t *sr, int errnum)
7309914Samw@Sun.COM {
7319914Samw@Sun.COM 	static struct {
7329914Samw@Sun.COM 		int errnum;
7339914Samw@Sun.COM 		uint16_t errcode;
7349914Samw@Sun.COM 		uint32_t status32;
7359914Samw@Sun.COM 	} rc_map[] = {
7369914Samw@Sun.COM 	{ EEXIST, ERROR_ALREADY_EXISTS,	NT_STATUS_OBJECT_NAME_COLLISION },
7379914Samw@Sun.COM 	{ EPIPE,  ERROR_SHARING_VIOLATION, NT_STATUS_SHARING_VIOLATION },
7389914Samw@Sun.COM 	{ ENOENT, ERROR_FILE_NOT_FOUND,	NT_STATUS_OBJECT_NAME_NOT_FOUND },
7399914Samw@Sun.COM 	{ ESRCH,  ERROR_FILE_NOT_FOUND,	NT_STATUS_NO_SUCH_FILE },
7409914Samw@Sun.COM 	{ EINVAL, ERROR_INVALID_PARAMETER, NT_STATUS_INVALID_PARAMETER },
74110001SJoyce.McIntosh@Sun.COM 	{ EACCES, ERROR_ACCESS_DENIED,	NT_STATUS_ACCESS_DENIED },
74210966SJordan.Brown@Sun.COM 	{ EISDIR, ERROR_ACCESS_DENIED,	NT_STATUS_FILE_IS_A_DIRECTORY },
74310001SJoyce.McIntosh@Sun.COM 	{ EIO,    ERROR_INTERNAL_ERROR,	NT_STATUS_INTERNAL_ERROR }
7449914Samw@Sun.COM 	};
7459914Samw@Sun.COM 
7469914Samw@Sun.COM 	int i;
7479914Samw@Sun.COM 
7489914Samw@Sun.COM 	if (errnum == 0)
7499914Samw@Sun.COM 		return;
7509914Samw@Sun.COM 
7519914Samw@Sun.COM 	for (i = 0; i < sizeof (rc_map)/sizeof (rc_map[0]); ++i) {
7529914Samw@Sun.COM 		if (rc_map[i].errnum == errnum) {
7539914Samw@Sun.COM 			smbsr_error(sr, rc_map[i].status32,
7549914Samw@Sun.COM 			    ERRDOS, rc_map[i].errcode);
7559914Samw@Sun.COM 			return;
7569914Samw@Sun.COM 		}
7579914Samw@Sun.COM 	}
7589914Samw@Sun.COM 
7599914Samw@Sun.COM 	smbsr_errno(sr, errnum);
7609914Samw@Sun.COM }
761