Print this page
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-5844 want SMB2 ioctl FSCTL_SRV_COPYCHUNK
NEX-6124 smb_fsop_read/write should allow file != sr->fid_ofile
NEX-6125 smbtorture invalid response with smb2.ioctl
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-6041 Should pass the smbtorture lock tests
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-2370 unable to save/modify files (zip,notepad,excel) on CIFS share from Windows 7
NEX-2039 Codenomicon failure in smb_write
re #7815 SMB server delivers old modification time...


   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, &param->rw_last_write);
 146         } else {
 147                 rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid,
 148                     &count, &off, &param->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", &param->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                     &param->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, &param->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, &param->rw_last_write);
 144         } else {
 145                 rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid,
 146                     &count, &off, &param->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", &param->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                     &param->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, &param->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);