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.
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.
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]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
26 #include <sys/synch.h>
27 #include <smbsrv/smb_kproto.h>
28 #include <smbsrv/smb_fsops.h>
29 #include <sys/nbmlock.h>
32 * NT_RENAME InformationLevels:
34 * SMB_NT_RENAME_MOVE_CLUSTER_INFO Server returns invalid parameter.
35 * SMB_NT_RENAME_SET_LINK_INFO Create a hard link to a file.
36 * SMB_NT_RENAME_RENAME_FILE In-place rename of a file.
37 * SMB_NT_RENAME_MOVE_FILE Move (rename) a file.
39 #define SMB_NT_RENAME_MOVE_CLUSTER_INFO 0x0102
40 #define SMB_NT_RENAME_SET_LINK_INFO 0x0103
41 #define SMB_NT_RENAME_RENAME_FILE 0x0104
42 #define SMB_NT_RENAME_MOVE_FILE 0x0105
45 * SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag
47 #define SMB_RENAME_FLAG_OVERWRITE 0x001
49 static int smb_common_rename(smb_request_t
*, smb_fqi_t
*, smb_fqi_t
*);
50 static int smb_make_link(smb_request_t
*, smb_fqi_t
*, smb_fqi_t
*);
51 static int smb_rename_check_stream(smb_fqi_t
*, smb_fqi_t
*);
52 static int smb_rename_check_attr(smb_request_t
*, smb_node_t
*, uint16_t);
53 static void smb_rename_set_error(smb_request_t
*, int);
55 static int smb_rename_lookup_src(smb_request_t
*);
56 static void smb_rename_release_src(smb_request_t
*);
61 * Rename a file. Files OldFileName must exist and NewFileName must not.
62 * Both pathnames must be relative to the Tid specified in the request.
63 * Open files may be renamed.
65 * Multiple files may be renamed in response to a single request as Rename
66 * File supports wildcards in the file name (last component of the path).
67 * NOTE: we don't support rename with wildcards.
69 * SearchAttributes indicates the attributes that the target file(s) must
70 * have. If SearchAttributes is zero then only normal files are renamed.
71 * If the system file or hidden attributes are specified then the rename
72 * is inclusive - both the specified type(s) of files and normal files are
76 smb_pre_rename(smb_request_t
*sr
)
78 smb_fqi_t
*src_fqi
= &sr
->arg
.dirop
.fqi
;
79 smb_fqi_t
*dst_fqi
= &sr
->arg
.dirop
.dst_fqi
;
82 if ((rc
= smbsr_decode_vwv(sr
, "w", &src_fqi
->fq_sattr
)) == 0) {
83 rc
= smbsr_decode_data(sr
, "%SS", sr
, &src_fqi
->fq_path
.pn_path
,
84 &dst_fqi
->fq_path
.pn_path
);
86 dst_fqi
->fq_sattr
= 0;
89 DTRACE_SMB_2(op__Rename__start
, smb_request_t
*, sr
,
90 struct dirop
*, &sr
->arg
.dirop
);
92 return ((rc
== 0) ? SDRC_SUCCESS
: SDRC_ERROR
);
96 smb_post_rename(smb_request_t
*sr
)
98 DTRACE_SMB_1(op__Rename__done
, smb_request_t
*, sr
);
102 smb_com_rename(smb_request_t
*sr
)
105 smb_fqi_t
*src_fqi
= &sr
->arg
.dirop
.fqi
;
106 smb_fqi_t
*dst_fqi
= &sr
->arg
.dirop
.dst_fqi
;
107 smb_pathname_t
*src_pn
= &src_fqi
->fq_path
;
108 smb_pathname_t
*dst_pn
= &dst_fqi
->fq_path
;
110 if (!STYPE_ISDSK(sr
->tid_tree
->t_res_type
)) {
111 smbsr_error(sr
, NT_STATUS_ACCESS_DENIED
,
112 ERRDOS
, ERROR_ACCESS_DENIED
);
116 smb_pathname_init(sr
, src_pn
, src_pn
->pn_path
);
117 smb_pathname_init(sr
, dst_pn
, dst_pn
->pn_path
);
118 if (!smb_pathname_validate(sr
, src_pn
) ||
119 !smb_pathname_validate(sr
, dst_pn
)) {
123 rc
= smb_common_rename(sr
, src_fqi
, dst_fqi
);
126 smb_rename_set_error(sr
, rc
);
130 rc
= smbsr_encode_empty_result(sr
);
131 return ((rc
== 0) ? SDRC_SUCCESS
: SDRC_ERROR
);
137 * Rename a file. Files OldFileName must exist and NewFileName must not.
138 * Both pathnames must be relative to the Tid specified in the request.
139 * Open files may be renamed.
141 * SearchAttributes indicates the attributes that the target file(s) must
142 * have. If SearchAttributes is zero then only normal files are renamed.
143 * If the system file or hidden attributes are specified then the rename
144 * is inclusive - both the specified type(s) of files and normal files are
148 smb_pre_nt_rename(smb_request_t
*sr
)
150 smb_fqi_t
*src_fqi
= &sr
->arg
.dirop
.fqi
;
151 smb_fqi_t
*dst_fqi
= &sr
->arg
.dirop
.dst_fqi
;
155 rc
= smbsr_decode_vwv(sr
, "wwl", &src_fqi
->fq_sattr
,
156 &sr
->arg
.dirop
.info_level
, &clusters
);
158 rc
= smbsr_decode_data(sr
, "%SS", sr
,
159 &src_fqi
->fq_path
.pn_path
, &dst_fqi
->fq_path
.pn_path
);
161 dst_fqi
->fq_sattr
= 0;
164 DTRACE_SMB_2(op__NtRename__start
, smb_request_t
*, sr
,
165 struct dirop
*, &sr
->arg
.dirop
);
167 return ((rc
== 0) ? SDRC_SUCCESS
: SDRC_ERROR
);
171 smb_post_nt_rename(smb_request_t
*sr
)
173 DTRACE_SMB_1(op__NtRename__done
, smb_request_t
*, sr
);
177 smb_com_nt_rename(smb_request_t
*sr
)
180 smb_fqi_t
*src_fqi
= &sr
->arg
.dirop
.fqi
;
181 smb_fqi_t
*dst_fqi
= &sr
->arg
.dirop
.dst_fqi
;
182 smb_pathname_t
*src_pn
= &src_fqi
->fq_path
;
183 smb_pathname_t
*dst_pn
= &dst_fqi
->fq_path
;
185 if (!STYPE_ISDSK(sr
->tid_tree
->t_res_type
)) {
186 smbsr_error(sr
, NT_STATUS_ACCESS_DENIED
,
187 ERRDOS
, ERROR_ACCESS_DENIED
);
191 smb_pathname_init(sr
, src_pn
, src_pn
->pn_path
);
192 smb_pathname_init(sr
, dst_pn
, dst_pn
->pn_path
);
193 if (!smb_pathname_validate(sr
, src_pn
) ||
194 !smb_pathname_validate(sr
, dst_pn
)) {
198 if (smb_contains_wildcards(src_pn
->pn_path
)) {
199 smbsr_error(sr
, NT_STATUS_OBJECT_PATH_SYNTAX_BAD
,
200 ERRDOS
, ERROR_BAD_PATHNAME
);
204 switch (sr
->arg
.dirop
.info_level
) {
205 case SMB_NT_RENAME_SET_LINK_INFO
:
206 rc
= smb_make_link(sr
, src_fqi
, dst_fqi
);
208 case SMB_NT_RENAME_RENAME_FILE
:
209 case SMB_NT_RENAME_MOVE_FILE
:
210 rc
= smb_common_rename(sr
, src_fqi
, dst_fqi
);
212 case SMB_NT_RENAME_MOVE_CLUSTER_INFO
:
221 smb_rename_set_error(sr
, rc
);
225 rc
= smbsr_encode_empty_result(sr
);
226 return ((rc
== 0) ? SDRC_SUCCESS
: SDRC_ERROR
);
230 * smb_nt_transact_rename
232 * Windows servers return SUCCESS without renaming file.
233 * The only check required is to check that the handle (fid) is valid.
236 smb_nt_transact_rename(smb_request_t
*sr
, smb_xa_t
*xa
)
238 if (smb_mbc_decodef(&xa
->req_param_mb
, "w", &sr
->smb_fid
) != 0)
241 smbsr_lookup_file(sr
);
242 if (sr
->fid_ofile
== NULL
) {
243 smbsr_error(sr
, NT_STATUS_INVALID_HANDLE
, ERRDOS
, ERRbadfid
);
246 smbsr_release_file(sr
);
248 return (SDRC_SUCCESS
);
254 * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo
255 * and Trans2_Set_PathInfo.
256 * If the new filename (dst_fqi) already exists it may be overwritten
260 smb_trans2_rename(smb_request_t
*sr
, smb_node_t
*node
, char *fname
, int flags
)
263 smb_fqi_t
*src_fqi
= &sr
->arg
.dirop
.fqi
;
264 smb_fqi_t
*dst_fqi
= &sr
->arg
.dirop
.dst_fqi
;
265 smb_pathname_t
*dst_pn
= &dst_fqi
->fq_path
;
269 sr
->arg
.dirop
.flags
= flags
? SMB_RENAME_FLAG_OVERWRITE
: 0;
270 sr
->arg
.dirop
.info_level
= SMB_NT_RENAME_RENAME_FILE
;
272 src_fqi
->fq_sattr
= SMB_SEARCH_ATTRIBUTES
;
273 src_fqi
->fq_fnode
= node
;
274 src_fqi
->fq_dnode
= node
->n_dnode
;
276 /* costruct and validate the dst pathname */
277 path
= smb_srm_zalloc(sr
, MAXPATHLEN
);
278 if (src_fqi
->fq_path
.pn_pname
) {
279 (void) snprintf(path
, MAXPATHLEN
, "%s\\%s",
280 src_fqi
->fq_path
.pn_pname
, fname
);
282 rc
= smb_node_getshrpath(node
->n_dnode
, sr
->tid_tree
,
285 smb_rename_set_error(sr
, rc
);
289 (void) snprintf(path
+ len
, MAXPATHLEN
- len
, "\\%s", fname
);
292 smb_pathname_init(sr
, dst_pn
, path
);
293 if (!smb_pathname_validate(sr
, dst_pn
))
296 dst_fqi
->fq_dnode
= node
->n_dnode
;
297 (void) strlcpy(dst_fqi
->fq_last_comp
, dst_pn
->pn_fname
, MAXNAMELEN
);
299 rc
= smb_common_rename(sr
, src_fqi
, dst_fqi
);
301 smb_rename_set_error(sr
, rc
);
311 * Common code for renaming a file.
313 * If the source and destination are identical, we go through all
314 * the checks but we don't actually do the rename. If the source
315 * and destination files differ only in case, we do a case-sensitive
316 * rename. Otherwise, we do a full case-insensitive rename.
318 * Returns errno values.
321 smb_common_rename(smb_request_t
*sr
, smb_fqi_t
*src_fqi
, smb_fqi_t
*dst_fqi
)
323 smb_node_t
*src_fnode
, *src_dnode
, *dst_dnode
;
324 smb_node_t
*dst_fnode
= 0;
325 smb_node_t
*tnode
= 0;
328 char *new_name
, *path
;
330 path
= dst_fqi
->fq_path
.pn_path
;
332 /* Check if attempting to rename a stream - not yet supported */
333 rc
= smb_rename_check_stream(src_fqi
, dst_fqi
);
337 /* The source node may already have been provided */
338 if (src_fqi
->fq_fnode
) {
339 smb_node_start_crit(src_fqi
->fq_fnode
, RW_READER
);
340 smb_node_ref(src_fqi
->fq_fnode
);
341 smb_node_ref(src_fqi
->fq_dnode
);
343 /* lookup and validate src node */
344 rc
= smb_rename_lookup_src(sr
);
349 src_fnode
= src_fqi
->fq_fnode
;
350 src_dnode
= src_fqi
->fq_dnode
;
351 tnode
= sr
->tid_tree
->t_snode
;
353 /* Find destination dnode and last_comp */
354 if (dst_fqi
->fq_dnode
) {
355 smb_node_ref(dst_fqi
->fq_dnode
);
357 rc
= smb_pathname_reduce(sr
, sr
->user_cr
, path
, tnode
, tnode
,
358 &dst_fqi
->fq_dnode
, dst_fqi
->fq_last_comp
);
360 smb_rename_release_src(sr
);
365 dst_dnode
= dst_fqi
->fq_dnode
;
366 new_name
= dst_fqi
->fq_last_comp
;
368 /* If exact name match in same directory, we're done */
369 if ((src_dnode
== dst_dnode
) &&
370 (strcmp(src_fnode
->od_name
, new_name
) == 0)) {
371 smb_rename_release_src(sr
);
372 smb_node_release(dst_dnode
);
376 /* Lookup destination node */
377 rc
= smb_fsop_lookup(sr
, sr
->user_cr
, 0, tnode
,
378 dst_dnode
, new_name
, &dst_fqi
->fq_fnode
);
380 /* If the destination node doesn't already exist, validate new_name. */
382 if (smb_is_invalid_filename(new_name
)) {
383 smb_rename_release_src(sr
);
384 smb_node_release(dst_dnode
);
385 return (EILSEQ
); /* NT_STATUS_OBJECT_NAME_INVALID */
390 * Handle case where changing case of the same directory entry.
392 * If we found the dst node in the same directory as the src node,
393 * and their names differ only in case:
395 * If the tree is case sensitive (or mixed):
396 * Do case sensitive lookup to see if exact match exists.
397 * If the exact match is the same node as src_node we're done.
399 * If the tree is case insensitive:
400 * There is currently no way to tell if the case is different
401 * or not, so do the rename (unless the specified new name was
405 (src_dnode
== dst_dnode
) &&
406 (smb_strcasecmp(src_fnode
->od_name
,
407 dst_fqi
->fq_fnode
->od_name
, 0) == 0)) {
408 smb_node_release(dst_fqi
->fq_fnode
);
409 dst_fqi
->fq_fnode
= NULL
;
411 if (smb_tree_has_feature(sr
->tid_tree
,
412 SMB_TREE_NO_CASESENSITIVE
)) {
413 if (smb_strcasecmp(src_fnode
->od_name
,
414 dst_fqi
->fq_last_comp
, 0) != 0) {
415 smb_rename_release_src(sr
);
416 smb_node_release(dst_dnode
);
420 rc
= smb_fsop_lookup(sr
, sr
->user_cr
,
421 SMB_CASE_SENSITIVE
, tnode
, dst_dnode
, new_name
,
425 (dst_fqi
->fq_fnode
== src_fnode
)) {
426 smb_rename_release_src(sr
);
427 smb_node_release(dst_fqi
->fq_fnode
);
428 smb_node_release(dst_dnode
);
434 if ((rc
!= 0) && (rc
!= ENOENT
)) {
435 smb_rename_release_src(sr
);
436 smb_node_release(dst_fqi
->fq_dnode
);
440 if (dst_fqi
->fq_fnode
) {
442 * Destination already exists. Do delete checks.
444 dst_fnode
= dst_fqi
->fq_fnode
;
446 if (!(sr
->arg
.dirop
.flags
&& SMB_RENAME_FLAG_OVERWRITE
)) {
447 smb_rename_release_src(sr
);
448 smb_node_release(dst_fnode
);
449 smb_node_release(dst_dnode
);
453 (void) smb_oplock_break(sr
, dst_fnode
,
454 SMB_OPLOCK_BREAK_TO_NONE
| SMB_OPLOCK_BREAK_BATCH
);
457 * Wait (a little) for the oplock break to be
458 * responded to by clients closing handles.
459 * Hold node->n_lock as reader to keep new
460 * ofiles from showing up after we check.
462 smb_node_rdlock(dst_fnode
);
463 for (count
= 0; count
<= 12; count
++) {
464 status
= smb_node_delete_check(dst_fnode
);
465 if (status
!= NT_STATUS_SHARING_VIOLATION
)
467 smb_node_unlock(dst_fnode
);
468 delay(MSEC_TO_TICK(100));
469 smb_node_rdlock(dst_fnode
);
471 if (status
!= NT_STATUS_SUCCESS
) {
472 smb_node_unlock(dst_fnode
);
473 smb_rename_release_src(sr
);
474 smb_node_release(dst_fnode
);
475 smb_node_release(dst_dnode
);
480 * Note, the combination of these two:
481 * smb_node_rdlock(node);
482 * nbl_start_crit(node->vp, RW_READER);
483 * is equivalent to this call:
484 * smb_node_start_crit(node, RW_READER)
486 * Cleanup after this point should use:
487 * smb_node_end_crit(dst_fnode)
489 nbl_start_crit(dst_fnode
->vp
, RW_READER
);
492 * This checks nbl_share_conflict, nbl_lock_conflict
494 status
= smb_nbl_conflict(dst_fnode
, 0, UINT64_MAX
, NBL_REMOVE
);
495 if (status
!= NT_STATUS_SUCCESS
) {
496 smb_node_end_crit(dst_fnode
);
497 smb_rename_release_src(sr
);
498 smb_node_release(dst_fnode
);
499 smb_node_release(dst_dnode
);
503 new_name
= dst_fnode
->od_name
;
506 rc
= smb_fsop_rename(sr
, sr
->user_cr
,
507 src_dnode
, src_fnode
->od_name
,
508 dst_dnode
, new_name
);
512 * Note that renames in the same directory are normally
513 * delivered in {old,new} pairs, and clients expect them
514 * in that order, if both events are delivered.
516 int a_src
, a_dst
; /* action codes */
517 if (src_dnode
== dst_dnode
) {
518 a_src
= FILE_ACTION_RENAMED_OLD_NAME
;
519 a_dst
= FILE_ACTION_RENAMED_NEW_NAME
;
521 a_src
= FILE_ACTION_REMOVED
;
522 a_dst
= FILE_ACTION_ADDED
;
524 smb_node_notify_change(src_dnode
, a_src
, src_fnode
->od_name
);
525 smb_node_notify_change(dst_dnode
, a_dst
, new_name
);
528 smb_rename_release_src(sr
);
530 if (dst_fqi
->fq_fnode
) {
531 smb_node_end_crit(dst_fnode
);
532 smb_node_release(dst_fnode
);
534 smb_node_release(dst_dnode
);
540 * smb_rename_check_stream
542 * For a stream rename the dst path must begin with ':', or "\\:".
543 * We don't yet support stream rename, Return EACCES.
545 * If not a stream rename, in accordance with the above rule,
546 * it is not valid for either the src or dst to be a stream.
550 smb_rename_check_stream(smb_fqi_t
*src_fqi
, smb_fqi_t
*dst_fqi
)
552 smb_node_t
*src_fnode
= src_fqi
->fq_fnode
;
553 char *src_path
= src_fqi
->fq_path
.pn_path
;
554 char *dst_path
= dst_fqi
->fq_path
.pn_path
;
556 /* We do not yet support named stream rename - ACCESS DENIED */
557 if ((dst_path
[0] == ':') ||
558 ((dst_path
[0] == '\\') && (dst_path
[1] == ':'))) {
563 * If not stream rename (above) neither src or dst can be
567 if (smb_is_stream_name(dst_path
))
570 if (src_fqi
->fq_fnode
) {
571 if (SMB_IS_STREAM(src_fnode
))
574 if (smb_is_stream_name(src_path
))
585 * Creating a hard link (adding an additional name) for a file.
587 * If the source and destination are identical, we go through all
588 * the checks but we don't create a link.
590 * If the file is a symlink we create the hardlink on the target
591 * of the symlink (i.e. use SMB_FOLLOW_LINKS when looking up src).
592 * If the target of the symlink does not exist we fail with ENOENT.
594 * Returns errno values.
597 smb_make_link(smb_request_t
*sr
, smb_fqi_t
*src_fqi
, smb_fqi_t
*dst_fqi
)
603 /* Cannnot create link on named stream */
604 if (smb_is_stream_name(src_fqi
->fq_path
.pn_path
) ||
605 smb_is_stream_name(dst_fqi
->fq_path
.pn_path
)) {
609 /* lookup and validate src node */
610 rc
= smb_rename_lookup_src(sr
);
614 /* if src and dest paths match we're done */
615 if (smb_strcasecmp(src_fqi
->fq_path
.pn_path
,
616 dst_fqi
->fq_path
.pn_path
, 0) == 0) {
617 smb_rename_release_src(sr
);
621 /* find the destination dnode and last_comp */
622 tnode
= sr
->tid_tree
->t_snode
;
623 path
= dst_fqi
->fq_path
.pn_path
;
624 rc
= smb_pathname_reduce(sr
, sr
->user_cr
, path
, tnode
, tnode
,
625 &dst_fqi
->fq_dnode
, dst_fqi
->fq_last_comp
);
627 smb_rename_release_src(sr
);
631 /* If name match in same directory, we're done */
632 if ((src_fqi
->fq_dnode
== dst_fqi
->fq_dnode
) &&
633 (smb_strcasecmp(src_fqi
->fq_fnode
->od_name
,
634 dst_fqi
->fq_last_comp
, 0) == 0)) {
635 smb_rename_release_src(sr
);
636 smb_node_release(dst_fqi
->fq_dnode
);
640 if (smb_is_invalid_filename(dst_fqi
->fq_last_comp
)) {
641 smb_rename_release_src(sr
);
642 smb_node_release(dst_fqi
->fq_dnode
);
643 return (EILSEQ
); /* NT_STATUS_INVALID_OBJECT_NAME */
646 /* Lookup the destination node. It MUST NOT exist. */
647 rc
= smb_fsop_lookup(sr
, sr
->user_cr
, 0, tnode
,
648 dst_fqi
->fq_dnode
, dst_fqi
->fq_last_comp
, &dst_fqi
->fq_fnode
);
650 smb_node_release(dst_fqi
->fq_fnode
);
654 smb_rename_release_src(sr
);
655 smb_node_release(dst_fqi
->fq_dnode
);
659 rc
= smb_fsop_link(sr
, sr
->user_cr
, src_fqi
->fq_fnode
,
660 dst_fqi
->fq_dnode
, dst_fqi
->fq_last_comp
);
663 smb_node_notify_change(dst_fqi
->fq_dnode
,
664 FILE_ACTION_ADDED
, dst_fqi
->fq_last_comp
);
667 smb_rename_release_src(sr
);
668 smb_node_release(dst_fqi
->fq_dnode
);
673 * smb_rename_lookup_src
675 * Lookup the src node, checking for sharing violations and
676 * breaking any existing BATCH oplock.
677 * Populate sr->arg.dirop.fqi
679 * Upon success, the dnode and fnode will have holds and the
680 * fnode will be in a critical section. These should be
681 * released using smb_rename_release_src().
683 * Returns errno values.
686 smb_rename_lookup_src(smb_request_t
*sr
)
688 smb_node_t
*src_node
, *tnode
;
694 struct dirop
*dirop
= &sr
->arg
.dirop
;
695 smb_fqi_t
*src_fqi
= &sr
->arg
.dirop
.fqi
;
697 if (smb_is_stream_name(src_fqi
->fq_path
.pn_path
))
700 /* Lookup the source node */
701 tnode
= sr
->tid_tree
->t_snode
;
702 path
= src_fqi
->fq_path
.pn_path
;
703 rc
= smb_pathname_reduce(sr
, sr
->user_cr
, path
, tnode
, tnode
,
704 &src_fqi
->fq_dnode
, src_fqi
->fq_last_comp
);
708 rc
= smb_fsop_lookup(sr
, sr
->user_cr
, 0, tnode
,
709 src_fqi
->fq_dnode
, src_fqi
->fq_last_comp
, &src_fqi
->fq_fnode
);
711 smb_node_release(src_fqi
->fq_dnode
);
715 /* Not valid to create hardlink for directory */
716 if ((dirop
->info_level
== SMB_NT_RENAME_SET_LINK_INFO
) &&
717 (smb_node_is_dir(src_fqi
->fq_fnode
))) {
718 smb_node_release(src_fqi
->fq_fnode
);
719 smb_node_release(src_fqi
->fq_dnode
);
723 src_node
= src_fqi
->fq_fnode
;
725 rc
= smb_rename_check_attr(sr
, src_node
, src_fqi
->fq_sattr
);
727 smb_node_release(src_fqi
->fq_fnode
);
728 smb_node_release(src_fqi
->fq_dnode
);
733 * Break BATCH oplock before ofile checks. If a client
734 * has a file open, this will force a flush or close,
735 * which may affect the outcome of any share checking.
737 (void) smb_oplock_break(sr
, src_node
,
738 SMB_OPLOCK_BREAK_TO_LEVEL_II
| SMB_OPLOCK_BREAK_BATCH
);
741 * Wait (a little) for the oplock break to be
742 * responded to by clients closing handles.
743 * Hold node->n_lock as reader to keep new
744 * ofiles from showing up after we check.
746 smb_node_rdlock(src_node
);
747 for (count
= 0; count
<= 12; count
++) {
748 status
= smb_node_rename_check(src_node
);
749 if (status
!= NT_STATUS_SHARING_VIOLATION
)
751 smb_node_unlock(src_node
);
752 delay(MSEC_TO_TICK(100));
753 smb_node_rdlock(src_node
);
755 if (status
!= NT_STATUS_SUCCESS
) {
756 smb_node_unlock(src_node
);
757 smb_node_release(src_fqi
->fq_fnode
);
758 smb_node_release(src_fqi
->fq_dnode
);
759 return (EPIPE
); /* = ERRbadshare */
763 * Note, the combination of these two:
764 * smb_node_rdlock(node);
765 * nbl_start_crit(node->vp, RW_READER);
766 * is equivalent to this call:
767 * smb_node_start_crit(node, RW_READER)
769 * Cleanup after this point should use:
770 * smb_node_end_crit(src_node)
772 nbl_start_crit(src_node
->vp
, RW_READER
);
775 * This checks nbl_share_conflict, nbl_lock_conflict
777 status
= smb_nbl_conflict(src_node
, 0, UINT64_MAX
, NBL_RENAME
);
778 if (status
!= NT_STATUS_SUCCESS
) {
779 smb_node_end_crit(src_node
);
780 smb_node_release(src_fqi
->fq_fnode
);
781 smb_node_release(src_fqi
->fq_dnode
);
782 if (status
== NT_STATUS_SHARING_VIOLATION
)
783 return (EPIPE
); /* = ERRbadshare */
787 /* NB: Caller expects holds on src_fqi fnode, dnode */
792 * smb_rename_release_src
795 smb_rename_release_src(smb_request_t
*sr
)
797 smb_fqi_t
*src_fqi
= &sr
->arg
.dirop
.fqi
;
799 smb_node_end_crit(src_fqi
->fq_fnode
);
800 smb_node_release(src_fqi
->fq_fnode
);
801 smb_node_release(src_fqi
->fq_dnode
);
806 smb_rename_check_attr(smb_request_t
*sr
, smb_node_t
*node
, uint16_t sattr
)
810 bzero(&attr
, sizeof (attr
));
811 attr
.sa_mask
= SMB_AT_DOSATTR
;
812 if (smb_node_getattr(sr
, node
, zone_kcred(), NULL
, &attr
) != 0)
815 if ((attr
.sa_dosattr
& FILE_ATTRIBUTE_HIDDEN
) &&
816 !(SMB_SEARCH_HIDDEN(sattr
)))
819 if ((attr
.sa_dosattr
& FILE_ATTRIBUTE_SYSTEM
) &&
820 !(SMB_SEARCH_SYSTEM(sattr
)))
827 * The following values are based on observed WFWG, Windows 9x, Windows NT
828 * and Windows 2000 behaviour.
830 * ERROR_FILE_EXISTS doesn't work for Windows 98 clients.
832 * Windows 95 clients don't see the problem because the target is deleted
833 * before the rename request.
836 smb_rename_set_error(smb_request_t
*sr
, int errnum
)
843 { EEXIST
, ERROR_ALREADY_EXISTS
, NT_STATUS_OBJECT_NAME_COLLISION
},
844 { EPIPE
, ERROR_SHARING_VIOLATION
, NT_STATUS_SHARING_VIOLATION
},
845 { ENOENT
, ERROR_FILE_NOT_FOUND
, NT_STATUS_OBJECT_NAME_NOT_FOUND
},
846 { ESRCH
, ERROR_FILE_NOT_FOUND
, NT_STATUS_NO_SUCH_FILE
},
847 { EINVAL
, ERROR_INVALID_PARAMETER
, NT_STATUS_INVALID_PARAMETER
},
848 { EACCES
, ERROR_ACCESS_DENIED
, NT_STATUS_ACCESS_DENIED
},
849 { EISDIR
, ERROR_ACCESS_DENIED
, NT_STATUS_FILE_IS_A_DIRECTORY
},
850 { EIO
, ERROR_INTERNAL_ERROR
, NT_STATUS_INTERNAL_ERROR
}
858 for (i
= 0; i
< sizeof (rc_map
)/sizeof (rc_map
[0]); ++i
) {
859 if (rc_map
[i
].errnum
== errnum
) {
860 smbsr_error(sr
, rc_map
[i
].status32
,
861 ERRDOS
, rc_map
[i
].errcode
);
866 smbsr_errno(sr
, errnum
);