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 /* 22*8934SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #include <smbsrv/nterror.h> 275331Samw #include <sys/synch.h> 285331Samw #include <smbsrv/smb_incl.h> 295331Samw #include <smbsrv/smb_fsops.h> 305772Sas200622 #include <sys/nbmlock.h> 315331Samw 327961SNatalie.Li@Sun.COM static int smb_do_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *); 335331Samw 345331Samw /* 355331Samw * smb_com_rename 365331Samw * 375331Samw * Rename a file. Files OldFileName must exist and NewFileName must not. 385331Samw * Both pathnames must be relative to the Tid specified in the request. 395331Samw * Open files may be renamed. 405331Samw * 415331Samw * Multiple files may be renamed in response to a single request as Rename 425331Samw * File supports wildcards in the file name (last component of the path). 435331Samw * NOTE: we don't support rename with wildcards. 445331Samw * 455331Samw * SearchAttributes indicates the attributes that the target file(s) must 465331Samw * have. If SearchAttributes is zero then only normal files are renamed. 475331Samw * If the system file or hidden attributes are specified then the rename 485331Samw * is inclusive - both the specified type(s) of files and normal files are 495331Samw * renamed. The encoding of SearchAttributes is described in section 3.10 505331Samw * - File Attribute Encoding. 515331Samw */ 526030Sjb150015 smb_sdrc_t 536139Sjb150015 smb_pre_rename(smb_request_t *sr) 546139Sjb150015 { 557961SNatalie.Li@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 567961SNatalie.Li@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 576139Sjb150015 int rc; 586139Sjb150015 596139Sjb150015 if ((rc = smbsr_decode_vwv(sr, "w", &src_fqi->srch_attr)) == 0) { 606139Sjb150015 rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->path, 616139Sjb150015 &dst_fqi->path); 626139Sjb150015 636139Sjb150015 dst_fqi->srch_attr = 0; 646139Sjb150015 } 656139Sjb150015 666139Sjb150015 DTRACE_SMB_2(op__Rename__start, smb_request_t *, sr, 676139Sjb150015 struct dirop *, &sr->arg.dirop); 686139Sjb150015 696139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 706139Sjb150015 } 716139Sjb150015 726139Sjb150015 void 736139Sjb150015 smb_post_rename(smb_request_t *sr) 746139Sjb150015 { 756139Sjb150015 DTRACE_SMB_1(op__Rename__done, smb_request_t *, sr); 766139Sjb150015 } 776139Sjb150015 786139Sjb150015 smb_sdrc_t 796139Sjb150015 smb_com_rename(smb_request_t *sr) 805331Samw { 815331Samw static kmutex_t mutex; 827961SNatalie.Li@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 837961SNatalie.Li@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 845331Samw struct smb_node *dst_node; 855331Samw int rc; 865331Samw 875331Samw if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 885772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 895331Samw ERRDOS, ERROR_ACCESS_DENIED); 906139Sjb150015 return (SDRC_ERROR); 915331Samw } 925331Samw 935331Samw mutex_enter(&mutex); 945331Samw rc = smb_do_rename(sr, src_fqi, dst_fqi); 955331Samw mutex_exit(&mutex); 965331Samw 975331Samw if (rc != 0) { 985331Samw /* 996139Sjb150015 * The following values are based on observed WFWG, 1006139Sjb150015 * Windows 9x, NT and Windows 2000 behaviour. 1016139Sjb150015 * ERROR_FILE_EXISTS doesn't work for Windows 98 clients. 1026139Sjb150015 * Windows 95 clients don't see the problem because the 1036139Sjb150015 * target is deleted before the rename request. 1045331Samw */ 1056139Sjb150015 switch (rc) { 1066139Sjb150015 case EEXIST: 1075772Sas200622 smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION, 1085331Samw ERRDOS, ERROR_ALREADY_EXISTS); 1096139Sjb150015 break; 1106139Sjb150015 case EPIPE: 1115772Sas200622 smbsr_error(sr, NT_STATUS_SHARING_VIOLATION, 1125331Samw ERRDOS, ERROR_SHARING_VIOLATION); 1136139Sjb150015 break; 1146139Sjb150015 case ENOENT: 1156139Sjb150015 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 1166139Sjb150015 ERRDOS, ERROR_FILE_NOT_FOUND); 1176139Sjb150015 break; 1186139Sjb150015 default: 1196139Sjb150015 smbsr_errno(sr, rc); 1206139Sjb150015 break; 1215331Samw } 1225331Samw 1236139Sjb150015 return (SDRC_ERROR); 1245331Samw } 1255331Samw 1265331Samw if (src_fqi->dir_snode) 1275331Samw smb_node_release(src_fqi->dir_snode); 1285331Samw 1295331Samw dst_node = dst_fqi->dir_snode; 1305331Samw if (dst_node) { 1315331Samw if (dst_node->flags & NODE_FLAGS_NOTIFY_CHANGE) { 1325331Samw dst_node->flags |= NODE_FLAGS_CHANGED; 1335331Samw smb_process_node_notify_change_queue(dst_node); 1345331Samw } 1355331Samw smb_node_release(dst_node); 1365331Samw } 1375331Samw 1385331Samw SMB_NULL_FQI_NODES(*src_fqi); 1395331Samw SMB_NULL_FQI_NODES(*dst_fqi); 1405331Samw 1416030Sjb150015 rc = smbsr_encode_empty_result(sr); 1426139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1435331Samw } 1445331Samw 1455331Samw /* 1465331Samw * smb_do_rename 1475331Samw * 1485331Samw * Backend to smb_com_rename to ensure that the rename operation is atomic. 1495331Samw * This function should be called within a mutual exclusion region. If the 1505331Samw * source and destination are identical, we don't actually do a rename, we 1515331Samw * just check that the conditions are right. If the source and destination 1525331Samw * files differ only in case, we a case-sensitive rename. Otherwise, we do 1535331Samw * a full case-insensitive rename. 1545331Samw * 1555331Samw * This function should always return errno values. 1565331Samw * 1575331Samw * Upon success, the last_snode's and dir_snode's of both src_fqi and dst_fqi 1585331Samw * are not released in this routine but in smb_com_rename(). 1595331Samw */ 1605331Samw static int 1615331Samw smb_do_rename( 1626139Sjb150015 smb_request_t *sr, 1637961SNatalie.Li@Sun.COM smb_fqi_t *src_fqi, 1647961SNatalie.Li@Sun.COM smb_fqi_t *dst_fqi) 1655331Samw { 1667961SNatalie.Li@Sun.COM smb_node_t *src_node; 1675331Samw char *dstname; 1685331Samw DWORD status; 1695331Samw int rc; 1705331Samw int count; 1715331Samw 1725331Samw if ((rc = smbd_fs_query(sr, src_fqi, FQM_PATH_MUST_EXIST)) != 0) { 1735331Samw return (rc); 1745331Samw } 1755331Samw 1765331Samw src_node = src_fqi->last_snode; 1775331Samw 1785331Samw /* 1795331Samw * Break the oplock before access checks. If a client 1805331Samw * has a file open, this will force a flush or close, 1815331Samw * which may affect the outcome of any share checking. 1825331Samw */ 183*8934SJose.Borrego@Sun.COM (void) smb_oplock_break(src_node, SMB_SESSION_GET_ID(sr->session), 184*8934SJose.Borrego@Sun.COM B_FALSE); 1855331Samw 1865772Sas200622 for (count = 0; count <= 3; count++) { 1875772Sas200622 if (count) { 1885772Sas200622 smb_node_end_crit(src_node); 1895772Sas200622 delay(MSEC_TO_TICK(400)); 1905772Sas200622 } 1915772Sas200622 1925772Sas200622 smb_node_start_crit(src_node, RW_READER); 1935772Sas200622 1945772Sas200622 status = smb_node_rename_check(src_node); 1955772Sas200622 1965772Sas200622 if (status != NT_STATUS_SHARING_VIOLATION) 1975772Sas200622 break; 1985772Sas200622 } 1995772Sas200622 2005772Sas200622 if (status == NT_STATUS_SHARING_VIOLATION) { 2015772Sas200622 smb_node_end_crit(src_node); 2025772Sas200622 2035772Sas200622 smb_node_release(src_node); 2045772Sas200622 smb_node_release(src_fqi->dir_snode); 2055772Sas200622 2065772Sas200622 SMB_NULL_FQI_NODES(*src_fqi); 2075772Sas200622 SMB_NULL_FQI_NODES(*dst_fqi); 2085772Sas200622 return (EPIPE); /* = ERRbadshare */ 2095772Sas200622 } 2105772Sas200622 2117348SJose.Borrego@Sun.COM status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE); 2125772Sas200622 2135331Samw if (status != NT_STATUS_SUCCESS) { 2145772Sas200622 smb_node_end_crit(src_node); 2155772Sas200622 2165331Samw smb_node_release(src_node); 2175331Samw smb_node_release(src_fqi->dir_snode); 2185331Samw 2195331Samw SMB_NULL_FQI_NODES(*src_fqi); 2205331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2215331Samw return (EACCES); 2225331Samw } 2235331Samw 2245331Samw if (utf8_strcasecmp(src_fqi->path, dst_fqi->path) == 0) { 2255331Samw if ((rc = smbd_fs_query(sr, dst_fqi, 0)) != 0) { 2265772Sas200622 smb_node_end_crit(src_node); 2275772Sas200622 2285772Sas200622 smb_node_release(src_node); 2295331Samw smb_node_release(src_fqi->dir_snode); 2305331Samw 2315331Samw SMB_NULL_FQI_NODES(*src_fqi); 2325331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2335331Samw return (rc); 2345331Samw } 2355331Samw 2365331Samw /* 2375331Samw * Because the fqm parameter to smbd_fs_query() was 0, 2385331Samw * a successful return value means that dst_fqi->last_snode 2395331Samw * may be NULL. 2405331Samw */ 2415331Samw if (dst_fqi->last_snode) 2425331Samw smb_node_release(dst_fqi->last_snode); 2435331Samw 2445331Samw rc = strcmp(src_fqi->last_comp_od, dst_fqi->last_comp); 2455331Samw if (rc == 0) { 2465772Sas200622 smb_node_end_crit(src_node); 2475772Sas200622 2485772Sas200622 smb_node_release(src_node); 2495331Samw smb_node_release(src_fqi->dir_snode); 2505331Samw smb_node_release(dst_fqi->dir_snode); 2515331Samw 2525331Samw SMB_NULL_FQI_NODES(*src_fqi); 2535331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2545331Samw return (0); 2555331Samw } 2565331Samw 2575331Samw rc = smb_fsop_rename(sr, sr->user_cr, 2585331Samw src_fqi->dir_snode, 2595331Samw src_fqi->last_comp_od, 2605331Samw dst_fqi->dir_snode, 2615331Samw dst_fqi->last_comp); 2625331Samw 2635331Samw if (rc != 0) { 2645331Samw smb_node_release(src_fqi->dir_snode); 2655331Samw smb_node_release(dst_fqi->dir_snode); 2665331Samw 2675331Samw SMB_NULL_FQI_NODES(*src_fqi); 2685331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2695331Samw } 2705772Sas200622 2715772Sas200622 smb_node_end_crit(src_node); 2725772Sas200622 2735772Sas200622 smb_node_release(src_node); 2745331Samw return (rc); 2755331Samw } 2765331Samw 2775331Samw rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST); 2785331Samw if (rc != 0) { 2795772Sas200622 smb_node_end_crit(src_node); 2805772Sas200622 2815772Sas200622 smb_node_release(src_node); 2825331Samw smb_node_release(src_fqi->dir_snode); 2835331Samw 2845331Samw SMB_NULL_FQI_NODES(*src_fqi); 2855331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2865331Samw return (rc); 2875331Samw } 2885331Samw 2895331Samw /* 2905331Samw * Because of FQM_PATH_MUST_NOT_EXIST and the successful return 2915331Samw * value, only dst_fqi->dir_snode is valid (dst_fqi->last_snode 2925331Samw * is NULL). 2935331Samw */ 2945331Samw 2955331Samw /* 2965331Samw * Use the unmangled form of the destination name if the 2975331Samw * source and destination names are the same and the source 2985331Samw * name is mangled. (We are taking a chance here, assuming 2995331Samw * that this is what the user wants.) 3005331Samw */ 3015331Samw 3025331Samw if ((smb_maybe_mangled_name(src_fqi->last_comp)) && 3035331Samw (strcmp(src_fqi->last_comp, dst_fqi->last_comp) == 0)) { 3045331Samw dstname = src_fqi->last_comp_od; 3055331Samw } else { 3065331Samw dstname = dst_fqi->last_comp; 3075331Samw } 3085331Samw 3095331Samw rc = smb_fsop_rename(sr, sr->user_cr, 3105331Samw src_fqi->dir_snode, 3115331Samw src_fqi->last_comp_od, 3125331Samw dst_fqi->dir_snode, 3135331Samw dstname); 3145331Samw 3155331Samw if (rc != 0) { 3165331Samw smb_node_release(src_fqi->dir_snode); 3175331Samw smb_node_release(dst_fqi->dir_snode); 3185331Samw 3195331Samw SMB_NULL_FQI_NODES(*src_fqi); 3205331Samw SMB_NULL_FQI_NODES(*dst_fqi); 3215331Samw } 3225331Samw 3235772Sas200622 smb_node_end_crit(src_node); 3245772Sas200622 3255772Sas200622 smb_node_release(src_node); 3265772Sas200622 3275331Samw return (rc); 3285331Samw } 329