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 26*7348SJose.Borrego@Sun.COM #pragma ident "@(#)smb_rename.c 1.6 08/08/04 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 346139Sjb150015 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 556139Sjb150015 smb_pre_rename(smb_request_t *sr) 566139Sjb150015 { 576139Sjb150015 struct smb_fqi *src_fqi = &sr->arg.dirop.fqi; 586139Sjb150015 struct smb_fqi *dst_fqi = &sr->arg.dirop.dst_fqi; 596139Sjb150015 int rc; 606139Sjb150015 616139Sjb150015 if ((rc = smbsr_decode_vwv(sr, "w", &src_fqi->srch_attr)) == 0) { 626139Sjb150015 rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->path, 636139Sjb150015 &dst_fqi->path); 646139Sjb150015 656139Sjb150015 dst_fqi->srch_attr = 0; 666139Sjb150015 } 676139Sjb150015 686139Sjb150015 DTRACE_SMB_2(op__Rename__start, smb_request_t *, sr, 696139Sjb150015 struct dirop *, &sr->arg.dirop); 706139Sjb150015 716139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 726139Sjb150015 } 736139Sjb150015 746139Sjb150015 void 756139Sjb150015 smb_post_rename(smb_request_t *sr) 766139Sjb150015 { 776139Sjb150015 DTRACE_SMB_1(op__Rename__done, smb_request_t *, sr); 786139Sjb150015 } 796139Sjb150015 806139Sjb150015 smb_sdrc_t 816139Sjb150015 smb_com_rename(smb_request_t *sr) 825331Samw { 835331Samw static kmutex_t mutex; 846139Sjb150015 struct smb_fqi *src_fqi = &sr->arg.dirop.fqi; 856139Sjb150015 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); 926139Sjb150015 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 /* 1016139Sjb150015 * The following values are based on observed WFWG, 1026139Sjb150015 * Windows 9x, NT and Windows 2000 behaviour. 1036139Sjb150015 * ERROR_FILE_EXISTS doesn't work for Windows 98 clients. 1046139Sjb150015 * Windows 95 clients don't see the problem because the 1056139Sjb150015 * target is deleted before the rename request. 1065331Samw */ 1076139Sjb150015 switch (rc) { 1086139Sjb150015 case EEXIST: 1095772Sas200622 smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION, 1105331Samw ERRDOS, ERROR_ALREADY_EXISTS); 1116139Sjb150015 break; 1126139Sjb150015 case EPIPE: 1135772Sas200622 smbsr_error(sr, NT_STATUS_SHARING_VIOLATION, 1145331Samw ERRDOS, ERROR_SHARING_VIOLATION); 1156139Sjb150015 break; 1166139Sjb150015 case ENOENT: 1176139Sjb150015 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 1186139Sjb150015 ERRDOS, ERROR_FILE_NOT_FOUND); 1196139Sjb150015 break; 1206139Sjb150015 default: 1216139Sjb150015 smbsr_errno(sr, rc); 1226139Sjb150015 break; 1235331Samw } 1245331Samw 1256139Sjb150015 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); 1446139Sjb150015 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( 1646139Sjb150015 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 1866600Sas200622 smb_oplock_break(src_node); 1875331Samw 1885772Sas200622 for (count = 0; count <= 3; count++) { 1895772Sas200622 if (count) { 1905772Sas200622 smb_node_end_crit(src_node); 1915772Sas200622 delay(MSEC_TO_TICK(400)); 1925772Sas200622 } 1935772Sas200622 1945772Sas200622 smb_node_start_crit(src_node, RW_READER); 1955772Sas200622 1965772Sas200622 status = smb_node_rename_check(src_node); 1975772Sas200622 1985772Sas200622 if (status != NT_STATUS_SHARING_VIOLATION) 1995772Sas200622 break; 2005772Sas200622 } 2015772Sas200622 2025772Sas200622 if (status == NT_STATUS_SHARING_VIOLATION) { 2035772Sas200622 smb_node_end_crit(src_node); 2045772Sas200622 2055772Sas200622 smb_node_release(src_node); 2065772Sas200622 smb_node_release(src_fqi->dir_snode); 2075772Sas200622 2085772Sas200622 SMB_NULL_FQI_NODES(*src_fqi); 2095772Sas200622 SMB_NULL_FQI_NODES(*dst_fqi); 2105772Sas200622 return (EPIPE); /* = ERRbadshare */ 2115772Sas200622 } 2125772Sas200622 213*7348SJose.Borrego@Sun.COM status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE); 2145772Sas200622 2155331Samw if (status != NT_STATUS_SUCCESS) { 2165772Sas200622 smb_node_end_crit(src_node); 2175772Sas200622 2185331Samw smb_node_release(src_node); 2195331Samw smb_node_release(src_fqi->dir_snode); 2205331Samw 2215331Samw SMB_NULL_FQI_NODES(*src_fqi); 2225331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2235331Samw return (EACCES); 2245331Samw } 2255331Samw 2265331Samw if (utf8_strcasecmp(src_fqi->path, dst_fqi->path) == 0) { 2275331Samw if ((rc = smbd_fs_query(sr, dst_fqi, 0)) != 0) { 2285772Sas200622 smb_node_end_crit(src_node); 2295772Sas200622 2305772Sas200622 smb_node_release(src_node); 2315331Samw smb_node_release(src_fqi->dir_snode); 2325331Samw 2335331Samw SMB_NULL_FQI_NODES(*src_fqi); 2345331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2355331Samw return (rc); 2365331Samw } 2375331Samw 2385331Samw /* 2395331Samw * Because the fqm parameter to smbd_fs_query() was 0, 2405331Samw * a successful return value means that dst_fqi->last_snode 2415331Samw * may be NULL. 2425331Samw */ 2435331Samw if (dst_fqi->last_snode) 2445331Samw smb_node_release(dst_fqi->last_snode); 2455331Samw 2465331Samw rc = strcmp(src_fqi->last_comp_od, dst_fqi->last_comp); 2475331Samw if (rc == 0) { 2485772Sas200622 smb_node_end_crit(src_node); 2495772Sas200622 2505772Sas200622 smb_node_release(src_node); 2515331Samw smb_node_release(src_fqi->dir_snode); 2525331Samw smb_node_release(dst_fqi->dir_snode); 2535331Samw 2545331Samw SMB_NULL_FQI_NODES(*src_fqi); 2555331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2565331Samw return (0); 2575331Samw } 2585331Samw 2595331Samw rc = smb_fsop_rename(sr, sr->user_cr, 2605331Samw src_fqi->dir_snode, 2615331Samw src_fqi->last_comp_od, 2625331Samw dst_fqi->dir_snode, 2635331Samw dst_fqi->last_comp); 2645331Samw 2655331Samw if (rc != 0) { 2665331Samw smb_node_release(src_fqi->dir_snode); 2675331Samw smb_node_release(dst_fqi->dir_snode); 2685331Samw 2695331Samw SMB_NULL_FQI_NODES(*src_fqi); 2705331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2715331Samw } 2725772Sas200622 2735772Sas200622 smb_node_end_crit(src_node); 2745772Sas200622 2755772Sas200622 smb_node_release(src_node); 2765331Samw return (rc); 2775331Samw } 2785331Samw 2795331Samw rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST); 2805331Samw if (rc != 0) { 2815772Sas200622 smb_node_end_crit(src_node); 2825772Sas200622 2835772Sas200622 smb_node_release(src_node); 2845331Samw smb_node_release(src_fqi->dir_snode); 2855331Samw 2865331Samw SMB_NULL_FQI_NODES(*src_fqi); 2875331Samw SMB_NULL_FQI_NODES(*dst_fqi); 2885331Samw return (rc); 2895331Samw } 2905331Samw 2915331Samw /* 2925331Samw * Because of FQM_PATH_MUST_NOT_EXIST and the successful return 2935331Samw * value, only dst_fqi->dir_snode is valid (dst_fqi->last_snode 2945331Samw * is NULL). 2955331Samw */ 2965331Samw 2975331Samw /* 2985331Samw * Use the unmangled form of the destination name if the 2995331Samw * source and destination names are the same and the source 3005331Samw * name is mangled. (We are taking a chance here, assuming 3015331Samw * that this is what the user wants.) 3025331Samw */ 3035331Samw 3045331Samw if ((smb_maybe_mangled_name(src_fqi->last_comp)) && 3055331Samw (strcmp(src_fqi->last_comp, dst_fqi->last_comp) == 0)) { 3065331Samw dstname = src_fqi->last_comp_od; 3075331Samw } else { 3085331Samw dstname = dst_fqi->last_comp; 3095331Samw } 3105331Samw 3115331Samw rc = smb_fsop_rename(sr, sr->user_cr, 3125331Samw src_fqi->dir_snode, 3135331Samw src_fqi->last_comp_od, 3145331Samw dst_fqi->dir_snode, 3155331Samw dstname); 3165331Samw 3175331Samw if (rc != 0) { 3185331Samw smb_node_release(src_fqi->dir_snode); 3195331Samw smb_node_release(dst_fqi->dir_snode); 3205331Samw 3215331Samw SMB_NULL_FQI_NODES(*src_fqi); 3225331Samw SMB_NULL_FQI_NODES(*dst_fqi); 3235331Samw } 3245331Samw 3255772Sas200622 smb_node_end_crit(src_node); 3265772Sas200622 3275772Sas200622 smb_node_release(src_node); 3285772Sas200622 3295331Samw return (rc); 3305331Samw } 331