1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22*7f667e74Sjose borrego * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23da6c28aaSamw * Use is subject to license terms. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw /* 27da6c28aaSamw * General Structures Layout 28da6c28aaSamw * ------------------------- 29da6c28aaSamw * 30da6c28aaSamw * This is a simplified diagram showing the relationship between most of the 31da6c28aaSamw * main structures. 32da6c28aaSamw * 33da6c28aaSamw * +-------------------+ 34da6c28aaSamw * | SMB_INFO | 35da6c28aaSamw * +-------------------+ 36da6c28aaSamw * | 37da6c28aaSamw * | 38da6c28aaSamw * v 39da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 40da6c28aaSamw * | SESSION |<----->| SESSION |......| SESSION | 41da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 42da6c28aaSamw * | 43da6c28aaSamw * | 44da6c28aaSamw * v 45da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 46da6c28aaSamw * | USER |<----->| USER |......| USER | 47da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 48da6c28aaSamw * | 49da6c28aaSamw * | 50da6c28aaSamw * v 51da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 52da6c28aaSamw * | TREE |<----->| TREE |......| TREE | 53da6c28aaSamw * +-------------------+ +-------------------+ +-------------------+ 54da6c28aaSamw * | | 55da6c28aaSamw * | | 56da6c28aaSamw * | v 57da6c28aaSamw * | +-------+ +-------+ +-------+ 58da6c28aaSamw * | | OFILE |<----->| OFILE |......| OFILE | 59da6c28aaSamw * | +-------+ +-------+ +-------+ 60da6c28aaSamw * | 61da6c28aaSamw * | 62da6c28aaSamw * v 63da6c28aaSamw * +-------+ +------+ +------+ 64da6c28aaSamw * | ODIR |<----->| ODIR |......| ODIR | 65da6c28aaSamw * +-------+ +------+ +------+ 66da6c28aaSamw * 67da6c28aaSamw * 68da6c28aaSamw * Odir State Machine 69da6c28aaSamw * ------------------ 70da6c28aaSamw * 71*7f667e74Sjose borrego * +-------------------------+ 72*7f667e74Sjose borrego * | SMB_ODIR_STATE_OPEN |<----------- open / creation 73da6c28aaSamw * +-------------------------+ 74da6c28aaSamw * | 75*7f667e74Sjose borrego * | close 76da6c28aaSamw * | 77da6c28aaSamw * v 78da6c28aaSamw * +-------------------------+ 79da6c28aaSamw * | SMB_ODIR_STATE_CLOSING | 80da6c28aaSamw * +-------------------------+ 81da6c28aaSamw * | 82*7f667e74Sjose borrego * | last release 83da6c28aaSamw * | 84da6c28aaSamw * v 85*7f667e74Sjose borrego * +-------------------------+ 86*7f667e74Sjose borrego * | SMB_ODIR_STATE_CLOSED |----------> deletion 87da6c28aaSamw * +-------------------------+ 88da6c28aaSamw * 89da6c28aaSamw * 90*7f667e74Sjose borrego * SMB_ODIR_STATE_OPEN 91*7f667e74Sjose borrego * - the odir exists in the list of odirs of its tree. 92*7f667e74Sjose borrego * - references will be given out if the odir is looked up 93*7f667e74Sjose borrego * - if a close is received the odir will transition to 94*7f667e74Sjose borrego * SMB_ODIR_STATE_CLOSING. 95da6c28aaSamw * 96da6c28aaSamw * SMB_ODIR_STATE_CLOSING 97*7f667e74Sjose borrego * - the odir exists in the list of odirs of its tree. 98*7f667e74Sjose borrego * - references will NOT be given out if the odir is looked up. 99*7f667e74Sjose borrego * - when the last reference is released (refcnt == 0) the 100*7f667e74Sjose borrego * odir will transition to SMB_ODIR_STATE_CLOSED. 101da6c28aaSamw * 102da6c28aaSamw * SMB_ODIR_STATE_CLOSED 103*7f667e74Sjose borrego * - the odir exists in the list of odirs of its tree. 104*7f667e74Sjose borrego * - there are no users of the odir (refcnt == 0) 105*7f667e74Sjose borrego * - references will NOT be given out if the odir is looked up. 106*7f667e74Sjose borrego * - the odir is being removed from the tree's list and deleted. 107da6c28aaSamw * 108da6c28aaSamw * Comments 109da6c28aaSamw * -------- 110da6c28aaSamw * The state machine of the odir structures is controlled by 3 elements: 111da6c28aaSamw * - The list of odirs of the tree it belongs to. 112da6c28aaSamw * - The mutex embedded in the structure itself. 113da6c28aaSamw * - The reference count. 114da6c28aaSamw * 115da6c28aaSamw * There's a mutex embedded in the odir structure used to protect its fields 116da6c28aaSamw * and there's a lock embedded in the list of odirs of a tree. To 117da6c28aaSamw * increment or to decrement the reference count the mutex must be entered. 118da6c28aaSamw * To insert the odir into the list of odirs of the tree and to remove 119da6c28aaSamw * the odir from it, the lock must be entered in RW_WRITER mode. 120da6c28aaSamw * 121*7f667e74Sjose borrego * In order to avoid deadlocks, when both (mutex and lock of the odir 122da6c28aaSamw * list) have to be entered, the lock must be entered first. 123da6c28aaSamw * 124da6c28aaSamw * 125*7f667e74Sjose borrego * Odir Interface 126*7f667e74Sjose borrego * --------------- 127*7f667e74Sjose borrego * odid = smb_odir_open(pathname) 128*7f667e74Sjose borrego * Create an odir representing the directory specified in pathname and 129*7f667e74Sjose borrego * add it into the tree's list of odirs. 130*7f667e74Sjose borrego * Return an identifier (odid) uniquely identifying the created odir. 131da6c28aaSamw * 132*7f667e74Sjose borrego * smb_odir_openat(smb_node_t *unode) 133*7f667e74Sjose borrego * Create an odir representing the extended attribute directory 134*7f667e74Sjose borrego * associated with the file (or directory) represented by unode 135*7f667e74Sjose borrego * and add it into the tree's list of odirs. 136*7f667e74Sjose borrego * Return an identifier (odid) uniquely identifying the created odir. 137da6c28aaSamw * 138*7f667e74Sjose borrego * smb_odir_t *odir = smb_tree_lookup_odir(odid) 139*7f667e74Sjose borrego * Find the odir corresponding to the specified odid in the tree's 140*7f667e74Sjose borrego * list of odirs. 141da6c28aaSamw * 142*7f667e74Sjose borrego * smb_odir_read(..., smb_odirent_t *odirent) 143*7f667e74Sjose borrego * Find the next directory entry in the odir and return it in odirent. 144*7f667e74Sjose borrego * 145*7f667e74Sjose borrego * smb_odir_read_fileinfo(..., smb_fileinfo_t *) 146*7f667e74Sjose borrego * Find the next directory entry in the odir. Return the details of 147*7f667e74Sjose borrego * the directory entry in smb_fileinfo_t. (See odir internals below) 148*7f667e74Sjose borrego * 149*7f667e74Sjose borrego * smb_odir_read_stream_info(..., smb_streaminfo_t *) 150*7f667e74Sjose borrego * Find the next named stream entry in the odir. Return the details of 151*7f667e74Sjose borrego * the named stream in smb_streaminfo_t. 152*7f667e74Sjose borrego * 153*7f667e74Sjose borrego * smb_odir_release(smb_odir_t *odir) 154*7f667e74Sjose borrego * Release the hold on the odir, obtained by lookup. 155*7f667e74Sjose borrego * 156*7f667e74Sjose borrego * smb_odir_close(smb_odir_t *odir) 157*7f667e74Sjose borrego * Close the odir and remove it from the tree's list of odirs. 158*7f667e74Sjose borrego * 159*7f667e74Sjose borrego * 160*7f667e74Sjose borrego * Odir Internals 161*7f667e74Sjose borrego * -------------- 162*7f667e74Sjose borrego * The odir object represent an open directory search. Each read operation 163*7f667e74Sjose borrego * provides the caller with a structure containing information pertaining 164*7f667e74Sjose borrego * to the next directory entry that matches the search criteria, namely 165*7f667e74Sjose borrego * the filename or match pattern and, in the case of smb_odir_read_fileinfo(), 166*7f667e74Sjose borrego * the search attributes. 167*7f667e74Sjose borrego * 168*7f667e74Sjose borrego * The odir maintains a buffer (d_buf) of directory entries read from 169*7f667e74Sjose borrego * the filesystem via a vop_readdir. The buffer is populated when a read 170*7f667e74Sjose borrego * request (smb_odir_next_odirent) finds that the buffer is empty or that 171*7f667e74Sjose borrego * the end of the buffer has been reached, and also when a new client request 172*7f667e74Sjose borrego * (find next) begins. 173*7f667e74Sjose borrego * 174*7f667e74Sjose borrego * The data in d_buf (that which is returned from the file system) can 175*7f667e74Sjose borrego * be in one of two formats. If the file system supports extended directory 176*7f667e74Sjose borrego * entries we request that the data be returned as edirent_t structures. If 177*7f667e74Sjose borrego * it does not the data will be returned as dirent64_t structures. For 178*7f667e74Sjose borrego * convenience, when the next directory entry is read from d_buf by 179*7f667e74Sjose borrego * smb_odir_next_odirent it is translated into an smb_odirent_t. 180*7f667e74Sjose borrego * 181*7f667e74Sjose borrego * smb_odir_read_fileinfo 182*7f667e74Sjose borrego * The processing required to obtain the information to populate the caller's 183*7f667e74Sjose borrego * smb_fileinfo_t differs depending upon whether the directory search is for a 184*7f667e74Sjose borrego * single specified filename or for multiple files matching a search pattern. 185*7f667e74Sjose borrego * Thus smb_odir_read_fileinfo uses two static functions: 186*7f667e74Sjose borrego * smb_odir_single_fileinfo - obtains the smb_fileinfo_t info for the single 187*7f667e74Sjose borrego * filename as specified in smb_odir_open request. 188*7f667e74Sjose borrego * smb_odir_wildcard_fileinfo - obtains the smb_fileinfo_t info for the filename 189*7f667e74Sjose borrego * returned from the smb_odir_next_odirent. This is called in a loop until 190*7f667e74Sjose borrego * an entry matching the search criteria is found or no more entries exist. 191*7f667e74Sjose borrego * 192*7f667e74Sjose borrego * If a directory entry is a VLNK, the name returned in the smb_fileinfo_t 193*7f667e74Sjose borrego * is the name of the directory entry but the attributes are the attribites 194*7f667e74Sjose borrego * of the file that is the target of the link. If the link target cannot 195*7f667e74Sjose borrego * be found the attributes returned are the attributes of the link itself. 196*7f667e74Sjose borrego * 197*7f667e74Sjose borrego * smb_odir_read_stream_info 198*7f667e74Sjose borrego * In order for an odir to provide information about stream files it 199*7f667e74Sjose borrego * must be opened with smb_odir_openat(). smb_odir_read_streaminfo() can 200*7f667e74Sjose borrego * then be used to obtain the name and size of named stream files. 201*7f667e74Sjose borrego * 202*7f667e74Sjose borrego * Resuming a Search 203*7f667e74Sjose borrego * ----------------- 204*7f667e74Sjose borrego * A directory search often consists of multiple client requests: an initial 205*7f667e74Sjose borrego * find_first request followed by zero or more find_next requests and a 206*7f667e74Sjose borrego * find_close request. 207*7f667e74Sjose borrego * The find_first request will open and lookup the odir, read its desired 208*7f667e74Sjose borrego * number of entries from the odir, then release the odir and return. 209*7f667e74Sjose borrego * A find_next request will lookup the odir and read its desired number of 210*7f667e74Sjose borrego * entries from the odir, then release the odir and return. 211*7f667e74Sjose borrego * At the end of the search the find_close request will close the odir. 212*7f667e74Sjose borrego * 213*7f667e74Sjose borrego * In order to be able to resume a directory search (find_next) the odir 214*7f667e74Sjose borrego * provides the capability for the caller to save one or more resume points 215*7f667e74Sjose borrego * (cookies) at the end of a request, and to specify which resume point 216*7f667e74Sjose borrego * (cookie) to restart from at the beginning of the next search. 217*7f667e74Sjose borrego * smb_odir_save_cookie(..., cookie) 218*7f667e74Sjose borrego * smb_odir_resume_at(smb_odir_resume_t *resume) 219*7f667e74Sjose borrego * A search can be resumed at a specified resume point (cookie), the resume 220*7f667e74Sjose borrego * point (cookie) stored at a specified index in the d_cookies array, or 221*7f667e74Sjose borrego * a specified filename. The latter (specified filename) is not yet supported. 222*7f667e74Sjose borrego * 223*7f667e74Sjose borrego * See smb_search, smb_find, smb_find_unique, and smb_trans2_find for details 224da6c28aaSamw */ 225*7f667e74Sjose borrego 226da6c28aaSamw #include <smbsrv/smb_incl.h> 227da6c28aaSamw #include <smbsrv/smb_kproto.h> 228da6c28aaSamw #include <smbsrv/smb_fsops.h> 229*7f667e74Sjose borrego #include <sys/extdirent.h> 230da6c28aaSamw 231*7f667e74Sjose borrego /* static functions */ 232*7f667e74Sjose borrego static smb_odir_t *smb_odir_create(smb_request_t *, smb_node_t *, 233*7f667e74Sjose borrego char *, uint16_t); 234*7f667e74Sjose borrego static void smb_odir_delete(smb_odir_t *); 235*7f667e74Sjose borrego static int smb_odir_single_fileinfo(smb_request_t *, smb_odir_t *, 236*7f667e74Sjose borrego smb_fileinfo_t *); 237*7f667e74Sjose borrego static int smb_odir_wildcard_fileinfo(smb_request_t *, smb_odir_t *, 238*7f667e74Sjose borrego smb_odirent_t *, smb_fileinfo_t *); 239*7f667e74Sjose borrego static int smb_odir_next_odirent(smb_odir_t *, smb_odirent_t *); 240*7f667e74Sjose borrego static boolean_t smb_odir_lookup_link(smb_request_t *, smb_odir_t *, char *, 241*7f667e74Sjose borrego smb_node_t **, smb_attr_t *); 242da6c28aaSamw 243da6c28aaSamw 244da6c28aaSamw /* 245da6c28aaSamw * smb_odir_open 246*7f667e74Sjose borrego * 247*7f667e74Sjose borrego * Create an odir representing the directory specified in pathname. 248*7f667e74Sjose borrego * 249*7f667e74Sjose borrego * Returns: 250*7f667e74Sjose borrego * odid - Unique identifier of newly created odir. 251*7f667e74Sjose borrego * 0 - error, error details set in sr. 252da6c28aaSamw */ 253*7f667e74Sjose borrego uint16_t 254*7f667e74Sjose borrego smb_odir_open(smb_request_t *sr, char *path, uint16_t sattr) 255da6c28aaSamw { 256*7f667e74Sjose borrego int rc; 257*7f667e74Sjose borrego smb_tree_t *tree; 258*7f667e74Sjose borrego smb_node_t *dnode; 259*7f667e74Sjose borrego char pattern[MAXNAMELEN]; 260*7f667e74Sjose borrego smb_odir_t *od; 261da6c28aaSamw 262*7f667e74Sjose borrego ASSERT(sr); 263*7f667e74Sjose borrego ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 264*7f667e74Sjose borrego ASSERT(sr->tid_tree); 265*7f667e74Sjose borrego ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC); 266da6c28aaSamw 267*7f667e74Sjose borrego tree = sr->tid_tree; 268*7f667e74Sjose borrego 269*7f667e74Sjose borrego rc = smb_pathname_reduce(sr, sr->user_cr, path, 270*7f667e74Sjose borrego tree->t_snode, tree->t_snode, &dnode, pattern); 271*7f667e74Sjose borrego if (rc != 0) { 272*7f667e74Sjose borrego smbsr_errno(sr, rc); 273*7f667e74Sjose borrego return (0); 274da6c28aaSamw } 275da6c28aaSamw 276*7f667e74Sjose borrego if (dnode->vp->v_type != VDIR) { 277*7f667e74Sjose borrego smbsr_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND, 278*7f667e74Sjose borrego ERRDOS, ERROR_PATH_NOT_FOUND); 279*7f667e74Sjose borrego smb_node_release(dnode); 280*7f667e74Sjose borrego return (0); 281da6c28aaSamw } 282da6c28aaSamw 283*7f667e74Sjose borrego if (smb_fsop_access(sr, sr->user_cr, dnode, FILE_LIST_DIRECTORY) != 0) { 284*7f667e74Sjose borrego smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 285*7f667e74Sjose borrego ERRDOS, ERROR_ACCESS_DENIED); 286*7f667e74Sjose borrego smb_node_release(dnode); 287*7f667e74Sjose borrego return (0); 288*7f667e74Sjose borrego } 289da6c28aaSamw 290*7f667e74Sjose borrego od = smb_odir_create(sr, dnode, pattern, sattr); 291*7f667e74Sjose borrego smb_node_release(dnode); 292*7f667e74Sjose borrego return (od ? od->d_odid : 0); 293*7f667e74Sjose borrego } 294*7f667e74Sjose borrego 295*7f667e74Sjose borrego /* 296*7f667e74Sjose borrego * smb_odir_openat 297*7f667e74Sjose borrego * 298*7f667e74Sjose borrego * Create an odir representing the extended attribute directory 299*7f667e74Sjose borrego * associated with the file (or directory) represented by unode. 300*7f667e74Sjose borrego * 301*7f667e74Sjose borrego * Returns: 302*7f667e74Sjose borrego * odid - Unique identifier of newly created odir. 303*7f667e74Sjose borrego * 0 - error, error details set in sr. 304*7f667e74Sjose borrego */ 305*7f667e74Sjose borrego uint16_t 306*7f667e74Sjose borrego smb_odir_openat(smb_request_t *sr, smb_node_t *unode) 307*7f667e74Sjose borrego { 308*7f667e74Sjose borrego int rc; 309*7f667e74Sjose borrego vnode_t *xattr_dvp; 310*7f667e74Sjose borrego smb_odir_t *od; 311*7f667e74Sjose borrego cred_t *cr; 312*7f667e74Sjose borrego char pattern[SMB_STREAM_PREFIX_LEN + 2]; 313*7f667e74Sjose borrego 314*7f667e74Sjose borrego smb_node_t *xattr_dnode; 315*7f667e74Sjose borrego smb_attr_t tmp_attr; 316*7f667e74Sjose borrego 317*7f667e74Sjose borrego ASSERT(sr); 318*7f667e74Sjose borrego ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 319*7f667e74Sjose borrego ASSERT(unode); 320*7f667e74Sjose borrego ASSERT(unode->n_magic == SMB_NODE_MAGIC); 321*7f667e74Sjose borrego 322*7f667e74Sjose borrego if (SMB_TREE_CONTAINS_NODE(sr, unode) == 0) { 323*7f667e74Sjose borrego smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 324*7f667e74Sjose borrego ERRDOS, ERROR_ACCESS_DENIED); 325*7f667e74Sjose borrego return (0); 326*7f667e74Sjose borrego } 327*7f667e74Sjose borrego cr = sr->user_cr; 328*7f667e74Sjose borrego 329*7f667e74Sjose borrego /* find the xattrdir vnode */ 330*7f667e74Sjose borrego rc = smb_vop_lookup_xattrdir(unode->vp, &xattr_dvp, LOOKUP_XATTR, cr); 331*7f667e74Sjose borrego if (rc != 0) { 332*7f667e74Sjose borrego smbsr_errno(sr, rc); 333*7f667e74Sjose borrego return (0); 334*7f667e74Sjose borrego } 335*7f667e74Sjose borrego 336*7f667e74Sjose borrego /* lookup the xattrdir's smb_node */ 337*7f667e74Sjose borrego xattr_dnode = smb_node_lookup(sr, NULL, cr, xattr_dvp, XATTR_DIR, 338*7f667e74Sjose borrego unode, NULL, &tmp_attr); 339*7f667e74Sjose borrego VN_RELE(xattr_dvp); 340*7f667e74Sjose borrego if (xattr_dnode == NULL) { 341*7f667e74Sjose borrego smbsr_error(sr, NT_STATUS_NO_MEMORY, 342*7f667e74Sjose borrego ERRDOS, ERROR_NOT_ENOUGH_MEMORY); 343*7f667e74Sjose borrego return (0); 344*7f667e74Sjose borrego } 345*7f667e74Sjose borrego 346*7f667e74Sjose borrego (void) snprintf(pattern, sizeof (pattern), "%s*", SMB_STREAM_PREFIX); 347*7f667e74Sjose borrego od = smb_odir_create(sr, xattr_dnode, pattern, SMB_SEARCH_ATTRIBUTES); 348*7f667e74Sjose borrego smb_node_release(xattr_dnode); 349*7f667e74Sjose borrego if (od == NULL) 350*7f667e74Sjose borrego return (0); 351*7f667e74Sjose borrego 352*7f667e74Sjose borrego od->d_xat = B_TRUE; 353*7f667e74Sjose borrego return (od->d_odid); 354*7f667e74Sjose borrego } 355*7f667e74Sjose borrego 356*7f667e74Sjose borrego /* 357*7f667e74Sjose borrego * smb_odir_hold 358*7f667e74Sjose borrego */ 359*7f667e74Sjose borrego boolean_t 360*7f667e74Sjose borrego smb_odir_hold(smb_odir_t *od) 361*7f667e74Sjose borrego { 362*7f667e74Sjose borrego ASSERT(od); 363*7f667e74Sjose borrego ASSERT(od->d_magic == SMB_ODIR_MAGIC); 364*7f667e74Sjose borrego 365*7f667e74Sjose borrego mutex_enter(&od->d_mutex); 366*7f667e74Sjose borrego if (od->d_state != SMB_ODIR_STATE_OPEN) { 367*7f667e74Sjose borrego mutex_exit(&od->d_mutex); 368*7f667e74Sjose borrego return (B_FALSE); 369*7f667e74Sjose borrego } 370*7f667e74Sjose borrego 371*7f667e74Sjose borrego od->d_refcnt++; 372*7f667e74Sjose borrego mutex_exit(&od->d_mutex); 373*7f667e74Sjose borrego return (B_TRUE); 374*7f667e74Sjose borrego } 375*7f667e74Sjose borrego 376*7f667e74Sjose borrego /* 377*7f667e74Sjose borrego * smb_odir_release 378*7f667e74Sjose borrego * 379*7f667e74Sjose borrego * If the odir is in SMB_ODIR_STATE_CLOSING and this release 380*7f667e74Sjose borrego * results in a refcnt of 0, the odir may be removed from 381*7f667e74Sjose borrego * the tree's list of odirs and deleted. The odir's state is 382*7f667e74Sjose borrego * set to SMB_ODIR_STATE_CLOSED prior to exiting the mutex and 383*7f667e74Sjose borrego * deleting it. This ensure that nobody else can ontain a reference 384*7f667e74Sjose borrego * to it while we are deleting it. 385*7f667e74Sjose borrego */ 386*7f667e74Sjose borrego void 387*7f667e74Sjose borrego smb_odir_release(smb_odir_t *od) 388*7f667e74Sjose borrego { 389*7f667e74Sjose borrego ASSERT(od); 390*7f667e74Sjose borrego ASSERT(od->d_magic == SMB_ODIR_MAGIC); 391*7f667e74Sjose borrego 392*7f667e74Sjose borrego mutex_enter(&od->d_mutex); 393*7f667e74Sjose borrego ASSERT(od->d_refcnt); 394*7f667e74Sjose borrego 395*7f667e74Sjose borrego switch (od->d_state) { 396*7f667e74Sjose borrego case SMB_ODIR_STATE_OPEN: 397*7f667e74Sjose borrego od->d_refcnt--; 398*7f667e74Sjose borrego break; 399*7f667e74Sjose borrego case SMB_ODIR_STATE_CLOSING: 400*7f667e74Sjose borrego od->d_refcnt--; 401*7f667e74Sjose borrego if (od->d_refcnt == 0) { 402*7f667e74Sjose borrego od->d_state = SMB_ODIR_STATE_CLOSED; 403*7f667e74Sjose borrego mutex_exit(&od->d_mutex); 404*7f667e74Sjose borrego smb_odir_delete(od); 405*7f667e74Sjose borrego return; 406*7f667e74Sjose borrego } 407*7f667e74Sjose borrego break; 408*7f667e74Sjose borrego case SMB_ODIR_STATE_CLOSED: 409*7f667e74Sjose borrego break; 410*7f667e74Sjose borrego default: 411*7f667e74Sjose borrego ASSERT(0); 412*7f667e74Sjose borrego break; 413*7f667e74Sjose borrego } 414*7f667e74Sjose borrego 415*7f667e74Sjose borrego mutex_exit(&od->d_mutex); 416da6c28aaSamw } 417da6c28aaSamw 418da6c28aaSamw /* 419da6c28aaSamw * smb_odir_close 420da6c28aaSamw */ 421da6c28aaSamw void 422*7f667e74Sjose borrego smb_odir_close(smb_odir_t *od) 423da6c28aaSamw { 424da6c28aaSamw ASSERT(od); 425da6c28aaSamw ASSERT(od->d_refcnt); 426da6c28aaSamw 427da6c28aaSamw mutex_enter(&od->d_mutex); 428da6c28aaSamw if (od->d_state != SMB_ODIR_STATE_OPEN) { 429da6c28aaSamw mutex_exit(&od->d_mutex); 430*7f667e74Sjose borrego return; 431da6c28aaSamw } 432*7f667e74Sjose borrego od->d_state = SMB_ODIR_STATE_CLOSING; 433da6c28aaSamw mutex_exit(&od->d_mutex); 434da6c28aaSamw 435*7f667e74Sjose borrego smb_odir_release(od); 436*7f667e74Sjose borrego } 437da6c28aaSamw 438da6c28aaSamw /* 439*7f667e74Sjose borrego * smb_odir_read 440da6c28aaSamw * 441*7f667e74Sjose borrego * Find the next directory entry matching the search pattern. 442*7f667e74Sjose borrego * No search attribute matching is performed. 443*7f667e74Sjose borrego * 444*7f667e74Sjose borrego * Returns: 445*7f667e74Sjose borrego * 0 - success. 446*7f667e74Sjose borrego * - If a matching entry was found eof will be B_FALSE and 447*7f667e74Sjose borrego * odirent will be populated. 448*7f667e74Sjose borrego * - If there are no matching entries eof will be B_TRUE. 449*7f667e74Sjose borrego * -1 - error, error details set in sr. 450da6c28aaSamw */ 451*7f667e74Sjose borrego int 452*7f667e74Sjose borrego smb_odir_read(smb_request_t *sr, smb_odir_t *od, 453*7f667e74Sjose borrego smb_odirent_t *odirent, boolean_t *eof) 454da6c28aaSamw { 455*7f667e74Sjose borrego int rc; 456da6c28aaSamw 457*7f667e74Sjose borrego ASSERT(sr); 458*7f667e74Sjose borrego ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 459da6c28aaSamw ASSERT(od); 460da6c28aaSamw ASSERT(od->d_magic == SMB_ODIR_MAGIC); 461*7f667e74Sjose borrego ASSERT(odirent); 462da6c28aaSamw 463da6c28aaSamw mutex_enter(&od->d_mutex); 464*7f667e74Sjose borrego 465*7f667e74Sjose borrego ASSERT(od->d_state == SMB_ODIR_STATE_OPEN); 466*7f667e74Sjose borrego if (od->d_state != SMB_ODIR_STATE_OPEN) { 467da6c28aaSamw mutex_exit(&od->d_mutex); 468*7f667e74Sjose borrego return (-1); 469*7f667e74Sjose borrego } 470*7f667e74Sjose borrego 471*7f667e74Sjose borrego for (;;) { 472*7f667e74Sjose borrego if ((rc = smb_odir_next_odirent(od, odirent)) != 0) 473da6c28aaSamw break; 474*7f667e74Sjose borrego if (smb_match_name(odirent->od_ino, odirent->od_name, 475*7f667e74Sjose borrego od->d_pattern, od->d_ignore_case)) 476da6c28aaSamw break; 477da6c28aaSamw } 478*7f667e74Sjose borrego 479*7f667e74Sjose borrego mutex_exit(&od->d_mutex); 480*7f667e74Sjose borrego 481*7f667e74Sjose borrego switch (rc) { 482*7f667e74Sjose borrego case 0: 483*7f667e74Sjose borrego *eof = B_FALSE; 484*7f667e74Sjose borrego return (0); 485*7f667e74Sjose borrego case ENOENT: 486*7f667e74Sjose borrego *eof = B_TRUE; 487*7f667e74Sjose borrego return (0); 488*7f667e74Sjose borrego default: 489*7f667e74Sjose borrego smbsr_errno(sr, rc); 490*7f667e74Sjose borrego return (-1); 491*7f667e74Sjose borrego } 492*7f667e74Sjose borrego } 493*7f667e74Sjose borrego 494*7f667e74Sjose borrego /* 495*7f667e74Sjose borrego * smb_odir_read_fileinfo 496*7f667e74Sjose borrego * 497*7f667e74Sjose borrego * Find the next directory entry matching the search pattern 498*7f667e74Sjose borrego * and attributes: od->d_pattern and od->d_sattr. 499*7f667e74Sjose borrego * 500*7f667e74Sjose borrego * If the search pattern specifies a single filename call 501*7f667e74Sjose borrego * smb_odir_single_fileinfo to get the file attributes and 502*7f667e74Sjose borrego * populate the caller's smb_fileinfo_t. 503*7f667e74Sjose borrego * 504*7f667e74Sjose borrego * If the search pattern contains wildcards call smb_odir_next_odirent 505*7f667e74Sjose borrego * to get the next directory entry then. Repeat until a matching 506*7f667e74Sjose borrego * filename is found. Call smb_odir_wildcard_fileinfo to get the 507*7f667e74Sjose borrego * file attributes and populate the caller's smb_fileinfo_t. 508*7f667e74Sjose borrego * This is repeated until a file matching the search criteria is found. 509*7f667e74Sjose borrego * 510*7f667e74Sjose borrego * Returns: 511*7f667e74Sjose borrego * 0 - success. 512*7f667e74Sjose borrego * - If a matching entry was found eof will be B_FALSE and 513*7f667e74Sjose borrego * fileinfo will be populated. 514*7f667e74Sjose borrego * - If there are no matching entries eof will be B_TRUE. 515*7f667e74Sjose borrego * -1 - error, error details set in sr. 516*7f667e74Sjose borrego */ 517*7f667e74Sjose borrego int 518*7f667e74Sjose borrego smb_odir_read_fileinfo(smb_request_t *sr, smb_odir_t *od, 519*7f667e74Sjose borrego smb_fileinfo_t *fileinfo, boolean_t *eof) 520*7f667e74Sjose borrego { 521*7f667e74Sjose borrego int rc; 522*7f667e74Sjose borrego smb_odirent_t *odirent; 523*7f667e74Sjose borrego 524*7f667e74Sjose borrego ASSERT(sr); 525*7f667e74Sjose borrego ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 526*7f667e74Sjose borrego ASSERT(od); 527*7f667e74Sjose borrego ASSERT(od->d_magic == SMB_ODIR_MAGIC); 528*7f667e74Sjose borrego ASSERT(fileinfo); 529*7f667e74Sjose borrego 530*7f667e74Sjose borrego mutex_enter(&od->d_mutex); 531*7f667e74Sjose borrego 532*7f667e74Sjose borrego ASSERT(od->d_state == SMB_ODIR_STATE_OPEN); 533*7f667e74Sjose borrego if (od->d_state != SMB_ODIR_STATE_OPEN) { 534*7f667e74Sjose borrego mutex_exit(&od->d_mutex); 535*7f667e74Sjose borrego return (-1); 536*7f667e74Sjose borrego } 537*7f667e74Sjose borrego 538*7f667e74Sjose borrego if (!od->d_wildcards) { 539*7f667e74Sjose borrego if (od->d_eof) 540*7f667e74Sjose borrego rc = ENOENT; 541*7f667e74Sjose borrego else 542*7f667e74Sjose borrego rc = smb_odir_single_fileinfo(sr, od, fileinfo); 543*7f667e74Sjose borrego od->d_eof = B_TRUE; 544*7f667e74Sjose borrego } else { 545*7f667e74Sjose borrego odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); 546*7f667e74Sjose borrego for (;;) { 547*7f667e74Sjose borrego bzero(fileinfo, sizeof (smb_fileinfo_t)); 548*7f667e74Sjose borrego if ((rc = smb_odir_next_odirent(od, odirent)) != 0) 549*7f667e74Sjose borrego break; 550*7f667e74Sjose borrego 551*7f667e74Sjose borrego if (!smb_match_name(odirent->od_ino, odirent->od_name, 552*7f667e74Sjose borrego od->d_pattern, od->d_ignore_case)) 553*7f667e74Sjose borrego continue; 554*7f667e74Sjose borrego 555*7f667e74Sjose borrego rc = smb_odir_wildcard_fileinfo(sr, od, odirent, 556*7f667e74Sjose borrego fileinfo); 557*7f667e74Sjose borrego if (rc == 0) 558*7f667e74Sjose borrego break; 559*7f667e74Sjose borrego } 560*7f667e74Sjose borrego kmem_free(odirent, sizeof (smb_odirent_t)); 561*7f667e74Sjose borrego } 562*7f667e74Sjose borrego mutex_exit(&od->d_mutex); 563*7f667e74Sjose borrego 564*7f667e74Sjose borrego switch (rc) { 565*7f667e74Sjose borrego case 0: 566*7f667e74Sjose borrego *eof = B_FALSE; 567*7f667e74Sjose borrego return (0); 568*7f667e74Sjose borrego case ENOENT: 569*7f667e74Sjose borrego *eof = B_TRUE; 570*7f667e74Sjose borrego return (0); 571*7f667e74Sjose borrego default: 572*7f667e74Sjose borrego smbsr_errno(sr, rc); 573*7f667e74Sjose borrego return (-1); 574*7f667e74Sjose borrego } 575*7f667e74Sjose borrego } 576*7f667e74Sjose borrego 577*7f667e74Sjose borrego 578*7f667e74Sjose borrego /* 579*7f667e74Sjose borrego * smb_odir_read_streaminfo 580*7f667e74Sjose borrego * 581*7f667e74Sjose borrego * Find the next directory entry whose name begins with SMB_STREAM_PREFIX, 582*7f667e74Sjose borrego * and thus represents an NTFS named stream. 583*7f667e74Sjose borrego * No search attribute matching is performed. 584*7f667e74Sjose borrego * 585*7f667e74Sjose borrego * Returns: 586*7f667e74Sjose borrego * 0 - success. 587*7f667e74Sjose borrego * - If a matching entry was found eof will be B_FALSE and 588*7f667e74Sjose borrego * sinfo will be populated. 589*7f667e74Sjose borrego * - If there are no matching entries eof will be B_TRUE. 590*7f667e74Sjose borrego * -1 - error, error details set in sr. 591*7f667e74Sjose borrego */ 592*7f667e74Sjose borrego int 593*7f667e74Sjose borrego smb_odir_read_streaminfo(smb_request_t *sr, smb_odir_t *od, 594*7f667e74Sjose borrego smb_streaminfo_t *sinfo, boolean_t *eof) 595*7f667e74Sjose borrego { 596*7f667e74Sjose borrego int rc; 597*7f667e74Sjose borrego smb_odirent_t *odirent; 598*7f667e74Sjose borrego vnode_t *vp; 599*7f667e74Sjose borrego smb_attr_t attr; 600*7f667e74Sjose borrego 601*7f667e74Sjose borrego ASSERT(sr); 602*7f667e74Sjose borrego ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 603*7f667e74Sjose borrego ASSERT(od); 604*7f667e74Sjose borrego ASSERT(od->d_magic == SMB_ODIR_MAGIC); 605*7f667e74Sjose borrego ASSERT(sinfo); 606*7f667e74Sjose borrego 607*7f667e74Sjose borrego mutex_enter(&od->d_mutex); 608*7f667e74Sjose borrego 609*7f667e74Sjose borrego ASSERT(od->d_state == SMB_ODIR_STATE_OPEN); 610*7f667e74Sjose borrego if (od->d_state != SMB_ODIR_STATE_OPEN) { 611*7f667e74Sjose borrego mutex_exit(&od->d_mutex); 612*7f667e74Sjose borrego return (-1); 613*7f667e74Sjose borrego } 614*7f667e74Sjose borrego 615*7f667e74Sjose borrego /* Check that odir represents an xattr directory */ 616*7f667e74Sjose borrego if (!od->d_xat) { 617*7f667e74Sjose borrego *eof = B_TRUE; 618*7f667e74Sjose borrego mutex_exit(&od->d_mutex); 619*7f667e74Sjose borrego return (0); 620*7f667e74Sjose borrego } 621*7f667e74Sjose borrego 622*7f667e74Sjose borrego odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); 623*7f667e74Sjose borrego 624*7f667e74Sjose borrego for (;;) { 625*7f667e74Sjose borrego bzero(sinfo, sizeof (smb_streaminfo_t)); 626*7f667e74Sjose borrego if ((rc = smb_odir_next_odirent(od, odirent)) != 0) 627*7f667e74Sjose borrego break; 628*7f667e74Sjose borrego 629*7f667e74Sjose borrego if (strncmp(odirent->od_name, SMB_STREAM_PREFIX, 630*7f667e74Sjose borrego SMB_STREAM_PREFIX_LEN)) { 631*7f667e74Sjose borrego continue; 632*7f667e74Sjose borrego } 633*7f667e74Sjose borrego 634*7f667e74Sjose borrego /* 635*7f667e74Sjose borrego * since we only care about the size attribute we don't need to 636*7f667e74Sjose borrego * pass the vp of the unnamed stream file to smb_vop_getattr 637*7f667e74Sjose borrego */ 638*7f667e74Sjose borrego rc = smb_vop_lookup(od->d_dnode->vp, odirent->od_name, &vp, 639*7f667e74Sjose borrego NULL, 0, od->d_tree->t_snode->vp, od->d_user->u_cred); 640*7f667e74Sjose borrego if (rc == 0) { 641*7f667e74Sjose borrego rc = smb_vop_getattr(vp, NULL, &attr, 0, 642*7f667e74Sjose borrego od->d_user->u_cred); 643*7f667e74Sjose borrego VN_RELE(vp); 644*7f667e74Sjose borrego } 645*7f667e74Sjose borrego 646*7f667e74Sjose borrego if (rc == 0) { 647*7f667e74Sjose borrego (void) strlcpy(sinfo->si_name, 648*7f667e74Sjose borrego odirent->od_name + SMB_STREAM_PREFIX_LEN, 649*7f667e74Sjose borrego sizeof (sinfo->si_name)); 650*7f667e74Sjose borrego sinfo->si_size = attr.sa_vattr.va_size; 651*7f667e74Sjose borrego break; 652*7f667e74Sjose borrego } 653*7f667e74Sjose borrego } 654*7f667e74Sjose borrego mutex_exit(&od->d_mutex); 655*7f667e74Sjose borrego 656*7f667e74Sjose borrego kmem_free(odirent, sizeof (smb_odirent_t)); 657*7f667e74Sjose borrego 658*7f667e74Sjose borrego switch (rc) { 659*7f667e74Sjose borrego case 0: 660*7f667e74Sjose borrego *eof = B_FALSE; 661*7f667e74Sjose borrego return (0); 662*7f667e74Sjose borrego case ENOENT: 663*7f667e74Sjose borrego *eof = B_TRUE; 664*7f667e74Sjose borrego return (0); 665*7f667e74Sjose borrego default: 666*7f667e74Sjose borrego smbsr_errno(sr, rc); 667*7f667e74Sjose borrego return (-1); 668*7f667e74Sjose borrego } 669*7f667e74Sjose borrego } 670*7f667e74Sjose borrego 671*7f667e74Sjose borrego /* 672*7f667e74Sjose borrego * smb_odir_save_cookie 673*7f667e74Sjose borrego * 674*7f667e74Sjose borrego * Callers can save up to SMB_MAX_SEARCH cookies in the odir 675*7f667e74Sjose borrego * to be used as resume points for a 'find next' request. 676*7f667e74Sjose borrego */ 677*7f667e74Sjose borrego void 678*7f667e74Sjose borrego smb_odir_save_cookie(smb_odir_t *od, int idx, uint32_t cookie) 679*7f667e74Sjose borrego { 680*7f667e74Sjose borrego ASSERT(od); 681*7f667e74Sjose borrego ASSERT(od->d_magic == SMB_ODIR_MAGIC); 682*7f667e74Sjose borrego ASSERT(idx >= 0 && idx < SMB_MAX_SEARCH); 683*7f667e74Sjose borrego 684*7f667e74Sjose borrego mutex_enter(&od->d_mutex); 685*7f667e74Sjose borrego od->d_cookies[idx] = cookie; 686*7f667e74Sjose borrego mutex_exit(&od->d_mutex); 687*7f667e74Sjose borrego } 688*7f667e74Sjose borrego 689*7f667e74Sjose borrego /* 690*7f667e74Sjose borrego * smb_odir_resume_at 691*7f667e74Sjose borrego * 692*7f667e74Sjose borrego * Searching can be resumed from: 693*7f667e74Sjose borrego * - the cookie saved at a specified index (SMBsearch, SMBfind). 694*7f667e74Sjose borrego * - a specified cookie (SMB_trans2_find) 695*7f667e74Sjose borrego * - a specified filename (SMB_trans2_find) - NOT SUPPORTED. 696*7f667e74Sjose borrego * Defaults to continuing from where the last search ended. 697*7f667e74Sjose borrego * 698*7f667e74Sjose borrego * Continuation from where the last search ended (SMB_trans2_find) 699*7f667e74Sjose borrego * is implemented by saving the last cookie at a specific index (0) 700*7f667e74Sjose borrego * smb_odir_resume_at indicates a new request, so reset od->d_bufptr 701*7f667e74Sjose borrego * and d_eof to force a vop_readdir. 702*7f667e74Sjose borrego */ 703*7f667e74Sjose borrego void 704*7f667e74Sjose borrego smb_odir_resume_at(smb_odir_t *od, smb_odir_resume_t *resume) 705*7f667e74Sjose borrego { 706*7f667e74Sjose borrego ASSERT(od); 707*7f667e74Sjose borrego ASSERT(od->d_magic == SMB_ODIR_MAGIC); 708*7f667e74Sjose borrego ASSERT(resume); 709*7f667e74Sjose borrego 710*7f667e74Sjose borrego mutex_enter(&od->d_mutex); 711*7f667e74Sjose borrego 712*7f667e74Sjose borrego switch (resume->or_type) { 713*7f667e74Sjose borrego case SMB_ODIR_RESUME_IDX: 714*7f667e74Sjose borrego ASSERT(resume->or_idx >= 0); 715*7f667e74Sjose borrego ASSERT(resume->or_idx < SMB_MAX_SEARCH); 716*7f667e74Sjose borrego 717*7f667e74Sjose borrego if ((resume->or_idx < 0) || 718*7f667e74Sjose borrego (resume->or_idx >= SMB_MAX_SEARCH)) { 719*7f667e74Sjose borrego resume->or_idx = 0; 720*7f667e74Sjose borrego } 721*7f667e74Sjose borrego od->d_offset = od->d_cookies[resume->or_idx]; 722*7f667e74Sjose borrego break; 723*7f667e74Sjose borrego case SMB_ODIR_RESUME_COOKIE: 724*7f667e74Sjose borrego od->d_offset = resume->or_cookie; 725*7f667e74Sjose borrego break; 726*7f667e74Sjose borrego case SMB_ODIR_RESUME_FNAME: 727*7f667e74Sjose borrego default: 728*7f667e74Sjose borrego od->d_offset = od->d_cookies[0]; 729*7f667e74Sjose borrego break; 730*7f667e74Sjose borrego } 731*7f667e74Sjose borrego 732*7f667e74Sjose borrego /* Force a vop_readdir to refresh d_buf */ 733*7f667e74Sjose borrego od->d_bufptr = NULL; 734*7f667e74Sjose borrego od->d_eof = B_FALSE; 735*7f667e74Sjose borrego 736*7f667e74Sjose borrego mutex_exit(&od->d_mutex); 737*7f667e74Sjose borrego } 738*7f667e74Sjose borrego 739*7f667e74Sjose borrego 740*7f667e74Sjose borrego /* *** static functions *** */ 741*7f667e74Sjose borrego 742*7f667e74Sjose borrego /* 743*7f667e74Sjose borrego * smb_odir_create 744*7f667e74Sjose borrego * Allocate and populate an odir obect and add it to the tree's list. 745*7f667e74Sjose borrego */ 746*7f667e74Sjose borrego static smb_odir_t * 747*7f667e74Sjose borrego smb_odir_create(smb_request_t *sr, smb_node_t *dnode, 748*7f667e74Sjose borrego char *pattern, uint16_t sattr) 749*7f667e74Sjose borrego { 750*7f667e74Sjose borrego smb_odir_t *od; 751*7f667e74Sjose borrego smb_tree_t *tree; 752*7f667e74Sjose borrego uint16_t odid; 753*7f667e74Sjose borrego 754*7f667e74Sjose borrego ASSERT(sr); 755*7f667e74Sjose borrego ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 756*7f667e74Sjose borrego ASSERT(sr->tid_tree); 757*7f667e74Sjose borrego ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC); 758*7f667e74Sjose borrego ASSERT(dnode); 759*7f667e74Sjose borrego ASSERT(dnode->n_magic == SMB_NODE_MAGIC); 760*7f667e74Sjose borrego 761*7f667e74Sjose borrego tree = sr->tid_tree; 762*7f667e74Sjose borrego 763*7f667e74Sjose borrego if (smb_idpool_alloc(&tree->t_odid_pool, &odid)) { 764*7f667e74Sjose borrego smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES, 765*7f667e74Sjose borrego ERRDOS, ERROR_TOO_MANY_OPEN_FILES); 766*7f667e74Sjose borrego return (NULL); 767*7f667e74Sjose borrego } 768*7f667e74Sjose borrego 769*7f667e74Sjose borrego od = kmem_cache_alloc(tree->t_server->si_cache_odir, KM_SLEEP); 770*7f667e74Sjose borrego bzero(od, sizeof (smb_odir_t)); 771*7f667e74Sjose borrego 772*7f667e74Sjose borrego mutex_init(&od->d_mutex, NULL, MUTEX_DEFAULT, NULL); 773*7f667e74Sjose borrego od->d_refcnt = 1; 774*7f667e74Sjose borrego od->d_state = SMB_ODIR_STATE_OPEN; 775*7f667e74Sjose borrego od->d_magic = SMB_ODIR_MAGIC; 776*7f667e74Sjose borrego od->d_opened_by_pid = sr->smb_pid; 777*7f667e74Sjose borrego od->d_session = tree->t_session; 778*7f667e74Sjose borrego od->d_user = tree->t_user; 779*7f667e74Sjose borrego od->d_tree = tree; 780*7f667e74Sjose borrego od->d_dnode = dnode; 781*7f667e74Sjose borrego smb_node_ref(dnode); 782*7f667e74Sjose borrego od->d_odid = odid; 783*7f667e74Sjose borrego od->d_sattr = sattr; 784*7f667e74Sjose borrego (void) strlcpy(od->d_pattern, pattern, sizeof (od->d_pattern)); 785*7f667e74Sjose borrego od->d_wildcards = (smb_convert_unicode_wildcards(od->d_pattern) != 0); 786*7f667e74Sjose borrego od->d_is_edp = vfs_has_feature(dnode->vp->v_vfsp, VFSFT_DIRENTFLAGS); 787*7f667e74Sjose borrego od->d_ignore_case = 788*7f667e74Sjose borrego smb_tree_has_feature(tree, SMB_TREE_CASEINSENSITIVE); 789*7f667e74Sjose borrego od->d_eof = B_FALSE; 790*7f667e74Sjose borrego 791*7f667e74Sjose borrego smb_llist_enter(&tree->t_odir_list, RW_WRITER); 792*7f667e74Sjose borrego smb_llist_insert_tail(&tree->t_odir_list, od); 793*7f667e74Sjose borrego smb_llist_exit(&tree->t_odir_list); 794*7f667e74Sjose borrego 795*7f667e74Sjose borrego atomic_inc_32(&tree->t_session->s_dir_cnt); 796*7f667e74Sjose borrego return (od); 797da6c28aaSamw } 798da6c28aaSamw 799da6c28aaSamw /* 800da6c28aaSamw * smb_odir_delete 801*7f667e74Sjose borrego * 802*7f667e74Sjose borrego * Removal of the odir from the tree's list of odirs must be 803*7f667e74Sjose borrego * done before any resources associated with the odir are 804*7f667e74Sjose borrego * released. 805da6c28aaSamw */ 806da6c28aaSamw static void 807*7f667e74Sjose borrego smb_odir_delete(smb_odir_t *od) 808da6c28aaSamw { 809da6c28aaSamw ASSERT(od); 810da6c28aaSamw ASSERT(od->d_magic == SMB_ODIR_MAGIC); 811da6c28aaSamw ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED); 812da6c28aaSamw ASSERT(od->d_refcnt == 0); 813da6c28aaSamw 814da6c28aaSamw smb_llist_enter(&od->d_tree->t_odir_list, RW_WRITER); 815da6c28aaSamw smb_llist_remove(&od->d_tree->t_odir_list, od); 816da6c28aaSamw smb_llist_exit(&od->d_tree->t_odir_list); 817da6c28aaSamw 818*7f667e74Sjose borrego od->d_magic = 0; 819da6c28aaSamw atomic_dec_32(&od->d_tree->t_session->s_dir_cnt); 820*7f667e74Sjose borrego smb_node_release(od->d_dnode); 821*7f667e74Sjose borrego smb_idpool_free(&od->d_tree->t_odid_pool, od->d_odid); 822da6c28aaSamw mutex_destroy(&od->d_mutex); 823faa1795aSjb150015 kmem_cache_free(od->d_tree->t_server->si_cache_odir, od); 824da6c28aaSamw } 825*7f667e74Sjose borrego 826*7f667e74Sjose borrego /* 827*7f667e74Sjose borrego * smb_odir_next_odirent 828*7f667e74Sjose borrego * 829*7f667e74Sjose borrego * Find the next directory entry in d_buf. If d_bufptr is NULL (buffer 830*7f667e74Sjose borrego * is empty or we've reached the end of it), read the next set of 831*7f667e74Sjose borrego * entries from the file system (vop_readdir). 832*7f667e74Sjose borrego * 833*7f667e74Sjose borrego * File systems which support VFSFT_EDIRENT_FLAGS will return the 834*7f667e74Sjose borrego * directory entries as a buffer of edirent_t structure. Others will 835*7f667e74Sjose borrego * return a buffer of dirent64_t structures. For simplicity translate 836*7f667e74Sjose borrego * the data into an smb_odirent_t structure. 837*7f667e74Sjose borrego * The ed_name/d_name in d_buf is NULL terminated by the file system. 838*7f667e74Sjose borrego * 839*7f667e74Sjose borrego * Some file systems can have directories larger than SMB_MAXDIRSIZE. 840*7f667e74Sjose borrego * If the odirent offset >= SMB_MAXDIRSIZE return ENOENT. 841*7f667e74Sjose borrego * 842*7f667e74Sjose borrego * Returns: 843*7f667e74Sjose borrego * 0 - success. odirent is populated with the next directory entry 844*7f667e74Sjose borrego * ENOENT - no more directory entries 845*7f667e74Sjose borrego * errno - error 846*7f667e74Sjose borrego */ 847*7f667e74Sjose borrego static int 848*7f667e74Sjose borrego smb_odir_next_odirent(smb_odir_t *od, smb_odirent_t *odirent) 849*7f667e74Sjose borrego { 850*7f667e74Sjose borrego int rc; 851*7f667e74Sjose borrego int reclen; 852*7f667e74Sjose borrego int eof; 853*7f667e74Sjose borrego dirent64_t *dp; 854*7f667e74Sjose borrego edirent_t *edp; 855*7f667e74Sjose borrego 856*7f667e74Sjose borrego ASSERT(MUTEX_HELD(&od->d_mutex)); 857*7f667e74Sjose borrego 858*7f667e74Sjose borrego if (od->d_bufptr != NULL) { 859*7f667e74Sjose borrego reclen = od->d_is_edp ? 860*7f667e74Sjose borrego od->d_edp->ed_reclen : od->d_dp->d_reclen; 861*7f667e74Sjose borrego 862*7f667e74Sjose borrego if (reclen == 0) { 863*7f667e74Sjose borrego od->d_bufptr = NULL; 864*7f667e74Sjose borrego } else { 865*7f667e74Sjose borrego od->d_bufptr += reclen; 866*7f667e74Sjose borrego if (od->d_bufptr >= od->d_buf + od->d_bufsize) 867*7f667e74Sjose borrego od->d_bufptr = NULL; 868*7f667e74Sjose borrego } 869*7f667e74Sjose borrego } 870*7f667e74Sjose borrego 871*7f667e74Sjose borrego if (od->d_bufptr == NULL) { 872*7f667e74Sjose borrego if (od->d_eof) 873*7f667e74Sjose borrego return (ENOENT); 874*7f667e74Sjose borrego 875*7f667e74Sjose borrego od->d_bufsize = sizeof (od->d_buf); 876*7f667e74Sjose borrego 877*7f667e74Sjose borrego rc = smb_vop_readdir(od->d_dnode->vp, od->d_offset, 878*7f667e74Sjose borrego od->d_buf, &od->d_bufsize, &eof, od->d_user->u_cred); 879*7f667e74Sjose borrego 880*7f667e74Sjose borrego if ((rc == 0) && (od->d_bufsize == 0)) 881*7f667e74Sjose borrego rc = ENOENT; 882*7f667e74Sjose borrego 883*7f667e74Sjose borrego if (rc != 0) { 884*7f667e74Sjose borrego od->d_bufptr = NULL; 885*7f667e74Sjose borrego od->d_bufsize = 0; 886*7f667e74Sjose borrego return (rc); 887*7f667e74Sjose borrego } 888*7f667e74Sjose borrego 889*7f667e74Sjose borrego od->d_eof = (eof != 0); 890*7f667e74Sjose borrego od->d_bufptr = od->d_buf; 891*7f667e74Sjose borrego } 892*7f667e74Sjose borrego 893*7f667e74Sjose borrego od->d_offset = (od->d_is_edp) ? od->d_edp->ed_off : od->d_dp->d_off; 894*7f667e74Sjose borrego if (od->d_offset >= SMB_MAXDIRSIZE) { 895*7f667e74Sjose borrego od->d_bufptr = NULL; 896*7f667e74Sjose borrego od->d_bufsize = 0; 897*7f667e74Sjose borrego return (ENOENT); 898*7f667e74Sjose borrego } 899*7f667e74Sjose borrego 900*7f667e74Sjose borrego if (od->d_is_edp) { 901*7f667e74Sjose borrego edp = od->d_edp; 902*7f667e74Sjose borrego odirent->od_ino = edp->ed_ino; 903*7f667e74Sjose borrego odirent->od_eflags = edp->ed_eflags; 904*7f667e74Sjose borrego (void) strlcpy(odirent->od_name, edp->ed_name, 905*7f667e74Sjose borrego sizeof (odirent->od_name)); 906*7f667e74Sjose borrego } else { 907*7f667e74Sjose borrego dp = od->d_dp; 908*7f667e74Sjose borrego odirent->od_ino = dp->d_ino; 909*7f667e74Sjose borrego odirent->od_eflags = 0; 910*7f667e74Sjose borrego (void) strlcpy(odirent->od_name, dp->d_name, 911*7f667e74Sjose borrego sizeof (odirent->od_name)); 912*7f667e74Sjose borrego } 913*7f667e74Sjose borrego 914*7f667e74Sjose borrego return (0); 915*7f667e74Sjose borrego } 916*7f667e74Sjose borrego 917*7f667e74Sjose borrego /* 918*7f667e74Sjose borrego * smb_odir_single_fileinfo 919*7f667e74Sjose borrego * 920*7f667e74Sjose borrego * Lookup the file identified by od->d_pattern. 921*7f667e74Sjose borrego * 922*7f667e74Sjose borrego * If the looked up file is a link, we attempt to lookup the link target 923*7f667e74Sjose borrego * to use its attributes in place of those of the files's. 924*7f667e74Sjose borrego * If we fail to lookup the target of the link we use the original 925*7f667e74Sjose borrego * file's attributes. 926*7f667e74Sjose borrego * Check if the attributes match the search attributes. 927*7f667e74Sjose borrego * 928*7f667e74Sjose borrego * Returns: 0 - success 929*7f667e74Sjose borrego * ENOENT - no match 930*7f667e74Sjose borrego * errno - error 931*7f667e74Sjose borrego */ 932*7f667e74Sjose borrego static int 933*7f667e74Sjose borrego smb_odir_single_fileinfo(smb_request_t *sr, smb_odir_t *od, 934*7f667e74Sjose borrego smb_fileinfo_t *fileinfo) 935*7f667e74Sjose borrego { 936*7f667e74Sjose borrego int rc; 937*7f667e74Sjose borrego smb_node_t *fnode, *tgt_node; 938*7f667e74Sjose borrego smb_attr_t attr, tgt_attr, *fattr; 939*7f667e74Sjose borrego ino64_t ino; 940*7f667e74Sjose borrego char *name; 941*7f667e74Sjose borrego uint32_t dosattr; 942*7f667e74Sjose borrego 943*7f667e74Sjose borrego ASSERT(sr); 944*7f667e74Sjose borrego ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 945*7f667e74Sjose borrego ASSERT(od); 946*7f667e74Sjose borrego ASSERT(od->d_magic == SMB_ODIR_MAGIC); 947*7f667e74Sjose borrego 948*7f667e74Sjose borrego ASSERT(MUTEX_HELD(&od->d_mutex)); 949*7f667e74Sjose borrego bzero(fileinfo, sizeof (smb_fileinfo_t)); 950*7f667e74Sjose borrego 951*7f667e74Sjose borrego rc = smb_fsop_lookup(sr, od->d_user->u_cred, 0, od->d_tree->t_snode, 952*7f667e74Sjose borrego od->d_dnode, od->d_pattern, &fnode, &attr, 0, 0); 953*7f667e74Sjose borrego if (rc != 0) 954*7f667e74Sjose borrego return (rc); 955*7f667e74Sjose borrego 956*7f667e74Sjose borrego name = fnode->od_name; 957*7f667e74Sjose borrego 958*7f667e74Sjose borrego (void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name)); 959*7f667e74Sjose borrego ino = attr.sa_vattr.va_nodeid; 960*7f667e74Sjose borrego (void) smb_mangle_name(ino, name, 961*7f667e74Sjose borrego fileinfo->fi_shortname, fileinfo->fi_name83, 0); 962*7f667e74Sjose borrego 963*7f667e74Sjose borrego /* follow link to get target node & attr */ 964*7f667e74Sjose borrego if ((fnode->vp->v_type == VLNK) && 965*7f667e74Sjose borrego (smb_odir_lookup_link(sr, od, name, &tgt_node, &tgt_attr))) { 966*7f667e74Sjose borrego smb_node_release(fnode); 967*7f667e74Sjose borrego fnode = tgt_node; 968*7f667e74Sjose borrego fattr = &tgt_attr; 969*7f667e74Sjose borrego } else { 970*7f667e74Sjose borrego fattr = &attr; 971*7f667e74Sjose borrego } 972*7f667e74Sjose borrego 973*7f667e74Sjose borrego /* check search attributes */ 974*7f667e74Sjose borrego dosattr = smb_node_get_dosattr(fnode); 975*7f667e74Sjose borrego if (!smb_sattr_check(dosattr, od->d_sattr, fileinfo->fi_name)) { 976*7f667e74Sjose borrego smb_node_release(fnode); 977*7f667e74Sjose borrego return (ENOENT); 978*7f667e74Sjose borrego } 979*7f667e74Sjose borrego 980*7f667e74Sjose borrego fileinfo->fi_dosattr = dosattr; 981*7f667e74Sjose borrego fileinfo->fi_nodeid = fattr->sa_vattr.va_nodeid; 982*7f667e74Sjose borrego fileinfo->fi_size = smb_node_get_size(fnode, fattr); 983*7f667e74Sjose borrego fileinfo->fi_alloc_size = fattr->sa_vattr.va_nblocks * DEV_BSIZE; 984*7f667e74Sjose borrego fileinfo->fi_atime = fattr->sa_vattr.va_atime; 985*7f667e74Sjose borrego fileinfo->fi_mtime = fattr->sa_vattr.va_mtime; 986*7f667e74Sjose borrego fileinfo->fi_ctime = fattr->sa_vattr.va_ctime; 987*7f667e74Sjose borrego if (fattr->sa_crtime.tv_sec) 988*7f667e74Sjose borrego fileinfo->fi_crtime = fattr->sa_crtime; 989*7f667e74Sjose borrego else 990*7f667e74Sjose borrego fileinfo->fi_crtime = fattr->sa_vattr.va_mtime; 991*7f667e74Sjose borrego 992*7f667e74Sjose borrego smb_node_release(fnode); 993*7f667e74Sjose borrego return (0); 994*7f667e74Sjose borrego } 995*7f667e74Sjose borrego 996*7f667e74Sjose borrego /* 997*7f667e74Sjose borrego * smb_odir_wildcard_fileinfo 998*7f667e74Sjose borrego * 999*7f667e74Sjose borrego * odirent contains a directory entry, obtained from a vop_readdir. 1000*7f667e74Sjose borrego * If a case conflict is identified the filename is mangled and the 1001*7f667e74Sjose borrego * shortname is used as 'name', in place of odirent->od_name. This 1002*7f667e74Sjose borrego * name will be used in the smb_fsop_lookup because smb_fsop_lookup 1003*7f667e74Sjose borrego * performs a case insensitive lookup if the tree is case insesitive, 1004*7f667e74Sjose borrego * so the mangled name is required in the case conflict scenario to 1005*7f667e74Sjose borrego * ensure the correct match. 1006*7f667e74Sjose borrego * 1007*7f667e74Sjose borrego * If the looked up file is a link, we attempt to lookup the link target 1008*7f667e74Sjose borrego * to use its attributes in place of those of the files's. 1009*7f667e74Sjose borrego * If we fail to lookup the target of the link we use the original 1010*7f667e74Sjose borrego * file's attributes. 1011*7f667e74Sjose borrego * Check if the attributes match the search attributes. 1012*7f667e74Sjose borrego * 1013*7f667e74Sjose borrego * Although some file systems can have directories larger than 1014*7f667e74Sjose borrego * SMB_MAXDIRSIZE smb_odir_next_odirent ensures that no offset larger 1015*7f667e74Sjose borrego * than SMB_MAXDIRSIZE is returned. It is therefore safe to use the 1016*7f667e74Sjose borrego * offset as the cookie (uint32_t). 1017*7f667e74Sjose borrego * 1018*7f667e74Sjose borrego * Returns: 0 - success 1019*7f667e74Sjose borrego * ENOENT - no match, proceed to next entry 1020*7f667e74Sjose borrego * errno - error 1021*7f667e74Sjose borrego */ 1022*7f667e74Sjose borrego static int 1023*7f667e74Sjose borrego smb_odir_wildcard_fileinfo(smb_request_t *sr, smb_odir_t *od, 1024*7f667e74Sjose borrego smb_odirent_t *odirent, smb_fileinfo_t *fileinfo) 1025*7f667e74Sjose borrego { 1026*7f667e74Sjose borrego int rc; 1027*7f667e74Sjose borrego smb_node_t *fnode, *tgt_node; 1028*7f667e74Sjose borrego smb_attr_t attr, tgt_attr, *fattr; 1029*7f667e74Sjose borrego char *name; 1030*7f667e74Sjose borrego uint32_t dosattr; 1031*7f667e74Sjose borrego boolean_t case_conflict; 1032*7f667e74Sjose borrego 1033*7f667e74Sjose borrego ASSERT(sr); 1034*7f667e74Sjose borrego ASSERT(sr->sr_magic == SMB_REQ_MAGIC); 1035*7f667e74Sjose borrego ASSERT(od); 1036*7f667e74Sjose borrego ASSERT(od->d_magic == SMB_ODIR_MAGIC); 1037*7f667e74Sjose borrego 1038*7f667e74Sjose borrego ASSERT(MUTEX_HELD(&od->d_mutex)); 1039*7f667e74Sjose borrego bzero(fileinfo, sizeof (smb_fileinfo_t)); 1040*7f667e74Sjose borrego 1041*7f667e74Sjose borrego case_conflict = ((od->d_ignore_case) && 1042*7f667e74Sjose borrego (odirent->od_eflags & ED_CASE_CONFLICT)); 1043*7f667e74Sjose borrego (void) smb_mangle_name(odirent->od_ino, odirent->od_name, 1044*7f667e74Sjose borrego fileinfo->fi_shortname, fileinfo->fi_name83, case_conflict); 1045*7f667e74Sjose borrego name = (case_conflict) ? fileinfo->fi_shortname : odirent->od_name; 1046*7f667e74Sjose borrego (void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name)); 1047*7f667e74Sjose borrego 1048*7f667e74Sjose borrego rc = smb_fsop_lookup(sr, od->d_user->u_cred, 0, od->d_tree->t_snode, 1049*7f667e74Sjose borrego od->d_dnode, name, &fnode, &attr, 0, 0); 1050*7f667e74Sjose borrego if (rc != 0) 1051*7f667e74Sjose borrego return (rc); 1052*7f667e74Sjose borrego 1053*7f667e74Sjose borrego /* follow link to get target node & attr */ 1054*7f667e74Sjose borrego if ((fnode->vp->v_type == VLNK) && 1055*7f667e74Sjose borrego (smb_odir_lookup_link(sr, od, name, &tgt_node, &tgt_attr))) { 1056*7f667e74Sjose borrego smb_node_release(fnode); 1057*7f667e74Sjose borrego fnode = tgt_node; 1058*7f667e74Sjose borrego fattr = &tgt_attr; 1059*7f667e74Sjose borrego } else { 1060*7f667e74Sjose borrego fattr = &attr; 1061*7f667e74Sjose borrego } 1062*7f667e74Sjose borrego 1063*7f667e74Sjose borrego /* check search attributes */ 1064*7f667e74Sjose borrego dosattr = smb_node_get_dosattr(fnode); 1065*7f667e74Sjose borrego if (!smb_sattr_check(dosattr, od->d_sattr, fileinfo->fi_name)) { 1066*7f667e74Sjose borrego smb_node_release(fnode); 1067*7f667e74Sjose borrego return (ENOENT); 1068*7f667e74Sjose borrego } 1069*7f667e74Sjose borrego 1070*7f667e74Sjose borrego fileinfo->fi_cookie = (uint32_t)od->d_offset; 1071*7f667e74Sjose borrego fileinfo->fi_dosattr = dosattr; 1072*7f667e74Sjose borrego fileinfo->fi_nodeid = fattr->sa_vattr.va_nodeid; 1073*7f667e74Sjose borrego fileinfo->fi_size = smb_node_get_size(fnode, fattr); 1074*7f667e74Sjose borrego fileinfo->fi_alloc_size = fattr->sa_vattr.va_nblocks * DEV_BSIZE; 1075*7f667e74Sjose borrego fileinfo->fi_atime = fattr->sa_vattr.va_atime; 1076*7f667e74Sjose borrego fileinfo->fi_mtime = fattr->sa_vattr.va_mtime; 1077*7f667e74Sjose borrego fileinfo->fi_ctime = fattr->sa_vattr.va_ctime; 1078*7f667e74Sjose borrego if (fattr->sa_crtime.tv_sec) 1079*7f667e74Sjose borrego fileinfo->fi_crtime = fattr->sa_crtime; 1080*7f667e74Sjose borrego else 1081*7f667e74Sjose borrego fileinfo->fi_crtime = fattr->sa_vattr.va_mtime; 1082*7f667e74Sjose borrego 1083*7f667e74Sjose borrego smb_node_release(fnode); 1084*7f667e74Sjose borrego return (0); 1085*7f667e74Sjose borrego } 1086*7f667e74Sjose borrego 1087*7f667e74Sjose borrego /* 1088*7f667e74Sjose borrego * smb_odir_lookup_link 1089*7f667e74Sjose borrego * 1090*7f667e74Sjose borrego * If the file is a symlink we lookup the object to which the 1091*7f667e74Sjose borrego * symlink refers so that we can return its attributes. 1092*7f667e74Sjose borrego * This can cause a problem if a symlink in a sub-directory 1093*7f667e74Sjose borrego * points to a parent directory (some UNIX GUI's create a symlink 1094*7f667e74Sjose borrego * in $HOME/.desktop that points to the user's home directory). 1095*7f667e74Sjose borrego * Some Windows applications (e.g. virus scanning) loop/hang 1096*7f667e74Sjose borrego * trying to follow this recursive path and there is little 1097*7f667e74Sjose borrego * we can do because the path is constructed on the client. 1098*7f667e74Sjose borrego * smb_dirsymlink_enable allows an end-user to disable 1099*7f667e74Sjose borrego * symlinks to directories. Symlinks to other object types 1100*7f667e74Sjose borrego * should be unaffected. 1101*7f667e74Sjose borrego * 1102*7f667e74Sjose borrego * Returns: B_TRUE - followed link. tgt_node and tgt_attr set 1103*7f667e74Sjose borrego * B_FALSE - link not followed 1104*7f667e74Sjose borrego */ 1105*7f667e74Sjose borrego static boolean_t 1106*7f667e74Sjose borrego smb_odir_lookup_link(smb_request_t *sr, smb_odir_t *od, 1107*7f667e74Sjose borrego char *fname, smb_node_t **tgt_node, smb_attr_t *tgt_attr) 1108*7f667e74Sjose borrego { 1109*7f667e74Sjose borrego int rc; 1110*7f667e74Sjose borrego 1111*7f667e74Sjose borrego rc = smb_fsop_lookup(sr, od->d_user->u_cred, SMB_FOLLOW_LINKS, 1112*7f667e74Sjose borrego od->d_tree->t_snode, od->d_dnode, fname, tgt_node, tgt_attr, 0, 0); 1113*7f667e74Sjose borrego if (rc != 0) { 1114*7f667e74Sjose borrego *tgt_node = NULL; 1115*7f667e74Sjose borrego return (B_FALSE); 1116*7f667e74Sjose borrego } 1117*7f667e74Sjose borrego 1118*7f667e74Sjose borrego if ((tgt_attr->sa_vattr.va_type == VDIR) && (!smb_dirsymlink_enable)) { 1119*7f667e74Sjose borrego smb_node_release(*tgt_node); 1120*7f667e74Sjose borrego *tgt_node = NULL; 1121*7f667e74Sjose borrego return (B_FALSE); 1122*7f667e74Sjose borrego } 1123*7f667e74Sjose borrego 1124*7f667e74Sjose borrego return (B_TRUE); 1125*7f667e74Sjose borrego } 1126