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