xref: /titanic_50/usr/src/uts/common/fs/smbsrv/smb_node.c (revision a90cf9f29973990687fa61de9f1f6ea22e924e40)
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
smb_node_init(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
smb_node_fini(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 *
smb_node_lookup(struct smb_request * sr,struct open_param * op,cred_t * cred,vnode_t * vp,char * od_name,smb_node_t * dnode,smb_node_t * unode)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 *
smb_stream_node_lookup(smb_request_t * sr,cred_t * cr,smb_node_t * fnode,vnode_t * xattrdirvp,vnode_t * vp,char * stream_name)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
smb_node_ref(smb_node_t * node)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
smb_node_release(smb_node_t * node)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
smb_node_delete_on_close(smb_node_t * node)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
smb_node_rename(smb_node_t * from_dnode,smb_node_t * ret_node,smb_node_t * to_dnode,char * to_name)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
smb_node_root_init(smb_server_t * sv,smb_node_t ** svrootp)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
smb_rmdir_possible(smb_node_t * n,uint32_t flags)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
smb_node_set_delete_on_close(smb_node_t * node,cred_t * cr,uint32_t flags)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
smb_node_reset_delete_on_close(smb_node_t * node)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
smb_node_open_check(smb_node_t * node,uint32_t desired_access,uint32_t share_access)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
smb_node_rename_check(smb_node_t * node)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
smb_node_delete_check(smb_node_t * node)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
smb_node_share_check(smb_node_t * node)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
smb_node_fcn_subscribe(smb_node_t * node,smb_request_t * sr)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
smb_node_fcn_unsubscribe(smb_node_t * node,smb_request_t * sr)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
smb_node_notify_change(smb_node_t * node,uint_t action,const char * name)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
smb_node_notify_parents(smb_node_t * dnode)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
smb_node_start_crit(smb_node_t * node,krw_t mode)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
smb_node_end_crit(smb_node_t * node)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
smb_node_in_crit(smb_node_t * node)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
smb_node_rdlock(smb_node_t * node)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
smb_node_wrlock(smb_node_t * node)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
smb_node_unlock(smb_node_t * node)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
smb_node_add_ofile(smb_node_t * node,smb_ofile_t * of)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
smb_node_rem_ofile(smb_node_t * node,smb_ofile_t * of)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
smb_node_inc_open_ofiles(smb_node_t * node)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
smb_node_dec_open_ofiles(smb_node_t * node)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
smb_node_inc_opening_count(smb_node_t * node)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
smb_node_dec_opening_count(smb_node_t * node)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
smb_node_getmntpath(smb_node_t * node,char * buf,uint32_t buflen)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
smb_node_getshrpath(smb_node_t * node,smb_tree_t * tree,char * buf,uint32_t buflen)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
smb_node_getpath(smb_node_t * node,vnode_t * rootvp,char * buf,uint32_t buflen)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 *
smb_node_alloc(char * od_name,vnode_t * vp,smb_llist_t * bucket,uint32_t hashkey)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
smb_node_free(smb_node_t * node)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
smb_node_constructor(void * buf,void * un,int kmflags)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
smb_node_destructor(void * buf,void * un)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
smb_node_create_audit_buf(smb_node_t * node,int kmflags)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
smb_node_destroy_audit_buf(smb_node_t * node)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
smb_node_audit(smb_node_t * node)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 *
smb_node_get_hash(fsid_t * fsid,smb_attr_t * attr,uint32_t * phashkey)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
smb_node_is_file(smb_node_t * node)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
smb_node_is_dir(smb_node_t * node)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
smb_node_is_symlink(smb_node_t * node)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
smb_node_is_dfslink(smb_node_t * node)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
smb_node_is_reparse(smb_node_t * node)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
smb_node_is_vfsroot(smb_node_t * node)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
smb_node_is_system(smb_node_t * node)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
smb_node_file_is_readonly(smb_node_t * node)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
smb_node_setattr(smb_request_t * sr,smb_node_t * node,cred_t * cr,smb_ofile_t * of,smb_attr_t * attr)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
smb_node_getattr(smb_request_t * sr,smb_node_t * node,cred_t * cr,smb_ofile_t * of,smb_attr_t * attr)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
smb_node_init_reparse(smb_node_t * node,smb_attr_t * attr)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
smb_node_init_system(smb_node_t * node)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