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