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