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