Print this page
    
NEX-18761 panic in smb_ofile_free with vdbench
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15069 smtorture smb2.create.blob is failed
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-4053 Customer DIR command hangs with smb2 enabled
NEX-4080 SMB_ODIR_FLAG_WILDCARDS can be incorrectly inherited
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-2058 Access Based Enumeration partially working in 4.0.1
OS-143 Cpqary3 driver does not see drives on P400 Smart-Array
SUP-813 Directory's are not visible or deleteable though CIFS
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-65 SMB server in non-global zones (use zone_kcred())
SMB-65 SMB server in non-global zones (kmem_caches)
common kmem_cache instances across zones
separate GZ-only init from NGZ init
SMB-63 taskq_create_proc ... TQ_DYNAMIC puts tasks in p0
re #11974 CIFS Share - Tree connect fails from Windows 7 Clients
re #7815 SMB server delivers old modification time...
re #6854 FindFirstFile,FindFirstFileEx,... are not working correctly on Nexenta CIFS-shares
re #10733 Windows 7 directory listing keeps restarting (fix lint)
re #10733 Windows 7 directory listing keeps restarting
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/smbsrv/smb_odir.c
          +++ new/usr/src/uts/common/fs/smbsrv/smb_odir.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   *
  
    | 
      ↓ open down ↓ | 
    12 lines elided | 
    
      ↑ open up ↑ | 
  
  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   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23      - * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
       23 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  24   24   */
  25   25  
  26   26  /*
  27   27   * General Structures Layout
  28   28   * -------------------------
  29   29   *
  30   30   * This is a simplified diagram showing the relationship between most of the
  31   31   * main structures.
  32   32   *
  33   33   * +-------------------+
  34   34   * |     SMB_INFO      |
  35   35   * +-------------------+
  36   36   *          |
  37   37   *          |
  38   38   *          v
  39   39   * +-------------------+       +-------------------+      +-------------------+
  40   40   * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
  41   41   * +-------------------+       +-------------------+      +-------------------+
  42   42   *   |          |
  43   43   *   |          |
  44   44   *   |          v
  45   45   *   |  +-------------------+     +-------------------+   +-------------------+
  46   46   *   |  |       USER        |<--->|       USER        |...|       USER        |
  47   47   *   |  +-------------------+     +-------------------+   +-------------------+
  48   48   *   |
  49   49   *   |
  50   50   *   v
  51   51   * +-------------------+       +-------------------+      +-------------------+
  52   52   * |       TREE        |<----->|       TREE        |......|       TREE        |
  53   53   * +-------------------+       +-------------------+      +-------------------+
  54   54   *      |         |
  55   55   *      |         |
  56   56   *      |         v
  57   57   *      |     +-------+       +-------+      +-------+
  58   58   *      |     | OFILE |<----->| OFILE |......| OFILE |
  59   59   *      |     +-------+       +-------+      +-------+
  60   60   *      |
  61   61   *      |
  62   62   *      v
  63   63   *  +-------+       +------+      +------+
  64   64   *  | ODIR  |<----->| ODIR |......| ODIR |
  65   65   *  +-------+       +------+      +------+
  66   66   *
  67   67   *
  68   68   * Odir State Machine
  69   69   * ------------------
  70   70   *
  71   71   *    +-------------------------+
  72   72   *    |  SMB_ODIR_STATE_OPEN    |<----------- open / creation
  73   73   *    +-------------------------+
  74   74   *          |            ^
  75   75   *          | (first)    | (last)
  76   76   *          | lookup     | release
  77   77   *          v            |
  78   78   *    +-------------------------+
  79   79   *    | SMB_ODIR_STATE_IN_USE   |----
  80   80   *    +-------------------------+   | lookup / release / read
  81   81   *          |                ^-------
  82   82   *          | close
  83   83   *          |
  84   84   *          v
  85   85   *    +-------------------------+
  86   86   *    | SMB_ODIR_STATE_CLOSING  |----
  87   87   *    +-------------------------+   | close / release / read
  88   88   *          |                ^-------
  89   89   *          | (last) release
  90   90   *          |
  91   91   *          v
  92   92   *    +-------------------------+
  93   93   *    | SMB_ODIR_STATE_CLOSED   |----------> deletion
  94   94   *    +-------------------------+
  95   95   *
  96   96   *
  97   97   * SMB_ODIR_STATE_OPEN
  98   98   * - the odir exists in the list of odirs of its tree
  99   99   * - lookup is valid in this state. It will place a hold on the odir
 100  100   *   by incrementing the reference count and the odir will transition
 101  101   *   to SMB_ODIR_STATE_IN_USE
 102  102   * - read/close/release not valid in this state
 103  103   *
 104  104   * SMB_ODIR_STATE_IN_USE
 105  105   * - the odir exists in the list of odirs of its tree.
 106  106   * - lookup is valid in this state. It will place a hold on the odir
 107  107   *   by incrementing the reference count.
 108  108   * - if the last hold is released the odir will transition
 109  109   *   back to SMB_ODIR_STATE_OPEN
 110  110   * - if a close is received the odir will transition to
 111  111   *   SMB_ODIR_STATE_CLOSING.
 112  112   *
 113  113   * SMB_ODIR_STATE_CLOSING
 114  114   * - the odir exists in the list of odirs of its tree.
 115  115   * - lookup will fail in this state.
 116  116   * - when the last hold is released the odir will transition
 117  117   *   to SMB_ODIR_STATE_CLOSED.
 118  118   *
 119  119   * SMB_ODIR_STATE_CLOSED
 120  120   * - the odir exists in the list of odirs of its tree.
 121  121   * - there are no users of the odir (refcnt == 0)
 122  122   * - the odir is being removed from the tree's list and deleted.
 123  123   * - lookup will fail in this state.
 124  124   * - read/close/release not valid in this state
 125  125   *
 126  126   * Comments
 127  127   * --------
 128  128   *    The state machine of the odir structures is controlled by 3 elements:
 129  129   *      - The list of odirs of the tree it belongs to.
 130  130   *      - The mutex embedded in the structure itself.
 131  131   *      - The reference count.
 132  132   *
 133  133   *    There's a mutex embedded in the odir structure used to protect its fields
 134  134   *    and there's a lock embedded in the list of odirs of a tree. To
 135  135   *    increment or to decrement the reference count the mutex must be entered.
 136  136   *    To insert the odir into the list of odirs of the tree and to remove
 137  137   *    the odir from it, the lock must be entered in RW_WRITER mode.
 138  138   *
 139  139   *    In order to avoid deadlocks, when both (mutex and lock of the odir
 140  140   *    list) have to be entered, the lock must be entered first.
 141  141   *
 142  142   *
 143  143   * Odir Interface
 144  144   * ---------------
 145  145   * smb_odir_open(char *pathname)
 146  146   *      Create an odir representing the directory specified in pathname and
 147  147   *      add it into the tree's list of odirs.
 148  148   *      Returns NT status.
 149  149   *
 150  150   * smb_odir_openfh(smb_ofile_t *of)
 151  151   *      Create an odir representing the directory specified by the
 152  152   *      existing open handle (from a prior open of the directory).
 153  153   *      Returns NT status.
 154  154   *
 155  155   * smb_odir_openat(smb_node_t *unode)
 156  156   *      Create an odir representing the extended attribute directory
 157  157   *      associated with the file (or directory) represented by unode
 158  158   *      and add it into the tree's list of odirs.
 159  159   *      Returns NT status.
 160  160   *
 161  161   * smb_odir_t *odir = smb_tree_lookup_odir(..., odid)
 162  162   *      Find the odir corresponding to the specified odid in the tree's
 163  163   *      list of odirs. Place a hold on the odir.
 164  164   *
 165  165   * smb_odir_read(..., smb_odirent_t *odirent)
 166  166   *      Find the next directory entry in the odir and return it in odirent.
 167  167   *
 168  168   * smb_odir_read_fileinfo(..., smb_fileinfo_t *)
 169  169   *      Find the next directory entry in the odir. Return the details of
 170  170   *      the directory entry in smb_fileinfo_t. (See odir internals below)
 171  171   *
 172  172   * smb_odir_read_streaminfo(..., smb_streaminfo_t *)
 173  173   *      Find the next named stream entry in the odir. Return the details of
 174  174   *      the named stream in smb_streaminfo_t.
 175  175   *
 176  176   * smb_odir_close(smb_odir_t *odir)
 177  177   *  Close the odir.
 178  178   *  The caller of close must have a hold on the odir being closed.
 179  179   *  The hold should be released after closing.
 180  180   *
 181  181   * smb_odir_release(smb_odir_t *odir)
 182  182   *      Release the hold on the odir, obtained by lookup.
 183  183   *
 184  184   *
 185  185   * Odir Internals
 186  186   * --------------
 187  187   * The odir object represent an open directory search. Each read operation
 188  188   * provides the caller with a structure containing information  pertaining
 189  189   * to the next directory entry that matches the search criteria, namely
 190  190   * the filename or match pattern and, in the case of smb_odir_read_fileinfo(),
 191  191   * the search attributes.
 192  192   *
 193  193   * The odir maintains a buffer (d_buf) of directory entries read from
 194  194   * the filesystem via a vop_readdir. The buffer is populated when a read
 195  195   * request (smb_odir_next_odirent) finds that the buffer is empty or that
 196  196   * the end of the buffer has been reached, and also when a new client request
 197  197   * (find next) begins.
 198  198   *
 199  199   * The data in d_buf (that which is returned from the file system) can
 200  200   * be in one of two formats. If the file system supports extended directory
 201  201   * entries we request that the data be returned as edirent_t structures. If
 202  202   * it does not the data will be returned as dirent64_t structures. For
 203  203   * convenience, when the next directory entry is read from d_buf by
 204  204   * smb_odir_next_odirent it is translated into an smb_odirent_t.
 205  205   *
 206  206   * smb_odir_read_fileinfo
 207  207   * The processing required to obtain the information to populate the caller's
 208  208   * smb_fileinfo_t differs depending upon whether the directory search is for a
 209  209   * single specified filename or for multiple files matching a search pattern.
 210  210   * Thus smb_odir_read_fileinfo uses two static functions:
 211  211   * smb_odir_single_fileinfo - obtains the smb_fileinfo_t info for the single
 212  212   * filename as specified in smb_odir_open request.
 213  213   * smb_odir_wildcard_fileinfo - obtains the smb_fileinfo_t info for the filename
 214  214   * returned from the smb_odir_next_odirent. This is called in a loop until
 215  215   * an entry matching the search criteria is found or no more entries exist.
 216  216   *
 217  217   * If a directory entry is a VLNK, the name returned in the smb_fileinfo_t
 218  218   * is the name of the directory entry but the attributes are the attribites
 219  219   * of the file that is the target of the link. If the link target cannot
 220  220   * be found the attributes returned are the attributes of the link itself.
 221  221   *
 222  222   * smb_odir_read_streaminfo
 223  223   * In order for an odir to provide information about stream files it
 224  224   * must be opened with smb_odir_openat(). smb_odir_read_streaminfo() can
 225  225   * then be used to obtain the name and size of named stream files.
 226  226   *
 227  227   * Resuming a Search
 228  228   * -----------------
 229  229   * A directory search often consists of multiple client requests: an initial
 230  230   * find_first request followed by zero or more find_next requests and a
 231  231   * find_close request.
 232  232   * The find_first request will open and lookup the odir, read its desired
 233  233   * number of entries from the odir, then release the odir and return.
 234  234   * A find_next request will lookup the odir and read its desired number of
 235  235   * entries from the odir, then release the odir and return.
 236  236   * At the end of the search the find_close request will close the odir.
 237  237   *
 238  238   * In order to be able to resume a directory search (find_next) the odir
 239  239   * provides the capability for the caller to save one or more resume points
 240  240   * (cookies) at the end of a request, and to specify which resume point
 241  241   * (cookie) to restart from at the beginning of the next search.
 242  242   *      smb_odir_save_cookie(..., cookie)
 243  243   *      smb_odir_resume_at(smb_odir_resume_t *resume)
 244  244   * A search can be resumed at a specified resume point (cookie), the resume
 245  245   * point (cookie) stored at a specified index in the d_cookies array, or
 246  246   * a specified filename. The latter (specified filename) is not yet supported.
 247  247   *
 248  248   * See smb_search, smb_find, smb_find_unique, and smb_trans2_find for details
 249  249   */
 250  250  
 251  251  #include <smbsrv/smb_kproto.h>
 252  252  #include <smbsrv/smb_fsops.h>
 253  253  #include <smbsrv/smb_share.h>
 254  254  #include <sys/extdirent.h>
 255  255  
 256  256  /* static functions */
  
    | 
      ↓ open down ↓ | 
    223 lines elided | 
    
      ↑ open up ↑ | 
  
 257  257  static smb_odir_t *smb_odir_create(smb_request_t *, smb_node_t *,
 258  258      const char *, uint16_t, uint16_t, cred_t *);
 259  259  static int smb_odir_single_fileinfo(smb_request_t *, smb_odir_t *,
 260  260      smb_fileinfo_t *);
 261  261  static int smb_odir_wildcard_fileinfo(smb_request_t *, smb_odir_t *,
 262  262      smb_odirent_t *, smb_fileinfo_t *);
 263  263  static int smb_odir_next_odirent(smb_odir_t *, smb_odirent_t *);
 264  264  static boolean_t smb_odir_lookup_link(smb_request_t *, smb_odir_t *,
 265  265      char *, smb_node_t **);
 266  266  static boolean_t smb_odir_match_name(smb_odir_t *, smb_odirent_t *);
      267 +static void smb_odir_delete(void *);
 267  268  
 268  269  
 269  270  /*
 270  271   * smb_odir_openpath
 271  272   *
 272  273   * Create an odir representing the directory specified in pathname.
 273  274   *
 274  275   * Returns:
 275  276   *    NT Status
 276  277   */
 277  278  uint32_t
 278  279  smb_odir_openpath(smb_request_t *sr, char *path, uint16_t sattr,
 279  280          uint32_t flags, smb_odir_t **odp)
 280  281  {
 281  282          int             rc;
 282  283          smb_tree_t      *tree;
 283  284          smb_node_t      *dnode;
 284  285          char            pattern[MAXNAMELEN];
 285      -        uint16_t        odid;
      286 +        uint16_t        odid;
 286  287          cred_t          *cr;
 287  288  
 288  289          ASSERT(sr);
 289  290          ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
 290  291          ASSERT(sr->tid_tree);
 291  292          ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC);
 292  293          *odp = NULL;
 293  294  
 294  295          tree = sr->tid_tree;
 295  296  
 296  297          if (sr->session->dialect < NT_LM_0_12)
 297  298                  smb_convert_wildcards(path);
 298  299  
 299  300          rc = smb_pathname_reduce(sr, sr->user_cr, path,
 300  301              tree->t_snode, tree->t_snode, &dnode, pattern);
 301  302          if (rc != 0)
 302  303                  return (smb_errno2status(rc));
 303  304  
 304  305          if (!smb_node_is_dir(dnode)) {
 305  306                  smb_node_release(dnode);
 306  307                  return (NT_STATUS_OBJECT_PATH_NOT_FOUND);
 307  308          }
 308  309  
 309  310          if (smb_fsop_access(sr, sr->user_cr, dnode, FILE_LIST_DIRECTORY) != 0) {
 310  311                  smb_node_release(dnode);
 311  312                  return (NT_STATUS_ACCESS_DENIED);
 312  313          }
 313  314  
 314  315          if (smb_idpool_alloc(&tree->t_odid_pool, &odid)) {
 315  316                  smb_node_release(dnode);
 316  317                  return (NT_STATUS_TOO_MANY_OPENED_FILES);
 317  318          }
 318  319  
 319  320          if (flags & SMB_ODIR_OPENF_BACKUP_INTENT)
 320  321                  cr = smb_user_getprivcred(sr->uid_user);
 321  322          else
 322  323                  cr = sr->uid_user->u_cred;
 323  324  
 324  325          *odp = smb_odir_create(sr, dnode, pattern, sattr, odid, cr);
 325  326          smb_node_release(dnode);
 326  327  
 327  328          return (0);
 328  329  }
 329  330  
 330  331  /*
 331  332   * smb_odir_openfh
 332  333   *
 333  334   * Create an odir representing the directory already opened on "of".
 334  335   *
 335  336   * Returns:
 336  337   *    NT status
 337  338   */
 338  339  uint32_t
 339  340  smb_odir_openfh(smb_request_t *sr, const char *pattern, uint16_t sattr,
 340  341          smb_odir_t **odp)
 341  342  {
 342  343          smb_ofile_t     *of = sr->fid_ofile;
 343  344  
 344  345          *odp = NULL;
 345  346  
 346  347          if (of->f_node == NULL || !smb_node_is_dir(of->f_node))
 347  348                  return (NT_STATUS_INVALID_PARAMETER);
 348  349  
 349  350          if ((of->f_granted_access & FILE_LIST_DIRECTORY) == 0)
 350  351                  return (NT_STATUS_ACCESS_DENIED);
 351  352  
 352  353          *odp = smb_odir_create(sr, of->f_node, pattern, sattr, 0, of->f_cr);
 353  354  
 354  355          return (0);
 355  356  }
 356  357  
 357  358  /*
 358  359   * smb_odir_openat
 359  360   *
 360  361   * Create an odir representing the extended attribute directory
 361  362   * associated with the file (or directory) represented by unode.
 362  363   *
 363  364   * Returns:
 364  365   *    NT status
 365  366   */
 366  367  uint32_t
 367  368  smb_odir_openat(smb_request_t *sr, smb_node_t *unode, smb_odir_t **odp)
 368  369  {
 369  370          char            pattern[SMB_STREAM_PREFIX_LEN + 2];
 370  371          vnode_t         *xattr_dvp;
 371  372          cred_t          *cr;
 372  373          smb_node_t      *xattr_dnode;
 373  374          int             rc;
 374  375  
 375  376          ASSERT(sr);
 376  377          ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
 377  378          ASSERT(unode);
 378  379          ASSERT(unode->n_magic == SMB_NODE_MAGIC);
 379  380          *odp = NULL;
 380  381  
 381  382          if (SMB_TREE_CONTAINS_NODE(sr, unode) == 0 ||
 382  383              SMB_TREE_HAS_ACCESS(sr, ACE_LIST_DIRECTORY) == 0)
 383  384                  return (NT_STATUS_ACCESS_DENIED);
 384  385  
 385  386          cr = zone_kcred();
 386  387  
 387  388          /* find the xattrdir vnode */
 388  389          rc = smb_vop_lookup_xattrdir(unode->vp, &xattr_dvp, LOOKUP_XATTR, cr);
 389  390          if (rc != 0)
 390  391                  return (smb_errno2status(rc));
 391  392  
 392  393          /* lookup the xattrdir's smb_node */
 393  394          xattr_dnode = smb_node_lookup(sr, NULL, cr, xattr_dvp, XATTR_DIR,
 394  395              unode, NULL);
 395  396          VN_RELE(xattr_dvp);
 396  397          if (xattr_dnode == NULL)
 397  398                  return (NT_STATUS_NO_MEMORY);
 398  399  
 399  400          (void) snprintf(pattern, sizeof (pattern), "%s*", SMB_STREAM_PREFIX);
 400  401          *odp = smb_odir_create(sr, xattr_dnode, pattern,
 401  402              SMB_SEARCH_ATTRIBUTES, 0, cr);
 402  403  
 403  404          smb_node_release(xattr_dnode);
 404  405          return (0);
 405  406  }
 406  407  
 407  408  /*
 408  409   * smb_odir_hold
 409  410   *
 410  411   * A hold will only be granted if the odir is open or in_use.
 411  412   */
 412  413  boolean_t
 413  414  smb_odir_hold(smb_odir_t *od)
 414  415  {
 415  416          ASSERT(od);
 416  417          ASSERT(od->d_magic == SMB_ODIR_MAGIC);
 417  418  
 418  419          mutex_enter(&od->d_mutex);
 419  420  
 420  421          switch (od->d_state) {
 421  422          case SMB_ODIR_STATE_OPEN:
 422  423                  od->d_refcnt++;
 423  424                  od->d_state = SMB_ODIR_STATE_IN_USE;
 424  425                  break;
 425  426          case SMB_ODIR_STATE_IN_USE:
 426  427                  od->d_refcnt++;
 427  428                  break;
 428  429          case SMB_ODIR_STATE_CLOSING:
 429  430          case SMB_ODIR_STATE_CLOSED:
 430  431          default:
 431  432                  mutex_exit(&od->d_mutex);
 432  433                  return (B_FALSE);
 433  434          }
 434  435  
 435  436          mutex_exit(&od->d_mutex);
 436  437          return (B_TRUE);
 437  438  }
  
    | 
      ↓ open down ↓ | 
    142 lines elided | 
    
      ↑ open up ↑ | 
  
 438  439  
 439  440  /*
 440  441   * If the odir is in SMB_ODIR_STATE_CLOSING and this release results in
 441  442   * a refcnt of 0, change the state to SMB_ODIR_STATE_CLOSED and post the
 442  443   * object for deletion.  Object deletion is deferred to avoid modifying
 443  444   * a list while an iteration may be in progress.
 444  445   */
 445  446  void
 446  447  smb_odir_release(smb_odir_t *od)
 447  448  {
      449 +        smb_tree_t *tree = od->d_tree;
      450 +
 448  451          SMB_ODIR_VALID(od);
 449  452  
 450  453          mutex_enter(&od->d_mutex);
 451  454          ASSERT(od->d_refcnt > 0);
 452  455  
 453  456          switch (od->d_state) {
 454  457          case SMB_ODIR_STATE_OPEN:
 455  458                  break;
 456  459          case SMB_ODIR_STATE_IN_USE:
 457  460                  od->d_refcnt--;
 458  461                  if (od->d_refcnt == 0)
 459  462                          od->d_state = SMB_ODIR_STATE_OPEN;
 460  463                  break;
 461  464          case SMB_ODIR_STATE_CLOSING:
 462  465                  od->d_refcnt--;
 463  466                  if (od->d_refcnt == 0) {
 464  467                          od->d_state = SMB_ODIR_STATE_CLOSED;
 465      -                        smb_tree_post_odir(od->d_tree, od);
      468 +                        smb_llist_post(&tree->t_odir_list, od,
      469 +                            smb_odir_delete);
 466  470                  }
 467  471                  break;
 468  472          case SMB_ODIR_STATE_CLOSED:
 469  473          default:
 470  474                  break;
 471  475          }
 472  476  
 473  477          mutex_exit(&od->d_mutex);
 474  478  }
 475  479  
 476  480  /*
 477  481   * smb_odir_close
 478  482   */
 479  483  void
 480  484  smb_odir_close(smb_odir_t *od)
 481  485  {
 482  486          ASSERT(od);
 483  487          ASSERT(od->d_magic == SMB_ODIR_MAGIC);
 484  488  
 485  489          mutex_enter(&od->d_mutex);
 486  490          ASSERT(od->d_refcnt > 0);
 487  491          switch (od->d_state) {
 488  492          case SMB_ODIR_STATE_OPEN:
 489  493                  break;
 490  494          case SMB_ODIR_STATE_IN_USE:
 491  495                  od->d_state = SMB_ODIR_STATE_CLOSING;
 492  496                  break;
 493  497          case SMB_ODIR_STATE_CLOSING:
 494  498          case SMB_ODIR_STATE_CLOSED:
 495  499          default:
 496  500                  break;
 497  501          }
 498  502          mutex_exit(&od->d_mutex);
 499  503  }
 500  504  
 501  505  /*
 502  506   * smb_odir_read
 503  507   *
 504  508   * Find the next directory entry matching the search pattern.
 505  509   * No search attribute matching is performed.
 506  510   *
 507  511   * Returns:
 508  512   *  0 - success.
 509  513   *      - If a matching entry was found eof will be B_FALSE and
 510  514   *        odirent will be populated.
 511  515   * ENOENT
 512  516   *      - If we've scanned to the end, eof will be B_TRUE.
 513  517   * errno - other errors
 514  518   */
 515  519  int
 516  520  smb_odir_read(smb_request_t *sr, smb_odir_t *od,
 517  521      smb_odirent_t *odirent, boolean_t *eof)
 518  522  {
 519  523          int             rc;
 520  524  
 521  525          ASSERT(sr);
 522  526          ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
 523  527          ASSERT(od);
 524  528          ASSERT(od->d_magic == SMB_ODIR_MAGIC);
 525  529          ASSERT(odirent);
 526  530  
 527  531          mutex_enter(&od->d_mutex);
 528  532          ASSERT(od->d_refcnt > 0);
 529  533  
 530  534          switch (od->d_state) {
 531  535          case SMB_ODIR_STATE_IN_USE:
 532  536          case SMB_ODIR_STATE_CLOSING:
 533  537                  break;
 534  538          case SMB_ODIR_STATE_OPEN:
 535  539          case SMB_ODIR_STATE_CLOSED:
 536  540          default:
 537  541                  mutex_exit(&od->d_mutex);
 538  542                  return (EBADF);
 539  543          }
 540  544  
 541  545          for (;;) {
 542  546                  if ((rc = smb_odir_next_odirent(od, odirent)) != 0)
 543  547                          break;
 544  548                  if (smb_odir_match_name(od, odirent))
 545  549                          break;
 546  550          }
 547  551  
 548  552          mutex_exit(&od->d_mutex);
 549  553  
 550  554          switch (rc) {
 551  555          case 0:
 552  556                  *eof = B_FALSE;
 553  557                  return (0);
 554  558          case ENOENT:
 555  559                  *eof = B_TRUE;
 556  560                  /* FALLTHROUGH */
 557  561          default:
 558  562                  return (rc);
 559  563          }
 560  564  }
 561  565  
 562  566  /*
 563  567   * smb_odir_read_fileinfo
 564  568   *
 565  569   * Find the next directory entry matching the search pattern
 566  570   * and attributes: od->d_pattern and od->d_sattr.
 567  571   *
 568  572   * If the search pattern specifies a single filename call
 569  573   * smb_odir_single_fileinfo to get the file attributes and
 570  574   * populate the caller's smb_fileinfo_t.
 571  575   *
 572  576   * If the search pattern contains wildcards call smb_odir_next_odirent
 573  577   * to get the next directory entry then. Repeat until a matching
 574  578   * filename is found. Call smb_odir_wildcard_fileinfo to get the
 575  579   * file attributes and populate the caller's smb_fileinfo_t.
 576  580   * This is repeated until a file matching the search criteria is found.
 577  581   *
 578  582   * Returns:
 579  583   *  0 - success.
 580  584   *      - If a matching entry was found eof will be B_FALSE and
 581  585   *        fileinfo will be populated.
 582  586   * ENOENT
 583  587   *      - If at end of dir, eof will be B_TRUE.
 584  588   * errno - other error
 585  589   */
 586  590  int
 587  591  smb_odir_read_fileinfo(smb_request_t *sr, smb_odir_t *od,
 588  592      smb_fileinfo_t *fileinfo, uint16_t *eof)
 589  593  {
 590  594          int             rc, errnum;
 591  595          smb_odirent_t   *odirent;
 592  596  
 593  597          ASSERT(sr);
 594  598          ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
 595  599          ASSERT(od);
 596  600          ASSERT(od->d_magic == SMB_ODIR_MAGIC);
 597  601          ASSERT(fileinfo);
 598  602  
 599  603          mutex_enter(&od->d_mutex);
 600  604          ASSERT(od->d_refcnt > 0);
 601  605  
 602  606          switch (od->d_state) {
 603  607          case SMB_ODIR_STATE_IN_USE:
 604  608          case SMB_ODIR_STATE_CLOSING:
 605  609                  break;
 606  610          case SMB_ODIR_STATE_OPEN:
 607  611          case SMB_ODIR_STATE_CLOSED:
 608  612          default:
 609  613                  mutex_exit(&od->d_mutex);
 610  614                  return (EBADF);
 611  615          }
 612  616  
 613  617          if ((od->d_flags & SMB_ODIR_FLAG_WILDCARDS) == 0) {
 614  618                  if (od->d_eof)
 615  619                          rc = ENOENT;
 616  620                  else
 617  621                          rc = smb_odir_single_fileinfo(sr, od, fileinfo);
 618  622                  od->d_eof = B_TRUE;
 619  623          } else {
 620  624                  odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
 621  625                  for (;;) {
 622  626                          bzero(fileinfo, sizeof (smb_fileinfo_t));
 623  627                          if ((rc = smb_odir_next_odirent(od, odirent)) != 0)
 624  628                                  break;
 625  629  
 626  630                          /* skip non utf8 filename */
 627  631                          if (u8_validate(odirent->od_name,
 628  632                              strlen(odirent->od_name), NULL,
 629  633                              U8_VALIDATE_ENTIRE, &errnum) < 0)
 630  634                                  continue;
 631  635  
 632  636                          if (!smb_odir_match_name(od, odirent))
 633  637                                  continue;
 634  638  
 635  639                          rc = smb_odir_wildcard_fileinfo(sr, od, odirent,
 636  640                              fileinfo);
 637  641                          if (rc == 0)
 638  642                                  break;
 639  643                  }
 640  644                  kmem_free(odirent, sizeof (smb_odirent_t));
 641  645          }
 642  646          mutex_exit(&od->d_mutex);
 643  647  
 644  648          switch (rc) {
 645  649          case 0:
 646  650                  *eof = 0;
 647  651                  return (0);
 648  652          case ENOENT:
 649  653                  *eof = 1;       /* per. FindFirst, FindNext spec. */
 650  654                  /* FALLTHROUGH */
 651  655          default:
 652  656                  return (rc);
 653  657          }
 654  658  }
 655  659  
 656  660  /*
 657  661   * smb_odir_read_streaminfo
 658  662   *
 659  663   * Find the next directory entry whose name begins with SMB_STREAM_PREFIX,
 660  664   * and thus represents an NTFS named stream.
 661  665   * No search attribute matching is performed.
 662  666   * No case conflict name mangling is required for NTFS named stream names.
 663  667   *
 664  668   * Returns:
 665  669   *  0 - success.
 666  670   *      - If a matching entry was found eof will be B_FALSE and
 667  671   *        sinfo will be populated.
 668  672   *      - If there are no matching entries eof will be B_TRUE.
 669  673   * errno - error
 670  674   */
 671  675  int
 672  676  smb_odir_read_streaminfo(smb_request_t *sr, smb_odir_t *od,
 673  677      smb_streaminfo_t *sinfo, boolean_t *eof)
 674  678  {
 675  679          int             rc;
 676  680          cred_t          *kcr;
 677  681          smb_odirent_t   *odirent;
 678  682          smb_node_t      *fnode;
 679  683          smb_attr_t      attr;
 680  684  
 681  685          ASSERT(sr);
 682  686          ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
 683  687          ASSERT(od);
 684  688          ASSERT(od->d_magic == SMB_ODIR_MAGIC);
 685  689          ASSERT(sinfo);
 686  690  
 687  691          kcr = zone_kcred();
 688  692  
 689  693          mutex_enter(&od->d_mutex);
 690  694          ASSERT(od->d_refcnt > 0);
 691  695  
 692  696          switch (od->d_state) {
 693  697          case SMB_ODIR_STATE_IN_USE:
 694  698          case SMB_ODIR_STATE_CLOSING:
 695  699                  break;
 696  700          case SMB_ODIR_STATE_OPEN:
 697  701          case SMB_ODIR_STATE_CLOSED:
 698  702          default:
 699  703                  mutex_exit(&od->d_mutex);
 700  704                  return (EBADF);
 701  705          }
 702  706  
 703  707          /* Check that odir represents an xattr directory */
 704  708          if (!(od->d_flags & SMB_ODIR_FLAG_XATTR)) {
 705  709                  *eof = B_TRUE;
 706  710                  mutex_exit(&od->d_mutex);
 707  711                  return (0);
 708  712          }
 709  713  
 710  714          odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
 711  715          bzero(&attr, sizeof (attr));
 712  716  
 713  717          for (;;) {
 714  718                  bzero(sinfo, sizeof (smb_streaminfo_t));
 715  719                  if ((rc = smb_odir_next_odirent(od, odirent)) != 0)
 716  720                          break;
 717  721  
 718  722                  if (strncmp(odirent->od_name, SMB_STREAM_PREFIX,
 719  723                      SMB_STREAM_PREFIX_LEN)) {
 720  724                          continue;
 721  725                  }
 722  726  
 723  727                  rc = smb_fsop_lookup(sr, od->d_cred, 0, od->d_tree->t_snode,
 724  728                      od->d_dnode, odirent->od_name, &fnode);
 725  729                  if (rc == 0) {
 726  730                          /*
 727  731                           * We just need the file sizes, and don't want
 728  732                           * EACCES failures here, so use kcred and pass
 729  733                           * NULL as the sr to skip sr->fid-ofile checks.
 730  734                           */
 731  735                          attr.sa_mask = SMB_AT_SIZE | SMB_AT_ALLOCSZ;
 732  736                          rc = smb_node_getattr(NULL, fnode, kcr, NULL, &attr);
 733  737                          smb_node_release(fnode);
 734  738                  }
 735  739  
 736  740                  if (rc == 0) {
 737  741                          (void) strlcpy(sinfo->si_name,
 738  742                              odirent->od_name + SMB_STREAM_PREFIX_LEN,
 739  743                              sizeof (sinfo->si_name));
 740  744                          sinfo->si_size = attr.sa_vattr.va_size;
 741  745                          sinfo->si_alloc_size = attr.sa_allocsz;
 742  746                          break;
 743  747                  }
 744  748          }
 745  749          mutex_exit(&od->d_mutex);
 746  750  
 747  751          kmem_free(odirent, sizeof (smb_odirent_t));
 748  752  
 749  753          switch (rc) {
 750  754          case 0:
 751  755                  *eof = B_FALSE;
 752  756                  return (0);
 753  757          case ENOENT:
 754  758                  *eof = B_TRUE;
 755  759                  return (0);
 756  760          default:
 757  761                  return (rc);
 758  762          }
 759  763  }
 760  764  
 761  765  /*
 762  766   * smb_odir_save_cookie
 763  767   *
 764  768   * Callers can save up to SMB_MAX_SEARCH cookies in the odir
 765  769   * to be used as resume points for a 'find next' request.
 766  770   */
 767  771  void
 768  772  smb_odir_save_cookie(smb_odir_t *od, int idx, uint32_t cookie)
 769  773  {
 770  774          ASSERT(od);
 771  775          ASSERT(od->d_magic == SMB_ODIR_MAGIC);
 772  776          ASSERT(idx >= 0 && idx < SMB_MAX_SEARCH);
 773  777  
 774  778          mutex_enter(&od->d_mutex);
 775  779          od->d_cookies[idx] = cookie;
 776  780          mutex_exit(&od->d_mutex);
 777  781  }
 778  782  
 779  783  /*
 780  784   * smb_odir_save_fname
 781  785   *
 782  786   * Save a filename / offset pair, which are basically a
 783  787   * one entry cache.  See smb_com_trans2_find_next2.
 784  788   */
 785  789  void
 786  790  smb_odir_save_fname(smb_odir_t *od, uint32_t cookie, const char *fname)
 787  791  {
 788  792          ASSERT(od);
 789  793          ASSERT(od->d_magic == SMB_ODIR_MAGIC);
 790  794  
 791  795          mutex_enter(&od->d_mutex);
 792  796  
 793  797          od->d_last_cookie = cookie;
 794  798          bzero(od->d_last_name, MAXNAMELEN);
 795  799          if (fname != NULL)
 796  800                  (void) strlcpy(od->d_last_name, fname, MAXNAMELEN);
 797  801  
 798  802          mutex_exit(&od->d_mutex);
 799  803  }
 800  804  
 801  805  /*
 802  806   * smb_odir_resume_at
 803  807   *
 804  808   * If SMB_ODIR_FLAG_WILDCARDS is not set, and we're rewinding,
 805  809   * assume we're no longer at EOF.
 806  810   *
 807  811   * Wildcard searching can be resumed from:
 808  812   * - the cookie saved at a specified index (SMBsearch, SMBfind).
 809  813   * - a specified cookie (SMB_trans2_find)
 810  814   * - a specified filename (SMB_trans2_find) - NOT SUPPORTED.
 811  815   *   Defaults to continuing from where the last search ended.
 812  816   *
 813  817   * Continuation from where the last search ended (SMB_trans2_find)
 814  818   * is implemented by saving the last cookie at a specific index (0)
 815  819   * smb_odir_resume_at indicates a new request, so reset od->d_bufptr
 816  820   * and d_eof to force a vop_readdir.
 817  821   */
 818  822  void
 819  823  smb_odir_resume_at(smb_odir_t *od, smb_odir_resume_t *resume)
 820  824  {
 821  825          uint64_t save_offset;
 822  826  
 823  827          ASSERT(od);
 824  828          ASSERT(od->d_magic == SMB_ODIR_MAGIC);
 825  829          ASSERT(resume);
 826  830  
 827  831          if ((od->d_flags & SMB_ODIR_FLAG_WILDCARDS) == 0) {
 828  832                  if (resume->or_type == SMB_ODIR_RESUME_COOKIE)
 829  833                          od->d_eof = B_FALSE;
 830  834                  return;
 831  835          }
 832  836          mutex_enter(&od->d_mutex);
 833  837  
 834  838          save_offset = od->d_offset;
 835  839          switch (resume->or_type) {
 836  840  
 837  841          default:
 838  842          case SMB_ODIR_RESUME_CONT:
 839  843                  /* Continue where we left off. */
 840  844                  break;
 841  845  
 842  846          case SMB_ODIR_RESUME_IDX:
 843  847                  /*
 844  848                   * This is used only by the (ancient) SMB_SEARCH.
 845  849                   * Modern clients use trans2 FindFirst, FindNext.
 846  850                   */
 847  851                  ASSERT(resume->or_idx >= 0);
 848  852                  ASSERT(resume->or_idx < SMB_MAX_SEARCH);
 849  853  
 850  854                  if ((resume->or_idx < 0) ||
 851  855                      (resume->or_idx >= SMB_MAX_SEARCH)) {
 852  856                          resume->or_idx = 0;
 853  857                  }
 854  858                  od->d_offset = od->d_cookies[resume->or_idx];
 855  859                  break;
 856  860  
 857  861          case SMB_ODIR_RESUME_COOKIE:
 858  862                  od->d_offset = resume->or_cookie;
 859  863                  break;
 860  864  
 861  865          case SMB_ODIR_RESUME_FNAME:
 862  866                  /*
 863  867                   * If the name matches the last one saved,
 864  868                   * use the offset that was saved with it in
 865  869                   * the odir.  Otherwise use the cookie value
 866  870                   * in the resume data from the client.
 867  871                   */
 868  872                  if (strcmp(resume->or_fname, od->d_last_name) &&
 869  873                      od->d_last_cookie != 0) {
 870  874                          od->d_offset = od->d_last_cookie;
 871  875                  } else if (resume->or_cookie != 0) {
 872  876                          od->d_offset = resume->or_cookie;
 873  877                  } /* else continue where we left off */
 874  878                  break;
 875  879          }
 876  880  
 877  881          if (od->d_offset != save_offset) {
 878  882                  /* Force a vop_readdir to refresh d_buf */
 879  883                  od->d_bufptr = NULL;
 880  884                  od->d_eof = B_FALSE;
 881  885          }
 882  886  
 883  887          mutex_exit(&od->d_mutex);
 884  888  }
 885  889  
 886  890  
 887  891  /* *** static functions *** */
 888  892  
 889  893  /*
 890  894   * smb_odir_create
 891  895   * Allocate and populate an odir obect and add it to the tree's list.
 892  896   */
 893  897  static smb_odir_t *
 894  898  smb_odir_create(smb_request_t *sr, smb_node_t *dnode,
 895  899          const char *pattern, uint16_t sattr, uint16_t odid, cred_t *cr)
 896  900  {
 897  901          smb_odir_t      *od;
 898  902          smb_tree_t      *tree;
 899  903  
 900  904          ASSERT(sr);
 901  905          ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
 902  906          ASSERT(sr->tid_tree);
 903  907          ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC);
 904  908          ASSERT(dnode);
 905  909          ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
 906  910  
 907  911          tree = sr->tid_tree;
 908  912  
 909  913          od = kmem_cache_alloc(smb_cache_odir, KM_SLEEP);
 910  914          bzero(od, sizeof (smb_odir_t));
 911  915  
 912  916          mutex_init(&od->d_mutex, NULL, MUTEX_DEFAULT, NULL);
 913  917  
 914  918          /*
 915  919           * Return this to the caller as if they had done
 916  920           * smb_tree_lookup_odir() to obtain the odir.
 917  921           */
 918  922          od->d_refcnt = 1;
 919  923          od->d_state = SMB_ODIR_STATE_IN_USE;
 920  924          od->d_magic = SMB_ODIR_MAGIC;
 921  925          od->d_opened_by_pid = sr->smb_pid;
 922  926          od->d_session = tree->t_session;
 923  927          od->d_cred = cr;
 924  928          /*
 925  929           * grab a ref for od->d_user
 926  930           * released in  smb_odir_delete()
 927  931           */
 928  932          smb_user_hold_internal(sr->uid_user);
 929  933          od->d_user = sr->uid_user;
 930  934          od->d_tree = tree;
 931  935          od->d_dnode = dnode;
 932  936          smb_node_ref(dnode);
 933  937          od->d_odid = odid;
 934  938          od->d_sattr = sattr;
 935  939          (void) strlcpy(od->d_pattern, pattern, sizeof (od->d_pattern));
 936  940          od->d_flags = 0;
 937  941          if (smb_contains_wildcards(od->d_pattern))
 938  942                  od->d_flags |= SMB_ODIR_FLAG_WILDCARDS;
 939  943          if (vfs_has_feature(dnode->vp->v_vfsp, VFSFT_DIRENTFLAGS))
 940  944                  od->d_flags |= SMB_ODIR_FLAG_EDIRENT;
 941  945          if (smb_tree_has_feature(tree, SMB_TREE_CASEINSENSITIVE))
 942  946                  od->d_flags |= SMB_ODIR_FLAG_IGNORE_CASE;
 943  947          if (smb_tree_has_feature(tree, SMB_TREE_SHORTNAMES))
 944  948                  od->d_flags |= SMB_ODIR_FLAG_SHORTNAMES;
 945  949          if (SMB_TREE_SUPPORTS_CATIA(sr))
 946  950                  od->d_flags |= SMB_ODIR_FLAG_CATIA;
 947  951          if (SMB_TREE_SUPPORTS_ABE(sr))
 948  952                  od->d_flags |= SMB_ODIR_FLAG_ABE;
 949  953          if (dnode->flags & NODE_XATTR_DIR)
 950  954                  od->d_flags |= SMB_ODIR_FLAG_XATTR;
 951  955          od->d_eof = B_FALSE;
 952  956  
 953  957          smb_llist_enter(&tree->t_odir_list, RW_WRITER);
 954  958          smb_llist_insert_tail(&tree->t_odir_list, od);
 955  959          smb_llist_exit(&tree->t_odir_list);
 956  960  
 957  961          atomic_inc_32(&tree->t_session->s_dir_cnt);
 958  962          return (od);
 959  963  }
 960  964  
 961  965  /*
 962  966   * Set a new pattern, attributes, and rewind.
 963  967   */
 964  968  void
 965  969  smb_odir_reopen(smb_odir_t *od, const char *pattern, uint16_t sattr)
 966  970  {
 967  971  
 968  972          SMB_ODIR_VALID(od);
 969  973  
 970  974          mutex_enter(&od->d_mutex);
 971  975          od->d_sattr = sattr;
 972  976          (void) strlcpy(od->d_pattern, pattern, sizeof (od->d_pattern));
 973  977          if (smb_contains_wildcards(od->d_pattern))
 974  978                  od->d_flags |= SMB_ODIR_FLAG_WILDCARDS;
 975  979          else
 976  980                  od->d_flags &= ~SMB_ODIR_FLAG_WILDCARDS;
 977  981  
 978  982          /* Internal smb_odir_resume_at */
 979  983          od->d_offset = 0;
 980  984          od->d_bufptr = NULL;
 981  985          od->d_eof = B_FALSE;
  
    | 
      ↓ open down ↓ | 
    506 lines elided | 
    
      ↑ open up ↑ | 
  
 982  986  
 983  987          mutex_exit(&od->d_mutex);
 984  988  }
 985  989  
 986  990  /*
 987  991   * Delete an odir.
 988  992   *
 989  993   * Remove the odir from the tree list before freeing resources
 990  994   * associated with the odir.
 991  995   */
 992      -void
      996 +static void
 993  997  smb_odir_delete(void *arg)
 994  998  {
 995  999          smb_tree_t      *tree;
 996 1000          smb_odir_t      *od = (smb_odir_t *)arg;
 997 1001  
 998 1002          SMB_ODIR_VALID(od);
 999 1003          ASSERT(od->d_refcnt == 0);
1000 1004          ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED);
1001 1005  
1002 1006          tree = od->d_tree;
1003 1007          smb_llist_enter(&tree->t_odir_list, RW_WRITER);
1004 1008          smb_llist_remove(&tree->t_odir_list, od);
1005 1009          if (od->d_odid != 0)
1006 1010                  smb_idpool_free(&tree->t_odid_pool, od->d_odid);
1007 1011          atomic_dec_32(&tree->t_session->s_dir_cnt);
1008 1012          smb_llist_exit(&tree->t_odir_list);
1009 1013  
     1014 +        /*
     1015 +         * This ofile is no longer on t_odir_list, however...
     1016 +         *
     1017 +         * This is called via smb_llist_post, which means it may run
     1018 +         * BEFORE smb_odir_release drops d_mutex (if another thread
     1019 +         * flushes the delete queue before we do).  Synchronize.
     1020 +         */
