15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 225772Sas200622 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #pragma ident "%Z%%M% %I% %E% SMI" 275331Samw 285331Samw /* 295331Samw * SMB Node State Machine 305331Samw * ---------------------- 315331Samw * 325331Samw * +----------------------------+ T0 335331Samw * | SMB_NODE_STATE_AVAILABLE |<----------- Creation/Allocation 345331Samw * +----------------------------+ 355331Samw * | 365331Samw * | T1 375331Samw * | 385331Samw * v 395331Samw * +-----------------------------+ T2 405331Samw * | SMB_NODE_STATE_DESTROYING |----------> Deletion/Free 415331Samw * +-----------------------------+ 425331Samw * 435331Samw * Transition T0 445331Samw * 455331Samw * This transition occurs in smb_node_lookup(). If the node looked for is 465331Samw * not found in the has table a new node is created. The reference count is 475331Samw * initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE. 485331Samw * 495331Samw * Transition T1 505331Samw * 515331Samw * This transition occurs in smb_node_release(). If the reference count 525331Samw * drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more 535331Samw * reference count will be given out for that node. 545331Samw * 555331Samw * Transition T2 565331Samw * 575331Samw * This transition occurs in smb_node_release(). The structure is deleted. 585331Samw * 595331Samw * Comments 605331Samw * -------- 615331Samw * 625331Samw * The reason the smb node has 2 states is the following synchronization 635331Samw * rule: 645331Samw * 655331Samw * There's a mutex embedded in the node used to protect its fields and 665331Samw * there's a lock embedded in the bucket of the hash table the node belongs 675331Samw * to. To increment or to decrement the reference count the mutex must be 685331Samw * entered. To insert the node into the bucket and to remove it from the 695331Samw * bucket the lock must be entered in RW_WRITER mode. When both (mutex and 705331Samw * lock) have to be entered, the lock has always to be entered first then 715331Samw * the mutex. This prevents a deadlock between smb_node_lookup() and 725331Samw * smb_node_release() from occurring. However, in smb_node_release() when the 735331Samw * reference count drops to zero and triggers the deletion of the node, the 745331Samw * mutex has to be released before entering the lock of the bucket (to 755331Samw * remove the node). This creates a window during which the node that is 765331Samw * about to be freed could be given out by smb_node_lookup(). To close that 775331Samw * window the node is moved to the state SMB_NODE_STATE_DESTROYING before 785331Samw * releasing the mutex. That way, even if smb_node_lookup() finds it, the 795331Samw * state will indicate that the node should be treated as non existent (of 805331Samw * course the state of the node should be tested/updated under the 815331Samw * protection of the mutex). 825331Samw */ 835331Samw #include <smbsrv/smb_incl.h> 845331Samw #include <smbsrv/smb_fsops.h> 855331Samw #include <sys/pathname.h> 865331Samw #include <sys/sdt.h> 875772Sas200622 #include <sys/nbmlock.h> 885331Samw 895331Samw uint32_t smb_is_executable(char *path); 905331Samw static void smb_node_delete_on_close(smb_node_t *node); 915331Samw 925331Samw #define VALIDATE_DIR_NODE(_dir_, _node_) \ 935331Samw ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \ 945331Samw ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \ 955331Samw ASSERT((_dir_)->dir_snode != (_node_)); 965331Samw 97*6139Sjb150015 static boolean_t smb_node_initialized = B_FALSE; 98*6139Sjb150015 static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1]; 99*6139Sjb150015 100*6139Sjb150015 /* 101*6139Sjb150015 * smb_node_init 102*6139Sjb150015 * 103*6139Sjb150015 * Initialization of the SMB node layer. 104*6139Sjb150015 * 105*6139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 106*6139Sjb150015 * thread makes the call. 107*6139Sjb150015 */ 108*6139Sjb150015 int 109*6139Sjb150015 smb_node_init(void) 110*6139Sjb150015 { 111*6139Sjb150015 int i; 112*6139Sjb150015 113*6139Sjb150015 if (smb_node_initialized) 114*6139Sjb150015 return (0); 115*6139Sjb150015 116*6139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 117*6139Sjb150015 smb_llist_constructor(&smb_node_hash_table[i], 118*6139Sjb150015 sizeof (smb_node_t), offsetof(smb_node_t, n_lnd)); 119*6139Sjb150015 } 120*6139Sjb150015 smb_node_initialized = B_TRUE; 121*6139Sjb150015 return (0); 122*6139Sjb150015 } 123*6139Sjb150015 124*6139Sjb150015 /* 125*6139Sjb150015 * smb_node_fini 126*6139Sjb150015 * 127*6139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 128*6139Sjb150015 * thread makes the call. 129*6139Sjb150015 */ 130*6139Sjb150015 void 131*6139Sjb150015 smb_node_fini(void) 132*6139Sjb150015 { 133*6139Sjb150015 int i; 134*6139Sjb150015 135*6139Sjb150015 if (!smb_node_initialized) 136*6139Sjb150015 return; 137*6139Sjb150015 138*6139Sjb150015 #ifdef DEBUG 139*6139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 140*6139Sjb150015 smb_node_t *node; 141*6139Sjb150015 142*6139Sjb150015 /* 143*6139Sjb150015 * The following sequence is just intended for sanity check. 144*6139Sjb150015 * This will have to be modified when the code goes into 145*6139Sjb150015 * production. 146*6139Sjb150015 * 147*6139Sjb150015 * The SMB node hash table should be emtpy at this point. If the 148*6139Sjb150015 * hash table is not empty a panic will be triggered. 149*6139Sjb150015 * 150*6139Sjb150015 * The reason why SMB nodes are still remaining in the hash 151*6139Sjb150015 * table is problably due to a mismatch between calls to 152*6139Sjb150015 * smb_node_lookup() and smb_node_release(). You must track that 153*6139Sjb150015 * down. 154*6139Sjb150015 */ 155*6139Sjb150015 node = smb_llist_head(&smb_node_hash_table[i]); 156*6139Sjb150015 ASSERT(node == NULL); 157*6139Sjb150015 } 158*6139Sjb150015 #endif 159*6139Sjb150015 160*6139Sjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 161*6139Sjb150015 smb_llist_destructor(&smb_node_hash_table[i]); 162*6139Sjb150015 } 163*6139Sjb150015 smb_node_initialized = B_FALSE; 164*6139Sjb150015 } 165*6139Sjb150015 1665331Samw /* 1675331Samw * smb_node_lookup() 1685331Samw * 1695331Samw * NOTE: This routine should only be called by the file system interface layer, 1705331Samw * and not by SMB. 1715331Samw * 1725331Samw * smb_node_lookup() is called upon successful lookup, mkdir, and create 1735331Samw * (for both non-streams and streams). In each of these cases, a held vnode is 1745331Samw * passed into this routine. If an smb_node already exists for this vnode, 1755331Samw * the vp is released. Otherwise, a new smb_node will be created and the 1765331Samw * reference will be held until the refcnt on the node goes to 0 (see 1775331Samw * smb_node_release()). 1785331Samw * 1795331Samw * A reference is taken on the smb_node whether found in the hash table 1805331Samw * or newly created. 1815331Samw * 1825331Samw * If an smb_node needs to be created, a reference is also taken on the 1835331Samw * dir_snode (if passed in). 1845331Samw * 1855331Samw * See smb_node_release() for details on the release of these references. 1865331Samw */ 1875331Samw 1885331Samw /*ARGSUSED*/ 1895331Samw smb_node_t * 1905331Samw smb_node_lookup( 1915331Samw struct smb_request *sr, 1925331Samw struct open_param *op, 1935331Samw cred_t *cred, 1945331Samw vnode_t *vp, 1955331Samw char *od_name, 1965331Samw smb_node_t *dir_snode, 1975331Samw smb_node_t *unnamed_node, 1985331Samw smb_attr_t *attr) 1995331Samw { 2005331Samw smb_llist_t *node_hdr; 2015331Samw smb_node_t *node; 2025331Samw uint32_t hashkey = 0; 2035331Samw fs_desc_t fsd; 2045331Samw int error; 2055331Samw krw_t lock_mode; 2065331Samw vnode_t *unnamed_vp = NULL; 2075331Samw 2085331Samw /* 2095331Samw * smb_vop_getattr() is called here instead of smb_fsop_getattr(), 2105331Samw * because the node may not yet exist. We also do not want to call 2115331Samw * it with the list lock held. 2125331Samw */ 2135331Samw 2145331Samw if (unnamed_node) 2155331Samw unnamed_vp = unnamed_node->vp; 2165331Samw 2175331Samw /* 2185331Samw * This getattr is performed on behalf of the server 2195331Samw * that's why kcred is used not the user's cred 2205331Samw */ 2215331Samw attr->sa_mask = SMB_AT_ALL; 2225772Sas200622 error = smb_vop_getattr(vp, unnamed_vp, attr, 0, kcred); 2235331Samw if (error) 2245331Samw return (NULL); 2255331Samw 2265331Samw if (sr) { 2275331Samw if (sr->tid_tree) { 2285331Samw /* 2295331Samw * The fsd for a file is that of the tree, even 2305331Samw * if the file resides in a different mountpoint 2315331Samw * under the share. 2325331Samw */ 2335331Samw fsd = sr->tid_tree->t_fsd; 2345331Samw } else { 2355331Samw /* 2365331Samw * This should be getting executed only for the 2375331Samw * tree's root smb_node. 2385331Samw */ 2395331Samw fsd = vp->v_vfsp->vfs_fsid; 2405331Samw } 2415331Samw } else { 2425331Samw fsd = vp->v_vfsp->vfs_fsid; 2435331Samw } 2445331Samw 2455331Samw hashkey = fsd.val[0] + attr->sa_vattr.va_nodeid; 2465331Samw hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 247*6139Sjb150015 node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]; 2485331Samw lock_mode = RW_READER; 2495331Samw 2505331Samw smb_llist_enter(node_hdr, lock_mode); 2515331Samw for (;;) { 2525331Samw node = list_head(&node_hdr->ll_list); 2535331Samw while (node) { 2545331Samw ASSERT(node->n_magic == SMB_NODE_MAGIC); 2555331Samw ASSERT(node->n_hash_bucket == node_hdr); 2565331Samw if ((node->n_hashkey == hashkey) && (node->vp == vp)) { 2575331Samw smb_rwx_xenter(&node->n_lock); 2585331Samw DTRACE_PROBE1(smb_node_lookup_hit, 2595331Samw smb_node_t *, node); 2605331Samw switch (node->n_state) { 2615331Samw case SMB_NODE_STATE_AVAILABLE: 2625331Samw /* The node was found. */ 2635331Samw node->n_refcnt++; 2645331Samw if ((node->dir_snode == NULL) && 2655331Samw (dir_snode != NULL) && 2665331Samw (strcmp(od_name, "..") != 0) && 2675331Samw (strcmp(od_name, ".") != 0)) { 2685331Samw VALIDATE_DIR_NODE(dir_snode, 2695331Samw node); 2705331Samw node->dir_snode = dir_snode; 2715331Samw smb_node_ref(dir_snode); 2725331Samw } 2735331Samw node->attr = *attr; 2745772Sas200622 node->n_size = attr->sa_vattr.va_size; 2755331Samw 2765331Samw smb_audit_node(node); 2775331Samw smb_rwx_xexit(&node->n_lock); 2785331Samw smb_llist_exit(node_hdr); 2795331Samw VN_RELE(vp); 2805331Samw return (node); 2815331Samw 2825331Samw case SMB_NODE_STATE_DESTROYING: 2835331Samw /* 2845331Samw * Although the node exists it is about 2855331Samw * to be destroyed. We act as it hasn't 2865331Samw * been found. 2875331Samw */ 2885331Samw smb_rwx_xexit(&node->n_lock); 2895331Samw break; 2905331Samw default: 2915331Samw /* 2925331Samw * Although the node exists it is in an 2935331Samw * unknown state. We act as it hasn't 2945331Samw * been found. 2955331Samw */ 2965331Samw ASSERT(0); 2975331Samw smb_rwx_xexit(&node->n_lock); 2985331Samw break; 2995331Samw } 3005331Samw } 3015331Samw node = smb_llist_next(node_hdr, node); 3025331Samw } 3035331Samw if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) { 3045331Samw lock_mode = RW_WRITER; 3055331Samw continue; 3065331Samw } 3075331Samw break; 3085331Samw } 309*6139Sjb150015 node = kmem_cache_alloc(sr->sr_server->si_cache_node, KM_SLEEP); 3105331Samw bzero(node, sizeof (smb_node_t)); 3115331Samw 3125331Samw node->n_state = SMB_NODE_STATE_AVAILABLE; 3135331Samw node->n_hash_bucket = node_hdr; 314*6139Sjb150015 node->n_sr = sr; 315*6139Sjb150015 node->vp = vp; 316*6139Sjb150015 node->n_hashkey = hashkey; 317*6139Sjb150015 node->n_refcnt = 1; 318*6139Sjb150015 node->tree_fsd = vp->v_vfsp->vfs_fsid; 319*6139Sjb150015 node->attr = *attr; 320*6139Sjb150015 node->flags |= NODE_FLAGS_ATTR_VALID; 321*6139Sjb150015 node->n_size = node->attr.sa_vattr.va_size; 322*6139Sjb150015 node->n_orig_session_id = sr->session->s_kid; 323*6139Sjb150015 node->n_orig_uid = crgetuid(sr->user_cr); 324*6139Sjb150015 node->n_cache = sr->sr_server->si_cache_node; 3255331Samw 326*6139Sjb150015 ASSERT(od_name); 327*6139Sjb150015 (void) strlcpy(node->od_name, od_name, sizeof (node->od_name)); 328*6139Sjb150015 329*6139Sjb150015 if (fsd_chkcap(&vp->v_vfsp->vfs_fsid, FSOLF_READONLY) > 0) 3305331Samw node->flags |= NODE_READ_ONLY; 3315331Samw 3325331Samw smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 3335331Samw offsetof(smb_ofile_t, f_nnd)); 3345331Samw smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 3355331Samw offsetof(smb_lock_t, l_lnd)); 3365331Samw 3375331Samw 3385967Scp160787 if (strcmp(od_name, XATTR_DIR) == 0) 3395967Scp160787 node->flags |= NODE_XATTR_DIR; 3405331Samw if (op) 3415331Samw node->flags |= smb_is_executable(op->fqi.last_comp); 3425331Samw 3435331Samw if (dir_snode) { 3445331Samw smb_node_ref(dir_snode); 3455331Samw node->dir_snode = dir_snode; 3465331Samw ASSERT(dir_snode->dir_snode != node); 3475331Samw ASSERT((dir_snode->vp->v_xattrdir) || 3485331Samw (dir_snode->vp->v_type == VDIR)); 3495331Samw } 3505331Samw 3515331Samw if (unnamed_node) { 3525331Samw smb_node_ref(unnamed_node); 3535331Samw node->unnamed_stream_node = unnamed_node; 3545331Samw } 3555331Samw 3565331Samw smb_rwx_init(&node->n_lock); 3575331Samw node->n_magic = SMB_NODE_MAGIC; 3585331Samw smb_audit_buf_node_create(node); 3595331Samw DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node); 3605331Samw smb_audit_node(node); 3615331Samw smb_llist_insert_head(node_hdr, node); 362*6139Sjb150015 3635331Samw smb_llist_exit(node_hdr); 3645331Samw return (node); 3655331Samw } 3665331Samw 3675331Samw /* 3685331Samw * smb_stream_node_lookup() 3695331Samw * 3705331Samw * Note: stream_name (the name that will be stored in the "od_name" field 3715331Samw * of a stream's smb_node) is the same as the on-disk name for the stream 3725331Samw * except that it does not have SMB_STREAM_PREFIX prepended. 3735331Samw */ 3745331Samw 3755331Samw smb_node_t * 3765331Samw smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode, 3775331Samw vnode_t *xattrdirvp, vnode_t *vp, char *stream_name, smb_attr_t *ret_attr) 3785331Samw { 3795331Samw smb_node_t *xattrdir_node; 3805331Samw smb_node_t *snode; 3815331Samw smb_attr_t tmp_attr; 3825331Samw 3835331Samw xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR, 3845331Samw fnode, NULL, &tmp_attr); 3855331Samw 3865331Samw if (xattrdir_node == NULL) 3875331Samw return (NULL); 3885331Samw 3895331Samw snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node, 3905331Samw fnode, ret_attr); 3915331Samw 3925331Samw /* 3935331Samw * The following VN_HOLD is necessary because the caller will VN_RELE 3945331Samw * xattrdirvp in the case of an error. (xattrdir_node has the original 3955331Samw * hold on the vnode, which the smb_node_release() call below will 3965331Samw * release.) 3975331Samw */ 3985331Samw if (snode == NULL) { 3995331Samw VN_HOLD(xattrdirvp); 4005331Samw } 4015331Samw (void) smb_node_release(xattrdir_node); 4025331Samw return (snode); 4035331Samw } 4045331Samw 4055331Samw 4065331Samw /* 4075331Samw * This function should be called whenever a reference is needed on an 4085331Samw * smb_node pointer. The copy of an smb_node pointer from one non-local 4095331Samw * data structure to another requires a reference to be taken on the smb_node 4105331Samw * (unless the usage is localized). Each data structure deallocation routine 4115331Samw * will call smb_node_release() on its smb_node pointers. 4125331Samw * 4135331Samw * In general, an smb_node pointer residing in a structure should never be 4145331Samw * stale. A node pointer may be NULL, however, and care should be taken 4155331Samw * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid. 4165331Samw * Care also needs to be taken with respect to racing deallocations of a 4175331Samw * structure. 4185331Samw */ 4195331Samw 4205331Samw void 4215331Samw smb_node_ref(smb_node_t *node) 4225331Samw { 4235331Samw ASSERT(node); 4245331Samw ASSERT(node->n_magic == SMB_NODE_MAGIC); 4255331Samw ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 4265331Samw 4275331Samw smb_rwx_xenter(&node->n_lock); 4285331Samw node->n_refcnt++; 4295331Samw ASSERT(node->n_refcnt); 4305331Samw DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node); 4315331Samw smb_audit_node(node); 4325331Samw smb_rwx_xexit(&node->n_lock); 4335331Samw } 4345331Samw 4355331Samw /* 4365331Samw * smb_node_lookup() takes a hold on an smb_node, whether found in the 4375331Samw * hash table or newly created. This hold is expected to be released 4385331Samw * in the following manner. 4395331Samw * 4405331Samw * smb_node_lookup() takes an address of an smb_node pointer. This should 4415331Samw * be getting passed down via a lookup (whether path name or component), mkdir, 4425331Samw * create. If the original smb_node pointer resides in a data structure, then 4435331Samw * the deallocation routine for the data structure is responsible for calling 4445331Samw * smb_node_release() on the smb_node pointer. Alternatively, 4455331Samw * smb_node_release() can be called as soon as the smb_node pointer is no longer 4465331Samw * needed. In this case, callers are responsible for setting an embedded 4475331Samw * pointer to NULL if it is known that the last reference is being released. 4485331Samw * 4495331Samw * If the passed-in address of the smb_node pointer belongs to a local variable, 4505331Samw * then the caller with the local variable should call smb_node_release() 4515331Samw * directly. 4525331Samw * 4535331Samw * smb_node_release() itself will call smb_node_release() on a node's dir_snode, 4545331Samw * as smb_node_lookup() takes a hold on dir_snode. 4555331Samw */ 4565331Samw void 4575331Samw smb_node_release(smb_node_t *node) 4585331Samw { 4595331Samw ASSERT(node); 4605331Samw ASSERT(node->n_magic == SMB_NODE_MAGIC); 4615331Samw 4625331Samw smb_rwx_xenter(&node->n_lock); 4635331Samw ASSERT(node->n_refcnt); 4645331Samw DTRACE_PROBE1(smb_node_release, smb_node_t *, node); 4655331Samw if (--node->n_refcnt == 0) { 4665331Samw switch (node->n_state) { 4675331Samw 4685331Samw case SMB_NODE_STATE_AVAILABLE: 4695331Samw node->n_state = SMB_NODE_STATE_DESTROYING; 4705331Samw smb_rwx_xexit(&node->n_lock); 4715331Samw 4725331Samw smb_llist_enter(node->n_hash_bucket, RW_WRITER); 4735331Samw smb_llist_remove(node->n_hash_bucket, node); 4745331Samw smb_llist_exit(node->n_hash_bucket); 4755331Samw 4765331Samw /* 4775331Samw * Check if the file was deleted 4785331Samw */ 4795331Samw smb_node_delete_on_close(node); 4805331Samw node->n_magic = (uint32_t)~SMB_NODE_MAGIC; 4815331Samw 4825331Samw /* These lists should be empty. */ 4835331Samw smb_llist_destructor(&node->n_ofile_list); 4845331Samw smb_llist_destructor(&node->n_lock_list); 4855331Samw 4865331Samw if (node->dir_snode) { 4875331Samw ASSERT(node->dir_snode->n_magic == 4885331Samw SMB_NODE_MAGIC); 4895331Samw smb_node_release(node->dir_snode); 4905331Samw } 4915331Samw 4925331Samw if (node->unnamed_stream_node) { 4935331Samw ASSERT(node->unnamed_stream_node->n_magic == 4945331Samw SMB_NODE_MAGIC); 4955331Samw smb_node_release(node->unnamed_stream_node); 4965331Samw } 4975331Samw 4985331Samw ASSERT(node->vp); 4995331Samw VN_RELE(node->vp); 5005331Samw 5015331Samw smb_audit_buf_node_destroy(node); 5025331Samw smb_rwx_destroy(&node->n_lock); 503*6139Sjb150015 kmem_cache_free(node->n_cache, node); 5045331Samw return; 5055331Samw 5065331Samw default: 5075331Samw ASSERT(0); 5085331Samw break; 5095331Samw } 5105331Samw } 5115331Samw smb_audit_node(node); 5125331Samw smb_rwx_xexit(&node->n_lock); 5135331Samw } 5145331Samw 5155331Samw static void 5165331Samw smb_node_delete_on_close(smb_node_t *node) 5175331Samw { 5185331Samw smb_node_t *d_snode; 5195331Samw int rc = 0; 5205331Samw 5215331Samw d_snode = node->dir_snode; 5225331Samw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 5235331Samw 5245331Samw node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 5255331Samw ASSERT(node->od_name != NULL); 5265331Samw if (node->attr.sa_vattr.va_type == VDIR) 5275331Samw rc = smb_fsop_rmdir(0, node->delete_on_close_cred, 5285331Samw d_snode, node->od_name, 1); 5295331Samw else 5305331Samw rc = smb_fsop_remove(0, node->delete_on_close_cred, 5315331Samw d_snode, node->od_name, 1); 5325331Samw smb_cred_rele(node->delete_on_close_cred); 5335331Samw } 5345331Samw if (rc != 0) 5355331Samw cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n", 5365331Samw node->od_name, rc); 5375331Samw DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node); 5385331Samw } 5395331Samw 5405331Samw /* 5415331Samw * smb_node_rename() 5425331Samw * 5435331Samw */ 5445331Samw int 5455331Samw smb_node_rename( 5465331Samw smb_node_t *from_dir_snode, 5475331Samw smb_node_t *ret_snode, 5485331Samw smb_node_t *to_dir_snode, 5495331Samw char *to_name) 5505331Samw { 5515331Samw ASSERT(from_dir_snode); 5525331Samw ASSERT(to_dir_snode); 5535331Samw ASSERT(ret_snode); 5545331Samw ASSERT(from_dir_snode->n_magic == SMB_NODE_MAGIC); 5555331Samw ASSERT(to_dir_snode->n_magic == SMB_NODE_MAGIC); 5565331Samw ASSERT(ret_snode->n_magic == SMB_NODE_MAGIC); 5575331Samw ASSERT(from_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE); 5585331Samw ASSERT(to_dir_snode->n_state == SMB_NODE_STATE_AVAILABLE); 5595331Samw ASSERT(ret_snode->n_state == SMB_NODE_STATE_AVAILABLE); 5605331Samw 5615331Samw smb_node_ref(to_dir_snode); 5625331Samw smb_rwx_xenter(&ret_snode->n_lock); 5635331Samw ret_snode->dir_snode = to_dir_snode; 5645331Samw smb_rwx_xexit(&ret_snode->n_lock); 5655331Samw ASSERT(to_dir_snode->dir_snode != ret_snode); 5665331Samw ASSERT((to_dir_snode->vp->v_xattrdir) || 5675331Samw (to_dir_snode->vp->v_type == VDIR)); 5685331Samw smb_node_release(from_dir_snode); 5695331Samw 5705331Samw (void) strcpy(ret_snode->od_name, to_name); 5715331Samw 5725331Samw /* 5735331Samw * XXX Need to update attributes? 5745331Samw */ 5755331Samw 5765331Samw return (0); 5775331Samw } 5785331Samw 5795331Samw int 580*6139Sjb150015 smb_node_root_init(vnode_t *vp, smb_server_t *sv, smb_node_t **root) 5815331Samw { 582*6139Sjb150015 smb_attr_t va; 583*6139Sjb150015 int error; 584*6139Sjb150015 uint32_t hashkey; 585*6139Sjb150015 smb_llist_t *node_hdr; 586*6139Sjb150015 smb_node_t *node; 5875331Samw 5885331Samw /* 5895331Samw * Take an explicit hold on rootdir. This goes with the 5905331Samw * corresponding release in smb_node_root_fini()/smb_node_release(). 5915331Samw */ 592*6139Sjb150015 VN_HOLD(vp); 5935331Samw 594*6139Sjb150015 va.sa_mask = SMB_AT_ALL; 595*6139Sjb150015 error = smb_vop_getattr(vp, NULL, &va, 0, kcred); 596*6139Sjb150015 if (error) { 597*6139Sjb150015 VN_RELE(vp); 598*6139Sjb150015 return (error); 599*6139Sjb150015 } 600*6139Sjb150015 601*6139Sjb150015 hashkey = vp->v_vfsp->vfs_fsid.val[0] + va.sa_vattr.va_nodeid; 602*6139Sjb150015 hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 603*6139Sjb150015 node_hdr = &smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]; 604*6139Sjb150015 605*6139Sjb150015 node = kmem_cache_alloc(sv->si_cache_node, KM_SLEEP); 606*6139Sjb150015 bzero(node, sizeof (smb_node_t)); 6075331Samw 608*6139Sjb150015 node->n_state = SMB_NODE_STATE_AVAILABLE; 609*6139Sjb150015 node->n_hash_bucket = node_hdr; 610*6139Sjb150015 node->vp = vp; 611*6139Sjb150015 node->n_hashkey = hashkey; 612*6139Sjb150015 node->n_refcnt = 1; 613*6139Sjb150015 node->tree_fsd = vp->v_vfsp->vfs_fsid; 614*6139Sjb150015 node->attr = va; 615*6139Sjb150015 node->flags |= NODE_FLAGS_ATTR_VALID; 616*6139Sjb150015 node->n_size = node->attr.sa_vattr.va_size; 617*6139Sjb150015 node->n_cache = sv->si_cache_node; 618*6139Sjb150015 (void) strlcpy(node->od_name, ROOTVOL, sizeof (node->od_name)); 619*6139Sjb150015 620*6139Sjb150015 if (fsd_chkcap(&vp->v_vfsp->vfs_fsid, FSOLF_READONLY) > 0) 621*6139Sjb150015 node->flags |= NODE_READ_ONLY; 6225331Samw 623*6139Sjb150015 smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 624*6139Sjb150015 offsetof(smb_ofile_t, f_nnd)); 625*6139Sjb150015 smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 626*6139Sjb150015 offsetof(smb_lock_t, l_lnd)); 627*6139Sjb150015 628*6139Sjb150015 smb_rwx_init(&node->n_lock); 629*6139Sjb150015 node->n_magic = SMB_NODE_MAGIC; 630*6139Sjb150015 smb_audit_buf_node_create(node); 631*6139Sjb150015 632*6139Sjb150015 sv->si_root_smb_node = node; 633*6139Sjb150015 634*6139Sjb150015 smb_audit_node(node); 635*6139Sjb150015 smb_llist_enter(node_hdr, RW_WRITER); 636*6139Sjb150015 smb_llist_insert_head(node_hdr, node); 637*6139Sjb150015 smb_llist_exit(node_hdr); 638*6139Sjb150015 639*6139Sjb150015 *root = node; 640*6139Sjb150015 641*6139Sjb150015 return (0); 6425331Samw } 6435331Samw 6445331Samw /* 6455331Samw * smb_node_get_size 6465331Samw */ 6475331Samw uint64_t 6485331Samw smb_node_get_size( 6495331Samw smb_node_t *node, 6505331Samw smb_attr_t *attr) 6515331Samw { 6525331Samw uint64_t size; 6535331Samw 6545331Samw if (attr->sa_vattr.va_type == VDIR) 6555331Samw return (0); 6565331Samw 6575331Samw smb_rwx_xenter(&node->n_lock); 6585331Samw if (node && (node->flags & NODE_FLAGS_SET_SIZE)) 6595331Samw size = node->n_size; 6605331Samw else 6615331Samw size = attr->sa_vattr.va_size; 6625331Samw smb_rwx_xexit(&node->n_lock); 6635331Samw return (size); 6645331Samw } 6655331Samw 6665331Samw static int 6675331Samw timeval_cmp(timestruc_t *a, timestruc_t *b) 6685331Samw { 6695331Samw if (a->tv_sec < b->tv_sec) 6705331Samw return (-1); 6715331Samw if (a->tv_sec > b->tv_sec) 6725331Samw return (1); 6735331Samw /* Seconds are equal compare tv_nsec */ 6745331Samw if (a->tv_nsec < b->tv_nsec) 6755331Samw return (-1); 6765331Samw return (a->tv_nsec > b->tv_nsec); 6775331Samw } 6785331Samw 6795331Samw /* 6805331Samw * smb_node_set_time 6815331Samw * 6825331Samw * This function will update the time stored in the node and 6835331Samw * set the appropriate flags. If there is nothing to update 6845331Samw * or the node is readonly, the function would return without 6855331Samw * any updates. The update is only in the node level and the 6865331Samw * attribute in the file system will be updated when client 6875331Samw * close the file. 6885331Samw */ 6895331Samw void 6905331Samw smb_node_set_time(struct smb_node *node, struct timestruc *crtime, 6915331Samw struct timestruc *mtime, struct timestruc *atime, 6925331Samw struct timestruc *ctime, unsigned int what) 6935331Samw { 6945331Samw smb_rwx_xenter(&node->n_lock); 6955331Samw if (node->flags & NODE_READ_ONLY || what == 0) { 6965331Samw smb_rwx_xexit(&node->n_lock); 6975331Samw return; 6985331Samw } 6995331Samw 7005331Samw if ((what & SMB_AT_CRTIME && crtime == 0) || 7015331Samw (what & SMB_AT_MTIME && mtime == 0) || 7025331Samw (what & SMB_AT_ATIME && atime == 0) || 7035331Samw (what & SMB_AT_CTIME && ctime == 0)) { 7045331Samw smb_rwx_xexit(&node->n_lock); 7055331Samw return; 7065331Samw } 7075331Samw 7085331Samw if ((what & SMB_AT_CRTIME) && 7095331Samw timeval_cmp((timestruc_t *)&node->attr.sa_crtime, 7105331Samw crtime) != 0) { 7115331Samw node->what |= SMB_AT_CRTIME; 7125331Samw node->attr.sa_crtime = *((timestruc_t *)crtime); 7135331Samw } 7145331Samw 7155331Samw if ((what & SMB_AT_MTIME) && 7165331Samw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_mtime, 7175331Samw mtime) != 0) { 7185331Samw node->what |= SMB_AT_MTIME; 7195331Samw node->attr.sa_vattr.va_mtime = *((timestruc_t *)mtime); 7205331Samw } 7215331Samw 7225331Samw if ((what & SMB_AT_ATIME) && 7235331Samw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_atime, 7245331Samw atime) != 0) { 7255331Samw node->what |= SMB_AT_ATIME; 7265331Samw node->attr.sa_vattr.va_atime = *((timestruc_t *)atime); 7275331Samw } 7285331Samw 7295331Samw /* 7305331Samw * The ctime handling is trickier. It has three scenarios. 7315331Samw * 1. Only ctime need to be set and it is the same as the ctime 7325331Samw * stored in the node. (update not necessary) 7335331Samw * 2. The ctime is the same as the ctime stored in the node but 7345331Samw * is not the only time need to be set. (update required) 7355331Samw * 3. The ctime need to be set and is not the same as the ctime 7365331Samw * stored in the node. (update required) 7375331Samw * Unlike other time setting, the ctime needs to be set even when 7385331Samw * it is the same as the ctime in the node if there are other time 7395331Samw * needs to be set (#2). This will ensure the ctime not being 7405331Samw * updated when other times are being updated in the file system. 7415331Samw * 7425331Samw * Retained file rules: 7435331Samw * 7445331Samw * 1. Don't add SMB_AT_CTIME to node->what by default because the 7455331Samw * request will be rejected by filesystem 7465331Samw * 2. 'what' SMB_AT_CTIME shouldn't be set for retained files, i.e. 7475331Samw * any request for changing ctime on these files should have 7485331Samw * been already rejected 7495331Samw */ 7505331Samw node->what |= SMB_AT_CTIME; 7515331Samw if (what & SMB_AT_CTIME) { 7525331Samw if ((what == SMB_AT_CTIME) && 7535331Samw timeval_cmp((timestruc_t *)&node->attr.sa_vattr.va_ctime, 7545331Samw ctime) == 0) { 7555331Samw node->what &= ~SMB_AT_CTIME; 7565331Samw } else { 7575331Samw gethrestime(&node->attr.sa_vattr.va_ctime); 7585331Samw } 7595331Samw } else { 7605331Samw gethrestime(&node->attr.sa_vattr.va_ctime); 7615331Samw } 7625331Samw smb_rwx_xexit(&node->n_lock); 7635331Samw } 7645331Samw 7655331Samw 7665331Samw timestruc_t * 7675331Samw smb_node_get_crtime(smb_node_t *node) 7685331Samw { 7695331Samw return ((timestruc_t *)&node->attr.sa_crtime); 7705331Samw } 7715331Samw 7725331Samw timestruc_t * 7735331Samw smb_node_get_atime(smb_node_t *node) 7745331Samw { 7755331Samw return ((timestruc_t *)&node->attr.sa_vattr.va_atime); 7765331Samw } 7775331Samw 7785331Samw timestruc_t * 7795331Samw smb_node_get_ctime(smb_node_t *node) 7805331Samw { 7815331Samw return ((timestruc_t *)&node->attr.sa_vattr.va_ctime); 7825331Samw } 7835331Samw 7845331Samw timestruc_t * 7855331Samw smb_node_get_mtime(smb_node_t *node) 7865331Samw { 7875331Samw return ((timestruc_t *)&node->attr.sa_vattr.va_mtime); 7885331Samw } 7895331Samw 7905331Samw /* 7915331Samw * smb_node_set_dosattr 7925331Samw * 7935331Samw * Parse the specified DOS attributes and, if they have been modified, 7945331Samw * update the node cache. This call should be followed by a 7955331Samw * smb_sync_fsattr() call to write the attribute changes to filesystem. 7965331Samw */ 7975331Samw void 7985331Samw smb_node_set_dosattr(smb_node_t *node, uint32_t dos_attr) 7995331Samw { 8005331Samw unsigned int mode; /* New mode */ 8015331Samw 8025331Samw mode = 0; 8035331Samw 8045331Samw /* Handle the archive bit */ 8055331Samw if (dos_attr & SMB_FA_ARCHIVE) 8065331Samw mode |= FILE_ATTRIBUTE_ARCHIVE; 8075331Samw 8085331Samw /* Handle the readonly bit */ 8095331Samw if (dos_attr & SMB_FA_READONLY) 8105331Samw mode |= FILE_ATTRIBUTE_READONLY; 8115331Samw 8125331Samw /* Handle the hidden bit */ 8135331Samw if (dos_attr & SMB_FA_HIDDEN) 8145331Samw mode |= FILE_ATTRIBUTE_HIDDEN; 8155331Samw 8165331Samw /* Handle the system bit */ 8175331Samw if (dos_attr & SMB_FA_SYSTEM) 8185331Samw mode |= FILE_ATTRIBUTE_SYSTEM; 8195331Samw 8205331Samw smb_rwx_xenter(&node->n_lock); 8215331Samw if (node->attr.sa_dosattr != mode) { 8225331Samw node->attr.sa_dosattr = mode; 8235331Samw node->what |= SMB_AT_DOSATTR; 8245331Samw } 8255331Samw smb_rwx_xexit(&node->n_lock); 8265331Samw } 8275331Samw 8285331Samw /* 8295331Samw * smb_node_get_dosattr 8305331Samw * 8315331Samw * This function will get dos attribute using the node. 8325331Samw */ 8335331Samw uint32_t 8345331Samw smb_node_get_dosattr(smb_node_t *node) 8355331Samw { 8365331Samw return (smb_mode_to_dos_attributes(&node->attr)); 8375331Samw } 8385331Samw 8395331Samw int 8405331Samw smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr) 8415331Samw { 8425331Samw int rc = -1; 8435331Samw 8445331Samw smb_rwx_xenter(&node->n_lock); 8455331Samw if (!(node->attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) && 8465331Samw !(node->flags & NODE_FLAGS_DELETE_ON_CLOSE)) { 8475331Samw crhold(cr); 8485331Samw node->delete_on_close_cred = cr; 8495331Samw node->flags |= NODE_FLAGS_DELETE_ON_CLOSE; 8505331Samw rc = 0; 8515331Samw } 8525331Samw smb_rwx_xexit(&node->n_lock); 8535331Samw return (rc); 8545331Samw } 8555331Samw 8565331Samw void 8575331Samw smb_node_reset_delete_on_close(smb_node_t *node) 8585331Samw { 8595331Samw smb_rwx_xenter(&node->n_lock); 8605331Samw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 8615331Samw node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 8625331Samw crfree(node->delete_on_close_cred); 8635331Samw node->delete_on_close_cred = NULL; 8645331Samw } 8655331Samw smb_rwx_xexit(&node->n_lock); 8665331Samw } 8675772Sas200622 8685772Sas200622 /* 8695772Sas200622 * smb_node_share_check 8705772Sas200622 * 8715772Sas200622 * check file sharing rules for current open request 8725772Sas200622 * against all existing opens for a file. 8735772Sas200622 * 8745772Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 8755772Sas200622 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 8765772Sas200622 */ 8775772Sas200622 uint32_t 8785772Sas200622 smb_node_open_check(struct smb_node *node, cred_t *cr, 8795772Sas200622 uint32_t desired_access, uint32_t share_access) 8805772Sas200622 { 8815772Sas200622 smb_ofile_t *of; 8825772Sas200622 uint32_t status; 8835772Sas200622 8845772Sas200622 ASSERT(node); 8855772Sas200622 ASSERT(node->n_magic == SMB_NODE_MAGIC); 8865772Sas200622 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 8875772Sas200622 8885772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 8895772Sas200622 of = smb_llist_head(&node->n_ofile_list); 8905772Sas200622 while (of) { 8915772Sas200622 status = smb_node_share_check(node, cr, desired_access, 8925772Sas200622 share_access, of); 8935772Sas200622 if (status == NT_STATUS_SHARING_VIOLATION) { 8945772Sas200622 smb_llist_exit(&node->n_ofile_list); 8955772Sas200622 return (status); 8965772Sas200622 } 8975772Sas200622 of = smb_llist_next(&node->n_ofile_list, of); 8985772Sas200622 } 8995772Sas200622 smb_llist_exit(&node->n_ofile_list); 9005772Sas200622 9015772Sas200622 return (NT_STATUS_SUCCESS); 9025772Sas200622 } 9035772Sas200622 9045772Sas200622 /* 9055772Sas200622 * smb_open_share_check 9065772Sas200622 * 9075772Sas200622 * check file sharing rules for current open request 9085772Sas200622 * against the given existing open. 9095772Sas200622 * 9105772Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 9115772Sas200622 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 9125772Sas200622 */ 9135772Sas200622 uint32_t 9145772Sas200622 smb_node_share_check( 9155772Sas200622 struct smb_node *node, 9165772Sas200622 cred_t *cr, 9175772Sas200622 uint32_t desired_access, 9185772Sas200622 uint32_t share_access, 9195772Sas200622 smb_ofile_t *of) 9205772Sas200622 { 9215772Sas200622 /* 9225772Sas200622 * It appears that share modes are not relevant to 9235772Sas200622 * directories, but this check will remain as it is not 9245772Sas200622 * clear whether it was originally put here for a reason. 9255772Sas200622 */ 9265772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) { 9275772Sas200622 if (SMB_DENY_RW(of->f_share_access) && 9285772Sas200622 (node->n_orig_uid != crgetuid(cr))) { 9295772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 9305772Sas200622 } 9315772Sas200622 9325772Sas200622 return (NT_STATUS_SUCCESS); 9335772Sas200622 } 9345772Sas200622 9355772Sas200622 /* if it's just meta data */ 9365772Sas200622 if ((of->f_granted_access & FILE_DATA_ALL) == 0) 9375772Sas200622 return (NT_STATUS_SUCCESS); 9385772Sas200622 9395772Sas200622 /* 9405772Sas200622 * Check requested share access against the 9415772Sas200622 * open granted (desired) access 9425772Sas200622 */ 9435772Sas200622 if (SMB_DENY_DELETE(share_access) && (of->f_granted_access & DELETE)) 9445772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 9455772Sas200622 9465772Sas200622 if (SMB_DENY_READ(share_access) && 9475772Sas200622 (of->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE))) 9485772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 9495772Sas200622 9505772Sas200622 if (SMB_DENY_WRITE(share_access) && 9515772Sas200622 (of->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) 9525772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 9535772Sas200622 9545772Sas200622 /* check requested desired access against the open share access */ 9555772Sas200622 if (SMB_DENY_DELETE(of->f_share_access) && (desired_access & DELETE)) 9565772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 9575772Sas200622 9585772Sas200622 if (SMB_DENY_READ(of->f_share_access) && 9595772Sas200622 (desired_access & (FILE_READ_DATA | FILE_EXECUTE))) 9605772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 9615772Sas200622 9625772Sas200622 if (SMB_DENY_WRITE(of->f_share_access) && 9635772Sas200622 (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) 9645772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 9655772Sas200622 9665772Sas200622 return (NT_STATUS_SUCCESS); 9675772Sas200622 } 9685772Sas200622 9695772Sas200622 /* 9705772Sas200622 * smb_rename_share_check 9715772Sas200622 * 9725772Sas200622 * An open file can be renamed if 9735772Sas200622 * 9745772Sas200622 * 1. isn't opened for data writing or deleting 9755772Sas200622 * 9765772Sas200622 * 2. Opened with "Deny Delete" share mode 9775772Sas200622 * But not opened for data reading or executing 9785772Sas200622 * (opened for accessing meta data) 9795772Sas200622 */ 9805772Sas200622 9815772Sas200622 DWORD 9825772Sas200622 smb_node_rename_check(struct smb_node *node) 9835772Sas200622 { 9845772Sas200622 struct smb_ofile *open; 9855772Sas200622 9865772Sas200622 ASSERT(node); 9875772Sas200622 ASSERT(node->n_magic == SMB_NODE_MAGIC); 9885772Sas200622 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 9895772Sas200622 9905772Sas200622 /* 9915772Sas200622 * Intra-CIFS check 9925772Sas200622 */ 9935772Sas200622 9945772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 9955772Sas200622 open = smb_llist_head(&node->n_ofile_list); 9965772Sas200622 while (open) { 9975772Sas200622 if (open->f_granted_access & 9985772Sas200622 (FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE)) { 9995772Sas200622 smb_llist_exit(&node->n_ofile_list); 10005772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 10015772Sas200622 } 10025772Sas200622 10035772Sas200622 if ((open->f_share_access & FILE_SHARE_DELETE) == 0) { 10045772Sas200622 if (open->f_granted_access & 10055772Sas200622 (FILE_READ_DATA | FILE_EXECUTE)) { 10065772Sas200622 smb_llist_exit(&node->n_ofile_list); 10075772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 10085772Sas200622 } 10095772Sas200622 } 10105772Sas200622 open = smb_llist_next(&node->n_ofile_list, open); 10115772Sas200622 } 10125772Sas200622 smb_llist_exit(&node->n_ofile_list); 10135772Sas200622 10145772Sas200622 /* 10155772Sas200622 * system-wide share check 10165772Sas200622 */ 10175772Sas200622 10185772Sas200622 if (nbl_share_conflict(node->vp, NBL_RENAME, NULL)) 10195772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 10205772Sas200622 else 10215772Sas200622 return (NT_STATUS_SUCCESS); 10225772Sas200622 } 10235772Sas200622 10245772Sas200622 /* 10255772Sas200622 * smb_node_delete_check 10265772Sas200622 * 10275772Sas200622 * An open file can be deleted only if opened for 10285772Sas200622 * accessing meta data. Share modes aren't important 10295772Sas200622 * in this case. 10305772Sas200622 * 10315772Sas200622 * NOTE: there is another mechanism for deleting an 10325772Sas200622 * open file that NT clients usually use. 10335772Sas200622 * That's setting "Delete on close" flag for an open 10345772Sas200622 * file. In this way the file will be deleted after 10355772Sas200622 * last close. This flag can be set by SmbTrans2SetFileInfo 10365772Sas200622 * with FILE_DISPOSITION_INFO information level. 10375772Sas200622 * For setting this flag, the file should be opened by 10385772Sas200622 * DELETE access in the FID that is passed in the Trans2 10395772Sas200622 * request. 10405772Sas200622 */ 10415772Sas200622 DWORD 10425772Sas200622 smb_node_delete_check(smb_node_t *node) 10435772Sas200622 { 10445772Sas200622 smb_ofile_t *file; 10455772Sas200622 10465772Sas200622 ASSERT(node); 10475772Sas200622 ASSERT(node->n_magic == SMB_NODE_MAGIC); 10485772Sas200622 ASSERT(node->n_state == SMB_NODE_STATE_AVAILABLE); 10495772Sas200622 10505772Sas200622 if (node->attr.sa_vattr.va_type == VDIR) 10515772Sas200622 return (NT_STATUS_SUCCESS); 10525772Sas200622 10535772Sas200622 /* 10545772Sas200622 * intra-CIFS check 10555772Sas200622 */ 10565772Sas200622 10575772Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 10585772Sas200622 file = smb_llist_head(&node->n_ofile_list); 10595772Sas200622 while (file) { 10605772Sas200622 ASSERT(file->f_magic == SMB_OFILE_MAGIC); 10615772Sas200622 if (file->f_granted_access & 10625772Sas200622 (FILE_READ_DATA | 10635772Sas200622 FILE_WRITE_DATA | 10645772Sas200622 FILE_APPEND_DATA | 10655772Sas200622 FILE_EXECUTE | 10665772Sas200622 DELETE)) { 10675772Sas200622 smb_llist_exit(&node->n_ofile_list); 10685772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 10695772Sas200622 } 10705772Sas200622 file = smb_llist_next(&node->n_ofile_list, file); 10715772Sas200622 } 10725772Sas200622 smb_llist_exit(&node->n_ofile_list); 10735772Sas200622 10745772Sas200622 /* 10755772Sas200622 * system-wide share check 10765772Sas200622 */ 10775772Sas200622 10785772Sas200622 if (nbl_share_conflict(node->vp, NBL_REMOVE, NULL)) 10795772Sas200622 return (NT_STATUS_SHARING_VIOLATION); 10805772Sas200622 else 10815772Sas200622 return (NT_STATUS_SUCCESS); 10825772Sas200622 } 10835772Sas200622 10845772Sas200622 /* 10855772Sas200622 * smb_node_start_crit() 10865772Sas200622 * 10875772Sas200622 * Enter critical region for share reservations. 10885772Sas200622 * See comments above smb_fsop_shrlock(). 10895772Sas200622 */ 10905772Sas200622 10915772Sas200622 void 10925772Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode) 10935772Sas200622 { 10945772Sas200622 rw_enter(&node->n_share_lock, mode); 10955772Sas200622 nbl_start_crit(node->vp, mode); 10965772Sas200622 } 10975772Sas200622 10985772Sas200622 /* 10995772Sas200622 * smb_node_end_crit() 11005772Sas200622 * 11015772Sas200622 * Exit critical region for share reservations. 11025772Sas200622 */ 11035772Sas200622 11045772Sas200622 void 11055772Sas200622 smb_node_end_crit(smb_node_t *node) 11065772Sas200622 { 11075772Sas200622 nbl_end_crit(node->vp); 11085772Sas200622 rw_exit(&node->n_share_lock); 11095772Sas200622 } 11105772Sas200622 11115772Sas200622 int 11125772Sas200622 smb_node_in_crit(smb_node_t *node) 11135772Sas200622 { 11145772Sas200622 return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_share_lock)); 11155772Sas200622 } 1116