xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_rename.c (revision eb1d736b1c19f6abeee90c921a9320b67fedd016)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
222c2961f8Sjose borrego  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #include <smbsrv/nterror.h>
27da6c28aaSamw #include <sys/synch.h>
28da6c28aaSamw #include <smbsrv/smb_incl.h>
29da6c28aaSamw #include <smbsrv/smb_fsops.h>
30dc20a302Sas200622 #include <sys/nbmlock.h>
31da6c28aaSamw 
32b89a8333Snatalie li - Sun Microsystems - Irvine United States static int smb_do_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *);
33da6c28aaSamw 
34da6c28aaSamw /*
35da6c28aaSamw  * smb_com_rename
36da6c28aaSamw  *
37da6c28aaSamw  * Rename a file. Files OldFileName must exist and NewFileName must not.
38da6c28aaSamw  * Both pathnames must be relative to the Tid specified in the request.
39da6c28aaSamw  * Open files may be renamed.
40da6c28aaSamw  *
41da6c28aaSamw  * Multiple files may be renamed in response to a single request as Rename
42da6c28aaSamw  * File supports wildcards in the file name (last component of the path).
43da6c28aaSamw  * NOTE: we don't support rename with wildcards.
44da6c28aaSamw  *
45da6c28aaSamw  * SearchAttributes indicates the attributes that the target file(s) must
46da6c28aaSamw  * have. If SearchAttributes is zero then only normal files are renamed.
47da6c28aaSamw  * If the system file or hidden attributes are specified then the rename
48da6c28aaSamw  * is inclusive - both the specified type(s) of files and normal files are
49da6c28aaSamw  * renamed. The encoding of SearchAttributes is described in section 3.10
50da6c28aaSamw  * - File Attribute Encoding.
51da6c28aaSamw  */
527b59d02dSjb150015 smb_sdrc_t
53faa1795aSjb150015 smb_pre_rename(smb_request_t *sr)
54faa1795aSjb150015 {
55b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
56b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
57faa1795aSjb150015 	int rc;
58faa1795aSjb150015 
59*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if ((rc = smbsr_decode_vwv(sr, "w", &src_fqi->fq_sattr)) == 0) {
60*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->fq_path.pn_path,
61*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		    &dst_fqi->fq_path.pn_path);
62faa1795aSjb150015 
63*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		dst_fqi->fq_sattr = 0;
64faa1795aSjb150015 	}
65faa1795aSjb150015 
66faa1795aSjb150015 	DTRACE_SMB_2(op__Rename__start, smb_request_t *, sr,
67faa1795aSjb150015 	    struct dirop *, &sr->arg.dirop);
68faa1795aSjb150015 
69faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
70faa1795aSjb150015 }
71faa1795aSjb150015 
72faa1795aSjb150015 void
73faa1795aSjb150015 smb_post_rename(smb_request_t *sr)
74faa1795aSjb150015 {
75faa1795aSjb150015 	DTRACE_SMB_1(op__Rename__done, smb_request_t *, sr);
76faa1795aSjb150015 }
77faa1795aSjb150015 
78faa1795aSjb150015 smb_sdrc_t
79faa1795aSjb150015 smb_com_rename(smb_request_t *sr)
80da6c28aaSamw {
81da6c28aaSamw 	static kmutex_t mutex;
82b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
83b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
84da6c28aaSamw 	struct smb_node *dst_node;
85da6c28aaSamw 	int rc;
86da6c28aaSamw 
87da6c28aaSamw 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
88dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
89da6c28aaSamw 		    ERRDOS, ERROR_ACCESS_DENIED);
90faa1795aSjb150015 		return (SDRC_ERROR);
91da6c28aaSamw 	}
92da6c28aaSamw 
93da6c28aaSamw 	mutex_enter(&mutex);
94da6c28aaSamw 	rc = smb_do_rename(sr, src_fqi, dst_fqi);
95da6c28aaSamw 	mutex_exit(&mutex);
96da6c28aaSamw 
97da6c28aaSamw 	if (rc != 0) {
98da6c28aaSamw 		/*
99faa1795aSjb150015 		 * The following values are based on observed WFWG,
100faa1795aSjb150015 		 * Windows 9x, NT and Windows 2000 behaviour.
101da6c28aaSamw 		 * ERROR_FILE_EXISTS doesn't work for Windows 98 clients.
102faa1795aSjb150015 		 * Windows 95 clients don't see the problem because the
103faa1795aSjb150015 		 * target is deleted before the rename request.
104da6c28aaSamw 		 */
105faa1795aSjb150015 		switch (rc) {
106faa1795aSjb150015 		case EEXIST:
107dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
108da6c28aaSamw 			    ERRDOS, ERROR_ALREADY_EXISTS);
109faa1795aSjb150015 			break;
110faa1795aSjb150015 		case EPIPE:
111dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_SHARING_VIOLATION,
112da6c28aaSamw 			    ERRDOS, ERROR_SHARING_VIOLATION);
113faa1795aSjb150015 			break;
114faa1795aSjb150015 		case ENOENT:
115faa1795aSjb150015 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
116faa1795aSjb150015 			    ERRDOS, ERROR_FILE_NOT_FOUND);
117faa1795aSjb150015 			break;
118faa1795aSjb150015 		default:
119faa1795aSjb150015 			smbsr_errno(sr, rc);
120faa1795aSjb150015 			break;
121da6c28aaSamw 		}
122da6c28aaSamw 
123faa1795aSjb150015 		return (SDRC_ERROR);
124da6c28aaSamw 	}
125da6c28aaSamw 
126*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (src_fqi->fq_dnode)
127*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_node_release(src_fqi->fq_dnode);
128da6c28aaSamw 
129*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	dst_node = dst_fqi->fq_dnode;
130da6c28aaSamw 	if (dst_node) {
131da6c28aaSamw 		if (dst_node->flags & NODE_FLAGS_NOTIFY_CHANGE) {
132da6c28aaSamw 			dst_node->flags |= NODE_FLAGS_CHANGED;
133da6c28aaSamw 			smb_process_node_notify_change_queue(dst_node);
134da6c28aaSamw 		}
135da6c28aaSamw 		smb_node_release(dst_node);
136da6c28aaSamw 	}
137da6c28aaSamw 
138da6c28aaSamw 	SMB_NULL_FQI_NODES(*src_fqi);
139da6c28aaSamw 	SMB_NULL_FQI_NODES(*dst_fqi);
140da6c28aaSamw 
1417b59d02dSjb150015 	rc = smbsr_encode_empty_result(sr);
142faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
143da6c28aaSamw }
144da6c28aaSamw 
145da6c28aaSamw /*
146da6c28aaSamw  * smb_do_rename
147da6c28aaSamw  *
148da6c28aaSamw  * Backend to smb_com_rename to ensure that the rename operation is atomic.
149da6c28aaSamw  * This function should be called within a mutual exclusion region. If the
150da6c28aaSamw  * source and destination are identical, we don't actually do a rename, we
151da6c28aaSamw  * just check that the conditions are right. If the source and destination
152da6c28aaSamw  * files differ only in case, we a case-sensitive rename. Otherwise, we do
153da6c28aaSamw  * a full case-insensitive rename.
154da6c28aaSamw  *
155da6c28aaSamw  * This function should always return errno values.
156da6c28aaSamw  *
157da6c28aaSamw  * Upon success, the last_snode's and dir_snode's of both src_fqi and dst_fqi
158da6c28aaSamw  * are not released in this routine but in smb_com_rename().
159da6c28aaSamw  */
160da6c28aaSamw static int
161da6c28aaSamw smb_do_rename(
162faa1795aSjb150015     smb_request_t *sr,
163b89a8333Snatalie li - Sun Microsystems - Irvine United States     smb_fqi_t *src_fqi,
164b89a8333Snatalie li - Sun Microsystems - Irvine United States     smb_fqi_t *dst_fqi)
165da6c28aaSamw {
166b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_node_t *src_node;
167da6c28aaSamw 	char *dstname;
168da6c28aaSamw 	DWORD status;
169da6c28aaSamw 	int rc;
170da6c28aaSamw 	int count;
171da6c28aaSamw 
172da6c28aaSamw 	if ((rc = smbd_fs_query(sr, src_fqi, FQM_PATH_MUST_EXIST)) != 0) {
173da6c28aaSamw 		return (rc);
174da6c28aaSamw 	}
175da6c28aaSamw 
176*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	src_node = src_fqi->fq_fnode;
177da6c28aaSamw 
178da6c28aaSamw 	/*
179da6c28aaSamw 	 * Break the oplock before access checks. If a client
180da6c28aaSamw 	 * has a file open, this will force a flush or close,
181da6c28aaSamw 	 * which may affect the outcome of any share checking.
182da6c28aaSamw 	 */
183fc724630SAlan Wright 	(void) smb_oplock_break(src_node, sr->session, B_FALSE);
184da6c28aaSamw 
185dc20a302Sas200622 	for (count = 0; count <= 3; count++) {
186dc20a302Sas200622 		if (count) {
187dc20a302Sas200622 			smb_node_end_crit(src_node);
188dc20a302Sas200622 			delay(MSEC_TO_TICK(400));
189dc20a302Sas200622 		}
190dc20a302Sas200622 
191dc20a302Sas200622 		smb_node_start_crit(src_node, RW_READER);
192dc20a302Sas200622 
193dc20a302Sas200622 		status = smb_node_rename_check(src_node);
194dc20a302Sas200622 
195dc20a302Sas200622 		if (status != NT_STATUS_SHARING_VIOLATION)
196dc20a302Sas200622 			break;
197dc20a302Sas200622 	}
198dc20a302Sas200622 
199dc20a302Sas200622 	if (status == NT_STATUS_SHARING_VIOLATION) {
200dc20a302Sas200622 		smb_node_end_crit(src_node);
201dc20a302Sas200622 
202dc20a302Sas200622 		smb_node_release(src_node);
203*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_node_release(src_fqi->fq_dnode);
204dc20a302Sas200622 
205dc20a302Sas200622 		SMB_NULL_FQI_NODES(*src_fqi);
206dc20a302Sas200622 		SMB_NULL_FQI_NODES(*dst_fqi);
207dc20a302Sas200622 		return (EPIPE); /* = ERRbadshare */
208dc20a302Sas200622 	}
209dc20a302Sas200622 
210c8ec8eeaSjose borrego 	status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE);
211dc20a302Sas200622 
212da6c28aaSamw 	if (status != NT_STATUS_SUCCESS) {
213dc20a302Sas200622 		smb_node_end_crit(src_node);
214dc20a302Sas200622 
215da6c28aaSamw 		smb_node_release(src_node);
216*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_node_release(src_fqi->fq_dnode);
217da6c28aaSamw 
218da6c28aaSamw 		SMB_NULL_FQI_NODES(*src_fqi);
219da6c28aaSamw 		SMB_NULL_FQI_NODES(*dst_fqi);
220da6c28aaSamw 		return (EACCES);
221da6c28aaSamw 	}
222da6c28aaSamw 
223*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (utf8_strcasecmp(src_fqi->fq_path.pn_path,
224*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	    dst_fqi->fq_path.pn_path) == 0) {
225da6c28aaSamw 		if ((rc = smbd_fs_query(sr, dst_fqi, 0)) != 0) {
226dc20a302Sas200622 			smb_node_end_crit(src_node);
227dc20a302Sas200622 
228dc20a302Sas200622 			smb_node_release(src_node);
229*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_node_release(src_fqi->fq_dnode);
230da6c28aaSamw 
231da6c28aaSamw 			SMB_NULL_FQI_NODES(*src_fqi);
232da6c28aaSamw 			SMB_NULL_FQI_NODES(*dst_fqi);
233da6c28aaSamw 			return (rc);
234da6c28aaSamw 		}
235da6c28aaSamw 
236da6c28aaSamw 		/*
237da6c28aaSamw 		 * Because the fqm parameter to smbd_fs_query() was 0,
238*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		 * a successful return value means that dst_fqi->fq_fnode
239da6c28aaSamw 		 * may be NULL.
240da6c28aaSamw 		 */
241*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		if (dst_fqi->fq_fnode)
242*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_node_release(dst_fqi->fq_fnode);
243da6c28aaSamw 
244*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		rc = strcmp(src_fqi->fq_od_name, dst_fqi->fq_last_comp);
245da6c28aaSamw 		if (rc == 0) {
246dc20a302Sas200622 			smb_node_end_crit(src_node);
247dc20a302Sas200622 
248dc20a302Sas200622 			smb_node_release(src_node);
249*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_node_release(src_fqi->fq_dnode);
250*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_node_release(dst_fqi->fq_dnode);
251da6c28aaSamw 
252da6c28aaSamw 			SMB_NULL_FQI_NODES(*src_fqi);
253da6c28aaSamw 			SMB_NULL_FQI_NODES(*dst_fqi);
254da6c28aaSamw 			return (0);
255da6c28aaSamw 		}
256da6c28aaSamw 
257da6c28aaSamw 		rc = smb_fsop_rename(sr, sr->user_cr,
258*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		    src_fqi->fq_dnode,
259*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		    src_fqi->fq_od_name,
260*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		    dst_fqi->fq_dnode,
261*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		    dst_fqi->fq_last_comp);
262da6c28aaSamw 
263da6c28aaSamw 		if (rc != 0) {
264*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_node_release(src_fqi->fq_dnode);
265*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 			smb_node_release(dst_fqi->fq_dnode);
266da6c28aaSamw 
267da6c28aaSamw 			SMB_NULL_FQI_NODES(*src_fqi);
268da6c28aaSamw 			SMB_NULL_FQI_NODES(*dst_fqi);
269da6c28aaSamw 		}
270dc20a302Sas200622 
271dc20a302Sas200622 		smb_node_end_crit(src_node);
272dc20a302Sas200622 
273dc20a302Sas200622 		smb_node_release(src_node);
274da6c28aaSamw 		return (rc);
275da6c28aaSamw 	}
276da6c28aaSamw 
277da6c28aaSamw 	rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST);
278da6c28aaSamw 	if (rc != 0) {
279dc20a302Sas200622 		smb_node_end_crit(src_node);
280dc20a302Sas200622 
281dc20a302Sas200622 		smb_node_release(src_node);
282*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_node_release(src_fqi->fq_dnode);
283da6c28aaSamw 
284da6c28aaSamw 		SMB_NULL_FQI_NODES(*src_fqi);
285da6c28aaSamw 		SMB_NULL_FQI_NODES(*dst_fqi);
286da6c28aaSamw 		return (rc);
287da6c28aaSamw 	}
288da6c28aaSamw 
289da6c28aaSamw 	/*
290da6c28aaSamw 	 * Because of FQM_PATH_MUST_NOT_EXIST and the successful return
291*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	 * value, only dst_fqi->fq_dnode is valid (dst_fqi->fq_fnode
292da6c28aaSamw 	 * is NULL).
293da6c28aaSamw 	 */
294da6c28aaSamw 
295da6c28aaSamw 	/*
296da6c28aaSamw 	 * Use the unmangled form of the destination name if the
297da6c28aaSamw 	 * source and destination names are the same and the source
298da6c28aaSamw 	 * name is mangled.  (We are taking a chance here, assuming
299da6c28aaSamw 	 * that this is what the user wants.)
300da6c28aaSamw 	 */
301da6c28aaSamw 
302*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if ((smb_maybe_mangled_name(src_fqi->fq_last_comp)) &&
303*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	    (strcmp(src_fqi->fq_last_comp, dst_fqi->fq_last_comp) == 0)) {
304*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		dstname = src_fqi->fq_od_name;
305da6c28aaSamw 	} else {
306*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		dstname = dst_fqi->fq_last_comp;
307da6c28aaSamw 	}
308da6c28aaSamw 
309da6c28aaSamw 	rc = smb_fsop_rename(sr, sr->user_cr,
310*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	    src_fqi->fq_dnode,
311*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	    src_fqi->fq_od_name,
312*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	    dst_fqi->fq_dnode,
313da6c28aaSamw 	    dstname);
314da6c28aaSamw 
315da6c28aaSamw 	if (rc != 0) {
316*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_node_release(src_fqi->fq_dnode);
317*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_node_release(dst_fqi->fq_dnode);
318da6c28aaSamw 
319da6c28aaSamw 		SMB_NULL_FQI_NODES(*src_fqi);
320da6c28aaSamw 		SMB_NULL_FQI_NODES(*dst_fqi);
321da6c28aaSamw 	}
322da6c28aaSamw 
323dc20a302Sas200622 	smb_node_end_crit(src_node);
324dc20a302Sas200622 
325dc20a302Sas200622 	smb_node_release(src_node);
326dc20a302Sas200622 
327da6c28aaSamw 	return (rc);
328da6c28aaSamw }
329