xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_write.c (revision 5521:cf62335046cd)
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 /*
225331Samw  * Copyright 2007 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));
815331Samw 		smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
825331Samw 		    ERRDOS, ERRbadfid);
835331Samw 		/* NOTREACHED */
845331Samw 	}
855331Samw 
865331Samw 	param->w_offset = (uint64_t)off;
87*5521Sas200622 	param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
885331Samw 
895331Samw 	if (param->w_count == 0) {
905331Samw 		rc = smb_write_truncate(sr, param);
915331Samw 	} else {
925331Samw 		rc = smbsr_decode_data(sr, "D", &param->w_vdb);
935331Samw 
945331Samw 		if ((rc != 0) || (param->w_vdb.len != param->w_count)) {
955331Samw 			kmem_free(param, sizeof (smb_write_param_t));
965331Samw 			smbsr_decode_error(sr);
975331Samw 			/* NOTREACHED */
985331Samw 		}
995331Samw 
100*5521Sas200622 		param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
1015331Samw 
1025331Samw 		rc = smb_write_common(sr, param);
1035331Samw 	}
1045331Samw 
1055331Samw 	if (rc != 0) {
1065331Samw 		kmem_free(param, sizeof (smb_write_param_t));
1075331Samw 		smbsr_raise_errno(sr, rc);
1085331Samw 		/* NOTREACHED */
1095331Samw 	}
1105331Samw 
1115331Samw 	smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0);
1125331Samw 	kmem_free(param, sizeof (smb_write_param_t));
1135331Samw 	return (SDRC_NORMAL_REPLY);
1145331Samw }
1155331Samw 
1165331Samw /*
1175331Samw  * Write count bytes to a file and then close the file.  This function
1185331Samw  * can only be used to write to 32-bit offsets and the client must set
1195331Samw  * WordCount (6 or 12) correctly in order to locate the data to be
1205331Samw  * written.  If an error occurs on the write, the file should still be
1215331Samw  * closed.  If Count is 0, the file is truncated (or extended) to offset.
1225331Samw  *
1235331Samw  * If the last_write time is non-zero, last_write should be used to set
1245331Samw  * the mtime.  Otherwise the file system stamps the mtime.  Failure to
1255331Samw  * set mtime should not result in an error response.
1265331Samw  */
1275331Samw int
1285331Samw smb_com_write_and_close(struct smb_request *sr)
1295331Samw {
1305331Samw 	smb_write_param_t *param;
1315331Samw 	uint32_t last_write;
1325331Samw 	uint32_t off;
1335331Samw 	int rc = 0;
1345331Samw 
1355331Samw 	param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
1365331Samw 
1375331Samw 	if (sr->smb_wct == 12) {
1385331Samw 		rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid,
1395331Samw 		    &param->w_count, &off, &last_write);
1405331Samw 	} else {
1415331Samw 		rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid,
1425331Samw 		    &param->w_count, &off, &last_write);
1435331Samw 	}
1445331Samw 
1455331Samw 	if (rc != 0) {
1465331Samw 		kmem_free(param, sizeof (smb_write_param_t));
1475331Samw 		smbsr_decode_error(sr);
1485331Samw 		/* NOTREACHED */
1495331Samw 	}
1505331Samw 
1515331Samw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
1525331Samw 	if (sr->fid_ofile == NULL) {
1535331Samw 		kmem_free(param, sizeof (smb_write_param_t));
1545331Samw 		smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
1555331Samw 		    ERRDOS, ERRbadfid);
1565331Samw 		/* NOTREACHED */
1575331Samw 	}
1585331Samw 
1595331Samw 	param->w_offset = (uint64_t)off;
1605331Samw 
1615331Samw 	if (param->w_count == 0) {
1625331Samw 		rc = smb_write_truncate(sr, param);
1635331Samw 	} else {
1645331Samw 		/*
1655331Samw 		 * There may be a bug here: should this be "3.#B"?
1665331Samw 		 */
1675331Samw 		rc = smbsr_decode_data(sr, ".#B", param->w_count,
1685331Samw 		    &param->w_vdb);
1695331Samw 
1705331Samw 		if ((rc != 0) || (param->w_vdb.len != param->w_count)) {
1715331Samw 			kmem_free(param, sizeof (smb_write_param_t));
1725331Samw 			smbsr_decode_error(sr);
1735331Samw 			/* NOTREACHED */
1745331Samw 		}
1755331Samw 
176*5521Sas200622 		param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
1775331Samw 
1785331Samw 		rc = smb_write_common(sr, param);
1795331Samw 	}
1805331Samw 
1815331Samw 	if (rc != 0) {
1825331Samw 		kmem_free(param, sizeof (smb_write_param_t));
1835331Samw 		smbsr_raise_errno(sr, rc);
1845331Samw 		/* NOTREACHED */
1855331Samw 	}
1865331Samw 
1875331Samw 	if ((rc = smb_common_close(sr, last_write)) != 0) {
1885331Samw 		kmem_free(param, sizeof (smb_write_param_t));
1895331Samw 		smbsr_raise_errno(sr, rc);
1905331Samw 		/* NOTREACHED */
1915331Samw 	}
1925331Samw 
1935331Samw 	smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0);
1945331Samw 	kmem_free(param, sizeof (smb_write_param_t));
1955331Samw 	return (SDRC_NORMAL_REPLY);
1965331Samw }
1975331Samw 
1985331Samw /*
1995331Samw  * Write count bytes to a file at the specified offset and then unlock
2005331Samw  * them.  Write behind is safe because the client should have the range
2015331Samw  * locked and this request is allowed to extend the file - note that
2025331Samw  * offest is limited to 32-bits.  It is an error for count to be zero.
2035331Samw  *
2045331Samw  * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk
2055331Samw  * files.  Reject any attempt to use it on other shares.
2065331Samw  *
2075331Samw  * The response count indicates the actual number of bytes written, which
2085331Samw  * will equal the requested count on success.  If request and response
2095331Samw  * counts differ but there is no error, the client will assume that the
2105331Samw  * server encountered a resource issue.
2115331Samw  */
2125331Samw int
2135331Samw smb_com_write_and_unlock(struct smb_request *sr)
2145331Samw {
2155331Samw 	smb_write_param_t *param;
2165331Samw 	uint32_t off;
2175331Samw 	uint32_t result;
2185331Samw 	uint16_t remcnt;
2195331Samw 	int rc = 0;
2205331Samw 
2215331Samw 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
2225331Samw 		smbsr_raise_error(sr, ERRDOS, ERRnoaccess);
2235331Samw 		/* NOTREACHED */
2245331Samw 	}
2255331Samw 
2265331Samw 	param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
2275331Samw 
2285331Samw 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &param->w_count, &off,
2295331Samw 	    &remcnt);
2305331Samw 	if (rc != 0) {
2315331Samw 		kmem_free(param, sizeof (smb_write_param_t));
2325331Samw 		smbsr_decode_error(sr);
2335331Samw 		/* NOTREACHED */
2345331Samw 	}
2355331Samw 
2365331Samw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
2375331Samw 	if (sr->fid_ofile == NULL) {
2385331Samw 		kmem_free(param, sizeof (smb_write_param_t));
2395331Samw 		smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
2405331Samw 		    ERRDOS, ERRbadfid);
2415331Samw 		/* NOTREACHED */
2425331Samw 	}
2435331Samw 
2445331Samw 	if (param->w_count == 0) {
2455331Samw 		smbsr_decode_error(sr);
2465331Samw 		/* NOTREACHED */
2475331Samw 	}
2485331Samw 
2495331Samw 	rc = smbsr_decode_data(sr, "D", &param->w_vdb);
2505331Samw 
2515331Samw 	if ((rc != 0) || (param->w_count != param->w_vdb.len)) {
2525331Samw 		kmem_free(param, sizeof (smb_write_param_t));
2535331Samw 		smbsr_decode_error(sr);
2545331Samw 		/* NOTREACHED */
2555331Samw 	}
2565331Samw 
2575331Samw 	param->w_offset = (uint64_t)off;
258*5521Sas200622 	param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
2595331Samw 
2605331Samw 	if ((rc = smb_write_common(sr, param)) != 0) {
2615331Samw 		kmem_free(param, sizeof (smb_write_param_t));
2625331Samw 		smbsr_raise_errno(sr, rc);
2635331Samw 		/* NOTREACHED */
2645331Samw 	}
2655331Samw 
2665331Samw 	result = smb_unlock_range(sr, sr->fid_ofile->f_node, param->w_offset,
2675331Samw 	    (uint64_t)param->w_count);
2685331Samw 	if (result != NT_STATUS_SUCCESS) {
2695331Samw 		kmem_free(param, sizeof (smb_write_param_t));
2705331Samw 		smb_unlock_range_raise_error(sr, result);
2715331Samw 		/* NOTREACHED */
2725331Samw 	}
2735331Samw 
2745331Samw 	smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0);
2755331Samw 	kmem_free(param, sizeof (smb_write_param_t));
2765331Samw 	return (SDRC_NORMAL_REPLY);
2775331Samw }
2785331Samw 
2795331Samw /*
2805331Samw  * Write bytes to a file (SMB Core).  This request was extended in
2815331Samw  * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
2825331Samw  * 14, instead of 12, and including additional offset information.
2835331Samw  *
2845331Samw  * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE
2855331Samw  * to truncate a file.  A zero length merely transfers zero bytes.
2865331Samw  *
2875331Samw  * If bit 0 of WriteMode is set, Fid must refer to a disk file and
2885331Samw  * the data must be on stable storage before responding.
2895331Samw  */
2905331Samw int
2915331Samw smb_com_write_andx(struct smb_request *sr)
2925331Samw {
2935331Samw 	smb_write_param_t *param;
2945331Samw 	uint32_t off_low;
2955331Samw 	uint32_t off_high;
2965331Samw 	uint16_t data_offset;
2975331Samw 	uint16_t remcnt;
2985331Samw 	int rc = 0;
2995331Samw 
3005331Samw 	param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP);
3015331Samw 
3025331Samw 	if (sr->smb_wct == 14) {
3035331Samw 		rc = smbsr_decode_vwv(sr, "4.wl4.ww2.wwl", &sr->smb_fid,
3045331Samw 		    &off_low, &param->w_mode, &remcnt, &param->w_count,
3055331Samw 		    &data_offset, &off_high);
3065331Samw 
3075331Samw 		data_offset -= 63;
3085331Samw 		param->w_offset = ((uint64_t)off_high << 32) | off_low;
3095331Samw 	} else {
3105331Samw 		rc = smbsr_decode_vwv(sr, "4.wl4.ww2.ww", &sr->smb_fid,
3115331Samw 		    &off_low, &param->w_mode, &remcnt, &param->w_count,
3125331Samw 		    &data_offset);
3135331Samw 
3145331Samw 		param->w_offset = (uint64_t)off_low;
3155331Samw 		data_offset -= 59;
3165331Samw 	}
3175331Samw 
3185331Samw 	if (rc != 0) {
3195331Samw 		kmem_free(param, sizeof (smb_write_param_t));
3205331Samw 		smbsr_decode_error(sr);
3215331Samw 		/* NOTREACHED */
3225331Samw 	}
3235331Samw 
3245331Samw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
3255331Samw 	if (sr->fid_ofile == NULL) {
3265331Samw 		kmem_free(param, sizeof (smb_write_param_t));
3275331Samw 		smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
3285331Samw 		    ERRDOS, ERRbadfid);
3295331Samw 		/* NOTREACHED */
3305331Samw 	}
3315331Samw 
3325331Samw 	if (SMB_WRMODE_IS_STABLE(param->w_mode) &&
3335331Samw 	    STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
3345331Samw 		kmem_free(param, sizeof (smb_write_param_t));
3355331Samw 		smbsr_raise_error(sr, ERRSRV, ERRaccess);
3365331Samw 		/* NOTREACHED */
3375331Samw 	}
3385331Samw 
3395331Samw 	rc = smbsr_decode_data(sr, "#.#B", data_offset, param->w_count,
3405331Samw 	    &param->w_vdb);
3415331Samw 	if ((rc != 0) || (param->w_vdb.len != param->w_count)) {
3425331Samw 		kmem_free(param, sizeof (smb_write_param_t));
3435331Samw 		smbsr_decode_error(sr);
3445331Samw 		/* NOTREACHED */
3455331Samw 	}
3465331Samw 
347*5521Sas200622 	param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset;
3485331Samw 
3495331Samw 	if (param->w_count != 0) {
3505331Samw 		if ((rc = smb_write_common(sr, param)) != 0) {
3515331Samw 			kmem_free(param, sizeof (smb_write_param_t));
3525331Samw 			smbsr_raise_errno(sr, rc);
3535331Samw 			/* NOTREACHED */
3545331Samw 		}
3555331Samw 	}
3565331Samw 
3575331Samw 	smbsr_encode_result(sr, 6, 0, "bb1.ww6.w",
3585331Samw 	    6, sr->andx_com, 15, param->w_count, 0);
3595331Samw 
3605331Samw 	kmem_free(param, sizeof (smb_write_param_t));
3615331Samw 	return (SDRC_NORMAL_REPLY);
3625331Samw }
3635331Samw 
3645331Samw /*
3655331Samw  * Common function for writing files or IPC/MSRPC named pipes.
3665331Samw  *
3675331Samw  * Returns errno values.
3685331Samw  */
3695331Samw int
3705331Samw smb_write_common(struct smb_request *sr, smb_write_param_t *param)
3715331Samw {
3725331Samw 	struct smb_ofile *ofile = sr->fid_ofile;
3735331Samw 	smb_node_t *node;
3745331Samw 	uint32_t stability = FSSTAB_UNSTABLE;
3755331Samw 	uint32_t lcount;
3765331Samw 	int rc = 0;
3775331Samw 
3785331Samw 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
3795331Samw 	case STYPE_DISKTREE:
3805331Samw 		node = ofile->f_node;
3815331Samw 
3825331Samw 		if (node->attr.sa_vattr.va_type != VDIR) {
3835331Samw 			rc = smb_lock_range_access(sr, node, param->w_offset,
3845331Samw 			    param->w_count, FILE_WRITE_DATA);
3855331Samw 			if (rc != NT_STATUS_SUCCESS) {
3865331Samw 				smbsr_raise_cifs_error(sr, rc,
3875331Samw 				    ERRSRV, ERRaccess);
3885331Samw 				/* NOTREACHED */
3895331Samw 			}
3905331Samw 		}
3915331Samw 
3925331Samw 		if (SMB_WRMODE_IS_STABLE(param->w_mode) ||
3935331Samw 		    (node->flags & NODE_FLAGS_WRITE_THROUGH)) {
3945331Samw 			stability = FSSTAB_FILE_SYNC;
3955331Samw 		}
3965331Samw 
3975331Samw 		rc = smb_fsop_write(sr, sr->user_cr, node,
3985331Samw 		    &param->w_vdb.uio, &lcount, &node->attr, &stability);
3995331Samw 
4005331Samw 		if (rc)
4015331Samw 			return (rc);
4025331Samw 
4035331Samw 		node->flags |= NODE_FLAGS_SYNCATIME;
4045331Samw 
4055331Samw 		if (node->flags & NODE_FLAGS_SET_SIZE) {
4065331Samw 			if ((param->w_offset + lcount) >= node->n_size) {
4075331Samw 				node->flags &= ~NODE_FLAGS_SET_SIZE;
4085331Samw 				node->n_size = param->w_offset + lcount;
4095331Samw 			}
4105331Samw 		}
4115331Samw 
4125331Samw 		param->w_count = (uint16_t)lcount;
4135331Samw 		break;
4145331Samw 
4155331Samw 	case STYPE_IPC:
4165331Samw 		param->w_count = (uint16_t)param->w_vdb.uio.uio_resid;
4175331Samw 
4185331Samw 		if ((rc = smb_rpc_write(sr, &param->w_vdb.uio)) != 0)
4195331Samw 			param->w_count = 0;
4205331Samw 		break;
4215331Samw 
4225331Samw 	default:
4235331Samw 		rc = EACCES;
4245331Samw 		break;
4255331Samw 	}
4265331Samw 
4275331Samw 	if (rc != 0)
4285331Samw 		return (rc);
4295331Samw 
4305331Samw 	mutex_enter(&ofile->f_mutex);
4315331Samw 	ofile->f_seek_pos = param->w_offset + param->w_count;
4325331Samw 	mutex_exit(&ofile->f_mutex);
4335331Samw 	return (rc);
4345331Samw }
4355331Samw 
4365331Samw /*
4375331Samw  * Truncate a disk file to the specified offset.
4385331Samw  * Typically, w_count will be zero here.
4395331Samw  *
4405331Samw  * Returns errno values.
4415331Samw  */
4425331Samw int
4435331Samw smb_write_truncate(struct smb_request *sr, smb_write_param_t *param)
4445331Samw {
4455331Samw 	struct smb_ofile *ofile = sr->fid_ofile;
4465331Samw 	smb_node_t *node = ofile->f_node;
4475331Samw 	int rc;
4485331Samw 
4495331Samw 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0)
4505331Samw 		return (0);
4515331Samw 
4525331Samw 	if (node->attr.sa_vattr.va_type != VDIR) {
4535331Samw 		rc = smb_lock_range_access(sr, node, param->w_offset,
4545331Samw 		    param->w_count, FILE_WRITE_DATA);
4555331Samw 		if (rc != NT_STATUS_SUCCESS) {
4565331Samw 			smbsr_raise_cifs_error(sr, rc,
4575331Samw 			    ERRSRV, ERRaccess);
4585331Samw 			/* NOTREACHED */
4595331Samw 		}
4605331Samw 	}
4615331Samw 
4625331Samw 	/*
4635331Samw 	 * XXX what if the file has been opened only with
4645331Samw 	 * FILE_APPEND_DATA?
4655331Samw 	 */
4665331Samw 	rc = smb_ofile_access(ofile, sr->user_cr, FILE_WRITE_DATA);
4675331Samw 	if (rc != NT_STATUS_SUCCESS) {
4685331Samw 		smbsr_raise_cifs_error(sr, NT_STATUS_ACCESS_DENIED,
4695331Samw 		    ERRDOS, ERROR_ACCESS_DENIED);
4705331Samw 		/* NOTREACHED */
4715331Samw 	}
4725331Samw 
4735331Samw 	node->flags |= NODE_FLAGS_SET_SIZE;
4745331Samw 	node->n_size = param->w_offset;
4755331Samw 
4765331Samw 	if ((rc = smb_set_file_size(sr)) != 0)
4775331Samw 		return (rc);
4785331Samw 
4795331Samw 	mutex_enter(&ofile->f_mutex);
4805331Samw 	ofile->f_seek_pos = param->w_offset + param->w_count;
4815331Samw 	mutex_exit(&ofile->f_mutex);
4825331Samw 	return (0);
4835331Samw }
4845331Samw 
4855331Samw /*
4865331Samw  * Set the file size using the value in the node. The file will only be
4875331Samw  * updated if NODE_FLAGS_SET_SIZE is set.  It is safe to pass a null node
4885331Samw  * pointer, we just return success.
4895331Samw  *
4905331Samw  * The node attributes are refreshed here from the file system. So any
4915331Samw  * attributes that are affected by file size changes, i.e. the mtime,
4925331Samw  * will be current.
4935331Samw  *
4945331Samw  * Note that smb_write_andx cannot be used to reduce the file size so,
4955331Samw  * if this is required, smb_write is called with a count of zero and
4965331Samw  * the appropriate file length in offset. The file should be resized
4975331Samw  * to the length specified by the offset.
4985331Samw  *
4995331Samw  * Returns 0 on success. Otherwise returns EACCES.
5005331Samw  */
5015331Samw int
5025331Samw smb_set_file_size(struct smb_request *sr)
5035331Samw {
5045331Samw 	struct smb_node *node;
5055331Samw 	smb_attr_t new_attr;
5065331Samw 	uint32_t dosattr;
5075331Samw 
5085331Samw 	if ((node = sr->fid_ofile->f_node) == 0)
5095331Samw 		return (0);
5105331Samw 
5115331Samw 	if ((node->flags & NODE_FLAGS_SET_SIZE) == 0)
5125331Samw 		return (0);
5135331Samw 
5145331Samw 	node->flags &= ~NODE_FLAGS_SET_SIZE;
5155331Samw 
5165331Samw 	dosattr = smb_node_get_dosattr(node);
5175331Samw 
5185331Samw 	if (dosattr & SMB_FA_READONLY) {
5195331Samw 		if (((node->flags & NODE_FLAGS_CREATED) == 0) ||
5205331Samw 		    (sr->session->s_kid != node->n_orig_session_id))
5215331Samw 			return (EACCES);
5225331Samw 	}
5235331Samw 
5245331Samw 	bzero(&new_attr, sizeof (new_attr));
5255331Samw 	new_attr.sa_vattr.va_size = node->n_size;
5265331Samw 	new_attr.sa_mask = SMB_AT_SIZE;
5275331Samw 
5285331Samw 	(void) smb_fsop_setattr(sr, sr->user_cr, node, &new_attr,
5295331Samw 	    &node->attr);
5305331Samw 
5315331Samw 	return (0);
5325331Samw }
5335331Samw 
5345331Samw /*
5355331Samw  * write_complete is sent acknowledge completion of raw write requests.
5365331Samw  * We never send raw write commands to other servers so, if we receive a
5375331Samw  * write_complete, we treat it as an error.
5385331Samw  */
5395331Samw int
5405331Samw smb_com_write_complete(struct smb_request *sr)
5415331Samw {
5425331Samw 	smbsr_decode_error(sr);
5435331Samw 	/* NOT REACHED */
5445331Samw 	return (0);
5455331Samw }
5465331Samw 
5475331Samw /*
5485331Samw  * The Write Block Multiplexed protocol is used to maximize performance
5495331Samw  * when writing a large block of data.
5505331Samw  *
5515331Samw  * The mpx sub protocol is not supported because we support only
5525331Samw  * connection oriented transports and NT supports SMB_COM_READ_MPX
5535331Samw  * only over connectionless transports.
5545331Samw  */
5555331Samw int /*ARGSUSED*/
5565331Samw smb_com_write_mpx(struct smb_request *sr)
5575331Samw {
5585331Samw 	return (SDRC_UNIMPLEMENTED);
5595331Samw }
5605331Samw 
5615331Samw int /*ARGSUSED*/
5625331Samw smb_com_write_mpx_secondary(struct smb_request *sr)
5635331Samw {
5645331Samw 	return (SDRC_UNIMPLEMENTED);
5655331Samw }
566