diff options
Diffstat (limited to 'usr/src/uts/common/fs/smbsrv/smb_rename.c')
-rw-r--r-- | usr/src/uts/common/fs/smbsrv/smb_rename.c | 675 |
1 files changed, 422 insertions, 253 deletions
diff --git a/usr/src/uts/common/fs/smbsrv/smb_rename.c b/usr/src/uts/common/fs/smbsrv/smb_rename.c index 6da6809374..1a88f12700 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_rename.c +++ b/usr/src/uts/common/fs/smbsrv/smb_rename.c @@ -23,9 +23,8 @@ * Use is subject to license terms. */ -#include <smbsrv/nterror.h> #include <sys/synch.h> -#include <smbsrv/smb_incl.h> +#include <smbsrv/smb_kproto.h> #include <smbsrv/smb_fsops.h> #include <sys/nbmlock.h> @@ -42,11 +41,20 @@ #define SMB_NT_RENAME_RENAME_FILE 0x0104 #define SMB_NT_RENAME_MOVE_FILE 0x0105 -static int smb_do_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *); +/* + * SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag + */ +#define SMB_RENAME_FLAG_OVERWRITE 0x001 + +static int smb_common_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *); static int smb_make_link(smb_request_t *, smb_fqi_t *, smb_fqi_t *); +static int smb_rename_check_stream(smb_fqi_t *, smb_fqi_t *); static int smb_rename_check_attr(smb_request_t *, smb_node_t *, uint16_t); static void smb_rename_set_error(smb_request_t *, int); +static int smb_rename_lookup_src(smb_request_t *); +static void smb_rename_release_src(smb_request_t *); + /* * smb_com_rename * @@ -62,8 +70,7 @@ static void smb_rename_set_error(smb_request_t *, int); * have. If SearchAttributes is zero then only normal files are renamed. * If the system file or hidden attributes are specified then the rename * is inclusive - both the specified type(s) of files and normal files are - * renamed. The encoding of SearchAttributes is described in section 3.10 - * - File Attribute Encoding. + * renamed. */ smb_sdrc_t smb_pre_rename(smb_request_t *sr) @@ -104,7 +111,7 @@ smb_com_rename(smb_request_t *sr) return (SDRC_ERROR); } - rc = smb_do_rename(sr, src_fqi, dst_fqi); + rc = smb_common_rename(sr, src_fqi, dst_fqi); if (rc != 0) { smb_rename_set_error(sr, rc); @@ -116,208 +123,17 @@ smb_com_rename(smb_request_t *sr) } /* - * smb_do_rename - * - * Common code for renaming a file. - * - * If the source and destination are identical, we go through all - * the checks but we don't actually do the rename. If the source - * and destination files differ only in case, we do a case-sensitive - * rename. Otherwise, we do a full case-insensitive rename. - * - * Returns errno values. - */ -static int -smb_do_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) -{ - smb_node_t *src_node, *tnode; - char *dstname; - DWORD status; - int rc; - int count; - char *path; - - tnode = sr->tid_tree->t_snode; - - /* Lookup the source node. It MUST exist. */ - path = src_fqi->fq_path.pn_path; - rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, - &src_fqi->fq_dnode, src_fqi->fq_last_comp); - if (rc != 0) - return (rc); - - rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode, - src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode); - if (rc != 0) { - smb_node_release(src_fqi->fq_dnode); - return (rc); - } - - src_node = src_fqi->fq_fnode; - rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr); - if (rc != 0) { - smb_node_release(src_fqi->fq_fnode); - smb_node_release(src_fqi->fq_dnode); - return (rc); - } - - /* - * Break the oplock before access checks. If a client - * has a file open, this will force a flush or close, - * which may affect the outcome of any share checking. - */ - (void) smb_oplock_break(src_node, sr->session, B_FALSE); - - for (count = 0; count <= 3; count++) { - if (count) { - smb_node_end_crit(src_node); - delay(MSEC_TO_TICK(400)); - } - - smb_node_start_crit(src_node, RW_READER); - - status = smb_node_rename_check(src_node); - - if (status != NT_STATUS_SHARING_VIOLATION) - break; - } - - if (status == NT_STATUS_SHARING_VIOLATION) { - smb_node_end_crit(src_node); - smb_node_release(src_fqi->fq_fnode); - smb_node_release(src_fqi->fq_dnode); - return (EPIPE); /* = ERRbadshare */ - } - - status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE); - - if (status != NT_STATUS_SUCCESS) { - smb_node_end_crit(src_node); - smb_node_release(src_fqi->fq_fnode); - smb_node_release(src_fqi->fq_dnode); - return (EACCES); - } - - /* Lookup destination node. */ - path = dst_fqi->fq_path.pn_path; - rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, - &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); - if (rc != 0) { - smb_node_end_crit(src_node); - smb_node_release(src_fqi->fq_fnode); - smb_node_release(src_fqi->fq_dnode); - return (rc); - } - - rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode, - dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode); - if ((rc != 0) && (rc != ENOENT)) { - smb_node_end_crit(src_node); - smb_node_release(src_fqi->fq_fnode); - smb_node_release(src_fqi->fq_dnode); - smb_node_release(dst_fqi->fq_dnode); - return (rc); - } - - if (utf8_strcasecmp(src_fqi->fq_path.pn_path, - dst_fqi->fq_path.pn_path) == 0) { - - if (dst_fqi->fq_fnode) - smb_node_release(dst_fqi->fq_fnode); - - rc = strcmp(src_fqi->fq_fnode->od_name, dst_fqi->fq_last_comp); - if (rc == 0) { - smb_node_end_crit(src_node); - smb_node_release(src_fqi->fq_fnode); - smb_node_release(src_fqi->fq_dnode); - smb_node_release(dst_fqi->fq_dnode); - return (0); - } - - rc = smb_fsop_rename(sr, sr->user_cr, - src_fqi->fq_dnode, src_fqi->fq_fnode->od_name, - dst_fqi->fq_dnode, dst_fqi->fq_last_comp); - - smb_node_end_crit(src_node); - if (rc == 0) - smb_node_notify_change(dst_fqi->fq_dnode); - smb_node_release(src_fqi->fq_fnode); - smb_node_release(src_fqi->fq_dnode); - smb_node_release(dst_fqi->fq_dnode); - return (rc); - } - - /* dst node must not exist */ - if (dst_fqi->fq_fnode) { - smb_node_end_crit(src_node); - smb_node_release(src_fqi->fq_fnode); - smb_node_release(src_fqi->fq_dnode); - smb_node_release(dst_fqi->fq_fnode); - smb_node_release(dst_fqi->fq_dnode); - return (EEXIST); - } - - /* - * If the source name is mangled but the source and destination - * on-disk names are identical, we'll use the on-disk name. - */ - if ((smb_maybe_mangled_name(src_fqi->fq_last_comp)) && - (strcmp(src_fqi->fq_last_comp, dst_fqi->fq_last_comp) == 0)) { - dstname = src_fqi->fq_fnode->od_name; - } else { - dstname = dst_fqi->fq_last_comp; - } - - rc = smb_fsop_rename(sr, sr->user_cr, - src_fqi->fq_dnode, src_fqi->fq_fnode->od_name, - dst_fqi->fq_dnode, dstname); - - smb_node_end_crit(src_node); - if (rc == 0) - smb_node_notify_change(dst_fqi->fq_dnode); - smb_node_release(src_fqi->fq_fnode); - smb_node_release(src_fqi->fq_dnode); - smb_node_release(dst_fqi->fq_dnode); - return (rc); -} - -/* * smb_com_nt_rename * * Rename a file. Files OldFileName must exist and NewFileName must not. * Both pathnames must be relative to the Tid specified in the request. * Open files may be renamed. * - * Multiple files may be renamed in response to a single request as Rename - * File supports wildcards in the file name (last component of the path). - * NOTE: we don't support rename with wildcards. - * * SearchAttributes indicates the attributes that the target file(s) must * have. If SearchAttributes is zero then only normal files are renamed. * If the system file or hidden attributes are specified then the rename * is inclusive - both the specified type(s) of files and normal files are - * renamed. The encoding of SearchAttributes is described in section 3.10 - * - File Attribute Encoding. - * - * Client Request Description - * ================================= ================================== - * UCHAR WordCount; Count of parameter words = 4 - * USHORT SearchAttributes; - * USHORT InformationLevel; 0x0103 Create a hard link - * 0x0104 In-place rename - * 0x0105 Move (rename) a file - * ULONG ClusterCount Servers should ignore this value - * USHORT ByteCount; Count of data bytes; min = 4 - * UCHAR Buffer[]; Buffer containing: - * UCHAR BufferFormat1 0x04 - * UCHAR OldFileName[] OldFileName - * UCHAR BufferFormat1 0x04 - * UCHAR OldFileName[] NewFileName - * - * Server Response Description - * ================================= ================================== - * UCHAR WordCount; Count of parameter words = 0 - * UCHAR ByteCount; Count of data bytes = 0 + * renamed. */ smb_sdrc_t smb_pre_nt_rename(smb_request_t *sr) @@ -373,7 +189,7 @@ smb_com_nt_rename(smb_request_t *sr) break; case SMB_NT_RENAME_RENAME_FILE: case SMB_NT_RENAME_MOVE_FILE: - rc = smb_do_rename(sr, src_fqi, dst_fqi); + rc = smb_common_rename(sr, src_fqi, dst_fqi); break; case SMB_NT_RENAME_MOVE_CLUSTER_INFO: rc = EINVAL; @@ -393,43 +209,423 @@ smb_com_nt_rename(smb_request_t *sr) } /* + * smb_nt_transact_rename + * + * Windows servers return SUCCESS without renaming file. + * The only check required is to check that the handle (fid) is valid. + */ +smb_sdrc_t +smb_nt_transact_rename(smb_request_t *sr, smb_xa_t *xa) +{ + if (smb_mbc_decodef(&xa->req_param_mb, "w", &sr->smb_fid) != 0) + return (SDRC_ERROR); + + smbsr_lookup_file(sr); + if (sr->fid_ofile == NULL) { + smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); + return (SDRC_ERROR); + } + smbsr_release_file(sr); + + return (SDRC_SUCCESS); +} + +/* + * smb_trans2_rename + * + * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo + * and Trans2_Set_PathInfo. + * If the new filename (dst_fqi) already exists it may be overwritten + * if flags == 1. + */ +int +smb_trans2_rename(smb_request_t *sr, smb_node_t *node, char *fname, int flags) +{ + int rc; + smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; + smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; + + sr->arg.dirop.flags = flags ? SMB_RENAME_FLAG_OVERWRITE : 0; + sr->arg.dirop.info_level = SMB_NT_RENAME_RENAME_FILE; + + src_fqi->fq_sattr = SMB_SEARCH_ATTRIBUTES; + src_fqi->fq_fnode = node; + src_fqi->fq_dnode = node->n_dnode; + + dst_fqi->fq_path.pn_path = fname; + dst_fqi->fq_dnode = node->n_dnode; + (void) strlcpy(dst_fqi->fq_last_comp, fname, MAXNAMELEN); + + rc = smb_common_rename(sr, src_fqi, dst_fqi); + if (rc != 0) { + smb_rename_set_error(sr, rc); + return (-1); + } + + return (0); +} + +/* + * smb_common_rename + * + * Common code for renaming a file. + * + * If the source and destination are identical, we go through all + * the checks but we don't actually do the rename. If the source + * and destination files differ only in case, we do a case-sensitive + * rename. Otherwise, we do a full case-insensitive rename. + * + * Returns errno values. + */ +static int +smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) +{ + smb_node_t *src_fnode, *src_dnode, *dst_fnode, *dst_dnode; + smb_node_t *tnode; + int rc, count; + DWORD status; + char *new_name, *path; + + path = dst_fqi->fq_path.pn_path; + + /* Check if attempting to rename a stream - not yet supported */ + rc = smb_rename_check_stream(src_fqi, dst_fqi); + if (rc != 0) + return (rc); + + /* The source node may already have been provided */ + if (src_fqi->fq_fnode) { + smb_node_start_crit(src_fqi->fq_fnode, RW_READER); + smb_node_ref(src_fqi->fq_fnode); + smb_node_ref(src_fqi->fq_dnode); + } else { + /* lookup and validate src node */ + rc = smb_rename_lookup_src(sr); + if (rc != 0) + return (rc); + } + + src_fnode = src_fqi->fq_fnode; + src_dnode = src_fqi->fq_dnode; + + /* Find destination dnode and last_comp */ + if (dst_fqi->fq_dnode) { + smb_node_ref(dst_fqi->fq_dnode); + } else { + tnode = sr->tid_tree->t_snode; + rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, + &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); + if (rc != 0) { + smb_rename_release_src(sr); + return (rc); + } + } + + dst_dnode = dst_fqi->fq_dnode; + new_name = dst_fqi->fq_last_comp; + + /* If exact name match in same directory, we're done */ + if ((src_dnode == dst_dnode) && + (strcmp(src_fnode->od_name, new_name) == 0)) { + smb_rename_release_src(sr); + smb_node_release(dst_dnode); + return (0); + } + + /* Lookup destination node */ + rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, + dst_dnode, new_name, &dst_fqi->fq_fnode); + + /* + * Handle case where changing case of the same directory entry. + * + * If we found the dst node in the same directory as the src node, + * and their names differ only in case: + * + * If the tree is case sensitive (or mixed): + * Do case sensitive lookup to see if exact match exists. + * If the exact match is the same node as src_node we're done. + * + * If the tree is case insensitive: + * There is currently no way to tell if the case is different + * or not, so do the rename (unless the specified new name was + * mangled). + */ + if ((rc == 0) && + (src_dnode == dst_dnode) && + (smb_strcasecmp(src_fnode->od_name, + dst_fqi->fq_fnode->od_name, 0) == 0)) { + smb_node_release(dst_fqi->fq_fnode); + dst_fqi->fq_fnode = NULL; + + if (smb_tree_has_feature(sr->tid_tree, + SMB_TREE_NO_CASESENSITIVE)) { + if (smb_strcasecmp(src_fnode->od_name, + dst_fqi->fq_last_comp, 0) != 0) { + smb_rename_release_src(sr); + smb_node_release(dst_dnode); + return (0); + } + } else { + rc = smb_fsop_lookup(sr, sr->user_cr, + SMB_CASE_SENSITIVE, tnode, dst_dnode, new_name, + &dst_fqi->fq_fnode); + + if ((rc == 0) && + (dst_fqi->fq_fnode == src_fnode)) { + smb_rename_release_src(sr); + smb_node_release(dst_fqi->fq_fnode); + smb_node_release(dst_dnode); + return (0); + } + } + } + + if ((rc != 0) && (rc != ENOENT)) { + smb_rename_release_src(sr); + smb_node_release(dst_fqi->fq_dnode); + return (rc); + } + + if (dst_fqi->fq_fnode) { + dst_fnode = dst_fqi->fq_fnode; + + if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) { + smb_rename_release_src(sr); + smb_node_release(dst_fnode); + smb_node_release(dst_dnode); + return (EEXIST); + } + + (void) smb_oplock_break(dst_fnode, sr->session, B_FALSE); + + for (count = 0; count <= 3; count++) { + if (count) { + smb_node_end_crit(dst_fnode); + delay(MSEC_TO_TICK(400)); + } + + smb_node_start_crit(dst_fnode, RW_READER); + status = smb_node_delete_check(dst_fnode); + + if (status != NT_STATUS_SHARING_VIOLATION) + break; + } + + if (status != NT_STATUS_SHARING_VIOLATION) + status = smb_range_check(sr, dst_fnode, + 0, UINT64_MAX, B_TRUE); + + if (status != NT_STATUS_SUCCESS) { + smb_rename_release_src(sr); + smb_node_end_crit(dst_fnode); + smb_node_release(dst_fnode); + smb_node_release(dst_dnode); + return (EACCES); + } + + if (smb_maybe_mangled_name(new_name)) { + (void) strlcpy(new_name, dst_fnode->od_name, + MAXNAMELEN); + } + } + + rc = smb_fsop_rename(sr, sr->user_cr, + src_dnode, src_fnode->od_name, + dst_dnode, new_name); + + smb_rename_release_src(sr); + + if (rc == 0) + smb_node_notify_change(dst_dnode); + + if (dst_fqi->fq_fnode) { + smb_node_end_crit(dst_fnode); + smb_node_release(dst_fnode); + } + smb_node_release(dst_dnode); + + return (rc); +} + +/* + * smb_rename_check_stream + * + * For a stream rename the dst path must begin with ':', or "\\:". + * We don't yet support stream rename, Return EACCES. + * + * If not a stream rename, in accordance with the above rule, + * it is not valid for either the src or dst to be a stream. + * Return EINVAL. + */ +static int +smb_rename_check_stream(smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) +{ + smb_node_t *src_fnode = src_fqi->fq_fnode; + char *src_path = src_fqi->fq_path.pn_path; + char *dst_path = dst_fqi->fq_path.pn_path; + + /* We do not yet support named stream rename - ACCESS DENIED */ + if ((dst_path[0] == ':') || + ((dst_path[0] == '\\') && (dst_path[1] == ':'))) { + return (EACCES); + } + + /* + * If not stream rename (above) neither src or dst can be + * a named stream. + */ + + if (smb_is_stream_name(dst_path)) + return (EINVAL); + + if (src_fqi->fq_fnode) { + if (SMB_IS_STREAM(src_fnode)) + return (EINVAL); + } else { + if (smb_is_stream_name(src_path)) + return (EINVAL); + } + + return (0); +} + + +/* * smb_make_link * - * Common code for creating a hard link (adding an additional name - * for a file. + * Creating a hard link (adding an additional name) for a file. * * If the source and destination are identical, we go through all * the checks but we don't create a link. * + * If the file is a symlink we create the hardlink on the target + * of the symlink (i.e. use SMB_FOLLOW_LINKS when looking up src). + * If the target of the symlink does not exist we fail with ENOENT. + * * Returns errno values. */ static int smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) { - smb_node_t *src_fnode, *tnode; + smb_node_t *tnode; + char *path; + int rc; + + /* Cannnot create link on named stream */ + if (smb_is_stream_name(src_fqi->fq_path.pn_path) || + smb_is_stream_name(dst_fqi->fq_path.pn_path)) { + return (EINVAL); + } + + /* lookup and validate src node */ + rc = smb_rename_lookup_src(sr); + if (rc != 0) + return (rc); + + /* if src and dest paths match we're done */ + if (smb_strcasecmp(src_fqi->fq_path.pn_path, + dst_fqi->fq_path.pn_path, 0) == 0) { + smb_rename_release_src(sr); + return (0); + } + + /* find the destination dnode and last_comp */ + tnode = sr->tid_tree->t_snode; + path = dst_fqi->fq_path.pn_path; + rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, + &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); + if (rc != 0) { + smb_rename_release_src(sr); + return (rc); + } + + /* If name match in same directory, we're done */ + if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) && + (smb_strcasecmp(src_fqi->fq_fnode->od_name, + dst_fqi->fq_last_comp, 0) == 0)) { + smb_rename_release_src(sr); + smb_node_release(dst_fqi->fq_dnode); + return (0); + } + + /* Lookup the destination node. It MUST NOT exist. */ + rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, + dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode); + if (rc == 0) { + smb_node_release(dst_fqi->fq_fnode); + rc = EEXIST; + } + if (rc != ENOENT) { + smb_rename_release_src(sr); + smb_node_release(dst_fqi->fq_dnode); + return (rc); + } + + rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode, + dst_fqi->fq_dnode, dst_fqi->fq_last_comp); + + smb_rename_release_src(sr); + if (rc == 0) + smb_node_notify_change(dst_fqi->fq_dnode); + smb_node_release(dst_fqi->fq_dnode); + return (rc); +} + +/* + * smb_rename_lookup_src + * + * Lookup the src node, checking for sharing violations and + * breaking any existing oplock. + * Populate sr->arg.dirop.fqi + * + * Upon success, the dnode and fnode will have holds and the + * fnode will be in a critical section. These should be + * released using smb_rename_release_src(). + * + * Returns errno values. + */ +static int +smb_rename_lookup_src(smb_request_t *sr) +{ + smb_node_t *src_node, *tnode; DWORD status; int rc; int count; char *path; - tnode = sr->tid_tree->t_snode; + struct dirop *dirop = &sr->arg.dirop; + smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; + + if (smb_is_stream_name(src_fqi->fq_path.pn_path)) + return (EINVAL); - /* Lookup the source node. It MUST exist. */ + /* Lookup the source node */ + tnode = sr->tid_tree->t_snode; path = src_fqi->fq_path.pn_path; rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, &src_fqi->fq_dnode, src_fqi->fq_last_comp); if (rc != 0) return (rc); - rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode, + rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode); if (rc != 0) { smb_node_release(src_fqi->fq_dnode); return (rc); } - src_fnode = src_fqi->fq_fnode; - rc = smb_rename_check_attr(sr, src_fnode, src_fqi->fq_sattr); + /* Not valid to create hardlink for directory */ + if ((dirop->info_level == SMB_NT_RENAME_SET_LINK_INFO) && + (smb_node_is_dir(src_fqi->fq_fnode))) { + smb_node_release(src_fqi->fq_fnode); + smb_node_release(src_fqi->fq_dnode); + return (EISDIR); + } + + src_node = src_fqi->fq_fnode; + + rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr); if (rc != 0) { smb_node_release(src_fqi->fq_fnode); smb_node_release(src_fqi->fq_dnode); @@ -441,81 +637,53 @@ smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) * has a file open, this will force a flush or close, * which may affect the outcome of any share checking. */ - (void) smb_oplock_break(src_fnode, sr->session, B_FALSE); + (void) smb_oplock_break(src_node, sr->session, B_FALSE); for (count = 0; count <= 3; count++) { if (count) { - smb_node_end_crit(src_fnode); + smb_node_end_crit(src_node); delay(MSEC_TO_TICK(400)); } - smb_node_start_crit(src_fnode, RW_READER); - status = smb_node_rename_check(src_fnode); + smb_node_start_crit(src_node, RW_READER); + status = smb_node_rename_check(src_node); if (status != NT_STATUS_SHARING_VIOLATION) break; } if (status == NT_STATUS_SHARING_VIOLATION) { - smb_node_end_crit(src_fnode); + smb_node_end_crit(src_node); smb_node_release(src_fqi->fq_fnode); smb_node_release(src_fqi->fq_dnode); return (EPIPE); /* = ERRbadshare */ } - status = smb_range_check(sr, src_fnode, 0, UINT64_MAX, B_TRUE); + status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE); if (status != NT_STATUS_SUCCESS) { - smb_node_end_crit(src_fnode); + smb_node_end_crit(src_node); smb_node_release(src_fqi->fq_fnode); smb_node_release(src_fqi->fq_dnode); return (EACCES); } - if (utf8_strcasecmp(src_fqi->fq_path.pn_path, - dst_fqi->fq_path.pn_path) == 0) { - smb_node_end_crit(src_fnode); - smb_node_release(src_fqi->fq_fnode); - smb_node_release(src_fqi->fq_dnode); - return (0); - } - - /* Lookup the destination node. It MUST NOT exist. */ - path = dst_fqi->fq_path.pn_path; - rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, - &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); - if (rc != 0) { - smb_node_end_crit(src_fnode); - smb_node_release(src_fqi->fq_fnode); - smb_node_release(src_fqi->fq_dnode); - return (rc); - } - - rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode, - dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode); - if (rc == 0) { - smb_node_release(dst_fqi->fq_fnode); - rc = EEXIST; - } - if (rc != ENOENT) { - smb_node_end_crit(src_fnode); - smb_node_release(src_fqi->fq_fnode); - smb_node_release(src_fqi->fq_dnode); - smb_node_release(dst_fqi->fq_dnode); - return (rc); - } + return (0); +} - rc = smb_fsop_link(sr, sr->user_cr, dst_fqi->fq_dnode, src_fnode, - dst_fqi->fq_last_comp); +/* + * smb_rename_release_src + */ +static void +smb_rename_release_src(smb_request_t *sr) +{ + smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; - smb_node_end_crit(src_fnode); - if (rc == 0) - smb_node_notify_change(dst_fqi->fq_dnode); + smb_node_end_crit(src_fqi->fq_fnode); smb_node_release(src_fqi->fq_fnode); smb_node_release(src_fqi->fq_dnode); - smb_node_release(dst_fqi->fq_dnode); - return (rc); } + static int smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr) { @@ -558,6 +726,7 @@ smb_rename_set_error(smb_request_t *sr, int errnum) { ESRCH, ERROR_FILE_NOT_FOUND, NT_STATUS_NO_SUCH_FILE }, { EINVAL, ERROR_INVALID_PARAMETER, NT_STATUS_INVALID_PARAMETER }, { EACCES, ERROR_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED }, + { EISDIR, ERROR_ACCESS_DENIED, NT_STATUS_FILE_IS_A_DIRECTORY }, { EIO, ERROR_INTERNAL_ERROR, NT_STATUS_INTERNAL_ERROR } }; |