xref: /titanic_52/usr/src/uts/common/fs/smbsrv/smb_write.c (revision 1fb4a876cbadf3a151ab8a149be6956199e83e22)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21148c5f43SAlan Wright 
22da6c28aaSamw /*
23148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24*1fb4a876SGordon Ross  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
25da6c28aaSamw  */
26da6c28aaSamw 
27da6c28aaSamw #include <sys/sdt.h>
28bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
29da6c28aaSamw #include <smbsrv/smb_fsops.h>
30da6c28aaSamw #include <smbsrv/netbios.h>
31da6c28aaSamw 
32da6c28aaSamw 
33faa1795aSjb150015 static int smb_write_truncate(smb_request_t *, smb_rw_param_t *);
34da6c28aaSamw 
35da6c28aaSamw 
36da6c28aaSamw /*
37da6c28aaSamw  * Write count bytes at the specified offset in a file.  The offset is
38da6c28aaSamw  * limited to 32-bits.  If the count is zero, the file is truncated to
39da6c28aaSamw  * the length specified by the offset.
40da6c28aaSamw  *
41da6c28aaSamw  * The response count indicates the actual number of bytes written, which
42da6c28aaSamw  * will equal the requested count on success.  If request and response
43da6c28aaSamw  * counts differ but there is no error, the client will assume that the
44da6c28aaSamw  * server encountered a resource issue.
45da6c28aaSamw  */
467b59d02dSjb150015 smb_sdrc_t
47faa1795aSjb150015 smb_pre_write(smb_request_t *sr)
48da6c28aaSamw {
49faa1795aSjb150015 	smb_rw_param_t *param;
50da6c28aaSamw 	uint32_t off;
512c2961f8Sjose borrego 	uint16_t count;
52da6c28aaSamw 	int rc;
53da6c28aaSamw 
54faa1795aSjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
55faa1795aSjb150015 	sr->arg.rw = param;
56faa1795aSjb150015 	param->rw_magic = SMB_RW_MAGIC;
57da6c28aaSamw 
582c2961f8Sjose borrego 	rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off);
59faa1795aSjb150015 
602c2961f8Sjose borrego 	param->rw_count = (uint32_t)count;
61faa1795aSjb150015 	param->rw_offset = (uint64_t)off;
622c2961f8Sjose borrego 	param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
63faa1795aSjb150015 
64faa1795aSjb150015 	DTRACE_SMB_2(op__Write__start, smb_request_t *, sr,
65faa1795aSjb150015 	    smb_rw_param_t *, param);
66faa1795aSjb150015 
67faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
68da6c28aaSamw }
69da6c28aaSamw 
70faa1795aSjb150015 void
71faa1795aSjb150015 smb_post_write(smb_request_t *sr)
72faa1795aSjb150015 {
73faa1795aSjb150015 	DTRACE_SMB_2(op__Write__done, smb_request_t *, sr,
74faa1795aSjb150015 	    smb_rw_param_t *, sr->arg.rw);
75faa1795aSjb150015 
76faa1795aSjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
77faa1795aSjb150015 }
78faa1795aSjb150015 
79faa1795aSjb150015 smb_sdrc_t
80faa1795aSjb150015 smb_com_write(smb_request_t *sr)
81faa1795aSjb150015 {
82faa1795aSjb150015 	smb_rw_param_t *param = sr->arg.rw;
83faa1795aSjb150015 	int rc;
84faa1795aSjb150015 
852c2961f8Sjose borrego 	smbsr_lookup_file(sr);
86da6c28aaSamw 	if (sr->fid_ofile == NULL) {
87dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
88faa1795aSjb150015 		return (SDRC_ERROR);
89da6c28aaSamw 	}
90da6c28aaSamw 
91b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
92b89a8333Snatalie li - Sun Microsystems - Irvine United States 
93faa1795aSjb150015 	if (param->rw_count == 0) {
94da6c28aaSamw 		rc = smb_write_truncate(sr, param);
95da6c28aaSamw 	} else {
96faa1795aSjb150015 		rc = smbsr_decode_data(sr, "D", &param->rw_vdb);
97da6c28aaSamw 
982c2961f8Sjose borrego 		if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
99faa1795aSjb150015 			smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
100faa1795aSjb150015 			    ERRDOS, ERROR_INVALID_PARAMETER);
101faa1795aSjb150015 			return (SDRC_ERROR);
102da6c28aaSamw 		}
103da6c28aaSamw 
1042c2961f8Sjose borrego 		param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
105da6c28aaSamw 
106f96bd5c8SAlan Wright 		rc = smb_common_write(sr, param);
107da6c28aaSamw 	}
108da6c28aaSamw 
109da6c28aaSamw 	if (rc != 0) {
110faa1795aSjb150015 		if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
111dc20a302Sas200622 			smbsr_errno(sr, rc);
112faa1795aSjb150015 		return (SDRC_ERROR);
113da6c28aaSamw 	}
114da6c28aaSamw 
1152c2961f8Sjose borrego 	rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
1162c2961f8Sjose borrego 	    (uint16_t)param->rw_count, 0);
117faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
118da6c28aaSamw }
119da6c28aaSamw 
120da6c28aaSamw /*
121da6c28aaSamw  * Write count bytes to a file and then close the file.  This function
122da6c28aaSamw  * can only be used to write to 32-bit offsets and the client must set
123da6c28aaSamw  * WordCount (6 or 12) correctly in order to locate the data to be
124da6c28aaSamw  * written.  If an error occurs on the write, the file should still be
125da6c28aaSamw  * closed.  If Count is 0, the file is truncated (or extended) to offset.
126da6c28aaSamw  *
127da6c28aaSamw  * If the last_write time is non-zero, last_write should be used to set
128da6c28aaSamw  * the mtime.  Otherwise the file system stamps the mtime.  Failure to
129da6c28aaSamw  * set mtime should not result in an error response.
130da6c28aaSamw  */
1317b59d02dSjb150015 smb_sdrc_t
132faa1795aSjb150015 smb_pre_write_and_close(smb_request_t *sr)
133da6c28aaSamw {
134faa1795aSjb150015 	smb_rw_param_t *param;
135da6c28aaSamw 	uint32_t off;
1362c2961f8Sjose borrego 	uint16_t count;
137faa1795aSjb150015 	int rc;
138da6c28aaSamw 
139faa1795aSjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
140faa1795aSjb150015 	sr->arg.rw = param;
141faa1795aSjb150015 	param->rw_magic = SMB_RW_MAGIC;
142da6c28aaSamw 
143da6c28aaSamw 	if (sr->smb_wct == 12) {
144da6c28aaSamw 		rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid,
1452c2961f8Sjose borrego 		    &count, &off, &param->rw_last_write);
146da6c28aaSamw 	} else {
147da6c28aaSamw 		rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid,
1482c2961f8Sjose borrego 		    &count, &off, &param->rw_last_write);
149da6c28aaSamw 	}
150da6c28aaSamw 
1512c2961f8Sjose borrego 	param->rw_count = (uint32_t)count;
152faa1795aSjb150015 	param->rw_offset = (uint64_t)off;
153faa1795aSjb150015 
154faa1795aSjb150015 	DTRACE_SMB_2(op__WriteAndClose__start, smb_request_t *, sr,
155faa1795aSjb150015 	    smb_rw_param_t *, param);
156faa1795aSjb150015 
157faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
158da6c28aaSamw }
159da6c28aaSamw 
160faa1795aSjb150015 void
161faa1795aSjb150015 smb_post_write_and_close(smb_request_t *sr)
162faa1795aSjb150015 {
163faa1795aSjb150015 	DTRACE_SMB_2(op__WriteAndClose__done, smb_request_t *, sr,
164faa1795aSjb150015 	    smb_rw_param_t *, sr->arg.rw);
165faa1795aSjb150015 
166faa1795aSjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
167faa1795aSjb150015 }
168faa1795aSjb150015 
169faa1795aSjb150015 smb_sdrc_t
170faa1795aSjb150015 smb_com_write_and_close(smb_request_t *sr)
171faa1795aSjb150015 {
172faa1795aSjb150015 	smb_rw_param_t *param = sr->arg.rw;
1732c2961f8Sjose borrego 	uint16_t count;
174faa1795aSjb150015 	int rc = 0;
175faa1795aSjb150015 
1762c2961f8Sjose borrego 	smbsr_lookup_file(sr);
177da6c28aaSamw 	if (sr->fid_ofile == NULL) {
178dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
179faa1795aSjb150015 		return (SDRC_ERROR);
180da6c28aaSamw 	}
181da6c28aaSamw 
182b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
183b89a8333Snatalie li - Sun Microsystems - Irvine United States 
184faa1795aSjb150015 	if (param->rw_count == 0) {
185da6c28aaSamw 		rc = smb_write_truncate(sr, param);
186da6c28aaSamw 	} else {
187da6c28aaSamw 		/*
188da6c28aaSamw 		 * There may be a bug here: should this be "3.#B"?
189da6c28aaSamw 		 */
190faa1795aSjb150015 		rc = smbsr_decode_data(sr, ".#B", param->rw_count,
191faa1795aSjb150015 		    &param->rw_vdb);
192da6c28aaSamw 
1932c2961f8Sjose borrego 		if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
194faa1795aSjb150015 			smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
195faa1795aSjb150015 			    ERRDOS, ERROR_INVALID_PARAMETER);
196faa1795aSjb150015 			return (SDRC_ERROR);
197da6c28aaSamw 		}
198da6c28aaSamw 
1992c2961f8Sjose borrego 		param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
200da6c28aaSamw 
201f96bd5c8SAlan Wright 		rc = smb_common_write(sr, param);
202da6c28aaSamw 	}
203da6c28aaSamw 
204da6c28aaSamw 	if (rc != 0) {
205faa1795aSjb150015 		if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
206dc20a302Sas200622 			smbsr_errno(sr, rc);
207faa1795aSjb150015 		return (SDRC_ERROR);
208da6c28aaSamw 	}
209da6c28aaSamw 
210c8ec8eeaSjose borrego 	smb_ofile_close(sr->fid_ofile, param->rw_last_write);
211da6c28aaSamw 
2122c2961f8Sjose borrego 	count = (uint16_t)param->rw_count;
2132c2961f8Sjose borrego 	rc = smbsr_encode_result(sr, 1, 0, "bww", 1, count, 0);
214faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
215da6c28aaSamw }
216da6c28aaSamw 
217da6c28aaSamw /*
218da6c28aaSamw  * Write count bytes to a file at the specified offset and then unlock
219da6c28aaSamw  * them.  Write behind is safe because the client should have the range
220da6c28aaSamw  * locked and this request is allowed to extend the file - note that
221faa1795aSjb150015  * offset is limited to 32-bits.
222faa1795aSjb150015  *
223faa1795aSjb150015  * Spec advice: it is an error for count to be zero.  For compatibility,
224faa1795aSjb150015  * we take no action and return success.
225da6c28aaSamw  *
226da6c28aaSamw  * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk
227da6c28aaSamw  * files.  Reject any attempt to use it on other shares.
228da6c28aaSamw  *
229da6c28aaSamw  * The response count indicates the actual number of bytes written, which
230da6c28aaSamw  * will equal the requested count on success.  If request and response
231da6c28aaSamw  * counts differ but there is no error, the client will assume that the
232da6c28aaSamw  * server encountered a resource issue.
233da6c28aaSamw  */
2347b59d02dSjb150015 smb_sdrc_t
235faa1795aSjb150015 smb_pre_write_and_unlock(smb_request_t *sr)
236da6c28aaSamw {
237faa1795aSjb150015 	smb_rw_param_t *param;
238da6c28aaSamw 	uint32_t off;
2392c2961f8Sjose borrego 	uint16_t count;
240da6c28aaSamw 	uint16_t remcnt;
241faa1795aSjb150015 	int rc;
242faa1795aSjb150015 
243faa1795aSjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
244faa1795aSjb150015 	sr->arg.rw = param;
245faa1795aSjb150015 	param->rw_magic = SMB_RW_MAGIC;
246faa1795aSjb150015 
2472c2961f8Sjose borrego 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt);
248faa1795aSjb150015 
2492c2961f8Sjose borrego 	param->rw_count = (uint32_t)count;
250faa1795aSjb150015 	param->rw_offset = (uint64_t)off;
251faa1795aSjb150015 
252faa1795aSjb150015 	DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr,
253faa1795aSjb150015 	    smb_rw_param_t *, param);
254faa1795aSjb150015 
255faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
256faa1795aSjb150015 }
257faa1795aSjb150015 
258faa1795aSjb150015 void
259faa1795aSjb150015 smb_post_write_and_unlock(smb_request_t *sr)
260faa1795aSjb150015 {
261faa1795aSjb150015 	DTRACE_SMB_2(op__WriteAndUnlock__done, smb_request_t *, sr,
262faa1795aSjb150015 	    smb_rw_param_t *, sr->arg.rw);
263faa1795aSjb150015 
264faa1795aSjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
265faa1795aSjb150015 }
266faa1795aSjb150015 
267faa1795aSjb150015 smb_sdrc_t
268faa1795aSjb150015 smb_com_write_and_unlock(smb_request_t *sr)
269faa1795aSjb150015 {
270faa1795aSjb150015 	smb_rw_param_t *param = sr->arg.rw;
271faa1795aSjb150015 	uint32_t status;
272da6c28aaSamw 	int rc = 0;
273da6c28aaSamw 
274da6c28aaSamw 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
275dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
276faa1795aSjb150015 		return (SDRC_ERROR);
277da6c28aaSamw 	}
278da6c28aaSamw 
2792c2961f8Sjose borrego 	smbsr_lookup_file(sr);
280da6c28aaSamw 	if (sr->fid_ofile == NULL) {
281dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
282faa1795aSjb150015 		return (SDRC_ERROR);
283da6c28aaSamw 	}
284da6c28aaSamw 
285b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
286b89a8333Snatalie li - Sun Microsystems - Irvine United States 
287faa1795aSjb150015 	if (param->rw_count == 0) {
288faa1795aSjb150015 		rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0);
289faa1795aSjb150015 		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
290da6c28aaSamw 	}
291da6c28aaSamw 
2922c2961f8Sjose borrego 
293faa1795aSjb150015 	rc = smbsr_decode_data(sr, "D", &param->rw_vdb);
294da6c28aaSamw 
2952c2961f8Sjose borrego 	if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) {
296faa1795aSjb150015 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
297faa1795aSjb150015 		    ERRDOS, ERROR_INVALID_PARAMETER);
298faa1795aSjb150015 		return (SDRC_ERROR);
299da6c28aaSamw 	}
300da6c28aaSamw 
3012c2961f8Sjose borrego 	param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
302da6c28aaSamw 
303f96bd5c8SAlan Wright 	if ((rc = smb_common_write(sr, param)) != 0) {
304faa1795aSjb150015 		if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
305dc20a302Sas200622 			smbsr_errno(sr, rc);
306faa1795aSjb150015 		return (SDRC_ERROR);
307da6c28aaSamw 	}
308da6c28aaSamw 
309faa1795aSjb150015 	status = smb_unlock_range(sr, sr->fid_ofile->f_node, param->rw_offset,
310faa1795aSjb150015 	    (uint64_t)param->rw_count);
311faa1795aSjb150015 	if (status != NT_STATUS_SUCCESS) {
312dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
313148c5f43SAlan Wright 		    ERRDOS, ERROR_NOT_LOCKED);
314faa1795aSjb150015 		return (SDRC_ERROR);
315da6c28aaSamw 	}
316da6c28aaSamw 
3172c2961f8Sjose borrego 	rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
3182c2961f8Sjose borrego 	    (uint16_t)param->rw_count, 0);
319faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
320da6c28aaSamw }
321da6c28aaSamw 
322da6c28aaSamw /*
323da6c28aaSamw  * Write bytes to a file (SMB Core).  This request was extended in
324da6c28aaSamw  * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
325da6c28aaSamw  * 14, instead of 12, and including additional offset information.
326da6c28aaSamw  *
327da6c28aaSamw  * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE
328da6c28aaSamw  * to truncate a file.  A zero length merely transfers zero bytes.
329da6c28aaSamw  *
330da6c28aaSamw  * If bit 0 of WriteMode is set, Fid must refer to a disk file and
331da6c28aaSamw  * the data must be on stable storage before responding.
3322c2961f8Sjose borrego  *
3332c2961f8Sjose borrego  * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5:
3342c2961f8Sjose borrego  * If CAP_LARGE_WRITEX is set, the byte count may be larger than the
3352c2961f8Sjose borrego  * negotiated buffer size and the server is expected to write the
3362c2961f8Sjose borrego  * number of bytes specified.
337da6c28aaSamw  */
3387b59d02dSjb150015 smb_sdrc_t
339faa1795aSjb150015 smb_pre_write_andx(smb_request_t *sr)
340da6c28aaSamw {
341faa1795aSjb150015 	smb_rw_param_t *param;
342da6c28aaSamw 	uint32_t off_low;
343da6c28aaSamw 	uint32_t off_high;
3442c2961f8Sjose borrego 	uint16_t datalen_low;
3452c2961f8Sjose borrego 	uint16_t datalen_high;
346da6c28aaSamw 	uint16_t remcnt;
347faa1795aSjb150015 	int rc;
348da6c28aaSamw 
349faa1795aSjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
350faa1795aSjb150015 	sr->arg.rw = param;
351faa1795aSjb150015 	param->rw_magic = SMB_RW_MAGIC;
352da6c28aaSamw 
353da6c28aaSamw 	if (sr->smb_wct == 14) {
3542c2961f8Sjose borrego 		rc = smbsr_decode_vwv(sr, "4.wl4.wwwwwl", &sr->smb_fid,
3552c2961f8Sjose borrego 		    &off_low, &param->rw_mode, &remcnt, &datalen_high,
3562c2961f8Sjose borrego 		    &datalen_low, &param->rw_dsoff, &off_high);
357da6c28aaSamw 
358*1fb4a876SGordon Ross 		if (param->rw_dsoff >= 63)
359faa1795aSjb150015 			param->rw_dsoff -= 63;
360faa1795aSjb150015 		param->rw_offset = ((uint64_t)off_high << 32) | off_low;
361*1fb4a876SGordon Ross 	} else if (sr->smb_wct == 12) {
3622c2961f8Sjose borrego 		rc = smbsr_decode_vwv(sr, "4.wl4.wwwww", &sr->smb_fid,
3632c2961f8Sjose borrego 		    &off_low, &param->rw_mode, &remcnt, &datalen_high,
3642c2961f8Sjose borrego 		    &datalen_low, &param->rw_dsoff);
365da6c28aaSamw 
366*1fb4a876SGordon Ross 		if (param->rw_dsoff >= 59)
367faa1795aSjb150015 			param->rw_dsoff -= 59;
368*1fb4a876SGordon Ross 		param->rw_offset = (uint64_t)off_low;
369*1fb4a876SGordon Ross 		/* off_high not present */
370*1fb4a876SGordon Ross 	} else {
371*1fb4a876SGordon Ross 		rc = -1;
372da6c28aaSamw 	}
373da6c28aaSamw 
3743a6c5f83SAlan Wright 	param->rw_count = (uint32_t)datalen_low;
3753a6c5f83SAlan Wright 
376*1fb4a876SGordon Ross 	/*
377*1fb4a876SGordon Ross 	 * Work-around a Win7 bug, where it fails to set the
378*1fb4a876SGordon Ross 	 * CAP_LARGE_WRITEX flag during session setup.  Assume
379*1fb4a876SGordon Ross 	 * a large write if the data remaining is >= 64k.
380*1fb4a876SGordon Ross 	 */
381*1fb4a876SGordon Ross 	if ((sr->session->capabilities & CAP_LARGE_WRITEX) != 0 ||
382*1fb4a876SGordon Ross 	    (sr->smb_data.max_bytes > (sr->smb_data.chain_offset + 0xFFFF)))
3833a6c5f83SAlan Wright 		param->rw_count |= ((uint32_t)datalen_high << 16);
3842c2961f8Sjose borrego 
385faa1795aSjb150015 	DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr,
386faa1795aSjb150015 	    smb_rw_param_t *, param);
387faa1795aSjb150015 
388faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
389da6c28aaSamw }
390da6c28aaSamw 
391faa1795aSjb150015 void
392faa1795aSjb150015 smb_post_write_andx(smb_request_t *sr)
393faa1795aSjb150015 {
394faa1795aSjb150015 	DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr,
395faa1795aSjb150015 	    smb_rw_param_t *, sr->arg.rw);
396faa1795aSjb150015 
397faa1795aSjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
398faa1795aSjb150015 }
399faa1795aSjb150015 
400faa1795aSjb150015 smb_sdrc_t
401faa1795aSjb150015 smb_com_write_andx(smb_request_t *sr)
402faa1795aSjb150015 {
403faa1795aSjb150015 	smb_rw_param_t *param = sr->arg.rw;
4042c2961f8Sjose borrego 	uint16_t count_high;
4052c2961f8Sjose borrego 	uint16_t count_low;
406faa1795aSjb150015 	int rc;
407faa1795aSjb150015 
408faa1795aSjb150015 	ASSERT(param);
409faa1795aSjb150015 	ASSERT(param->rw_magic == SMB_RW_MAGIC);
410faa1795aSjb150015 
4112c2961f8Sjose borrego 	smbsr_lookup_file(sr);
412da6c28aaSamw 	if (sr->fid_ofile == NULL) {
413dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
414faa1795aSjb150015 		return (SDRC_ERROR);
415da6c28aaSamw 	}
416da6c28aaSamw 
417b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
418b89a8333Snatalie li - Sun Microsystems - Irvine United States 
419faa1795aSjb150015 	if (SMB_WRMODE_IS_STABLE(param->rw_mode) &&
420f96bd5c8SAlan Wright 	    STYPE_ISIPC(sr->tid_tree->t_res_type)) {
421dc20a302Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRaccess);
422faa1795aSjb150015 		return (SDRC_ERROR);
423da6c28aaSamw 	}
424da6c28aaSamw 
425faa1795aSjb150015 	rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count,
426faa1795aSjb150015 	    &param->rw_vdb);
4272c2961f8Sjose borrego 
4282c2961f8Sjose borrego 	if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
429faa1795aSjb150015 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
430faa1795aSjb150015 		    ERRDOS, ERROR_INVALID_PARAMETER);
431faa1795aSjb150015 		return (SDRC_ERROR);
432da6c28aaSamw 	}
433da6c28aaSamw 
4342c2961f8Sjose borrego 	param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
435da6c28aaSamw 
436faa1795aSjb150015 	if (param->rw_count != 0) {
437f96bd5c8SAlan Wright 		if ((rc = smb_common_write(sr, param)) != 0) {
438faa1795aSjb150015 			if (sr->smb_error.status !=
439faa1795aSjb150015 			    NT_STATUS_FILE_LOCK_CONFLICT)
440dc20a302Sas200622 				smbsr_errno(sr, rc);
441faa1795aSjb150015 			return (SDRC_ERROR);
442da6c28aaSamw 		}
443da6c28aaSamw 	}
444da6c28aaSamw 
4452c2961f8Sjose borrego 	count_low = param->rw_count & 0xFFFF;
4462c2961f8Sjose borrego 	count_high = (param->rw_count >> 16) & 0xFF;
4472c2961f8Sjose borrego 
4482c2961f8Sjose borrego 	rc = smbsr_encode_result(sr, 6, 0, "bb1.wwwwww",
4492c2961f8Sjose borrego 	    6, sr->andx_com, 15, count_low, 0, count_high, 0, 0);
450da6c28aaSamw 
451faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
452da6c28aaSamw }
453da6c28aaSamw 
454da6c28aaSamw /*
455da6c28aaSamw  * Common function for writing files or IPC/MSRPC named pipes.
456da6c28aaSamw  *
457da6c28aaSamw  * Returns errno values.
458da6c28aaSamw  */
459f96bd5c8SAlan Wright int
460f96bd5c8SAlan Wright smb_common_write(smb_request_t *sr, smb_rw_param_t *param)
461da6c28aaSamw {
462037cac00Sjoyce mcintosh 	smb_ofile_t *ofile = sr->fid_ofile;
463da6c28aaSamw 	smb_node_t *node;
4643db3f65cSamw 	int stability = 0;
465da6c28aaSamw 	uint32_t lcount;
466da6c28aaSamw 	int rc = 0;
467da6c28aaSamw 
468da6c28aaSamw 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
469da6c28aaSamw 	case STYPE_DISKTREE:
470f96bd5c8SAlan Wright 	case STYPE_PRINTQ:
471da6c28aaSamw 		node = ofile->f_node;
472da6c28aaSamw 
473037cac00Sjoyce mcintosh 		if (!smb_node_is_dir(node)) {
474faa1795aSjb150015 			rc = smb_lock_range_access(sr, node, param->rw_offset,
475faa1795aSjb150015 			    param->rw_count, B_TRUE);
476faa1795aSjb150015 			if (rc != NT_STATUS_SUCCESS) {
477faa1795aSjb150015 				smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
478faa1795aSjb150015 				    ERRDOS, ERROR_LOCK_VIOLATION);
479faa1795aSjb150015 				return (EACCES);
480faa1795aSjb150015 			}
481da6c28aaSamw 		}
482da6c28aaSamw 
483faa1795aSjb150015 		if (SMB_WRMODE_IS_STABLE(param->rw_mode) ||
484da6c28aaSamw 		    (node->flags & NODE_FLAGS_WRITE_THROUGH)) {
4853db3f65cSamw 			stability = FSYNC;
486da6c28aaSamw 		}
487da6c28aaSamw 
488da6c28aaSamw 		rc = smb_fsop_write(sr, sr->user_cr, node,
489037cac00Sjoyce mcintosh 		    &param->rw_vdb.vdb_uio, &lcount, stability);
490da6c28aaSamw 
491da6c28aaSamw 		if (rc)
492da6c28aaSamw 			return (rc);
493da6c28aaSamw 
4945fd03bc0SGordon Ross 		/*
4955fd03bc0SGordon Ross 		 * Used to have code here to set mtime.
4965fd03bc0SGordon Ross 		 * We have just done a write, so we know
4975fd03bc0SGordon Ross 		 * the file system will update mtime.
4985fd03bc0SGordon Ross 		 * No need to do it again here.
4995fd03bc0SGordon Ross 		 *
5005fd03bc0SGordon Ross 		 * However, keep track of the fact that
5015fd03bc0SGordon Ross 		 * we have written data via this handle.
5025fd03bc0SGordon Ross 		 */
5035fd03bc0SGordon Ross 		ofile->f_written = B_TRUE;
504da6c28aaSamw 
505cb174861Sjoyce mcintosh 		if (!smb_node_is_dir(node))
506cb174861Sjoyce mcintosh 			smb_oplock_break_levelII(node);
507cb174861Sjoyce mcintosh 
5082c2961f8Sjose borrego 		param->rw_count = lcount;
509da6c28aaSamw 		break;
510da6c28aaSamw 
511da6c28aaSamw 	case STYPE_IPC:
5122c2961f8Sjose borrego 		param->rw_count = param->rw_vdb.vdb_uio.uio_resid;
513da6c28aaSamw 
5142c2961f8Sjose borrego 		if ((rc = smb_opipe_write(sr, &param->rw_vdb.vdb_uio)) != 0)
515faa1795aSjb150015 			param->rw_count = 0;
516da6c28aaSamw 		break;
517da6c28aaSamw 
518da6c28aaSamw 	default:
519da6c28aaSamw 		rc = EACCES;
520da6c28aaSamw 		break;
521da6c28aaSamw 	}
522da6c28aaSamw 
523da6c28aaSamw 	if (rc != 0)
524da6c28aaSamw 		return (rc);
525da6c28aaSamw 
526da6c28aaSamw 	mutex_enter(&ofile->f_mutex);
527faa1795aSjb150015 	ofile->f_seek_pos = param->rw_offset + param->rw_count;
528da6c28aaSamw 	mutex_exit(&ofile->f_mutex);
529da6c28aaSamw 	return (rc);
530da6c28aaSamw }
531da6c28aaSamw 
532da6c28aaSamw /*
533da6c28aaSamw  * Truncate a disk file to the specified offset.
534da6c28aaSamw  * Typically, w_count will be zero here.
535da6c28aaSamw  *
536037cac00Sjoyce mcintosh  * Note that smb_write_andx cannot be used to reduce the file size so,
537037cac00Sjoyce mcintosh  * if this is required, smb_write is called with a count of zero and
538037cac00Sjoyce mcintosh  * the appropriate file length in offset. The file should be resized
539037cac00Sjoyce mcintosh  * to the length specified by the offset.
540037cac00Sjoyce mcintosh  *
541da6c28aaSamw  * Returns errno values.
542da6c28aaSamw  */
5437b59d02dSjb150015 static int
544faa1795aSjb150015 smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param)
545da6c28aaSamw {
546037cac00Sjoyce mcintosh 	smb_ofile_t *ofile = sr->fid_ofile;
547da6c28aaSamw 	smb_node_t *node = ofile->f_node;
548037cac00Sjoyce mcintosh 	smb_attr_t attr;
5497b59d02dSjb150015 	uint32_t status;
550da6c28aaSamw 	int rc;
551da6c28aaSamw 
552f96bd5c8SAlan Wright 	if (STYPE_ISIPC(sr->tid_tree->t_res_type))
553da6c28aaSamw 		return (0);
554da6c28aaSamw 
5552c2961f8Sjose borrego 	mutex_enter(&node->n_mutex);
556037cac00Sjoyce mcintosh 	if (!smb_node_is_dir(node)) {
557faa1795aSjb150015 		status = smb_lock_range_access(sr, node, param->rw_offset,
558faa1795aSjb150015 		    param->rw_count, B_TRUE);
5597b59d02dSjb150015 		if (status != NT_STATUS_SUCCESS) {
5602c2961f8Sjose borrego 			mutex_exit(&node->n_mutex);
561faa1795aSjb150015 			smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
562faa1795aSjb150015 			    ERRDOS, ERROR_LOCK_VIOLATION);
5637b59d02dSjb150015 			return (EACCES);
564dc20a302Sas200622 		}
565dc20a302Sas200622 	}
5662c2961f8Sjose borrego 	mutex_exit(&node->n_mutex);
567dc20a302Sas200622 
568037cac00Sjoyce mcintosh 	bzero(&attr, sizeof (smb_attr_t));
569037cac00Sjoyce mcintosh 	attr.sa_mask = SMB_AT_SIZE;
570037cac00Sjoyce mcintosh 	attr.sa_vattr.va_size = param->rw_offset;
571037cac00Sjoyce mcintosh 	rc = smb_node_setattr(sr, node, sr->user_cr, ofile, &attr);
572037cac00Sjoyce mcintosh 	if (rc != 0)
573da6c28aaSamw 		return (rc);
574da6c28aaSamw 
575da6c28aaSamw 	mutex_enter(&ofile->f_mutex);
576faa1795aSjb150015 	ofile->f_seek_pos = param->rw_offset + param->rw_count;
577da6c28aaSamw 	mutex_exit(&ofile->f_mutex);
578da6c28aaSamw 	return (0);
579da6c28aaSamw }
580