1010 1021          mutex_enter(&od->d_mutex);
1011 1022          mutex_exit(&od->d_mutex);
1012 1023  
1013 1024          od->d_magic = 0;
1014 1025          smb_node_release(od->d_dnode);
1015 1026          smb_user_release(od->d_user);
1016 1027          mutex_destroy(&od->d_mutex);
1017 1028          kmem_cache_free(smb_cache_odir, od);
1018 1029  }
1019 1030  
1020 1031  /*
1021 1032   * smb_odir_next_odirent
1022 1033   *
1023 1034   * Find the next directory entry in d_buf. If d_bufptr is NULL (buffer
1024 1035   * is empty or we've reached the end of it), read the next set of
1025 1036   * entries from the file system (vop_readdir).
1026 1037   *
1027 1038   * File systems which support VFSFT_EDIRENT_FLAGS will return the
1028 1039   * directory entries as a buffer of edirent_t structure. Others will
1029 1040   * return a buffer of dirent64_t structures.  For simplicity translate
1030 1041   * the data into an smb_odirent_t structure.
1031 1042   * The ed_name/d_name in d_buf is NULL terminated by the file system.
1032 1043   *
1033 1044   * Some file systems can have directories larger than SMB_MAXDIRSIZE.
1034 1045   * If the odirent offset >= SMB_MAXDIRSIZE return ENOENT and set d_eof
1035 1046   * to true to stop subsequent calls to smb_vop_readdir.
1036 1047   *
1037 1048   * Returns:
1038 1049   *      0 - success. odirent is populated with the next directory entry
1039 1050   * ENOENT - no more directory entries
1040 1051   *  errno - error
  
    | 
      ↓ open down ↓ | 
    21 lines elided | 
    
      ↑ open up ↑ | 
  
1041 1052   */
1042 1053  static int
1043 1054  smb_odir_next_odirent(smb_odir_t *od, smb_odirent_t *odirent)
1044 1055  {
1045 1056          int             rc;
1046 1057          int             reclen;
1047 1058          int             eof;
1048 1059          dirent64_t      *dp;
1049 1060          edirent_t       *edp;
1050 1061          char            *np;
1051      -        uint32_t        abe_flag = 0;
     1062 +        uint32_t        rddir_flags = 0;
1052 1063  
1053 1064          ASSERT(MUTEX_HELD(&od->d_mutex));
1054 1065  
1055 1066          bzero(odirent, sizeof (smb_odirent_t));
1056 1067  
     1068 +        if (od->d_flags & SMB_ODIR_FLAG_ABE)
     1069 +                rddir_flags |= SMB_ABE;
     1070 +        if (od->d_flags & SMB_ODIR_FLAG_EDIRENT)
     1071 +                rddir_flags |= SMB_EDIRENT;
     1072 +
1057 1073          if (od->d_bufptr != NULL) {
1058 1074                  if (od->d_flags & SMB_ODIR_FLAG_EDIRENT)
1059 1075                          reclen = od->d_edp->ed_reclen;
1060 1076                  else
1061 1077                          reclen = od->d_dp->d_reclen;
1062 1078  
1063 1079                  if (reclen == 0) {
1064 1080                          od->d_bufptr = NULL;
1065 1081                  } else {
1066 1082                          od->d_bufptr += reclen;
1067 1083                          if (od->d_bufptr >= od->d_buf + od->d_bufsize)
  
    | 
      ↓ open down ↓ | 
    1 lines elided | 
    
      ↑ open up ↑ | 
  
1068 1084                                  od->d_bufptr = NULL;
1069 1085                  }
1070 1086          }
1071 1087  
1072 1088          if (od->d_bufptr == NULL) {
1073 1089                  if (od->d_eof)
1074 1090                          return (ENOENT);
1075 1091  
1076 1092                  od->d_bufsize = sizeof (od->d_buf);
1077 1093  
1078      -                if (od->d_flags & SMB_ODIR_FLAG_ABE)
1079      -                        abe_flag = SMB_ABE;
1080      -
1081 1094                  rc = smb_vop_readdir(od->d_dnode->vp, od->d_offset,
1082      -                    od->d_buf, &od->d_bufsize, &eof, abe_flag, od->d_cred);
     1095 +                    od->d_buf, &od->d_bufsize, &eof, rddir_flags, od->d_cred);
1083 1096  
1084 1097                  if ((rc == 0) && (od->d_bufsize == 0))
1085 1098                          rc = ENOENT;
1086 1099  
1087 1100                  if (rc != 0) {
1088 1101                          od->d_bufptr = NULL;
1089 1102                          od->d_bufsize = 0;
1090 1103                          return (rc);
1091 1104                  }
1092 1105  
1093 1106                  od->d_eof = (eof != 0);
1094 1107                  od->d_bufptr = od->d_buf;
1095 1108          }
1096 1109  
1097 1110          if (od->d_flags & SMB_ODIR_FLAG_EDIRENT)
1098 1111                  od->d_offset = od->d_edp->ed_off;
1099 1112          else
1100 1113                  od->d_offset = od->d_dp->d_off;
1101 1114  
1102 1115          if (od->d_offset >= SMB_MAXDIRSIZE) {
1103 1116                  od->d_bufptr = NULL;
1104 1117                  od->d_bufsize = 0;
1105 1118                  od->d_eof = B_TRUE;
1106 1119                  return (ENOENT);
1107 1120          }
1108 1121  
1109 1122          if (od->d_flags & SMB_ODIR_FLAG_EDIRENT) {
1110 1123                  edp = od->d_edp;
1111 1124                  odirent->od_ino = edp->ed_ino;
1112 1125                  odirent->od_eflags = edp->ed_eflags;
1113 1126                  np = edp->ed_name;
1114 1127          } else {
1115 1128                  dp = od->d_dp;
1116 1129                  odirent->od_ino = dp->d_ino;
1117 1130                  odirent->od_eflags = 0;
1118 1131                  np =  dp->d_name;
1119 1132          }
1120 1133  
1121 1134          if ((od->d_flags & SMB_ODIR_FLAG_CATIA) &&
1122 1135              ((od->d_flags & SMB_ODIR_FLAG_XATTR) == 0)) {
1123 1136                  smb_vop_catia_v4tov5(np, odirent->od_name,
1124 1137                      sizeof (odirent->od_name));
1125 1138          } else {
1126 1139                  (void) strlcpy(odirent->od_name, np,
1127 1140                      sizeof (odirent->od_name));
1128 1141          }
1129 1142  
1130 1143          return (0);
1131 1144  }
1132 1145  
1133 1146  /*
1134 1147   * smb_odir_single_fileinfo
1135 1148   *
1136 1149   * Lookup the file identified by od->d_pattern.
1137 1150   *
1138 1151   * If the looked up file is a link, we attempt to lookup the link target
1139 1152   * to use its attributes in place of those of the files's.
1140 1153   * If we fail to lookup the target of the link we use the original
1141 1154   * file's attributes.
1142 1155   * Check if the attributes match the search attributes.
1143 1156   *
1144 1157   * Returns: 0 - success
1145 1158   *     ENOENT - no match
1146 1159   *      errno - error
1147 1160   */
1148 1161  static int
1149 1162  smb_odir_single_fileinfo(smb_request_t *sr, smb_odir_t *od,
1150 1163      smb_fileinfo_t *fileinfo)
1151 1164  {
1152 1165          int             rc;
1153 1166          smb_node_t      *fnode, *tgt_node;
1154 1167          smb_attr_t      attr;
1155 1168          ino64_t         fid;
1156 1169          char            *name;
1157 1170          boolean_t       case_conflict = B_FALSE;
1158 1171          int             lookup_flags, flags = 0;
1159 1172          vnode_t         *vp;
1160 1173  
1161 1174          ASSERT(sr);
1162 1175          ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
1163 1176          ASSERT(od);
1164 1177          ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1165 1178  
1166 1179          ASSERT(MUTEX_HELD(&od->d_mutex));
1167 1180          bzero(fileinfo, sizeof (smb_fileinfo_t));
1168 1181  
1169 1182          rc = smb_fsop_lookup(sr, od->d_cred, 0, od->d_tree->t_snode,
1170 1183              od->d_dnode, od->d_pattern, &fnode);
1171 1184          if (rc != 0)
1172 1185                  return (rc);
1173 1186  
1174 1187          /*
1175 1188           * If case sensitive, do a case insensitive smb_vop_lookup to
1176 1189           * check for case conflict
1177 1190           */
1178 1191          if (od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) {
1179 1192                  lookup_flags = SMB_IGNORE_CASE;
1180 1193                  if (od->d_flags & SMB_ODIR_FLAG_CATIA)
1181 1194                          lookup_flags |= SMB_CATIA;
1182 1195  
1183 1196                  rc = smb_vop_lookup(od->d_dnode->vp, fnode->od_name, &vp,
1184 1197                      NULL, lookup_flags, &flags, od->d_tree->t_snode->vp,
1185 1198                      NULL, od->d_cred);
1186 1199                  if (rc != 0)
1187 1200                          return (rc);
1188 1201                  VN_RELE(vp);
1189 1202  
1190 1203                  if (flags & ED_CASE_CONFLICT)
1191 1204                          case_conflict = B_TRUE;
1192 1205          }
1193 1206  
1194 1207          bzero(&attr, sizeof (attr));
1195 1208          attr.sa_mask = SMB_AT_ALL;
1196 1209          rc = smb_node_getattr(NULL, fnode, zone_kcred(), NULL, &attr);
1197 1210          if (rc != 0) {
1198 1211                  smb_node_release(fnode);
1199 1212                  return (rc);
1200 1213          }
1201 1214  
1202 1215  
1203 1216          /* follow link to get target node & attr */
1204 1217          if (smb_node_is_symlink(fnode) &&
1205 1218              smb_odir_lookup_link(sr, od, fnode->od_name, &tgt_node)) {
1206 1219                  smb_node_release(fnode);
1207 1220                  fnode = tgt_node;
1208 1221                  attr.sa_mask = SMB_AT_ALL;
1209 1222                  rc = smb_node_getattr(NULL, fnode, zone_kcred(), NULL, &attr);
1210 1223                  if (rc != 0) {
1211 1224                          smb_node_release(fnode);
1212 1225                          return (rc);
1213 1226                  }
1214 1227          }
1215 1228  
1216 1229          /* check search attributes */
1217 1230          if (!smb_sattr_check(attr.sa_dosattr, od->d_sattr)) {
1218 1231                  smb_node_release(fnode);
1219 1232                  return (ENOENT);
1220 1233          }
1221 1234  
1222 1235          name = fnode->od_name;
1223 1236          if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) {
1224 1237                  fid = attr.sa_vattr.va_nodeid;
1225 1238                  if (case_conflict || smb_needs_mangled(name)) {
1226 1239                          smb_mangle(name, fid, fileinfo->fi_shortname,
1227 1240                              SMB_SHORTNAMELEN);
1228 1241                  }
1229 1242                  if (case_conflict)
1230 1243                          name = fileinfo->fi_shortname;
1231 1244          }
1232 1245  
1233 1246          (void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name));
1234 1247  
1235 1248          fileinfo->fi_dosattr = attr.sa_dosattr;
1236 1249          fileinfo->fi_nodeid = attr.sa_vattr.va_nodeid;
1237 1250          fileinfo->fi_size = attr.sa_vattr.va_size;
1238 1251          fileinfo->fi_alloc_size = attr.sa_allocsz;
1239 1252          fileinfo->fi_atime = attr.sa_vattr.va_atime;
1240 1253          fileinfo->fi_mtime = attr.sa_vattr.va_mtime;
1241 1254          fileinfo->fi_ctime = attr.sa_vattr.va_ctime;
1242 1255          if (attr.sa_crtime.tv_sec)
1243 1256                  fileinfo->fi_crtime = attr.sa_crtime;
1244 1257          else
1245 1258                  fileinfo->fi_crtime = attr.sa_vattr.va_mtime;
1246 1259  
1247 1260          smb_node_release(fnode);
1248 1261          return (0);
1249 1262  }
1250 1263  
1251 1264  /*
1252 1265   * smb_odir_wildcard_fileinfo
1253 1266   *
1254 1267   * odirent contains a directory entry, obtained from a vop_readdir.
1255 1268   * If a case conflict is identified the filename is mangled and the
1256 1269   * shortname is used as 'name', in place of odirent->od_name.
1257 1270   *
1258 1271   * If the looked up file is a link, we attempt to lookup the link target
1259 1272   * to use its attributes in place of those of the files's.
1260 1273   * If we fail to lookup the target of the link we use the original
1261 1274   * file's attributes.
1262 1275   * Check if the attributes match the search attributes.
1263 1276   *
1264 1277   * Although some file systems can have directories larger than
1265 1278   * SMB_MAXDIRSIZE smb_odir_next_odirent ensures that no offset larger
1266 1279   * than SMB_MAXDIRSIZE is returned.  It is therefore safe to use the
1267 1280   * offset as the cookie (uint32_t).
1268 1281   *
1269 1282   * Returns: 0 - success
1270 1283   *     ENOENT - no match, proceed to next entry
1271 1284   *      errno - error
1272 1285   */
1273 1286  static int
1274 1287  smb_odir_wildcard_fileinfo(smb_request_t *sr, smb_odir_t *od,
1275 1288      smb_odirent_t *odirent, smb_fileinfo_t *fileinfo)
1276 1289  {
1277 1290          int             rc;
1278 1291          cred_t          *cr;
1279 1292          smb_node_t      *fnode, *tgt_node;
1280 1293          smb_attr_t      attr;
1281 1294          char            *name;
1282 1295          boolean_t       case_conflict;
1283 1296  
1284 1297          ASSERT(sr);
1285 1298          ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
1286 1299          ASSERT(od);
1287 1300          ASSERT(od->d_magic == SMB_ODIR_MAGIC);
1288 1301  
1289 1302          ASSERT(MUTEX_HELD(&od->d_mutex));
1290 1303          bzero(fileinfo, sizeof (smb_fileinfo_t));
1291 1304  
1292 1305          rc = smb_fsop_lookup(sr, od->d_cred, SMB_CASE_SENSITIVE,
1293 1306              od->d_tree->t_snode, od->d_dnode, odirent->od_name, &fnode);
1294 1307          if (rc != 0)
1295 1308                  return (rc);
1296 1309  
1297 1310          /* follow link to get target node & attr */
1298 1311          if (smb_node_is_symlink(fnode) &&
1299 1312              smb_odir_lookup_link(sr, od, odirent->od_name, &tgt_node)) {
1300 1313                  smb_node_release(fnode);
1301 1314                  fnode = tgt_node;
1302 1315          }
1303 1316  
1304 1317          /* skip system files */
1305 1318          if (smb_node_is_system(fnode)) {
1306 1319                  smb_node_release(fnode);
1307 1320                  return (ENOENT);
1308 1321          }
1309 1322  
1310 1323          /*
1311 1324           * Windows directory listings return not only names, but
1312 1325           * also some attributes.  In Unix, you need some access to
1313 1326           * get those attributes.  Which credential should we use to
1314 1327           * get those?  If we're doing Access Based Enumeration (ABE)
1315 1328           * we want this getattr to fail, which will cause the caller
1316 1329           * to skip this entry.  If we're NOT doing ABE, we normally
1317 1330           * want to show all the directory entries (including their
1318 1331           * attributes) so we want this getattr to succeed!
1319 1332           */
1320 1333          if (smb_tree_has_feature(od->d_tree, SMB_TREE_ABE))
1321 1334                  cr = od->d_cred;
1322 1335          else
1323 1336                  cr = zone_kcred();
1324 1337  
1325 1338          bzero(&attr, sizeof (attr));
1326 1339          attr.sa_mask = SMB_AT_ALL;
1327 1340          rc = smb_node_getattr(NULL, fnode, cr, NULL, &attr);
1328 1341          if (rc != 0) {
1329 1342                  smb_node_release(fnode);
1330 1343                  return (rc);
1331 1344          }
1332 1345  
1333 1346          /* check search attributes */
1334 1347          if (!smb_sattr_check(attr.sa_dosattr, od->d_sattr)) {
1335 1348                  smb_node_release(fnode);
1336 1349                  return (ENOENT);
1337 1350          }
1338 1351  
1339 1352          name = odirent->od_name;
1340 1353          if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) {
1341 1354                  case_conflict = ((od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) &&
1342 1355                      (odirent->od_eflags & ED_CASE_CONFLICT));
1343 1356                  if (case_conflict || smb_needs_mangled(name)) {
1344 1357                          smb_mangle(name, odirent->od_ino,
1345 1358                              fileinfo->fi_shortname, SMB_SHORTNAMELEN);
1346 1359                  }
1347 1360                  if (case_conflict)
1348 1361                          name = fileinfo->fi_shortname;
1349 1362          }
1350 1363  
1351 1364          (void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name));
1352 1365  
1353 1366          fileinfo->fi_cookie = (uint32_t)od->d_offset;
1354 1367          fileinfo->fi_dosattr = attr.sa_dosattr;
1355 1368          fileinfo->fi_nodeid = attr.sa_vattr.va_nodeid;
1356 1369          fileinfo->fi_size = attr.sa_vattr.va_size;
1357 1370          fileinfo->fi_alloc_size = attr.sa_allocsz;
1358 1371          fileinfo->fi_atime = attr.sa_vattr.va_atime;
1359 1372          fileinfo->fi_mtime = attr.sa_vattr.va_mtime;
1360 1373          fileinfo->fi_ctime = attr.sa_vattr.va_ctime;
1361 1374          if (attr.sa_crtime.tv_sec)
1362 1375                  fileinfo->fi_crtime = attr.sa_crtime;
1363 1376          else
1364 1377                  fileinfo->fi_crtime = attr.sa_vattr.va_mtime;
1365 1378  
1366 1379          smb_node_release(fnode);
1367 1380          return (0);
1368 1381  }
1369 1382  
1370 1383  /*
1371 1384   * smb_odir_lookup_link
1372 1385   *
1373 1386   * If the file is a symlink we lookup the object to which the
1374 1387   * symlink refers so that we can return its attributes.
1375 1388   * This can cause a problem if a symlink in a sub-directory
1376 1389   * points to a parent directory (some UNIX GUI's create a symlink
1377 1390   * in $HOME/.desktop that points to the user's home directory).
1378 1391   * Some Windows applications (e.g. virus scanning) loop/hang
1379 1392   * trying to follow this recursive path and there is little
1380 1393   * we can do because the path is constructed on the client.
1381 1394   * smb_dirsymlink_enable allows an end-user to disable
1382 1395   * symlinks to directories. Symlinks to other object types
1383 1396   * should be unaffected.
1384 1397   *
1385 1398   * Returns: B_TRUE  - followed link. tgt_node and tgt_attr set
1386 1399   *          B_FALSE - link not followed
1387 1400   */
1388 1401  static boolean_t
1389 1402  smb_odir_lookup_link(smb_request_t *sr, smb_odir_t *od,
1390 1403      char *fname, smb_node_t **tgt_node)
1391 1404  {
1392 1405          int rc;
1393 1406          uint32_t flags = SMB_FOLLOW_LINKS | SMB_CASE_SENSITIVE;
1394 1407  
1395 1408          rc = smb_fsop_lookup(sr, od->d_cred, flags,
1396 1409              od->d_tree->t_snode, od->d_dnode, fname, tgt_node);
1397 1410          if (rc != 0) {
1398 1411                  *tgt_node = NULL;
1399 1412                  return (B_FALSE);
1400 1413          }
1401 1414  
1402 1415          if (smb_node_is_dir(*tgt_node) && (!smb_dirsymlink_enable)) {
1403 1416                  smb_node_release(*tgt_node);
1404 1417                  *tgt_node = NULL;
1405 1418                  return (B_FALSE);
1406 1419          }
1407 1420  
1408 1421          return (B_TRUE);
1409 1422  }
1410 1423  
1411 1424  /*
1412 1425   * smb_odir_match_name
1413 1426   *
1414 1427   * Check if the directory entry name matches the search pattern:
1415 1428   * - Don't match reserved dos filenames.
1416 1429   * - Check if odirent->od_name matches od->d_pattern.
1417 1430   * - If shortnames are supported, generate the shortname from
1418 1431   *   odirent->od_name and check if it matches od->d_pattern.
1419 1432   */
1420 1433  static boolean_t
1421 1434  smb_odir_match_name(smb_odir_t *od, smb_odirent_t *odirent)
1422 1435  {
1423 1436          char    *name = odirent->od_name;
1424 1437          char    shortname[SMB_SHORTNAMELEN];
1425 1438          ino64_t ino = odirent->od_ino;
1426 1439          boolean_t ci = (od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) != 0;
1427 1440  
1428 1441          if (smb_is_reserved_dos_name(name))
1429 1442                  return (B_FALSE);
1430 1443  
1431 1444          if (smb_match(od->d_pattern, name, ci))
1432 1445                  return (B_TRUE);
1433 1446  
1434 1447          if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) {
1435 1448                  smb_mangle(name, ino, shortname, SMB_SHORTNAMELEN);
1436 1449                  if (smb_match(od->d_pattern, shortname, ci))
1437 1450                          return (B_TRUE);
1438 1451          }
1439 1452  
1440 1453          return (B_FALSE);
1441 1454  }
  
    | 
      ↓ open down ↓ | 
    349 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX