xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_rename.c (revision 7348:73b61202d5d6)
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