xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_ofile.c (revision da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0)
1*da6c28aaSamw /*
2*da6c28aaSamw  * CDDL HEADER START
3*da6c28aaSamw  *
4*da6c28aaSamw  * The contents of this file are subject to the terms of the
5*da6c28aaSamw  * Common Development and Distribution License (the "License").
6*da6c28aaSamw  * You may not use this file except in compliance with the License.
7*da6c28aaSamw  *
8*da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10*da6c28aaSamw  * See the License for the specific language governing permissions
11*da6c28aaSamw  * and limitations under the License.
12*da6c28aaSamw  *
13*da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14*da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16*da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17*da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18*da6c28aaSamw  *
19*da6c28aaSamw  * CDDL HEADER END
20*da6c28aaSamw  */
21*da6c28aaSamw /*
22*da6c28aaSamw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*da6c28aaSamw  * Use is subject to license terms.
24*da6c28aaSamw  */
25*da6c28aaSamw 
26*da6c28aaSamw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*da6c28aaSamw 
28*da6c28aaSamw /*
29*da6c28aaSamw  * General Structures Layout
30*da6c28aaSamw  * -------------------------
31*da6c28aaSamw  *
32*da6c28aaSamw  * This is a simplified diagram showing the relationship between most of the
33*da6c28aaSamw  * main structures.
34*da6c28aaSamw  *
35*da6c28aaSamw  * +-------------------+
36*da6c28aaSamw  * |     SMB_INFO      |
37*da6c28aaSamw  * +-------------------+
38*da6c28aaSamw  *          |
39*da6c28aaSamw  *          |
40*da6c28aaSamw  *          v
41*da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
42*da6c28aaSamw  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
43*da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
44*da6c28aaSamw  *          |
45*da6c28aaSamw  *          |
46*da6c28aaSamw  *          v
47*da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
48*da6c28aaSamw  * |       USER        |<----->|       USER        |......|       USER        |
49*da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
50*da6c28aaSamw  *          |
51*da6c28aaSamw  *          |
52*da6c28aaSamw  *          v
53*da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
54*da6c28aaSamw  * |       TREE        |<----->|       TREE        |......|       TREE        |
55*da6c28aaSamw  * +-------------------+       +-------------------+      +-------------------+
56*da6c28aaSamw  *      |         |
57*da6c28aaSamw  *      |         |
58*da6c28aaSamw  *      |         v
59*da6c28aaSamw  *      |     +-------+       +-------+      +-------+
60*da6c28aaSamw  *      |     | OFILE |<----->| OFILE |......| OFILE |
61*da6c28aaSamw  *      |     +-------+       +-------+      +-------+
62*da6c28aaSamw  *      |
63*da6c28aaSamw  *      |
64*da6c28aaSamw  *      v
65*da6c28aaSamw  *  +-------+       +------+      +------+
66*da6c28aaSamw  *  | ODIR  |<----->| ODIR |......| ODIR |
67*da6c28aaSamw  *  +-------+       +------+      +------+
68*da6c28aaSamw  *
69*da6c28aaSamw  *
70*da6c28aaSamw  * Ofile State Machine
71*da6c28aaSamw  * ------------------
72*da6c28aaSamw  *
73*da6c28aaSamw  *    +-------------------------+	 T0
74*da6c28aaSamw  *    |  SMB_OFILE_STATE_OPEN   |<----------- Creation/Allocation
75*da6c28aaSamw  *    +-------------------------+
76*da6c28aaSamw  *		    |
77*da6c28aaSamw  *		    | T1
78*da6c28aaSamw  *		    |
79*da6c28aaSamw  *		    v
80*da6c28aaSamw  *    +-------------------------+
81*da6c28aaSamw  *    | SMB_OFILE_STATE_CLOSING |
82*da6c28aaSamw  *    +-------------------------+
83*da6c28aaSamw  *		    |
84*da6c28aaSamw  *		    | T2
85*da6c28aaSamw  *		    |
86*da6c28aaSamw  *		    v
87*da6c28aaSamw  *    +-------------------------+    T3
88*da6c28aaSamw  *    | SMB_OFILE_STATE_CLOSED  |----------> Deletion/Free
89*da6c28aaSamw  *    +-------------------------+
90*da6c28aaSamw  *
91*da6c28aaSamw  * SMB_OFILE_STATE_OPEN
92*da6c28aaSamw  *
93*da6c28aaSamw  *    While in this state:
94*da6c28aaSamw  *      - The ofile is queued in the list of ofiles of its tree.
95*da6c28aaSamw  *      - References will be given out if the ofile is looked up.
96*da6c28aaSamw  *
97*da6c28aaSamw  * SMB_OFILE_STATE_CLOSING
98*da6c28aaSamw  *
99*da6c28aaSamw  *    While in this state:
100*da6c28aaSamw  *      - The ofile is queued in the list of ofiles of its tree.
101*da6c28aaSamw  *      - References will not be given out if the ofile is looked up.
102*da6c28aaSamw  *      - The file is closed and the locks held are being released.
103*da6c28aaSamw  *      - The resources associated with the ofile remain.
104*da6c28aaSamw  *
105*da6c28aaSamw  * SMB_OFILE_STATE_CLOSED
106*da6c28aaSamw  *
107*da6c28aaSamw  *    While in this state:
108*da6c28aaSamw  *      - The ofile is queued in the list of ofiles of its tree.
109*da6c28aaSamw  *      - References will not be given out if the ofile is looked up.
110*da6c28aaSamw  *      - The resources associated with the ofile remain.
111*da6c28aaSamw  *
112*da6c28aaSamw  * Transition T0
113*da6c28aaSamw  *
114*da6c28aaSamw  *    This transition occurs in smb_ofile_open(). A new ofile is created and
115*da6c28aaSamw  *    added to the list of ofiles of a tree.
116*da6c28aaSamw  *
117*da6c28aaSamw  * Transition T1
118*da6c28aaSamw  *
119*da6c28aaSamw  *    This transition occurs in smb_ofile_close().
120*da6c28aaSamw  *
121*da6c28aaSamw  * Transition T2
122*da6c28aaSamw  *
123*da6c28aaSamw  *    This transition occurs in smb_ofile_release(). The resources associated
124*da6c28aaSamw  *    with the ofile are freed as well as the ofile structure. For the
125*da6c28aaSamw  *    transition to occur, the ofile must be in the SMB_OFILE_STATE_CLOSED
126*da6c28aaSamw  *    state and the reference count be zero.
127*da6c28aaSamw  *
128*da6c28aaSamw  * Comments
129*da6c28aaSamw  * --------
130*da6c28aaSamw  *
131*da6c28aaSamw  *    The state machine of the ofile structures is controlled by 3 elements:
132*da6c28aaSamw  *      - The list of ofiles of the tree it belongs to.
133*da6c28aaSamw  *      - The mutex embedded in the structure itself.
134*da6c28aaSamw  *      - The reference count.
135*da6c28aaSamw  *
136*da6c28aaSamw  *    There's a mutex embedded in the ofile structure used to protect its fields
137*da6c28aaSamw  *    and there's a lock embedded in the list of ofiles of a tree. To
138*da6c28aaSamw  *    increment or to decrement the reference count the mutex must be entered.
139*da6c28aaSamw  *    To insert the ofile into the list of ofiles of the tree and to remove
140*da6c28aaSamw  *    the ofile from it, the lock must be entered in RW_WRITER mode.
141*da6c28aaSamw  *
142*da6c28aaSamw  *    Rules of access to a ofile structure:
143*da6c28aaSamw  *
144*da6c28aaSamw  *    1) In order to avoid deadlocks, when both (mutex and lock of the ofile
145*da6c28aaSamw  *       list) have to be entered, the lock must be entered first.
146*da6c28aaSamw  *
147*da6c28aaSamw  *    2) All actions applied to an ofile require a reference count.
148*da6c28aaSamw  *
149*da6c28aaSamw  *    3) There are 2 ways of getting a reference count. One is when the ofile
150*da6c28aaSamw  *       is opened. The other one when the ofile is looked up. This translates
151*da6c28aaSamw  *       into 2 functions: smb_ofile_open() and smb_ofile_lookup_by_fid().
152*da6c28aaSamw  *
153*da6c28aaSamw  *    It should be noted that the reference count of an ofile registers the
154*da6c28aaSamw  *    number of references to the ofile in other structures (such as an smb
155*da6c28aaSamw  *    request). The reference count is not incremented in these 2 instances:
156*da6c28aaSamw  *
157*da6c28aaSamw  *    1) The ofile is open. An ofile is anchored by his state. If there's
158*da6c28aaSamw  *       no activity involving an ofile currently open, the reference count
159*da6c28aaSamw  *       of that ofile is zero.
160*da6c28aaSamw  *
161*da6c28aaSamw  *    2) The ofile is queued in the list of ofiles of its tree. The fact of
162*da6c28aaSamw  *       being queued in that list is NOT registered by incrementing the
163*da6c28aaSamw  *       reference count.
164*da6c28aaSamw  */
165*da6c28aaSamw #include <smbsrv/smb_incl.h>
166*da6c28aaSamw #include <smbsrv/smb_kproto.h>
167*da6c28aaSamw #include <smbsrv/smb_fsops.h>
168*da6c28aaSamw 
169*da6c28aaSamw /* Static functions defined further down this file. */
170*da6c28aaSamw static void		smb_ofile_delete(smb_ofile_t *of);
171*da6c28aaSamw static smb_ofile_t	*smb_ofile_close_and_next(smb_ofile_t *of);
172*da6c28aaSamw 
173*da6c28aaSamw /*
174*da6c28aaSamw  * smb_ofile_open
175*da6c28aaSamw  *
176*da6c28aaSamw  *
177*da6c28aaSamw  */
178*da6c28aaSamw smb_ofile_t *
179*da6c28aaSamw smb_ofile_open(
180*da6c28aaSamw     smb_tree_t		*tree,
181*da6c28aaSamw     smb_node_t		*node,
182*da6c28aaSamw     uint16_t		pid,
183*da6c28aaSamw     uint32_t		access_granted,
184*da6c28aaSamw     uint32_t		create_options,
185*da6c28aaSamw     uint32_t		share_access,
186*da6c28aaSamw     uint16_t		ftype,
187*da6c28aaSamw     char		*pipe_name,
188*da6c28aaSamw     uint32_t		rpc_fid,
189*da6c28aaSamw     smb_error_t		*err)
190*da6c28aaSamw {
191*da6c28aaSamw 	smb_ofile_t	*of;
192*da6c28aaSamw 	uint16_t	fid;
193*da6c28aaSamw 
194*da6c28aaSamw 	if (smb_idpool_alloc(&tree->t_fid_pool, &fid)) {
195*da6c28aaSamw 		err->status = NT_STATUS_TOO_MANY_OPENED_FILES;
196*da6c28aaSamw 		err->errcls = ERRDOS;
197*da6c28aaSamw 		err->errcode = ERROR_TOO_MANY_OPEN_FILES;
198*da6c28aaSamw 		return (NULL);
199*da6c28aaSamw 	}
200*da6c28aaSamw 
201*da6c28aaSamw 	of = kmem_cache_alloc(smb_info.si_cache_ofile, KM_SLEEP);
202*da6c28aaSamw 	bzero(of, sizeof (smb_ofile_t));
203*da6c28aaSamw 	of->f_magic = SMB_OFILE_MAGIC;
204*da6c28aaSamw 	of->f_refcnt = 1;
205*da6c28aaSamw 	of->f_fid = fid;
206*da6c28aaSamw 	of->f_opened_by_pid = pid;
207*da6c28aaSamw 	of->f_granted_access = access_granted;
208*da6c28aaSamw 	of->f_share_access = share_access;
209*da6c28aaSamw 	of->f_create_options = create_options;
210*da6c28aaSamw 	of->f_cr = tree->t_user->u_cred;
211*da6c28aaSamw 	crhold(of->f_cr);
212*da6c28aaSamw 	of->f_ftype = ftype;
213*da6c28aaSamw 	of->f_session = tree->t_user->u_session;
214*da6c28aaSamw 	of->f_user = tree->t_user;
215*da6c28aaSamw 	of->f_tree = tree;
216*da6c28aaSamw 	of->f_node = node;
217*da6c28aaSamw 	mutex_init(&of->f_mutex, NULL, MUTEX_DEFAULT, NULL);
218*da6c28aaSamw 	of->f_state = SMB_OFILE_STATE_OPEN;
219*da6c28aaSamw 
220*da6c28aaSamw 	if (ftype == SMB_FTYPE_MESG_PIPE) {
221*da6c28aaSamw 		of->f_pipe_info = kmem_alloc(sizeof (mlsvc_pipe_t), KM_SLEEP);
222*da6c28aaSamw 		bzero(of->f_pipe_info, sizeof (mlsvc_pipe_t));
223*da6c28aaSamw 		of->f_pipe_info->pipe_name = pipe_name;
224*da6c28aaSamw 		of->f_pipe_info->fid = rpc_fid;
225*da6c28aaSamw 		mutex_init(&of->f_pipe_info->mutex, NULL, MUTEX_DEFAULT, NULL);
226*da6c28aaSamw 		cv_init(&of->f_pipe_info->cv, NULL, CV_DEFAULT, NULL);
227*da6c28aaSamw 	} else {
228*da6c28aaSamw 		ASSERT(ftype == SMB_FTYPE_DISK); /* Regular file, not a pipe */
229*da6c28aaSamw 		ASSERT(node);
230*da6c28aaSamw 		if (crgetuid(of->f_cr) == node->attr.sa_vattr.va_uid) {
231*da6c28aaSamw 			/*
232*da6c28aaSamw 			 * Add this bit for the file's owner even if it's not
233*da6c28aaSamw 			 * specified in the request (Windows behavior).
234*da6c28aaSamw 			 */
235*da6c28aaSamw 			of->f_granted_access |= FILE_READ_ATTRIBUTES;
236*da6c28aaSamw 		}
237*da6c28aaSamw 
238*da6c28aaSamw 		if ((node->vp->v_type == VREG) && (smb_fsop_open(of) != 0)) {
239*da6c28aaSamw 			of->f_magic = 0;
240*da6c28aaSamw 			mutex_destroy(&of->f_mutex);
241*da6c28aaSamw 			crfree(of->f_cr);
242*da6c28aaSamw 			smb_idpool_free(&tree->t_fid_pool, of->f_fid);
243*da6c28aaSamw 			kmem_cache_free(smb_info.si_cache_ofile, of);
244*da6c28aaSamw 			err->status = NT_STATUS_ACCESS_DENIED;
245*da6c28aaSamw 			err->errcls = ERRDOS;
246*da6c28aaSamw 			err->errcode = ERROR_ACCESS_DENIED;
247*da6c28aaSamw 			return (NULL);
248*da6c28aaSamw 		}
249*da6c28aaSamw 		smb_llist_enter(&node->n_ofile_list, RW_WRITER);
250*da6c28aaSamw 		smb_llist_insert_tail(&node->n_ofile_list, of);
251*da6c28aaSamw 		smb_llist_exit(&node->n_ofile_list);
252*da6c28aaSamw 	}
253*da6c28aaSamw 	smb_llist_enter(&tree->t_ofile_list, RW_WRITER);
254*da6c28aaSamw 	smb_llist_insert_tail(&tree->t_ofile_list, of);
255*da6c28aaSamw 	smb_llist_exit(&tree->t_ofile_list);
256*da6c28aaSamw 	atomic_inc_32(&smb_info.open_files);
257*da6c28aaSamw 	atomic_inc_32(&of->f_session->s_file_cnt);
258*da6c28aaSamw 
259*da6c28aaSamw 	return (of);
260*da6c28aaSamw }
261*da6c28aaSamw 
262*da6c28aaSamw /*
263*da6c28aaSamw  * smb_ofile_close
264*da6c28aaSamw  *
265*da6c28aaSamw  *
266*da6c28aaSamw  */
267*da6c28aaSamw int
268*da6c28aaSamw smb_ofile_close(
269*da6c28aaSamw     smb_ofile_t		*of,
270*da6c28aaSamw     uint32_t		last_wtime)
271*da6c28aaSamw {
272*da6c28aaSamw 	int	rc = 0;
273*da6c28aaSamw 
274*da6c28aaSamw 
275*da6c28aaSamw 	ASSERT(of);
276*da6c28aaSamw 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
277*da6c28aaSamw 
278*da6c28aaSamw 	mutex_enter(&of->f_mutex);
279*da6c28aaSamw 	ASSERT(of->f_refcnt);
280*da6c28aaSamw 	switch (of->f_state) {
281*da6c28aaSamw 	case SMB_OFILE_STATE_OPEN: {
282*da6c28aaSamw 
283*da6c28aaSamw 		of->f_state = SMB_OFILE_STATE_CLOSING;
284*da6c28aaSamw 		mutex_exit(&of->f_mutex);
285*da6c28aaSamw 
286*da6c28aaSamw 		if (of->f_ftype == SMB_FTYPE_MESG_PIPE) {
287*da6c28aaSamw 			smb_rpc_close(of);
288*da6c28aaSamw 		} else {
289*da6c28aaSamw 			if (of->f_node->vp->v_type == VREG)
290*da6c28aaSamw 				(void) smb_fsop_close(of);
291*da6c28aaSamw 
292*da6c28aaSamw 			if (of->f_node->flags & NODE_CREATED_READONLY) {
293*da6c28aaSamw 				smb_node_set_dosattr(of->f_node,
294*da6c28aaSamw 				    of->f_node->attr.sa_dosattr |
295*da6c28aaSamw 				    SMB_FA_READONLY);
296*da6c28aaSamw 				of->f_node->flags &= ~NODE_CREATED_READONLY;
297*da6c28aaSamw 			}
298*da6c28aaSamw 
299*da6c28aaSamw 			smb_ofile_close_timestamp_update(of, last_wtime);
300*da6c28aaSamw 			rc = smb_sync_fsattr(NULL, of->f_cr, of->f_node);
301*da6c28aaSamw 			smb_commit_delete_on_close(of);
302*da6c28aaSamw 			smb_release_oplock(of, OPLOCK_RELEASE_FILE_CLOSED);
303*da6c28aaSamw 			smb_commit_delete_on_close(of);
304*da6c28aaSamw 			/*
305*da6c28aaSamw 			 * if there is any notify change request for
306*da6c28aaSamw 			 * this file then see if any of them is related
307*da6c28aaSamw 			 * to this open instance. If there is any then
308*da6c28aaSamw 			 * cancel them.
309*da6c28aaSamw 			 */
310*da6c28aaSamw 			if (of->f_node->flags & NODE_FLAGS_NOTIFY_CHANGE)
311*da6c28aaSamw 				smb_process_file_notify_change_queue(of);
312*da6c28aaSamw 			smb_node_destroy_lock_by_ofile(of->f_node, of);
313*da6c28aaSamw 		}
314*da6c28aaSamw 		atomic_dec_32(&smb_info.open_files);
315*da6c28aaSamw 
316*da6c28aaSamw 		mutex_enter(&of->f_mutex);
317*da6c28aaSamw 		ASSERT(of->f_refcnt);
318*da6c28aaSamw 		ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING);
319*da6c28aaSamw 		of->f_state = SMB_OFILE_STATE_CLOSED;
320*da6c28aaSamw 		mutex_exit(&of->f_mutex);
321*da6c28aaSamw 		return (rc);
322*da6c28aaSamw 	}
323*da6c28aaSamw 	case SMB_OFILE_STATE_CLOSED:
324*da6c28aaSamw 	case SMB_OFILE_STATE_CLOSING:
325*da6c28aaSamw 		break;
326*da6c28aaSamw 
327*da6c28aaSamw 	default:
328*da6c28aaSamw 		ASSERT(0);
329*da6c28aaSamw 		break;
330*da6c28aaSamw 	}
331*da6c28aaSamw 	mutex_exit(&of->f_mutex);
332*da6c28aaSamw 	return (rc);
333*da6c28aaSamw }
334*da6c28aaSamw 
335*da6c28aaSamw /*
336*da6c28aaSamw  * smb_ofile_close_all
337*da6c28aaSamw  *
338*da6c28aaSamw  *
339*da6c28aaSamw  */
340*da6c28aaSamw void
341*da6c28aaSamw smb_ofile_close_all(
342*da6c28aaSamw     smb_tree_t		*tree)
343*da6c28aaSamw {
344*da6c28aaSamw 	smb_ofile_t	*of;
345*da6c28aaSamw 
346*da6c28aaSamw 	ASSERT(tree);
347*da6c28aaSamw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
348*da6c28aaSamw 
349*da6c28aaSamw 	smb_llist_enter(&tree->t_ofile_list, RW_READER);
350*da6c28aaSamw 	of = smb_llist_head(&tree->t_ofile_list);
351*da6c28aaSamw 	while (of) {
352*da6c28aaSamw 		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
353*da6c28aaSamw 		ASSERT(of->f_tree == tree);
354*da6c28aaSamw 		of = smb_ofile_close_and_next(of);
355*da6c28aaSamw 	}
356*da6c28aaSamw 	smb_llist_exit(&tree->t_ofile_list);
357*da6c28aaSamw }
358*da6c28aaSamw 
359*da6c28aaSamw /*
360*da6c28aaSamw  * smb_ofiles_close_by_pid
361*da6c28aaSamw  *
362*da6c28aaSamw  *
363*da6c28aaSamw  */
364*da6c28aaSamw void
365*da6c28aaSamw smb_ofile_close_all_by_pid(
366*da6c28aaSamw     smb_tree_t		*tree,
367*da6c28aaSamw     uint16_t		pid)
368*da6c28aaSamw {
369*da6c28aaSamw 	smb_ofile_t	*of;
370*da6c28aaSamw 
371*da6c28aaSamw 	ASSERT(tree);
372*da6c28aaSamw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
373*da6c28aaSamw 
374*da6c28aaSamw 	smb_llist_enter(&tree->t_ofile_list, RW_READER);
375*da6c28aaSamw 	of = smb_llist_head(&tree->t_ofile_list);
376*da6c28aaSamw 	while (of) {
377*da6c28aaSamw 		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
378*da6c28aaSamw 		ASSERT(of->f_tree == tree);
379*da6c28aaSamw 		if (of->f_opened_by_pid == pid) {
380*da6c28aaSamw 			of = smb_ofile_close_and_next(of);
381*da6c28aaSamw 		} else {
382*da6c28aaSamw 			of = smb_llist_next(&tree->t_ofile_list, of);
383*da6c28aaSamw 		}
384*da6c28aaSamw 	}
385*da6c28aaSamw 	smb_llist_exit(&tree->t_ofile_list);
386*da6c28aaSamw }
387*da6c28aaSamw 
388*da6c28aaSamw /*
389*da6c28aaSamw  * smb_ofile_release
390*da6c28aaSamw  *
391*da6c28aaSamw  */
392*da6c28aaSamw void
393*da6c28aaSamw smb_ofile_release(
394*da6c28aaSamw     smb_ofile_t		*of)
395*da6c28aaSamw {
396*da6c28aaSamw 	ASSERT(of);
397*da6c28aaSamw 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
398*da6c28aaSamw 
399*da6c28aaSamw 	mutex_enter(&of->f_mutex);
400*da6c28aaSamw 	ASSERT(of->f_refcnt);
401*da6c28aaSamw 	of->f_refcnt--;
402*da6c28aaSamw 	switch (of->f_state) {
403*da6c28aaSamw 	case SMB_OFILE_STATE_OPEN:
404*da6c28aaSamw 	case SMB_OFILE_STATE_CLOSING:
405*da6c28aaSamw 		break;
406*da6c28aaSamw 
407*da6c28aaSamw 	case SMB_OFILE_STATE_CLOSED:
408*da6c28aaSamw 		if (of->f_refcnt == 0) {
409*da6c28aaSamw 			mutex_exit(&of->f_mutex);
410*da6c28aaSamw 			smb_ofile_delete(of);
411*da6c28aaSamw 			return;
412*da6c28aaSamw 		}
413*da6c28aaSamw 		break;
414*da6c28aaSamw 
415*da6c28aaSamw 	default:
416*da6c28aaSamw 		ASSERT(0);
417*da6c28aaSamw 		break;
418*da6c28aaSamw 	}
419*da6c28aaSamw 	mutex_exit(&of->f_mutex);
420*da6c28aaSamw }
421*da6c28aaSamw 
422*da6c28aaSamw /*
423*da6c28aaSamw  * smb_ofile_lookup_by_fid
424*da6c28aaSamw  *
425*da6c28aaSamw  * Find the open file whose fid matches the one specified in the request.
426*da6c28aaSamw  * If we can't find the fid or the shares (trees) don't match, we have a
427*da6c28aaSamw  * bad fid.
428*da6c28aaSamw  */
429*da6c28aaSamw smb_ofile_t *
430*da6c28aaSamw smb_ofile_lookup_by_fid(
431*da6c28aaSamw     smb_tree_t		*tree,
432*da6c28aaSamw     uint16_t		fid)
433*da6c28aaSamw {
434*da6c28aaSamw 	smb_llist_t	*of_list;
435*da6c28aaSamw 	smb_ofile_t	*of;
436*da6c28aaSamw 
437*da6c28aaSamw 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
438*da6c28aaSamw 
439*da6c28aaSamw 	of_list = &tree->t_ofile_list;
440*da6c28aaSamw 
441*da6c28aaSamw 	smb_llist_enter(of_list, RW_READER);
442*da6c28aaSamw 	of = smb_llist_head(of_list);
443*da6c28aaSamw 	while (of) {
444*da6c28aaSamw 		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
445*da6c28aaSamw 		ASSERT(of->f_tree == tree);
446*da6c28aaSamw 		if (of->f_fid == fid) {
447*da6c28aaSamw 			mutex_enter(&of->f_mutex);
448*da6c28aaSamw 			if (of->f_state != SMB_OFILE_STATE_OPEN) {
449*da6c28aaSamw 				mutex_exit(&of->f_mutex);
450*da6c28aaSamw 				smb_llist_exit(of_list);
451*da6c28aaSamw 				return (NULL);
452*da6c28aaSamw 			}
453*da6c28aaSamw 			of->f_refcnt++;
454*da6c28aaSamw 			mutex_exit(&of->f_mutex);
455*da6c28aaSamw 			break;
456*da6c28aaSamw 		}
457*da6c28aaSamw 		of = smb_llist_next(of_list, of);
458*da6c28aaSamw 	}
459*da6c28aaSamw 	smb_llist_exit(of_list);
460*da6c28aaSamw 	return (of);
461*da6c28aaSamw }
462*da6c28aaSamw 
463*da6c28aaSamw /*
464*da6c28aaSamw  * smb_ofile_set_flags
465*da6c28aaSamw  *
466*da6c28aaSamw  * Return value:
467*da6c28aaSamw  *
468*da6c28aaSamw  *	Current flags value
469*da6c28aaSamw  *
470*da6c28aaSamw  */
471*da6c28aaSamw void
472*da6c28aaSamw smb_ofile_set_flags(
473*da6c28aaSamw     smb_ofile_t		*of,
474*da6c28aaSamw     uint32_t		flags)
475*da6c28aaSamw {
476*da6c28aaSamw 	ASSERT(of);
477*da6c28aaSamw 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
478*da6c28aaSamw 	ASSERT(of->f_refcnt);
479*da6c28aaSamw 
480*da6c28aaSamw 	mutex_enter(&of->f_mutex);
481*da6c28aaSamw 	of->f_flags |= flags;
482*da6c28aaSamw 	mutex_exit(&of->f_mutex);
483*da6c28aaSamw }
484*da6c28aaSamw /*
485*da6c28aaSamw  * smb_ofile_seek
486*da6c28aaSamw  *
487*da6c28aaSamw  * Return value:
488*da6c28aaSamw  *
489*da6c28aaSamw  *	0		Success
490*da6c28aaSamw  *	EINVAL		Unknown mode
491*da6c28aaSamw  *	EOVERFLOW	offset too big
492*da6c28aaSamw  *
493*da6c28aaSamw  */
494*da6c28aaSamw int
495*da6c28aaSamw smb_ofile_seek(
496*da6c28aaSamw     smb_ofile_t		*of,
497*da6c28aaSamw     ushort_t		mode,
498*da6c28aaSamw     int32_t		off,
499*da6c28aaSamw     uint32_t		*retoff)
500*da6c28aaSamw {
501*da6c28aaSamw 	off_t		newoff = 0;
502*da6c28aaSamw 	int		rc = 0;
503*da6c28aaSamw 
504*da6c28aaSamw 	ASSERT(of);
505*da6c28aaSamw 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
506*da6c28aaSamw 	ASSERT(of->f_refcnt);
507*da6c28aaSamw 
508*da6c28aaSamw 	mutex_enter(&of->f_mutex);
509*da6c28aaSamw 	switch (mode) {
510*da6c28aaSamw 	case SMB_SEEK_SET:
511*da6c28aaSamw 		if (off < 0)
512*da6c28aaSamw 			newoff = 0;
513*da6c28aaSamw 		else
514*da6c28aaSamw 			newoff = (off_t)off;
515*da6c28aaSamw 		break;
516*da6c28aaSamw 
517*da6c28aaSamw 	case SMB_SEEK_CUR:
518*da6c28aaSamw 		if (off < 0 && (-off) > of->f_seek_pos)
519*da6c28aaSamw 			newoff = 0;
520*da6c28aaSamw 		else
521*da6c28aaSamw 			newoff = of->f_seek_pos + (off_t)off;
522*da6c28aaSamw 		break;
523*da6c28aaSamw 
524*da6c28aaSamw 	case SMB_SEEK_END:
525*da6c28aaSamw 		if (off < 0 && (-off) > of->f_node->attr.sa_vattr.va_size)
526*da6c28aaSamw 			newoff = 0;
527*da6c28aaSamw 		else
528*da6c28aaSamw 			newoff = of->f_node->attr.sa_vattr.va_size + (off_t)off;
529*da6c28aaSamw 		break;
530*da6c28aaSamw 
531*da6c28aaSamw 	default:
532*da6c28aaSamw 		mutex_exit(&of->f_mutex);
533*da6c28aaSamw 		return (EINVAL);
534*da6c28aaSamw 	}
535*da6c28aaSamw 
536*da6c28aaSamw 	if (newoff > ULONG_MAX) {
537*da6c28aaSamw 		rc = EOVERFLOW;
538*da6c28aaSamw 	} else {
539*da6c28aaSamw 		of->f_seek_pos = newoff;
540*da6c28aaSamw 		*retoff = (uint32_t)newoff;
541*da6c28aaSamw 	}
542*da6c28aaSamw 	mutex_exit(&of->f_mutex);
543*da6c28aaSamw 	return (rc);
544*da6c28aaSamw }
545*da6c28aaSamw 
546*da6c28aaSamw /*
547*da6c28aaSamw  * smb_ofile_close_timestamp_update
548*da6c28aaSamw  *
549*da6c28aaSamw  *
550*da6c28aaSamw  */
551*da6c28aaSamw void
552*da6c28aaSamw smb_ofile_close_timestamp_update(
553*da6c28aaSamw     smb_ofile_t		*of,
554*da6c28aaSamw     uint32_t		last_wtime)
555*da6c28aaSamw {
556*da6c28aaSamw 	smb_node_t	*node;
557*da6c28aaSamw 	timestruc_t	mtime, atime;
558*da6c28aaSamw 	unsigned int	what = 0;
559*da6c28aaSamw 
560*da6c28aaSamw 	mtime.tv_sec = last_wtime;
561*da6c28aaSamw 	mtime.tv_nsec = 0;
562*da6c28aaSamw 
563*da6c28aaSamw 	if (mtime.tv_sec != 0 && mtime.tv_sec != 0xFFFFFFFF) {
564*da6c28aaSamw 		mtime.tv_sec = smb_local_time_to_gmt(mtime.tv_sec);
565*da6c28aaSamw 		what |= SMB_AT_MTIME;
566*da6c28aaSamw 	}
567*da6c28aaSamw 
568*da6c28aaSamw 	/*
569*da6c28aaSamw 	 * NODE_FLAGS_SYNCATIME is set whenever something is
570*da6c28aaSamw 	 * written to a file. Compliant volumes don't update
571*da6c28aaSamw 	 * atime upon write, so don't update the atime if the
572*da6c28aaSamw 	 * volume is compliant.
573*da6c28aaSamw 	 */
574*da6c28aaSamw 	node = of->f_node;
575*da6c28aaSamw 	if (node->flags & NODE_FLAGS_SYNCATIME) {
576*da6c28aaSamw 		node->flags &= ~NODE_FLAGS_SYNCATIME;
577*da6c28aaSamw 		what |= SMB_AT_ATIME;
578*da6c28aaSamw 		(void) microtime(&atime);
579*da6c28aaSamw 	}
580*da6c28aaSamw 
581*da6c28aaSamw 	smb_node_set_time(node, 0, &mtime, &atime, 0, what);
582*da6c28aaSamw }
583*da6c28aaSamw 
584*da6c28aaSamw /*
585*da6c28aaSamw  * smb_ofile_is_open
586*da6c28aaSamw  *
587*da6c28aaSamw  */
588*da6c28aaSamw boolean_t
589*da6c28aaSamw smb_ofile_is_open(
590*da6c28aaSamw     smb_ofile_t		*of)
591*da6c28aaSamw {
592*da6c28aaSamw 	boolean_t	rc = B_FALSE;
593*da6c28aaSamw 
594*da6c28aaSamw 	ASSERT(of);
595*da6c28aaSamw 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
596*da6c28aaSamw 
597*da6c28aaSamw 	mutex_enter(&of->f_mutex);
598*da6c28aaSamw 	if (of->f_state == SMB_OFILE_STATE_OPEN) {
599*da6c28aaSamw 		rc = B_TRUE;
600*da6c28aaSamw 	}
601*da6c28aaSamw 	mutex_exit(&of->f_mutex);
602*da6c28aaSamw 	return (rc);
603*da6c28aaSamw }
604*da6c28aaSamw 
605*da6c28aaSamw /* *************************** Static Functions ***************************** */
606*da6c28aaSamw 
607*da6c28aaSamw /*
608*da6c28aaSamw  * smb_ofile_close_and_next
609*da6c28aaSamw  *
610*da6c28aaSamw  * This function closes the file passed in (if appropriate) and returns the
611*da6c28aaSamw  * next open file in the list of open files of the tree of the open file passed
612*da6c28aaSamw  * in. It requires that the list of open files of the tree be entered in
613*da6c28aaSamw  * RW_READER mode before being called.
614*da6c28aaSamw  */
615*da6c28aaSamw static smb_ofile_t *
616*da6c28aaSamw smb_ofile_close_and_next(
617*da6c28aaSamw     smb_ofile_t		*of)
618*da6c28aaSamw {
619*da6c28aaSamw 	smb_ofile_t	*next_of;
620*da6c28aaSamw 	smb_tree_t	*tree;
621*da6c28aaSamw 
622*da6c28aaSamw 	ASSERT(of);
623*da6c28aaSamw 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
624*da6c28aaSamw 
625*da6c28aaSamw 	mutex_enter(&of->f_mutex);
626*da6c28aaSamw 	switch (of->f_state) {
627*da6c28aaSamw 	case SMB_OFILE_STATE_OPEN:
628*da6c28aaSamw 		/* The file is still open. */
629*da6c28aaSamw 		of->f_refcnt++;
630*da6c28aaSamw 		ASSERT(of->f_refcnt);
631*da6c28aaSamw 		tree = of->f_tree;
632*da6c28aaSamw 		mutex_exit(&of->f_mutex);
633*da6c28aaSamw 		smb_llist_exit(&of->f_tree->t_ofile_list);
634*da6c28aaSamw 		(void) smb_ofile_close(of, 0);
635*da6c28aaSamw 		smb_ofile_release(of);
636*da6c28aaSamw 		smb_llist_enter(&tree->t_ofile_list, RW_READER);
637*da6c28aaSamw 		next_of = smb_llist_head(&tree->t_ofile_list);
638*da6c28aaSamw 		break;
639*da6c28aaSamw 	case SMB_OFILE_STATE_CLOSING:
640*da6c28aaSamw 	case SMB_OFILE_STATE_CLOSED:
641*da6c28aaSamw 		/*
642*da6c28aaSamw 		 * The ofile exists but is closed or
643*da6c28aaSamw 		 * in the process being closed.
644*da6c28aaSamw 		 */
645*da6c28aaSamw 		mutex_exit(&of->f_mutex);
646*da6c28aaSamw 		next_of = smb_llist_next(&of->f_tree->t_ofile_list, of);
647*da6c28aaSamw 		break;
648*da6c28aaSamw 	default:
649*da6c28aaSamw 		ASSERT(0);
650*da6c28aaSamw 		mutex_exit(&of->f_mutex);
651*da6c28aaSamw 		next_of = smb_llist_next(&of->f_tree->t_ofile_list, of);
652*da6c28aaSamw 		break;
653*da6c28aaSamw 	}
654*da6c28aaSamw 	return (next_of);
655*da6c28aaSamw }
656*da6c28aaSamw 
657*da6c28aaSamw /*
658*da6c28aaSamw  * smb_ofile_delete
659*da6c28aaSamw  *
660*da6c28aaSamw  *
661*da6c28aaSamw  */
662*da6c28aaSamw static void
663*da6c28aaSamw smb_ofile_delete(
664*da6c28aaSamw     smb_ofile_t		*of)
665*da6c28aaSamw {
666*da6c28aaSamw 	ASSERT(of);
667*da6c28aaSamw 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
668*da6c28aaSamw 	ASSERT(of->f_refcnt == 0);
669*da6c28aaSamw 	ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED);
670*da6c28aaSamw 
671*da6c28aaSamw 	/*
672*da6c28aaSamw 	 * Let's remove the ofile from the list of ofiles of the tree. This has
673*da6c28aaSamw 	 * to be done before any resources associated with the ofile are
674*da6c28aaSamw 	 * released.
675*da6c28aaSamw 	 */
676*da6c28aaSamw 	smb_llist_enter(&of->f_tree->t_ofile_list, RW_WRITER);
677*da6c28aaSamw 	smb_llist_remove(&of->f_tree->t_ofile_list, of);
678*da6c28aaSamw 	smb_llist_exit(&of->f_tree->t_ofile_list);
679*da6c28aaSamw 	atomic_dec_32(&of->f_session->s_file_cnt);
680*da6c28aaSamw 
681*da6c28aaSamw 	if (of->f_ftype == SMB_FTYPE_MESG_PIPE) {
682*da6c28aaSamw 		kmem_free(of->f_pipe_info, sizeof (mlsvc_pipe_t));
683*da6c28aaSamw 		of->f_pipe_info = NULL;
684*da6c28aaSamw 	} else {
685*da6c28aaSamw 		ASSERT(of->f_ftype == SMB_FTYPE_DISK);
686*da6c28aaSamw 		ASSERT(of->f_node != NULL);
687*da6c28aaSamw 		smb_llist_enter(&of->f_node->n_ofile_list, RW_WRITER);
688*da6c28aaSamw 		smb_llist_remove(&of->f_node->n_ofile_list, of);
689*da6c28aaSamw 		smb_llist_exit(&of->f_node->n_ofile_list);
690*da6c28aaSamw 		smb_node_release(of->f_node);
691*da6c28aaSamw 	}
692*da6c28aaSamw 
693*da6c28aaSamw 	of->f_magic = (uint32_t)~SMB_OFILE_MAGIC;
694*da6c28aaSamw 	mutex_destroy(&of->f_mutex);
695*da6c28aaSamw 	crfree(of->f_cr);
696*da6c28aaSamw 	smb_idpool_free(&of->f_tree->t_fid_pool, of->f_fid);
697*da6c28aaSamw 	kmem_cache_free(smb_info.si_cache_ofile, of);
698*da6c28aaSamw }
699*da6c28aaSamw 
700*da6c28aaSamw /*
701*da6c28aaSamw  * smb_ofile_access
702*da6c28aaSamw  *
703*da6c28aaSamw  * This function will check to see if the access requested is granted.
704*da6c28aaSamw  * Returns NT status codes.
705*da6c28aaSamw  */
706*da6c28aaSamw uint32_t
707*da6c28aaSamw smb_ofile_access(smb_ofile_t *of, cred_t *cr, uint32_t access)
708*da6c28aaSamw {
709*da6c28aaSamw 
710*da6c28aaSamw 	if ((of == NULL) || (cr == kcred))
711*da6c28aaSamw 		return (NT_STATUS_SUCCESS);
712*da6c28aaSamw 
713*da6c28aaSamw 	/*
714*da6c28aaSamw 	 * If the request is for something
715*da6c28aaSamw 	 * I don't grant it is an error
716*da6c28aaSamw 	 */
717*da6c28aaSamw 	if (~(of->f_granted_access) & access) {
718*da6c28aaSamw 		if (!(of->f_granted_access & ACCESS_SYSTEM_SECURITY) &&
719*da6c28aaSamw 		    (access & ACCESS_SYSTEM_SECURITY)) {
720*da6c28aaSamw 			return (NT_STATUS_PRIVILEGE_NOT_HELD);
721*da6c28aaSamw 		}
722*da6c28aaSamw 		return (NT_STATUS_ACCESS_DENIED);
723*da6c28aaSamw 	}
724*da6c28aaSamw 
725*da6c28aaSamw 	return (NT_STATUS_SUCCESS);
726*da6c28aaSamw }
727