xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_rename.c (revision 12890:16985853e3aa)
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 /*
22*12890SJoyce.McIntosh@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235331Samw  */
245331Samw 
255331Samw #include <sys/synch.h>
2610966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
275331Samw #include <smbsrv/smb_fsops.h>
285772Sas200622 #include <sys/nbmlock.h>
295331Samw 
309914Samw@Sun.COM /*
319914Samw@Sun.COM  * NT_RENAME InformationLevels:
329914Samw@Sun.COM  *
339914Samw@Sun.COM  * SMB_NT_RENAME_MOVE_CLUSTER_INFO	Server returns invalid parameter.
349914Samw@Sun.COM  * SMB_NT_RENAME_SET_LINK_INFO		Create a hard link to a file.
359914Samw@Sun.COM  * SMB_NT_RENAME_RENAME_FILE		In-place rename of a file.
369914Samw@Sun.COM  * SMB_NT_RENAME_MOVE_FILE		Move (rename) a file.
379914Samw@Sun.COM  */
389914Samw@Sun.COM #define	SMB_NT_RENAME_MOVE_CLUSTER_INFO	0x0102
399914Samw@Sun.COM #define	SMB_NT_RENAME_SET_LINK_INFO	0x0103
409914Samw@Sun.COM #define	SMB_NT_RENAME_RENAME_FILE	0x0104
419914Samw@Sun.COM #define	SMB_NT_RENAME_MOVE_FILE		0x0105
429914Samw@Sun.COM 
4310966SJordan.Brown@Sun.COM /*
4410966SJordan.Brown@Sun.COM  * SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag
4510966SJordan.Brown@Sun.COM  */
4610966SJordan.Brown@Sun.COM #define	SMB_RENAME_FLAG_OVERWRITE	0x001
4710966SJordan.Brown@Sun.COM 
4810966SJordan.Brown@Sun.COM static int smb_common_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *);
499914Samw@Sun.COM static int smb_make_link(smb_request_t *, smb_fqi_t *, smb_fqi_t *);
5010966SJordan.Brown@Sun.COM static int smb_rename_check_stream(smb_fqi_t *, smb_fqi_t *);
5110001SJoyce.McIntosh@Sun.COM static int smb_rename_check_attr(smb_request_t *, smb_node_t *, uint16_t);
529914Samw@Sun.COM static void smb_rename_set_error(smb_request_t *, int);
535331Samw 
5410966SJordan.Brown@Sun.COM static int smb_rename_lookup_src(smb_request_t *);
5510966SJordan.Brown@Sun.COM static void smb_rename_release_src(smb_request_t *);
5610966SJordan.Brown@Sun.COM 
575331Samw /*
585331Samw  * smb_com_rename
595331Samw  *
605331Samw  * Rename a file. Files OldFileName must exist and NewFileName must not.
615331Samw  * Both pathnames must be relative to the Tid specified in the request.
625331Samw  * Open files may be renamed.
635331Samw  *
645331Samw  * Multiple files may be renamed in response to a single request as Rename
655331Samw  * File supports wildcards in the file name (last component of the path).
665331Samw  * NOTE: we don't support rename with wildcards.
675331Samw  *
685331Samw  * SearchAttributes indicates the attributes that the target file(s) must
695331Samw  * have. If SearchAttributes is zero then only normal files are renamed.
705331Samw  * If the system file or hidden attributes are specified then the rename
715331Samw  * is inclusive - both the specified type(s) of files and normal files are
7210966SJordan.Brown@Sun.COM  * renamed.
735331Samw  */
746030Sjb150015 smb_sdrc_t
smb_pre_rename(smb_request_t * sr)756139Sjb150015 smb_pre_rename(smb_request_t *sr)
766139Sjb150015 {
777961SNatalie.Li@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
787961SNatalie.Li@Sun.COM 	smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
796139Sjb150015 	int rc;
806139Sjb150015 
819343SAfshin.Ardakani@Sun.COM 	if ((rc = smbsr_decode_vwv(sr, "w", &src_fqi->fq_sattr)) == 0) {
829343SAfshin.Ardakani@Sun.COM 		rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->fq_path.pn_path,
839343SAfshin.Ardakani@Sun.COM 		    &dst_fqi->fq_path.pn_path);
846139Sjb150015 
859343SAfshin.Ardakani@Sun.COM 		dst_fqi->fq_sattr = 0;
866139Sjb150015 	}
876139Sjb150015 
886139Sjb150015 	DTRACE_SMB_2(op__Rename__start, smb_request_t *, sr,
896139Sjb150015 	    struct dirop *, &sr->arg.dirop);
906139Sjb150015 
916139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
926139Sjb150015 }
936139Sjb150015 
946139Sjb150015 void
smb_post_rename(smb_request_t * sr)956139Sjb150015 smb_post_rename(smb_request_t *sr)
966139Sjb150015 {
976139Sjb150015 	DTRACE_SMB_1(op__Rename__done, smb_request_t *, sr);
986139Sjb150015 }
996139Sjb150015 
1006139Sjb150015 smb_sdrc_t
smb_com_rename(smb_request_t * sr)1016139Sjb150015 smb_com_rename(smb_request_t *sr)
1025331Samw {
10311963SAfshin.Ardakani@Sun.COM 	int		rc;
10411963SAfshin.Ardakani@Sun.COM 	smb_fqi_t	*src_fqi = &sr->arg.dirop.fqi;
10511963SAfshin.Ardakani@Sun.COM 	smb_fqi_t	*dst_fqi = &sr->arg.dirop.dst_fqi;
10611963SAfshin.Ardakani@Sun.COM 	smb_pathname_t	*src_pn = &src_fqi->fq_path;
10711963SAfshin.Ardakani@Sun.COM 	smb_pathname_t	*dst_pn = &dst_fqi->fq_path;
1085331Samw 
1095331Samw 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
1105772Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
1115331Samw 		    ERRDOS, ERROR_ACCESS_DENIED);
1126139Sjb150015 		return (SDRC_ERROR);
1135331Samw 	}
1145331Samw 
11511963SAfshin.Ardakani@Sun.COM 	smb_pathname_init(sr, src_pn, src_pn->pn_path);
11611963SAfshin.Ardakani@Sun.COM 	smb_pathname_init(sr, dst_pn, dst_pn->pn_path);
11711963SAfshin.Ardakani@Sun.COM 	if (!smb_pathname_validate(sr, src_pn) ||
11811963SAfshin.Ardakani@Sun.COM 	    !smb_pathname_validate(sr, dst_pn)) {
11911963SAfshin.Ardakani@Sun.COM 		return (SDRC_ERROR);
12011963SAfshin.Ardakani@Sun.COM 	}
12111963SAfshin.Ardakani@Sun.COM 
12210966SJordan.Brown@Sun.COM 	rc = smb_common_rename(sr, src_fqi, dst_fqi);
1235331Samw 
1245331Samw 	if (rc != 0) {
1259914Samw@Sun.COM 		smb_rename_set_error(sr, rc);
1266139Sjb150015 		return (SDRC_ERROR);
1275331Samw 	}
1285331Samw 
1296030Sjb150015 	rc = smbsr_encode_empty_result(sr);
1306139Sjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1315331Samw }
1325331Samw 
1335331Samw /*
1349914Samw@Sun.COM  * smb_com_nt_rename
1359914Samw@Sun.COM  *
1369914Samw@Sun.COM  * Rename a file. Files OldFileName must exist and NewFileName must not.
1379914Samw@Sun.COM  * Both pathnames must be relative to the Tid specified in the request.
1389914Samw@Sun.COM  * Open files may be renamed.
1399914Samw@Sun.COM  *
1409914Samw@Sun.COM  * SearchAttributes indicates the attributes that the target file(s) must
1419914Samw@Sun.COM  * have. If SearchAttributes is zero then only normal files are renamed.
1429914Samw@Sun.COM  * If the system file or hidden attributes are specified then the rename
1439914Samw@Sun.COM  * is inclusive - both the specified type(s) of files and normal files are
14410966SJordan.Brown@Sun.COM  * renamed.
1459914Samw@Sun.COM  */
1469914Samw@Sun.COM smb_sdrc_t
smb_pre_nt_rename(smb_request_t * sr)1479914Samw@Sun.COM smb_pre_nt_rename(smb_request_t *sr)
1489914Samw@Sun.COM {
1499914Samw@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
1509914Samw@Sun.COM 	smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
1519914Samw@Sun.COM 	uint32_t clusters;
1529914Samw@Sun.COM 	int rc;
1539914Samw@Sun.COM 
1549914Samw@Sun.COM 	rc = smbsr_decode_vwv(sr, "wwl", &src_fqi->fq_sattr,
1559914Samw@Sun.COM 	    &sr->arg.dirop.info_level, &clusters);
1569914Samw@Sun.COM 	if (rc == 0) {
1579914Samw@Sun.COM 		rc = smbsr_decode_data(sr, "%SS", sr,
1589914Samw@Sun.COM 		    &src_fqi->fq_path.pn_path, &dst_fqi->fq_path.pn_path);
1599914Samw@Sun.COM 
1609914Samw@Sun.COM 		dst_fqi->fq_sattr = 0;
1619914Samw@Sun.COM 	}
1629914Samw@Sun.COM 
1639914Samw@Sun.COM 	DTRACE_SMB_2(op__NtRename__start, smb_request_t *, sr,
1649914Samw@Sun.COM 	    struct dirop *, &sr->arg.dirop);
1659914Samw@Sun.COM 
1669914Samw@Sun.COM 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1679914Samw@Sun.COM }
1689914Samw@Sun.COM 
1699914Samw@Sun.COM void
smb_post_nt_rename(smb_request_t * sr)1709914Samw@Sun.COM smb_post_nt_rename(smb_request_t *sr)
1719914Samw@Sun.COM {
1729914Samw@Sun.COM 	DTRACE_SMB_1(op__NtRename__done, smb_request_t *, sr);
1739914Samw@Sun.COM }
1749914Samw@Sun.COM 
1759914Samw@Sun.COM smb_sdrc_t
smb_com_nt_rename(smb_request_t * sr)1769914Samw@Sun.COM smb_com_nt_rename(smb_request_t *sr)
1779914Samw@Sun.COM {
17811963SAfshin.Ardakani@Sun.COM 	int		rc;
17911963SAfshin.Ardakani@Sun.COM 	smb_fqi_t	*src_fqi = &sr->arg.dirop.fqi;
18011963SAfshin.Ardakani@Sun.COM 	smb_fqi_t	*dst_fqi = &sr->arg.dirop.dst_fqi;
18111963SAfshin.Ardakani@Sun.COM 	smb_pathname_t	*src_pn = &src_fqi->fq_path;
18211963SAfshin.Ardakani@Sun.COM 	smb_pathname_t	*dst_pn = &dst_fqi->fq_path;
1839914Samw@Sun.COM 
1849914Samw@Sun.COM 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
1859914Samw@Sun.COM 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
1869914Samw@Sun.COM 		    ERRDOS, ERROR_ACCESS_DENIED);
1879914Samw@Sun.COM 		return (SDRC_ERROR);
1889914Samw@Sun.COM 	}
1899914Samw@Sun.COM 
19011963SAfshin.Ardakani@Sun.COM 	smb_pathname_init(sr, src_pn, src_pn->pn_path);
19111963SAfshin.Ardakani@Sun.COM 	smb_pathname_init(sr, dst_pn, dst_pn->pn_path);
19211963SAfshin.Ardakani@Sun.COM 	if (!smb_pathname_validate(sr, src_pn) ||
19311963SAfshin.Ardakani@Sun.COM 	    !smb_pathname_validate(sr, dst_pn)) {
19411963SAfshin.Ardakani@Sun.COM 		return (SDRC_ERROR);
19511963SAfshin.Ardakani@Sun.COM 	}
19611963SAfshin.Ardakani@Sun.COM 
19711963SAfshin.Ardakani@Sun.COM 	if (smb_contains_wildcards(src_pn->pn_path)) {
1989914Samw@Sun.COM 		smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
1999914Samw@Sun.COM 		    ERRDOS, ERROR_BAD_PATHNAME);
2009914Samw@Sun.COM 		return (SDRC_ERROR);
2019914Samw@Sun.COM 	}
2029914Samw@Sun.COM 
2039914Samw@Sun.COM 	switch (sr->arg.dirop.info_level) {
2049914Samw@Sun.COM 	case SMB_NT_RENAME_SET_LINK_INFO:
2059914Samw@Sun.COM 		rc = smb_make_link(sr, src_fqi, dst_fqi);
2069914Samw@Sun.COM 		break;
2079914Samw@Sun.COM 	case SMB_NT_RENAME_RENAME_FILE:
2089914Samw@Sun.COM 	case SMB_NT_RENAME_MOVE_FILE:
20910966SJordan.Brown@Sun.COM 		rc = smb_common_rename(sr, src_fqi, dst_fqi);
2109914Samw@Sun.COM 		break;
2119914Samw@Sun.COM 	case SMB_NT_RENAME_MOVE_CLUSTER_INFO:
2129914Samw@Sun.COM 		rc = EINVAL;
2139914Samw@Sun.COM 		break;
2149914Samw@Sun.COM 	default:
2159914Samw@Sun.COM 		rc = EACCES;
2169914Samw@Sun.COM 		break;
2179914Samw@Sun.COM 	}
2189914Samw@Sun.COM 
2199914Samw@Sun.COM 	if (rc != 0) {
2209914Samw@Sun.COM 		smb_rename_set_error(sr, rc);
2219914Samw@Sun.COM 		return (SDRC_ERROR);
2229914Samw@Sun.COM 	}
2239914Samw@Sun.COM 
2249914Samw@Sun.COM 	rc = smbsr_encode_empty_result(sr);
2259914Samw@Sun.COM 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
2269914Samw@Sun.COM }
2279914Samw@Sun.COM 
2289914Samw@Sun.COM /*
22910966SJordan.Brown@Sun.COM  * smb_nt_transact_rename
23010966SJordan.Brown@Sun.COM  *
23110966SJordan.Brown@Sun.COM  * Windows servers return SUCCESS without renaming file.
23210966SJordan.Brown@Sun.COM  * The only check required is to check that the handle (fid) is valid.
23310966SJordan.Brown@Sun.COM  */
23410966SJordan.Brown@Sun.COM smb_sdrc_t
smb_nt_transact_rename(smb_request_t * sr,smb_xa_t * xa)23510966SJordan.Brown@Sun.COM smb_nt_transact_rename(smb_request_t *sr, smb_xa_t *xa)
23610966SJordan.Brown@Sun.COM {
23710966SJordan.Brown@Sun.COM 	if (smb_mbc_decodef(&xa->req_param_mb, "w", &sr->smb_fid) != 0)
23810966SJordan.Brown@Sun.COM 		return (SDRC_ERROR);
23910966SJordan.Brown@Sun.COM 
24010966SJordan.Brown@Sun.COM 	smbsr_lookup_file(sr);
24110966SJordan.Brown@Sun.COM 	if (sr->fid_ofile == NULL) {
24210966SJordan.Brown@Sun.COM 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
24310966SJordan.Brown@Sun.COM 		return (SDRC_ERROR);
24410966SJordan.Brown@Sun.COM 	}
24510966SJordan.Brown@Sun.COM 	smbsr_release_file(sr);
24610966SJordan.Brown@Sun.COM 
24710966SJordan.Brown@Sun.COM 	return (SDRC_SUCCESS);
24810966SJordan.Brown@Sun.COM }
24910966SJordan.Brown@Sun.COM 
25010966SJordan.Brown@Sun.COM /*
25110966SJordan.Brown@Sun.COM  * smb_trans2_rename
25210966SJordan.Brown@Sun.COM  *
25310966SJordan.Brown@Sun.COM  * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo
25410966SJordan.Brown@Sun.COM  * and Trans2_Set_PathInfo.
25510966SJordan.Brown@Sun.COM  * If the new filename (dst_fqi) already exists it may be overwritten
25610966SJordan.Brown@Sun.COM  * if flags == 1.
25710966SJordan.Brown@Sun.COM  */
25810966SJordan.Brown@Sun.COM int
smb_trans2_rename(smb_request_t * sr,smb_node_t * node,char * fname,int flags)25910966SJordan.Brown@Sun.COM smb_trans2_rename(smb_request_t *sr, smb_node_t *node, char *fname, int flags)
26010966SJordan.Brown@Sun.COM {
26111963SAfshin.Ardakani@Sun.COM 	int		rc = 0;
26211963SAfshin.Ardakani@Sun.COM 	smb_fqi_t	*src_fqi = &sr->arg.dirop.fqi;
26311963SAfshin.Ardakani@Sun.COM 	smb_fqi_t	*dst_fqi = &sr->arg.dirop.dst_fqi;
26411963SAfshin.Ardakani@Sun.COM 	smb_pathname_t	*dst_pn = &dst_fqi->fq_path;
26511963SAfshin.Ardakani@Sun.COM 	char		*path;
26611963SAfshin.Ardakani@Sun.COM 	int		len;
26710966SJordan.Brown@Sun.COM 
26810966SJordan.Brown@Sun.COM 	sr->arg.dirop.flags = flags ? SMB_RENAME_FLAG_OVERWRITE : 0;
26910966SJordan.Brown@Sun.COM 	sr->arg.dirop.info_level = SMB_NT_RENAME_RENAME_FILE;
27010966SJordan.Brown@Sun.COM 
27110966SJordan.Brown@Sun.COM 	src_fqi->fq_sattr = SMB_SEARCH_ATTRIBUTES;
27210966SJordan.Brown@Sun.COM 	src_fqi->fq_fnode = node;
27310966SJordan.Brown@Sun.COM 	src_fqi->fq_dnode = node->n_dnode;
27410966SJordan.Brown@Sun.COM 
27511963SAfshin.Ardakani@Sun.COM 	/* costruct and validate the dst pathname */
27611963SAfshin.Ardakani@Sun.COM 	path = smb_srm_zalloc(sr, MAXPATHLEN);
27711963SAfshin.Ardakani@Sun.COM 	if (src_fqi->fq_path.pn_pname) {
27811963SAfshin.Ardakani@Sun.COM 		(void) snprintf(path, MAXPATHLEN, "%s\\%s",
27911963SAfshin.Ardakani@Sun.COM 		    src_fqi->fq_path.pn_pname, fname);
28011963SAfshin.Ardakani@Sun.COM 	} else {
28111963SAfshin.Ardakani@Sun.COM 		rc = smb_node_getshrpath(node->n_dnode, sr->tid_tree,
28211963SAfshin.Ardakani@Sun.COM 		    path, MAXPATHLEN);
28311963SAfshin.Ardakani@Sun.COM 		if (rc != 0) {
28411963SAfshin.Ardakani@Sun.COM 			smb_rename_set_error(sr, rc);
28511963SAfshin.Ardakani@Sun.COM 			return (-1);
28611963SAfshin.Ardakani@Sun.COM 		}
28711963SAfshin.Ardakani@Sun.COM 		len = strlen(path);
28811963SAfshin.Ardakani@Sun.COM 		(void) snprintf(path + len, MAXPATHLEN - len, "\\%s", fname);
28911963SAfshin.Ardakani@Sun.COM 	}
29011963SAfshin.Ardakani@Sun.COM 
29111963SAfshin.Ardakani@Sun.COM 	smb_pathname_init(sr, dst_pn, path);
29211963SAfshin.Ardakani@Sun.COM 	if (!smb_pathname_validate(sr, dst_pn))
29311963SAfshin.Ardakani@Sun.COM 		return (-1);
29411963SAfshin.Ardakani@Sun.COM 
29510966SJordan.Brown@Sun.COM 	dst_fqi->fq_dnode = node->n_dnode;
29611963SAfshin.Ardakani@Sun.COM 	(void) strlcpy(dst_fqi->fq_last_comp, dst_pn->pn_fname, MAXNAMELEN);
29710966SJordan.Brown@Sun.COM 
29810966SJordan.Brown@Sun.COM 	rc = smb_common_rename(sr, src_fqi, dst_fqi);
29910966SJordan.Brown@Sun.COM 	if (rc != 0) {
30010966SJordan.Brown@Sun.COM 		smb_rename_set_error(sr, rc);
30110966SJordan.Brown@Sun.COM 		return (-1);
30210966SJordan.Brown@Sun.COM 	}
30310966SJordan.Brown@Sun.COM 
30410966SJordan.Brown@Sun.COM 	return (0);
30510966SJordan.Brown@Sun.COM }
30610966SJordan.Brown@Sun.COM 
30710966SJordan.Brown@Sun.COM /*
30810966SJordan.Brown@Sun.COM  * smb_common_rename
30910966SJordan.Brown@Sun.COM  *
31010966SJordan.Brown@Sun.COM  * Common code for renaming a file.
31110966SJordan.Brown@Sun.COM  *
31210966SJordan.Brown@Sun.COM  * If the source and destination are identical, we go through all
31310966SJordan.Brown@Sun.COM  * the checks but we don't actually do the rename.  If the source
31410966SJordan.Brown@Sun.COM  * and destination files differ only in case, we do a case-sensitive
31510966SJordan.Brown@Sun.COM  * rename.  Otherwise, we do a full case-insensitive rename.
31610966SJordan.Brown@Sun.COM  *
31710966SJordan.Brown@Sun.COM  * Returns errno values.
31810966SJordan.Brown@Sun.COM  */
31910966SJordan.Brown@Sun.COM static int
smb_common_rename(smb_request_t * sr,smb_fqi_t * src_fqi,smb_fqi_t * dst_fqi)32010966SJordan.Brown@Sun.COM smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
32110966SJordan.Brown@Sun.COM {
32210966SJordan.Brown@Sun.COM 	smb_node_t *src_fnode, *src_dnode, *dst_fnode, *dst_dnode;
32310966SJordan.Brown@Sun.COM 	smb_node_t *tnode;
32410966SJordan.Brown@Sun.COM 	int rc, count;
32510966SJordan.Brown@Sun.COM 	DWORD status;
32610966SJordan.Brown@Sun.COM 	char *new_name, *path;
32710966SJordan.Brown@Sun.COM 
32810966SJordan.Brown@Sun.COM 	path = dst_fqi->fq_path.pn_path;
32910966SJordan.Brown@Sun.COM 
33010966SJordan.Brown@Sun.COM 	/* Check if attempting to rename a stream - not yet supported */
33110966SJordan.Brown@Sun.COM 	rc = smb_rename_check_stream(src_fqi, dst_fqi);
33210966SJordan.Brown@Sun.COM 	if (rc != 0)
33310966SJordan.Brown@Sun.COM 		return (rc);
33410966SJordan.Brown@Sun.COM 
33510966SJordan.Brown@Sun.COM 	/* The source node may already have been provided */
33610966SJordan.Brown@Sun.COM 	if (src_fqi->fq_fnode) {
33710966SJordan.Brown@Sun.COM 		smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
33810966SJordan.Brown@Sun.COM 		smb_node_ref(src_fqi->fq_fnode);
33910966SJordan.Brown@Sun.COM 		smb_node_ref(src_fqi->fq_dnode);
34010966SJordan.Brown@Sun.COM 	} else {
34110966SJordan.Brown@Sun.COM 		/* lookup and validate src node */
34210966SJordan.Brown@Sun.COM 		rc = smb_rename_lookup_src(sr);
34310966SJordan.Brown@Sun.COM 		if (rc != 0)
34410966SJordan.Brown@Sun.COM 			return (rc);
34510966SJordan.Brown@Sun.COM 	}
34610966SJordan.Brown@Sun.COM 
34710966SJordan.Brown@Sun.COM 	src_fnode = src_fqi->fq_fnode;
34810966SJordan.Brown@Sun.COM 	src_dnode = src_fqi->fq_dnode;
34910966SJordan.Brown@Sun.COM 
35010966SJordan.Brown@Sun.COM 	/* Find destination dnode and last_comp */
35110966SJordan.Brown@Sun.COM 	if (dst_fqi->fq_dnode) {
35210966SJordan.Brown@Sun.COM 		smb_node_ref(dst_fqi->fq_dnode);
35310966SJordan.Brown@Sun.COM 	} else {
35410966SJordan.Brown@Sun.COM 		tnode = sr->tid_tree->t_snode;
35510966SJordan.Brown@Sun.COM 		rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
35610966SJordan.Brown@Sun.COM 		    &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
35710966SJordan.Brown@Sun.COM 		if (rc != 0) {
35810966SJordan.Brown@Sun.COM 			smb_rename_release_src(sr);
35910966SJordan.Brown@Sun.COM 			return (rc);
36010966SJordan.Brown@Sun.COM 		}
36110966SJordan.Brown@Sun.COM 	}
36210966SJordan.Brown@Sun.COM 
36310966SJordan.Brown@Sun.COM 	dst_dnode = dst_fqi->fq_dnode;
36410966SJordan.Brown@Sun.COM 	new_name = dst_fqi->fq_last_comp;
36510966SJordan.Brown@Sun.COM 
36610966SJordan.Brown@Sun.COM 	/* If exact name match in same directory, we're done */
36710966SJordan.Brown@Sun.COM 	if ((src_dnode == dst_dnode) &&
36810966SJordan.Brown@Sun.COM 	    (strcmp(src_fnode->od_name, new_name) == 0)) {
36910966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
37010966SJordan.Brown@Sun.COM 		smb_node_release(dst_dnode);
37110966SJordan.Brown@Sun.COM 		return (0);
37210966SJordan.Brown@Sun.COM 	}
37310966SJordan.Brown@Sun.COM 
37410966SJordan.Brown@Sun.COM 	/* Lookup destination node */
37510966SJordan.Brown@Sun.COM 	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
37610966SJordan.Brown@Sun.COM 	    dst_dnode, new_name, &dst_fqi->fq_fnode);
37710966SJordan.Brown@Sun.COM 
37811337SWilliam.Krier@Sun.COM 	/* If the destination node doesn't already exist, validate new_name. */
37911337SWilliam.Krier@Sun.COM 	if (rc == ENOENT) {
38011337SWilliam.Krier@Sun.COM 		if (smb_is_invalid_filename(new_name)) {
38111337SWilliam.Krier@Sun.COM 			smb_rename_release_src(sr);
38211337SWilliam.Krier@Sun.COM 			smb_node_release(dst_dnode);
38311337SWilliam.Krier@Sun.COM 			return (EILSEQ); /* NT_STATUS_OBJECT_NAME_INVALID */
38411337SWilliam.Krier@Sun.COM 		}
38511337SWilliam.Krier@Sun.COM 	}
38611337SWilliam.Krier@Sun.COM 
38710966SJordan.Brown@Sun.COM 	/*
38810966SJordan.Brown@Sun.COM 	 * Handle case where changing case of the same directory entry.
38910966SJordan.Brown@Sun.COM 	 *
39010966SJordan.Brown@Sun.COM 	 * If we found the dst node in the same directory as the src node,
39110966SJordan.Brown@Sun.COM 	 * and their names differ only in case:
39210966SJordan.Brown@Sun.COM 	 *
39310966SJordan.Brown@Sun.COM 	 * If the tree is case sensitive (or mixed):
39410966SJordan.Brown@Sun.COM 	 *  Do case sensitive lookup to see if exact match exists.
39510966SJordan.Brown@Sun.COM 	 *  If the exact match is the same node as src_node we're done.
39610966SJordan.Brown@Sun.COM 	 *
39710966SJordan.Brown@Sun.COM 	 * If the tree is case insensitive:
39810966SJordan.Brown@Sun.COM 	 *  There is currently no way to tell if the case is different
39910966SJordan.Brown@Sun.COM 	 *  or not, so do the rename (unless the specified new name was
40010966SJordan.Brown@Sun.COM 	 *  mangled).
40110966SJordan.Brown@Sun.COM 	 */
40210966SJordan.Brown@Sun.COM 	if ((rc == 0) &&
40310966SJordan.Brown@Sun.COM 	    (src_dnode == dst_dnode) &&
40410966SJordan.Brown@Sun.COM 	    (smb_strcasecmp(src_fnode->od_name,
40510966SJordan.Brown@Sun.COM 	    dst_fqi->fq_fnode->od_name, 0) == 0)) {
40610966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_fnode);
40710966SJordan.Brown@Sun.COM 		dst_fqi->fq_fnode = NULL;
40810966SJordan.Brown@Sun.COM 
40910966SJordan.Brown@Sun.COM 		if (smb_tree_has_feature(sr->tid_tree,
41010966SJordan.Brown@Sun.COM 		    SMB_TREE_NO_CASESENSITIVE)) {
41110966SJordan.Brown@Sun.COM 			if (smb_strcasecmp(src_fnode->od_name,
41210966SJordan.Brown@Sun.COM 			    dst_fqi->fq_last_comp, 0) != 0) {
41310966SJordan.Brown@Sun.COM 				smb_rename_release_src(sr);
41410966SJordan.Brown@Sun.COM 				smb_node_release(dst_dnode);
41510966SJordan.Brown@Sun.COM 				return (0);
41610966SJordan.Brown@Sun.COM 			}
41710966SJordan.Brown@Sun.COM 		} else {
41810966SJordan.Brown@Sun.COM 			rc = smb_fsop_lookup(sr, sr->user_cr,
41910966SJordan.Brown@Sun.COM 			    SMB_CASE_SENSITIVE, tnode, dst_dnode, new_name,
42010966SJordan.Brown@Sun.COM 			    &dst_fqi->fq_fnode);
42110966SJordan.Brown@Sun.COM 
42210966SJordan.Brown@Sun.COM 			if ((rc == 0) &&
42310966SJordan.Brown@Sun.COM 			    (dst_fqi->fq_fnode == src_fnode)) {
42410966SJordan.Brown@Sun.COM 				smb_rename_release_src(sr);
42510966SJordan.Brown@Sun.COM 				smb_node_release(dst_fqi->fq_fnode);
42610966SJordan.Brown@Sun.COM 				smb_node_release(dst_dnode);
42710966SJordan.Brown@Sun.COM 				return (0);
42810966SJordan.Brown@Sun.COM 			}
42910966SJordan.Brown@Sun.COM 		}
43010966SJordan.Brown@Sun.COM 	}
43110966SJordan.Brown@Sun.COM 
43210966SJordan.Brown@Sun.COM 	if ((rc != 0) && (rc != ENOENT)) {
43310966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
43410966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_dnode);
43510966SJordan.Brown@Sun.COM 		return (rc);
43610966SJordan.Brown@Sun.COM 	}
43710966SJordan.Brown@Sun.COM 
43810966SJordan.Brown@Sun.COM 	if (dst_fqi->fq_fnode) {
43910966SJordan.Brown@Sun.COM 		dst_fnode = dst_fqi->fq_fnode;
44010966SJordan.Brown@Sun.COM 
44110966SJordan.Brown@Sun.COM 		if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) {
44210966SJordan.Brown@Sun.COM 			smb_rename_release_src(sr);
44310966SJordan.Brown@Sun.COM 			smb_node_release(dst_fnode);
44410966SJordan.Brown@Sun.COM 			smb_node_release(dst_dnode);
44510966SJordan.Brown@Sun.COM 			return (EEXIST);
44610966SJordan.Brown@Sun.COM 		}
44710966SJordan.Brown@Sun.COM 
448*12890SJoyce.McIntosh@Sun.COM 		(void) smb_oplock_break(sr, dst_fnode,
449*12890SJoyce.McIntosh@Sun.COM 		    SMB_OPLOCK_BREAK_TO_NONE | SMB_OPLOCK_BREAK_BATCH);
45010966SJordan.Brown@Sun.COM 
45110966SJordan.Brown@Sun.COM 		for (count = 0; count <= 3; count++) {
45210966SJordan.Brown@Sun.COM 			if (count) {
45310966SJordan.Brown@Sun.COM 				smb_node_end_crit(dst_fnode);
45410966SJordan.Brown@Sun.COM 				delay(MSEC_TO_TICK(400));
45510966SJordan.Brown@Sun.COM 			}
45610966SJordan.Brown@Sun.COM 
45710966SJordan.Brown@Sun.COM 			smb_node_start_crit(dst_fnode, RW_READER);
45810966SJordan.Brown@Sun.COM 			status = smb_node_delete_check(dst_fnode);
45910966SJordan.Brown@Sun.COM 
46010966SJordan.Brown@Sun.COM 			if (status != NT_STATUS_SHARING_VIOLATION)
46110966SJordan.Brown@Sun.COM 				break;
46210966SJordan.Brown@Sun.COM 		}
46310966SJordan.Brown@Sun.COM 
46410966SJordan.Brown@Sun.COM 		if (status != NT_STATUS_SHARING_VIOLATION)
46510966SJordan.Brown@Sun.COM 			status = smb_range_check(sr, dst_fnode,
46610966SJordan.Brown@Sun.COM 			    0, UINT64_MAX, B_TRUE);
46710966SJordan.Brown@Sun.COM 
46810966SJordan.Brown@Sun.COM 		if (status != NT_STATUS_SUCCESS) {
46910966SJordan.Brown@Sun.COM 			smb_rename_release_src(sr);
47010966SJordan.Brown@Sun.COM 			smb_node_end_crit(dst_fnode);
47110966SJordan.Brown@Sun.COM 			smb_node_release(dst_fnode);
47210966SJordan.Brown@Sun.COM 			smb_node_release(dst_dnode);
47310966SJordan.Brown@Sun.COM 			return (EACCES);
47410966SJordan.Brown@Sun.COM 		}
47510966SJordan.Brown@Sun.COM 
47611337SWilliam.Krier@Sun.COM 		new_name = dst_fnode->od_name;
47710966SJordan.Brown@Sun.COM 	}
47810966SJordan.Brown@Sun.COM 
47910966SJordan.Brown@Sun.COM 	rc = smb_fsop_rename(sr, sr->user_cr,
48010966SJordan.Brown@Sun.COM 	    src_dnode, src_fnode->od_name,
48110966SJordan.Brown@Sun.COM 	    dst_dnode, new_name);
48210966SJordan.Brown@Sun.COM 
48310966SJordan.Brown@Sun.COM 	smb_rename_release_src(sr);
48410966SJordan.Brown@Sun.COM 
48510966SJordan.Brown@Sun.COM 	if (rc == 0)
48610966SJordan.Brown@Sun.COM 		smb_node_notify_change(dst_dnode);
48710966SJordan.Brown@Sun.COM 
48810966SJordan.Brown@Sun.COM 	if (dst_fqi->fq_fnode) {
48910966SJordan.Brown@Sun.COM 		smb_node_end_crit(dst_fnode);
49010966SJordan.Brown@Sun.COM 		smb_node_release(dst_fnode);
49110966SJordan.Brown@Sun.COM 	}
49210966SJordan.Brown@Sun.COM 	smb_node_release(dst_dnode);
49310966SJordan.Brown@Sun.COM 
49410966SJordan.Brown@Sun.COM 	return (rc);
49510966SJordan.Brown@Sun.COM }
49610966SJordan.Brown@Sun.COM 
49710966SJordan.Brown@Sun.COM /*
49810966SJordan.Brown@Sun.COM  * smb_rename_check_stream
49910966SJordan.Brown@Sun.COM  *
50010966SJordan.Brown@Sun.COM  * For a stream rename the dst path must begin with ':', or "\\:".
50110966SJordan.Brown@Sun.COM  * We don't yet support stream rename, Return EACCES.
50210966SJordan.Brown@Sun.COM  *
50310966SJordan.Brown@Sun.COM  * If not a stream rename, in accordance with the above rule,
50410966SJordan.Brown@Sun.COM  * it is not valid for either the src or dst to be a stream.
50510966SJordan.Brown@Sun.COM  * Return EINVAL.
50610966SJordan.Brown@Sun.COM  */
50710966SJordan.Brown@Sun.COM static int
smb_rename_check_stream(smb_fqi_t * src_fqi,smb_fqi_t * dst_fqi)50810966SJordan.Brown@Sun.COM smb_rename_check_stream(smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
50910966SJordan.Brown@Sun.COM {
51010966SJordan.Brown@Sun.COM 	smb_node_t *src_fnode = src_fqi->fq_fnode;
51110966SJordan.Brown@Sun.COM 	char *src_path = src_fqi->fq_path.pn_path;
51210966SJordan.Brown@Sun.COM 	char *dst_path = dst_fqi->fq_path.pn_path;
51310966SJordan.Brown@Sun.COM 
51410966SJordan.Brown@Sun.COM 	/* We do not yet support named stream rename - ACCESS DENIED */
51510966SJordan.Brown@Sun.COM 	if ((dst_path[0] == ':') ||
51610966SJordan.Brown@Sun.COM 	    ((dst_path[0] == '\\') && (dst_path[1] == ':'))) {
51710966SJordan.Brown@Sun.COM 		return (EACCES);
51810966SJordan.Brown@Sun.COM 	}
51910966SJordan.Brown@Sun.COM 
52010966SJordan.Brown@Sun.COM 	/*
52110966SJordan.Brown@Sun.COM 	 * If not stream rename (above) neither src or dst can be
52210966SJordan.Brown@Sun.COM 	 * a named stream.
52310966SJordan.Brown@Sun.COM 	 */
52410966SJordan.Brown@Sun.COM 
52510966SJordan.Brown@Sun.COM 	if (smb_is_stream_name(dst_path))
52610966SJordan.Brown@Sun.COM 		return (EINVAL);
52710966SJordan.Brown@Sun.COM 
52810966SJordan.Brown@Sun.COM 	if (src_fqi->fq_fnode) {
52910966SJordan.Brown@Sun.COM 		if (SMB_IS_STREAM(src_fnode))
53010966SJordan.Brown@Sun.COM 			return (EINVAL);
53110966SJordan.Brown@Sun.COM 	} else {
53210966SJordan.Brown@Sun.COM 		if (smb_is_stream_name(src_path))
53310966SJordan.Brown@Sun.COM 			return (EINVAL);
53410966SJordan.Brown@Sun.COM 	}
53510966SJordan.Brown@Sun.COM 
53610966SJordan.Brown@Sun.COM 	return (0);
53710966SJordan.Brown@Sun.COM }
53810966SJordan.Brown@Sun.COM 
53910966SJordan.Brown@Sun.COM 
54010966SJordan.Brown@Sun.COM /*
5419914Samw@Sun.COM  * smb_make_link
5429914Samw@Sun.COM  *
54310966SJordan.Brown@Sun.COM  * Creating a hard link (adding an additional name) for a file.
5449914Samw@Sun.COM  *
5459914Samw@Sun.COM  * If the source and destination are identical, we go through all
5469914Samw@Sun.COM  * the checks but we don't create a link.
5479914Samw@Sun.COM  *
54810966SJordan.Brown@Sun.COM  * If the file is a symlink we create the hardlink on the target
54910966SJordan.Brown@Sun.COM  * of the symlink (i.e. use SMB_FOLLOW_LINKS when looking up src).
55010966SJordan.Brown@Sun.COM  * If the target of the symlink does not exist we fail with ENOENT.
55110966SJordan.Brown@Sun.COM  *
5529914Samw@Sun.COM  * Returns errno values.
5539914Samw@Sun.COM  */
5549914Samw@Sun.COM static int
smb_make_link(smb_request_t * sr,smb_fqi_t * src_fqi,smb_fqi_t * dst_fqi)5559914Samw@Sun.COM smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
5569914Samw@Sun.COM {
55710966SJordan.Brown@Sun.COM 	smb_node_t *tnode;
55810966SJordan.Brown@Sun.COM 	char *path;
55910966SJordan.Brown@Sun.COM 	int rc;
56010966SJordan.Brown@Sun.COM 
56110966SJordan.Brown@Sun.COM 	/* Cannnot create link on named stream */
56210966SJordan.Brown@Sun.COM 	if (smb_is_stream_name(src_fqi->fq_path.pn_path) ||
56310966SJordan.Brown@Sun.COM 	    smb_is_stream_name(dst_fqi->fq_path.pn_path)) {
56410966SJordan.Brown@Sun.COM 		return (EINVAL);
56510966SJordan.Brown@Sun.COM 	}
56610966SJordan.Brown@Sun.COM 
56710966SJordan.Brown@Sun.COM 	/* lookup and validate src node */
56810966SJordan.Brown@Sun.COM 	rc = smb_rename_lookup_src(sr);
56910966SJordan.Brown@Sun.COM 	if (rc != 0)
57010966SJordan.Brown@Sun.COM 		return (rc);
57110966SJordan.Brown@Sun.COM 
57210966SJordan.Brown@Sun.COM 	/* if src and dest paths match we're done */
57310966SJordan.Brown@Sun.COM 	if (smb_strcasecmp(src_fqi->fq_path.pn_path,
57410966SJordan.Brown@Sun.COM 	    dst_fqi->fq_path.pn_path, 0) == 0) {
57510966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
57610966SJordan.Brown@Sun.COM 		return (0);
57710966SJordan.Brown@Sun.COM 	}
57810966SJordan.Brown@Sun.COM 
57910966SJordan.Brown@Sun.COM 	/* find the destination dnode and last_comp */
58010966SJordan.Brown@Sun.COM 	tnode = sr->tid_tree->t_snode;
58110966SJordan.Brown@Sun.COM 	path = dst_fqi->fq_path.pn_path;
58210966SJordan.Brown@Sun.COM 	rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
58310966SJordan.Brown@Sun.COM 	    &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
58410966SJordan.Brown@Sun.COM 	if (rc != 0) {
58510966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
58610966SJordan.Brown@Sun.COM 		return (rc);
58710966SJordan.Brown@Sun.COM 	}
58810966SJordan.Brown@Sun.COM 
58910966SJordan.Brown@Sun.COM 	/* If name match in same directory, we're done */
59010966SJordan.Brown@Sun.COM 	if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) &&
59110966SJordan.Brown@Sun.COM 	    (smb_strcasecmp(src_fqi->fq_fnode->od_name,
59210966SJordan.Brown@Sun.COM 	    dst_fqi->fq_last_comp, 0) == 0)) {
59310966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
59410966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_dnode);
59510966SJordan.Brown@Sun.COM 		return (0);
59610966SJordan.Brown@Sun.COM 	}
59710966SJordan.Brown@Sun.COM 
59811337SWilliam.Krier@Sun.COM 	if (smb_is_invalid_filename(dst_fqi->fq_last_comp)) {
59911337SWilliam.Krier@Sun.COM 		smb_rename_release_src(sr);
60011337SWilliam.Krier@Sun.COM 		smb_node_release(dst_fqi->fq_dnode);
60111337SWilliam.Krier@Sun.COM 		return (EILSEQ); /* NT_STATUS_INVALID_OBJECT_NAME */
60211337SWilliam.Krier@Sun.COM 	}
60311337SWilliam.Krier@Sun.COM 
60410966SJordan.Brown@Sun.COM 	/* Lookup the destination node. It MUST NOT exist. */
60510966SJordan.Brown@Sun.COM 	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
60610966SJordan.Brown@Sun.COM 	    dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode);
60710966SJordan.Brown@Sun.COM 	if (rc == 0) {
60810966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_fnode);
60910966SJordan.Brown@Sun.COM 		rc = EEXIST;
61010966SJordan.Brown@Sun.COM 	}
61110966SJordan.Brown@Sun.COM 	if (rc != ENOENT) {
61210966SJordan.Brown@Sun.COM 		smb_rename_release_src(sr);
61310966SJordan.Brown@Sun.COM 		smb_node_release(dst_fqi->fq_dnode);
61410966SJordan.Brown@Sun.COM 		return (rc);
61510966SJordan.Brown@Sun.COM 	}
61610966SJordan.Brown@Sun.COM 
61710966SJordan.Brown@Sun.COM 	rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode,
61810966SJordan.Brown@Sun.COM 	    dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
61910966SJordan.Brown@Sun.COM 
62010966SJordan.Brown@Sun.COM 	smb_rename_release_src(sr);
62110966SJordan.Brown@Sun.COM 	if (rc == 0)
62210966SJordan.Brown@Sun.COM 		smb_node_notify_change(dst_fqi->fq_dnode);
62310966SJordan.Brown@Sun.COM 	smb_node_release(dst_fqi->fq_dnode);
62410966SJordan.Brown@Sun.COM 	return (rc);
62510966SJordan.Brown@Sun.COM }
62610966SJordan.Brown@Sun.COM 
62710966SJordan.Brown@Sun.COM /*
62810966SJordan.Brown@Sun.COM  * smb_rename_lookup_src
62910966SJordan.Brown@Sun.COM  *
63010966SJordan.Brown@Sun.COM  * Lookup the src node, checking for sharing violations and
631*12890SJoyce.McIntosh@Sun.COM  * breaking any existing BATCH oplock.
63210966SJordan.Brown@Sun.COM  * Populate sr->arg.dirop.fqi
63310966SJordan.Brown@Sun.COM  *
63410966SJordan.Brown@Sun.COM  * Upon success, the dnode and fnode will have holds and the
63510966SJordan.Brown@Sun.COM  * fnode will be in a critical section. These should be
63610966SJordan.Brown@Sun.COM  * released using smb_rename_release_src().
63710966SJordan.Brown@Sun.COM  *
63810966SJordan.Brown@Sun.COM  * Returns errno values.
63910966SJordan.Brown@Sun.COM  */
64010966SJordan.Brown@Sun.COM static int
smb_rename_lookup_src(smb_request_t * sr)64110966SJordan.Brown@Sun.COM smb_rename_lookup_src(smb_request_t *sr)
64210966SJordan.Brown@Sun.COM {
64310966SJordan.Brown@Sun.COM 	smb_node_t *src_node, *tnode;
6449914Samw@Sun.COM 	DWORD status;
6459914Samw@Sun.COM 	int rc;
6469914Samw@Sun.COM 	int count;
64710504SKeyur.Desai@Sun.COM 	char *path;
6489914Samw@Sun.COM 
64910966SJordan.Brown@Sun.COM 	struct dirop *dirop = &sr->arg.dirop;
65010966SJordan.Brown@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
65110504SKeyur.Desai@Sun.COM 
65210966SJordan.Brown@Sun.COM 	if (smb_is_stream_name(src_fqi->fq_path.pn_path))
65310966SJordan.Brown@Sun.COM 		return (EINVAL);
65410966SJordan.Brown@Sun.COM 
65510966SJordan.Brown@Sun.COM 	/* Lookup the source node */
65610966SJordan.Brown@Sun.COM 	tnode = sr->tid_tree->t_snode;
65710504SKeyur.Desai@Sun.COM 	path = src_fqi->fq_path.pn_path;
65810504SKeyur.Desai@Sun.COM 	rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
65910504SKeyur.Desai@Sun.COM 	    &src_fqi->fq_dnode, src_fqi->fq_last_comp);
66010504SKeyur.Desai@Sun.COM 	if (rc != 0)
6619914Samw@Sun.COM 		return (rc);
6629914Samw@Sun.COM 
66310966SJordan.Brown@Sun.COM 	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
66410504SKeyur.Desai@Sun.COM 	    src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
66510504SKeyur.Desai@Sun.COM 	if (rc != 0) {
66610504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
66710504SKeyur.Desai@Sun.COM 		return (rc);
66810504SKeyur.Desai@Sun.COM 	}
6699914Samw@Sun.COM 
67010966SJordan.Brown@Sun.COM 	/* Not valid to create hardlink for directory */
67110966SJordan.Brown@Sun.COM 	if ((dirop->info_level == SMB_NT_RENAME_SET_LINK_INFO) &&
67210966SJordan.Brown@Sun.COM 	    (smb_node_is_dir(src_fqi->fq_fnode))) {
67310966SJordan.Brown@Sun.COM 		smb_node_release(src_fqi->fq_fnode);
67410966SJordan.Brown@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
67510966SJordan.Brown@Sun.COM 		return (EISDIR);
67610966SJordan.Brown@Sun.COM 	}
67710966SJordan.Brown@Sun.COM 
67810966SJordan.Brown@Sun.COM 	src_node = src_fqi->fq_fnode;
67910966SJordan.Brown@Sun.COM 
68010966SJordan.Brown@Sun.COM 	rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr);
68110504SKeyur.Desai@Sun.COM 	if (rc != 0) {
68210504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_fnode);
68310504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
68410504SKeyur.Desai@Sun.COM 		return (rc);
68510504SKeyur.Desai@Sun.COM 	}
6869914Samw@Sun.COM 
6879914Samw@Sun.COM 	/*
688*12890SJoyce.McIntosh@Sun.COM 	 * Break BATCH oplock before access checks. If a client
6899914Samw@Sun.COM 	 * has a file open, this will force a flush or close,
6909914Samw@Sun.COM 	 * which may affect the outcome of any share checking.
6919914Samw@Sun.COM 	 */
692*12890SJoyce.McIntosh@Sun.COM 	(void) smb_oplock_break(sr, src_node,
693*12890SJoyce.McIntosh@Sun.COM 	    SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH);
6949914Samw@Sun.COM 
6959914Samw@Sun.COM 	for (count = 0; count <= 3; count++) {
6969914Samw@Sun.COM 		if (count) {
69710966SJordan.Brown@Sun.COM 			smb_node_end_crit(src_node);
6989914Samw@Sun.COM 			delay(MSEC_TO_TICK(400));
6999914Samw@Sun.COM 		}
7009914Samw@Sun.COM 
70110966SJordan.Brown@Sun.COM 		smb_node_start_crit(src_node, RW_READER);
7029914Samw@Sun.COM 
70310966SJordan.Brown@Sun.COM 		status = smb_node_rename_check(src_node);
7049914Samw@Sun.COM 		if (status != NT_STATUS_SHARING_VIOLATION)
7059914Samw@Sun.COM 			break;
7069914Samw@Sun.COM 	}
7079914Samw@Sun.COM 
7089914Samw@Sun.COM 	if (status == NT_STATUS_SHARING_VIOLATION) {
70910966SJordan.Brown@Sun.COM 		smb_node_end_crit(src_node);
71010504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_fnode);
71110504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
71210504SKeyur.Desai@Sun.COM 		return (EPIPE); /* = ERRbadshare */
7139914Samw@Sun.COM 	}
7149914Samw@Sun.COM 
71510966SJordan.Brown@Sun.COM 	status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE);
7169914Samw@Sun.COM 	if (status != NT_STATUS_SUCCESS) {
71710966SJordan.Brown@Sun.COM 		smb_node_end_crit(src_node);
71810504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_fnode);
71910504SKeyur.Desai@Sun.COM 		smb_node_release(src_fqi->fq_dnode);
72010504SKeyur.Desai@Sun.COM 		return (EACCES);
7219914Samw@Sun.COM 	}
7229914Samw@Sun.COM 
72310966SJordan.Brown@Sun.COM 	return (0);
72410966SJordan.Brown@Sun.COM }
7259914Samw@Sun.COM 
72610966SJordan.Brown@Sun.COM /*
72710966SJordan.Brown@Sun.COM  * smb_rename_release_src
72810966SJordan.Brown@Sun.COM  */
72910966SJordan.Brown@Sun.COM static void
smb_rename_release_src(smb_request_t * sr)73010966SJordan.Brown@Sun.COM smb_rename_release_src(smb_request_t *sr)
73110966SJordan.Brown@Sun.COM {
73210966SJordan.Brown@Sun.COM 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
73310504SKeyur.Desai@Sun.COM 
73410966SJordan.Brown@Sun.COM 	smb_node_end_crit(src_fqi->fq_fnode);
73510504SKeyur.Desai@Sun.COM 	smb_node_release(src_fqi->fq_fnode);
7369914Samw@Sun.COM 	smb_node_release(src_fqi->fq_dnode);
7379914Samw@Sun.COM }
7389914Samw@Sun.COM 
73910966SJordan.Brown@Sun.COM 
7409914Samw@Sun.COM static int
smb_rename_check_attr(smb_request_t * sr,smb_node_t * node,uint16_t sattr)74110001SJoyce.McIntosh@Sun.COM smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr)
7429914Samw@Sun.COM {
74310001SJoyce.McIntosh@Sun.COM 	smb_attr_t attr;
7449914Samw@Sun.COM 
74510001SJoyce.McIntosh@Sun.COM 	if (smb_node_getattr(sr, node, &attr) != 0)
74610001SJoyce.McIntosh@Sun.COM 		return (EIO);
74710001SJoyce.McIntosh@Sun.COM 
74810001SJoyce.McIntosh@Sun.COM 	if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) &&
74910001SJoyce.McIntosh@Sun.COM 	    !(SMB_SEARCH_HIDDEN(sattr)))
7509914Samw@Sun.COM 		return (ESRCH);
7519914Samw@Sun.COM 
75210001SJoyce.McIntosh@Sun.COM 	if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) &&
75310001SJoyce.McIntosh@Sun.COM 	    !(SMB_SEARCH_SYSTEM(sattr)))
7549914Samw@Sun.COM 		return (ESRCH);
7559914Samw@Sun.COM 
7569914Samw@Sun.COM 	return (0);
7579914Samw@Sun.COM }
7589914Samw@Sun.COM 
7599914Samw@Sun.COM /*
7609914Samw@Sun.COM  * The following values are based on observed WFWG, Windows 9x, Windows NT
7619914Samw@Sun.COM  * and Windows 2000 behaviour.
7629914Samw@Sun.COM  *
7639914Samw@Sun.COM  * ERROR_FILE_EXISTS doesn't work for Windows 98 clients.
7649914Samw@Sun.COM  *
7659914Samw@Sun.COM  * Windows 95 clients don't see the problem because the target is deleted
7669914Samw@Sun.COM  * before the rename request.
7679914Samw@Sun.COM  */
7689914Samw@Sun.COM static void
smb_rename_set_error(smb_request_t * sr,int errnum)7699914Samw@Sun.COM smb_rename_set_error(smb_request_t *sr, int errnum)
7709914Samw@Sun.COM {
7719914Samw@Sun.COM 	static struct {
7729914Samw@Sun.COM 		int errnum;
7739914Samw@Sun.COM 		uint16_t errcode;
7749914Samw@Sun.COM 		uint32_t status32;
7759914Samw@Sun.COM 	} rc_map[] = {
7769914Samw@Sun.COM 	{ EEXIST, ERROR_ALREADY_EXISTS,	NT_STATUS_OBJECT_NAME_COLLISION },
7779914Samw@Sun.COM 	{ EPIPE,  ERROR_SHARING_VIOLATION, NT_STATUS_SHARING_VIOLATION },
7789914Samw@Sun.COM 	{ ENOENT, ERROR_FILE_NOT_FOUND,	NT_STATUS_OBJECT_NAME_NOT_FOUND },
7799914Samw@Sun.COM 	{ ESRCH,  ERROR_FILE_NOT_FOUND,	NT_STATUS_NO_SUCH_FILE },
7809914Samw@Sun.COM 	{ EINVAL, ERROR_INVALID_PARAMETER, NT_STATUS_INVALID_PARAMETER },
78110001SJoyce.McIntosh@Sun.COM 	{ EACCES, ERROR_ACCESS_DENIED,	NT_STATUS_ACCESS_DENIED },
78210966SJordan.Brown@Sun.COM 	{ EISDIR, ERROR_ACCESS_DENIED,	NT_STATUS_FILE_IS_A_DIRECTORY },
78310001SJoyce.McIntosh@Sun.COM 	{ EIO,    ERROR_INTERNAL_ERROR,	NT_STATUS_INTERNAL_ERROR }
7849914Samw@Sun.COM 	};
7859914Samw@Sun.COM 
7869914Samw@Sun.COM 	int i;
7879914Samw@Sun.COM 
7889914Samw@Sun.COM 	if (errnum == 0)
7899914Samw@Sun.COM 		return;
7909914Samw@Sun.COM 
7919914Samw@Sun.COM 	for (i = 0; i < sizeof (rc_map)/sizeof (rc_map[0]); ++i) {
7929914Samw@Sun.COM 		if (rc_map[i].errnum == errnum) {
7939914Samw@Sun.COM 			smbsr_error(sr, rc_map[i].status32,
7949914Samw@Sun.COM 			    ERRDOS, rc_map[i].errcode);
7959914Samw@Sun.COM 			return;
7969914Samw@Sun.COM 		}
7979914Samw@Sun.COM 	}
7989914Samw@Sun.COM 
7999914Samw@Sun.COM 	smbsr_errno(sr, errnum);
8009914Samw@Sun.COM }
801