1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 222c2961f8Sjose borrego * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw #include <smbsrv/nterror.h> 27da6c28aaSamw #include <sys/synch.h> 28da6c28aaSamw #include <smbsrv/smb_incl.h> 29da6c28aaSamw #include <smbsrv/smb_fsops.h> 30dc20a302Sas200622 #include <sys/nbmlock.h> 31da6c28aaSamw 32b89a8333Snatalie li - Sun Microsystems - Irvine United States static int smb_do_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *); 33da6c28aaSamw 34da6c28aaSamw /* 35da6c28aaSamw * smb_com_rename 36da6c28aaSamw * 37da6c28aaSamw * Rename a file. Files OldFileName must exist and NewFileName must not. 38da6c28aaSamw * Both pathnames must be relative to the Tid specified in the request. 39da6c28aaSamw * Open files may be renamed. 40da6c28aaSamw * 41da6c28aaSamw * Multiple files may be renamed in response to a single request as Rename 42da6c28aaSamw * File supports wildcards in the file name (last component of the path). 43da6c28aaSamw * NOTE: we don't support rename with wildcards. 44da6c28aaSamw * 45da6c28aaSamw * SearchAttributes indicates the attributes that the target file(s) must 46da6c28aaSamw * have. If SearchAttributes is zero then only normal files are renamed. 47da6c28aaSamw * If the system file or hidden attributes are specified then the rename 48da6c28aaSamw * is inclusive - both the specified type(s) of files and normal files are 49da6c28aaSamw * renamed. The encoding of SearchAttributes is described in section 3.10 50da6c28aaSamw * - File Attribute Encoding. 51da6c28aaSamw */ 527b59d02dSjb150015 smb_sdrc_t 53faa1795aSjb150015 smb_pre_rename(smb_request_t *sr) 54faa1795aSjb150015 { 55b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 56b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 57faa1795aSjb150015 int rc; 58faa1795aSjb150015 59*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if ((rc = smbsr_decode_vwv(sr, "w", &src_fqi->fq_sattr)) == 0) { 60*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->fq_path.pn_path, 61*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States &dst_fqi->fq_path.pn_path); 62faa1795aSjb150015 63*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States dst_fqi->fq_sattr = 0; 64faa1795aSjb150015 } 65faa1795aSjb150015 66faa1795aSjb150015 DTRACE_SMB_2(op__Rename__start, smb_request_t *, sr, 67faa1795aSjb150015 struct dirop *, &sr->arg.dirop); 68faa1795aSjb150015 69faa1795aSjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 70faa1795aSjb150015 } 71faa1795aSjb150015 72faa1795aSjb150015 void 73faa1795aSjb150015 smb_post_rename(smb_request_t *sr) 74faa1795aSjb150015 { 75faa1795aSjb150015 DTRACE_SMB_1(op__Rename__done, smb_request_t *, sr); 76faa1795aSjb150015 } 77faa1795aSjb150015 78faa1795aSjb150015 smb_sdrc_t 79faa1795aSjb150015 smb_com_rename(smb_request_t *sr) 80da6c28aaSamw { 81da6c28aaSamw static kmutex_t mutex; 82b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 83b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 84da6c28aaSamw struct smb_node *dst_node; 85da6c28aaSamw int rc; 86da6c28aaSamw 87da6c28aaSamw if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 88dc20a302Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 89da6c28aaSamw ERRDOS, ERROR_ACCESS_DENIED); 90faa1795aSjb150015 return (SDRC_ERROR); 91da6c28aaSamw } 92da6c28aaSamw 93da6c28aaSamw mutex_enter(&mutex); 94da6c28aaSamw rc = smb_do_rename(sr, src_fqi, dst_fqi); 95da6c28aaSamw mutex_exit(&mutex); 96da6c28aaSamw 97da6c28aaSamw if (rc != 0) { 98da6c28aaSamw /* 99faa1795aSjb150015 * The following values are based on observed WFWG, 100faa1795aSjb150015 * Windows 9x, NT and Windows 2000 behaviour. 101da6c28aaSamw * ERROR_FILE_EXISTS doesn't work for Windows 98 clients. 102faa1795aSjb150015 * Windows 95 clients don't see the problem because the 103faa1795aSjb150015 * target is deleted before the rename request. 104da6c28aaSamw */ 105faa1795aSjb150015 switch (rc) { 106faa1795aSjb150015 case EEXIST: 107dc20a302Sas200622 smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION, 108da6c28aaSamw ERRDOS, ERROR_ALREADY_EXISTS); 109faa1795aSjb150015 break; 110faa1795aSjb150015 case EPIPE: 111dc20a302Sas200622 smbsr_error(sr, NT_STATUS_SHARING_VIOLATION, 112da6c28aaSamw ERRDOS, ERROR_SHARING_VIOLATION); 113faa1795aSjb150015 break; 114faa1795aSjb150015 case ENOENT: 115faa1795aSjb150015 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 116faa1795aSjb150015 ERRDOS, ERROR_FILE_NOT_FOUND); 117faa1795aSjb150015 break; 118faa1795aSjb150015 default: 119faa1795aSjb150015 smbsr_errno(sr, rc); 120faa1795aSjb150015 break; 121da6c28aaSamw } 122da6c28aaSamw 123faa1795aSjb150015 return (SDRC_ERROR); 124da6c28aaSamw } 125da6c28aaSamw 126*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (src_fqi->fq_dnode) 127*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(src_fqi->fq_dnode); 128da6c28aaSamw 129*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States dst_node = dst_fqi->fq_dnode; 130da6c28aaSamw if (dst_node) { 131da6c28aaSamw if (dst_node->flags & NODE_FLAGS_NOTIFY_CHANGE) { 132da6c28aaSamw dst_node->flags |= NODE_FLAGS_CHANGED; 133da6c28aaSamw smb_process_node_notify_change_queue(dst_node); 134da6c28aaSamw } 135da6c28aaSamw smb_node_release(dst_node); 136da6c28aaSamw } 137da6c28aaSamw 138da6c28aaSamw SMB_NULL_FQI_NODES(*src_fqi); 139da6c28aaSamw SMB_NULL_FQI_NODES(*dst_fqi); 140da6c28aaSamw 1417b59d02dSjb150015 rc = smbsr_encode_empty_result(sr); 142faa1795aSjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 143da6c28aaSamw } 144da6c28aaSamw 145da6c28aaSamw /* 146da6c28aaSamw * smb_do_rename 147da6c28aaSamw * 148da6c28aaSamw * Backend to smb_com_rename to ensure that the rename operation is atomic. 149da6c28aaSamw * This function should be called within a mutual exclusion region. If the 150da6c28aaSamw * source and destination are identical, we don't actually do a rename, we 151da6c28aaSamw * just check that the conditions are right. If the source and destination 152da6c28aaSamw * files differ only in case, we a case-sensitive rename. Otherwise, we do 153da6c28aaSamw * a full case-insensitive rename. 154da6c28aaSamw * 155da6c28aaSamw * This function should always return errno values. 156da6c28aaSamw * 157da6c28aaSamw * Upon success, the last_snode's and dir_snode's of both src_fqi and dst_fqi 158da6c28aaSamw * are not released in this routine but in smb_com_rename(). 159da6c28aaSamw */ 160da6c28aaSamw static int 161da6c28aaSamw smb_do_rename( 162faa1795aSjb150015 smb_request_t *sr, 163b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_fqi_t *src_fqi, 164b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_fqi_t *dst_fqi) 165da6c28aaSamw { 166b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_node_t *src_node; 167da6c28aaSamw char *dstname; 168da6c28aaSamw DWORD status; 169da6c28aaSamw int rc; 170da6c28aaSamw int count; 171da6c28aaSamw 172da6c28aaSamw if ((rc = smbd_fs_query(sr, src_fqi, FQM_PATH_MUST_EXIST)) != 0) { 173da6c28aaSamw return (rc); 174da6c28aaSamw } 175da6c28aaSamw 176*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States src_node = src_fqi->fq_fnode; 177da6c28aaSamw 178da6c28aaSamw /* 179da6c28aaSamw * Break the oplock before access checks. If a client 180da6c28aaSamw * has a file open, this will force a flush or close, 181da6c28aaSamw * which may affect the outcome of any share checking. 182da6c28aaSamw */ 183fc724630SAlan Wright (void) smb_oplock_break(src_node, sr->session, B_FALSE); 184da6c28aaSamw 185dc20a302Sas200622 for (count = 0; count <= 3; count++) { 186dc20a302Sas200622 if (count) { 187dc20a302Sas200622 smb_node_end_crit(src_node); 188dc20a302Sas200622 delay(MSEC_TO_TICK(400)); 189dc20a302Sas200622 } 190dc20a302Sas200622 191dc20a302Sas200622 smb_node_start_crit(src_node, RW_READER); 192dc20a302Sas200622 193dc20a302Sas200622 status = smb_node_rename_check(src_node); 194dc20a302Sas200622 195dc20a302Sas200622 if (status != NT_STATUS_SHARING_VIOLATION) 196dc20a302Sas200622 break; 197dc20a302Sas200622 } 198dc20a302Sas200622 199dc20a302Sas200622 if (status == NT_STATUS_SHARING_VIOLATION) { 200dc20a302Sas200622 smb_node_end_crit(src_node); 201dc20a302Sas200622 202dc20a302Sas200622 smb_node_release(src_node); 203*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(src_fqi->fq_dnode); 204dc20a302Sas200622 205dc20a302Sas200622 SMB_NULL_FQI_NODES(*src_fqi); 206dc20a302Sas200622 SMB_NULL_FQI_NODES(*dst_fqi); 207dc20a302Sas200622 return (EPIPE); /* = ERRbadshare */ 208dc20a302Sas200622 } 209dc20a302Sas200622 210c8ec8eeaSjose borrego status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE); 211dc20a302Sas200622 212da6c28aaSamw if (status != NT_STATUS_SUCCESS) { 213dc20a302Sas200622 smb_node_end_crit(src_node); 214dc20a302Sas200622 215da6c28aaSamw smb_node_release(src_node); 216*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(src_fqi->fq_dnode); 217da6c28aaSamw 218da6c28aaSamw SMB_NULL_FQI_NODES(*src_fqi); 219da6c28aaSamw SMB_NULL_FQI_NODES(*dst_fqi); 220da6c28aaSamw return (EACCES); 221da6c28aaSamw } 222da6c28aaSamw 223*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (utf8_strcasecmp(src_fqi->fq_path.pn_path, 224*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States dst_fqi->fq_path.pn_path) == 0) { 225da6c28aaSamw if ((rc = smbd_fs_query(sr, dst_fqi, 0)) != 0) { 226dc20a302Sas200622 smb_node_end_crit(src_node); 227dc20a302Sas200622 228dc20a302Sas200622 smb_node_release(src_node); 229*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(src_fqi->fq_dnode); 230da6c28aaSamw 231da6c28aaSamw SMB_NULL_FQI_NODES(*src_fqi); 232da6c28aaSamw SMB_NULL_FQI_NODES(*dst_fqi); 233da6c28aaSamw return (rc); 234da6c28aaSamw } 235da6c28aaSamw 236da6c28aaSamw /* 237da6c28aaSamw * Because the fqm parameter to smbd_fs_query() was 0, 238*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * a successful return value means that dst_fqi->fq_fnode 239da6c28aaSamw * may be NULL. 240da6c28aaSamw */ 241*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if (dst_fqi->fq_fnode) 242*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(dst_fqi->fq_fnode); 243da6c28aaSamw 244*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States rc = strcmp(src_fqi->fq_od_name, dst_fqi->fq_last_comp); 245da6c28aaSamw if (rc == 0) { 246dc20a302Sas200622 smb_node_end_crit(src_node); 247dc20a302Sas200622 248dc20a302Sas200622 smb_node_release(src_node); 249*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(src_fqi->fq_dnode); 250*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(dst_fqi->fq_dnode); 251da6c28aaSamw 252da6c28aaSamw SMB_NULL_FQI_NODES(*src_fqi); 253da6c28aaSamw SMB_NULL_FQI_NODES(*dst_fqi); 254da6c28aaSamw return (0); 255da6c28aaSamw } 256da6c28aaSamw 257da6c28aaSamw rc = smb_fsop_rename(sr, sr->user_cr, 258*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States src_fqi->fq_dnode, 259*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States src_fqi->fq_od_name, 260*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States dst_fqi->fq_dnode, 261*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States dst_fqi->fq_last_comp); 262da6c28aaSamw 263da6c28aaSamw if (rc != 0) { 264*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(src_fqi->fq_dnode); 265*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(dst_fqi->fq_dnode); 266da6c28aaSamw 267da6c28aaSamw SMB_NULL_FQI_NODES(*src_fqi); 268da6c28aaSamw SMB_NULL_FQI_NODES(*dst_fqi); 269da6c28aaSamw } 270dc20a302Sas200622 271dc20a302Sas200622 smb_node_end_crit(src_node); 272dc20a302Sas200622 273dc20a302Sas200622 smb_node_release(src_node); 274da6c28aaSamw return (rc); 275da6c28aaSamw } 276da6c28aaSamw 277da6c28aaSamw rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST); 278da6c28aaSamw if (rc != 0) { 279dc20a302Sas200622 smb_node_end_crit(src_node); 280dc20a302Sas200622 281dc20a302Sas200622 smb_node_release(src_node); 282*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(src_fqi->fq_dnode); 283da6c28aaSamw 284da6c28aaSamw SMB_NULL_FQI_NODES(*src_fqi); 285da6c28aaSamw SMB_NULL_FQI_NODES(*dst_fqi); 286da6c28aaSamw return (rc); 287da6c28aaSamw } 288da6c28aaSamw 289da6c28aaSamw /* 290da6c28aaSamw * Because of FQM_PATH_MUST_NOT_EXIST and the successful return 291*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States * value, only dst_fqi->fq_dnode is valid (dst_fqi->fq_fnode 292da6c28aaSamw * is NULL). 293da6c28aaSamw */ 294da6c28aaSamw 295da6c28aaSamw /* 296da6c28aaSamw * Use the unmangled form of the destination name if the 297da6c28aaSamw * source and destination names are the same and the source 298da6c28aaSamw * name is mangled. (We are taking a chance here, assuming 299da6c28aaSamw * that this is what the user wants.) 300da6c28aaSamw */ 301da6c28aaSamw 302*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States if ((smb_maybe_mangled_name(src_fqi->fq_last_comp)) && 303*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States (strcmp(src_fqi->fq_last_comp, dst_fqi->fq_last_comp) == 0)) { 304*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States dstname = src_fqi->fq_od_name; 305da6c28aaSamw } else { 306*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States dstname = dst_fqi->fq_last_comp; 307da6c28aaSamw } 308da6c28aaSamw 309da6c28aaSamw rc = smb_fsop_rename(sr, sr->user_cr, 310*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States src_fqi->fq_dnode, 311*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States src_fqi->fq_od_name, 312*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States dst_fqi->fq_dnode, 313da6c28aaSamw dstname); 314da6c28aaSamw 315da6c28aaSamw if (rc != 0) { 316*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(src_fqi->fq_dnode); 317*eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_release(dst_fqi->fq_dnode); 318da6c28aaSamw 319da6c28aaSamw SMB_NULL_FQI_NODES(*src_fqi); 320da6c28aaSamw SMB_NULL_FQI_NODES(*dst_fqi); 321da6c28aaSamw } 322da6c28aaSamw 323dc20a302Sas200622 smb_node_end_crit(src_node); 324dc20a302Sas200622 325dc20a302Sas200622 smb_node_release(src_node); 326dc20a302Sas200622 327da6c28aaSamw return (rc); 328da6c28aaSamw } 329