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...
    
      
        | 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
  
    | 
      ↓ open down ↓ | 
    13 lines elided | 
    
      ↑ open up ↑ | 
  
  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      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
       24 + * Copyright 2017 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 ↓ | 
    19 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_START(op__Write, 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_DONE(op__Write, 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_START(op__WriteAndClose, 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_DONE(op__WriteAndClose, 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_START(op__WriteAndUnlock, 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_DONE(op__WriteAndUnlock, 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;
      265 +        uint32_t lk_pid;
 271  266          uint32_t status;
 272  267          int rc = 0;
 273  268  
 274  269          if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
 275  270                  smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
 276  271                  return (SDRC_ERROR);
 277  272          }
 278  273  
 279  274          smbsr_lookup_file(sr);
 280  275          if (sr->fid_ofile == NULL) {
 281  276                  smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
 282  277                  return (SDRC_ERROR);
 283  278          }
 284  279  
 285  280          sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
 286  281  
 287  282          if (param->rw_count == 0) {
 288  283                  rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0);
 289  284                  return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 290  285          }
 291  286  
 292  287  
 293  288          rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb);
 294  289  
 295  290          if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) {
 296  291                  smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
 297  292                      ERRDOS, ERROR_INVALID_PARAMETER);
 298  293                  return (SDRC_ERROR);
  
    | 
      ↓ open down ↓ | 
    18 lines elided | 
    
      ↑ open up ↑ | 
  
 299  294          }
 300  295  
 301  296          param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
 302  297  
 303  298          if ((rc = smb_common_write(sr, param)) != 0) {
 304  299                  if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT)
 305  300                          smbsr_errno(sr, rc);
 306  301                  return (SDRC_ERROR);
 307  302          }
 308  303  
 309      -        status = smb_unlock_range(sr, sr->fid_ofile->f_node, param->rw_offset,
 310      -            (uint64_t)param->rw_count);
      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);
 311  310          if (status != NT_STATUS_SUCCESS) {
 312  311                  smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED,
 313  312                      ERRDOS, ERROR_NOT_LOCKED);
 314  313                  return (SDRC_ERROR);
 315  314          }
 316  315  
 317  316          rc = smbsr_encode_result(sr, 1, 0, "bww", 1,
 318  317              (uint16_t)param->rw_count, 0);
 319  318          return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 320  319  }
 321  320  
 322  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 +/*
 323  351   * Write bytes to a file (SMB Core).  This request was extended in
 324  352   * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
 325  353   * 14, instead of 12, and including additional offset information.
 326  354   *
 327  355   * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE
 328  356   * to truncate a file.  A zero length merely transfers zero bytes.
 329  357   *
 330  358   * If bit 0 of WriteMode is set, Fid must refer to a disk file and
 331  359   * the data must be on stable storage before responding.
 332  360   *
 333  361   * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5:
 334  362   * If CAP_LARGE_WRITEX is set, the byte count may be larger than the
 335  363   * negotiated buffer size and the server is expected to write the
 336  364   * number of bytes specified.
 337  365   */
 338  366  smb_sdrc_t
 339  367  smb_pre_write_andx(smb_request_t *sr)
 340  368  {
 341  369          smb_rw_param_t *param;
 342  370          uint32_t off_low;
 343  371          uint32_t off_high;
 344  372          uint16_t datalen_low;
 345  373          uint16_t datalen_high;
 346  374          uint16_t remcnt;
 347  375          int rc;
 348  376  
 349  377          param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
 350  378          sr->arg.rw = param;
 351  379          param->rw_magic = SMB_RW_MAGIC;
 352  380  
 353  381          if (sr->smb_wct == 14) {
 354  382                  rc = smbsr_decode_vwv(sr, "4.wl4.wwwwwl", &sr->smb_fid,
 355  383                      &off_low, ¶m->rw_mode, &remcnt, &datalen_high,
 356  384                      &datalen_low, ¶m->rw_dsoff, &off_high);
 357  385  
 358  386                  if (param->rw_dsoff >= 63)
 359  387                          param->rw_dsoff -= 63;
 360  388                  param->rw_offset = ((uint64_t)off_high << 32) | off_low;
 361  389          } else if (sr->smb_wct == 12) {
 362  390                  rc = smbsr_decode_vwv(sr, "4.wl4.wwwww", &sr->smb_fid,
 363  391                      &off_low, ¶m->rw_mode, &remcnt, &datalen_high,
 364  392                      &datalen_low, ¶m->rw_dsoff);
 365  393  
 366  394                  if (param->rw_dsoff >= 59)
 367  395                          param->rw_dsoff -= 59;
 368  396                  param->rw_offset = (uint64_t)off_low;
 369  397                  /* off_high not present */
 370  398          } else {
 371  399                  rc = -1;
 372  400          }
 373  401  
 374  402          param->rw_count = (uint32_t)datalen_low;
  
    | 
      ↓ open down ↓ | 
    42 lines elided | 
    
      ↑ open up ↑ | 
  
 375  403  
 376  404          /*
 377  405           * Work-around a Win7 bug, where it fails to set the
 378  406           * CAP_LARGE_WRITEX flag during session setup.  Assume
 379  407           * a large write if the data remaining is >= 64k.
 380  408           */
 381  409          if ((sr->session->capabilities & CAP_LARGE_WRITEX) != 0 ||
 382  410              (sr->smb_data.max_bytes > (sr->smb_data.chain_offset + 0xFFFF)))
 383  411                  param->rw_count |= ((uint32_t)datalen_high << 16);
 384  412  
 385      -        DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr,
 386      -            smb_rw_param_t *, param);
      413 +        DTRACE_SMB_START(op__WriteX, smb_request_t *, sr); /* arg.rw */
 387  414  
 388  415          return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 389  416  }
 390  417  
 391  418  void
 392  419  smb_post_write_andx(smb_request_t *sr)
 393  420  {
 394      -        DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr,
 395      -            smb_rw_param_t *, sr->arg.rw);
      421 +        DTRACE_SMB_DONE(op__WriteX, smb_request_t *, sr); /* arg.rw */
 396  422  
 397  423          kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
 398  424  }
 399  425  
 400  426  smb_sdrc_t
 401  427  smb_com_write_andx(smb_request_t *sr)
 402  428  {
 403  429          smb_rw_param_t *param = sr->arg.rw;
 404  430          uint16_t count_high;
 405  431          uint16_t count_low;
 406  432          int rc;
 407  433  
 408  434          ASSERT(param);
 409  435          ASSERT(param->rw_magic == SMB_RW_MAGIC);
 410  436  
 411  437          smbsr_lookup_file(sr);
 412  438          if (sr->fid_ofile == NULL) {
 413  439                  smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
 414  440                  return (SDRC_ERROR);
 415  441          }
 416  442  
 417  443          sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
 418  444  
 419  445          if (SMB_WRMODE_IS_STABLE(param->rw_mode) &&
 420  446              STYPE_ISIPC(sr->tid_tree->t_res_type)) {
 421  447                  smbsr_error(sr, 0, ERRSRV, ERRaccess);
 422  448                  return (SDRC_ERROR);
 423  449          }
 424  450  
 425  451          rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count,
 426  452              ¶m->rw_vdb);
 427  453  
 428  454          if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) {
 429  455                  smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
 430  456                      ERRDOS, ERROR_INVALID_PARAMETER);
 431  457                  return (SDRC_ERROR);
 432  458          }
 433  459  
 434  460          param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset;
 435  461  
 436  462          if (param->rw_count != 0) {
 437  463                  if ((rc = smb_common_write(sr, param)) != 0) {
 438  464                          if (sr->smb_error.status !=
 439  465                              NT_STATUS_FILE_LOCK_CONFLICT)
 440  466                                  smbsr_errno(sr, rc);
 441  467                          return (SDRC_ERROR);
 442  468                  }
 443  469          }
 444  470  
 445  471          count_low = param->rw_count & 0xFFFF;
 446  472          count_high = (param->rw_count >> 16) & 0xFF;
 447  473  
 448  474          rc = smbsr_encode_result(sr, 6, 0, "bb1.wwwwww",
 449  475              6, sr->andx_com, 15, count_low, 0, count_high, 0, 0);
 450  476  
 451  477          return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 452  478  }
 453  479  
 454  480  /*
 455  481   * Common function for writing files or IPC/MSRPC named pipes.
 456  482   *
 457  483   * Returns errno values.
 458  484   */
 459  485  int
 460  486  smb_common_write(smb_request_t *sr, smb_rw_param_t *param)
 461  487  {
 462  488          smb_ofile_t *ofile = sr->fid_ofile;
 463  489          smb_node_t *node;
 464  490          int stability = 0;
 465  491          uint32_t lcount;
 466  492          int rc = 0;
 467  493  
 468  494          switch (sr->tid_tree->t_res_type & STYPE_MASK) {
 469  495          case STYPE_DISKTREE:
 470  496          case STYPE_PRINTQ:
 471  497                  node = ofile->f_node;
 472  498  
 473  499                  if (!smb_node_is_dir(node)) {
 474  500                          rc = smb_lock_range_access(sr, node, param->rw_offset,
 475  501                              param->rw_count, B_TRUE);
 476  502                          if (rc != NT_STATUS_SUCCESS) {
 477  503                                  smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
  
    | 
      ↓ open down ↓ | 
    72 lines elided | 
    
      ↑ open up ↑ | 
  
 478  504                                      ERRDOS, ERROR_LOCK_VIOLATION);
 479  505                                  return (EACCES);
 480  506                          }
 481  507                  }
 482  508  
 483  509                  if (SMB_WRMODE_IS_STABLE(param->rw_mode) ||
 484  510                      (node->flags & NODE_FLAGS_WRITE_THROUGH)) {
 485  511                          stability = FSYNC;
 486  512                  }
 487  513  
 488      -                rc = smb_fsop_write(sr, sr->user_cr, node,
      514 +                rc = smb_fsop_write(sr, sr->user_cr, node, ofile,
 489  515                      ¶m->rw_vdb.vdb_uio, &lcount, stability);
 490  516  
 491  517                  if (rc)
 492  518                          return (rc);
 493  519  
 494  520                  /*
 495  521                   * Used to have code here to set mtime.
 496  522                   * We have just done a write, so we know
 497  523                   * the file system will update mtime.
 498  524                   * No need to do it again here.
 499  525                   *
 500  526                   * However, keep track of the fact that
 501  527                   * we have written data via this handle.
 502  528                   */
 503  529                  ofile->f_written = B_TRUE;
 504  530  
 505      -                if (!smb_node_is_dir(node))
 506      -                        smb_oplock_break_levelII(node);
      531 +                /* This revokes read cache delegations. */
      532 +                (void) smb_oplock_break_WRITE(node, ofile);
 507  533  
 508  534                  param->rw_count = lcount;
 509  535                  break;
 510  536  
 511  537          case STYPE_IPC:
 512  538                  param->rw_count = param->rw_vdb.vdb_uio.uio_resid;
 513  539  
 514  540                  if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.vdb_uio)) != 0)
 515  541                          param->rw_count = 0;
 516  542                  break;
 517  543  
 518  544          default:
 519  545                  rc = EACCES;
 520  546                  break;
 521  547          }
 522  548  
 523  549          if (rc != 0)
 524  550                  return (rc);
 525  551  
 526  552          mutex_enter(&ofile->f_mutex);
 527  553          ofile->f_seek_pos = param->rw_offset + param->rw_count;
 528  554          mutex_exit(&ofile->f_mutex);
 529  555          return (rc);
 530  556  }
 531  557  
 532  558  /*
 533  559   * Truncate a disk file to the specified offset.
 534  560   * Typically, w_count will be zero here.
 535  561   *
 536  562   * Note that smb_write_andx cannot be used to reduce the file size so,
 537  563   * if this is required, smb_write is called with a count of zero and
 538  564   * the appropriate file length in offset. The file should be resized
 539  565   * to the length specified by the offset.
 540  566   *
 541  567   * Returns errno values.
 542  568   */
 543  569  static int
 544  570  smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param)
 545  571  {
 546  572          smb_ofile_t *ofile = sr->fid_ofile;
 547  573          smb_node_t *node = ofile->f_node;
 548  574          smb_attr_t attr;
 549  575          uint32_t status;
 550  576          int rc;
 551  577  
 552  578          if (STYPE_ISIPC(sr->tid_tree->t_res_type))
 553  579                  return (0);
 554  580  
 555  581          mutex_enter(&node->n_mutex);
 556  582          if (!smb_node_is_dir(node)) {
 557  583                  status = smb_lock_range_access(sr, node, param->rw_offset,
 558  584                      param->rw_count, B_TRUE);
 559  585                  if (status != NT_STATUS_SUCCESS) {
 560  586                          mutex_exit(&node->n_mutex);
 561  587                          smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT,
 562  588                              ERRDOS, ERROR_LOCK_VIOLATION);
 563  589                          return (EACCES);
 564  590                  }
 565  591          }
 566  592          mutex_exit(&node->n_mutex);
 567  593  
 568  594          bzero(&attr, sizeof (smb_attr_t));
 569  595          attr.sa_mask = SMB_AT_SIZE;
 570  596          attr.sa_vattr.va_size = param->rw_offset;
 571  597          rc = smb_node_setattr(sr, node, sr->user_cr, ofile, &attr);
 572  598          if (rc != 0)
 573  599                  return (rc);
 574  600  
 575  601          mutex_enter(&ofile->f_mutex);
 576  602          ofile->f_seek_pos = param->rw_offset + param->rw_count;
 577  603          mutex_exit(&ofile->f_mutex);
 578  604          return (0);
 579  605  }
  
    | 
      ↓ open down ↓ | 
    63 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX