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 /* 22c5866007SKeyur Desai * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23*a90cf9f2SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 24da6c28aaSamw */ 25da6c28aaSamw /* 26da6c28aaSamw * SMB Node State Machine 27da6c28aaSamw * ---------------------- 28da6c28aaSamw * 29fc724630SAlan Wright * 30fc724630SAlan Wright * +----------- Creation/Allocation 31da6c28aaSamw * | 32fc724630SAlan Wright * | T0 33da6c28aaSamw * | 34da6c28aaSamw * v 35cb174861Sjoyce mcintosh * +----------------------------+ 36cb174861Sjoyce mcintosh * | SMB_NODE_STATE_AVAILABLE | 37cb174861Sjoyce mcintosh * +----------------------------+ 38cb174861Sjoyce mcintosh * | 39cb174861Sjoyce mcintosh * | T1 40fc724630SAlan Wright * | 41fc724630SAlan Wright * v 42da6c28aaSamw * +-----------------------------+ 43fc724630SAlan Wright * | SMB_NODE_STATE_DESTROYING | 44fc724630SAlan Wright * +-----------------------------+ 45fc724630SAlan Wright * | 46fc724630SAlan Wright * | 47cb174861Sjoyce mcintosh * | T2 48fc724630SAlan Wright * | 49fc724630SAlan Wright * +----------> Deletion/Free 50da6c28aaSamw * 51da6c28aaSamw * Transition T0 52da6c28aaSamw * 53da6c28aaSamw * This transition occurs in smb_node_lookup(). If the node looked for is 54da6c28aaSamw * not found in the has table a new node is created. The reference count is 55da6c28aaSamw * initialized to 1 and the state initialized to SMB_NODE_STATE_AVAILABLE. 56da6c28aaSamw * 57da6c28aaSamw * Transition T1 58da6c28aaSamw * 59da6c28aaSamw * This transition occurs in smb_node_release(). If the reference count 60da6c28aaSamw * drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more 61da6c28aaSamw * reference count will be given out for that node. 62da6c28aaSamw * 63cb174861Sjoyce mcintosh * Transition T2 64da6c28aaSamw * 65da6c28aaSamw * This transition occurs in smb_node_release(). The structure is deleted. 66da6c28aaSamw * 67da6c28aaSamw * Comments 68da6c28aaSamw * -------- 69da6c28aaSamw * 70da6c28aaSamw * The reason the smb node has 2 states is the following synchronization 71da6c28aaSamw * rule: 72da6c28aaSamw * 73da6c28aaSamw * There's a mutex embedded in the node used to protect its fields and 74da6c28aaSamw * there's a lock embedded in the bucket of the hash table the node belongs 75da6c28aaSamw * to. To increment or to decrement the reference count the mutex must be 76da6c28aaSamw * entered. To insert the node into the bucket and to remove it from the 77da6c28aaSamw * bucket the lock must be entered in RW_WRITER mode. When both (mutex and 78da6c28aaSamw * lock) have to be entered, the lock has always to be entered first then 79da6c28aaSamw * the mutex. This prevents a deadlock between smb_node_lookup() and 80da6c28aaSamw * smb_node_release() from occurring. However, in smb_node_release() when the 81da6c28aaSamw * reference count drops to zero and triggers the deletion of the node, the 82da6c28aaSamw * mutex has to be released before entering the lock of the bucket (to 83da6c28aaSamw * remove the node). This creates a window during which the node that is 84da6c28aaSamw * about to be freed could be given out by smb_node_lookup(). To close that 85da6c28aaSamw * window the node is moved to the state SMB_NODE_STATE_DESTROYING before 86da6c28aaSamw * releasing the mutex. That way, even if smb_node_lookup() finds it, the 87da6c28aaSamw * state will indicate that the node should be treated as non existent (of 88da6c28aaSamw * course the state of the node should be tested/updated under the 89da6c28aaSamw * protection of the mutex). 90da6c28aaSamw */ 91bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h> 92da6c28aaSamw #include <smbsrv/smb_fsops.h> 932c2961f8Sjose borrego #include <smbsrv/smb_kstat.h> 945496c117SAlek Pinchuk #include <sys/ddi.h> 955496c117SAlek Pinchuk #include <sys/extdirent.h> 96da6c28aaSamw #include <sys/pathname.h> 97da6c28aaSamw #include <sys/sdt.h> 98dc20a302Sas200622 #include <sys/nbmlock.h> 999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <fs/fs_reparse.h> 100da6c28aaSamw 1012c2961f8Sjose borrego uint32_t smb_is_executable(char *); 1022c2961f8Sjose borrego static void smb_node_delete_on_close(smb_node_t *); 1032c2961f8Sjose borrego static void smb_node_create_audit_buf(smb_node_t *, int); 1042c2961f8Sjose borrego static void smb_node_destroy_audit_buf(smb_node_t *); 1052c2961f8Sjose borrego static void smb_node_audit(smb_node_t *); 106037cac00Sjoyce mcintosh static smb_node_t *smb_node_alloc(char *, vnode_t *, smb_llist_t *, uint32_t); 1072c2961f8Sjose borrego static void smb_node_free(smb_node_t *); 1082c2961f8Sjose borrego static int smb_node_constructor(void *, void *, int); 1092c2961f8Sjose borrego static void smb_node_destructor(void *, void *); 1102c2961f8Sjose borrego static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *); 111e3f2c991SKeyur Desai 1129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void smb_node_init_reparse(smb_node_t *, smb_attr_t *); 1139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void smb_node_init_system(smb_node_t *); 114e3f2c991SKeyur Desai 115da6c28aaSamw #define VALIDATE_DIR_NODE(_dir_, _node_) \ 116da6c28aaSamw ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \ 117da6c28aaSamw ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \ 1181fcced4cSJordan Brown ASSERT((_dir_)->n_dnode != (_node_)); 119da6c28aaSamw 120e3f2c991SKeyur Desai /* round sz to DEV_BSIZE block */ 121e3f2c991SKeyur Desai #define SMB_ALLOCSZ(sz) (((sz) + DEV_BSIZE-1) & ~(DEV_BSIZE-1)) 122e3f2c991SKeyur Desai 1232c2961f8Sjose borrego static kmem_cache_t *smb_node_cache = NULL; 124faa1795aSjb150015 static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1]; 1258622ec45SGordon Ross static smb_node_t *smb_root_node; 126faa1795aSjb150015 127faa1795aSjb150015 /* 128faa1795aSjb150015 * smb_node_init 129faa1795aSjb150015 * 130faa1795aSjb150015 * Initialization of the SMB node layer. 131faa1795aSjb150015 * 132faa1795aSjb150015 * This function is not multi-thread safe. The caller must make sure only one 133faa1795aSjb150015 * thread makes the call. 134faa1795aSjb150015 */ 1358622ec45SGordon Ross void 136faa1795aSjb150015 smb_node_init(void) 137faa1795aSjb150015 { 1388622ec45SGordon Ross smb_attr_t attr; 1398622ec45SGordon Ross smb_llist_t *node_hdr; 1408622ec45SGordon Ross smb_node_t *node; 1418622ec45SGordon Ross uint32_t hashkey; 142faa1795aSjb150015 int i; 143faa1795aSjb150015 1448622ec45SGordon Ross if (smb_node_cache != NULL) 1458622ec45SGordon Ross return; 1468622ec45SGordon Ross 1472c2961f8Sjose borrego smb_node_cache = kmem_cache_create(SMBSRV_KSTAT_NODE_CACHE, 1482c2961f8Sjose borrego sizeof (smb_node_t), 8, smb_node_constructor, smb_node_destructor, 1492c2961f8Sjose borrego NULL, NULL, NULL, 0); 150faa1795aSjb150015 151faa1795aSjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 152faa1795aSjb150015 smb_llist_constructor(&smb_node_hash_table[i], 153faa1795aSjb150015 sizeof (smb_node_t), offsetof(smb_node_t, n_lnd)); 154faa1795aSjb150015 } 1558622ec45SGordon Ross 1568622ec45SGordon Ross /* 1578622ec45SGordon Ross * The node cache is shared by all zones, so the smb_root_node 1588622ec45SGordon Ross * must represent the real (global zone) rootdir. 1598622ec45SGordon Ross * Note intentional use of kcred here. 1608622ec45SGordon Ross */ 1618622ec45SGordon Ross attr.sa_mask = SMB_AT_ALL; 1628622ec45SGordon Ross VERIFY0(smb_vop_getattr(rootdir, NULL, &attr, 0, kcred)); 1638622ec45SGordon Ross node_hdr = smb_node_get_hash(&rootdir->v_vfsp->vfs_fsid, &attr, 1648622ec45SGordon Ross &hashkey); 1658622ec45SGordon Ross node = smb_node_alloc("/", rootdir, node_hdr, hashkey); 1668622ec45SGordon Ross smb_llist_enter(node_hdr, RW_WRITER); 1678622ec45SGordon Ross smb_llist_insert_head(node_hdr, node); 1688622ec45SGordon Ross smb_llist_exit(node_hdr); 1698622ec45SGordon Ross smb_root_node = node; /* smb_node_release in smb_node_fini */ 170faa1795aSjb150015 } 171faa1795aSjb150015 172faa1795aSjb150015 /* 173faa1795aSjb150015 * smb_node_fini 174faa1795aSjb150015 * 175faa1795aSjb150015 * This function is not multi-thread safe. The caller must make sure only one 176faa1795aSjb150015 * thread makes the call. 177faa1795aSjb150015 */ 178faa1795aSjb150015 void 179faa1795aSjb150015 smb_node_fini(void) 180faa1795aSjb150015 { 181faa1795aSjb150015 int i; 182faa1795aSjb150015 1838622ec45SGordon Ross if (smb_root_node != NULL) { 1848622ec45SGordon Ross smb_node_release(smb_root_node); 1858622ec45SGordon Ross smb_root_node = NULL; 1868622ec45SGordon Ross } 1878622ec45SGordon Ross 1888622ec45SGordon Ross if (smb_node_cache == NULL) 189faa1795aSjb150015 return; 190faa1795aSjb150015 191faa1795aSjb150015 #ifdef DEBUG 192faa1795aSjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 193faa1795aSjb150015 smb_node_t *node; 194faa1795aSjb150015 195faa1795aSjb150015 /* 196faa1795aSjb150015 * The following sequence is just intended for sanity check. 197faa1795aSjb150015 * This will have to be modified when the code goes into 198faa1795aSjb150015 * production. 199faa1795aSjb150015 * 200faa1795aSjb150015 * The SMB node hash table should be emtpy at this point. If the 201faa1795aSjb150015 * hash table is not empty a panic will be triggered. 202faa1795aSjb150015 * 203faa1795aSjb150015 * The reason why SMB nodes are still remaining in the hash 204faa1795aSjb150015 * table is problably due to a mismatch between calls to 205faa1795aSjb150015 * smb_node_lookup() and smb_node_release(). You must track that 206faa1795aSjb150015 * down. 207faa1795aSjb150015 */ 208faa1795aSjb150015 node = smb_llist_head(&smb_node_hash_table[i]); 209faa1795aSjb150015 ASSERT(node == NULL); 210faa1795aSjb150015 } 211faa1795aSjb150015 #endif 212faa1795aSjb150015 213faa1795aSjb150015 for (i = 0; i <= SMBND_HASH_MASK; i++) { 214faa1795aSjb150015 smb_llist_destructor(&smb_node_hash_table[i]); 215faa1795aSjb150015 } 2162c2961f8Sjose borrego kmem_cache_destroy(smb_node_cache); 2172c2961f8Sjose borrego smb_node_cache = NULL; 218faa1795aSjb150015 } 219faa1795aSjb150015 220da6c28aaSamw /* 221da6c28aaSamw * smb_node_lookup() 222da6c28aaSamw * 223da6c28aaSamw * NOTE: This routine should only be called by the file system interface layer, 224da6c28aaSamw * and not by SMB. 225da6c28aaSamw * 226da6c28aaSamw * smb_node_lookup() is called upon successful lookup, mkdir, and create 227da6c28aaSamw * (for both non-streams and streams). In each of these cases, a held vnode is 2287f667e74Sjose borrego * passed into this routine. If a new smb_node is created it will take its 2297f667e74Sjose borrego * own hold on the vnode. The caller's hold therefore still belongs to, and 2307f667e74Sjose borrego * should be released by, the caller. 231da6c28aaSamw * 232da6c28aaSamw * A reference is taken on the smb_node whether found in the hash table 233da6c28aaSamw * or newly created. 234da6c28aaSamw * 235da6c28aaSamw * If an smb_node needs to be created, a reference is also taken on the 2361fcced4cSJordan Brown * dnode (if passed in). 237da6c28aaSamw * 238da6c28aaSamw * See smb_node_release() for details on the release of these references. 239da6c28aaSamw */ 240da6c28aaSamw 241da6c28aaSamw /*ARGSUSED*/ 242da6c28aaSamw smb_node_t * 243da6c28aaSamw smb_node_lookup( 244da6c28aaSamw struct smb_request *sr, 245da6c28aaSamw struct open_param *op, 246da6c28aaSamw cred_t *cred, 247da6c28aaSamw vnode_t *vp, 248da6c28aaSamw char *od_name, 2491fcced4cSJordan Brown smb_node_t *dnode, 2501fcced4cSJordan Brown smb_node_t *unode) 251da6c28aaSamw { 252da6c28aaSamw smb_llist_t *node_hdr; 253da6c28aaSamw smb_node_t *node; 254037cac00Sjoyce mcintosh smb_attr_t attr; 255da6c28aaSamw uint32_t hashkey = 0; 256c8ec8eeaSjose borrego fsid_t fsid; 257da6c28aaSamw int error; 258da6c28aaSamw krw_t lock_mode; 259da6c28aaSamw vnode_t *unnamed_vp = NULL; 260da6c28aaSamw 261da6c28aaSamw /* 262da6c28aaSamw * smb_vop_getattr() is called here instead of smb_fsop_getattr(), 263da6c28aaSamw * because the node may not yet exist. We also do not want to call 264da6c28aaSamw * it with the list lock held. 265da6c28aaSamw */ 266da6c28aaSamw 2671fcced4cSJordan Brown if (unode) 2681fcced4cSJordan Brown unnamed_vp = unode->vp; 269da6c28aaSamw 270da6c28aaSamw /* 271da6c28aaSamw * This getattr is performed on behalf of the server 272da6c28aaSamw * that's why kcred is used not the user's cred 273da6c28aaSamw */ 274037cac00Sjoyce mcintosh attr.sa_mask = SMB_AT_ALL; 2758622ec45SGordon Ross error = smb_vop_getattr(vp, unnamed_vp, &attr, 0, zone_kcred()); 276da6c28aaSamw if (error) 277da6c28aaSamw return (NULL); 278da6c28aaSamw 279c8ec8eeaSjose borrego if (sr && sr->tid_tree) { 280da6c28aaSamw /* 281c8ec8eeaSjose borrego * The fsid for a file is that of the tree, even 282da6c28aaSamw * if the file resides in a different mountpoint 283da6c28aaSamw * under the share. 284da6c28aaSamw */ 285c8ec8eeaSjose borrego fsid = SMB_TREE_FSID(sr->tid_tree); 286da6c28aaSamw } else { 287da6c28aaSamw /* 288da6c28aaSamw * This should be getting executed only for the 289c8ec8eeaSjose borrego * tree root smb_node. 290da6c28aaSamw */ 291c8ec8eeaSjose borrego fsid = vp->v_vfsp->vfs_fsid; 292da6c28aaSamw } 293da6c28aaSamw 294037cac00Sjoyce mcintosh node_hdr = smb_node_get_hash(&fsid, &attr, &hashkey); 295da6c28aaSamw lock_mode = RW_READER; 296da6c28aaSamw 297da6c28aaSamw smb_llist_enter(node_hdr, lock_mode); 298da6c28aaSamw for (;;) { 299da6c28aaSamw node = list_head(&node_hdr->ll_list); 300da6c28aaSamw while (node) { 301da6c28aaSamw ASSERT(node->n_magic == SMB_NODE_MAGIC); 302da6c28aaSamw ASSERT(node->n_hash_bucket == node_hdr); 303da6c28aaSamw if ((node->n_hashkey == hashkey) && (node->vp == vp)) { 3042c2961f8Sjose borrego mutex_enter(&node->n_mutex); 305da6c28aaSamw DTRACE_PROBE1(smb_node_lookup_hit, 306da6c28aaSamw smb_node_t *, node); 307da6c28aaSamw switch (node->n_state) { 308da6c28aaSamw case SMB_NODE_STATE_AVAILABLE: 309da6c28aaSamw /* The node was found. */ 310da6c28aaSamw node->n_refcnt++; 3111fcced4cSJordan Brown if ((node->n_dnode == NULL) && 3121fcced4cSJordan Brown (dnode != NULL) && 31396a62adaSjoyce mcintosh (node != dnode) && 314da6c28aaSamw (strcmp(od_name, "..") != 0) && 315da6c28aaSamw (strcmp(od_name, ".") != 0)) { 3161fcced4cSJordan Brown VALIDATE_DIR_NODE(dnode, node); 3171fcced4cSJordan Brown node->n_dnode = dnode; 3181fcced4cSJordan Brown smb_node_ref(dnode); 319da6c28aaSamw } 320da6c28aaSamw 3212c2961f8Sjose borrego smb_node_audit(node); 3222c2961f8Sjose borrego mutex_exit(&node->n_mutex); 323da6c28aaSamw smb_llist_exit(node_hdr); 324da6c28aaSamw return (node); 325da6c28aaSamw 326da6c28aaSamw case SMB_NODE_STATE_DESTROYING: 327da6c28aaSamw /* 328da6c28aaSamw * Although the node exists it is about 329da6c28aaSamw * to be destroyed. We act as it hasn't 330da6c28aaSamw * been found. 331da6c28aaSamw */ 3322c2961f8Sjose borrego mutex_exit(&node->n_mutex); 333da6c28aaSamw break; 334da6c28aaSamw default: 335da6c28aaSamw /* 336da6c28aaSamw * Although the node exists it is in an 337da6c28aaSamw * unknown state. We act as it hasn't 338da6c28aaSamw * been found. 339da6c28aaSamw */ 340da6c28aaSamw ASSERT(0); 3412c2961f8Sjose borrego mutex_exit(&node->n_mutex); 342da6c28aaSamw break; 343da6c28aaSamw } 344da6c28aaSamw } 345da6c28aaSamw node = smb_llist_next(node_hdr, node); 346da6c28aaSamw } 347da6c28aaSamw if ((lock_mode == RW_READER) && smb_llist_upgrade(node_hdr)) { 348da6c28aaSamw lock_mode = RW_WRITER; 349da6c28aaSamw continue; 350da6c28aaSamw } 351da6c28aaSamw break; 352da6c28aaSamw } 353037cac00Sjoyce mcintosh node = smb_node_alloc(od_name, vp, node_hdr, hashkey); 3549fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_init_reparse(node, &attr); 355da6c28aaSamw 356da6c28aaSamw if (op) 357eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States node->flags |= smb_is_executable(op->fqi.fq_last_comp); 358da6c28aaSamw 3591fcced4cSJordan Brown if (dnode) { 3601fcced4cSJordan Brown smb_node_ref(dnode); 3611fcced4cSJordan Brown node->n_dnode = dnode; 3621fcced4cSJordan Brown ASSERT(dnode->n_dnode != node); 3631fcced4cSJordan Brown ASSERT((dnode->vp->v_xattrdir) || 3641fcced4cSJordan Brown (dnode->vp->v_type == VDIR)); 365da6c28aaSamw } 366da6c28aaSamw 3671fcced4cSJordan Brown if (unode) { 3681fcced4cSJordan Brown smb_node_ref(unode); 3691fcced4cSJordan Brown node->n_unode = unode; 370da6c28aaSamw } 371da6c28aaSamw 3729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_init_system(node); 3739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 374da6c28aaSamw DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node); 3752c2961f8Sjose borrego smb_node_audit(node); 376da6c28aaSamw smb_llist_insert_head(node_hdr, node); 377da6c28aaSamw smb_llist_exit(node_hdr); 378da6c28aaSamw return (node); 379da6c28aaSamw } 380da6c28aaSamw 381da6c28aaSamw /* 382da6c28aaSamw * smb_stream_node_lookup() 383da6c28aaSamw * 384da6c28aaSamw * Note: stream_name (the name that will be stored in the "od_name" field 385da6c28aaSamw * of a stream's smb_node) is the same as the on-disk name for the stream 386da6c28aaSamw * except that it does not have SMB_STREAM_PREFIX prepended. 387da6c28aaSamw */ 388da6c28aaSamw 389da6c28aaSamw smb_node_t * 3902c2961f8Sjose borrego smb_stream_node_lookup(smb_request_t *sr, cred_t *cr, smb_node_t *fnode, 391037cac00Sjoyce mcintosh vnode_t *xattrdirvp, vnode_t *vp, char *stream_name) 392da6c28aaSamw { 393da6c28aaSamw smb_node_t *xattrdir_node; 394da6c28aaSamw smb_node_t *snode; 395da6c28aaSamw 396da6c28aaSamw xattrdir_node = smb_node_lookup(sr, NULL, cr, xattrdirvp, XATTR_DIR, 397037cac00Sjoyce mcintosh fnode, NULL); 398da6c28aaSamw 399da6c28aaSamw if (xattrdir_node == NULL) 400da6c28aaSamw return (NULL); 401da6c28aaSamw 402da6c28aaSamw snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node, 403037cac00Sjoyce mcintosh fnode); 404da6c28aaSamw 405da6c28aaSamw (void) smb_node_release(xattrdir_node); 406da6c28aaSamw return (snode); 407da6c28aaSamw } 408da6c28aaSamw 409da6c28aaSamw 410da6c28aaSamw /* 411da6c28aaSamw * This function should be called whenever a reference is needed on an 412da6c28aaSamw * smb_node pointer. The copy of an smb_node pointer from one non-local 413da6c28aaSamw * data structure to another requires a reference to be taken on the smb_node 414da6c28aaSamw * (unless the usage is localized). Each data structure deallocation routine 415da6c28aaSamw * will call smb_node_release() on its smb_node pointers. 416da6c28aaSamw * 417da6c28aaSamw * In general, an smb_node pointer residing in a structure should never be 418da6c28aaSamw * stale. A node pointer may be NULL, however, and care should be taken 419da6c28aaSamw * prior to calling smb_node_ref(), which ASSERTs that the pointer is valid. 420da6c28aaSamw * Care also needs to be taken with respect to racing deallocations of a 421da6c28aaSamw * structure. 422da6c28aaSamw */ 423da6c28aaSamw void 424da6c28aaSamw smb_node_ref(smb_node_t *node) 425da6c28aaSamw { 4262c2961f8Sjose borrego SMB_NODE_VALID(node); 427da6c28aaSamw 4282c2961f8Sjose borrego mutex_enter(&node->n_mutex); 4292c2961f8Sjose borrego switch (node->n_state) { 4302c2961f8Sjose borrego case SMB_NODE_STATE_AVAILABLE: 431da6c28aaSamw node->n_refcnt++; 432da6c28aaSamw ASSERT(node->n_refcnt); 433da6c28aaSamw DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node); 4342c2961f8Sjose borrego smb_node_audit(node); 4352c2961f8Sjose borrego break; 4362c2961f8Sjose borrego default: 4372c2961f8Sjose borrego SMB_PANIC(); 4382c2961f8Sjose borrego } 4392c2961f8Sjose borrego mutex_exit(&node->n_mutex); 440da6c28aaSamw } 441da6c28aaSamw 442da6c28aaSamw /* 443da6c28aaSamw * smb_node_lookup() takes a hold on an smb_node, whether found in the 444da6c28aaSamw * hash table or newly created. This hold is expected to be released 445da6c28aaSamw * in the following manner. 446da6c28aaSamw * 447da6c28aaSamw * smb_node_lookup() takes an address of an smb_node pointer. This should 448da6c28aaSamw * be getting passed down via a lookup (whether path name or component), mkdir, 449da6c28aaSamw * create. If the original smb_node pointer resides in a data structure, then 450da6c28aaSamw * the deallocation routine for the data structure is responsible for calling 451da6c28aaSamw * smb_node_release() on the smb_node pointer. Alternatively, 452da6c28aaSamw * smb_node_release() can be called as soon as the smb_node pointer is no longer 453da6c28aaSamw * needed. In this case, callers are responsible for setting an embedded 454da6c28aaSamw * pointer to NULL if it is known that the last reference is being released. 455da6c28aaSamw * 456da6c28aaSamw * If the passed-in address of the smb_node pointer belongs to a local variable, 457da6c28aaSamw * then the caller with the local variable should call smb_node_release() 458da6c28aaSamw * directly. 459da6c28aaSamw * 4601fcced4cSJordan Brown * smb_node_release() itself will call smb_node_release() on a node's n_dnode, 4611fcced4cSJordan Brown * as smb_node_lookup() takes a hold on dnode. 462da6c28aaSamw */ 463da6c28aaSamw void 464da6c28aaSamw smb_node_release(smb_node_t *node) 465da6c28aaSamw { 4662c2961f8Sjose borrego SMB_NODE_VALID(node); 467da6c28aaSamw 4682c2961f8Sjose borrego mutex_enter(&node->n_mutex); 469da6c28aaSamw ASSERT(node->n_refcnt); 470da6c28aaSamw DTRACE_PROBE1(smb_node_release, smb_node_t *, node); 471da6c28aaSamw if (--node->n_refcnt == 0) { 472da6c28aaSamw switch (node->n_state) { 473da6c28aaSamw 474da6c28aaSamw case SMB_NODE_STATE_AVAILABLE: 475da6c28aaSamw node->n_state = SMB_NODE_STATE_DESTROYING; 4762c2961f8Sjose borrego mutex_exit(&node->n_mutex); 477da6c28aaSamw 478da6c28aaSamw smb_llist_enter(node->n_hash_bucket, RW_WRITER); 479da6c28aaSamw smb_llist_remove(node->n_hash_bucket, node); 480da6c28aaSamw smb_llist_exit(node->n_hash_bucket); 481da6c28aaSamw 482da6c28aaSamw /* 483da6c28aaSamw * Check if the file was deleted 484da6c28aaSamw */ 485da6c28aaSamw smb_node_delete_on_close(node); 486da6c28aaSamw 4871fcced4cSJordan Brown if (node->n_dnode) { 4881fcced4cSJordan Brown ASSERT(node->n_dnode->n_magic == 489da6c28aaSamw SMB_NODE_MAGIC); 4901fcced4cSJordan Brown smb_node_release(node->n_dnode); 491da6c28aaSamw } 492da6c28aaSamw 4931fcced4cSJordan Brown if (node->n_unode) { 4941fcced4cSJordan Brown ASSERT(node->n_unode->n_magic == 495da6c28aaSamw SMB_NODE_MAGIC); 4961fcced4cSJordan Brown smb_node_release(node->n_unode); 497da6c28aaSamw } 498da6c28aaSamw 4992c2961f8Sjose borrego smb_node_free(node); 500da6c28aaSamw return; 501da6c28aaSamw 502da6c28aaSamw default: 5032c2961f8Sjose borrego SMB_PANIC(); 504da6c28aaSamw } 505da6c28aaSamw } 5062c2961f8Sjose borrego smb_node_audit(node); 5072c2961f8Sjose borrego mutex_exit(&node->n_mutex); 508da6c28aaSamw } 509da6c28aaSamw 510da6c28aaSamw static void 511da6c28aaSamw smb_node_delete_on_close(smb_node_t *node) 512da6c28aaSamw { 513da6c28aaSamw smb_node_t *d_snode; 514da6c28aaSamw int rc = 0; 5158b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States uint32_t flags = 0; 516da6c28aaSamw 5171fcced4cSJordan Brown d_snode = node->n_dnode; 518da6c28aaSamw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 519da6c28aaSamw node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 5208b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States flags = node->n_delete_on_close_flags; 521da6c28aaSamw ASSERT(node->od_name != NULL); 5228b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 5239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_node_is_dir(node)) 524da6c28aaSamw rc = smb_fsop_rmdir(0, node->delete_on_close_cred, 5258b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States d_snode, node->od_name, flags); 526da6c28aaSamw else 527da6c28aaSamw rc = smb_fsop_remove(0, node->delete_on_close_cred, 5288b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States d_snode, node->od_name, flags); 529148c5f43SAlan Wright crfree(node->delete_on_close_cred); 530da6c28aaSamw } 531da6c28aaSamw if (rc != 0) 532da6c28aaSamw cmn_err(CE_WARN, "File %s could not be removed, rc=%d\n", 533da6c28aaSamw node->od_name, rc); 534da6c28aaSamw DTRACE_PROBE2(smb_node_delete_on_close, int, rc, smb_node_t *, node); 535da6c28aaSamw } 536da6c28aaSamw 537da6c28aaSamw /* 538da6c28aaSamw * smb_node_rename() 539da6c28aaSamw * 540da6c28aaSamw */ 5412c2961f8Sjose borrego void 542da6c28aaSamw smb_node_rename( 5432c2961f8Sjose borrego smb_node_t *from_dnode, 5442c2961f8Sjose borrego smb_node_t *ret_node, 5452c2961f8Sjose borrego smb_node_t *to_dnode, 546da6c28aaSamw char *to_name) 547da6c28aaSamw { 5482c2961f8Sjose borrego SMB_NODE_VALID(from_dnode); 5492c2961f8Sjose borrego SMB_NODE_VALID(to_dnode); 5502c2961f8Sjose borrego SMB_NODE_VALID(ret_node); 551da6c28aaSamw 5522c2961f8Sjose borrego smb_node_ref(to_dnode); 5532c2961f8Sjose borrego mutex_enter(&ret_node->n_mutex); 5542c2961f8Sjose borrego switch (ret_node->n_state) { 5552c2961f8Sjose borrego case SMB_NODE_STATE_AVAILABLE: 5561fcced4cSJordan Brown ret_node->n_dnode = to_dnode; 5572c2961f8Sjose borrego mutex_exit(&ret_node->n_mutex); 5581fcced4cSJordan Brown ASSERT(to_dnode->n_dnode != ret_node); 5592c2961f8Sjose borrego ASSERT((to_dnode->vp->v_xattrdir) || 5602c2961f8Sjose borrego (to_dnode->vp->v_type == VDIR)); 5612c2961f8Sjose borrego smb_node_release(from_dnode); 5622c2961f8Sjose borrego (void) strcpy(ret_node->od_name, to_name); 563da6c28aaSamw /* 564da6c28aaSamw * XXX Need to update attributes? 565da6c28aaSamw */ 5662c2961f8Sjose borrego break; 5672c2961f8Sjose borrego default: 5682c2961f8Sjose borrego SMB_PANIC(); 5692c2961f8Sjose borrego } 570da6c28aaSamw } 571da6c28aaSamw 5728622ec45SGordon Ross /* 5738622ec45SGordon Ross * Find/create an SMB node for the root of this zone and store it 5748622ec45SGordon Ross * in *svrootp. Also create nodes leading to this directory. 5758622ec45SGordon Ross */ 576da6c28aaSamw int 5778622ec45SGordon Ross smb_node_root_init(smb_server_t *sv, smb_node_t **svrootp) 578da6c28aaSamw { 5798622ec45SGordon Ross zone_t *zone = curzone; 580faa1795aSjb150015 int error; 581da6c28aaSamw 5828622ec45SGordon Ross ASSERT(zone->zone_id == sv->sv_zid); 5838622ec45SGordon Ross if (smb_root_node == NULL) 5848622ec45SGordon Ross return (ENOENT); 5858622ec45SGordon Ross 5868622ec45SGordon Ross /* 5878622ec45SGordon Ross * We're getting smb nodes below the zone root here, 5888622ec45SGordon Ross * so need to use kcred, not zone_kcred(). 5898622ec45SGordon Ross */ 5908622ec45SGordon Ross error = smb_pathname(NULL, zone->zone_rootpath, 0, 5918622ec45SGordon Ross smb_root_node, smb_root_node, NULL, svrootp, kcred); 5928622ec45SGordon Ross 593faa1795aSjb150015 return (error); 594faa1795aSjb150015 } 595*a90cf9f2SGordon Ross 5965496c117SAlek Pinchuk /* 5975496c117SAlek Pinchuk * Helper function for smb_node_set_delete_on_close(). Assumes node is a dir. 5985496c117SAlek Pinchuk * Return 0 if this is an empty dir. Otherwise return a NT_STATUS code. 5995496c117SAlek Pinchuk * We distinguish between readdir failure and non-empty dir by returning 6005496c117SAlek Pinchuk * different values. 6015496c117SAlek Pinchuk */ 6025496c117SAlek Pinchuk static uint32_t 6035496c117SAlek Pinchuk smb_rmdir_possible(smb_node_t *n, uint32_t flags) 6045496c117SAlek Pinchuk { 6055496c117SAlek Pinchuk ASSERT(n->vp->v_type == VDIR); 6065496c117SAlek Pinchuk char buf[512]; /* Only large enough to see if the dir is empty. */ 6075496c117SAlek Pinchuk int eof, bsize = sizeof (buf), reclen = 0; 6085496c117SAlek Pinchuk char *name; 6095496c117SAlek Pinchuk boolean_t edp = vfs_has_feature(n->vp->v_vfsp, VFSFT_DIRENTFLAGS); 6105496c117SAlek Pinchuk 6115496c117SAlek Pinchuk union { 6125496c117SAlek Pinchuk char *u_bufptr; 6135496c117SAlek Pinchuk struct edirent *u_edp; 6145496c117SAlek Pinchuk struct dirent64 *u_dp; 6155496c117SAlek Pinchuk } u; 6165496c117SAlek Pinchuk #define bufptr u.u_bufptr 6175496c117SAlek Pinchuk #define extdp u.u_edp 6185496c117SAlek Pinchuk #define dp u.u_dp 6195496c117SAlek Pinchuk 6205496c117SAlek Pinchuk if (smb_vop_readdir(n->vp, 0, buf, &bsize, &eof, flags, zone_kcred())) 6215496c117SAlek Pinchuk return (NT_STATUS_CANNOT_DELETE); 6225496c117SAlek Pinchuk if (bsize == 0) 6235496c117SAlek Pinchuk return (NT_STATUS_CANNOT_DELETE); 6245496c117SAlek Pinchuk bufptr = buf; 6255496c117SAlek Pinchuk while ((bufptr += reclen) < buf + bsize) { 6265496c117SAlek Pinchuk if (edp) { 6275496c117SAlek Pinchuk reclen = extdp->ed_reclen; 6285496c117SAlek Pinchuk name = extdp->ed_name; 6295496c117SAlek Pinchuk } else { 6305496c117SAlek Pinchuk reclen = dp->d_reclen; 6315496c117SAlek Pinchuk name = dp->d_name; 6325496c117SAlek Pinchuk } 6335496c117SAlek Pinchuk if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0) 6345496c117SAlek Pinchuk return (NT_STATUS_DIRECTORY_NOT_EMPTY); 6355496c117SAlek Pinchuk } 6365496c117SAlek Pinchuk return (0); 6375496c117SAlek Pinchuk } 638da6c28aaSamw 639da6c28aaSamw /* 6408b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * When DeleteOnClose is set on an smb_node, the common open code will 6418b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * reject subsequent open requests for the file. Observation of Windows 6428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 2000 indicates that subsequent opens should be allowed (assuming 6438b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * there would be no sharing violation) until the file is closed using 6448b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * the fid on which the DeleteOnClose was requested. 6458b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 6468b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * If there are multiple opens with delete-on-close create options, 6478b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * whichever the first file handle is closed will trigger the node to be 6488b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * marked as delete-on-close. The credentials of that ofile will be used 6498b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * as the delete-on-close credentials of the node. 6508b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States */ 6515496c117SAlek Pinchuk uint32_t 6528b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags) 653da6c28aaSamw { 654a0aa776eSAlan Wright int rc = 0; 6555496c117SAlek Pinchuk uint32_t status; 656037cac00Sjoyce mcintosh smb_attr_t attr; 657da6c28aaSamw 6585fd03bc0SGordon Ross if (node->n_pending_dosattr & FILE_ATTRIBUTE_READONLY) 6595496c117SAlek Pinchuk return (NT_STATUS_CANNOT_DELETE); 660037cac00Sjoyce mcintosh 661037cac00Sjoyce mcintosh bzero(&attr, sizeof (smb_attr_t)); 662037cac00Sjoyce mcintosh attr.sa_mask = SMB_AT_DOSATTR; 6638622ec45SGordon Ross rc = smb_fsop_getattr(NULL, zone_kcred(), node, &attr); 664037cac00Sjoyce mcintosh if ((rc != 0) || (attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) { 6655496c117SAlek Pinchuk return (NT_STATUS_CANNOT_DELETE); 6665496c117SAlek Pinchuk } 6675496c117SAlek Pinchuk 6685496c117SAlek Pinchuk /* 6695496c117SAlek Pinchuk * If the directory is not empty we should fail setting del-on-close 6705496c117SAlek Pinchuk * with STATUS_DIRECTORY_NOT_EMPTY. see MS's 6715496c117SAlek Pinchuk * "File System Behavior Overview" doc section 4.3.2 6725496c117SAlek Pinchuk */ 6735496c117SAlek Pinchuk if (smb_node_is_dir(node)) { 6745496c117SAlek Pinchuk status = smb_rmdir_possible(node, flags); 6755496c117SAlek Pinchuk if (status != 0) { 6765496c117SAlek Pinchuk return (status); 6775496c117SAlek Pinchuk } 678037cac00Sjoyce mcintosh } 679037cac00Sjoyce mcintosh 680a0aa776eSAlan Wright mutex_enter(&node->n_mutex); 681a0aa776eSAlan Wright if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 6825496c117SAlek Pinchuk mutex_exit(&node->n_mutex); 6835496c117SAlek Pinchuk return (NT_STATUS_CANNOT_DELETE); 6845496c117SAlek Pinchuk } 6855496c117SAlek Pinchuk 686da6c28aaSamw crhold(cr); 687da6c28aaSamw node->delete_on_close_cred = cr; 6888b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States node->n_delete_on_close_flags = flags; 689da6c28aaSamw node->flags |= NODE_FLAGS_DELETE_ON_CLOSE; 6902c2961f8Sjose borrego mutex_exit(&node->n_mutex); 6915496c117SAlek Pinchuk 692*a90cf9f2SGordon Ross /* 693*a90cf9f2SGordon Ross * Tell any change notify calls to close their handles 694*a90cf9f2SGordon Ross * and get out of the way. FILE_ACTION_DELETE_PENDING 695*a90cf9f2SGordon Ross * is a special, internal-only action for this purpose. 696*a90cf9f2SGordon Ross */ 697*a90cf9f2SGordon Ross smb_notify_event(node, FILE_ACTION_DELETE_PENDING, NULL); 698*a90cf9f2SGordon Ross 6995496c117SAlek Pinchuk return (NT_STATUS_SUCCESS); 700da6c28aaSamw } 701da6c28aaSamw 702da6c28aaSamw void 703da6c28aaSamw smb_node_reset_delete_on_close(smb_node_t *node) 704da6c28aaSamw { 7052c2961f8Sjose borrego mutex_enter(&node->n_mutex); 706da6c28aaSamw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { 707da6c28aaSamw node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE; 708da6c28aaSamw crfree(node->delete_on_close_cred); 709da6c28aaSamw node->delete_on_close_cred = NULL; 7108b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States node->n_delete_on_close_flags = 0; 711da6c28aaSamw } 7122c2961f8Sjose borrego mutex_exit(&node->n_mutex); 713da6c28aaSamw } 714dc20a302Sas200622 715dc20a302Sas200622 /* 7163ad684d6Sjb150015 * smb_node_open_check 717dc20a302Sas200622 * 718dc20a302Sas200622 * check file sharing rules for current open request 719dc20a302Sas200622 * against all existing opens for a file. 720dc20a302Sas200622 * 721dc20a302Sas200622 * Returns NT_STATUS_SHARING_VIOLATION if there is any 722dc20a302Sas200622 * sharing conflict, otherwise returns NT_STATUS_SUCCESS. 723dc20a302Sas200622 */ 724dc20a302Sas200622 uint32_t 7259fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_open_check(smb_node_t *node, uint32_t desired_access, 7262c2961f8Sjose borrego uint32_t share_access) 727dc20a302Sas200622 { 728dc20a302Sas200622 smb_ofile_t *of; 729dc20a302Sas200622 uint32_t status; 730dc20a302Sas200622 7312c2961f8Sjose borrego SMB_NODE_VALID(node); 732dc20a302Sas200622 733dc20a302Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 734dc20a302Sas200622 of = smb_llist_head(&node->n_ofile_list); 735dc20a302Sas200622 while (of) { 7369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States status = smb_ofile_open_check(of, desired_access, share_access); 7373ad684d6Sjb150015 7383ad684d6Sjb150015 switch (status) { 7393ad684d6Sjb150015 case NT_STATUS_INVALID_HANDLE: 7403ad684d6Sjb150015 case NT_STATUS_SUCCESS: 7413ad684d6Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 7423ad684d6Sjb150015 break; 7433ad684d6Sjb150015 default: 7443ad684d6Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 745dc20a302Sas200622 smb_llist_exit(&node->n_ofile_list); 746dc20a302Sas200622 return (status); 747dc20a302Sas200622 } 748dc20a302Sas200622 } 7493ad684d6Sjb150015 750dc20a302Sas200622 smb_llist_exit(&node->n_ofile_list); 751dc20a302Sas200622 return (NT_STATUS_SUCCESS); 752dc20a302Sas200622 } 753dc20a302Sas200622 754dc20a302Sas200622 uint32_t 7552c2961f8Sjose borrego smb_node_rename_check(smb_node_t *node) 756dc20a302Sas200622 { 7572c2961f8Sjose borrego smb_ofile_t *of; 7583ad684d6Sjb150015 uint32_t status; 759dc20a302Sas200622 7602c2961f8Sjose borrego SMB_NODE_VALID(node); 761dc20a302Sas200622 762dc20a302Sas200622 /* 763dc20a302Sas200622 * Intra-CIFS check 764dc20a302Sas200622 */ 765dc20a302Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 7663ad684d6Sjb150015 of = smb_llist_head(&node->n_ofile_list); 7673ad684d6Sjb150015 while (of) { 7683ad684d6Sjb150015 status = smb_ofile_rename_check(of); 769dc20a302Sas200622 7703ad684d6Sjb150015 switch (status) { 7713ad684d6Sjb150015 case NT_STATUS_INVALID_HANDLE: 7723ad684d6Sjb150015 case NT_STATUS_SUCCESS: 7733ad684d6Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 7743ad684d6Sjb150015 break; 7753ad684d6Sjb150015 default: 7763ad684d6Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 777dc20a302Sas200622 smb_llist_exit(&node->n_ofile_list); 7783ad684d6Sjb150015 return (status); 779dc20a302Sas200622 } 780dc20a302Sas200622 } 781dc20a302Sas200622 smb_llist_exit(&node->n_ofile_list); 782dc20a302Sas200622 return (NT_STATUS_SUCCESS); 783dc20a302Sas200622 } 784dc20a302Sas200622 7853ad684d6Sjb150015 uint32_t 786dc20a302Sas200622 smb_node_delete_check(smb_node_t *node) 787dc20a302Sas200622 { 7883ad684d6Sjb150015 smb_ofile_t *of; 7893ad684d6Sjb150015 uint32_t status; 790dc20a302Sas200622 7912c2961f8Sjose borrego SMB_NODE_VALID(node); 792dc20a302Sas200622 7939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_node_is_dir(node)) 794dc20a302Sas200622 return (NT_STATUS_SUCCESS); 795dc20a302Sas200622 7969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (smb_node_is_reparse(node)) 7979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (NT_STATUS_ACCESS_DENIED); 7989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 799dc20a302Sas200622 /* 800dc20a302Sas200622 * intra-CIFS check 801dc20a302Sas200622 */ 802dc20a302Sas200622 smb_llist_enter(&node->n_ofile_list, RW_READER); 8033ad684d6Sjb150015 of = smb_llist_head(&node->n_ofile_list); 8043ad684d6Sjb150015 while (of) { 8053ad684d6Sjb150015 status = smb_ofile_delete_check(of); 8063ad684d6Sjb150015 8073ad684d6Sjb150015 switch (status) { 8083ad684d6Sjb150015 case NT_STATUS_INVALID_HANDLE: 8093ad684d6Sjb150015 case NT_STATUS_SUCCESS: 8103ad684d6Sjb150015 of = smb_llist_next(&node->n_ofile_list, of); 8113ad684d6Sjb150015 break; 8123ad684d6Sjb150015 default: 8133ad684d6Sjb150015 ASSERT(status == NT_STATUS_SHARING_VIOLATION); 814dc20a302Sas200622 smb_llist_exit(&node->n_ofile_list); 8153ad684d6Sjb150015 return (status); 816dc20a302Sas200622 } 817dc20a302Sas200622 } 818dc20a302Sas200622 smb_llist_exit(&node->n_ofile_list); 819dc20a302Sas200622 return (NT_STATUS_SUCCESS); 820dc20a302Sas200622 } 821dc20a302Sas200622 822cb174861Sjoyce mcintosh /* 823cb174861Sjoyce mcintosh * smb_node_share_check 824cb174861Sjoyce mcintosh * 825cb174861Sjoyce mcintosh * Returns: TRUE - ofiles have non-zero share access 826cb174861Sjoyce mcintosh * B_FALSE - ofile with share access NONE. 827cb174861Sjoyce mcintosh */ 828cb174861Sjoyce mcintosh boolean_t 829cb174861Sjoyce mcintosh smb_node_share_check(smb_node_t *node) 830cb174861Sjoyce mcintosh { 831cb174861Sjoyce mcintosh smb_ofile_t *of; 832cb174861Sjoyce mcintosh boolean_t status = B_TRUE; 833cb174861Sjoyce mcintosh 834cb174861Sjoyce mcintosh SMB_NODE_VALID(node); 835cb174861Sjoyce mcintosh 836cb174861Sjoyce mcintosh smb_llist_enter(&node->n_ofile_list, RW_READER); 837cb174861Sjoyce mcintosh of = smb_llist_head(&node->n_ofile_list); 838cb174861Sjoyce mcintosh if (of) 839cb174861Sjoyce mcintosh status = smb_ofile_share_check(of); 840cb174861Sjoyce mcintosh smb_llist_exit(&node->n_ofile_list); 841cb174861Sjoyce mcintosh 842cb174861Sjoyce mcintosh return (status); 843cb174861Sjoyce mcintosh } 844cb174861Sjoyce mcintosh 845ccc71be5SGordon Ross /* 846ccc71be5SGordon Ross * SMB Change Notification 847ccc71be5SGordon Ross */ 848ccc71be5SGordon Ross 849b1352070SAlan Wright void 850ccc71be5SGordon Ross smb_node_fcn_subscribe(smb_node_t *node, smb_request_t *sr) 851ccc71be5SGordon Ross { 852ccc71be5SGordon Ross smb_node_fcn_t *fcn = &node->n_fcn; 853ccc71be5SGordon Ross 854ccc71be5SGordon Ross mutex_enter(&fcn->fcn_mutex); 855ccc71be5SGordon Ross if (fcn->fcn_count == 0) 8568622ec45SGordon Ross (void) smb_fem_fcn_install(node); 857ccc71be5SGordon Ross fcn->fcn_count++; 858ccc71be5SGordon Ross list_insert_tail(&fcn->fcn_watchers, sr); 859ccc71be5SGordon Ross mutex_exit(&fcn->fcn_mutex); 860ccc71be5SGordon Ross } 861ccc71be5SGordon Ross 862ccc71be5SGordon Ross void 863ccc71be5SGordon Ross smb_node_fcn_unsubscribe(smb_node_t *node, smb_request_t *sr) 864ccc71be5SGordon Ross { 865ccc71be5SGordon Ross smb_node_fcn_t *fcn = &node->n_fcn; 866ccc71be5SGordon Ross 867ccc71be5SGordon Ross mutex_enter(&fcn->fcn_mutex); 868ccc71be5SGordon Ross list_remove(&fcn->fcn_watchers, sr); 869ccc71be5SGordon Ross fcn->fcn_count--; 870ccc71be5SGordon Ross if (fcn->fcn_count == 0) 871ccc71be5SGordon Ross smb_fem_fcn_uninstall(node); 872ccc71be5SGordon Ross mutex_exit(&fcn->fcn_mutex); 873ccc71be5SGordon Ross } 874ccc71be5SGordon Ross 875ccc71be5SGordon Ross void 876ccc71be5SGordon Ross smb_node_notify_change(smb_node_t *node, uint_t action, const char *name) 877b1352070SAlan Wright { 878b1352070SAlan Wright SMB_NODE_VALID(node); 879b1352070SAlan Wright 880ccc71be5SGordon Ross smb_notify_event(node, action, name); 881ccc71be5SGordon Ross 882ccc71be5SGordon Ross /* 883ccc71be5SGordon Ross * These two events come as a pair: 884ccc71be5SGordon Ross * FILE_ACTION_RENAMED_OLD_NAME 885ccc71be5SGordon Ross * FILE_ACTION_RENAMED_NEW_NAME 886ccc71be5SGordon Ross * Only do the parent notify for "new". 887ccc71be5SGordon Ross */ 888ccc71be5SGordon Ross if (action == FILE_ACTION_RENAMED_OLD_NAME) 889ccc71be5SGordon Ross return; 8909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 8919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_notify_parents(node); 892b1352070SAlan Wright } 893b1352070SAlan Wright 8949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 8959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * smb_node_notify_parents 8969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * 8979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Iterate up the directory tree notifying any parent 8989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * directories that are being watched for changes in 8999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * their sub directories. 9009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Stop at the root node, which has a NULL parent node. 9019fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 9029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void 9039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_notify_parents(smb_node_t *dnode) 904fe1c642dSBill Krier { 905ccc71be5SGordon Ross smb_node_t *pnode; /* parent */ 906fe1c642dSBill Krier 9079fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_NODE_VALID(dnode); 908ccc71be5SGordon Ross pnode = dnode->n_dnode; 9099fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 910ccc71be5SGordon Ross while (pnode != NULL) { 9119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_NODE_VALID(pnode); 912*a90cf9f2SGordon Ross smb_notify_event(pnode, FILE_ACTION_SUBDIR_CHANGED, NULL); 913ccc71be5SGordon Ross /* cd .. */ 914ccc71be5SGordon Ross dnode = pnode; 915ccc71be5SGordon Ross pnode = dnode->n_dnode; 9169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 917fe1c642dSBill Krier } 918fe1c642dSBill Krier 919dc20a302Sas200622 /* 920dc20a302Sas200622 * smb_node_start_crit() 921dc20a302Sas200622 * 922dc20a302Sas200622 * Enter critical region for share reservations. 923dc20a302Sas200622 * See comments above smb_fsop_shrlock(). 924dc20a302Sas200622 */ 925dc20a302Sas200622 void 926dc20a302Sas200622 smb_node_start_crit(smb_node_t *node, krw_t mode) 927dc20a302Sas200622 { 9282c2961f8Sjose borrego rw_enter(&node->n_lock, mode); 929dc20a302Sas200622 nbl_start_crit(node->vp, mode); 930dc20a302Sas200622 } 931dc20a302Sas200622 932dc20a302Sas200622 /* 933dc20a302Sas200622 * smb_node_end_crit() 934dc20a302Sas200622 * 935dc20a302Sas200622 * Exit critical region for share reservations. 936dc20a302Sas200622 */ 937dc20a302Sas200622 void 938dc20a302Sas200622 smb_node_end_crit(smb_node_t *node) 939dc20a302Sas200622 { 940dc20a302Sas200622 nbl_end_crit(node->vp); 9412c2961f8Sjose borrego rw_exit(&node->n_lock); 942dc20a302Sas200622 } 943dc20a302Sas200622 944dc20a302Sas200622 int 945dc20a302Sas200622 smb_node_in_crit(smb_node_t *node) 946dc20a302Sas200622 { 9472c2961f8Sjose borrego return (nbl_in_crit(node->vp) && RW_LOCK_HELD(&node->n_lock)); 9482c2961f8Sjose borrego } 9492c2961f8Sjose borrego 9502c2961f8Sjose borrego void 9512c2961f8Sjose borrego smb_node_rdlock(smb_node_t *node) 9522c2961f8Sjose borrego { 9532c2961f8Sjose borrego rw_enter(&node->n_lock, RW_READER); 9542c2961f8Sjose borrego } 9552c2961f8Sjose borrego 9562c2961f8Sjose borrego void 9572c2961f8Sjose borrego smb_node_wrlock(smb_node_t *node) 9582c2961f8Sjose borrego { 9592c2961f8Sjose borrego rw_enter(&node->n_lock, RW_WRITER); 9602c2961f8Sjose borrego } 9612c2961f8Sjose borrego 9622c2961f8Sjose borrego void 9632c2961f8Sjose borrego smb_node_unlock(smb_node_t *node) 9642c2961f8Sjose borrego { 9652c2961f8Sjose borrego rw_exit(&node->n_lock); 9662c2961f8Sjose borrego } 9672c2961f8Sjose borrego 9682c2961f8Sjose borrego void 9692c2961f8Sjose borrego smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of) 9702c2961f8Sjose borrego { 9712c2961f8Sjose borrego SMB_NODE_VALID(node); 9722c2961f8Sjose borrego 9732c2961f8Sjose borrego smb_llist_enter(&node->n_ofile_list, RW_WRITER); 9742c2961f8Sjose borrego smb_llist_insert_tail(&node->n_ofile_list, of); 9752c2961f8Sjose borrego smb_llist_exit(&node->n_ofile_list); 9762c2961f8Sjose borrego } 9772c2961f8Sjose borrego 9782c2961f8Sjose borrego void 9792c2961f8Sjose borrego smb_node_rem_ofile(smb_node_t *node, smb_ofile_t *of) 9802c2961f8Sjose borrego { 9812c2961f8Sjose borrego SMB_NODE_VALID(node); 9822c2961f8Sjose borrego 9832c2961f8Sjose borrego smb_llist_enter(&node->n_ofile_list, RW_WRITER); 9842c2961f8Sjose borrego smb_llist_remove(&node->n_ofile_list, of); 9852c2961f8Sjose borrego smb_llist_exit(&node->n_ofile_list); 9862c2961f8Sjose borrego } 9872c2961f8Sjose borrego 988037cac00Sjoyce mcintosh /* 989037cac00Sjoyce mcintosh * smb_node_inc_open_ofiles 990037cac00Sjoyce mcintosh */ 9912c2961f8Sjose borrego void 9922c2961f8Sjose borrego smb_node_inc_open_ofiles(smb_node_t *node) 9932c2961f8Sjose borrego { 9942c2961f8Sjose borrego SMB_NODE_VALID(node); 9955fd03bc0SGordon Ross atomic_inc_32(&node->n_open_count); 9962c2961f8Sjose borrego } 9972c2961f8Sjose borrego 998037cac00Sjoyce mcintosh /* 999037cac00Sjoyce mcintosh * smb_node_dec_open_ofiles 10005fd03bc0SGordon Ross * returns new value 1001037cac00Sjoyce mcintosh */ 10025fd03bc0SGordon Ross uint32_t 10032c2961f8Sjose borrego smb_node_dec_open_ofiles(smb_node_t *node) 10042c2961f8Sjose borrego { 10052c2961f8Sjose borrego SMB_NODE_VALID(node); 10065fd03bc0SGordon Ross return (atomic_dec_32_nv(&node->n_open_count)); 10072c2961f8Sjose borrego } 10082c2961f8Sjose borrego 1009cb174861Sjoyce mcintosh /* 1010cb174861Sjoyce mcintosh * smb_node_inc_opening_count 1011cb174861Sjoyce mcintosh */ 1012cb174861Sjoyce mcintosh void 1013cb174861Sjoyce mcintosh smb_node_inc_opening_count(smb_node_t *node) 10142c2961f8Sjose borrego { 10152c2961f8Sjose borrego SMB_NODE_VALID(node); 10165fd03bc0SGordon Ross atomic_inc_32(&node->n_opening_count); 1017cb174861Sjoyce mcintosh } 1018cb174861Sjoyce mcintosh 1019cb174861Sjoyce mcintosh /* 1020cb174861Sjoyce mcintosh * smb_node_dec_opening_count 1021cb174861Sjoyce mcintosh */ 1022cb174861Sjoyce mcintosh void 1023cb174861Sjoyce mcintosh smb_node_dec_opening_count(smb_node_t *node) 1024cb174861Sjoyce mcintosh { 1025cb174861Sjoyce mcintosh SMB_NODE_VALID(node); 10265fd03bc0SGordon Ross atomic_dec_32(&node->n_opening_count); 10272c2961f8Sjose borrego } 10282c2961f8Sjose borrego 10292c2961f8Sjose borrego /* 10309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * smb_node_getmntpath 10319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 10329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States int 10339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_getmntpath(smb_node_t *node, char *buf, uint32_t buflen) 10349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 10359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States vnode_t *vp, *root_vp; 10369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States vfs_t *vfsp; 10379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States int err; 10389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 10399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(node); 10409fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(node->vp); 10419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ASSERT(node->vp->v_vfsp); 10429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 10439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States vp = node->vp; 10449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States vfsp = vp->v_vfsp; 10459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 10469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (VFS_ROOT(vfsp, &root_vp)) 10479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (ENOENT); 10489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 10499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States VN_HOLD(vp); 10509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 10519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* NULL is passed in as we want to start at "/" */ 10528622ec45SGordon Ross err = vnodetopath(NULL, root_vp, buf, buflen, zone_kcred()); 10539fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 10549fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States VN_RELE(vp); 10559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States VN_RELE(root_vp); 10569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (err); 10579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 10589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 10599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 10609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * smb_node_getshrpath 10619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * 10629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Determine the absolute pathname of 'node' within the share (tree). 10639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * For example if the node represents file "test1.txt" in directory 10649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * "dir1" the pathname would be: \dir1\test1.txt 10659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 10669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States int 10679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_getshrpath(smb_node_t *node, smb_tree_t *tree, 10689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States char *buf, uint32_t buflen) 10699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 10709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States int rc; 10719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1072c5866007SKeyur Desai ASSERT(node); 1073c5866007SKeyur Desai ASSERT(tree); 1074c5866007SKeyur Desai ASSERT(tree->t_snode); 10759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1076c5866007SKeyur Desai rc = smb_node_getpath(node, tree->t_snode->vp, buf, buflen); 10779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) strsubst(buf, '/', '\\'); 1078c5866007SKeyur Desai return (rc); 1079c5866007SKeyur Desai } 10809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1081c5866007SKeyur Desai /* 1082c5866007SKeyur Desai * smb_node_getpath 1083c5866007SKeyur Desai * 1084c5866007SKeyur Desai * Determine the absolute pathname of 'node' from 'rootvp'. 1085c5866007SKeyur Desai * 1086c5866007SKeyur Desai * Using vnodetopath is only reliable for directory nodes (due to 1087c5866007SKeyur Desai * its reliance on the DNLC for non-directory nodes). Thus, if node 1088c5866007SKeyur Desai * represents a file, construct the pathname for the parent dnode 1089c5866007SKeyur Desai * and append filename. 1090c5866007SKeyur Desai * If node represents a named stream, construct the pathname for the 1091c5866007SKeyur Desai * associated unnamed stream and append the stream name. 1092c5866007SKeyur Desai * 1093c5866007SKeyur Desai * The pathname returned in buf will be '/' separated. 1094c5866007SKeyur Desai */ 1095c5866007SKeyur Desai int 1096c5866007SKeyur Desai smb_node_getpath(smb_node_t *node, vnode_t *rootvp, char *buf, uint32_t buflen) 1097c5866007SKeyur Desai { 1098c5866007SKeyur Desai int rc; 1099c5866007SKeyur Desai vnode_t *vp; 1100c5866007SKeyur Desai smb_node_t *unode, *dnode; 11018622ec45SGordon Ross cred_t *kcr = zone_kcred(); 1102c5866007SKeyur Desai 1103c5866007SKeyur Desai unode = (SMB_IS_STREAM(node)) ? node->n_unode : node; 1104c5866007SKeyur Desai dnode = (smb_node_is_dir(unode)) ? unode : unode->n_dnode; 1105c5866007SKeyur Desai 1106c5866007SKeyur Desai /* find path to directory node */ 1107c5866007SKeyur Desai vp = dnode->vp; 1108c5866007SKeyur Desai VN_HOLD(vp); 1109c5866007SKeyur Desai if (rootvp) { 1110c5866007SKeyur Desai VN_HOLD(rootvp); 11118622ec45SGordon Ross rc = vnodetopath(rootvp, vp, buf, buflen, kcr); 1112c5866007SKeyur Desai VN_RELE(rootvp); 1113c5866007SKeyur Desai } else { 11148622ec45SGordon Ross rc = vnodetopath(NULL, vp, buf, buflen, kcr); 1115c5866007SKeyur Desai } 1116c5866007SKeyur Desai VN_RELE(vp); 1117c5866007SKeyur Desai 1118c5866007SKeyur Desai if (rc != 0) 1119c5866007SKeyur Desai return (rc); 1120c5866007SKeyur Desai 1121c5866007SKeyur Desai /* append filename if necessary */ 1122c5866007SKeyur Desai if (!smb_node_is_dir(unode)) { 1123c5866007SKeyur Desai if (buf[strlen(buf) - 1] != '/') 1124c5866007SKeyur Desai (void) strlcat(buf, "/", buflen); 1125c5866007SKeyur Desai (void) strlcat(buf, unode->od_name, buflen); 1126c5866007SKeyur Desai } 1127c5866007SKeyur Desai 1128c5866007SKeyur Desai /* append named stream name if necessary */ 11299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (SMB_IS_STREAM(node)) 11309fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (void) strlcat(buf, node->od_name, buflen); 11319fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 11329fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (rc); 11339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 11349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 11359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 11362c2961f8Sjose borrego * smb_node_alloc 11372c2961f8Sjose borrego */ 11382c2961f8Sjose borrego static smb_node_t * 11392c2961f8Sjose borrego smb_node_alloc( 11402c2961f8Sjose borrego char *od_name, 11412c2961f8Sjose borrego vnode_t *vp, 11422c2961f8Sjose borrego smb_llist_t *bucket, 11432c2961f8Sjose borrego uint32_t hashkey) 11442c2961f8Sjose borrego { 11452c2961f8Sjose borrego smb_node_t *node; 11469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States vnode_t *root_vp; 11472c2961f8Sjose borrego 11482c2961f8Sjose borrego node = kmem_cache_alloc(smb_node_cache, KM_SLEEP); 11492c2961f8Sjose borrego 11502c2961f8Sjose borrego if (node->n_audit_buf != NULL) 11512c2961f8Sjose borrego node->n_audit_buf->anb_index = 0; 11522c2961f8Sjose borrego 1153037cac00Sjoyce mcintosh node->flags = 0; 11542c2961f8Sjose borrego VN_HOLD(vp); 11552c2961f8Sjose borrego node->vp = vp; 11562c2961f8Sjose borrego node->n_refcnt = 1; 11572c2961f8Sjose borrego node->n_hash_bucket = bucket; 11582c2961f8Sjose borrego node->n_hashkey = hashkey; 11595fd03bc0SGordon Ross node->n_pending_dosattr = 0; 11602c2961f8Sjose borrego node->n_open_count = 0; 11615fd03bc0SGordon Ross node->n_allocsz = 0; 11621fcced4cSJordan Brown node->n_dnode = NULL; 11631fcced4cSJordan Brown node->n_unode = NULL; 11642c2961f8Sjose borrego node->delete_on_close_cred = NULL; 11658b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States node->n_delete_on_close_flags = 0; 1166cb174861Sjoyce mcintosh node->n_oplock.ol_fem = B_FALSE; 1167cb174861Sjoyce mcintosh node->n_oplock.ol_xthread = NULL; 1168cb174861Sjoyce mcintosh node->n_oplock.ol_count = 0; 1169cb174861Sjoyce mcintosh node->n_oplock.ol_break = SMB_OPLOCK_NO_BREAK; 11702c2961f8Sjose borrego 11712c2961f8Sjose borrego (void) strlcpy(node->od_name, od_name, sizeof (node->od_name)); 11722c2961f8Sjose borrego if (strcmp(od_name, XATTR_DIR) == 0) 11732c2961f8Sjose borrego node->flags |= NODE_XATTR_DIR; 11742c2961f8Sjose borrego 11759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (VFS_ROOT(vp->v_vfsp, &root_vp) == 0) { 11769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (vp == root_vp) 11779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States node->flags |= NODE_FLAGS_VFSROOT; 11789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States VN_RELE(root_vp); 11799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 11809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 11812c2961f8Sjose borrego node->n_state = SMB_NODE_STATE_AVAILABLE; 11822c2961f8Sjose borrego node->n_magic = SMB_NODE_MAGIC; 11839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 11842c2961f8Sjose borrego return (node); 11852c2961f8Sjose borrego } 11862c2961f8Sjose borrego 11872c2961f8Sjose borrego /* 11882c2961f8Sjose borrego * smb_node_free 11892c2961f8Sjose borrego */ 11902c2961f8Sjose borrego static void 11912c2961f8Sjose borrego smb_node_free(smb_node_t *node) 11922c2961f8Sjose borrego { 11932c2961f8Sjose borrego SMB_NODE_VALID(node); 11942c2961f8Sjose borrego 11952c2961f8Sjose borrego node->n_magic = 0; 11962c2961f8Sjose borrego VERIFY(!list_link_active(&node->n_lnd)); 11972c2961f8Sjose borrego VERIFY(node->n_lock_list.ll_count == 0); 11982c2961f8Sjose borrego VERIFY(node->n_ofile_list.ll_count == 0); 1199cb174861Sjoyce mcintosh VERIFY(node->n_oplock.ol_count == 0); 12002c2961f8Sjose borrego VERIFY(node->n_oplock.ol_xthread == NULL); 1201cb174861Sjoyce mcintosh VERIFY(node->n_oplock.ol_fem == B_FALSE); 1202b819cea2SGordon Ross VERIFY(MUTEX_NOT_HELD(&node->n_mutex)); 1203fc724630SAlan Wright VERIFY(!RW_LOCK_HELD(&node->n_lock)); 12042c2961f8Sjose borrego VN_RELE(node->vp); 12052c2961f8Sjose borrego kmem_cache_free(smb_node_cache, node); 12062c2961f8Sjose borrego } 12072c2961f8Sjose borrego 12082c2961f8Sjose borrego /* 12092c2961f8Sjose borrego * smb_node_constructor 12102c2961f8Sjose borrego */ 12112c2961f8Sjose borrego static int 12122c2961f8Sjose borrego smb_node_constructor(void *buf, void *un, int kmflags) 12132c2961f8Sjose borrego { 12142c2961f8Sjose borrego _NOTE(ARGUNUSED(kmflags, un)) 12152c2961f8Sjose borrego 12162c2961f8Sjose borrego smb_node_t *node = (smb_node_t *)buf; 12172c2961f8Sjose borrego 12182c2961f8Sjose borrego bzero(node, sizeof (smb_node_t)); 12192c2961f8Sjose borrego 12202c2961f8Sjose borrego smb_llist_constructor(&node->n_ofile_list, sizeof (smb_ofile_t), 12212c2961f8Sjose borrego offsetof(smb_ofile_t, f_nnd)); 12222c2961f8Sjose borrego smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), 12232c2961f8Sjose borrego offsetof(smb_lock_t, l_lnd)); 1224ccc71be5SGordon Ross mutex_init(&node->n_fcn.fcn_mutex, NULL, MUTEX_DEFAULT, NULL); 1225ccc71be5SGordon Ross list_create(&node->n_fcn.fcn_watchers, sizeof (smb_request_t), 1226ccc71be5SGordon Ross offsetof(smb_request_t, sr_ncr.nc_lnd)); 12272c2961f8Sjose borrego cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL); 1228cb174861Sjoyce mcintosh mutex_init(&node->n_oplock.ol_mutex, NULL, MUTEX_DEFAULT, NULL); 1229cb174861Sjoyce mcintosh list_create(&node->n_oplock.ol_grants, sizeof (smb_oplock_grant_t), 1230cb174861Sjoyce mcintosh offsetof(smb_oplock_grant_t, og_lnd)); 12312c2961f8Sjose borrego rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL); 12322c2961f8Sjose borrego mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL); 12332c2961f8Sjose borrego smb_node_create_audit_buf(node, kmflags); 12342c2961f8Sjose borrego return (0); 12352c2961f8Sjose borrego } 12362c2961f8Sjose borrego 12372c2961f8Sjose borrego /* 12382c2961f8Sjose borrego * smb_node_destructor 12392c2961f8Sjose borrego */ 12402c2961f8Sjose borrego static void 12412c2961f8Sjose borrego smb_node_destructor(void *buf, void *un) 12422c2961f8Sjose borrego { 12432c2961f8Sjose borrego _NOTE(ARGUNUSED(un)) 12442c2961f8Sjose borrego 12452c2961f8Sjose borrego smb_node_t *node = (smb_node_t *)buf; 12462c2961f8Sjose borrego 12472c2961f8Sjose borrego smb_node_destroy_audit_buf(node); 12482c2961f8Sjose borrego mutex_destroy(&node->n_mutex); 12492c2961f8Sjose borrego rw_destroy(&node->n_lock); 12502c2961f8Sjose borrego cv_destroy(&node->n_oplock.ol_cv); 1251cb174861Sjoyce mcintosh mutex_destroy(&node->n_oplock.ol_mutex); 1252ccc71be5SGordon Ross list_destroy(&node->n_fcn.fcn_watchers); 1253ccc71be5SGordon Ross mutex_destroy(&node->n_fcn.fcn_mutex); 12542c2961f8Sjose borrego smb_llist_destructor(&node->n_lock_list); 12552c2961f8Sjose borrego smb_llist_destructor(&node->n_ofile_list); 1256cb174861Sjoyce mcintosh list_destroy(&node->n_oplock.ol_grants); 12572c2961f8Sjose borrego } 12582c2961f8Sjose borrego 12592c2961f8Sjose borrego /* 12602c2961f8Sjose borrego * smb_node_create_audit_buf 12612c2961f8Sjose borrego */ 12622c2961f8Sjose borrego static void 12632c2961f8Sjose borrego smb_node_create_audit_buf(smb_node_t *node, int kmflags) 12642c2961f8Sjose borrego { 12652c2961f8Sjose borrego smb_audit_buf_node_t *abn; 12662c2961f8Sjose borrego 12672c2961f8Sjose borrego if (smb_audit_flags & SMB_AUDIT_NODE) { 12682c2961f8Sjose borrego abn = kmem_zalloc(sizeof (smb_audit_buf_node_t), kmflags); 12692c2961f8Sjose borrego abn->anb_max_index = SMB_AUDIT_BUF_MAX_REC - 1; 12702c2961f8Sjose borrego node->n_audit_buf = abn; 12712c2961f8Sjose borrego } 12722c2961f8Sjose borrego } 12732c2961f8Sjose borrego 12742c2961f8Sjose borrego /* 12752c2961f8Sjose borrego * smb_node_destroy_audit_buf 12762c2961f8Sjose borrego */ 12772c2961f8Sjose borrego static void 12782c2961f8Sjose borrego smb_node_destroy_audit_buf(smb_node_t *node) 12792c2961f8Sjose borrego { 12802c2961f8Sjose borrego if (node->n_audit_buf != NULL) { 12812c2961f8Sjose borrego kmem_free(node->n_audit_buf, sizeof (smb_audit_buf_node_t)); 12822c2961f8Sjose borrego node->n_audit_buf = NULL; 12832c2961f8Sjose borrego } 12842c2961f8Sjose borrego } 12852c2961f8Sjose borrego 12862c2961f8Sjose borrego /* 12872c2961f8Sjose borrego * smb_node_audit 12882c2961f8Sjose borrego * 12892c2961f8Sjose borrego * This function saves the calling stack in the audit buffer of the node passed 12902c2961f8Sjose borrego * in. 12912c2961f8Sjose borrego */ 12922c2961f8Sjose borrego static void 12932c2961f8Sjose borrego smb_node_audit(smb_node_t *node) 12942c2961f8Sjose borrego { 1295b819cea2SGordon Ross #ifdef _KERNEL 12962c2961f8Sjose borrego smb_audit_buf_node_t *abn; 12972c2961f8Sjose borrego smb_audit_record_node_t *anr; 12982c2961f8Sjose borrego 12992c2961f8Sjose borrego if (node->n_audit_buf) { 13002c2961f8Sjose borrego abn = node->n_audit_buf; 13012c2961f8Sjose borrego anr = abn->anb_records; 13022c2961f8Sjose borrego anr += abn->anb_index; 13032c2961f8Sjose borrego abn->anb_index++; 13042c2961f8Sjose borrego abn->anb_index &= abn->anb_max_index; 13052c2961f8Sjose borrego anr->anr_refcnt = node->n_refcnt; 13062c2961f8Sjose borrego anr->anr_depth = getpcstack(anr->anr_stack, 13072c2961f8Sjose borrego SMB_AUDIT_STACK_DEPTH); 13082c2961f8Sjose borrego } 1309b819cea2SGordon Ross #else /* _KERNEL */ 1310b819cea2SGordon Ross _NOTE(ARGUNUSED(node)) 1311b819cea2SGordon Ross #endif /* _KERNEL */ 13122c2961f8Sjose borrego } 13132c2961f8Sjose borrego 13142c2961f8Sjose borrego static smb_llist_t * 13152c2961f8Sjose borrego smb_node_get_hash(fsid_t *fsid, smb_attr_t *attr, uint32_t *phashkey) 13162c2961f8Sjose borrego { 13172c2961f8Sjose borrego uint32_t hashkey; 13182c2961f8Sjose borrego 13192c2961f8Sjose borrego hashkey = fsid->val[0] + attr->sa_vattr.va_nodeid; 13202c2961f8Sjose borrego hashkey += (hashkey >> 24) + (hashkey >> 16) + (hashkey >> 8); 13212c2961f8Sjose borrego *phashkey = hashkey; 13222c2961f8Sjose borrego return (&smb_node_hash_table[(hashkey & SMBND_HASH_MASK)]); 1323dc20a302Sas200622 } 1324037cac00Sjoyce mcintosh 1325037cac00Sjoyce mcintosh boolean_t 13269fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_file(smb_node_t *node) 1327037cac00Sjoyce mcintosh { 1328037cac00Sjoyce mcintosh SMB_NODE_VALID(node); 13299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return (node->vp->v_type == VREG); 1330037cac00Sjoyce mcintosh } 1331037cac00Sjoyce mcintosh 1332037cac00Sjoyce mcintosh boolean_t 13339fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_dir(smb_node_t *node) 1334037cac00Sjoyce mcintosh { 1335037cac00Sjoyce mcintosh SMB_NODE_VALID(node); 13369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return ((node->vp->v_type == VDIR) || 13379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (node->flags & NODE_FLAGS_DFSLINK)); 13389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 13399fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 13409fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States boolean_t 13419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_symlink(smb_node_t *node) 13429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 13439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_NODE_VALID(node); 13449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return ((node->vp->v_type == VLNK) && 13459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States ((node->flags & NODE_FLAGS_REPARSE) == 0)); 13469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 13479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 13489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States boolean_t 13499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_dfslink(smb_node_t *node) 13509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 13519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_NODE_VALID(node); 13529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return ((node->vp->v_type == VLNK) && 13539fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (node->flags & NODE_FLAGS_DFSLINK)); 13549fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 13559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 13569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States boolean_t 13579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_reparse(smb_node_t *node) 13589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 13599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_NODE_VALID(node); 13609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return ((node->vp->v_type == VLNK) && 13619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (node->flags & NODE_FLAGS_REPARSE)); 13629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 13639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 13649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States boolean_t 13659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_vfsroot(smb_node_t *node) 13669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 13679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_NODE_VALID(node); 13689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return ((node->flags & NODE_FLAGS_VFSROOT) == NODE_FLAGS_VFSROOT); 13699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 13709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 13719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States boolean_t 13729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_is_system(smb_node_t *node) 13739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 13749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States SMB_NODE_VALID(node); 13759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return ((node->flags & NODE_FLAGS_SYSTEM) == NODE_FLAGS_SYSTEM); 1376037cac00Sjoyce mcintosh } 1377037cac00Sjoyce mcintosh 1378037cac00Sjoyce mcintosh /* 1379037cac00Sjoyce mcintosh * smb_node_file_is_readonly 1380037cac00Sjoyce mcintosh * 1381037cac00Sjoyce mcintosh * Checks if the file (which node represents) is marked readonly 1382037cac00Sjoyce mcintosh * in the filesystem. No account is taken of any pending readonly 1383037cac00Sjoyce mcintosh * in the node, which must be handled by the callers. 1384037cac00Sjoyce mcintosh * (See SMB_OFILE_IS_READONLY and SMB_PATHFILE_IS_READONLY) 1385037cac00Sjoyce mcintosh */ 1386037cac00Sjoyce mcintosh boolean_t 1387037cac00Sjoyce mcintosh smb_node_file_is_readonly(smb_node_t *node) 1388037cac00Sjoyce mcintosh { 1389037cac00Sjoyce mcintosh smb_attr_t attr; 1390037cac00Sjoyce mcintosh 1391037cac00Sjoyce mcintosh if (node == NULL) 13925fd03bc0SGordon Ross return (B_FALSE); /* pipes */ 13935fd03bc0SGordon Ross 13945fd03bc0SGordon Ross if (node->n_pending_dosattr & FILE_ATTRIBUTE_READONLY) 13955fd03bc0SGordon Ross return (B_TRUE); 1396037cac00Sjoyce mcintosh 1397037cac00Sjoyce mcintosh bzero(&attr, sizeof (smb_attr_t)); 1398037cac00Sjoyce mcintosh attr.sa_mask = SMB_AT_DOSATTR; 13998622ec45SGordon Ross (void) smb_fsop_getattr(NULL, zone_kcred(), node, &attr); 1400037cac00Sjoyce mcintosh return ((attr.sa_dosattr & FILE_ATTRIBUTE_READONLY) != 0); 1401037cac00Sjoyce mcintosh } 1402037cac00Sjoyce mcintosh 1403037cac00Sjoyce mcintosh /* 1404037cac00Sjoyce mcintosh * smb_node_setattr 1405037cac00Sjoyce mcintosh * 1406037cac00Sjoyce mcintosh * The sr may be NULL, for example when closing an ofile. 1407037cac00Sjoyce mcintosh * The ofile may be NULL, for example when a client request 1408037cac00Sjoyce mcintosh * specifies the file by pathname. 1409037cac00Sjoyce mcintosh * 14105fd03bc0SGordon Ross * Returns: errno 14115fd03bc0SGordon Ross * 1412e3f2c991SKeyur Desai * Timestamps 1413037cac00Sjoyce mcintosh * 14145fd03bc0SGordon Ross * Windows and Unix have different models for timestamp updates. 14155fd03bc0SGordon Ross * [MS-FSA 2.1.5.14 Server Requests Setting of File Information] 1416037cac00Sjoyce mcintosh * 14175fd03bc0SGordon Ross * An open "handle" in Windows can control whether and when 14185fd03bc0SGordon Ross * any timestamp updates happen for that handle. For example, 14195fd03bc0SGordon Ross * timestamps set via some handle are no longer updated by I/O 14205fd03bc0SGordon Ross * operations on that handle. In Unix we don't really have any 14215fd03bc0SGordon Ross * way to avoid the timestamp updates that the file system does. 14225fd03bc0SGordon Ross * Therefore, we need to make some compromises, and simulate the 14235fd03bc0SGordon Ross * more important parts of the Windows file system semantics. 1424037cac00Sjoyce mcintosh * 14255fd03bc0SGordon Ross * For example, when an SMB client sets file times, set those 14265fd03bc0SGordon Ross * times in the file system (so the change will be visible to 14275fd03bc0SGordon Ross * other clients, at least until they change again) but we also 14285fd03bc0SGordon Ross * make those times "sticky" in our open handle, and reapply 14295fd03bc0SGordon Ross * those times when the handle is closed. That reapply on close 14305fd03bc0SGordon Ross * simulates the Windows behavior where the timestamp updates 14315fd03bc0SGordon Ross * would be discontinued after they were set. These "sticky" 14325fd03bc0SGordon Ross * attributes are returned in any query on the handle where 14335fd03bc0SGordon Ross * they are stored. 14345fd03bc0SGordon Ross * 14355fd03bc0SGordon Ross * Other than the above, the file system layer takes care of the 14365fd03bc0SGordon Ross * normal time stamp updates, such as updating the mtime after a 14375fd03bc0SGordon Ross * write, and ctime after an attribute change. 14385fd03bc0SGordon Ross * 14395fd03bc0SGordon Ross * Dos Attributes are stored persistently, but with a twist: 14405fd03bc0SGordon Ross * In Windows, when you set the "read-only" bit on some file, 14415fd03bc0SGordon Ross * existing writable handles to that file continue to have 14425fd03bc0SGordon Ross * write access. (because access check happens at open) 14435fd03bc0SGordon Ross * If we were to set the read-only bit directly, we would 14445fd03bc0SGordon Ross * cause errors in subsequent writes on any of our open 14455fd03bc0SGordon Ross * (and writable) file handles. So here too, we have to 14465fd03bc0SGordon Ross * simulate the Windows behavior. We keep the read-only 14475fd03bc0SGordon Ross * bit "pending" in the smb_node (so it will be visible in 14485fd03bc0SGordon Ross * any new opens of the file) and apply it on close. 14495fd03bc0SGordon Ross * 14505fd03bc0SGordon Ross * File allocation size is also simulated, and not persistent. 1451e3f2c991SKeyur Desai * When the file allocation size is set it is first rounded up 1452e3f2c991SKeyur Desai * to block size. If the file size is smaller than the allocation 1453e3f2c991SKeyur Desai * size the file is truncated by setting the filesize to allocsz. 1454037cac00Sjoyce mcintosh */ 1455037cac00Sjoyce mcintosh int 1456037cac00Sjoyce mcintosh smb_node_setattr(smb_request_t *sr, smb_node_t *node, 1457037cac00Sjoyce mcintosh cred_t *cr, smb_ofile_t *of, smb_attr_t *attr) 1458037cac00Sjoyce mcintosh { 1459037cac00Sjoyce mcintosh int rc; 14605fd03bc0SGordon Ross uint_t times_mask; 1461e3f2c991SKeyur Desai smb_attr_t tmp_attr; 1462037cac00Sjoyce mcintosh 1463037cac00Sjoyce mcintosh SMB_NODE_VALID(node); 1464037cac00Sjoyce mcintosh 1465e3f2c991SKeyur Desai /* set attributes specified in attr */ 14665fd03bc0SGordon Ross if (attr->sa_mask == 0) 14675fd03bc0SGordon Ross return (0); /* nothing to do (caller bug?) */ 1468037cac00Sjoyce mcintosh 14695fd03bc0SGordon Ross /* 14705fd03bc0SGordon Ross * Allocation size and EOF position interact. 14715fd03bc0SGordon Ross * We don't persistently store the allocation size 14725fd03bc0SGordon Ross * but make it look like we do while there are opens. 14735fd03bc0SGordon Ross * Note: We update the caller's attr in the cases 14745fd03bc0SGordon Ross * where they're setting only one of allocsz|size. 14755fd03bc0SGordon Ross */ 14765fd03bc0SGordon Ross switch (attr->sa_mask & (SMB_AT_ALLOCSZ | SMB_AT_SIZE)) { 14775fd03bc0SGordon Ross 14785fd03bc0SGordon Ross case SMB_AT_ALLOCSZ: 14795fd03bc0SGordon Ross /* 14805fd03bc0SGordon Ross * Setting the allocation size but not EOF position. 14815fd03bc0SGordon Ross * Get the current EOF in tmp_attr and (if necessary) 14825fd03bc0SGordon Ross * truncate to the (rounded up) allocation size. 14838622ec45SGordon Ross * Using kcred here because if we don't have access, 14848622ec45SGordon Ross * we want to fail at setattr below and not here. 14855fd03bc0SGordon Ross */ 1486e3f2c991SKeyur Desai bzero(&tmp_attr, sizeof (smb_attr_t)); 1487e3f2c991SKeyur Desai tmp_attr.sa_mask = SMB_AT_SIZE; 14888622ec45SGordon Ross rc = smb_fsop_getattr(NULL, zone_kcred(), node, &tmp_attr); 14895fd03bc0SGordon Ross if (rc != 0) 14905fd03bc0SGordon Ross return (rc); 14915fd03bc0SGordon Ross attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_allocsz); 1492e3f2c991SKeyur Desai if (tmp_attr.sa_vattr.va_size > attr->sa_allocsz) { 14935fd03bc0SGordon Ross /* truncate the file to allocsz */ 1494e3f2c991SKeyur Desai attr->sa_vattr.va_size = attr->sa_allocsz; 1495e3f2c991SKeyur Desai attr->sa_mask |= SMB_AT_SIZE; 1496037cac00Sjoyce mcintosh } 14975fd03bc0SGordon Ross break; 1498037cac00Sjoyce mcintosh 14995fd03bc0SGordon Ross case SMB_AT_SIZE: 15005fd03bc0SGordon Ross /* 15015fd03bc0SGordon Ross * Setting the EOF position but not allocation size. 15025fd03bc0SGordon Ross * If the new EOF position would be greater than 15035fd03bc0SGordon Ross * the allocation size, increase the latter. 15045fd03bc0SGordon Ross */ 15055fd03bc0SGordon Ross if (node->n_allocsz < attr->sa_vattr.va_size) { 15065fd03bc0SGordon Ross attr->sa_mask |= SMB_AT_ALLOCSZ; 15075fd03bc0SGordon Ross attr->sa_allocsz = 15085fd03bc0SGordon Ross SMB_ALLOCSZ(attr->sa_vattr.va_size); 1509e3f2c991SKeyur Desai } 15105fd03bc0SGordon Ross break; 15115fd03bc0SGordon Ross 15125fd03bc0SGordon Ross case SMB_AT_ALLOCSZ | SMB_AT_SIZE: 15135fd03bc0SGordon Ross /* 15145fd03bc0SGordon Ross * Setting both. Increase alloc size if needed. 15155fd03bc0SGordon Ross */ 15165fd03bc0SGordon Ross if (attr->sa_allocsz < attr->sa_vattr.va_size) 15175fd03bc0SGordon Ross attr->sa_allocsz = 15185fd03bc0SGordon Ross SMB_ALLOCSZ(attr->sa_vattr.va_size); 15195fd03bc0SGordon Ross break; 15205fd03bc0SGordon Ross 15215fd03bc0SGordon Ross default: 15225fd03bc0SGordon Ross break; 1523e3f2c991SKeyur Desai } 1524037cac00Sjoyce mcintosh 1525e3f2c991SKeyur Desai /* 15265fd03bc0SGordon Ross * If we have an open file, and we set the size, 15275fd03bc0SGordon Ross * then set the "written" flag so that at close, 15285fd03bc0SGordon Ross * we can force an mtime update. 1529e3f2c991SKeyur Desai */ 15305fd03bc0SGordon Ross if (of != NULL && (attr->sa_mask & SMB_AT_SIZE) != 0) 15315fd03bc0SGordon Ross of->f_written = B_TRUE; 1532e3f2c991SKeyur Desai 15335fd03bc0SGordon Ross /* 15345fd03bc0SGordon Ross * When operating on an open file, some settable attributes 15355fd03bc0SGordon Ross * become "sticky" in the open file object until close. 15365fd03bc0SGordon Ross * (see above re. timestamps) 15375fd03bc0SGordon Ross */ 15385fd03bc0SGordon Ross times_mask = attr->sa_mask & SMB_AT_TIMES; 15395fd03bc0SGordon Ross if (of != NULL && times_mask != 0) { 15405fd03bc0SGordon Ross smb_attr_t *pa; 1541e3f2c991SKeyur Desai 15425fd03bc0SGordon Ross SMB_OFILE_VALID(of); 15435fd03bc0SGordon Ross mutex_enter(&of->f_mutex); 15445fd03bc0SGordon Ross pa = &of->f_pending_attr; 15455fd03bc0SGordon Ross 15465fd03bc0SGordon Ross pa->sa_mask |= times_mask; 15475fd03bc0SGordon Ross 15485fd03bc0SGordon Ross if (times_mask & SMB_AT_ATIME) 15495fd03bc0SGordon Ross pa->sa_vattr.va_atime = 15505fd03bc0SGordon Ross attr->sa_vattr.va_atime; 15515fd03bc0SGordon Ross if (times_mask & SMB_AT_MTIME) 15525fd03bc0SGordon Ross pa->sa_vattr.va_mtime = 15535fd03bc0SGordon Ross attr->sa_vattr.va_mtime; 15545fd03bc0SGordon Ross if (times_mask & SMB_AT_CTIME) 15555fd03bc0SGordon Ross pa->sa_vattr.va_ctime = 15565fd03bc0SGordon Ross attr->sa_vattr.va_ctime; 15575fd03bc0SGordon Ross if (times_mask & SMB_AT_CRTIME) 15585fd03bc0SGordon Ross pa->sa_crtime = 15595fd03bc0SGordon Ross attr->sa_crtime; 15605fd03bc0SGordon Ross 15615fd03bc0SGordon Ross mutex_exit(&of->f_mutex); 15625fd03bc0SGordon Ross /* 15635fd03bc0SGordon Ross * The f_pending_attr times are reapplied in 15645fd03bc0SGordon Ross * smb_ofile_close(). 15655fd03bc0SGordon Ross */ 1566e3f2c991SKeyur Desai } 1567e3f2c991SKeyur Desai 15685fd03bc0SGordon Ross /* 15695fd03bc0SGordon Ross * After this point, tmp_attr is what we will actually 15705fd03bc0SGordon Ross * store in the file system _now_, which may differ 15715fd03bc0SGordon Ross * from the callers attr and f_pending_attr w.r.t. 15725fd03bc0SGordon Ross * the DOS readonly flag etc. 15735fd03bc0SGordon Ross */ 15745fd03bc0SGordon Ross bcopy(attr, &tmp_attr, sizeof (tmp_attr)); 15755fd03bc0SGordon Ross if (attr->sa_mask & (SMB_AT_DOSATTR | SMB_AT_ALLOCSZ)) { 15765fd03bc0SGordon Ross mutex_enter(&node->n_mutex); 15775fd03bc0SGordon Ross if ((attr->sa_mask & SMB_AT_DOSATTR) != 0) { 15785fd03bc0SGordon Ross tmp_attr.sa_dosattr &= smb_vop_dosattr_settable; 15795fd03bc0SGordon Ross if (((tmp_attr.sa_dosattr & 15805fd03bc0SGordon Ross FILE_ATTRIBUTE_READONLY) != 0) && 15815fd03bc0SGordon Ross (node->n_open_count != 0)) { 15825fd03bc0SGordon Ross /* Delay setting readonly */ 15835fd03bc0SGordon Ross node->n_pending_dosattr = 15845fd03bc0SGordon Ross tmp_attr.sa_dosattr; 15855fd03bc0SGordon Ross tmp_attr.sa_dosattr &= 15865fd03bc0SGordon Ross ~FILE_ATTRIBUTE_READONLY; 15875fd03bc0SGordon Ross } else { 15885fd03bc0SGordon Ross node->n_pending_dosattr = 0; 15895fd03bc0SGordon Ross } 15905fd03bc0SGordon Ross } 15915fd03bc0SGordon Ross /* 15925fd03bc0SGordon Ross * Simulate n_allocsz persistence only while 15935fd03bc0SGordon Ross * there are opens. See smb_node_getattr 15945fd03bc0SGordon Ross */ 15955fd03bc0SGordon Ross if ((attr->sa_mask & SMB_AT_ALLOCSZ) != 0 && 15965fd03bc0SGordon Ross node->n_open_count != 0) 15975fd03bc0SGordon Ross node->n_allocsz = attr->sa_allocsz; 15985fd03bc0SGordon Ross mutex_exit(&node->n_mutex); 15995fd03bc0SGordon Ross } 1600e3f2c991SKeyur Desai 16015fd03bc0SGordon Ross rc = smb_fsop_setattr(sr, cr, node, &tmp_attr); 16025fd03bc0SGordon Ross if (rc != 0) 16035fd03bc0SGordon Ross return (rc); 1604037cac00Sjoyce mcintosh 1605ccc71be5SGordon Ross if (node->n_dnode != NULL) { 1606ccc71be5SGordon Ross smb_node_notify_change(node->n_dnode, 1607ccc71be5SGordon Ross FILE_ACTION_MODIFIED, node->od_name); 1608ccc71be5SGordon Ross } 1609fe1c642dSBill Krier 1610037cac00Sjoyce mcintosh return (0); 1611037cac00Sjoyce mcintosh } 1612037cac00Sjoyce mcintosh 1613037cac00Sjoyce mcintosh /* 1614037cac00Sjoyce mcintosh * smb_node_getattr 1615037cac00Sjoyce mcintosh * 1616037cac00Sjoyce mcintosh * Get attributes from the file system and apply any smb-specific 1617037cac00Sjoyce mcintosh * overrides for size, dos attributes and timestamps 1618037cac00Sjoyce mcintosh * 16195fd03bc0SGordon Ross * When node->n_pending_readonly is set on a node, pretend that 16205fd03bc0SGordon Ross * we've already set this node readonly at the filesystem level. 16215fd03bc0SGordon Ross * We can't actually do that until all writable handles are closed 16225fd03bc0SGordon Ross * or those writable handles would suddenly loose their access. 1623037cac00Sjoyce mcintosh * 1624037cac00Sjoyce mcintosh * Returns: errno 1625037cac00Sjoyce mcintosh */ 1626037cac00Sjoyce mcintosh int 16275fd03bc0SGordon Ross smb_node_getattr(smb_request_t *sr, smb_node_t *node, cred_t *cr, 16285fd03bc0SGordon Ross smb_ofile_t *of, smb_attr_t *attr) 1629037cac00Sjoyce mcintosh { 1630037cac00Sjoyce mcintosh int rc; 16315fd03bc0SGordon Ross uint_t want_mask, pend_mask; 16325fd03bc0SGordon Ross boolean_t isdir; 1633037cac00Sjoyce mcintosh 1634037cac00Sjoyce mcintosh SMB_NODE_VALID(node); 1635037cac00Sjoyce mcintosh 16365fd03bc0SGordon Ross /* Deal with some interdependencies */ 16375fd03bc0SGordon Ross if (attr->sa_mask & SMB_AT_ALLOCSZ) 16385fd03bc0SGordon Ross attr->sa_mask |= SMB_AT_SIZE; 16395fd03bc0SGordon Ross if (attr->sa_mask & SMB_AT_DOSATTR) 16405fd03bc0SGordon Ross attr->sa_mask |= SMB_AT_TYPE; 16415fd03bc0SGordon Ross 16425fd03bc0SGordon Ross rc = smb_fsop_getattr(sr, cr, node, attr); 1643037cac00Sjoyce mcintosh if (rc != 0) 1644037cac00Sjoyce mcintosh return (rc); 1645037cac00Sjoyce mcintosh 16465fd03bc0SGordon Ross isdir = smb_node_is_dir(node); 16475fd03bc0SGordon Ross 1648037cac00Sjoyce mcintosh mutex_enter(&node->n_mutex); 1649037cac00Sjoyce mcintosh 16505fd03bc0SGordon Ross /* 16515fd03bc0SGordon Ross * When there are open handles, and one of them has 16525fd03bc0SGordon Ross * set the DOS readonly flag (in n_pending_dosattr), 16535fd03bc0SGordon Ross * it will not have been stored in the file system. 16545fd03bc0SGordon Ross * In this case use n_pending_dosattr. Note that 16555fd03bc0SGordon Ross * n_pending_dosattr has only the settable bits, 16565fd03bc0SGordon Ross * (setattr masks it with smb_vop_dosattr_settable) 16575fd03bc0SGordon Ross * so we need to keep any non-settable bits we got 16585fd03bc0SGordon Ross * from the file-system above. 16595fd03bc0SGordon Ross */ 16605fd03bc0SGordon Ross if (attr->sa_mask & SMB_AT_DOSATTR) { 16615fd03bc0SGordon Ross if (node->n_pending_dosattr) { 16625fd03bc0SGordon Ross attr->sa_dosattr &= ~smb_vop_dosattr_settable; 16635fd03bc0SGordon Ross attr->sa_dosattr |= node->n_pending_dosattr; 16645fd03bc0SGordon Ross } 16655fd03bc0SGordon Ross if (attr->sa_dosattr == 0) { 16665fd03bc0SGordon Ross attr->sa_dosattr = (isdir) ? 16675fd03bc0SGordon Ross FILE_ATTRIBUTE_DIRECTORY: 16685fd03bc0SGordon Ross FILE_ATTRIBUTE_NORMAL; 16695fd03bc0SGordon Ross } 1670e3f2c991SKeyur Desai } 1671037cac00Sjoyce mcintosh 16725fd03bc0SGordon Ross /* 16735fd03bc0SGordon Ross * Also fix-up sa_allocsz, which is not persistent. 16745fd03bc0SGordon Ross * When there are no open files, allocsz is faked. 16755fd03bc0SGordon Ross * While there are open files, we pretend we have a 16765fd03bc0SGordon Ross * persistent allocation size in n_allocsz, and 16775fd03bc0SGordon Ross * keep that up-to-date here, increasing it when 16785fd03bc0SGordon Ross * we see the file size grow past it. 16795fd03bc0SGordon Ross */ 16805fd03bc0SGordon Ross if (attr->sa_mask & SMB_AT_ALLOCSZ) { 16815fd03bc0SGordon Ross if (isdir) { 16825fd03bc0SGordon Ross attr->sa_allocsz = 0; 16835fd03bc0SGordon Ross } else if (node->n_open_count == 0) { 16845fd03bc0SGordon Ross attr->sa_allocsz = 16855fd03bc0SGordon Ross SMB_ALLOCSZ(attr->sa_vattr.va_size); 16865fd03bc0SGordon Ross } else { 16875fd03bc0SGordon Ross if (node->n_allocsz < attr->sa_vattr.va_size) 16885fd03bc0SGordon Ross node->n_allocsz = 16895fd03bc0SGordon Ross SMB_ALLOCSZ(attr->sa_vattr.va_size); 16905fd03bc0SGordon Ross attr->sa_allocsz = node->n_allocsz; 16915fd03bc0SGordon Ross } 16925fd03bc0SGordon Ross } 1693e3f2c991SKeyur Desai 1694037cac00Sjoyce mcintosh mutex_exit(&node->n_mutex); 1695037cac00Sjoyce mcintosh 16965fd03bc0SGordon Ross if (isdir) { 16975fd03bc0SGordon Ross attr->sa_vattr.va_size = 0; 16985fd03bc0SGordon Ross attr->sa_vattr.va_nlink = 1; 16995fd03bc0SGordon Ross } 17005fd03bc0SGordon Ross 17015fd03bc0SGordon Ross /* 17025fd03bc0SGordon Ross * getattr with an ofile gets any "pending" times that 17035fd03bc0SGordon Ross * might have been previously set via this ofile. 17045fd03bc0SGordon Ross * This is what makes these times "sticky". 17055fd03bc0SGordon Ross */ 17065fd03bc0SGordon Ross want_mask = attr->sa_mask & SMB_AT_TIMES; 17075fd03bc0SGordon Ross if (of != NULL && want_mask != 0) { 17085fd03bc0SGordon Ross smb_attr_t *pa; 17095fd03bc0SGordon Ross 17105fd03bc0SGordon Ross SMB_OFILE_VALID(of); 17115fd03bc0SGordon Ross mutex_enter(&of->f_mutex); 17125fd03bc0SGordon Ross pa = &of->f_pending_attr; 17135fd03bc0SGordon Ross 17145fd03bc0SGordon Ross pend_mask = pa->sa_mask; 17155fd03bc0SGordon Ross 17165fd03bc0SGordon Ross if (want_mask & pend_mask & SMB_AT_ATIME) 17175fd03bc0SGordon Ross attr->sa_vattr.va_atime = 17185fd03bc0SGordon Ross pa->sa_vattr.va_atime; 17195fd03bc0SGordon Ross if (want_mask & pend_mask & SMB_AT_MTIME) 17205fd03bc0SGordon Ross attr->sa_vattr.va_mtime = 17215fd03bc0SGordon Ross pa->sa_vattr.va_mtime; 17225fd03bc0SGordon Ross if (want_mask & pend_mask & SMB_AT_CTIME) 17235fd03bc0SGordon Ross attr->sa_vattr.va_ctime = 17245fd03bc0SGordon Ross pa->sa_vattr.va_ctime; 17255fd03bc0SGordon Ross if (want_mask & pend_mask & SMB_AT_CRTIME) 17265fd03bc0SGordon Ross attr->sa_crtime = 17275fd03bc0SGordon Ross pa->sa_crtime; 17285fd03bc0SGordon Ross 17295fd03bc0SGordon Ross mutex_exit(&of->f_mutex); 17305fd03bc0SGordon Ross } 17315fd03bc0SGordon Ross 1732e3f2c991SKeyur Desai 1733037cac00Sjoyce mcintosh return (0); 1734037cac00Sjoyce mcintosh } 1735037cac00Sjoyce mcintosh 17369fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 1737b819cea2SGordon Ross #ifndef _KERNEL 1738b819cea2SGordon Ross extern int reparse_vnode_parse(vnode_t *vp, nvlist_t *nvl); 1739b819cea2SGordon Ross #endif /* _KERNEL */ 1740b819cea2SGordon Ross 17419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 17429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * Check to see if the node represents a reparse point. 17439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * If yes, whether the reparse point contains a DFS link. 17449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 17459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void 17469fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_init_reparse(smb_node_t *node, smb_attr_t *attr) 17479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 17489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States nvlist_t *nvl; 17499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States nvpair_t *rec; 17509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States char *rec_type; 17519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 17529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if ((attr->sa_dosattr & FILE_ATTRIBUTE_REPARSE_POINT) == 0) 17539fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return; 17549fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 17559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if ((nvl = reparse_init()) == NULL) 17569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return; 17579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 17589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (reparse_vnode_parse(node->vp, nvl) != 0) { 17599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States reparse_free(nvl); 17609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return; 17619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 17629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 17639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States node->flags |= NODE_FLAGS_REPARSE; 17649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 17659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States rec = nvlist_next_nvpair(nvl, NULL); 17669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States while (rec != NULL) { 17679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States rec_type = nvpair_name(rec); 17689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if ((rec_type != NULL) && 17699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (strcasecmp(rec_type, DFS_REPARSE_SVCTYPE) == 0)) { 17709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States node->flags |= NODE_FLAGS_DFSLINK; 17719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States break; 17729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 17739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States rec = nvlist_next_nvpair(nvl, rec); 17749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 17759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 17769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States reparse_free(nvl); 17779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 17789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 17799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /* 17809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * smb_node_init_system 17819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * 17829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * If the node represents a special system file set NODE_FLAG_SYSTEM. 17839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * System files: 17849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * - any node whose parent dnode has NODE_FLAG_SYSTEM set 17859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * - any node whose associated unnamed stream node (unode) has 17869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * NODE_FLAG_SYSTEM set 17879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States * - .$EXTEND at root of share (quota management) 17889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States */ 17899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static void 17909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_init_system(smb_node_t *node) 17919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States { 17929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *dnode = node->n_dnode; 17939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_node_t *unode = node->n_unode; 17949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 17959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if ((dnode) && (dnode->flags & NODE_FLAGS_SYSTEM)) { 17969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States node->flags |= NODE_FLAGS_SYSTEM; 17979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return; 17989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 17999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 18009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if ((unode) && (unode->flags & NODE_FLAGS_SYSTEM)) { 18019fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States node->flags |= NODE_FLAGS_SYSTEM; 18029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States return; 18039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 18049fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 18059fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if ((dnode) && (smb_node_is_vfsroot(node->n_dnode) && 18069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States (strcasecmp(node->od_name, ".$EXTEND") == 0))) { 18079fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States node->flags |= NODE_FLAGS_SYSTEM; 18089fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 18099fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States } 1810