xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_write.c (revision 5772:237ac22142fe)
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*5772Sas200622  * 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 <sys/sdt.h>
295331Samw #include <smbsrv/smb_incl.h>
305331Samw #include <smbsrv/smb_fsops.h>
315331Samw #include <smbsrv/mbuf.h>
325331Samw #include <smbsrv/netbios.h>
335331Samw 
345331Samw 
355331Samw #define	SMB_WRMODE_WRITE_THRU	0x0001
365331Samw #define	SMB_WRMODE_IS_STABLE(M)	((M) & SMB_WRMODE_WRITE_THRU)
375331Samw 
385331Samw 
395331Samw typedef struct smb_write_param {
405331Samw 	struct vardata_block w_vdb;
415331Samw 	uint64_t w_offset;
425331Samw 	uint16_t w_mode;
435331Samw 	uint16_t w_count;
445331Samw } smb_write_param_t;
455331Samw 
465331Samw 
475331Samw int smb_write_common(struct smb_request *sr, smb_write_param_t *param);
485331Samw int smb_write_truncate(struct smb_request *sr, smb_write_param_t *param);
495331Samw int smb_set_file_size(struct smb_request *sr);
505331Samw 
515331Samw 
525331Samw /*
535331Samw  * Write count bytes at the specified offset in a file.  The offset is
545331Samw  * limited to 32-bits.  If the count is zero, the file is truncated to
555331Samw  * the length specified by the offset.
565331Samw  *
575331Samw  * The response count indicates the actual number of bytes written, which
585331Samw  * will equal the requested count on success.  If request and response
595331Samw  * counts differ but there is no error, the client will assume that the
605331Samw  * server encountered a resource issue.
615331Samw  */
625331Samw int
635331Samw smb_com_write(struct smb_request *sr)
645331Samw {
655331Samw 	smb_write_param_t *param;
665331Samw 	uint32_t off;
675331Samw 	int rc;
685331Samw 
695331Samw 	param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
705331Samw 
715331Samw 	rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &param->w_count, &off);
725331Samw 	if (rc != 0) {
735331Samw 		kmem_free(param, sizeof (smb_write_param_t));
745331Samw 		smbsr_decode_error(sr);
755331Samw 		/* NOTREACHED */
765331Samw 	}
775331Samw 
785331Samw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
795331Samw 	if (sr->fid_ofile == NULL) {
805331Samw 		kmem_free(param, sizeof (smb_write_param_t));
81*5772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
825331Samw 		/* NOTREACHED */
835331Samw 	}
845331Samw 
855331Samw 	param->w_offset = (uint64_t)off;
865521Sas200622 	param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
875331Samw 
885331Samw 	if (param->w_count == 0) {
895331Samw 		rc = smb_write_truncate(sr, param);
905331Samw 	} else {
915331Samw 		rc = smbsr_decode_data(sr, "D", &param->w_vdb);
925331Samw 
935331Samw 		if ((rc != 0) || (param->w_vdb.len != param->w_count)) {
945331Samw 			kmem_free(param, sizeof (smb_write_param_t));
955331Samw 			smbsr_decode_error(sr);
965331Samw 			/* NOTREACHED */
975331Samw 		}
985331Samw 
995521Sas200622 		param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
1005331Samw 
1015331Samw 		rc = smb_write_common(sr, param);
1025331Samw 	}
1035331Samw 
1045331Samw 	if (rc != 0) {
1055331Samw 		kmem_free(param, sizeof (smb_write_param_t));
106*5772Sas200622 		smbsr_errno(sr, rc);
1075331Samw 		/* NOTREACHED */
1085331Samw 	}
1095331Samw 
1105331Samw 	smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0);
1115331Samw 	kmem_free(param, sizeof (smb_write_param_t));
1125331Samw 	return (SDRC_NORMAL_REPLY);
1135331Samw }
1145331Samw 
1155331Samw /*
1165331Samw  * Write count bytes to a file and then close the file.  This function
1175331Samw  * can only be used to write to 32-bit offsets and the client must set
1185331Samw  * WordCount (6 or 12) correctly in order to locate the data to be
1195331Samw  * written.  If an error occurs on the write, the file should still be
1205331Samw  * closed.  If Count is 0, the file is truncated (or extended) to offset.
1215331Samw  *
1225331Samw  * If the last_write time is non-zero, last_write should be used to set
1235331Samw  * the mtime.  Otherwise the file system stamps the mtime.  Failure to
1245331Samw  * set mtime should not result in an error response.
1255331Samw  */
1265331Samw int
1275331Samw smb_com_write_and_close(struct smb_request *sr)
1285331Samw {
1295331Samw 	smb_write_param_t *param;
1305331Samw 	uint32_t last_write;
1315331Samw 	uint32_t off;
1325331Samw 	int rc = 0;
1335331Samw 
1345331Samw 	param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
1355331Samw 
1365331Samw 	if (sr->smb_wct == 12) {
1375331Samw 		rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid,
1385331Samw 		    &param->w_count, &off, &last_write);
1395331Samw 	} else {
1405331Samw 		rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid,
1415331Samw 		    &param->w_count, &off, &last_write);
1425331Samw 	}
1435331Samw 
1445331Samw 	if (rc != 0) {
1455331Samw 		kmem_free(param, sizeof (smb_write_param_t));
1465331Samw 		smbsr_decode_error(sr);
1475331Samw 		/* NOTREACHED */
1485331Samw 	}
1495331Samw 
1505331Samw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
1515331Samw 	if (sr->fid_ofile == NULL) {
1525331Samw 		kmem_free(param, sizeof (smb_write_param_t));
153*5772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
1545331Samw 		/* NOTREACHED */
1555331Samw 	}
1565331Samw 
1575331Samw 	param->w_offset = (uint64_t)off;
1585331Samw 
1595331Samw 	if (param->w_count == 0) {
1605331Samw 		rc = smb_write_truncate(sr, param);
1615331Samw 	} else {
1625331Samw 		/*
1635331Samw 		 * There may be a bug here: should this be "3.#B"?
1645331Samw 		 */
1655331Samw 		rc = smbsr_decode_data(sr, ".#B", param->w_count,
1665331Samw 		    &param->w_vdb);
1675331Samw 
1685331Samw 		if ((rc != 0) || (param->w_vdb.len != param->w_count)) {
1695331Samw 			kmem_free(param, sizeof (smb_write_param_t));
1705331Samw 			smbsr_decode_error(sr);
1715331Samw 			/* NOTREACHED */
1725331Samw 		}
1735331Samw 
1745521Sas200622 		param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
1755331Samw 
1765331Samw 		rc = smb_write_common(sr, param);
1775331Samw 	}
1785331Samw 
1795331Samw 	if (rc != 0) {
1805331Samw 		kmem_free(param, sizeof (smb_write_param_t));
181*5772Sas200622 		smbsr_errno(sr, rc);
1825331Samw 		/* NOTREACHED */
1835331Samw 	}
1845331Samw 
1855331Samw 	if ((rc = smb_common_close(sr, last_write)) != 0) {
1865331Samw 		kmem_free(param, sizeof (smb_write_param_t));
187*5772Sas200622 		smbsr_errno(sr, rc);
1885331Samw 		/* NOTREACHED */
1895331Samw 	}
1905331Samw 
1915331Samw 	smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0);
1925331Samw 	kmem_free(param, sizeof (smb_write_param_t));
1935331Samw 	return (SDRC_NORMAL_REPLY);
1945331Samw }
1955331Samw 
1965331Samw /*
1975331Samw  * Write count bytes to a file at the specified offset and then unlock
1985331Samw  * them.  Write behind is safe because the client should have the range
1995331Samw  * locked and this request is allowed to extend the file - note that
2005331Samw  * offest is limited to 32-bits.  It is an error for count to be zero.
2015331Samw  *
2025331Samw  * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk
2035331Samw  * files.  Reject any attempt to use it on other shares.
2045331Samw  *
2055331Samw  * The response count indicates the actual number of bytes written, which
2065331Samw  * will equal the requested count on success.  If request and response
2075331Samw  * counts differ but there is no error, the client will assume that the
2085331Samw  * server encountered a resource issue.
2095331Samw  */
2105331Samw int
2115331Samw smb_com_write_and_unlock(struct smb_request *sr)
2125331Samw {
2135331Samw 	smb_write_param_t *param;
2145331Samw 	uint32_t off;
2155331Samw 	uint32_t result;
2165331Samw 	uint16_t remcnt;
2175331Samw 	int rc = 0;
2185331Samw 
2195331Samw 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
220*5772Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
2215331Samw 		/* NOTREACHED */
2225331Samw 	}
2235331Samw 
2245331Samw 	param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
2255331Samw 
2265331Samw 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &param->w_count, &off,
2275331Samw 	    &remcnt);
2285331Samw 	if (rc != 0) {
2295331Samw 		kmem_free(param, sizeof (smb_write_param_t));
2305331Samw 		smbsr_decode_error(sr);
2315331Samw 		/* NOTREACHED */
2325331Samw 	}
2335331Samw 
2345331Samw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
2355331Samw 	if (sr->fid_ofile == NULL) {
2365331Samw 		kmem_free(param, sizeof (smb_write_param_t));
237*5772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
2385331Samw 		/* NOTREACHED */
2395331Samw 	}
2405331Samw 
2415331Samw 	if (param->w_count == 0) {
2425331Samw 		smbsr_decode_error(sr);
2435331Samw 		/* NOTREACHED */
2445331Samw 	}
2455331Samw 
2465331Samw 	rc = smbsr_decode_data(sr, "D", &param->w_vdb);
2475331Samw 
2485331Samw 	if ((rc != 0) || (param->w_count != param->w_vdb.len)) {
2495331Samw 		kmem_free(param, sizeof (smb_write_param_t));
2505331Samw 		smbsr_decode_error(sr);
2515331Samw 		/* NOTREACHED */
2525331Samw 	}
2535331Samw 
2545331Samw 	param->w_offset = (uint64_t)off;
2555521Sas200622 	param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
2565331Samw 
2575331Samw 	if ((rc = smb_write_common(sr, param)) != 0) {
2585331Samw 		kmem_free(param, sizeof (smb_write_param_t));
259*5772Sas200622 		smbsr_errno(sr, rc);
2605331Samw 		/* NOTREACHED */
2615331Samw 	}
2625331Samw 
2635331Samw 	result = smb_unlock_range(sr, sr->fid_ofile->f_node, param->w_offset,
2645331Samw 	    (uint64_t)param->w_count);
2655331Samw 	if (result != NT_STATUS_SUCCESS) {
2665331Samw 		kmem_free(param, sizeof (smb_write_param_t));
267*5772Sas200622 		smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
268*5772Sas200622 		    ERRDOS, ERRnotlocked);
2695331Samw 		/* NOTREACHED */
2705331Samw 	}
2715331Samw 
2725331Samw 	smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0);
2735331Samw 	kmem_free(param, sizeof (smb_write_param_t));
2745331Samw 	return (SDRC_NORMAL_REPLY);
2755331Samw }
2765331Samw 
2775331Samw /*
2785331Samw  * Write bytes to a file (SMB Core).  This request was extended in
2795331Samw  * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
2805331Samw  * 14, instead of 12, and including additional offset information.
2815331Samw  *
2825331Samw  * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE
2835331Samw  * to truncate a file.  A zero length merely transfers zero bytes.
2845331Samw  *
2855331Samw  * If bit 0 of WriteMode is set, Fid must refer to a disk file and
2865331Samw  * the data must be on stable storage before responding.
2875331Samw  */
2885331Samw int
2895331Samw smb_com_write_andx(struct smb_request *sr)
2905331Samw {
2915331Samw 	smb_write_param_t *param;
2925331Samw 	uint32_t off_low;
2935331Samw 	uint32_t off_high;
2945331Samw 	uint16_t data_offset;
2955331Samw 	uint16_t remcnt;
2965331Samw 	int rc = 0;
2975331Samw 
2985331Samw 	param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
2995331Samw 
3005331Samw 	if (sr->smb_wct == 14) {
3015331Samw 		rc = smbsr_decode_vwv(sr, "4.wl4.ww2.wwl", &sr->smb_fid,
3025331Samw 		    &off_low, &param->w_mode, &remcnt, &param->w_count,
3035331Samw 		    &data_offset, &off_high);
3045331Samw 
3055331Samw 		data_offset -= 63;
3065331Samw 		param->w_offset = ((uint64_t)off_high << 32) | off_low;
3075331Samw 	} else {
3085331Samw 		rc = smbsr_decode_vwv(sr, "4.wl4.ww2.ww", &sr->smb_fid,
3095331Samw 		    &off_low, &param->w_mode, &remcnt, &param->w_count,
3105331Samw 		    &data_offset);
3115331Samw 
3125331Samw 		param->w_offset = (uint64_t)off_low;
3135331Samw 		data_offset -= 59;
3145331Samw 	}
3155331Samw 
3165331Samw 	if (rc != 0) {
3175331Samw 		kmem_free(param, sizeof (smb_write_param_t));
3185331Samw 		smbsr_decode_error(sr);
3195331Samw 		/* NOTREACHED */
3205331Samw 	}
3215331Samw 
3225331Samw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
3235331Samw 	if (sr->fid_ofile == NULL) {
3245331Samw 		kmem_free(param, sizeof (smb_write_param_t));
325*5772Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
3265331Samw 		/* NOTREACHED */
3275331Samw 	}
3285331Samw 
3295331Samw 	if (SMB_WRMODE_IS_STABLE(param->w_mode) &&
3305331Samw 	    STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
3315331Samw 		kmem_free(param, sizeof (smb_write_param_t));
332*5772Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRaccess);
3335331Samw 		/* NOTREACHED */
3345331Samw 	}
3355331Samw 
3365331Samw 	rc = smbsr_decode_data(sr, "#.#B", data_offset, param->w_count,
3375331Samw 	    &param->w_vdb);
3385331Samw 	if ((rc != 0) || (param->w_vdb.len != param->w_count)) {
3395331Samw 		kmem_free(param, sizeof (smb_write_param_t));
3405331Samw 		smbsr_decode_error(sr);
3415331Samw 		/* NOTREACHED */
3425331Samw 	}
3435331Samw 
3445521Sas200622 	param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
3455331Samw 
3465331Samw 	if (param->w_count != 0) {
3475331Samw 		if ((rc = smb_write_common(sr, param)) != 0) {
3485331Samw 			kmem_free(param, sizeof (smb_write_param_t));
349*5772Sas200622 			smbsr_errno(sr, rc);
3505331Samw 			/* NOTREACHED */
3515331Samw 		}
3525331Samw 	}
3535331Samw 
3545331Samw 	smbsr_encode_result(sr, 6, 0, "bb1.ww6.w",
3555331Samw 	    6, sr->andx_com, 15, param->w_count, 0);
3565331Samw 
3575331Samw 	kmem_free(param, sizeof (smb_write_param_t));
3585331Samw 	return (SDRC_NORMAL_REPLY);
3595331Samw }
3605331Samw 
3615331Samw /*
3625331Samw  * Common function for writing files or IPC/MSRPC named pipes.
3635331Samw  *
3645331Samw  * Returns errno values.
3655331Samw  */
3665331Samw int
3675331Samw smb_write_common(struct smb_request *sr, smb_write_param_t *param)
3685331Samw {
3695331Samw 	struct smb_ofile *ofile = sr->fid_ofile;
3705331Samw 	smb_node_t *node;
3715331Samw 	uint32_t stability = FSSTAB_UNSTABLE;
3725331Samw 	uint32_t lcount;
3735331Samw 	int rc = 0;
3745331Samw 
3755331Samw 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
3765331Samw 	case STYPE_DISKTREE:
3775331Samw 		node = ofile->f_node;
3785331Samw 
3795331Samw 		if (node->attr.sa_vattr.va_type != VDIR) {
3805331Samw 			rc = smb_lock_range_access(sr, node, param->w_offset,
381*5772Sas200622 			    param->w_count, B_TRUE);
3825331Samw 			if (rc != NT_STATUS_SUCCESS) {
383*5772Sas200622 				smbsr_error(sr, rc, ERRSRV, ERRaccess);
3845331Samw 				/* NOTREACHED */
3855331Samw 			}
3865331Samw 		}
3875331Samw 
3885331Samw 		if (SMB_WRMODE_IS_STABLE(param->w_mode) ||
3895331Samw 		    (node->flags & NODE_FLAGS_WRITE_THROUGH)) {
3905331Samw 			stability = FSSTAB_FILE_SYNC;
3915331Samw 		}
3925331Samw 
3935331Samw 		rc = smb_fsop_write(sr, sr->user_cr, node,
3945331Samw 		    &param->w_vdb.uio, &lcount, &node->attr, &stability);
3955331Samw 
3965331Samw 		if (rc)
3975331Samw 			return (rc);
3985331Samw 
3995331Samw 		node->flags |= NODE_FLAGS_SYNCATIME;
4005331Samw 
4015331Samw 		if (node->flags & NODE_FLAGS_SET_SIZE) {
4025331Samw 			if ((param->w_offset + lcount) >= node->n_size) {
4035331Samw 				node->flags &= ~NODE_FLAGS_SET_SIZE;
4045331Samw 				node->n_size = param->w_offset + lcount;
4055331Samw 			}
4065331Samw 		}
4075331Samw 
4085331Samw 		param->w_count = (uint16_t)lcount;
4095331Samw 		break;
4105331Samw 
4115331Samw 	case STYPE_IPC:
4125331Samw 		param->w_count = (uint16_t)param->w_vdb.uio.uio_resid;
4135331Samw 
4145331Samw 		if ((rc = smb_rpc_write(sr, &param->w_vdb.uio)) != 0)
4155331Samw 			param->w_count = 0;
4165331Samw 		break;
4175331Samw 
4185331Samw 	default:
4195331Samw 		rc = EACCES;
4205331Samw 		break;
4215331Samw 	}
4225331Samw 
4235331Samw 	if (rc != 0)
4245331Samw 		return (rc);
4255331Samw 
4265331Samw 	mutex_enter(&ofile->f_mutex);
4275331Samw 	ofile->f_seek_pos = param->w_offset + param->w_count;
4285331Samw 	mutex_exit(&ofile->f_mutex);
4295331Samw 	return (rc);
4305331Samw }
4315331Samw 
4325331Samw /*
4335331Samw  * Truncate a disk file to the specified offset.
4345331Samw  * Typically, w_count will be zero here.
4355331Samw  *
4365331Samw  * Returns errno values.
4375331Samw  */
4385331Samw int
4395331Samw smb_write_truncate(struct smb_request *sr, smb_write_param_t *param)
4405331Samw {
4415331Samw 	struct smb_ofile *ofile = sr->fid_ofile;
4425331Samw 	smb_node_t *node = ofile->f_node;
443*5772Sas200622 	boolean_t append_only = B_FALSE;
4445331Samw 	int rc;
4455331Samw 
4465331Samw 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0)
4475331Samw 		return (0);
4485331Samw 
449*5772Sas200622 	rc = smb_ofile_access(sr->fid_ofile, sr->user_cr, FILE_WRITE_DATA);
450*5772Sas200622 	if (rc != NT_STATUS_SUCCESS) {
451*5772Sas200622 		rc = smb_ofile_access(sr->fid_ofile, sr->user_cr,
452*5772Sas200622 		    FILE_APPEND_DATA);
453*5772Sas200622 		if (rc != NT_STATUS_SUCCESS) {
454*5772Sas200622 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
455*5772Sas200622 			    ERROR_ACCESS_DENIED);
456*5772Sas200622 			/* NOTREACHED */
457*5772Sas200622 		} else {
458*5772Sas200622 			append_only = B_TRUE;
459*5772Sas200622 		}
460*5772Sas200622 	}
461*5772Sas200622 
462*5772Sas200622 	smb_rwx_xenter(&node->n_lock);
463*5772Sas200622 
464*5772Sas200622 	if (append_only && (param->w_offset < node->n_size)) {
465*5772Sas200622 		smb_rwx_xexit(&node->n_lock);
466*5772Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
467*5772Sas200622 		    ERRDOS, ERRnoaccess);
468*5772Sas200622 		/* NOTREACHED */
469*5772Sas200622 	}
470*5772Sas200622 
4715331Samw 	if (node->attr.sa_vattr.va_type != VDIR) {
4725331Samw 		rc = smb_lock_range_access(sr, node, param->w_offset,
473*5772Sas200622 		    param->w_count, B_TRUE);
4745331Samw 		if (rc != NT_STATUS_SUCCESS) {
475*5772Sas200622 			smb_rwx_xexit(&node->n_lock);
476*5772Sas200622 			smbsr_error(sr, rc, ERRSRV, ERRaccess);
4775331Samw 			/* NOTREACHED */
4785331Samw 		}
4795331Samw 	}
4805331Samw 
4815331Samw 	node->flags |= NODE_FLAGS_SET_SIZE;
4825331Samw 	node->n_size = param->w_offset;
4835331Samw 
484*5772Sas200622 	smb_rwx_xexit(&node->n_lock);
485*5772Sas200622 
4865331Samw 	if ((rc = smb_set_file_size(sr)) != 0)
4875331Samw 		return (rc);
4885331Samw 
4895331Samw 	mutex_enter(&ofile->f_mutex);
4905331Samw 	ofile->f_seek_pos = param->w_offset + param->w_count;
4915331Samw 	mutex_exit(&ofile->f_mutex);
4925331Samw 	return (0);
4935331Samw }
4945331Samw 
4955331Samw /*
4965331Samw  * Set the file size using the value in the node. The file will only be
4975331Samw  * updated if NODE_FLAGS_SET_SIZE is set.  It is safe to pass a null node
4985331Samw  * pointer, we just return success.
4995331Samw  *
5005331Samw  * The node attributes are refreshed here from the file system. So any
5015331Samw  * attributes that are affected by file size changes, i.e. the mtime,
5025331Samw  * will be current.
5035331Samw  *
5045331Samw  * Note that smb_write_andx cannot be used to reduce the file size so,
5055331Samw  * if this is required, smb_write is called with a count of zero and
5065331Samw  * the appropriate file length in offset. The file should be resized
5075331Samw  * to the length specified by the offset.
5085331Samw  *
5095331Samw  * Returns 0 on success. Otherwise returns EACCES.
5105331Samw  */
5115331Samw int
5125331Samw smb_set_file_size(struct smb_request *sr)
5135331Samw {
5145331Samw 	struct smb_node *node;
5155331Samw 	smb_attr_t new_attr;
5165331Samw 	uint32_t dosattr;
5175331Samw 
5185331Samw 	if ((node = sr->fid_ofile->f_node) == 0)
5195331Samw 		return (0);
5205331Samw 
5215331Samw 	if ((node->flags & NODE_FLAGS_SET_SIZE) == 0)
5225331Samw 		return (0);
5235331Samw 
5245331Samw 	node->flags &= ~NODE_FLAGS_SET_SIZE;
5255331Samw 
5265331Samw 	dosattr = smb_node_get_dosattr(node);
5275331Samw 
5285331Samw 	if (dosattr & SMB_FA_READONLY) {
5295331Samw 		if (((node->flags & NODE_FLAGS_CREATED) == 0) ||
5305331Samw 		    (sr->session->s_kid != node->n_orig_session_id))
5315331Samw 			return (EACCES);
5325331Samw 	}
5335331Samw 
5345331Samw 	bzero(&new_attr, sizeof (new_attr));
5355331Samw 	new_attr.sa_vattr.va_size = node->n_size;
5365331Samw 	new_attr.sa_mask = SMB_AT_SIZE;
5375331Samw 
5385331Samw 	(void) smb_fsop_setattr(sr, sr->user_cr, node, &new_attr,
5395331Samw 	    &node->attr);
5405331Samw 
5415331Samw 	return (0);
5425331Samw }
5435331Samw 
5445331Samw /*
5455331Samw  * write_complete is sent acknowledge completion of raw write requests.
5465331Samw  * We never send raw write commands to other servers so, if we receive a
5475331Samw  * write_complete, we treat it as an error.
5485331Samw  */
5495331Samw int
5505331Samw smb_com_write_complete(struct smb_request *sr)
5515331Samw {
5525331Samw 	smbsr_decode_error(sr);
5535331Samw 	/* NOT REACHED */
5545331Samw 	return (0);
5555331Samw }
5565331Samw 
5575331Samw /*
5585331Samw  * The Write Block Multiplexed protocol is used to maximize performance
5595331Samw  * when writing a large block of data.
5605331Samw  *
5615331Samw  * The mpx sub protocol is not supported because we support only
5625331Samw  * connection oriented transports and NT supports SMB_COM_READ_MPX
5635331Samw  * only over connectionless transports.
5645331Samw  */
5655331Samw int /*ARGSUSED*/
5665331Samw smb_com_write_mpx(struct smb_request *sr)
5675331Samw {
5685331Samw 	return (SDRC_UNIMPLEMENTED);
5695331Samw }
5705331Samw 
5715331Samw int /*ARGSUSED*/
5725331Samw smb_com_write_mpx_secondary(struct smb_request *sr)
5735331Samw {
5745331Samw 	return (SDRC_UNIMPLEMENTED);
5755331Samw }
576