4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 #include <sys/sdt.h>
28 #include <smbsrv/smb_kproto.h>
29 #include <smbsrv/smb_fsops.h>
30 #include <smbsrv/netbios.h>
31
32
33 static int smb_write_truncate(smb_request_t *, smb_rw_param_t *);
34
35
36 /*
37 * Write count bytes at the specified offset in a file. The offset is
38 * limited to 32-bits. If the count is zero, the file is truncated to
39 * the length specified by the offset.
40 *
41 * The response count indicates the actual number of bytes written, which
42 * will equal the requested count on success. If request and response
43 * counts differ but there is no error, the client will assume that the
44 * server encountered a resource issue.
45 */
46 smb_sdrc_t
47 smb_pre_write(smb_request_t *sr)
48 {
49 smb_rw_param_t *param;
50 uint32_t off;
51 uint16_t count;
52 int rc;
53
54 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
55 sr->arg.rw = param;
56 param->rw_magic = SMB_RW_MAGIC;
57
58 rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off);
59
60 param->rw_count = (uint32_t)count;
61 param->rw_offset = (uint64_t)off;
62 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
63
64 DTRACE_SMB_2(op__Write__start, smb_request_t *, sr,
65 smb_rw_param_t *, param);
66
67 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
68 }
69
70 void
71 smb_post_write(smb_request_t *sr)
72 {
73 DTRACE_SMB_2(op__Write__done, smb_request_t *, sr,
74 smb_rw_param_t *, sr->arg.rw);
75
76 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
77 }
78
79 smb_sdrc_t
80 smb_com_write(smb_request_t *sr)
81 {
82 smb_rw_param_t *param = sr->arg.rw;
83 int rc;
84
85 smbsr_lookup_file(sr);
86 if (sr->fid_ofile == NULL) {
87 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
88 return (SDRC_ERROR);
89 }
90
91 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
92
93 if (param->rw_count == 0) {
94 rc = smb_write_truncate(sr, param);
134 smb_rw_param_t *param;
135 uint32_t off;
136 uint16_t count;
137 int rc;
138
139 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
140 sr->arg.rw = param;
141 param->rw_magic = SMB_RW_MAGIC;
142
143 if (sr->smb_wct == 12) {
144 rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid,
145 &count, &off, ¶m->rw_last_write);
146 } else {
147 rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid,
148 &count, &off, ¶m->rw_last_write);
149 }
150
151 param->rw_count = (uint32_t)count;
152 param->rw_offset = (uint64_t)off;
153
154 DTRACE_SMB_2(op__WriteAndClose__start, smb_request_t *, sr,
155 smb_rw_param_t *, param);
156
157 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
158 }
159
160 void
161 smb_post_write_and_close(smb_request_t *sr)
162 {
163 DTRACE_SMB_2(op__WriteAndClose__done, smb_request_t *, sr,
164 smb_rw_param_t *, sr->arg.rw);
165
166 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
167 }
168
169 smb_sdrc_t
170 smb_com_write_and_close(smb_request_t *sr)
171 {
172 smb_rw_param_t *param = sr->arg.rw;
173 uint16_t count;
174 int rc = 0;
175
176 smbsr_lookup_file(sr);
177 if (sr->fid_ofile == NULL) {
178 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
179 return (SDRC_ERROR);
180 }
181
182 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
183
184 if (param->rw_count == 0) {
232 * server encountered a resource issue.
233 */
234 smb_sdrc_t
235 smb_pre_write_and_unlock(smb_request_t *sr)
236 {
237 smb_rw_param_t *param;
238 uint32_t off;
239 uint16_t count;
240 uint16_t remcnt;
241 int rc;
242
243 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
244 sr->arg.rw = param;
245 param->rw_magic = SMB_RW_MAGIC;
246
247 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt);
248
249 param->rw_count = (uint32_t)count;
250 param->rw_offset = (uint64_t)off;
251
252 DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr,
253 smb_rw_param_t *, param);
254
255 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
256 }
257
258 void
259 smb_post_write_and_unlock(smb_request_t *sr)
260 {
261 DTRACE_SMB_2(op__WriteAndUnlock__done, smb_request_t *, sr,
262 smb_rw_param_t *, sr->arg.rw);
263
264 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
265 }
266
267 smb_sdrc_t
268 smb_com_write_and_unlock(smb_request_t *sr)
269 {
270 smb_rw_param_t *param = sr->arg.rw;
271 uint32_t status;
272 int rc = 0;
273
274 if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
275 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
276 return (SDRC_ERROR);
277 }
278
279 smbsr_lookup_file(sr);
280 if (sr->fid_ofile == NULL) {
281 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
282 return (SDRC_ERROR);
283 }
284
285 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
286
287 if (param->rw_count == 0) {
288 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0);
289 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
290 }
291
292
293 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb);
294
295 if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) {
296 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
297 ERRDOS, ERROR_INVALID_PARAMETER);
298 return (SDRC_ERROR);
299 }
300
301 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
302
303 if ((rc = smb_common_write(sr, param)) != 0) {
304 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
305 smbsr_errno(sr, rc);
306 return (SDRC_ERROR);
307 }
308
309 status = smb_unlock_range(sr, sr->fid_ofile->f_node, param->rw_offset,
310 (uint64_t)param->rw_count);
311 if (status != NT_STATUS_SUCCESS) {
312 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
313 ERRDOS, ERROR_NOT_LOCKED);
314 return (SDRC_ERROR);
315 }
316
317 rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
318 (uint16_t)param->rw_count, 0);
319 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
320 }
321
322 /*
323 * Write bytes to a file (SMB Core). This request was extended in
324 * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
325 * 14, instead of 12, and including additional offset information.
326 *
327 * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE
328 * to truncate a file. A zero length merely transfers zero bytes.
329 *
330 * If bit 0 of WriteMode is set, Fid must refer to a disk file and
331 * the data must be on stable storage before responding.
332 *
333 * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5:
334 * If CAP_LARGE_WRITEX is set, the byte count may be larger than the
335 * negotiated buffer size and the server is expected to write the
336 * number of bytes specified.
337 */
338 smb_sdrc_t
339 smb_pre_write_andx(smb_request_t *sr)
340 {
341 smb_rw_param_t *param;
342 uint32_t off_low;
365
366 if (param->rw_dsoff >= 59)
367 param->rw_dsoff -= 59;
368 param->rw_offset = (uint64_t)off_low;
369 /* off_high not present */
370 } else {
371 rc = -1;
372 }
373
374 param->rw_count = (uint32_t)datalen_low;
375
376 /*
377 * Work-around a Win7 bug, where it fails to set the
378 * CAP_LARGE_WRITEX flag during session setup. Assume
379 * a large write if the data remaining is >= 64k.
380 */
381 if ((sr->session->capabilities & CAP_LARGE_WRITEX) != 0 ||
382 (sr->smb_data.max_bytes > (sr->smb_data.chain_offset + 0xFFFF)))
383 param->rw_count |= ((uint32_t)datalen_high << 16);
384
385 DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr,
386 smb_rw_param_t *, param);
387
388 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
389 }
390
391 void
392 smb_post_write_andx(smb_request_t *sr)
393 {
394 DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr,
395 smb_rw_param_t *, sr->arg.rw);
396
397 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
398 }
399
400 smb_sdrc_t
401 smb_com_write_andx(smb_request_t *sr)
402 {
403 smb_rw_param_t *param = sr->arg.rw;
404 uint16_t count_high;
405 uint16_t count_low;
406 int rc;
407
408 ASSERT(param);
409 ASSERT(param->rw_magic == SMB_RW_MAGIC);
410
411 smbsr_lookup_file(sr);
412 if (sr->fid_ofile == NULL) {
413 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
414 return (SDRC_ERROR);
415 }
468 switch (sr->tid_tree->t_res_type & STYPE_MASK) {
469 case STYPE_DISKTREE:
470 case STYPE_PRINTQ:
471 node = ofile->f_node;
472
473 if (!smb_node_is_dir(node)) {
474 rc = smb_lock_range_access(sr, node, param->rw_offset,
475 param->rw_count, B_TRUE);
476 if (rc != NT_STATUS_SUCCESS) {
477 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
478 ERRDOS, ERROR_LOCK_VIOLATION);
479 return (EACCES);
480 }
481 }
482
483 if (SMB_WRMODE_IS_STABLE(param->rw_mode) ||
484 (node->flags & NODE_FLAGS_WRITE_THROUGH)) {
485 stability = FSYNC;
486 }
487
488 rc = smb_fsop_write(sr, sr->user_cr, node,
489 ¶m->rw_vdb.vdb_uio, &lcount, stability);
490
491 if (rc)
492 return (rc);
493
494 /*
495 * Used to have code here to set mtime.
496 * We have just done a write, so we know
497 * the file system will update mtime.
498 * No need to do it again here.
499 *
500 * However, keep track of the fact that
501 * we have written data via this handle.
502 */
503 ofile->f_written = B_TRUE;
504
505 if (!smb_node_is_dir(node))
506 smb_oplock_break_levelII(node);
507
508 param->rw_count = lcount;
509 break;
510
511 case STYPE_IPC:
512 param->rw_count = param->rw_vdb.vdb_uio.uio_resid;
513
514 if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.vdb_uio)) != 0)
515 param->rw_count = 0;
516 break;
517
518 default:
519 rc = EACCES;
520 break;
521 }
522
523 if (rc != 0)
524 return (rc);
525
526 mutex_enter(&ofile->f_mutex);
|
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 #include <sys/sdt.h>
28 #include <smbsrv/smb_kproto.h>
29 #include <smbsrv/smb_fsops.h>
30 #include <smbsrv/netbios.h>
31
32
33 static int smb_write_truncate(smb_request_t *, smb_rw_param_t *);
34
35
36 /*
37 * Write count bytes at the specified offset in a file. The offset is
38 * limited to 32-bits. If the count is zero, the file is truncated to
39 * the length specified by the offset.
40 *
41 * The response count indicates the actual number of bytes written, which
42 * will equal the requested count on success. If request and response
43 * counts differ but there is no error, the client will assume that the
44 * server encountered a resource issue.
45 */
46 smb_sdrc_t
47 smb_pre_write(smb_request_t *sr)
48 {
49 smb_rw_param_t *param;
50 uint32_t off;
51 uint16_t count;
52 int rc;
53
54 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
55 sr->arg.rw = param;
56 param->rw_magic = SMB_RW_MAGIC;
57
58 rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off);
59
60 param->rw_count = (uint32_t)count;
61 param->rw_offset = (uint64_t)off;
62 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
63
64 DTRACE_SMB_START(op__Write, smb_request_t *, sr); /* arg.rw */
65
66 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
67 }
68
69 void
70 smb_post_write(smb_request_t *sr)
71 {
72 DTRACE_SMB_DONE(op__Write, smb_request_t *, sr); /* arg.rw */
73
74 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
75 }
76
77 smb_sdrc_t
78 smb_com_write(smb_request_t *sr)
79 {
80 smb_rw_param_t *param = sr->arg.rw;
81 int rc;
82
83 smbsr_lookup_file(sr);
84 if (sr->fid_ofile == NULL) {
85 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
86 return (SDRC_ERROR);
87 }
88
89 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
90
91 if (param->rw_count == 0) {
92 rc = smb_write_truncate(sr, param);
132 smb_rw_param_t *param;
133 uint32_t off;
134 uint16_t count;
135 int rc;
136
137 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
138 sr->arg.rw = param;
139 param->rw_magic = SMB_RW_MAGIC;
140
141 if (sr->smb_wct == 12) {
142 rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid,
143 &count, &off, ¶m->rw_last_write);
144 } else {
145 rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid,
146 &count, &off, ¶m->rw_last_write);
147 }
148
149 param->rw_count = (uint32_t)count;
150 param->rw_offset = (uint64_t)off;
151
152 DTRACE_SMB_START(op__WriteAndClose, smb_request_t *, sr); /* arg.rw */
153
154 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
155 }
156
157 void
158 smb_post_write_and_close(smb_request_t *sr)
159 {
160 DTRACE_SMB_DONE(op__WriteAndClose, smb_request_t *, sr); /* arg.rw */
161
162 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
163 }
164
165 smb_sdrc_t
166 smb_com_write_and_close(smb_request_t *sr)
167 {
168 smb_rw_param_t *param = sr->arg.rw;
169 uint16_t count;
170 int rc = 0;
171
172 smbsr_lookup_file(sr);
173 if (sr->fid_ofile == NULL) {
174 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
175 return (SDRC_ERROR);
176 }
177
178 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
179
180 if (param->rw_count == 0) {
228 * server encountered a resource issue.
229 */
230 smb_sdrc_t
231 smb_pre_write_and_unlock(smb_request_t *sr)
232 {
233 smb_rw_param_t *param;
234 uint32_t off;
235 uint16_t count;
236 uint16_t remcnt;
237 int rc;
238
239 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
240 sr->arg.rw = param;
241 param->rw_magic = SMB_RW_MAGIC;
242
243 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt);
244
245 param->rw_count = (uint32_t)count;
246 param->rw_offset = (uint64_t)off;
247
248 DTRACE_SMB_START(op__WriteAndUnlock, smb_request_t *, sr); /* arg.rw */
249
250 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
251 }
252
253 void
254 smb_post_write_and_unlock(smb_request_t *sr)
255 {
256 DTRACE_SMB_DONE(op__WriteAndUnlock, smb_request_t *, sr); /* arg.rw */
257
258 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
259 }
260
261 smb_sdrc_t
262 smb_com_write_and_unlock(smb_request_t *sr)
263 {
264 smb_rw_param_t *param = sr->arg.rw;
265 uint32_t lk_pid;
266 uint32_t status;
267 int rc = 0;
268
269 if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
270 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
271 return (SDRC_ERROR);
272 }
273
274 smbsr_lookup_file(sr);
275 if (sr->fid_ofile == NULL) {
276 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
277 return (SDRC_ERROR);
278 }
279
280 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
281
282 if (param->rw_count == 0) {
283 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0);
284 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
285 }
286
287
288 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb);
289
290 if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) {
291 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
292 ERRDOS, ERROR_INVALID_PARAMETER);
293 return (SDRC_ERROR);
294 }
295
296 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
297
298 if ((rc = smb_common_write(sr, param)) != 0) {
299 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
300 smbsr_errno(sr, rc);
301 return (SDRC_ERROR);
302 }
303
304
305 /* Note: SMB1 locking uses 16-bit PIDs. */
306 lk_pid = sr->smb_pid & 0xFFFF;
307
308 status = smb_unlock_range(sr, param->rw_offset,
309 (uint64_t)param->rw_count, lk_pid);
310 if (status != NT_STATUS_SUCCESS) {
311 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
312 ERRDOS, ERROR_NOT_LOCKED);
313 return (SDRC_ERROR);
314 }
315
316 rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
317 (uint16_t)param->rw_count, 0);
318 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
319 }
320
321 /*
322 * The SMB_COM_WRITE_RAW protocol was a negotiated option introduced in
323 * SMB Core Plus to maximize performance when writing a large block
324 * of data to a server. It's obsolete and no longer supported.
325 *
326 * We keep a handler for it so the dtrace provider can see if
327 * the client tried to use this command.
328 */
329 smb_sdrc_t
330 smb_pre_write_raw(smb_request_t *sr)
331 {
332 DTRACE_SMB_START(op__WriteRaw, smb_request_t *, sr);
333 return (SDRC_SUCCESS);
334 }
335
336 void
337 smb_post_write_raw(smb_request_t *sr)
338 {
339 DTRACE_SMB_DONE(op__WriteRaw, smb_request_t *, sr);
340 }
341
342 smb_sdrc_t
343 smb_com_write_raw(struct smb_request *sr)
344 {
345 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, ERRDOS,
346 ERROR_NOT_SUPPORTED);
347 return (SDRC_ERROR);
348 }
349
350 /*
351 * Write bytes to a file (SMB Core). This request was extended in
352 * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
353 * 14, instead of 12, and including additional offset information.
354 *
355 * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE
356 * to truncate a file. A zero length merely transfers zero bytes.
357 *
358 * If bit 0 of WriteMode is set, Fid must refer to a disk file and
359 * the data must be on stable storage before responding.
360 *
361 * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5:
362 * If CAP_LARGE_WRITEX is set, the byte count may be larger than the
363 * negotiated buffer size and the server is expected to write the
364 * number of bytes specified.
365 */
366 smb_sdrc_t
367 smb_pre_write_andx(smb_request_t *sr)
368 {
369 smb_rw_param_t *param;
370 uint32_t off_low;
393
394 if (param->rw_dsoff >= 59)
395 param->rw_dsoff -= 59;
396 param->rw_offset = (uint64_t)off_low;
397 /* off_high not present */
398 } else {
399 rc = -1;
400 }
401
402 param->rw_count = (uint32_t)datalen_low;
403
404 /*
405 * Work-around a Win7 bug, where it fails to set the
406 * CAP_LARGE_WRITEX flag during session setup. Assume
407 * a large write if the data remaining is >= 64k.
408 */
409 if ((sr->session->capabilities & CAP_LARGE_WRITEX) != 0 ||
410 (sr->smb_data.max_bytes > (sr->smb_data.chain_offset + 0xFFFF)))
411 param->rw_count |= ((uint32_t)datalen_high << 16);
412
413 DTRACE_SMB_START(op__WriteX, smb_request_t *, sr); /* arg.rw */
414
415 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
416 }
417
418 void
419 smb_post_write_andx(smb_request_t *sr)
420 {
421 DTRACE_SMB_DONE(op__WriteX, smb_request_t *, sr); /* arg.rw */
422
423 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
424 }
425
426 smb_sdrc_t
427 smb_com_write_andx(smb_request_t *sr)
428 {
429 smb_rw_param_t *param = sr->arg.rw;
430 uint16_t count_high;
431 uint16_t count_low;
432 int rc;
433
434 ASSERT(param);
435 ASSERT(param->rw_magic == SMB_RW_MAGIC);
436
437 smbsr_lookup_file(sr);
438 if (sr->fid_ofile == NULL) {
439 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
440 return (SDRC_ERROR);
441 }
494 switch (sr->tid_tree->t_res_type & STYPE_MASK) {
495 case STYPE_DISKTREE:
496 case STYPE_PRINTQ:
497 node = ofile->f_node;
498
499 if (!smb_node_is_dir(node)) {
500 rc = smb_lock_range_access(sr, node, param->rw_offset,
501 param->rw_count, B_TRUE);
502 if (rc != NT_STATUS_SUCCESS) {
503 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
504 ERRDOS, ERROR_LOCK_VIOLATION);
505 return (EACCES);
506 }
507 }
508
509 if (SMB_WRMODE_IS_STABLE(param->rw_mode) ||
510 (node->flags & NODE_FLAGS_WRITE_THROUGH)) {
511 stability = FSYNC;
512 }
513
514 rc = smb_fsop_write(sr, sr->user_cr, node, ofile,
515 ¶m->rw_vdb.vdb_uio, &lcount, stability);
516
517 if (rc)
518 return (rc);
519
520 /*
521 * Used to have code here to set mtime.
522 * We have just done a write, so we know
523 * the file system will update mtime.
524 * No need to do it again here.
525 *
526 * However, keep track of the fact that
527 * we have written data via this handle.
528 */
529 ofile->f_written = B_TRUE;
530
531 /* This revokes read cache delegations. */
532 (void) smb_oplock_break_WRITE(node, ofile);
533
534 param->rw_count = lcount;
535 break;
536
537 case STYPE_IPC:
538 param->rw_count = param->rw_vdb.vdb_uio.uio_resid;
539
540 if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.vdb_uio)) != 0)
541 param->rw_count = 0;
542 break;
543
544 default:
545 rc = EACCES;
546 break;
547 }
548
549 if (rc != 0)
550 return (rc);
551
552 mutex_enter(&ofile->f_mutex);
|