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_fnode
, *dst_dnode
;
327 char *new_name
, *path
;
329 path
= dst_fqi
->fq_path
.pn_path
;
331 /* Check if attempting to rename a stream - not yet supported */
332 rc
= smb_rename_check_stream(src_fqi
, dst_fqi
);
336 /* The source node may already have been provided */
337 if (src_fqi
->fq_fnode
) {
338 smb_node_start_crit(src_fqi
->fq_fnode
, RW_READER
);
339 smb_node_ref(src_fqi
->fq_fnode
);
340 smb_node_ref(src_fqi
->fq_dnode
);
342 /* lookup and validate src node */
343 rc
= smb_rename_lookup_src(sr
);
348 src_fnode
= src_fqi
->fq_fnode
;
349 src_dnode
= src_fqi
->fq_dnode
;
350 tnode
= sr
->tid_tree
->t_snode
;
352 /* Find destination dnode and last_comp */
353 if (dst_fqi
->fq_dnode
) {
354 smb_node_ref(dst_fqi
->fq_dnode
);
356 rc
= smb_pathname_reduce(sr
, sr
->user_cr
, path
, tnode
, tnode
,
357 &dst_fqi
->fq_dnode
, dst_fqi
->fq_last_comp
);
359 smb_rename_release_src(sr
);
364 dst_dnode
= dst_fqi
->fq_dnode
;
365 new_name
= dst_fqi
->fq_last_comp
;
367 /* If exact name match in same directory, we're done */
368 if ((src_dnode
== dst_dnode
) &&
369 (strcmp(src_fnode
->od_name
, new_name
) == 0)) {
370 smb_rename_release_src(sr
);
371 smb_node_release(dst_dnode
);
375 /* Lookup destination node */
376 rc
= smb_fsop_lookup(sr
, sr
->user_cr
, 0, tnode
,
377 dst_dnode
, new_name
, &dst_fqi
->fq_fnode
);
379 /* If the destination node doesn't already exist, validate new_name. */
381 if (smb_is_invalid_filename(new_name
)) {
382 smb_rename_release_src(sr
);
383 smb_node_release(dst_dnode
);
384 return (EILSEQ
); /* NT_STATUS_OBJECT_NAME_INVALID */
389 * Handle case where changing case of the same directory entry.
391 * If we found the dst node in the same directory as the src node,
392 * and their names differ only in case:
394 * If the tree is case sensitive (or mixed):
395 * Do case sensitive lookup to see if exact match exists.
396 * If the exact match is the same node as src_node we're done.
398 * If the tree is case insensitive:
399 * There is currently no way to tell if the case is different
400 * or not, so do the rename (unless the specified new name was
404 (src_dnode
== dst_dnode
) &&
405 (smb_strcasecmp(src_fnode
->od_name
,
406 dst_fqi
->fq_fnode
->od_name
, 0) == 0)) {
407 smb_node_release(dst_fqi
->fq_fnode
);
408 dst_fqi
->fq_fnode
= NULL
;
410 if (smb_tree_has_feature(sr
->tid_tree
,
411 SMB_TREE_NO_CASESENSITIVE
)) {
412 if (smb_strcasecmp(src_fnode
->od_name
,
413 dst_fqi
->fq_last_comp
, 0) != 0) {
414 smb_rename_release_src(sr
);
415 smb_node_release(dst_dnode
);
419 rc
= smb_fsop_lookup(sr
, sr
->user_cr
,
420 SMB_CASE_SENSITIVE
, tnode
, dst_dnode
, new_name
,
424 (dst_fqi
->fq_fnode
== src_fnode
)) {
425 smb_rename_release_src(sr
);
426 smb_node_release(dst_fqi
->fq_fnode
);
427 smb_node_release(dst_dnode
);
433 if ((rc
!= 0) && (rc
!= ENOENT
)) {
434 smb_rename_release_src(sr
);
435 smb_node_release(dst_fqi
->fq_dnode
);
439 if (dst_fqi
->fq_fnode
) {
441 * Destination already exists. Do delete checks.
443 dst_fnode
= dst_fqi
->fq_fnode
;
445 if (!(sr
->arg
.dirop
.flags
&& SMB_RENAME_FLAG_OVERWRITE
)) {
446 smb_rename_release_src(sr
);
447 smb_node_release(dst_fnode
);
448 smb_node_release(dst_dnode
);
452 (void) smb_oplock_break(sr
, dst_fnode
,
453 SMB_OPLOCK_BREAK_TO_NONE
| SMB_OPLOCK_BREAK_BATCH
);
456 * Wait (a little) for the oplock break to be
457 * responded to by clients closing handles.
458 * Hold node->n_lock as reader to keep new
459 * ofiles from showing up after we check.
461 smb_node_rdlock(dst_fnode
);
462 for (count
= 0; count
<= 12; count
++) {
463 status
= smb_node_delete_check(dst_fnode
);
464 if (status
!= NT_STATUS_SHARING_VIOLATION
)
466 smb_node_unlock(dst_fnode
);
467 delay(MSEC_TO_TICK(100));
468 smb_node_rdlock(dst_fnode
);
470 if (status
!= NT_STATUS_SUCCESS
) {
471 smb_node_unlock(dst_fnode
);
472 smb_rename_release_src(sr
);
473 smb_node_release(dst_fnode
);
474 smb_node_release(dst_dnode
);
479 * Note, the combination of these two:
480 * smb_node_rdlock(node);
481 * nbl_start_crit(node->vp, RW_READER);
482 * is equivalent to this call:
483 * smb_node_start_crit(node, RW_READER)
485 * Cleanup after this point should use:
486 * smb_node_end_crit(dst_fnode)
488 nbl_start_crit(dst_fnode
->vp
, RW_READER
);
491 * This checks nbl_share_conflict, nbl_lock_conflict
493 status
= smb_nbl_conflict(dst_fnode
, 0, UINT64_MAX
, NBL_REMOVE
);
494 if (status
!= NT_STATUS_SUCCESS
) {
495 smb_node_end_crit(dst_fnode
);
496 smb_rename_release_src(sr
);
497 smb_node_release(dst_fnode
);
498 smb_node_release(dst_dnode
);
502 new_name
= dst_fnode
->od_name
;
505 rc
= smb_fsop_rename(sr
, sr
->user_cr
,
506 src_dnode
, src_fnode
->od_name
,
507 dst_dnode
, new_name
);
511 * Note that renames in the same directory are normally
512 * delivered in {old,new} pairs, and clients expect them
513 * in that order, if both events are delivered.
515 int a_src
, a_dst
; /* action codes */
516 if (src_dnode
== dst_dnode
) {
517 a_src
= FILE_ACTION_RENAMED_OLD_NAME
;
518 a_dst
= FILE_ACTION_RENAMED_NEW_NAME
;
520 a_src
= FILE_ACTION_REMOVED
;
521 a_dst
= FILE_ACTION_ADDED
;
523 smb_node_notify_change(src_dnode
, a_src
, src_fnode
->od_name
);
524 smb_node_notify_change(dst_dnode
, a_dst
, new_name
);
527 smb_rename_release_src(sr
);
529 if (dst_fqi
->fq_fnode
) {
530 smb_node_end_crit(dst_fnode
);
531 smb_node_release(dst_fnode
);
533 smb_node_release(dst_dnode
);
539 * smb_rename_check_stream
541 * For a stream rename the dst path must begin with ':', or "\\:".
542 * We don't yet support stream rename, Return EACCES.
544 * If not a stream rename, in accordance with the above rule,
545 * it is not valid for either the src or dst to be a stream.
549 smb_rename_check_stream(smb_fqi_t
*src_fqi
, smb_fqi_t
*dst_fqi
)
551 smb_node_t
*src_fnode
= src_fqi
->fq_fnode
;
552 char *src_path
= src_fqi
->fq_path
.pn_path
;
553 char *dst_path
= dst_fqi
->fq_path
.pn_path
;
555 /* We do not yet support named stream rename - ACCESS DENIED */
556 if ((dst_path
[0] == ':') ||
557 ((dst_path
[0] == '\\') && (dst_path
[1] == ':'))) {
562 * If not stream rename (above) neither src or dst can be
566 if (smb_is_stream_name(dst_path
))
569 if (src_fqi
->fq_fnode
) {
570 if (SMB_IS_STREAM(src_fnode
))
573 if (smb_is_stream_name(src_path
))
584 * Creating a hard link (adding an additional name) for a file.
586 * If the source and destination are identical, we go through all
587 * the checks but we don't create a link.
589 * If the file is a symlink we create the hardlink on the target
590 * of the symlink (i.e. use SMB_FOLLOW_LINKS when looking up src).
591 * If the target of the symlink does not exist we fail with ENOENT.
593 * Returns errno values.
596 smb_make_link(smb_request_t
*sr
, smb_fqi_t
*src_fqi
, smb_fqi_t
*dst_fqi
)
602 /* Cannnot create link on named stream */
603 if (smb_is_stream_name(src_fqi
->fq_path
.pn_path
) ||
604 smb_is_stream_name(dst_fqi
->fq_path
.pn_path
)) {
608 /* lookup and validate src node */
609 rc
= smb_rename_lookup_src(sr
);
613 /* if src and dest paths match we're done */
614 if (smb_strcasecmp(src_fqi
->fq_path
.pn_path
,
615 dst_fqi
->fq_path
.pn_path
, 0) == 0) {
616 smb_rename_release_src(sr
);
620 /* find the destination dnode and last_comp */
621 tnode
= sr
->tid_tree
->t_snode
;
622 path
= dst_fqi
->fq_path
.pn_path
;
623 rc
= smb_pathname_reduce(sr
, sr
->user_cr
, path
, tnode
, tnode
,
624 &dst_fqi
->fq_dnode
, dst_fqi
->fq_last_comp
);
626 smb_rename_release_src(sr
);
630 /* If name match in same directory, we're done */
631 if ((src_fqi
->fq_dnode
== dst_fqi
->fq_dnode
) &&
632 (smb_strcasecmp(src_fqi
->fq_fnode
->od_name
,
633 dst_fqi
->fq_last_comp
, 0) == 0)) {
634 smb_rename_release_src(sr
);
635 smb_node_release(dst_fqi
->fq_dnode
);
639 if (smb_is_invalid_filename(dst_fqi
->fq_last_comp
)) {
640 smb_rename_release_src(sr
);
641 smb_node_release(dst_fqi
->fq_dnode
);
642 return (EILSEQ
); /* NT_STATUS_INVALID_OBJECT_NAME */
645 /* Lookup the destination node. It MUST NOT exist. */
646 rc
= smb_fsop_lookup(sr
, sr
->user_cr
, 0, tnode
,
647 dst_fqi
->fq_dnode
, dst_fqi
->fq_last_comp
, &dst_fqi
->fq_fnode
);
649 smb_node_release(dst_fqi
->fq_fnode
);
653 smb_rename_release_src(sr
);
654 smb_node_release(dst_fqi
->fq_dnode
);
658 rc
= smb_fsop_link(sr
, sr
->user_cr
, src_fqi
->fq_fnode
,
659 dst_fqi
->fq_dnode
, dst_fqi
->fq_last_comp
);
662 smb_node_notify_change(dst_fqi
->fq_dnode
,
663 FILE_ACTION_ADDED
, dst_fqi
->fq_last_comp
);
666 smb_rename_release_src(sr
);
667 smb_node_release(dst_fqi
->fq_dnode
);
672 * smb_rename_lookup_src
674 * Lookup the src node, checking for sharing violations and
675 * breaking any existing BATCH oplock.
676 * Populate sr->arg.dirop.fqi
678 * Upon success, the dnode and fnode will have holds and the
679 * fnode will be in a critical section. These should be
680 * released using smb_rename_release_src().
682 * Returns errno values.
685 smb_rename_lookup_src(smb_request_t
*sr
)
687 smb_node_t
*src_node
, *tnode
;
693 struct dirop
*dirop
= &sr
->arg
.dirop
;
694 smb_fqi_t
*src_fqi
= &sr
->arg
.dirop
.fqi
;
696 if (smb_is_stream_name(src_fqi
->fq_path
.pn_path
))
699 /* Lookup the source node */
700 tnode
= sr
->tid_tree
->t_snode
;
701 path
= src_fqi
->fq_path
.pn_path
;
702 rc
= smb_pathname_reduce(sr
, sr
->user_cr
, path
, tnode
, tnode
,
703 &src_fqi
->fq_dnode
, src_fqi
->fq_last_comp
);
707 rc
= smb_fsop_lookup(sr
, sr
->user_cr
, 0, tnode
,
708 src_fqi
->fq_dnode
, src_fqi
->fq_last_comp
, &src_fqi
->fq_fnode
);
710 smb_node_release(src_fqi
->fq_dnode
);
714 /* Not valid to create hardlink for directory */
715 if ((dirop
->info_level
== SMB_NT_RENAME_SET_LINK_INFO
) &&
716 (smb_node_is_dir(src_fqi
->fq_fnode
))) {
717 smb_node_release(src_fqi
->fq_fnode
);
718 smb_node_release(src_fqi
->fq_dnode
);
722 src_node
= src_fqi
->fq_fnode
;
724 rc
= smb_rename_check_attr(sr
, src_node
, src_fqi
->fq_sattr
);
726 smb_node_release(src_fqi
->fq_fnode
);
727 smb_node_release(src_fqi
->fq_dnode
);
732 * Break BATCH oplock before ofile checks. If a client
733 * has a file open, this will force a flush or close,
734 * which may affect the outcome of any share checking.
736 (void) smb_oplock_break(sr
, src_node
,
737 SMB_OPLOCK_BREAK_TO_LEVEL_II
| SMB_OPLOCK_BREAK_BATCH
);
740 * Wait (a little) for the oplock break to be
741 * responded to by clients closing handles.
742 * Hold node->n_lock as reader to keep new
743 * ofiles from showing up after we check.
745 smb_node_rdlock(src_node
);
746 for (count
= 0; count
<= 12; count
++) {
747 status
= smb_node_rename_check(src_node
);
748 if (status
!= NT_STATUS_SHARING_VIOLATION
)
750 smb_node_unlock(src_node
);
751 delay(MSEC_TO_TICK(100));
752 smb_node_rdlock(src_node
);
754 if (status
!= NT_STATUS_SUCCESS
) {
755 smb_node_unlock(src_node
);
756 smb_node_release(src_fqi
->fq_fnode
);
757 smb_node_release(src_fqi
->fq_dnode
);
758 return (EPIPE
); /* = ERRbadshare */
762 * Note, the combination of these two:
763 * smb_node_rdlock(node);
764 * nbl_start_crit(node->vp, RW_READER);
765 * is equivalent to this call:
766 * smb_node_start_crit(node, RW_READER)
768 * Cleanup after this point should use:
769 * smb_node_end_crit(src_node)
771 nbl_start_crit(src_node
->vp
, RW_READER
);
774 * This checks nbl_share_conflict, nbl_lock_conflict
776 status
= smb_nbl_conflict(src_node
, 0, UINT64_MAX
, NBL_RENAME
);
777 if (status
!= NT_STATUS_SUCCESS
) {
778 smb_node_end_crit(src_node
);
779 smb_node_release(src_fqi
->fq_fnode
);
780 smb_node_release(src_fqi
->fq_dnode
);
781 if (status
== NT_STATUS_SHARING_VIOLATION
)
782 return (EPIPE
); /* = ERRbadshare */
786 /* NB: Caller expects holds on src_fqi fnode, dnode */
791 * smb_rename_release_src
794 smb_rename_release_src(smb_request_t
*sr
)
796 smb_fqi_t
*src_fqi
= &sr
->arg
.dirop
.fqi
;
798 smb_node_end_crit(src_fqi
->fq_fnode
);
799 smb_node_release(src_fqi
->fq_fnode
);
800 smb_node_release(src_fqi
->fq_dnode
);
805 smb_rename_check_attr(smb_request_t
*sr
, smb_node_t
*node
, uint16_t sattr
)
809 bzero(&attr
, sizeof (attr
));
810 attr
.sa_mask
= SMB_AT_DOSATTR
;
811 if (smb_node_getattr(sr
, node
, kcred
, NULL
, &attr
) != 0)
814 if ((attr
.sa_dosattr
& FILE_ATTRIBUTE_HIDDEN
) &&
815 !(SMB_SEARCH_HIDDEN(sattr
)))
818 if ((attr
.sa_dosattr
& FILE_ATTRIBUTE_SYSTEM
) &&
819 !(SMB_SEARCH_SYSTEM(sattr
)))
826 * The following values are based on observed WFWG, Windows 9x, Windows NT
827 * and Windows 2000 behaviour.
829 * ERROR_FILE_EXISTS doesn't work for Windows 98 clients.
831 * Windows 95 clients don't see the problem because the target is deleted
832 * before the rename request.
835 smb_rename_set_error(smb_request_t
*sr
, int errnum
)
842 { EEXIST
, ERROR_ALREADY_EXISTS
, NT_STATUS_OBJECT_NAME_COLLISION
},
843 { EPIPE
, ERROR_SHARING_VIOLATION
, NT_STATUS_SHARING_VIOLATION
},
844 { ENOENT
, ERROR_FILE_NOT_FOUND
, NT_STATUS_OBJECT_NAME_NOT_FOUND
},
845 { ESRCH
, ERROR_FILE_NOT_FOUND
, NT_STATUS_NO_SUCH_FILE
},
846 { EINVAL
, ERROR_INVALID_PARAMETER
, NT_STATUS_INVALID_PARAMETER
},
847 { EACCES
, ERROR_ACCESS_DENIED
, NT_STATUS_ACCESS_DENIED
},
848 { EISDIR
, ERROR_ACCESS_DENIED
, NT_STATUS_FILE_IS_A_DIRECTORY
},
849 { EIO
, ERROR_INTERNAL_ERROR
, NT_STATUS_INTERNAL_ERROR
}
857 for (i
= 0; i
< sizeof (rc_map
)/sizeof (rc_map
[0]); ++i
) {
858 if (rc_map
[i
].errnum
== errnum
) {
859 smbsr_error(sr
, rc_map
[i
].status32
,
860 ERRDOS
, rc_map
[i
].errcode
);
865 smbsr_errno(sr
, errnum
);