1a90cf9f2SGordon Ross /*
2a90cf9f2SGordon Ross  * CDDL HEADER START
3a90cf9f2SGordon Ross  *
4a90cf9f2SGordon Ross  * The contents of this file are subject to the terms of the
5a90cf9f2SGordon Ross  * Common Development and Distribution License (the "License").
6a90cf9f2SGordon Ross  * You may not use this file except in compliance with the License.
7a90cf9f2SGordon Ross  *
8a90cf9f2SGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a90cf9f2SGordon Ross  * or http://www.opensolaris.org/os/licensing.
10a90cf9f2SGordon Ross  * See the License for the specific language governing permissions
11a90cf9f2SGordon Ross  * and limitations under the License.
12a90cf9f2SGordon Ross  *
13a90cf9f2SGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
14a90cf9f2SGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a90cf9f2SGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
16a90cf9f2SGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
17a90cf9f2SGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
18a90cf9f2SGordon Ross  *
19a90cf9f2SGordon Ross  * CDDL HEADER END
20a90cf9f2SGordon Ross  */
21a90cf9f2SGordon Ross /*
22a90cf9f2SGordon Ross  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23*525641e8SGordon Ross  * Copyright 2013-2020 Tintri by DDN, Inc.  All rights reserved.
24*525641e8SGordon Ross  * Copyright 2019 RackTop Systems.
25a90cf9f2SGordon Ross  */
26a90cf9f2SGordon Ross 
27a90cf9f2SGordon Ross #include <sys/synch.h>
2894047d49SGordon Ross #include <smbsrv/smb2_kproto.h>
29a90cf9f2SGordon Ross #include <smbsrv/smb_fsops.h>
30a90cf9f2SGordon Ross #include <sys/nbmlock.h>
31a90cf9f2SGordon Ross 
32a90cf9f2SGordon Ross /*
33a90cf9f2SGordon Ross  * SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag
34a90cf9f2SGordon Ross  */
35a90cf9f2SGordon Ross #define	SMB_RENAME_FLAG_OVERWRITE	0x001
36a90cf9f2SGordon Ross 
37a90cf9f2SGordon Ross static int smb_rename_check_stream(smb_fqi_t *, smb_fqi_t *);
38a90cf9f2SGordon Ross static int smb_rename_check_attr(smb_request_t *, smb_node_t *, uint16_t);
39a90cf9f2SGordon Ross static int smb_rename_lookup_src(smb_request_t *);
4094047d49SGordon Ross static uint32_t smb_rename_check_src(smb_request_t *, smb_fqi_t *);
41a90cf9f2SGordon Ross static void smb_rename_release_src(smb_request_t *);
42a90cf9f2SGordon Ross static uint32_t smb_rename_errno2status(int);
43a90cf9f2SGordon Ross 
44a90cf9f2SGordon Ross /*
45a90cf9f2SGordon Ross  * smb_setinfo_rename
46a90cf9f2SGordon Ross  *
47a90cf9f2SGordon Ross  * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo
48a90cf9f2SGordon Ross  * and Trans2_Set_PathInfo and SMB2 set_info, FileRenameInformation.
49a90cf9f2SGordon Ross  * If the new filename (dst_fqi) already exists it may be overwritten
50a90cf9f2SGordon Ross  * if flags == 1.
51a90cf9f2SGordon Ross  *
52a90cf9f2SGordon Ross  * The passed path is a full path relative to the share root.
53a90cf9f2SGordon Ross  *
54a90cf9f2SGordon Ross  * Returns NT status codes.
55a90cf9f2SGordon Ross  *
56a90cf9f2SGordon Ross  * Similar to smb_setinfo_link(), below.
57a90cf9f2SGordon Ross  */
58a90cf9f2SGordon Ross uint32_t
smb_setinfo_rename(smb_request_t * sr,smb_node_t * node,char * path,int flags)59a90cf9f2SGordon Ross smb_setinfo_rename(smb_request_t *sr, smb_node_t *node, char *path, int flags)
60a90cf9f2SGordon Ross {
61a90cf9f2SGordon Ross 	smb_fqi_t	*src_fqi = &sr->arg.dirop.fqi;
62a90cf9f2SGordon Ross 	smb_fqi_t	*dst_fqi = &sr->arg.dirop.dst_fqi;
63a90cf9f2SGordon Ross 	smb_pathname_t	*dst_pn = &dst_fqi->fq_path;
64a90cf9f2SGordon Ross 	uint32_t	status;
65a90cf9f2SGordon Ross 
66a90cf9f2SGordon Ross 	sr->arg.dirop.flags = flags ? SMB_RENAME_FLAG_OVERWRITE : 0;
67a90cf9f2SGordon Ross 	sr->arg.dirop.info_level = FileRenameInformation;
68a90cf9f2SGordon Ross 
69a90cf9f2SGordon Ross 	src_fqi->fq_sattr = SMB_SEARCH_ATTRIBUTES;
70a90cf9f2SGordon Ross 	src_fqi->fq_fnode = node;
71a90cf9f2SGordon Ross 	src_fqi->fq_dnode = node->n_dnode;
72a90cf9f2SGordon Ross 
73a90cf9f2SGordon Ross 	/* validate the dst pathname */
74a90cf9f2SGordon Ross 	smb_pathname_init(sr, dst_pn, path);
75a90cf9f2SGordon Ross 	if (!smb_pathname_validate(sr, dst_pn))
76a90cf9f2SGordon Ross 		return (NT_STATUS_OBJECT_NAME_INVALID);
77a90cf9f2SGordon Ross 
78a90cf9f2SGordon Ross 	status = smb_common_rename(sr, src_fqi, dst_fqi);
79a90cf9f2SGordon Ross 	return (status);
80a90cf9f2SGordon Ross }
81a90cf9f2SGordon Ross 
82a90cf9f2SGordon Ross /*
83a90cf9f2SGordon Ross  * smb_common_rename
84a90cf9f2SGordon Ross  *
85a90cf9f2SGordon Ross  * Common code for renaming a file.
86a90cf9f2SGordon Ross  *
87a90cf9f2SGordon Ross  * If the source and destination are identical, we go through all
88a90cf9f2SGordon Ross  * the checks but we don't actually do the rename.  If the source
89a90cf9f2SGordon Ross  * and destination files differ only in case, we do a case-sensitive
90a90cf9f2SGordon Ross  * rename.  Otherwise, we do a full case-insensitive rename.
91a90cf9f2SGordon Ross  *
92a90cf9f2SGordon Ross  * Returns NT status values.
93a90cf9f2SGordon Ross  *
94a90cf9f2SGordon Ross  * Similar to smb_make_link(), below.
95a90cf9f2SGordon Ross  */
96a90cf9f2SGordon Ross uint32_t
smb_common_rename(smb_request_t * sr,smb_fqi_t * src_fqi,smb_fqi_t * dst_fqi)97a90cf9f2SGordon Ross smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
98a90cf9f2SGordon Ross {
99a90cf9f2SGordon Ross 	smb_node_t *src_fnode, *src_dnode, *dst_dnode;
100a90cf9f2SGordon Ross 	smb_node_t *dst_fnode = 0;
101a90cf9f2SGordon Ross 	smb_node_t *tnode;
102a90cf9f2SGordon Ross 	char *new_name, *path;
103a90cf9f2SGordon Ross 	DWORD status;
10494047d49SGordon Ross 	int rc;
105a90cf9f2SGordon Ross 
106a90cf9f2SGordon Ross 	tnode = sr->tid_tree->t_snode;
107a90cf9f2SGordon Ross 	path = dst_fqi->fq_path.pn_path;
108a90cf9f2SGordon Ross 
109a90cf9f2SGordon Ross 	/* Check if attempting to rename a stream - not yet supported */
110a90cf9f2SGordon Ross 	rc = smb_rename_check_stream(src_fqi, dst_fqi);
111a90cf9f2SGordon Ross 	if (rc != 0)
112a90cf9f2SGordon Ross 		return (smb_rename_errno2status(rc));
113a90cf9f2SGordon Ross 
114a90cf9f2SGordon Ross 	/*
115a90cf9f2SGordon Ross 	 * The source node may already have been provided,
11694047d49SGordon Ross 	 * i.e. when called by SMB1/SMB2 smb_setinfo_rename
11794047d49SGordon Ross 	 * with an ofile.  When we have an ofile, open has
11894047d49SGordon Ross 	 * already checked for sharing violations.  For
11994047d49SGordon Ross 	 * path-based operations, do sharing check here.
120a90cf9f2SGordon Ross 	 */
121a90cf9f2SGordon Ross 	if (src_fqi->fq_fnode) {
122a90cf9f2SGordon Ross 		smb_node_ref(src_fqi->fq_dnode);
12394047d49SGordon Ross 		smb_node_ref(src_fqi->fq_fnode);
124a90cf9f2SGordon Ross 	} else {
125a90cf9f2SGordon Ross 		/* lookup and validate src node */
126a90cf9f2SGordon Ross 		rc = smb_rename_lookup_src(sr);
127a90cf9f2SGordon Ross 		if (rc != 0)
128a90cf9f2SGordon Ross 			return (smb_rename_errno2status(rc));
12994047d49SGordon Ross 		/* Holding refs on dnode, fnode */
130a90cf9f2SGordon Ross 	}
131a90cf9f2SGordon Ross 	src_fnode = src_fqi->fq_fnode;
132a90cf9f2SGordon Ross 	src_dnode = src_fqi->fq_dnode;
133a90cf9f2SGordon Ross 
13494047d49SGordon Ross 	/* Break oplocks, and check share modes. */
13594047d49SGordon Ross 	status = smb_rename_check_src(sr, src_fqi);
13694047d49SGordon Ross 	if (status != NT_STATUS_SUCCESS) {
13794047d49SGordon Ross 		smb_node_release(src_fqi->fq_fnode);
13894047d49SGordon Ross 		smb_node_release(src_fqi->fq_dnode);
13994047d49SGordon Ross 		return (status);
14094047d49SGordon Ross 	}
14194047d49SGordon Ross 	/*
14294047d49SGordon Ross 	 * NB: src_fnode is now "in crit" (critical section)
14394047d49SGordon Ross 	 * as if we did smb_node_start_crit(..., RW_READER);
14494047d49SGordon Ross 	 * Call smb_rename_release_src(sr) on errors.
14594047d49SGordon Ross 	 */
14694047d49SGordon Ross 
147a90cf9f2SGordon Ross 	/*
148a90cf9f2SGordon Ross 	 * Find the destination dnode and last component.
149a90cf9f2SGordon Ross 	 * May already be provided, i.e. when called via
150a90cf9f2SGordon Ross 	 * SMB1 trans2 setinfo.
151a90cf9f2SGordon Ross 	 */
152a90cf9f2SGordon Ross 	if (dst_fqi->fq_dnode) {
153a90cf9f2SGordon Ross 		/* called via smb_set_rename_info */
154a90cf9f2SGordon Ross 		smb_node_ref(dst_fqi->fq_dnode);
155a90cf9f2SGordon Ross 	} else {
156a90cf9f2SGordon Ross 		/* called via smb2_setf_rename, smb_com_rename, etc. */
157a90cf9f2SGordon Ross 		rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
158a90cf9f2SGordon Ross 		    &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
159a90cf9f2SGordon Ross 		if (rc != 0) {
160a90cf9f2SGordon Ross 			smb_rename_release_src(sr);
161a90cf9f2SGordon Ross 			return (smb_rename_errno2status(rc));
162a90cf9f2SGordon Ross 		}
163a90cf9f2SGordon Ross 	}
164a90cf9f2SGordon Ross 
165a90cf9f2SGordon Ross 	dst_dnode = dst_fqi->fq_dnode;
166a90cf9f2SGordon Ross 	new_name = dst_fqi->fq_last_comp;
167a90cf9f2SGordon Ross 
168a90cf9f2SGordon Ross 	/* If exact name match in same directory, we're done */
169a90cf9f2SGordon Ross 	if ((src_dnode == dst_dnode) &&
170a90cf9f2SGordon Ross 	    (strcmp(src_fnode->od_name, new_name) == 0)) {
171a90cf9f2SGordon Ross 		smb_rename_release_src(sr);
172a90cf9f2SGordon Ross 		smb_node_release(dst_dnode);
173a90cf9f2SGordon Ross 		return (0);
174a90cf9f2SGordon Ross 	}
175a90cf9f2SGordon Ross 
176a90cf9f2SGordon Ross 	/* Lookup destination node */
177a90cf9f2SGordon Ross 	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
178a90cf9f2SGordon Ross 	    dst_dnode, new_name, &dst_fqi->fq_fnode);
179a90cf9f2SGordon Ross 
180a90cf9f2SGordon Ross 	/* If the destination node doesn't already exist, validate new_name. */
181a90cf9f2SGordon Ross 	if (rc == ENOENT) {
182a90cf9f2SGordon Ross 		if (smb_is_invalid_filename(new_name)) {
183a90cf9f2SGordon Ross 			smb_rename_release_src(sr);
184a90cf9f2SGordon Ross 			smb_node_release(dst_dnode);
185a90cf9f2SGordon Ross 			return (NT_STATUS_OBJECT_NAME_INVALID);
186a90cf9f2SGordon Ross 		}
187a90cf9f2SGordon Ross 	}
188a90cf9f2SGordon Ross 
189a90cf9f2SGordon Ross 	/*
190a90cf9f2SGordon Ross 	 * Handle case where changing case of the same directory entry.
191a90cf9f2SGordon Ross 	 *
192a90cf9f2SGordon Ross 	 * If we found the dst node in the same directory as the src node,
193a90cf9f2SGordon Ross 	 * and their names differ only in case:
194a90cf9f2SGordon Ross 	 *
195a90cf9f2SGordon Ross 	 * If the tree is case sensitive (or mixed):
196a90cf9f2SGordon Ross 	 *  Do case sensitive lookup to see if exact match exists.
197a90cf9f2SGordon Ross 	 *  If the exact match is the same node as src_node we're done.
198a90cf9f2SGordon Ross 	 *
199a90cf9f2SGordon Ross 	 * If the tree is case insensitive:
200a90cf9f2SGordon Ross 	 *  There is currently no way to tell if the case is different
201a90cf9f2SGordon Ross 	 *  or not, so do the rename (unless the specified new name was
202a90cf9f2SGordon Ross 	 *  mangled).
203a90cf9f2SGordon Ross 	 */
204a90cf9f2SGordon Ross 	if ((rc == 0) &&
205a90cf9f2SGordon Ross 	    (src_dnode == dst_dnode) &&
206a90cf9f2SGordon Ross 	    (smb_strcasecmp(src_fnode->od_name,
207a90cf9f2SGordon Ross 	    dst_fqi->fq_fnode->od_name, 0) == 0)) {
208a90cf9f2SGordon Ross 		smb_node_release(dst_fqi->fq_fnode);
209a90cf9f2SGordon Ross 		dst_fqi->fq_fnode = NULL;
210a90cf9f2SGordon Ross 
211a90cf9f2SGordon Ross 		if (smb_tree_has_feature(sr->tid_tree,
212a90cf9f2SGordon Ross 		    SMB_TREE_NO_CASESENSITIVE)) {
213a90cf9f2SGordon Ross 			if (smb_strcasecmp(src_fnode->od_name,
214a90cf9f2SGordon Ross 			    dst_fqi->fq_last_comp, 0) != 0) {
215a90cf9f2SGordon Ross 				smb_rename_release_src(sr);
216a90cf9f2SGordon Ross 				smb_node_release(dst_dnode);
217a90cf9f2SGordon Ross 				return (0);
218a90cf9f2SGordon Ross 			}
219a90cf9f2SGordon Ross 		} else {
220a90cf9f2SGordon Ross 			rc = smb_fsop_lookup(sr, sr->user_cr,
221a90cf9f2SGordon Ross 			    SMB_CASE_SENSITIVE, tnode, dst_dnode, new_name,
222a90cf9f2SGordon Ross 			    &dst_fqi->fq_fnode);
223a90cf9f2SGordon Ross 
224a90cf9f2SGordon Ross 			if ((rc == 0) &&
225a90cf9f2SGordon Ross 			    (dst_fqi->fq_fnode == src_fnode)) {
226a90cf9f2SGordon Ross 				smb_rename_release_src(sr);
227a90cf9f2SGordon Ross 				smb_node_release(dst_fqi->fq_fnode);
228a90cf9f2SGordon Ross 				smb_node_release(dst_dnode);
229a90cf9f2SGordon Ross 				return (0);
230a90cf9f2SGordon Ross 			}
231a90cf9f2SGordon Ross 		}
232a90cf9f2SGordon Ross 	}
233a90cf9f2SGordon Ross 
234a90cf9f2SGordon Ross 	if ((rc != 0) && (rc != ENOENT)) {
235a90cf9f2SGordon Ross 		smb_rename_release_src(sr);
236a90cf9f2SGordon Ross 		smb_node_release(dst_fqi->fq_dnode);
237a90cf9f2SGordon Ross 		return (smb_rename_errno2status(rc));
238a90cf9f2SGordon Ross 	}
239a90cf9f2SGordon Ross 
240a90cf9f2SGordon Ross 	if (dst_fqi->fq_fnode) {
241a90cf9f2SGordon Ross 		/*
242a90cf9f2SGordon Ross 		 * Destination already exists.  Do delete checks.
243a90cf9f2SGordon Ross 		 */
244a90cf9f2SGordon Ross 		dst_fnode = dst_fqi->fq_fnode;
245a90cf9f2SGordon Ross 
2465255b2c2SAram Hăvărneanu 		if ((sr->arg.dirop.flags & SMB_RENAME_FLAG_OVERWRITE) == 0) {
247a90cf9f2SGordon Ross 			smb_rename_release_src(sr);
248a90cf9f2SGordon Ross 			smb_node_release(dst_fnode);
249a90cf9f2SGordon Ross 			smb_node_release(dst_dnode);
250a90cf9f2SGordon Ross 			return (NT_STATUS_OBJECT_NAME_COLLISION);
251a90cf9f2SGordon Ross 		}
252a90cf9f2SGordon Ross 
25394047d49SGordon Ross 		status = smb_oplock_break_DELETE(dst_fnode, NULL);
25494047d49SGordon Ross 		if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
25594047d49SGordon Ross 			if (sr->session->dialect >= SMB_VERS_2_BASE)
25694047d49SGordon Ross 				(void) smb2sr_go_async(sr);
257*525641e8SGordon Ross 			(void) smb_oplock_wait_break(sr, dst_fnode, 0);
25894047d49SGordon Ross 			status = 0;
25994047d49SGordon Ross 		}
26094047d49SGordon Ross 		if (status != 0) {
26194047d49SGordon Ross 			smb_rename_release_src(sr);
26294047d49SGordon Ross 			smb_node_release(dst_fnode);
26394047d49SGordon Ross 			smb_node_release(dst_dnode);
26494047d49SGordon Ross 			return (status);
26594047d49SGordon Ross 		}
266a90cf9f2SGordon Ross 
267a90cf9f2SGordon Ross 		smb_node_rdlock(dst_fnode);
26894047d49SGordon Ross 		status = smb_node_delete_check(dst_fnode);
269a90cf9f2SGordon Ross 		if (status != NT_STATUS_SUCCESS) {
270a90cf9f2SGordon Ross 			smb_node_unlock(dst_fnode);
271a90cf9f2SGordon Ross 			smb_rename_release_src(sr);
272a90cf9f2SGordon Ross 			smb_node_release(dst_fnode);
273a90cf9f2SGordon Ross 			smb_node_release(dst_dnode);
274a90cf9f2SGordon Ross 			return (NT_STATUS_ACCESS_DENIED);
275a90cf9f2SGordon Ross 		}
276a90cf9f2SGordon Ross 
277a90cf9f2SGordon Ross 		/*
278a90cf9f2SGordon Ross 		 * Note, the combination of these two:
279a90cf9f2SGordon Ross 		 *	smb_node_rdlock(node);
280a90cf9f2SGordon Ross 		 *	nbl_start_crit(node->vp, RW_READER);
281a90cf9f2SGordon Ross 		 * is equivalent to this call:
282a90cf9f2SGordon Ross 		 *	smb_node_start_crit(node, RW_READER)
283a90cf9f2SGordon Ross 		 *
284a90cf9f2SGordon Ross 		 * Cleanup after this point should use:
285a90cf9f2SGordon Ross 		 *	smb_node_end_crit(dst_fnode)
286a90cf9f2SGordon Ross 		 */
287a90cf9f2SGordon Ross 		nbl_start_crit(dst_fnode->vp, RW_READER);
288a90cf9f2SGordon Ross 
289a90cf9f2SGordon Ross 		/*
290a90cf9f2SGordon Ross 		 * This checks nbl_share_conflict, nbl_lock_conflict
291a90cf9f2SGordon Ross 		 */
292a90cf9f2SGordon Ross 		status = smb_nbl_conflict(dst_fnode, 0, UINT64_MAX, NBL_REMOVE);
293a90cf9f2SGordon Ross 		if (status != NT_STATUS_SUCCESS) {
294a90cf9f2SGordon Ross 			smb_node_end_crit(dst_fnode);
295a90cf9f2SGordon Ross 			smb_rename_release_src(sr);
296a90cf9f2SGordon Ross 			smb_node_release(dst_fnode);
297a90cf9f2SGordon Ross 			smb_node_release(dst_dnode);
298a90cf9f2SGordon Ross 			return (NT_STATUS_ACCESS_DENIED);
299a90cf9f2SGordon Ross 		}
300a90cf9f2SGordon Ross 
301a90cf9f2SGordon Ross 		new_name = dst_fnode->od_name;
302a90cf9f2SGordon Ross 	}
303a90cf9f2SGordon Ross 
304a90cf9f2SGordon Ross 	rc = smb_fsop_rename(sr, sr->user_cr,
305a90cf9f2SGordon Ross 	    src_dnode, src_fnode->od_name,
306a90cf9f2SGordon Ross 	    dst_dnode, new_name);
307a90cf9f2SGordon Ross 
308a90cf9f2SGordon Ross 	if (rc == 0) {
309a90cf9f2SGordon Ross 		/*
310a90cf9f2SGordon Ross 		 * Note that renames in the same directory are normally
311a90cf9f2SGordon Ross 		 * delivered in {old,new} pairs, and clients expect them
312a90cf9f2SGordon Ross 		 * in that order, if both events are delivered.
313a90cf9f2SGordon Ross 		 */
314a90cf9f2SGordon Ross 		int a_src, a_dst; /* action codes */
315a90cf9f2SGordon Ross 		if (src_dnode == dst_dnode) {
316a90cf9f2SGordon Ross 			a_src = FILE_ACTION_RENAMED_OLD_NAME;
317a90cf9f2SGordon Ross 			a_dst = FILE_ACTION_RENAMED_NEW_NAME;
318a90cf9f2SGordon Ross 		} else {
319a90cf9f2SGordon Ross 			a_src = FILE_ACTION_REMOVED;
320a90cf9f2SGordon Ross 			a_dst = FILE_ACTION_ADDED;
321a90cf9f2SGordon Ross 		}
322a90cf9f2SGordon Ross 		smb_node_notify_change(src_dnode, a_src, src_fnode->od_name);
323a90cf9f2SGordon Ross 		smb_node_notify_change(dst_dnode, a_dst, new_name);
324a90cf9f2SGordon Ross 	}
325a90cf9f2SGordon Ross 
326a90cf9f2SGordon Ross 	smb_rename_release_src(sr);
327a90cf9f2SGordon Ross 
328a90cf9f2SGordon Ross 	if (dst_fqi->fq_fnode) {
329a90cf9f2SGordon Ross 		smb_node_end_crit(dst_fnode);
330a90cf9f2SGordon Ross 		smb_node_release(dst_fnode);
331a90cf9f2SGordon Ross 	}
332a90cf9f2SGordon Ross 	smb_node_release(dst_dnode);
333a90cf9f2SGordon Ross 
334a90cf9f2SGordon Ross 	return (smb_rename_errno2status(rc));
335a90cf9f2SGordon Ross }
336a90cf9f2SGordon Ross 
337a90cf9f2SGordon Ross /*
338a90cf9f2SGordon Ross  * smb_rename_check_stream
339a90cf9f2SGordon Ross  *
340a90cf9f2SGordon Ross  * For a stream rename the dst path must begin with ':', or "\\:".
341a90cf9f2SGordon Ross  * We don't yet support stream rename, Return EACCES.
342a90cf9f2SGordon Ross  *
343a90cf9f2SGordon Ross  * If not a stream rename, in accordance with the above rule,
344a90cf9f2SGordon Ross  * it is not valid for either the src or dst to be a stream.
345a90cf9f2SGordon Ross  * Return EINVAL.
346a90cf9f2SGordon Ross  */
347a90cf9f2SGordon Ross static int
smb_rename_check_stream(smb_fqi_t * src_fqi,smb_fqi_t * dst_fqi)348a90cf9f2SGordon Ross smb_rename_check_stream(smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
349a90cf9f2SGordon Ross {
350a90cf9f2SGordon Ross 	smb_node_t *src_fnode = src_fqi->fq_fnode;
351a90cf9f2SGordon Ross 	char *src_path = src_fqi->fq_path.pn_path;
352a90cf9f2SGordon Ross 	char *dst_path = dst_fqi->fq_path.pn_path;
353a90cf9f2SGordon Ross 
354a90cf9f2SGordon Ross 	/* We do not yet support named stream rename - ACCESS DENIED */
355a90cf9f2SGordon Ross 	if ((dst_path[0] == ':') ||
356a90cf9f2SGordon Ross 	    ((dst_path[0] == '\\') && (dst_path[1] == ':'))) {
357a90cf9f2SGordon Ross 		return (EACCES);
358a90cf9f2SGordon Ross 	}
359a90cf9f2SGordon Ross 
360a90cf9f2SGordon Ross 	/*
361a90cf9f2SGordon Ross 	 * If not stream rename (above) neither src or dst can be
362a90cf9f2SGordon Ross 	 * a named stream.
363a90cf9f2SGordon Ross 	 */
364a90cf9f2SGordon Ross 
365a90cf9f2SGordon Ross 	if (smb_is_stream_name(dst_path))
366a90cf9f2SGordon Ross 		return (EINVAL);
367a90cf9f2SGordon Ross 
368a90cf9f2SGordon Ross 	if (src_fqi->fq_fnode) {
369a90cf9f2SGordon Ross 		if (SMB_IS_STREAM(src_fnode))
370a90cf9f2SGordon Ross 			return (EINVAL);
371a90cf9f2SGordon Ross 	} else {
372a90cf9f2SGordon Ross 		if (smb_is_stream_name(src_path))
373a90cf9f2SGordon Ross 			return (EINVAL);
374a90cf9f2SGordon Ross 	}
375a90cf9f2SGordon Ross 
376a90cf9f2SGordon Ross 	return (0);
377a90cf9f2SGordon Ross }
378a90cf9f2SGordon Ross 
379a90cf9f2SGordon Ross 
380a90cf9f2SGordon Ross /*
381a90cf9f2SGordon Ross  * smb_setinfo_link
382a90cf9f2SGordon Ross  *
383a90cf9f2SGordon Ross  * Implements FileRenameInformation for SMB1 Trans2 setinfo, SMB2 setinfo.
384a90cf9f2SGordon Ross  * If the new filename (dst_fqi) already exists it may be overwritten
385a90cf9f2SGordon Ross  * if flags == 1.
386a90cf9f2SGordon Ross  *
387a90cf9f2SGordon Ross  * The passed path is a full path relative to the share root.
388a90cf9f2SGordon Ross  *
389a90cf9f2SGordon Ross  * Returns NT status codes.
390a90cf9f2SGordon Ross  *
391a90cf9f2SGordon Ross  * Similar to smb_setinfo_rename(), above.
392a90cf9f2SGordon Ross  */
393a90cf9f2SGordon Ross uint32_t
smb_setinfo_link(smb_request_t * sr,smb_node_t * node,char * path,int flags)394a90cf9f2SGordon Ross smb_setinfo_link(smb_request_t *sr, smb_node_t *node, char *path, int flags)
395a90cf9f2SGordon Ross {
396a90cf9f2SGordon Ross 	smb_fqi_t	*src_fqi = &sr->arg.dirop.fqi;
397a90cf9f2SGordon Ross 	smb_fqi_t	*dst_fqi = &sr->arg.dirop.dst_fqi;
398a90cf9f2SGordon Ross 	smb_pathname_t	*dst_pn = &dst_fqi->fq_path;
399a90cf9f2SGordon Ross 	uint32_t	status;
400a90cf9f2SGordon Ross 
401a90cf9f2SGordon Ross 	sr->arg.dirop.flags = flags ? SMB_RENAME_FLAG_OVERWRITE : 0;
402a90cf9f2SGordon Ross 	sr->arg.dirop.info_level = FileLinkInformation;
403a90cf9f2SGordon Ross 
404a90cf9f2SGordon Ross 	src_fqi->fq_sattr = SMB_SEARCH_ATTRIBUTES;
405a90cf9f2SGordon Ross 	src_fqi->fq_fnode = node;
406a90cf9f2SGordon Ross 	src_fqi->fq_dnode = node->n_dnode;
407a90cf9f2SGordon Ross 
408a90cf9f2SGordon Ross 	/* validate the dst pathname */
409a90cf9f2SGordon Ross 	smb_pathname_init(sr, dst_pn, path);
410a90cf9f2SGordon Ross 	if (!smb_pathname_validate(sr, dst_pn))
411a90cf9f2SGordon Ross 		return (NT_STATUS_OBJECT_NAME_INVALID);
412a90cf9f2SGordon Ross 
413a90cf9f2SGordon Ross 	status = smb_make_link(sr, src_fqi, dst_fqi);
414a90cf9f2SGordon Ross 	return (status);
415a90cf9f2SGordon Ross }
416a90cf9f2SGordon Ross 
417a90cf9f2SGordon Ross /*
418a90cf9f2SGordon Ross  * smb_make_link
419a90cf9f2SGordon Ross  *
420a90cf9f2SGordon Ross  * Creating a hard link (adding an additional name) for a file.
421a90cf9f2SGordon Ross  *
422a90cf9f2SGordon Ross  * If the source and destination are identical, we go through all
423a90cf9f2SGordon Ross  * the checks but we don't create a link.
424a90cf9f2SGordon Ross  *
425a90cf9f2SGordon Ross  * If the file is a symlink we create the hardlink on the target
426a90cf9f2SGordon Ross  * of the symlink (i.e. use SMB_FOLLOW_LINKS when looking up src).
427a90cf9f2SGordon Ross  * If the target of the symlink does not exist we fail with ENOENT.
428a90cf9f2SGordon Ross  *
429a90cf9f2SGordon Ross  * Returns NT status values.
430a90cf9f2SGordon Ross  *
431a90cf9f2SGordon Ross  * Similar to smb_common_rename() above.
432a90cf9f2SGordon Ross  */
433a90cf9f2SGordon Ross uint32_t
smb_make_link(smb_request_t * sr,smb_fqi_t * src_fqi,smb_fqi_t * dst_fqi)434a90cf9f2SGordon Ross smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
435a90cf9f2SGordon Ross {
436a90cf9f2SGordon Ross 	smb_node_t *tnode;
437a90cf9f2SGordon Ross 	char *path;
438a90cf9f2SGordon Ross 	int rc;
439a90cf9f2SGordon Ross 
440a90cf9f2SGordon Ross 	tnode = sr->tid_tree->t_snode;
441a90cf9f2SGordon Ross 	path = dst_fqi->fq_path.pn_path;
442a90cf9f2SGordon Ross 
443a90cf9f2SGordon Ross 	/* Cannnot create link on named stream */
444a90cf9f2SGordon Ross 	if (smb_is_stream_name(src_fqi->fq_path.pn_path) ||
445a90cf9f2SGordon Ross 	    smb_is_stream_name(dst_fqi->fq_path.pn_path)) {
446a90cf9f2SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
447a90cf9f2SGordon Ross 	}
448a90cf9f2SGordon Ross 
449a90cf9f2SGordon Ross 	/* The source node may already have been provided */
450a90cf9f2SGordon Ross 	if (src_fqi->fq_fnode) {
451a90cf9f2SGordon Ross 		smb_node_ref(src_fqi->fq_dnode);
45294047d49SGordon Ross 		smb_node_ref(src_fqi->fq_fnode);
453a90cf9f2SGordon Ross 	} else {
454a90cf9f2SGordon Ross 		/* lookup and validate src node */
455a90cf9f2SGordon Ross 		rc = smb_rename_lookup_src(sr);
456a90cf9f2SGordon Ross 		if (rc != 0)
457a90cf9f2SGordon Ross 			return (smb_rename_errno2status(rc));
45894047d49SGordon Ross 		/* Holding refs on dnode, fnode */
459a90cf9f2SGordon Ross 	}
460a90cf9f2SGordon Ross 
461a90cf9f2SGordon Ross 	/* Not valid to create hardlink for directory */
462a90cf9f2SGordon Ross 	if (smb_node_is_dir(src_fqi->fq_fnode)) {
46394047d49SGordon Ross 		smb_node_release(src_fqi->fq_dnode);
46494047d49SGordon Ross 		smb_node_release(src_fqi->fq_fnode);
465a90cf9f2SGordon Ross 		return (NT_STATUS_FILE_IS_A_DIRECTORY);
466a90cf9f2SGordon Ross 	}
467a90cf9f2SGordon Ross 
46894047d49SGordon Ross 	/*
46994047d49SGordon Ross 	 * Unlike in rename, we will not unlink the src,
47094047d49SGordon Ross 	 * so skip the smb_rename_check_src() call, and
47194047d49SGordon Ross 	 * just "start crit" instead.
47294047d49SGordon Ross 	 */
47394047d49SGordon Ross 	smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
47494047d49SGordon Ross 
475a90cf9f2SGordon Ross 	/*
476a90cf9f2SGordon Ross 	 * Find the destination dnode and last component.
477a90cf9f2SGordon Ross 	 * May already be provided, i.e. when called via
478a90cf9f2SGordon Ross 	 * SMB1 trans2 setinfo.
479a90cf9f2SGordon Ross 	 */
480a90cf9f2SGordon Ross 	if (dst_fqi->fq_dnode) {
481a90cf9f2SGordon Ross 		smb_node_ref(dst_fqi->fq_dnode);
482a90cf9f2SGordon Ross 	} else {
483a90cf9f2SGordon Ross 		rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
484a90cf9f2SGordon Ross 		    &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
485a90cf9f2SGordon Ross 		if (rc != 0) {
486a90cf9f2SGordon Ross 			smb_rename_release_src(sr);
487a90cf9f2SGordon Ross 			return (smb_rename_errno2status(rc));
488a90cf9f2SGordon Ross 		}
489a90cf9f2SGordon Ross 	}
490a90cf9f2SGordon Ross 
491a90cf9f2SGordon Ross 	/* If CI name match in same directory, we're done */
492a90cf9f2SGordon Ross 	if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) &&
493a90cf9f2SGordon Ross 	    (smb_strcasecmp(src_fqi->fq_fnode->od_name,
494a90cf9f2SGordon Ross 	    dst_fqi->fq_last_comp, 0) == 0)) {
495a90cf9f2SGordon Ross 		smb_rename_release_src(sr);
496a90cf9f2SGordon Ross 		smb_node_release(dst_fqi->fq_dnode);
497a90cf9f2SGordon Ross 		return (0);
498a90cf9f2SGordon Ross 	}
499a90cf9f2SGordon Ross 
500a90cf9f2SGordon Ross 	if (smb_is_invalid_filename(dst_fqi->fq_last_comp)) {
501a90cf9f2SGordon Ross 		smb_rename_release_src(sr);
502a90cf9f2SGordon Ross 		smb_node_release(dst_fqi->fq_dnode);
503a90cf9f2SGordon Ross 		return (NT_STATUS_OBJECT_NAME_INVALID);
504a90cf9f2SGordon Ross 	}
505a90cf9f2SGordon Ross 
506a90cf9f2SGordon Ross 	/* Lookup the destination node. It MUST NOT exist. */
507a90cf9f2SGordon Ross 	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
508a90cf9f2SGordon Ross 	    dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode);
509a90cf9f2SGordon Ross 	if (rc == 0) {
510a90cf9f2SGordon Ross 		smb_node_release(dst_fqi->fq_fnode);
511a90cf9f2SGordon Ross 		rc = EEXIST;
512a90cf9f2SGordon Ross 	}
513a90cf9f2SGordon Ross 	if (rc != ENOENT) {
514a90cf9f2SGordon Ross 		smb_rename_release_src(sr);
515a90cf9f2SGordon Ross 		smb_node_release(dst_fqi->fq_dnode);
516a90cf9f2SGordon Ross 		return (smb_rename_errno2status(rc));
517a90cf9f2SGordon Ross 	}
518a90cf9f2SGordon Ross 
519a90cf9f2SGordon Ross 	rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode,
520a90cf9f2SGordon Ross 	    dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
521a90cf9f2SGordon Ross 
522a90cf9f2SGordon Ross 	if (rc == 0) {
523a90cf9f2SGordon Ross 		smb_node_notify_change(dst_fqi->fq_dnode,
524a90cf9f2SGordon Ross 		    FILE_ACTION_ADDED, dst_fqi->fq_last_comp);
525a90cf9f2SGordon Ross 	}
526a90cf9f2SGordon Ross 
527a90cf9f2SGordon Ross 	smb_rename_release_src(sr);
528a90cf9f2SGordon Ross 	smb_node_release(dst_fqi->fq_dnode);
529a90cf9f2SGordon Ross 	return (smb_rename_errno2status(rc));
530a90cf9f2SGordon Ross }
531a90cf9f2SGordon Ross 
532a90cf9f2SGordon Ross /*
533a90cf9f2SGordon Ross  * smb_rename_lookup_src
534a90cf9f2SGordon Ross  *
53594047d49SGordon Ross  * Lookup the src node for a path-based link or rename.
536a90cf9f2SGordon Ross  *
53794047d49SGordon Ross  * On success, fills in sr->arg.dirop.fqi, and returns with
53894047d49SGordon Ross  * holds on the source dnode and fnode.
539a90cf9f2SGordon Ross  *
540a90cf9f2SGordon Ross  * Returns errno values.
541a90cf9f2SGordon Ross  */
542a90cf9f2SGordon Ross static int
smb_rename_lookup_src(smb_request_t * sr)543a90cf9f2SGordon Ross smb_rename_lookup_src(smb_request_t *sr)
544a90cf9f2SGordon Ross {
54594047d49SGordon Ross 	smb_node_t *tnode;
546a90cf9f2SGordon Ross 	char *path;
54794047d49SGordon Ross 	int rc;
548a90cf9f2SGordon Ross 
549a90cf9f2SGordon Ross 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
550a90cf9f2SGordon Ross 
551a90cf9f2SGordon Ross 	if (smb_is_stream_name(src_fqi->fq_path.pn_path))
552a90cf9f2SGordon Ross 		return (EINVAL);
553a90cf9f2SGordon Ross 
554a90cf9f2SGordon Ross 	/* Lookup the source node */
555a90cf9f2SGordon Ross 	tnode = sr->tid_tree->t_snode;
556a90cf9f2SGordon Ross 	path = src_fqi->fq_path.pn_path;
557a90cf9f2SGordon Ross 	rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
558a90cf9f2SGordon Ross 	    &src_fqi->fq_dnode, src_fqi->fq_last_comp);
559a90cf9f2SGordon Ross 	if (rc != 0)
560a90cf9f2SGordon Ross 		return (rc);
56194047d49SGordon Ross 	/* hold fq_dnode */
562a90cf9f2SGordon Ross 
563a90cf9f2SGordon Ross 	rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
564a90cf9f2SGordon Ross 	    src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
565a90cf9f2SGordon Ross 	if (rc != 0) {
566a90cf9f2SGordon Ross 		smb_node_release(src_fqi->fq_dnode);
567a90cf9f2SGordon Ross 		return (rc);
568a90cf9f2SGordon Ross 	}
56994047d49SGordon Ross 	/* hold fq_dnode, fq_fnode */
570a90cf9f2SGordon Ross 
57194047d49SGordon Ross 	rc = smb_rename_check_attr(sr, src_fqi->fq_fnode, src_fqi->fq_sattr);
572a90cf9f2SGordon Ross 	if (rc != 0) {
573a90cf9f2SGordon Ross 		smb_node_release(src_fqi->fq_fnode);
574a90cf9f2SGordon Ross 		smb_node_release(src_fqi->fq_dnode);
575a90cf9f2SGordon Ross 		return (rc);
576a90cf9f2SGordon Ross 	}
577a90cf9f2SGordon Ross 
57894047d49SGordon Ross 	return (0);
57994047d49SGordon Ross }
58094047d49SGordon Ross 
58194047d49SGordon Ross /*
58294047d49SGordon Ross  * smb_rename_check_src
58394047d49SGordon Ross  *
58494047d49SGordon Ross  * Check for sharing violations on the file we'll unlink, and
58594047d49SGordon Ross  * break oplocks for the rename operation.  Note that we've
58694047d49SGordon Ross  * already done oplock breaks associated with opening a handle
58794047d49SGordon Ross  * on the file to rename.
58894047d49SGordon Ross  *
58994047d49SGordon Ross  * On success, returns with fnode in a critical section,
59094047d49SGordon Ross  * as if smb_node_start_crit were called with the node.
59194047d49SGordon Ross  * Caller should release using smb_rename_release_src().
59294047d49SGordon Ross  */
59394047d49SGordon Ross static uint32_t
smb_rename_check_src(smb_request_t * sr,smb_fqi_t * src_fqi)59494047d49SGordon Ross smb_rename_check_src(smb_request_t *sr, smb_fqi_t *src_fqi)
59594047d49SGordon Ross {
59694047d49SGordon Ross 	smb_node_t *src_node = src_fqi->fq_fnode;
59794047d49SGordon Ross 	uint32_t status;
59894047d49SGordon Ross 
599a90cf9f2SGordon Ross 	/*
600a90cf9f2SGordon Ross 	 * Break BATCH oplock before ofile checks. If a client
601a90cf9f2SGordon Ross 	 * has a file open, this will force a flush or close,
602a90cf9f2SGordon Ross 	 * which may affect the outcome of any share checking.
60394047d49SGordon Ross 	 *
60494047d49SGordon Ross 	 * This operation may have either a handle or path for
60594047d49SGordon Ross 	 * the source node (that will be unlinked via rename).
606a90cf9f2SGordon Ross 	 */
60794047d49SGordon Ross 
60894047d49SGordon Ross 	if (sr->fid_ofile != NULL) {
60994047d49SGordon Ross 		status = smb_oplock_break_SETINFO(src_node, sr->fid_ofile,
61094047d49SGordon Ross 		    FileRenameInformation);
61194047d49SGordon Ross 		if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
61294047d49SGordon Ross 			if (sr->session->dialect >= SMB_VERS_2_BASE)
61394047d49SGordon Ross 				(void) smb2sr_go_async(sr);
614*525641e8SGordon Ross 			(void) smb_oplock_wait_break(sr, src_node, 0);
61594047d49SGordon Ross 			status = 0;
61694047d49SGordon Ross 		}
61794047d49SGordon Ross 
61894047d49SGordon Ross 		/*
61994047d49SGordon Ross 		 * Sharing violations were checked at open time.
62094047d49SGordon Ross 		 * Just "start crit" to be consistent with the
62194047d49SGordon Ross 		 * state returned for path-based rename.
62294047d49SGordon Ross 		 */
62394047d49SGordon Ross 		smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
62494047d49SGordon Ross 		return (NT_STATUS_SUCCESS);
62594047d49SGordon Ross 	}
626a90cf9f2SGordon Ross 
627a90cf9f2SGordon Ross 	/*
62894047d49SGordon Ross 	 * This code path operates without a real open, so
62994047d49SGordon Ross 	 * break oplocks now as if we opened for delete.
63094047d49SGordon Ross 	 * Note: SMB2 does only ofile-based rename.
63194047d49SGordon Ross 	 *
63294047d49SGordon Ross 	 * Todo:  Use an "internal open" for path-based
63394047d49SGordon Ross 	 * rename and delete, then delete this code.
634a90cf9f2SGordon Ross 	 */
63594047d49SGordon Ross 	ASSERT(sr->session->dialect < SMB_VERS_2_BASE);
63694047d49SGordon Ross 	status = smb_oplock_break_DELETE(src_node, NULL);
63794047d49SGordon Ross 	if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
638*525641e8SGordon Ross 		(void) smb_oplock_wait_break(sr, src_node, 0);
639a90cf9f2SGordon Ross 	}
64094047d49SGordon Ross 
64194047d49SGordon Ross 	/*
64294047d49SGordon Ross 	 * Path-based access to the src file (no ofile)
64394047d49SGordon Ross 	 * so check for sharing violations here.
64494047d49SGordon Ross 	 */
64594047d49SGordon Ross 	smb_node_rdlock(src_node);
64694047d49SGordon Ross 	status = smb_node_rename_check(src_node);
647a90cf9f2SGordon Ross 	if (status != NT_STATUS_SUCCESS) {
648a90cf9f2SGordon Ross 		smb_node_unlock(src_node);
64994047d49SGordon Ross 		return (status);
65094047d49SGordon Ross 	}
65194047d49SGordon Ross 
65294047d49SGordon Ross 	status = smb_oplock_break_SETINFO(src_node, NULL,
65394047d49SGordon Ross 	    FileRenameInformation);
65494047d49SGordon Ross 	if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
655*525641e8SGordon Ross 		(void) smb_oplock_wait_break(sr, src_node, 0);
656a90cf9f2SGordon Ross 	}
657a90cf9f2SGordon Ross 
658a90cf9f2SGordon Ross 	/*
659a90cf9f2SGordon Ross 	 * Note, the combination of these two:
660a90cf9f2SGordon Ross 	 *	smb_node_rdlock(node);
661a90cf9f2SGordon Ross 	 *	nbl_start_crit(node->vp, RW_READER);
662a90cf9f2SGordon Ross 	 * is equivalent to this call:
663a90cf9f2SGordon Ross 	 *	smb_node_start_crit(node, RW_READER)
664a90cf9f2SGordon Ross 	 *
665a90cf9f2SGordon Ross 	 * Cleanup after this point should use:
666a90cf9f2SGordon Ross 	 *	smb_node_end_crit(src_node)
667a90cf9f2SGordon Ross 	 */
668a90cf9f2SGordon Ross 	nbl_start_crit(src_node->vp, RW_READER);
669a90cf9f2SGordon Ross 
670a90cf9f2SGordon Ross 	/*
671a90cf9f2SGordon Ross 	 * This checks nbl_share_conflict, nbl_lock_conflict
672a90cf9f2SGordon Ross 	 */
673a90cf9f2SGordon Ross 	status = smb_nbl_conflict(src_node, 0, UINT64_MAX, NBL_RENAME);
674a90cf9f2SGordon Ross 	if (status != NT_STATUS_SUCCESS) {
675a90cf9f2SGordon Ross 		smb_node_end_crit(src_node);
676a90cf9f2SGordon Ross 	}
677a90cf9f2SGordon Ross 
67894047d49SGordon Ross 	/* NB: Caller expects to be "in crit" on fnode. */
67994047d49SGordon Ross 	return (status);
680a90cf9f2SGordon Ross }
681a90cf9f2SGordon Ross 
682a90cf9f2SGordon Ross /*
683a90cf9f2SGordon Ross  * smb_rename_release_src
684a90cf9f2SGordon Ross  */
685a90cf9f2SGordon Ross static void
smb_rename_release_src(smb_request_t * sr)686a90cf9f2SGordon Ross smb_rename_release_src(smb_request_t *sr)
687a90cf9f2SGordon Ross {
688a90cf9f2SGordon Ross 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
689a90cf9f2SGordon Ross 
690a90cf9f2SGordon Ross 	smb_node_end_crit(src_fqi->fq_fnode);
691a90cf9f2SGordon Ross 	smb_node_release(src_fqi->fq_fnode);
692a90cf9f2SGordon Ross 	smb_node_release(src_fqi->fq_dnode);
693a90cf9f2SGordon Ross }
694a90cf9f2SGordon Ross 
695a90cf9f2SGordon Ross 
696a90cf9f2SGordon Ross static int
smb_rename_check_attr(smb_request_t * sr,smb_node_t * node,uint16_t sattr)697a90cf9f2SGordon Ross smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr)
698a90cf9f2SGordon Ross {
699a90cf9f2SGordon Ross 	smb_attr_t attr;
700a90cf9f2SGordon Ross 
701a90cf9f2SGordon Ross 	bzero(&attr, sizeof (attr));
702a90cf9f2SGordon Ross 	attr.sa_mask = SMB_AT_DOSATTR;
703a90cf9f2SGordon Ross 	if (smb_node_getattr(sr, node, zone_kcred(), NULL, &attr) != 0)
704a90cf9f2SGordon Ross 		return (EACCES);
705a90cf9f2SGordon Ross 
706a90cf9f2SGordon Ross 	if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) &&
707a90cf9f2SGordon Ross 	    !(SMB_SEARCH_HIDDEN(sattr)))
708a90cf9f2SGordon Ross 		return (ESRCH);
709a90cf9f2SGordon Ross 
710a90cf9f2SGordon Ross 	if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) &&
711a90cf9f2SGordon Ross 	    !(SMB_SEARCH_SYSTEM(sattr)))
712a90cf9f2SGordon Ross 		return (ESRCH);
713a90cf9f2SGordon Ross 
714a90cf9f2SGordon Ross 	return (0);
715a90cf9f2SGordon Ross }
716a90cf9f2SGordon Ross 
717a90cf9f2SGordon Ross /*
718a90cf9f2SGordon Ross  * The following values are based on observed WFWG, Windows 9x, Windows NT
719a90cf9f2SGordon Ross  * and Windows 2000 behaviour.
720a90cf9f2SGordon Ross  *
721a90cf9f2SGordon Ross  * ERROR_FILE_EXISTS doesn't work for Windows 98 clients.
722a90cf9f2SGordon Ross  *
723a90cf9f2SGordon Ross  * Windows 95 clients don't see the problem because the target is deleted
724a90cf9f2SGordon Ross  * before the rename request.
725a90cf9f2SGordon Ross  */
726a90cf9f2SGordon Ross static uint32_t
smb_rename_errno2status(int errnum)727a90cf9f2SGordon Ross smb_rename_errno2status(int errnum)
728a90cf9f2SGordon Ross {
729a90cf9f2SGordon Ross 	static struct {
730a90cf9f2SGordon Ross 		int errnum;
731a90cf9f2SGordon Ross 		uint32_t status32;
732a90cf9f2SGordon Ross 	} rc_map[] = {
733a90cf9f2SGordon Ross 	{ EEXIST, NT_STATUS_OBJECT_NAME_COLLISION },
734a90cf9f2SGordon Ross 	{ EPIPE,  NT_STATUS_SHARING_VIOLATION },
735a90cf9f2SGordon Ross 	{ ENOENT, NT_STATUS_OBJECT_NAME_NOT_FOUND },
736a90cf9f2SGordon Ross 	{ ESRCH,  NT_STATUS_NO_SUCH_FILE },
737a90cf9f2SGordon Ross 	{ EINVAL, NT_STATUS_INVALID_PARAMETER },
738a90cf9f2SGordon Ross 	{ EACCES, NT_STATUS_ACCESS_DENIED },
739a90cf9f2SGordon Ross 	{ EISDIR, NT_STATUS_FILE_IS_A_DIRECTORY },
740a90cf9f2SGordon Ross 	{ EIO,    NT_STATUS_INTERNAL_ERROR }
741a90cf9f2SGordon Ross 	};
742a90cf9f2SGordon Ross 
743a90cf9f2SGordon Ross 	int i;
744a90cf9f2SGordon Ross 
745a90cf9f2SGordon Ross 	if (errnum == 0)
746a90cf9f2SGordon Ross 		return (0);
747a90cf9f2SGordon Ross 
748a90cf9f2SGordon Ross 	for (i = 0; i < sizeof (rc_map)/sizeof (rc_map[0]); ++i) {
749a90cf9f2SGordon Ross 		if (rc_map[i].errnum == errnum) {
750a90cf9f2SGordon Ross 			return (rc_map[i].status32);
751a90cf9f2SGordon Ross 		}
752a90cf9f2SGordon Ross 	}
753a90cf9f2SGordon Ross 
754a90cf9f2SGordon Ross 	return (smb_errno2status(errnum));
755a90cf9f2SGordon Ross }
756