Print this page
Build provider 3rd arg from smb_request_t
hacking...
NEX-1643 dtrace provider for smbsrv
Also illumos 1841:
DTrace smb provider was mis-implemented, doesn't exist.
Add back handlers for read/write raw, so that
legacy dtrace consumers can find the probes.
Kill extra arg in smb_negotiate
Fix missing "done" probe with smb_notify
Add example consumer: smb-trace.d
fix soi_pid
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb_write.c
+++ new/usr/src/uts/common/fs/smbsrv/smb_write.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
25 25 */
26 26
27 27 #include <sys/sdt.h>
28 28 #include <smbsrv/smb_kproto.h>
29 29 #include <smbsrv/smb_fsops.h>
30 30 #include <smbsrv/netbios.h>
31 31
32 32
33 33 static int smb_write_truncate(smb_request_t *, smb_rw_param_t *);
34 34
35 35
36 36 /*
37 37 * Write count bytes at the specified offset in a file. The offset is
38 38 * limited to 32-bits. If the count is zero, the file is truncated to
39 39 * the length specified by the offset.
40 40 *
41 41 * The response count indicates the actual number of bytes written, which
42 42 * will equal the requested count on success. If request and response
43 43 * counts differ but there is no error, the client will assume that the
44 44 * server encountered a resource issue.
45 45 */
46 46 smb_sdrc_t
47 47 smb_pre_write(smb_request_t *sr)
48 48 {
49 49 smb_rw_param_t *param;
50 50 uint32_t off;
51 51 uint16_t count;
52 52 int rc;
53 53
↓ open down ↓ |
53 lines elided |
↑ open up ↑ |
54 54 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
55 55 sr->arg.rw = param;
56 56 param->rw_magic = SMB_RW_MAGIC;
57 57
58 58 rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off);
59 59
60 60 param->rw_count = (uint32_t)count;
61 61 param->rw_offset = (uint64_t)off;
62 62 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
63 63
64 - DTRACE_SMB_2(op__Write__start, smb_request_t *, sr,
65 - smb_rw_param_t *, param);
64 + DTRACE_SMB_1(op__Write__start, smb_request_t *, sr); /* arg.rw */
66 65
67 66 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
68 67 }
69 68
70 69 void
71 70 smb_post_write(smb_request_t *sr)
72 71 {
73 - DTRACE_SMB_2(op__Write__done, smb_request_t *, sr,
74 - smb_rw_param_t *, sr->arg.rw);
72 + DTRACE_SMB_1(op__Write__done, smb_request_t *, sr); /* arg.rw */
75 73
76 74 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
77 75 }
78 76
79 77 smb_sdrc_t
80 78 smb_com_write(smb_request_t *sr)
81 79 {
82 80 smb_rw_param_t *param = sr->arg.rw;
83 81 int rc;
84 82
85 83 smbsr_lookup_file(sr);
86 84 if (sr->fid_ofile == NULL) {
87 85 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
88 86 return (SDRC_ERROR);
89 87 }
90 88
91 89 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
92 90
93 91 if (param->rw_count == 0) {
94 92 rc = smb_write_truncate(sr, param);
95 93 } else {
96 94 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb);
97 95
98 96 if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
99 97 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
100 98 ERRDOS, ERROR_INVALID_PARAMETER);
101 99 return (SDRC_ERROR);
102 100 }
103 101
104 102 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
105 103
106 104 rc = smb_common_write(sr, param);
107 105 }
108 106
109 107 if (rc != 0) {
110 108 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
111 109 smbsr_errno(sr, rc);
112 110 return (SDRC_ERROR);
113 111 }
114 112
115 113 rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
116 114 (uint16_t)param->rw_count, 0);
117 115 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
118 116 }
119 117
120 118 /*
121 119 * Write count bytes to a file and then close the file. This function
122 120 * can only be used to write to 32-bit offsets and the client must set
123 121 * WordCount (6 or 12) correctly in order to locate the data to be
124 122 * written. If an error occurs on the write, the file should still be
125 123 * closed. If Count is 0, the file is truncated (or extended) to offset.
126 124 *
127 125 * If the last_write time is non-zero, last_write should be used to set
128 126 * the mtime. Otherwise the file system stamps the mtime. Failure to
129 127 * set mtime should not result in an error response.
130 128 */
131 129 smb_sdrc_t
132 130 smb_pre_write_and_close(smb_request_t *sr)
133 131 {
134 132 smb_rw_param_t *param;
135 133 uint32_t off;
136 134 uint16_t count;
137 135 int rc;
138 136
139 137 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
140 138 sr->arg.rw = param;
141 139 param->rw_magic = SMB_RW_MAGIC;
142 140
143 141 if (sr->smb_wct == 12) {
↓ open down ↓ |
59 lines elided |
↑ open up ↑ |
144 142 rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid,
145 143 &count, &off, ¶m->rw_last_write);
146 144 } else {
147 145 rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid,
148 146 &count, &off, ¶m->rw_last_write);
149 147 }
150 148
151 149 param->rw_count = (uint32_t)count;
152 150 param->rw_offset = (uint64_t)off;
153 151
154 - DTRACE_SMB_2(op__WriteAndClose__start, smb_request_t *, sr,
155 - smb_rw_param_t *, param);
152 + DTRACE_SMB_1(op__WriteAndClose__start, smb_request_t *, sr); /* arg.rw */
156 153
157 154 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
158 155 }
159 156
160 157 void
161 158 smb_post_write_and_close(smb_request_t *sr)
162 159 {
163 - DTRACE_SMB_2(op__WriteAndClose__done, smb_request_t *, sr,
164 - smb_rw_param_t *, sr->arg.rw);
160 + DTRACE_SMB_1(op__WriteAndClose__done, smb_request_t *, sr); /* arg.rw */
165 161
166 162 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
167 163 }
168 164
169 165 smb_sdrc_t
170 166 smb_com_write_and_close(smb_request_t *sr)
171 167 {
172 168 smb_rw_param_t *param = sr->arg.rw;
173 169 uint16_t count;
174 170 int rc = 0;
175 171
176 172 smbsr_lookup_file(sr);
177 173 if (sr->fid_ofile == NULL) {
178 174 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
179 175 return (SDRC_ERROR);
180 176 }
181 177
182 178 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
183 179
184 180 if (param->rw_count == 0) {
185 181 rc = smb_write_truncate(sr, param);
186 182 } else {
187 183 /*
188 184 * There may be a bug here: should this be "3.#B"?
189 185 */
190 186 rc = smbsr_decode_data(sr, ".#B", param->rw_count,
191 187 ¶m->rw_vdb);
192 188
193 189 if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
194 190 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
195 191 ERRDOS, ERROR_INVALID_PARAMETER);
196 192 return (SDRC_ERROR);
197 193 }
198 194
199 195 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
200 196
201 197 rc = smb_common_write(sr, param);
202 198 }
203 199
204 200 if (rc != 0) {
205 201 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
206 202 smbsr_errno(sr, rc);
207 203 return (SDRC_ERROR);
208 204 }
209 205
210 206 smb_ofile_close(sr->fid_ofile, param->rw_last_write);
211 207
212 208 count = (uint16_t)param->rw_count;
213 209 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, count, 0);
214 210 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
215 211 }
216 212
217 213 /*
218 214 * Write count bytes to a file at the specified offset and then unlock
219 215 * them. Write behind is safe because the client should have the range
220 216 * locked and this request is allowed to extend the file - note that
221 217 * offset is limited to 32-bits.
222 218 *
223 219 * Spec advice: it is an error for count to be zero. For compatibility,
224 220 * we take no action and return success.
225 221 *
226 222 * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk
227 223 * files. Reject any attempt to use it on other shares.
228 224 *
229 225 * The response count indicates the actual number of bytes written, which
230 226 * will equal the requested count on success. If request and response
231 227 * counts differ but there is no error, the client will assume that the
232 228 * server encountered a resource issue.
233 229 */
234 230 smb_sdrc_t
235 231 smb_pre_write_and_unlock(smb_request_t *sr)
236 232 {
237 233 smb_rw_param_t *param;
238 234 uint32_t off;
239 235 uint16_t count;
240 236 uint16_t remcnt;
241 237 int rc;
↓ open down ↓ |
67 lines elided |
↑ open up ↑ |
242 238
243 239 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
244 240 sr->arg.rw = param;
245 241 param->rw_magic = SMB_RW_MAGIC;
246 242
247 243 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt);
248 244
249 245 param->rw_count = (uint32_t)count;
250 246 param->rw_offset = (uint64_t)off;
251 247
252 - DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr,
253 - smb_rw_param_t *, param);
248 + DTRACE_SMB_1(op__WriteAndUnlock__start, smb_request_t *, sr); /* arg.rw */
254 249
255 250 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
256 251 }
257 252
258 253 void
259 254 smb_post_write_and_unlock(smb_request_t *sr)
260 255 {
261 - DTRACE_SMB_2(op__WriteAndUnlock__done, smb_request_t *, sr,
262 - smb_rw_param_t *, sr->arg.rw);
256 + DTRACE_SMB_1(op__WriteAndUnlock__done, smb_request_t *, sr); /* arg.rw */
263 257
264 258 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
265 259 }
266 260
267 261 smb_sdrc_t
268 262 smb_com_write_and_unlock(smb_request_t *sr)
269 263 {
270 264 smb_rw_param_t *param = sr->arg.rw;
271 265 uint32_t lk_pid;
272 266 uint32_t status;
273 267 int rc = 0;
274 268
275 269 if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
276 270 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
277 271 return (SDRC_ERROR);
278 272 }
279 273
280 274 smbsr_lookup_file(sr);
281 275 if (sr->fid_ofile == NULL) {
282 276 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
283 277 return (SDRC_ERROR);
284 278 }
285 279
286 280 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
287 281
288 282 if (param->rw_count == 0) {
289 283 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0);
290 284 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
291 285 }
292 286
293 287
294 288 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb);
295 289
296 290 if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) {
297 291 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
298 292 ERRDOS, ERROR_INVALID_PARAMETER);
299 293 return (SDRC_ERROR);
300 294 }
301 295
302 296 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
303 297
304 298 if ((rc = smb_common_write(sr, param)) != 0) {
305 299 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
306 300 smbsr_errno(sr, rc);
307 301 return (SDRC_ERROR);
308 302 }
309 303
310 304
311 305 /* Note: SMB1 locking uses 16-bit PIDs. */
312 306 lk_pid = sr->smb_pid & 0xFFFF;
313 307
314 308 status = smb_unlock_range(sr, param->rw_offset,
315 309 (uint64_t)param->rw_count, lk_pid);
316 310 if (status != NT_STATUS_SUCCESS) {
317 311 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
↓ open down ↓ |
45 lines elided |
↑ open up ↑ |
318 312 ERRDOS, ERROR_NOT_LOCKED);
319 313 return (SDRC_ERROR);
320 314 }
321 315
322 316 rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
323 317 (uint16_t)param->rw_count, 0);
324 318 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
325 319 }
326 320
327 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 + smb_rw_param_t *param;
333 + uint32_t off_low;
334 + uint32_t timeout;
335 + uint32_t off_high;
336 + uint16_t datalen;
337 + uint16_t total;
338 + int rc;
339 +
340 + param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
341 + sr->arg.rw = param;
342 +
343 + if (sr->smb_wct == 12) {
344 + rc = smbsr_decode_vwv(sr, "ww2.llw4.ww", &sr->smb_fid, &total,
345 + &off_low, &timeout, ¶m->rw_mode, &datalen,
346 + ¶m->rw_dsoff);
347 +
348 + param->rw_offset = (uint64_t)off_low;
349 + } else {
350 + rc = smbsr_decode_vwv(sr, "ww2.llw4.wwl", &sr->smb_fid, &total,
351 + &off_low, &timeout, ¶m->rw_mode, &datalen,
352 + ¶m->rw_dsoff, &off_high);
353 +
354 + param->rw_offset = ((uint64_t)off_high << 32) | off_low;
355 + }
356 +
357 + param->rw_count = (uint32_t)datalen;
358 + param->rw_total = (uint32_t)total;
359 +
360 + DTRACE_SMB_1(op__WriteRaw__start, smb_request_t *, sr); /* arg.rw */
361 +
362 + return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
363 +}
364 +
365 +void
366 +smb_post_write_raw(smb_request_t *sr)
367 +{
368 + DTRACE_SMB_1(op__WriteRaw__done, smb_request_t *, sr); /* arg.rw */
369 +
370 + kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
371 +}
372 +
373 +smb_sdrc_t
374 +smb_com_write_raw(struct smb_request *sr)
375 +{
376 + smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, ERRDOS,
377 + ERROR_NOT_SUPPORTED);
378 + return (SDRC_ERROR);
379 +}
380 +
381 +/*
328 382 * Write bytes to a file (SMB Core). This request was extended in
329 383 * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
330 384 * 14, instead of 12, and including additional offset information.
331 385 *
332 386 * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE
333 387 * to truncate a file. A zero length merely transfers zero bytes.
334 388 *
335 389 * If bit 0 of WriteMode is set, Fid must refer to a disk file and
336 390 * the data must be on stable storage before responding.
337 391 *
338 392 * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5:
339 393 * If CAP_LARGE_WRITEX is set, the byte count may be larger than the
340 394 * negotiated buffer size and the server is expected to write the
341 395 * number of bytes specified.
342 396 */
343 397 smb_sdrc_t
344 398 smb_pre_write_andx(smb_request_t *sr)
345 399 {
346 400 smb_rw_param_t *param;
347 401 uint32_t off_low;
348 402 uint32_t off_high;
349 403 uint16_t datalen_low;
350 404 uint16_t datalen_high;
351 405 uint16_t remcnt;
352 406 int rc;
353 407
354 408 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
355 409 sr->arg.rw = param;
356 410 param->rw_magic = SMB_RW_MAGIC;
357 411
358 412 if (sr->smb_wct == 14) {
359 413 rc = smbsr_decode_vwv(sr, "4.wl4.wwwwwl", &sr->smb_fid,
360 414 &off_low, ¶m->rw_mode, &remcnt, &datalen_high,
361 415 &datalen_low, ¶m->rw_dsoff, &off_high);
362 416
363 417 if (param->rw_dsoff >= 63)
364 418 param->rw_dsoff -= 63;
365 419 param->rw_offset = ((uint64_t)off_high << 32) | off_low;
366 420 } else if (sr->smb_wct == 12) {
367 421 rc = smbsr_decode_vwv(sr, "4.wl4.wwwww", &sr->smb_fid,
368 422 &off_low, ¶m->rw_mode, &remcnt, &datalen_high,
369 423 &datalen_low, ¶m->rw_dsoff);
370 424
371 425 if (param->rw_dsoff >= 59)
372 426 param->rw_dsoff -= 59;
373 427 param->rw_offset = (uint64_t)off_low;
374 428 /* off_high not present */
375 429 } else {
376 430 rc = -1;
377 431 }
378 432
379 433 param->rw_count = (uint32_t)datalen_low;
↓ open down ↓ |
42 lines elided |
↑ open up ↑ |
380 434
381 435 /*
382 436 * Work-around a Win7 bug, where it fails to set the
383 437 * CAP_LARGE_WRITEX flag during session setup. Assume
384 438 * a large write if the data remaining is >= 64k.
385 439 */
386 440 if ((sr->session->capabilities & CAP_LARGE_WRITEX) != 0 ||
387 441 (sr->smb_data.max_bytes > (sr->smb_data.chain_offset + 0xFFFF)))
388 442 param->rw_count |= ((uint32_t)datalen_high << 16);
389 443
390 - DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr,
391 - smb_rw_param_t *, param);
444 + DTRACE_SMB_1(op__WriteX__start, smb_request_t *, sr); /* arg.rw */
392 445
393 446 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
394 447 }
395 448
396 449 void
397 450 smb_post_write_andx(smb_request_t *sr)
398 451 {
399 - DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr,
400 - smb_rw_param_t *, sr->arg.rw);
452 + DTRACE_SMB_1(op__WriteX__done, smb_request_t *, sr); /* arg.rw */
401 453
402 454 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
403 455 }
404 456
405 457 smb_sdrc_t
406 458 smb_com_write_andx(smb_request_t *sr)
407 459 {
408 460 smb_rw_param_t *param = sr->arg.rw;
409 461 uint16_t count_high;
410 462 uint16_t count_low;
411 463 int rc;
412 464
413 465 ASSERT(param);
414 466 ASSERT(param->rw_magic == SMB_RW_MAGIC);
415 467
416 468 smbsr_lookup_file(sr);
417 469 if (sr->fid_ofile == NULL) {
418 470 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
419 471 return (SDRC_ERROR);
420 472 }
421 473
422 474 sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
423 475
424 476 if (SMB_WRMODE_IS_STABLE(param->rw_mode) &&
425 477 STYPE_ISIPC(sr->tid_tree->t_res_type)) {
426 478 smbsr_error(sr, 0, ERRSRV, ERRaccess);
427 479 return (SDRC_ERROR);
428 480 }
429 481
430 482 rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count,
431 483 ¶m->rw_vdb);
432 484
433 485 if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
434 486 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
435 487 ERRDOS, ERROR_INVALID_PARAMETER);
436 488 return (SDRC_ERROR);
437 489 }
438 490
439 491 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
440 492
441 493 if (param->rw_count != 0) {
442 494 if ((rc = smb_common_write(sr, param)) != 0) {
443 495 if (sr->smb_error.status !=
444 496 NT_STATUS_FILE_LOCK_CONFLICT)
445 497 smbsr_errno(sr, rc);
446 498 return (SDRC_ERROR);
447 499 }
448 500 }
449 501
450 502 count_low = param->rw_count & 0xFFFF;
451 503 count_high = (param->rw_count >> 16) & 0xFF;
452 504
453 505 rc = smbsr_encode_result(sr, 6, 0, "bb1.wwwwww",
454 506 6, sr->andx_com, 15, count_low, 0, count_high, 0, 0);
455 507
456 508 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
457 509 }
458 510
459 511 /*
460 512 * Common function for writing files or IPC/MSRPC named pipes.
461 513 *
462 514 * Returns errno values.
463 515 */
464 516 int
465 517 smb_common_write(smb_request_t *sr, smb_rw_param_t *param)
466 518 {
467 519 smb_ofile_t *ofile = sr->fid_ofile;
468 520 smb_node_t *node;
469 521 int stability = 0;
470 522 uint32_t lcount;
471 523 int rc = 0;
472 524
473 525 switch (sr->tid_tree->t_res_type & STYPE_MASK) {
474 526 case STYPE_DISKTREE:
475 527 case STYPE_PRINTQ:
476 528 node = ofile->f_node;
477 529
478 530 if (!smb_node_is_dir(node)) {
479 531 rc = smb_lock_range_access(sr, node, param->rw_offset,
480 532 param->rw_count, B_TRUE);
481 533 if (rc != NT_STATUS_SUCCESS) {
482 534 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
483 535 ERRDOS, ERROR_LOCK_VIOLATION);
484 536 return (EACCES);
485 537 }
486 538 }
487 539
488 540 if (SMB_WRMODE_IS_STABLE(param->rw_mode) ||
489 541 (node->flags & NODE_FLAGS_WRITE_THROUGH)) {
490 542 stability = FSYNC;
491 543 }
492 544
493 545 rc = smb_fsop_write(sr, sr->user_cr, node, ofile,
494 546 ¶m->rw_vdb.vdb_uio, &lcount, stability);
495 547
496 548 if (rc)
497 549 return (rc);
498 550
499 551 /*
500 552 * Used to have code here to set mtime.
501 553 * We have just done a write, so we know
502 554 * the file system will update mtime.
503 555 * No need to do it again here.
504 556 *
505 557 * However, keep track of the fact that
506 558 * we have written data via this handle.
507 559 */
508 560 ofile->f_written = B_TRUE;
509 561
510 562 if (!smb_node_is_dir(node))
511 563 smb_oplock_break_levelII(node);
512 564
513 565 param->rw_count = lcount;
514 566 break;
515 567
516 568 case STYPE_IPC:
517 569 param->rw_count = param->rw_vdb.vdb_uio.uio_resid;
518 570
519 571 if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.vdb_uio)) != 0)
520 572 param->rw_count = 0;
521 573 break;
522 574
523 575 default:
524 576 rc = EACCES;
525 577 break;
526 578 }
527 579
528 580 if (rc != 0)
529 581 return (rc);
530 582
531 583 mutex_enter(&ofile->f_mutex);
532 584 ofile->f_seek_pos = param->rw_offset + param->rw_count;
533 585 mutex_exit(&ofile->f_mutex);
534 586 return (rc);
535 587 }
536 588
537 589 /*
538 590 * Truncate a disk file to the specified offset.
539 591 * Typically, w_count will be zero here.
540 592 *
541 593 * Note that smb_write_andx cannot be used to reduce the file size so,
542 594 * if this is required, smb_write is called with a count of zero and
543 595 * the appropriate file length in offset. The file should be resized
544 596 * to the length specified by the offset.
545 597 *
546 598 * Returns errno values.
547 599 */
548 600 static int
549 601 smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param)
550 602 {
551 603 smb_ofile_t *ofile = sr->fid_ofile;
552 604 smb_node_t *node = ofile->f_node;
553 605 smb_attr_t attr;
554 606 uint32_t status;
555 607 int rc;
556 608
557 609 if (STYPE_ISIPC(sr->tid_tree->t_res_type))
558 610 return (0);
559 611
560 612 mutex_enter(&node->n_mutex);
561 613 if (!smb_node_is_dir(node)) {
562 614 status = smb_lock_range_access(sr, node, param->rw_offset,
563 615 param->rw_count, B_TRUE);
564 616 if (status != NT_STATUS_SUCCESS) {
565 617 mutex_exit(&node->n_mutex);
566 618 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
567 619 ERRDOS, ERROR_LOCK_VIOLATION);
568 620 return (EACCES);
569 621 }
570 622 }
571 623 mutex_exit(&node->n_mutex);
572 624
573 625 bzero(&attr, sizeof (smb_attr_t));
574 626 attr.sa_mask = SMB_AT_SIZE;
575 627 attr.sa_vattr.va_size = param->rw_offset;
576 628 rc = smb_node_setattr(sr, node, sr->user_cr, ofile, &attr);
577 629 if (rc != 0)
578 630 return (rc);
579 631
580 632 mutex_enter(&ofile->f_mutex);
581 633 ofile->f_seek_pos = param->rw_offset + param->rw_count;
582 634 mutex_exit(&ofile->f_mutex);
583 635 return (0);
584 636 }
↓ open down ↓ |
174 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX