15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 225772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #pragma ident "%Z%%M% %I% %E% SMI" 275331Samw 285331Samw #include <smbsrv/nterror.h> 295331Samw #include <sys/synch.h> 305331Samw #include <smbsrv/smb_incl.h> 315331Samw #include <smbsrv/smb_fsops.h> 325772Sas200622 #include <sys/nbmlock.h> 335331Samw 34*6139Sjb150015 static int smb_do_rename(smb_request_t *, struct smb_fqi *, struct smb_fqi *); 355331Samw 365331Samw /* 375331Samw * smb_com_rename 385331Samw * 395331Samw * Rename a file. Files OldFileName must exist and NewFileName must not. 405331Samw * Both pathnames must be relative to the Tid specified in the request. 415331Samw * Open files may be renamed. 425331Samw * 435331Samw * Multiple files may be renamed in response to a single request as Rename 445331Samw * File supports wildcards in the file name (last component of the path). 455331Samw * NOTE: we don't support rename with wildcards. 465331Samw * 475331Samw * SearchAttributes indicates the attributes that the target file(s) must 485331Samw * have. If SearchAttributes is zero then only normal files are renamed. 495331Samw * If the system file or hidden attributes are specified then the rename 505331Samw * is inclusive - both the specified type(s) of files and normal files are 515331Samw * renamed. The encoding of SearchAttributes is described in section 3.10 525331Samw * - File Attribute Encoding. 535331Samw */ 546030Sjb150015 smb_sdrc_t 55*6139Sjb150015 smb_pre_rename(smb_request_t *sr) 56*6139Sjb150015 { 57*6139Sjb150015 struct smb_fqi *src_fqi = &sr->arg.dirop.fqi; 58*6139Sjb150015 struct smb_fqi *dst_fqi = &sr->arg.dirop.dst_fqi; 59*6139Sjb150015 int rc; 60*6139Sjb150015 61*6139Sjb150015 if ((rc = smbsr_decode_vwv(sr, "w", &src_fqi->srch_attr)) == 0) { 62*6139Sjb150015 rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->path, 63*6139Sjb150015 &dst_fqi->path); 64*6139Sjb150015 65*6139Sjb150015 dst_fqi->srch_attr = 0; 66*6139Sjb150015 } 67*6139Sjb150015 68*6139Sjb150015 DTRACE_SMB_2(op__Rename__start, smb_request_t *, sr, 69*6139Sjb150015 struct dirop *, &sr->arg.dirop); 70*6139Sjb150015 71*6139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 72*6139Sjb150015 } 73*6139Sjb150015 74*6139Sjb150015 void 75*6139Sjb150015 smb_post_rename(smb_request_t *sr) 76*6139Sjb150015 { 77*6139Sjb150015 DTRACE_SMB_1(op__Rename__done, smb_request_t *, sr); 78*6139Sjb150015 } 79*6139Sjb150015 80*6139Sjb150015 smb_sdrc_t 81*6139Sjb150015 smb_com_rename(smb_request_t *sr) 825331Samw { 835331Samw static kmutex_t mutex; 84*6139Sjb150015 struct smb_fqi *src_fqi = &sr->arg.dirop.fqi; 85*6139Sjb150015 struct smb_fqi *dst_fqi = &sr->arg.dirop.dst_fqi; 865331Samw struct smb_node *dst_node; 875331Samw int rc; 885331Samw 895331Samw if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 905772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 915331Samw ERRDOS, ERROR_ACCESS_DENIED); 92*6139Sjb150015 return (SDRC_ERROR); 935331Samw } 945331Samw 955331Samw mutex_enter(&mutex); 965331Samw rc = smb_do_rename(sr, src_fqi, dst_fqi); 975331Samw mutex_exit(&mutex); 985331Samw 995331Samw if (rc != 0) { 1005331Samw /* 101*6139Sjb150015 * The following values are based on observed WFWG, 102*6139Sjb150015 * Windows 9x, NT and Windows 2000 behaviour. 103*6139Sjb150015 * ERROR_FILE_EXISTS doesn't work for Windows 98 clients. 104*6139Sjb150015 * Windows 95 clients don't see the problem because the 105*6139Sjb150015 * target is deleted before the rename request. 1065331Samw */ 107*6139Sjb150015 switch (rc) { 108*6139Sjb150015 case EEXIST: 1095772Sas200622 smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION, 1105331Samw ERRDOS, ERROR_ALREADY_EXISTS); 111*6139Sjb150015 break; 112*6139Sjb150015 case EPIPE: 1135772Sas200622 smbsr_error(sr, NT_STATUS_SHARING_VIOLATION, 1145331Samw ERRDOS, ERROR_SHARING_VIOLATION); 115*6139Sjb150015 break; 116*6139Sjb150015 case ENOENT: 117*6139Sjb150015 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 118*6139Sjb150015 ERRDOS, ERROR_FILE_NOT_FOUND); 119*6139Sjb150015 break; 120*6139Sjb150015 default: 121*6139Sjb150015 smbsr_errno(sr, rc); 122*6139Sjb150015 break; 1235331Samw } 1245331Samw 125*6139Sjb150015 return (SDRC_ERROR); 1265331Samw } 1275331Samw 1285331Samw if (src_fqi->dir_snode) 1295331Samw smb_node_release(src_fqi->dir_snode); 1305331Samw 1315331Samw dst_node = dst_fqi->dir_snode; 1325331Samw if (dst_node) { 1335331Samw if (dst_node->flags & NODE_FLAGS_NOTIFY_CHANGE) { 1345331Samw dst_node->flags |= NODE_FLAGS_CHANGED; 1355331Samw smb_process_node_notify_change_queue(dst_node); 1365331Samw } 1375331Samw smb_node_release(dst_node); 1385331Samw } 1395331Samw 1405331Samw SMB_NULL_FQI_NODES(*src_fqi); 1415331Samw SMB_NULL_FQI_NODES(*dst_fqi); 1425331Samw 1436030Sjb150015 rc = smbsr_encode_empty_result(sr); 144*6139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1455331Samw } 1465331Samw 1475331Samw /* 1485331Samw * smb_do_rename 1495331Samw * 1505331Samw * Backend to smb_com_rename to ensure that the rename operation is atomic. 1515331Samw * This function should be called within a mutual exclusion region. If the 1525331Samw * source and destination are identical, we don't actually do a rename, we 1535331Samw * just check that the conditions are right. If the source and destination 1545331Samw * files differ only in case, we a case-sensitive rename. Otherwise, we do 1555331Samw * a full case-insensitive rename. 1565331Samw * 1575331Samw * This function should always return errno values. 1585331Samw * 1595331Samw * Upon success, the last_snode's and dir_snode's of both src_fqi and dst_fqi 1605331Samw * are not released in this routine but in smb_com_rename(). 1615331Samw */ 1625331Samw static int 1635331Samw smb_do_rename( 164*6139Sjb150015 smb_request_t *sr, 1655331Samw struct smb_fqi *src_fqi, 1665331Samw struct smb_fqi *dst_fqi) 1675331Samw { 1685331Samw struct smb_node *src_node; 1695331Samw char *dstname; 1705331Samw DWORD status; 1715331Samw int rc; 1725331Samw int count; 1735331Samw 1745331Samw if ((rc = smbd_fs_query(sr, src_fqi, FQM_PATH_MUST_EXIST)) != 0) { 1755331Samw return (rc); 1765331Samw } 1775331Samw 1785331Samw src_node = src_fqi->last_snode; 1795331Samw 1805331Samw /* 1815331Samw * Break the oplock before access checks. If a client 1825331Samw * has a file open, this will force a flush or close, 1835331Samw * which may affect the outcome of any share checking. 1845331Samw */ 1855331Samw if (OPLOCKS_IN_FORCE(src_node)) { 1865331Samw status = smb_break_oplock(sr, src_node); 1875331Samw 1885331Samw if (status != NT_STATUS_SUCCESS) { 1895331Samw smb_node_release(src_node); 1905331Samw smb_node_release(src_fqi->dir_snode); 1915331Samw 1925331Samw SMB_NULL_FQI_NODES(*src_fqi); 1935331Samw SMB_NULL_FQI_NODES(*dst_fqi); 1945331Samw return (EACCES); 1955331Samw } 1965331Samw } 1975331Samw 1985772Sas200622 for (count = 0; count <= 3; count++) { 1995772Sas200622 if (count) { 2005772Sas200622 smb_node_end_crit(src_node); 2015772Sas200622 delay(MSEC_TO_TICK(400)); 2025772Sas200622 } 2035772Sas200622 2045772Sas200622 smb_node_start_crit(src_node, RW_READER); 2055772Sas200622 2065772Sas200622 status = smb_node_rename_check(src_node); 2075772Sas200622 2085772Sas200622 if (status != NT_STATUS_SHARING_VIOLATION) 2095772Sas200622 break; 2105772Sas200622 } 2115772Sas200622 2125772Sas200622 if (status == NT_STATUS_SHARING_VIOLATION) { 2135772Sas200622 smb_node_end_crit(src_node); 2145772Sas200622 2155772Sas200622 smb_node_release(src_node); 2165772Sas200622 smb_node_release(src_fqi->dir_snode); 2175772Sas200622 2185772Sas200622 SMB_NULL_FQI_NODES(*src_fqi); 2195772Sas200622 SMB_NULL_FQI_NODES(*dst_fqi); 2205772Sas200622 return (EPIPE); /* = ERRbadshare */ 2215772Sas200622 } 2225772Sas200622 2235772Sas200622 status = smb_range_check(sr, sr->user_cr, src_node, 0, UINT64_MAX, 2245772Sas200622 B_TRUE); 2255772Sas200622 2265331Samw if (status != NT_STATUS_SUCCESS) { 2275772Sas200622 smb_node_end_crit(src_node); 2285772Sas200622 2295331Samw smb_node_release(src_node); 2305331Samw smb_node_release(src_fqi->dir_snode); 2315331Samw 2325331Samw SMB_NULL_FQI_NODES(*src_fqi); 2335331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2345331Samw return (EACCES); 2355331Samw } 2365331Samw 2375331Samw if (utf8_strcasecmp(src_fqi->path, dst_fqi->path) == 0) { 2385331Samw if ((rc = smbd_fs_query(sr, dst_fqi, 0)) != 0) { 2395772Sas200622 smb_node_end_crit(src_node); 2405772Sas200622 2415772Sas200622 smb_node_release(src_node); 2425331Samw smb_node_release(src_fqi->dir_snode); 2435331Samw 2445331Samw SMB_NULL_FQI_NODES(*src_fqi); 2455331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2465331Samw return (rc); 2475331Samw } 2485331Samw 2495331Samw /* 2505331Samw * Because the fqm parameter to smbd_fs_query() was 0, 2515331Samw * a successful return value means that dst_fqi->last_snode 2525331Samw * may be NULL. 2535331Samw */ 2545331Samw if (dst_fqi->last_snode) 2555331Samw smb_node_release(dst_fqi->last_snode); 2565331Samw 2575331Samw rc = strcmp(src_fqi->last_comp_od, dst_fqi->last_comp); 2585331Samw if (rc == 0) { 2595772Sas200622 smb_node_end_crit(src_node); 2605772Sas200622 2615772Sas200622 smb_node_release(src_node); 2625331Samw smb_node_release(src_fqi->dir_snode); 2635331Samw smb_node_release(dst_fqi->dir_snode); 2645331Samw 2655331Samw SMB_NULL_FQI_NODES(*src_fqi); 2665331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2675331Samw return (0); 2685331Samw } 2695331Samw 2705331Samw rc = smb_fsop_rename(sr, sr->user_cr, 2715331Samw src_fqi->dir_snode, 2725331Samw src_fqi->last_comp_od, 2735331Samw dst_fqi->dir_snode, 2745331Samw dst_fqi->last_comp); 2755331Samw 2765331Samw if (rc != 0) { 2775331Samw smb_node_release(src_fqi->dir_snode); 2785331Samw smb_node_release(dst_fqi->dir_snode); 2795331Samw 2805331Samw SMB_NULL_FQI_NODES(*src_fqi); 2815331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2825331Samw } 2835772Sas200622 2845772Sas200622 smb_node_end_crit(src_node); 2855772Sas200622 2865772Sas200622 smb_node_release(src_node); 2875331Samw return (rc); 2885331Samw } 2895331Samw 2905331Samw rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST); 2915331Samw if (rc != 0) { 2925772Sas200622 smb_node_end_crit(src_node); 2935772Sas200622 2945772Sas200622 smb_node_release(src_node); 2955331Samw smb_node_release(src_fqi->dir_snode); 2965331Samw 2975331Samw SMB_NULL_FQI_NODES(*src_fqi); 2985331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2995331Samw return (rc); 3005331Samw } 3015331Samw 3025331Samw /* 3035331Samw * Because of FQM_PATH_MUST_NOT_EXIST and the successful return 3045331Samw * value, only dst_fqi->dir_snode is valid (dst_fqi->last_snode 3055331Samw * is NULL). 3065331Samw */ 3075331Samw 3085331Samw /* 3095331Samw * Use the unmangled form of the destination name if the 3105331Samw * source and destination names are the same and the source 3115331Samw * name is mangled. (We are taking a chance here, assuming 3125331Samw * that this is what the user wants.) 3135331Samw */ 3145331Samw 3155331Samw if ((smb_maybe_mangled_name(src_fqi->last_comp)) && 3165331Samw (strcmp(src_fqi->last_comp, dst_fqi->last_comp) == 0)) { 3175331Samw dstname = src_fqi->last_comp_od; 3185331Samw } else { 3195331Samw dstname = dst_fqi->last_comp; 3205331Samw } 3215331Samw 3225331Samw rc = smb_fsop_rename(sr, sr->user_cr, 3235331Samw src_fqi->dir_snode, 3245331Samw src_fqi->last_comp_od, 3255331Samw dst_fqi->dir_snode, 3265331Samw dstname); 3275331Samw 3285331Samw if (rc != 0) { 3295331Samw smb_node_release(src_fqi->dir_snode); 3305331Samw smb_node_release(dst_fqi->dir_snode); 3315331Samw 3325331Samw SMB_NULL_FQI_NODES(*src_fqi); 3335331Samw SMB_NULL_FQI_NODES(*dst_fqi); 3345331Samw } 3355331Samw 3365772Sas200622 smb_node_end_crit(src_node); 3375772Sas200622 3385772Sas200622 smb_node_release(src_node); 3395772Sas200622 3405331Samw return (rc); 3415331Samw } 342