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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 #include <sys/synch.h>
27 #include <smbsrv/smb_kproto.h>
28 #include <smbsrv/smb_fsops.h>
29 #include <sys/nbmlock.h>
30
31 /*
32 * SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag
33 */
34 #define SMB_RENAME_FLAG_OVERWRITE 0x001
35
36 static int smb_rename_check_stream(smb_fqi_t *, smb_fqi_t *);
37 static int smb_rename_check_attr(smb_request_t *, smb_node_t *, uint16_t);
38 static int smb_rename_lookup_src(smb_request_t *);
39 static void smb_rename_release_src(smb_request_t *);
40 static uint32_t smb_rename_errno2status(int);
41
42 /*
43 * smb_setinfo_rename
44 *
45 * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo
46 * and Trans2_Set_PathInfo and SMB2 set_info, FileRenameInformation.
47 * If the new filename (dst_fqi) already exists it may be overwritten
48 * if flags == 1.
49 *
50 * The passed path is a full path relative to the share root.
51 *
52 * Returns NT status codes.
53 *
54 * Similar to smb_setinfo_link(), below.
55 */
56 uint32_t
57 smb_setinfo_rename(smb_request_t *sr, smb_node_t *node, char *path, int flags)
58 {
82 *
83 * Common code for renaming a file.
84 *
85 * If the source and destination are identical, we go through all
86 * the checks but we don't actually do the rename. If the source
87 * and destination files differ only in case, we do a case-sensitive
88 * rename. Otherwise, we do a full case-insensitive rename.
89 *
90 * Returns NT status values.
91 *
92 * Similar to smb_make_link(), below.
93 */
94 uint32_t
95 smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
96 {
97 smb_node_t *src_fnode, *src_dnode, *dst_dnode;
98 smb_node_t *dst_fnode = 0;
99 smb_node_t *tnode;
100 char *new_name, *path;
101 DWORD status;
102 int rc, count;
103
104 tnode = sr->tid_tree->t_snode;
105 path = dst_fqi->fq_path.pn_path;
106
107 /* Check if attempting to rename a stream - not yet supported */
108 rc = smb_rename_check_stream(src_fqi, dst_fqi);
109 if (rc != 0)
110 return (smb_rename_errno2status(rc));
111
112 /*
113 * The source node may already have been provided,
114 * i.e. when called by SMB1/SMB2 smb_setinfo_rename.
115 * Not provided by smb_com_rename, smb_com_nt_rename.
116 */
117 if (src_fqi->fq_fnode) {
118 smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
119 smb_node_ref(src_fqi->fq_fnode);
120 smb_node_ref(src_fqi->fq_dnode);
121 } else {
122 /* lookup and validate src node */
123 rc = smb_rename_lookup_src(sr);
124 if (rc != 0)
125 return (smb_rename_errno2status(rc));
126 }
127
128 src_fnode = src_fqi->fq_fnode;
129 src_dnode = src_fqi->fq_dnode;
130
131 /*
132 * Find the destination dnode and last component.
133 * May already be provided, i.e. when called via
134 * SMB1 trans2 setinfo.
135 */
136 if (dst_fqi->fq_dnode) {
137 /* called via smb_set_rename_info */
138 smb_node_ref(dst_fqi->fq_dnode);
139 } else {
140 /* called via smb2_setf_rename, smb_com_rename, etc. */
141 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
142 &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
143 if (rc != 0) {
144 smb_rename_release_src(sr);
145 return (smb_rename_errno2status(rc));
146 }
147 }
148
149 dst_dnode = dst_fqi->fq_dnode;
150 new_name = dst_fqi->fq_last_comp;
151
217
218 if ((rc != 0) && (rc != ENOENT)) {
219 smb_rename_release_src(sr);
220 smb_node_release(dst_fqi->fq_dnode);
221 return (smb_rename_errno2status(rc));
222 }
223
224 if (dst_fqi->fq_fnode) {
225 /*
226 * Destination already exists. Do delete checks.
227 */
228 dst_fnode = dst_fqi->fq_fnode;
229
230 if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) {
231 smb_rename_release_src(sr);
232 smb_node_release(dst_fnode);
233 smb_node_release(dst_dnode);
234 return (NT_STATUS_OBJECT_NAME_COLLISION);
235 }
236
237 (void) smb_oplock_break(sr, dst_fnode,
238 SMB_OPLOCK_BREAK_TO_NONE | SMB_OPLOCK_BREAK_BATCH);
239
240 /*
241 * Wait (a little) for the oplock break to be
242 * responded to by clients closing handles.
243 * Hold node->n_lock as reader to keep new
244 * ofiles from showing up after we check.
245 */
246 smb_node_rdlock(dst_fnode);
247 for (count = 0; count <= 12; count++) {
248 status = smb_node_delete_check(dst_fnode);
249 if (status != NT_STATUS_SHARING_VIOLATION)
250 break;
251 smb_node_unlock(dst_fnode);
252 delay(MSEC_TO_TICK(100));
253 smb_node_rdlock(dst_fnode);
254 }
255 if (status != NT_STATUS_SUCCESS) {
256 smb_node_unlock(dst_fnode);
257 smb_rename_release_src(sr);
258 smb_node_release(dst_fnode);
259 smb_node_release(dst_dnode);
260 return (NT_STATUS_ACCESS_DENIED);
261 }
262
263 /*
264 * Note, the combination of these two:
265 * smb_node_rdlock(node);
266 * nbl_start_crit(node->vp, RW_READER);
267 * is equivalent to this call:
268 * smb_node_start_crit(node, RW_READER)
269 *
270 * Cleanup after this point should use:
271 * smb_node_end_crit(dst_fnode)
272 */
273 nbl_start_crit(dst_fnode->vp, RW_READER);
274
275 /*
276 * This checks nbl_share_conflict, nbl_lock_conflict
277 */
278 status = smb_nbl_conflict(dst_fnode, 0, UINT64_MAX, NBL_REMOVE);
279 if (status != NT_STATUS_SUCCESS) {
280 smb_node_end_crit(dst_fnode);
281 smb_rename_release_src(sr);
282 smb_node_release(dst_fnode);
283 smb_node_release(dst_dnode);
284 return (NT_STATUS_ACCESS_DENIED);
285 }
286
287 new_name = dst_fnode->od_name;
288 }
289
290 rc = smb_fsop_rename(sr, sr->user_cr,
291 src_dnode, src_fnode->od_name,
292 dst_dnode, new_name);
293
294 if (rc == 0) {
295 /*
296 * Note that renames in the same directory are normally
297 * delivered in {old,new} pairs, and clients expect them
298 * in that order, if both events are delivered.
299 */
300 int a_src, a_dst; /* action codes */
301 if (src_dnode == dst_dnode) {
302 a_src = FILE_ACTION_RENAMED_OLD_NAME;
303 a_dst = FILE_ACTION_RENAMED_NEW_NAME;
304 } else {
305 a_src = FILE_ACTION_REMOVED;
306 a_dst = FILE_ACTION_ADDED;
307 }
308 smb_node_notify_change(src_dnode, a_src, src_fnode->od_name);
309 smb_node_notify_change(dst_dnode, a_dst, new_name);
310 }
311
312 smb_rename_release_src(sr);
313
417 * Similar to smb_common_rename() above.
418 */
419 uint32_t
420 smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
421 {
422 smb_node_t *tnode;
423 char *path;
424 int rc;
425
426 tnode = sr->tid_tree->t_snode;
427 path = dst_fqi->fq_path.pn_path;
428
429 /* Cannnot create link on named stream */
430 if (smb_is_stream_name(src_fqi->fq_path.pn_path) ||
431 smb_is_stream_name(dst_fqi->fq_path.pn_path)) {
432 return (NT_STATUS_INVALID_PARAMETER);
433 }
434
435 /* The source node may already have been provided */
436 if (src_fqi->fq_fnode) {
437 smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
438 smb_node_ref(src_fqi->fq_fnode);
439 smb_node_ref(src_fqi->fq_dnode);
440 } else {
441 /* lookup and validate src node */
442 rc = smb_rename_lookup_src(sr);
443 if (rc != 0)
444 return (smb_rename_errno2status(rc));
445 }
446
447 /* Not valid to create hardlink for directory */
448 if (smb_node_is_dir(src_fqi->fq_fnode)) {
449 smb_rename_release_src(sr);
450 return (NT_STATUS_FILE_IS_A_DIRECTORY);
451 }
452
453 /*
454 * Find the destination dnode and last component.
455 * May already be provided, i.e. when called via
456 * SMB1 trans2 setinfo.
457 */
458 if (dst_fqi->fq_dnode) {
459 smb_node_ref(dst_fqi->fq_dnode);
460 } else {
461 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
462 &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
463 if (rc != 0) {
464 smb_rename_release_src(sr);
465 return (smb_rename_errno2status(rc));
466 }
467 }
468
469 /* If CI name match in same directory, we're done */
470 if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) &&
471 (smb_strcasecmp(src_fqi->fq_fnode->od_name,
472 dst_fqi->fq_last_comp, 0) == 0)) {
473 smb_rename_release_src(sr);
493 smb_node_release(dst_fqi->fq_dnode);
494 return (smb_rename_errno2status(rc));
495 }
496
497 rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode,
498 dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
499
500 if (rc == 0) {
501 smb_node_notify_change(dst_fqi->fq_dnode,
502 FILE_ACTION_ADDED, dst_fqi->fq_last_comp);
503 }
504
505 smb_rename_release_src(sr);
506 smb_node_release(dst_fqi->fq_dnode);
507 return (smb_rename_errno2status(rc));
508 }
509
510 /*
511 * smb_rename_lookup_src
512 *
513 * Lookup the src node, checking for sharing violations and
514 * breaking any existing BATCH oplock.
515 * Populate sr->arg.dirop.fqi
516 *
517 * Upon success, the dnode and fnode will have holds and the
518 * fnode will be in a critical section. These should be
519 * released using smb_rename_release_src().
520 *
521 * Returns errno values.
522 */
523 static int
524 smb_rename_lookup_src(smb_request_t *sr)
525 {
526 smb_node_t *src_node, *tnode;
527 DWORD status;
528 int rc;
529 int count;
530 char *path;
531
532 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
533
534 if (smb_is_stream_name(src_fqi->fq_path.pn_path))
535 return (EINVAL);
536
537 /* Lookup the source node */
538 tnode = sr->tid_tree->t_snode;
539 path = src_fqi->fq_path.pn_path;
540 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
541 &src_fqi->fq_dnode, src_fqi->fq_last_comp);
542 if (rc != 0)
543 return (rc);
544
545 rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
546 src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
547 if (rc != 0) {
548 smb_node_release(src_fqi->fq_dnode);
549 return (rc);
550 }
551 src_node = src_fqi->fq_fnode;
552
553 rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr);
554 if (rc != 0) {
555 smb_node_release(src_fqi->fq_fnode);
556 smb_node_release(src_fqi->fq_dnode);
557 return (rc);
558 }
559
560 /*
561 * Break BATCH oplock before ofile checks. If a client
562 * has a file open, this will force a flush or close,
563 * which may affect the outcome of any share checking.
564 */
565 (void) smb_oplock_break(sr, src_node,
566 SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH);
567
568 /*
569 * Wait (a little) for the oplock break to be
570 * responded to by clients closing handles.
571 * Hold node->n_lock as reader to keep new
572 * ofiles from showing up after we check.
573 */
574 smb_node_rdlock(src_node);
575 for (count = 0; count <= 12; count++) {
576 status = smb_node_rename_check(src_node);
577 if (status != NT_STATUS_SHARING_VIOLATION)
578 break;
579 smb_node_unlock(src_node);
580 delay(MSEC_TO_TICK(100));
581 smb_node_rdlock(src_node);
582 }
583 if (status != NT_STATUS_SUCCESS) {
584 smb_node_unlock(src_node);
585 smb_node_release(src_fqi->fq_fnode);
586 smb_node_release(src_fqi->fq_dnode);
587 return (EPIPE); /* = ERRbadshare */
588 }
589
590 /*
591 * Note, the combination of these two:
592 * smb_node_rdlock(node);
593 * nbl_start_crit(node->vp, RW_READER);
594 * is equivalent to this call:
595 * smb_node_start_crit(node, RW_READER)
596 *
597 * Cleanup after this point should use:
598 * smb_node_end_crit(src_node)
599 */
600 nbl_start_crit(src_node->vp, RW_READER);
601
602 /*
603 * This checks nbl_share_conflict, nbl_lock_conflict
604 */
605 status = smb_nbl_conflict(src_node, 0, UINT64_MAX, NBL_RENAME);
606 if (status != NT_STATUS_SUCCESS) {
607 smb_node_end_crit(src_node);
608 smb_node_release(src_fqi->fq_fnode);
609 smb_node_release(src_fqi->fq_dnode);
610 if (status == NT_STATUS_SHARING_VIOLATION)
611 return (EPIPE); /* = ERRbadshare */
612 return (EACCES);
613 }
614
615 /* NB: Caller expects holds on src_fqi fnode, dnode */
616 return (0);
617 }
618
619 /*
620 * smb_rename_release_src
621 */
622 static void
623 smb_rename_release_src(smb_request_t *sr)
624 {
625 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
626
627 smb_node_end_crit(src_fqi->fq_fnode);
628 smb_node_release(src_fqi->fq_fnode);
629 smb_node_release(src_fqi->fq_dnode);
630 }
631
632
633 static int
634 smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr)
635 {
636 smb_attr_t attr;
|
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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 #include <sys/synch.h>
27 #include <smbsrv/smb2_kproto.h>
28 #include <smbsrv/smb_fsops.h>
29 #include <sys/nbmlock.h>
30
31 /*
32 * SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag
33 */
34 #define SMB_RENAME_FLAG_OVERWRITE 0x001
35
36 static int smb_rename_check_stream(smb_fqi_t *, smb_fqi_t *);
37 static int smb_rename_check_attr(smb_request_t *, smb_node_t *, uint16_t);
38 static int smb_rename_lookup_src(smb_request_t *);
39 static uint32_t smb_rename_check_src(smb_request_t *, smb_fqi_t *);
40 static void smb_rename_release_src(smb_request_t *);
41 static uint32_t smb_rename_errno2status(int);
42
43 /*
44 * smb_setinfo_rename
45 *
46 * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo
47 * and Trans2_Set_PathInfo and SMB2 set_info, FileRenameInformation.
48 * If the new filename (dst_fqi) already exists it may be overwritten
49 * if flags == 1.
50 *
51 * The passed path is a full path relative to the share root.
52 *
53 * Returns NT status codes.
54 *
55 * Similar to smb_setinfo_link(), below.
56 */
57 uint32_t
58 smb_setinfo_rename(smb_request_t *sr, smb_node_t *node, char *path, int flags)
59 {
83 *
84 * Common code for renaming a file.
85 *
86 * If the source and destination are identical, we go through all
87 * the checks but we don't actually do the rename. If the source
88 * and destination files differ only in case, we do a case-sensitive
89 * rename. Otherwise, we do a full case-insensitive rename.
90 *
91 * Returns NT status values.
92 *
93 * Similar to smb_make_link(), below.
94 */
95 uint32_t
96 smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
97 {
98 smb_node_t *src_fnode, *src_dnode, *dst_dnode;
99 smb_node_t *dst_fnode = 0;
100 smb_node_t *tnode;
101 char *new_name, *path;
102 DWORD status;
103 int rc;
104 boolean_t have_src = B_FALSE;
105 boolean_t dst_exists = B_FALSE;
106 boolean_t do_audit;
107 char *srcpath = NULL;
108 char *dstpath = NULL;
109
110 tnode = sr->tid_tree->t_snode;
111 path = dst_fqi->fq_path.pn_path;
112
113 /* Check if attempting to rename a stream - not yet supported */
114 rc = smb_rename_check_stream(src_fqi, dst_fqi);
115 if (rc != 0)
116 return (smb_rename_errno2status(rc));
117
118 /*
119 * The source node may already have been provided,
120 * i.e. when called by SMB1/SMB2 smb_setinfo_rename
121 * with an ofile. When we have an ofile, open has
122 * already checked for sharing violations. For
123 * path-based operations, do sharing check here.
124 */
125 if (src_fqi->fq_fnode) {
126 smb_node_ref(src_fqi->fq_dnode);
127 smb_node_ref(src_fqi->fq_fnode);
128 have_src = B_TRUE;
129 } else {
130 /* lookup and validate src node */
131 rc = smb_rename_lookup_src(sr);
132 if (rc != 0)
133 return (smb_rename_errno2status(rc));
134 /* Holding refs on dnode, fnode */
135 }
136 src_fnode = src_fqi->fq_fnode;
137 src_dnode = src_fqi->fq_dnode;
138
139 /* Break oplocks, and check share modes. */
140 status = smb_rename_check_src(sr, src_fqi);
141 if (status != NT_STATUS_SUCCESS) {
142 smb_node_release(src_fqi->fq_fnode);
143 smb_node_release(src_fqi->fq_dnode);
144 return (status);
145 }
146 /*
147 * NB: src_fnode is now "in crit" (critical section)
148 * as if we did smb_node_start_crit(..., RW_READER);
149 * Call smb_rename_release_src(sr) on errors.
150 */
151
152 /*
153 * Find the destination dnode and last component.
154 * May already be provided, i.e. when called via
155 * SMB1 trans2 setinfo.
156 */
157 if (dst_fqi->fq_dnode) {
158 /* called via smb_set_rename_info */
159 smb_node_ref(dst_fqi->fq_dnode);
160 } else {
161 /* called via smb2_setf_rename, smb_com_rename, etc. */
162 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
163 &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
164 if (rc != 0) {
165 smb_rename_release_src(sr);
166 return (smb_rename_errno2status(rc));
167 }
168 }
169
170 dst_dnode = dst_fqi->fq_dnode;
171 new_name = dst_fqi->fq_last_comp;
172
238
239 if ((rc != 0) && (rc != ENOENT)) {
240 smb_rename_release_src(sr);
241 smb_node_release(dst_fqi->fq_dnode);
242 return (smb_rename_errno2status(rc));
243 }
244
245 if (dst_fqi->fq_fnode) {
246 /*
247 * Destination already exists. Do delete checks.
248 */
249 dst_fnode = dst_fqi->fq_fnode;
250
251 if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) {
252 smb_rename_release_src(sr);
253 smb_node_release(dst_fnode);
254 smb_node_release(dst_dnode);
255 return (NT_STATUS_OBJECT_NAME_COLLISION);
256 }
257
258 status = smb_oplock_break_DELETE(dst_fnode, NULL);
259 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
260 if (sr->session->dialect >= SMB_VERS_2_BASE)
261 (void) smb2sr_go_async(sr);
262 (void) smb_oplock_wait_break(dst_fnode, 0);
263 status = 0;
264 }
265 if (status != 0) {
266 smb_rename_release_src(sr);
267 smb_node_release(dst_fnode);
268 smb_node_release(dst_dnode);
269 return (status);
270 }
271
272 smb_node_rdlock(dst_fnode);
273 status = smb_node_delete_check(dst_fnode);
274 if (status != NT_STATUS_SUCCESS) {
275 smb_node_unlock(dst_fnode);
276 smb_rename_release_src(sr);
277 smb_node_release(dst_fnode);
278 smb_node_release(dst_dnode);
279 return (NT_STATUS_ACCESS_DENIED);
280 }
281
282 /*
283 * Note, the combination of these two:
284 * smb_node_rdlock(node);
285 * nbl_start_crit(node->vp, RW_READER);
286 * is equivalent to this call:
287 * smb_node_start_crit(node, RW_READER)
288 *
289 * Cleanup after this point should use:
290 * smb_node_end_crit(dst_fnode)
291 */
292 nbl_start_crit(dst_fnode->vp, RW_READER);
293
294 /*
295 * This checks nbl_share_conflict, nbl_lock_conflict
296 */
297 status = smb_nbl_conflict(dst_fnode, 0, UINT64_MAX, NBL_REMOVE);
298 if (status != NT_STATUS_SUCCESS) {
299 smb_node_end_crit(dst_fnode);
300 smb_rename_release_src(sr);
301 smb_node_release(dst_fnode);
302 smb_node_release(dst_dnode);
303 return (NT_STATUS_ACCESS_DENIED);
304 }
305
306 new_name = dst_fnode->od_name;
307 dst_exists = B_TRUE;
308 }
309
310 do_audit = smb_audit_rename_init(sr);
311 /* save paths for later auditing */
312 if (do_audit) {
313 if (!have_src) {
314 srcpath = kmem_alloc(SMB_MAXPATHLEN, KM_SLEEP);
315 smb_node_getpath_nofail(src_fnode, smb_audit_rootvp(sr),
316 srcpath, SMB_MAXPATHLEN);
317 }
318 if (dst_exists) {
319 dstpath = kmem_alloc(SMB_MAXPATHLEN, KM_SLEEP);
320 smb_node_getpath_nofail(dst_fnode, smb_audit_rootvp(sr),
321 dstpath, SMB_MAXPATHLEN);
322 }
323 }
324
325 rc = smb_fsop_rename(sr, sr->user_cr,
326 src_dnode, src_fnode->od_name,
327 dst_dnode, new_name);
328
329 if (do_audit) {
330 smb_audit_rename_fini(sr,
331 srcpath,
332 dst_dnode,
333 dstpath,
334 rc == 0,
335 smb_node_is_dir(src_fnode));
336
337 if (srcpath != NULL)
338 kmem_free(srcpath, SMB_MAXPATHLEN);
339 if (dstpath != NULL)
340 kmem_free(dstpath, SMB_MAXPATHLEN);
341 }
342
343 if (rc == 0) {
344 /*
345 * Note that renames in the same directory are normally
346 * delivered in {old,new} pairs, and clients expect them
347 * in that order, if both events are delivered.
348 */
349 int a_src, a_dst; /* action codes */
350 if (src_dnode == dst_dnode) {
351 a_src = FILE_ACTION_RENAMED_OLD_NAME;
352 a_dst = FILE_ACTION_RENAMED_NEW_NAME;
353 } else {
354 a_src = FILE_ACTION_REMOVED;
355 a_dst = FILE_ACTION_ADDED;
356 }
357 smb_node_notify_change(src_dnode, a_src, src_fnode->od_name);
358 smb_node_notify_change(dst_dnode, a_dst, new_name);
359 }
360
361 smb_rename_release_src(sr);
362
466 * Similar to smb_common_rename() above.
467 */
468 uint32_t
469 smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
470 {
471 smb_node_t *tnode;
472 char *path;
473 int rc;
474
475 tnode = sr->tid_tree->t_snode;
476 path = dst_fqi->fq_path.pn_path;
477
478 /* Cannnot create link on named stream */
479 if (smb_is_stream_name(src_fqi->fq_path.pn_path) ||
480 smb_is_stream_name(dst_fqi->fq_path.pn_path)) {
481 return (NT_STATUS_INVALID_PARAMETER);
482 }
483
484 /* The source node may already have been provided */
485 if (src_fqi->fq_fnode) {
486 smb_node_ref(src_fqi->fq_dnode);
487 smb_node_ref(src_fqi->fq_fnode);
488 } else {
489 /* lookup and validate src node */
490 rc = smb_rename_lookup_src(sr);
491 if (rc != 0)
492 return (smb_rename_errno2status(rc));
493 /* Holding refs on dnode, fnode */
494 }
495
496 /* Not valid to create hardlink for directory */
497 if (smb_node_is_dir(src_fqi->fq_fnode)) {
498 smb_node_release(src_fqi->fq_dnode);
499 smb_node_release(src_fqi->fq_fnode);
500 return (NT_STATUS_FILE_IS_A_DIRECTORY);
501 }
502
503 /*
504 * Unlike in rename, we will not unlink the src,
505 * so skip the smb_rename_check_src() call, and
506 * just "start crit" instead.
507 */
508 smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
509
510 /*
511 * Find the destination dnode and last component.
512 * May already be provided, i.e. when called via
513 * SMB1 trans2 setinfo.
514 */
515 if (dst_fqi->fq_dnode) {
516 smb_node_ref(dst_fqi->fq_dnode);
517 } else {
518 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
519 &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
520 if (rc != 0) {
521 smb_rename_release_src(sr);
522 return (smb_rename_errno2status(rc));
523 }
524 }
525
526 /* If CI name match in same directory, we're done */
527 if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) &&
528 (smb_strcasecmp(src_fqi->fq_fnode->od_name,
529 dst_fqi->fq_last_comp, 0) == 0)) {
530 smb_rename_release_src(sr);
550 smb_node_release(dst_fqi->fq_dnode);
551 return (smb_rename_errno2status(rc));
552 }
553
554 rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode,
555 dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
556
557 if (rc == 0) {
558 smb_node_notify_change(dst_fqi->fq_dnode,
559 FILE_ACTION_ADDED, dst_fqi->fq_last_comp);
560 }
561
562 smb_rename_release_src(sr);
563 smb_node_release(dst_fqi->fq_dnode);
564 return (smb_rename_errno2status(rc));
565 }
566
567 /*
568 * smb_rename_lookup_src
569 *
570 * Lookup the src node for a path-based link or rename.
571 *
572 * On success, fills in sr->arg.dirop.fqi, and returns with
573 * holds on the source dnode and fnode.
574 *
575 * Returns errno values.
576 */
577 static int
578 smb_rename_lookup_src(smb_request_t *sr)
579 {
580 smb_node_t *tnode;
581 char *path;
582 int rc;
583
584 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
585
586 if (smb_is_stream_name(src_fqi->fq_path.pn_path))
587 return (EINVAL);
588
589 /* Lookup the source node */
590 tnode = sr->tid_tree->t_snode;
591 path = src_fqi->fq_path.pn_path;
592 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
593 &src_fqi->fq_dnode, src_fqi->fq_last_comp);
594 if (rc != 0)
595 return (rc);
596 /* hold fq_dnode */
597
598 rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
599 src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
600 if (rc != 0) {
601 smb_node_release(src_fqi->fq_dnode);
602 return (rc);
603 }
604 /* hold fq_dnode, fq_fnode */
605
606 rc = smb_rename_check_attr(sr, src_fqi->fq_fnode, src_fqi->fq_sattr);
607 if (rc != 0) {
608 smb_node_release(src_fqi->fq_fnode);
609 smb_node_release(src_fqi->fq_dnode);
610 return (rc);
611 }
612
613 return (0);
614 }
615
616 /*
617 * smb_rename_check_src
618 *
619 * Check for sharing violations on the file we'll unlink, and
620 * break oplocks for the rename operation. Note that we've
621 * already done oplock breaks associated with opening a handle
622 * on the file to rename.
623 *
624 * On success, returns with fnode in a critical section,
625 * as if smb_node_start_crit were called with the node.
626 * Caller should release using smb_rename_release_src().
627 */
628 static uint32_t
629 smb_rename_check_src(smb_request_t *sr, smb_fqi_t *src_fqi)
630 {
631 smb_node_t *src_node = src_fqi->fq_fnode;
632 uint32_t status;
633
634 /*
635 * Break BATCH oplock before ofile checks. If a client
636 * has a file open, this will force a flush or close,
637 * which may affect the outcome of any share checking.
638 *
639 * This operation may have either a handle or path for
640 * the source node (that will be unlinked via rename).
641 */
642
643 if (sr->fid_ofile != NULL) {
644 status = smb_oplock_break_SETINFO(src_node, sr->fid_ofile,
645 FileRenameInformation);
646 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
647 if (sr->session->dialect >= SMB_VERS_2_BASE)
648 (void) smb2sr_go_async(sr);
649 (void) smb_oplock_wait_break(src_node, 0);
650 status = 0;
651 }
652
653 /*
654 * Sharing violations were checked at open time.
655 * Just "start crit" to be consistent with the
656 * state returned for path-based rename.
657 */
658 smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
659 return (NT_STATUS_SUCCESS);
660 }
661
662 /*
663 * This code path operates without a real open, so
664 * break oplocks now as if we opened for delete.
665 * Note: SMB2 does only ofile-based rename.
666 *
667 * Todo: Use an "internal open" for path-based
668 * rename and delete, then delete this code.
669 */
670 ASSERT(sr->session->dialect < SMB_VERS_2_BASE);
671 status = smb_oplock_break_DELETE(src_node, NULL);
672 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
673 (void) smb_oplock_wait_break(src_node, 0);
674 }
675
676 /*
677 * Path-based access to the src file (no ofile)
678 * so check for sharing violations here.
679 */
680 smb_node_rdlock(src_node);
681 status = smb_node_rename_check(src_node);
682 if (status != NT_STATUS_SUCCESS) {
683 smb_node_unlock(src_node);
684 return (status);
685 }
686
687 status = smb_oplock_break_SETINFO(src_node, NULL,
688 FileRenameInformation);
689 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
690 (void) smb_oplock_wait_break(src_node, 0);
691 }
692
693 /*
694 * Note, the combination of these two:
695 * smb_node_rdlock(node);
696 * nbl_start_crit(node->vp, RW_READER);
697 * is equivalent to this call:
698 * smb_node_start_crit(node, RW_READER)
699 *
700 * Cleanup after this point should use:
701 * smb_node_end_crit(src_node)
702 */
703 nbl_start_crit(src_node->vp, RW_READER);
704
705 /*
706 * This checks nbl_share_conflict, nbl_lock_conflict
707 */
708 status = smb_nbl_conflict(src_node, 0, UINT64_MAX, NBL_RENAME);
709 if (status != NT_STATUS_SUCCESS) {
710 smb_node_end_crit(src_node);
711 }
712
713 /* NB: Caller expects to be "in crit" on fnode. */
714 return (status);
715 }
716
717 /*
718 * smb_rename_release_src
719 */
720 static void
721 smb_rename_release_src(smb_request_t *sr)
722 {
723 smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
724
725 smb_node_end_crit(src_fqi->fq_fnode);
726 smb_node_release(src_fqi->fq_fnode);
727 smb_node_release(src_fqi->fq_dnode);
728 }
729
730
731 static int
732 smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr)
733 {
734 smb_attr_t attr;
|