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.
24a8e9db1cSGordon Ross * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
25*f8e30ca2SGordon Ross * Copyright 2022 RackTop Systems, Inc.
26da6c28aaSamw */
27da6c28aaSamw
28da6c28aaSamw #include <sys/sdt.h>
29bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
30da6c28aaSamw #include <smbsrv/smb_fsops.h>
31da6c28aaSamw #include <smbsrv/netbios.h>
32da6c28aaSamw
33da6c28aaSamw
34faa1795aSjb static int smb_write_truncate(smb_request_t *, smb_rw_param_t *);
35da6c28aaSamw
36da6c28aaSamw
37da6c28aaSamw /*
38da6c28aaSamw * Write count bytes at the specified offset in a file. The offset is
39da6c28aaSamw * limited to 32-bits. If the count is zero, the file is truncated to
40da6c28aaSamw * the length specified by the offset.
41da6c28aaSamw *
42da6c28aaSamw * The response count indicates the actual number of bytes written, which
43da6c28aaSamw * will equal the requested count on success. If request and response
44da6c28aaSamw * counts differ but there is no error, the client will assume that the
45da6c28aaSamw * server encountered a resource issue.
46da6c28aaSamw */
477b59d02dSjb smb_sdrc_t
smb_pre_write(smb_request_t * sr)48faa1795aSjb smb_pre_write(smb_request_t *sr)
49da6c28aaSamw {
50faa1795aSjb smb_rw_param_t *param;
51da6c28aaSamw uint32_t off;
522c2961f8Sjose borrego uint16_t count;
53da6c28aaSamw int rc;
54da6c28aaSamw
55faa1795aSjb param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
56faa1795aSjb sr->arg.rw = param;
57faa1795aSjb param->rw_magic = SMB_RW_MAGIC;
58da6c28aaSamw
592c2961f8Sjose borrego rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off);
60faa1795aSjb
612c2961f8Sjose borrego param->rw_count = (uint32_t)count;
62faa1795aSjb param->rw_offset = (uint64_t)off;
632c2961f8Sjose borrego param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
64faa1795aSjb
6593bc28dbSGordon Ross DTRACE_SMB_START(op__Write, smb_request_t *, sr); /* arg.rw */
66faa1795aSjb
67faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
68faa1795aSjb }
69faa1795aSjb
70faa1795aSjb void
smb_post_write(smb_request_t * sr)71faa1795aSjb smb_post_write(smb_request_t *sr)
72faa1795aSjb {
7393bc28dbSGordon Ross DTRACE_SMB_DONE(op__Write, smb_request_t *, sr); /* arg.rw */
74faa1795aSjb
75faa1795aSjb kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
76faa1795aSjb }
77faa1795aSjb
78faa1795aSjb smb_sdrc_t
smb_com_write(smb_request_t * sr)79faa1795aSjb smb_com_write(smb_request_t *sr)
80faa1795aSjb {
81faa1795aSjb smb_rw_param_t *param = sr->arg.rw;
82faa1795aSjb int rc;
83da6c28aaSamw
842c2961f8Sjose borrego smbsr_lookup_file(sr);
85da6c28aaSamw if (sr->fid_ofile == NULL) {
86dc20a302Sas smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
87faa1795aSjb return (SDRC_ERROR);
88da6c28aaSamw }
89da6c28aaSamw
90b89a8333Snatalie li - Sun Microsystems - Irvine United States sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
91b89a8333Snatalie li - Sun Microsystems - Irvine United States
92faa1795aSjb if (param->rw_count == 0) {
93da6c28aaSamw rc = smb_write_truncate(sr, param);
94da6c28aaSamw } else {
95faa1795aSjb rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb);
96da6c28aaSamw
972c2961f8Sjose borrego if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
98faa1795aSjb smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
99faa1795aSjb ERRDOS, ERROR_INVALID_PARAMETER);
100faa1795aSjb return (SDRC_ERROR);
101da6c28aaSamw }
102da6c28aaSamw
1032c2961f8Sjose borrego param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
104da6c28aaSamw
105f96bd5c8SAlan Wright rc = smb_common_write(sr, param);
106da6c28aaSamw }
107da6c28aaSamw
108da6c28aaSamw if (rc != 0) {
109faa1795aSjb if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
110faa1795aSjb smbsr_errno(sr, rc);
111faa1795aSjb return (SDRC_ERROR);
112da6c28aaSamw }
113da6c28aaSamw
1142c2961f8Sjose borrego rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
1152c2961f8Sjose borrego (uint16_t)param->rw_count, 0);
116faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
117da6c28aaSamw }
118da6c28aaSamw
119da6c28aaSamw /*
120da6c28aaSamw * Write count bytes to a file and then close the file. This function
121da6c28aaSamw * can only be used to write to 32-bit offsets and the client must set
122da6c28aaSamw * WordCount (6 or 12) correctly in order to locate the data to be
123da6c28aaSamw * written. If an error occurs on the write, the file should still be
124da6c28aaSamw * closed. If Count is 0, the file is truncated (or extended) to offset.
125da6c28aaSamw *
126da6c28aaSamw * If the last_write time is non-zero, last_write should be used to set
127da6c28aaSamw * the mtime. Otherwise the file system stamps the mtime. Failure to
128da6c28aaSamw * set mtime should not result in an error response.
129da6c28aaSamw */
1307b59d02dSjb smb_sdrc_t
smb_pre_write_and_close(smb_request_t * sr)131faa1795aSjb smb_pre_write_and_close(smb_request_t *sr)
132da6c28aaSamw {
133faa1795aSjb smb_rw_param_t *param;
134da6c28aaSamw uint32_t off;
1352c2961f8Sjose borrego uint16_t count;
136faa1795aSjb int rc;
137da6c28aaSamw
138faa1795aSjb param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
139faa1795aSjb sr->arg.rw = param;
140faa1795aSjb param->rw_magic = SMB_RW_MAGIC;
141da6c28aaSamw
142da6c28aaSamw if (sr->smb_wct == 12) {
143da6c28aaSamw rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid,
1442c2961f8Sjose borrego &count, &off, ¶m->rw_last_write);
145da6c28aaSamw } else {
146da6c28aaSamw rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid,
1472c2961f8Sjose borrego &count, &off, ¶m->rw_last_write);
148da6c28aaSamw }
149da6c28aaSamw
1502c2961f8Sjose borrego param->rw_count = (uint32_t)count;
151faa1795aSjb param->rw_offset = (uint64_t)off;
152faa1795aSjb
15393bc28dbSGordon Ross DTRACE_SMB_START(op__WriteAndClose, smb_request_t *, sr); /* arg.rw */
154faa1795aSjb
155faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
156faa1795aSjb }
157faa1795aSjb
158faa1795aSjb void
smb_post_write_and_close(smb_request_t * sr)159faa1795aSjb smb_post_write_and_close(smb_request_t *sr)
160faa1795aSjb {
16193bc28dbSGordon Ross DTRACE_SMB_DONE(op__WriteAndClose, smb_request_t *, sr); /* arg.rw */
162faa1795aSjb
163faa1795aSjb kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
164faa1795aSjb }
165faa1795aSjb
166faa1795aSjb smb_sdrc_t
smb_com_write_and_close(smb_request_t * sr)167faa1795aSjb smb_com_write_and_close(smb_request_t *sr)
168faa1795aSjb {
169faa1795aSjb smb_rw_param_t *param = sr->arg.rw;
1702c2961f8Sjose borrego uint16_t count;
171faa1795aSjb int rc = 0;
172da6c28aaSamw
1732c2961f8Sjose borrego smbsr_lookup_file(sr);
174da6c28aaSamw if (sr->fid_ofile == NULL) {
175dc20a302Sas smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
176faa1795aSjb return (SDRC_ERROR);
177da6c28aaSamw }
178da6c28aaSamw
179b89a8333Snatalie li - Sun Microsystems - Irvine United States sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
180b89a8333Snatalie li - Sun Microsystems - Irvine United States
181faa1795aSjb if (param->rw_count == 0) {
182da6c28aaSamw rc = smb_write_truncate(sr, param);
183da6c28aaSamw } else {
184da6c28aaSamw /*
185da6c28aaSamw * There may be a bug here: should this be "3.#B"?
186da6c28aaSamw */
187faa1795aSjb rc = smbsr_decode_data(sr, ".#B", param->rw_count,
188faa1795aSjb ¶m->rw_vdb);
189da6c28aaSamw
1902c2961f8Sjose borrego if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
191faa1795aSjb smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
192faa1795aSjb ERRDOS, ERROR_INVALID_PARAMETER);
193faa1795aSjb return (SDRC_ERROR);
194da6c28aaSamw }
195da6c28aaSamw
1962c2961f8Sjose borrego param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
197da6c28aaSamw
198f96bd5c8SAlan Wright rc = smb_common_write(sr, param);
199da6c28aaSamw }
200da6c28aaSamw
201da6c28aaSamw if (rc != 0) {
202faa1795aSjb if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
203faa1795aSjb smbsr_errno(sr, rc);
204faa1795aSjb return (SDRC_ERROR);
205da6c28aaSamw }
206da6c28aaSamw
207c8ec8eeaSjose borrego smb_ofile_close(sr->fid_ofile, param->rw_last_write);
208da6c28aaSamw
2092c2961f8Sjose borrego count = (uint16_t)param->rw_count;
2102c2961f8Sjose borrego rc = smbsr_encode_result(sr, 1, 0, "bww", 1, count, 0);
211faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
212da6c28aaSamw }
213da6c28aaSamw
214da6c28aaSamw /*
215da6c28aaSamw * Write count bytes to a file at the specified offset and then unlock
216da6c28aaSamw * them. Write behind is safe because the client should have the range
217da6c28aaSamw * locked and this request is allowed to extend the file - note that
218faa1795aSjb * offset is limited to 32-bits.
219faa1795aSjb *
220faa1795aSjb * Spec advice: it is an error for count to be zero. For compatibility,
221faa1795aSjb * we take no action and return success.
222da6c28aaSamw *
223da6c28aaSamw * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk
224da6c28aaSamw * files. Reject any attempt to use it on other shares.
225da6c28aaSamw *
226da6c28aaSamw * The response count indicates the actual number of bytes written, which
227da6c28aaSamw * will equal the requested count on success. If request and response
228da6c28aaSamw * counts differ but there is no error, the client will assume that the
229da6c28aaSamw * server encountered a resource issue.
230da6c28aaSamw */
2317b59d02dSjb smb_sdrc_t
smb_pre_write_and_unlock(smb_request_t * sr)232faa1795aSjb smb_pre_write_and_unlock(smb_request_t *sr)
233da6c28aaSamw {
234faa1795aSjb smb_rw_param_t *param;
235da6c28aaSamw uint32_t off;
2362c2961f8Sjose borrego uint16_t count;
237da6c28aaSamw uint16_t remcnt;
238faa1795aSjb int rc;
239faa1795aSjb
240faa1795aSjb param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
241faa1795aSjb sr->arg.rw = param;
242faa1795aSjb param->rw_magic = SMB_RW_MAGIC;
243faa1795aSjb
2442c2961f8Sjose borrego rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt);
245faa1795aSjb
2462c2961f8Sjose borrego param->rw_count = (uint32_t)count;
247faa1795aSjb param->rw_offset = (uint64_t)off;
248faa1795aSjb
24993bc28dbSGordon Ross DTRACE_SMB_START(op__WriteAndUnlock, smb_request_t *, sr); /* arg.rw */
250faa1795aSjb
251faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
252faa1795aSjb }
253faa1795aSjb
254faa1795aSjb void
smb_post_write_and_unlock(smb_request_t * sr)255faa1795aSjb smb_post_write_and_unlock(smb_request_t *sr)
256faa1795aSjb {
25793bc28dbSGordon Ross DTRACE_SMB_DONE(op__WriteAndUnlock, smb_request_t *, sr); /* arg.rw */
258faa1795aSjb
259faa1795aSjb kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
260faa1795aSjb }
261faa1795aSjb
262faa1795aSjb smb_sdrc_t
smb_com_write_and_unlock(smb_request_t * sr)263faa1795aSjb smb_com_write_and_unlock(smb_request_t *sr)
264faa1795aSjb {
265faa1795aSjb smb_rw_param_t *param = sr->arg.rw;
2660897f7fbSGordon Ross uint32_t lk_pid;
267faa1795aSjb uint32_t status;
268da6c28aaSamw int rc = 0;
269da6c28aaSamw
270da6c28aaSamw if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
271dc20a302Sas smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
272faa1795aSjb return (SDRC_ERROR);
273da6c28aaSamw }
274da6c28aaSamw
2752c2961f8Sjose borrego smbsr_lookup_file(sr);
276da6c28aaSamw if (sr->fid_ofile == NULL) {
277dc20a302Sas smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
278faa1795aSjb return (SDRC_ERROR);
279da6c28aaSamw }
280da6c28aaSamw
281b89a8333Snatalie li - Sun Microsystems - Irvine United States sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
282b89a8333Snatalie li - Sun Microsystems - Irvine United States
283faa1795aSjb if (param->rw_count == 0) {
284faa1795aSjb rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0);
285faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
286da6c28aaSamw }
287da6c28aaSamw
2882c2961f8Sjose borrego
289faa1795aSjb rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb);
290da6c28aaSamw
2912c2961f8Sjose borrego if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) {
292faa1795aSjb smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
293faa1795aSjb ERRDOS, ERROR_INVALID_PARAMETER);
294faa1795aSjb return (SDRC_ERROR);
295da6c28aaSamw }
296da6c28aaSamw
2972c2961f8Sjose borrego param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
298da6c28aaSamw
299f96bd5c8SAlan Wright if ((rc = smb_common_write(sr, param)) != 0) {
300faa1795aSjb if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
301faa1795aSjb smbsr_errno(sr, rc);
302faa1795aSjb return (SDRC_ERROR);
303da6c28aaSamw }
304da6c28aaSamw
3050897f7fbSGordon Ross
3060897f7fbSGordon Ross /* Note: SMB1 locking uses 16-bit PIDs. */
3070897f7fbSGordon Ross lk_pid = sr->smb_pid & 0xFFFF;
3080897f7fbSGordon Ross
3090897f7fbSGordon Ross status = smb_unlock_range(sr, param->rw_offset,
3100897f7fbSGordon Ross (uint64_t)param->rw_count, lk_pid);
311faa1795aSjb if (status != NT_STATUS_SUCCESS) {
312dc20a302Sas smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
313148c5f43SAlan Wright ERRDOS, ERROR_NOT_LOCKED);
314faa1795aSjb return (SDRC_ERROR);
315da6c28aaSamw }
316da6c28aaSamw
3172c2961f8Sjose borrego rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
3182c2961f8Sjose borrego (uint16_t)param->rw_count, 0);
319faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
320da6c28aaSamw }
321da6c28aaSamw
32293bc28dbSGordon Ross /*
32393bc28dbSGordon Ross * The SMB_COM_WRITE_RAW protocol was a negotiated option introduced in
32493bc28dbSGordon Ross * SMB Core Plus to maximize performance when writing a large block
32593bc28dbSGordon Ross * of data to a server. It's obsolete and no longer supported.
32693bc28dbSGordon Ross *
32793bc28dbSGordon Ross * We keep a handler for it so the dtrace provider can see if
32893bc28dbSGordon Ross * the client tried to use this command.
32993bc28dbSGordon Ross */
33093bc28dbSGordon Ross smb_sdrc_t
smb_pre_write_raw(smb_request_t * sr)33193bc28dbSGordon Ross smb_pre_write_raw(smb_request_t *sr)
33293bc28dbSGordon Ross {
33393bc28dbSGordon Ross DTRACE_SMB_START(op__WriteRaw, smb_request_t *, sr);
33493bc28dbSGordon Ross return (SDRC_SUCCESS);
33593bc28dbSGordon Ross }
33693bc28dbSGordon Ross
33793bc28dbSGordon Ross void
smb_post_write_raw(smb_request_t * sr)33893bc28dbSGordon Ross smb_post_write_raw(smb_request_t *sr)
33993bc28dbSGordon Ross {
34093bc28dbSGordon Ross DTRACE_SMB_DONE(op__WriteRaw, smb_request_t *, sr);
34193bc28dbSGordon Ross }
34293bc28dbSGordon Ross
34393bc28dbSGordon Ross smb_sdrc_t
smb_com_write_raw(struct smb_request * sr)34493bc28dbSGordon Ross smb_com_write_raw(struct smb_request *sr)
34593bc28dbSGordon Ross {
34693bc28dbSGordon Ross smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, ERRDOS,
34793bc28dbSGordon Ross ERROR_NOT_SUPPORTED);
34893bc28dbSGordon Ross return (SDRC_ERROR);
34993bc28dbSGordon Ross }
35093bc28dbSGordon Ross
351da6c28aaSamw /*
352da6c28aaSamw * Write bytes to a file (SMB Core). This request was extended in
353da6c28aaSamw * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
354da6c28aaSamw * 14, instead of 12, and including additional offset information.
355da6c28aaSamw *
356da6c28aaSamw * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE
357da6c28aaSamw * to truncate a file. A zero length merely transfers zero bytes.
358da6c28aaSamw *
359da6c28aaSamw * If bit 0 of WriteMode is set, Fid must refer to a disk file and
360da6c28aaSamw * the data must be on stable storage before responding.
3612c2961f8Sjose borrego *
3622c2961f8Sjose borrego * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5:
3632c2961f8Sjose borrego * If CAP_LARGE_WRITEX is set, the byte count may be larger than the
3642c2961f8Sjose borrego * negotiated buffer size and the server is expected to write the
3652c2961f8Sjose borrego * number of bytes specified.
366da6c28aaSamw */
3677b59d02dSjb smb_sdrc_t
smb_pre_write_andx(smb_request_t * sr)368faa1795aSjb smb_pre_write_andx(smb_request_t *sr)
369da6c28aaSamw {
370faa1795aSjb smb_rw_param_t *param;
371da6c28aaSamw uint32_t off_low;
372da6c28aaSamw uint32_t off_high;
3732c2961f8Sjose borrego uint16_t datalen_low;
3742c2961f8Sjose borrego uint16_t datalen_high;
375da6c28aaSamw uint16_t remcnt;
376faa1795aSjb int rc;
377da6c28aaSamw
378faa1795aSjb param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
379faa1795aSjb sr->arg.rw = param;
380faa1795aSjb param->rw_magic = SMB_RW_MAGIC;
381da6c28aaSamw
382da6c28aaSamw if (sr->smb_wct == 14) {
3832c2961f8Sjose borrego rc = smbsr_decode_vwv(sr, "4.wl4.wwwwwl", &sr->smb_fid,
3842c2961f8Sjose borrego &off_low, ¶m->rw_mode, &remcnt, &datalen_high,
3852c2961f8Sjose borrego &datalen_low, ¶m->rw_dsoff, &off_high);
386da6c28aaSamw
3871fb4a876SGordon Ross if (param->rw_dsoff >= 63)
3881fb4a876SGordon Ross param->rw_dsoff -= 63;
389faa1795aSjb param->rw_offset = ((uint64_t)off_high << 32) | off_low;
3901fb4a876SGordon Ross } else if (sr->smb_wct == 12) {
3912c2961f8Sjose borrego rc = smbsr_decode_vwv(sr, "4.wl4.wwwww", &sr->smb_fid,
3922c2961f8Sjose borrego &off_low, ¶m->rw_mode, &remcnt, &datalen_high,
3932c2961f8Sjose borrego &datalen_low, ¶m->rw_dsoff);
394da6c28aaSamw
3951fb4a876SGordon Ross if (param->rw_dsoff >= 59)
3961fb4a876SGordon Ross param->rw_dsoff -= 59;
397faa1795aSjb param->rw_offset = (uint64_t)off_low;
3981fb4a876SGordon Ross /* off_high not present */
3991fb4a876SGordon Ross } else {
4001fb4a876SGordon Ross rc = -1;
401da6c28aaSamw }
402da6c28aaSamw
4033a6c5f83SAlan Wright param->rw_count = (uint32_t)datalen_low;
4043a6c5f83SAlan Wright
4051fb4a876SGordon Ross /*
4061fb4a876SGordon Ross * Work-around a Win7 bug, where it fails to set the
4071fb4a876SGordon Ross * CAP_LARGE_WRITEX flag during session setup. Assume
4081fb4a876SGordon Ross * a large write if the data remaining is >= 64k.
4091fb4a876SGordon Ross */
4101fb4a876SGordon Ross if ((sr->session->capabilities & CAP_LARGE_WRITEX) != 0 ||
4111fb4a876SGordon Ross (sr->smb_data.max_bytes > (sr->smb_data.chain_offset + 0xFFFF)))
4123a6c5f83SAlan Wright param->rw_count |= ((uint32_t)datalen_high << 16);
4132c2961f8Sjose borrego
41493bc28dbSGordon Ross DTRACE_SMB_START(op__WriteX, smb_request_t *, sr); /* arg.rw */
415faa1795aSjb
416faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
417faa1795aSjb }
418faa1795aSjb
419faa1795aSjb void
smb_post_write_andx(smb_request_t * sr)420faa1795aSjb smb_post_write_andx(smb_request_t *sr)
421faa1795aSjb {
42293bc28dbSGordon Ross DTRACE_SMB_DONE(op__WriteX, smb_request_t *, sr); /* arg.rw */
423faa1795aSjb
424faa1795aSjb kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
425faa1795aSjb }
426faa1795aSjb
427faa1795aSjb smb_sdrc_t
smb_com_write_andx(smb_request_t * sr)428faa1795aSjb smb_com_write_andx(smb_request_t *sr)
429faa1795aSjb {
430faa1795aSjb smb_rw_param_t *param = sr->arg.rw;
4312c2961f8Sjose borrego uint16_t count_high;
4322c2961f8Sjose borrego uint16_t count_low;
433faa1795aSjb int rc;
434faa1795aSjb
435faa1795aSjb ASSERT(param);
436faa1795aSjb ASSERT(param->rw_magic == SMB_RW_MAGIC);
437da6c28aaSamw
4382c2961f8Sjose borrego smbsr_lookup_file(sr);
439da6c28aaSamw if (sr->fid_ofile == NULL) {
440dc20a302Sas smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
441faa1795aSjb return (SDRC_ERROR);
442da6c28aaSamw }
443da6c28aaSamw
444b89a8333Snatalie li - Sun Microsystems - Irvine United States sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
445b89a8333Snatalie li - Sun Microsystems - Irvine United States
446faa1795aSjb if (SMB_WRMODE_IS_STABLE(param->rw_mode) &&
447f96bd5c8SAlan Wright STYPE_ISIPC(sr->tid_tree->t_res_type)) {
448dc20a302Sas smbsr_error(sr, 0, ERRSRV, ERRaccess);
449faa1795aSjb return (SDRC_ERROR);
450da6c28aaSamw }
451da6c28aaSamw
452faa1795aSjb rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count,
453faa1795aSjb ¶m->rw_vdb);
4542c2961f8Sjose borrego
4552c2961f8Sjose borrego if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
456faa1795aSjb smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
457faa1795aSjb ERRDOS, ERROR_INVALID_PARAMETER);
458faa1795aSjb return (SDRC_ERROR);
459da6c28aaSamw }
460da6c28aaSamw
4612c2961f8Sjose borrego param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
462da6c28aaSamw
463faa1795aSjb if (param->rw_count != 0) {
464f96bd5c8SAlan Wright if ((rc = smb_common_write(sr, param)) != 0) {
465faa1795aSjb if (sr->smb_error.status !=
466faa1795aSjb NT_STATUS_FILE_LOCK_CONFLICT)
467faa1795aSjb smbsr_errno(sr, rc);
468faa1795aSjb return (SDRC_ERROR);
469da6c28aaSamw }
470da6c28aaSamw }
471da6c28aaSamw
4722c2961f8Sjose borrego count_low = param->rw_count & 0xFFFF;
4732c2961f8Sjose borrego count_high = (param->rw_count >> 16) & 0xFF;
4742c2961f8Sjose borrego
4752c2961f8Sjose borrego rc = smbsr_encode_result(sr, 6, 0, "bb1.wwwwww",
4762c2961f8Sjose borrego 6, sr->andx_com, 15, count_low, 0, count_high, 0, 0);
477da6c28aaSamw
478faa1795aSjb return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
479da6c28aaSamw }
480da6c28aaSamw
481da6c28aaSamw /*
482da6c28aaSamw * Common function for writing files or IPC/MSRPC named pipes.
483da6c28aaSamw *
484da6c28aaSamw * Returns errno values.
485da6c28aaSamw */
486f96bd5c8SAlan Wright int
smb_common_write(smb_request_t * sr,smb_rw_param_t * param)487f96bd5c8SAlan Wright smb_common_write(smb_request_t *sr, smb_rw_param_t *param)
488da6c28aaSamw {
489037cac00Sjoyce mcintosh smb_ofile_t *ofile = sr->fid_ofile;
490da6c28aaSamw smb_node_t *node;
4913db3f65cSamw int stability = 0;
492da6c28aaSamw uint32_t lcount;
493da6c28aaSamw int rc = 0;
494da6c28aaSamw
495da6c28aaSamw switch (sr->tid_tree->t_res_type & STYPE_MASK) {
496da6c28aaSamw case STYPE_DISKTREE:
497f96bd5c8SAlan Wright case STYPE_PRINTQ:
498da6c28aaSamw node = ofile->f_node;
499da6c28aaSamw
500037cac00Sjoyce mcintosh if (!smb_node_is_dir(node)) {
501faa1795aSjb rc = smb_lock_range_access(sr, node, param->rw_offset,
502faa1795aSjb param->rw_count, B_TRUE);
503faa1795aSjb if (rc != NT_STATUS_SUCCESS) {
504faa1795aSjb smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
505faa1795aSjb ERRDOS, ERROR_LOCK_VIOLATION);
506faa1795aSjb return (EACCES);
507faa1795aSjb }
508da6c28aaSamw }
509da6c28aaSamw
510faa1795aSjb if (SMB_WRMODE_IS_STABLE(param->rw_mode) ||
511da6c28aaSamw (node->flags & NODE_FLAGS_WRITE_THROUGH)) {
5123db3f65cSamw stability = FSYNC;
513da6c28aaSamw }
514da6c28aaSamw
51555f0a249SGordon Ross rc = smb_fsop_write(sr, sr->user_cr, node, ofile,
516037cac00Sjoyce mcintosh ¶m->rw_vdb.vdb_uio, &lcount, stability);
517da6c28aaSamw if (rc)
518da6c28aaSamw return (rc);
519*f8e30ca2SGordon Ross param->rw_count = lcount;
52094047d49SGordon Ross /* This revokes read cache delegations. */
52194047d49SGordon Ross (void) smb_oplock_break_WRITE(node, ofile);
522*f8e30ca2SGordon Ross /*
523*f8e30ca2SGordon Ross * Don't want the performance cost of generating
524*f8e30ca2SGordon Ross * change notify events on every write. Instead:
525*f8e30ca2SGordon Ross * Keep track of the fact that we have written
526*f8e30ca2SGordon Ross * data via this handle, and do change notify
527*f8e30ca2SGordon Ross * work on the first write, and during close.
528*f8e30ca2SGordon Ross */
529*f8e30ca2SGordon Ross if (ofile->f_written == B_FALSE) {
530*f8e30ca2SGordon Ross ofile->f_written = B_TRUE;
531*f8e30ca2SGordon Ross smb_node_notify_modified(node);
532*f8e30ca2SGordon Ross }
533da6c28aaSamw break;
534da6c28aaSamw
535da6c28aaSamw case STYPE_IPC:
5362c2961f8Sjose borrego param->rw_count = param->rw_vdb.vdb_uio.uio_resid;
537da6c28aaSamw
5382c2961f8Sjose borrego if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.vdb_uio)) != 0)
539faa1795aSjb param->rw_count = 0;
540da6c28aaSamw break;
541da6c28aaSamw
542da6c28aaSamw default:
543da6c28aaSamw rc = EACCES;
544da6c28aaSamw break;
545da6c28aaSamw }
546da6c28aaSamw
547da6c28aaSamw if (rc != 0)
548da6c28aaSamw return (rc);
549da6c28aaSamw
550da6c28aaSamw mutex_enter(&ofile->f_mutex);
551faa1795aSjb ofile->f_seek_pos = param->rw_offset + param->rw_count;
552da6c28aaSamw mutex_exit(&ofile->f_mutex);
553da6c28aaSamw return (rc);
554da6c28aaSamw }
555da6c28aaSamw
556da6c28aaSamw /*
557da6c28aaSamw * Truncate a disk file to the specified offset.
558da6c28aaSamw * Typically, w_count will be zero here.
559da6c28aaSamw *
560037cac00Sjoyce mcintosh * Note that smb_write_andx cannot be used to reduce the file size so,
561037cac00Sjoyce mcintosh * if this is required, smb_write is called with a count of zero and
562037cac00Sjoyce mcintosh * the appropriate file length in offset. The file should be resized
563037cac00Sjoyce mcintosh * to the length specified by the offset.
564037cac00Sjoyce mcintosh *
565da6c28aaSamw * Returns errno values.
566da6c28aaSamw */
5677b59d02dSjb static int
smb_write_truncate(smb_request_t * sr,smb_rw_param_t * param)568faa1795aSjb smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param)
569da6c28aaSamw {
570037cac00Sjoyce mcintosh smb_ofile_t *ofile = sr->fid_ofile;
571da6c28aaSamw smb_node_t *node = ofile->f_node;
572037cac00Sjoyce mcintosh smb_attr_t attr;
5737b59d02dSjb uint32_t status;
574da6c28aaSamw int rc;
575da6c28aaSamw
576f96bd5c8SAlan Wright if (STYPE_ISIPC(sr->tid_tree->t_res_type))
577da6c28aaSamw return (0);
578da6c28aaSamw
5792c2961f8Sjose borrego mutex_enter(&node->n_mutex);
580037cac00Sjoyce mcintosh if (!smb_node_is_dir(node)) {
581faa1795aSjb status = smb_lock_range_access(sr, node, param->rw_offset,
582faa1795aSjb param->rw_count, B_TRUE);
5837b59d02dSjb if (status != NT_STATUS_SUCCESS) {
5842c2961f8Sjose borrego mutex_exit(&node->n_mutex);
585faa1795aSjb smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
586faa1795aSjb ERRDOS, ERROR_LOCK_VIOLATION);
5877b59d02dSjb return (EACCES);
588dc20a302Sas }
589dc20a302Sas }
5902c2961f8Sjose borrego mutex_exit(&node->n_mutex);
591dc20a302Sas
592037cac00Sjoyce mcintosh bzero(&attr, sizeof (smb_attr_t));
593037cac00Sjoyce mcintosh attr.sa_mask = SMB_AT_SIZE;
594037cac00Sjoyce mcintosh attr.sa_vattr.va_size = param->rw_offset;
595037cac00Sjoyce mcintosh rc = smb_node_setattr(sr, node, sr->user_cr, ofile, &attr);
596037cac00Sjoyce mcintosh if (rc != 0)
597da6c28aaSamw return (rc);
598da6c28aaSamw
599da6c28aaSamw mutex_enter(&ofile->f_mutex);
600faa1795aSjb ofile->f_seek_pos = param->rw_offset + param->rw_count;
601da6c28aaSamw mutex_exit(&ofile->f_mutex);
602da6c28aaSamw return (0);
603da6c28aaSamw }
604