xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_ofile.c (revision 49d8359737352b52625c23836d8a4be4ae8e55dd)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2016 Syneto S.R.L. All rights reserved.
24  * Copyright (c) 2016 by Delphix. All rights reserved.
25  * Copyright 2019 Nexenta Systems, Inc.  All rights reserved.
26  */
27 
28 /*
29  * General Structures Layout
30  * -------------------------
31  *
32  * This is a simplified diagram showing the relationship between most of the
33  * main structures.
34  *
35  * +-------------------+
36  * |     SMB_INFO      |
37  * +-------------------+
38  *          |
39  *          |
40  *          v
41  * +-------------------+       +-------------------+      +-------------------+
42  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
43  * +-------------------+       +-------------------+      +-------------------+
44  *   |          |
45  *   |          |
46  *   |          v
47  *   |  +-------------------+     +-------------------+   +-------------------+
48  *   |  |       USER        |<--->|       USER        |...|       USER        |
49  *   |  +-------------------+     +-------------------+   +-------------------+
50  *   |
51  *   |
52  *   v
53  * +-------------------+       +-------------------+      +-------------------+
54  * |       TREE        |<----->|       TREE        |......|       TREE        |
55  * +-------------------+       +-------------------+      +-------------------+
56  *      |         |
57  *      |         |
58  *      |         v
59  *      |     +-------+       +-------+      +-------+
60  *      |     | OFILE |<----->| OFILE |......| OFILE |
61  *      |     +-------+       +-------+      +-------+
62  *      |
63  *      |
64  *      v
65  *  +-------+       +------+      +------+
66  *  | ODIR  |<----->| ODIR |......| ODIR |
67  *  +-------+       +------+      +------+
68  *
69  *
70  * Ofile State Machine
71  * ------------------
72  *
73  *    +-------------------------+	 T0
74  *    |  SMB_OFILE_STATE_OPEN   |<----------- Creation/Allocation
75  *    +-------------------------+
76  *		    |
77  *		    | T1
78  *		    |
79  *		    v
80  *    +-------------------------+
81  *    | SMB_OFILE_STATE_CLOSING |
82  *    +-------------------------+
83  *		    |
84  *		    | T2
85  *		    |
86  *		    v
87  *    +-------------------------+    T3
88  *    | SMB_OFILE_STATE_CLOSED  |----------> Deletion/Free
89  *    +-------------------------+
90  *
91  * SMB_OFILE_STATE_OPEN
92  *
93  *    While in this state:
94  *      - The ofile is queued in the list of ofiles of its tree.
95  *      - References will be given out if the ofile is looked up.
96  *
97  * SMB_OFILE_STATE_CLOSING
98  *
99  *    While in this state:
100  *      - The ofile is queued in the list of ofiles of its tree.
101  *      - References will not be given out if the ofile is looked up.
102  *      - The file is closed and the locks held are being released.
103  *      - The resources associated with the ofile remain.
104  *
105  * SMB_OFILE_STATE_CLOSED
106  *
107  *    While in this state:
108  *      - The ofile is queued in the list of ofiles of its tree.
109  *      - References will not be given out if the ofile is looked up.
110  *      - The resources associated with the ofile remain.
111  *
112  * Transition T0
113  *
114  *    This transition occurs in smb_ofile_open(). A new ofile is created and
115  *    added to the list of ofiles of a tree.
116  *
117  * Transition T1
118  *
119  *    This transition occurs in smb_ofile_close().
120  *
121  * Transition T2
122  *
123  *    This transition occurs in smb_ofile_release(). The resources associated
124  *    with the ofile are freed as well as the ofile structure. For the
125  *    transition to occur, the ofile must be in the SMB_OFILE_STATE_CLOSED
126  *    state and the reference count be zero.
127  *
128  * Comments
129  * --------
130  *
131  *    The state machine of the ofile structures is controlled by 3 elements:
132  *      - The list of ofiles of the tree it belongs to.
133  *      - The mutex embedded in the structure itself.
134  *      - The reference count.
135  *
136  *    There's a mutex embedded in the ofile structure used to protect its fields
137  *    and there's a lock embedded in the list of ofiles of a tree. To
138  *    increment or to decrement the reference count the mutex must be entered.
139  *    To insert the ofile into the list of ofiles of the tree and to remove
140  *    the ofile from it, the lock must be entered in RW_WRITER mode.
141  *
142  *    Rules of access to a ofile structure:
143  *
144  *    1) In order to avoid deadlocks, when both (mutex and lock of the ofile
145  *       list) have to be entered, the lock must be entered first.
146  *
147  *    2) All actions applied to an ofile require a reference count.
148  *
149  *    3) There are 2 ways of getting a reference count. One is when the ofile
150  *       is opened. The other one when the ofile is looked up. This translates
151  *       into 2 functions: smb_ofile_open() and smb_ofile_lookup_by_fid().
152  *
153  *    It should be noted that the reference count of an ofile registers the
154  *    number of references to the ofile in other structures (such as an smb
155  *    request). The reference count is not incremented in these 2 instances:
156  *
157  *    1) The ofile is open. An ofile is anchored by its state. If there's
158  *       no activity involving an ofile currently open, the reference count
159  *       of that ofile is zero.
160  *
161  *    2) The ofile is queued in the list of ofiles of its tree. The fact of
162  *       being queued in that list is NOT registered by incrementing the
163  *       reference count.
164  */
165 #include <smbsrv/smb_kproto.h>
166 #include <smbsrv/smb_fsops.h>
167 
168 static boolean_t smb_ofile_is_open_locked(smb_ofile_t *);
169 static smb_ofile_t *smb_ofile_close_and_next(smb_ofile_t *);
170 static int smb_ofile_netinfo_encode(smb_ofile_t *, uint8_t *, size_t,
171     uint32_t *);
172 static int smb_ofile_netinfo_init(smb_ofile_t *, smb_netfileinfo_t *);
173 static void smb_ofile_netinfo_fini(smb_netfileinfo_t *);
174 
175 /*
176  * smb_ofile_open
177  */
178 smb_ofile_t *
179 smb_ofile_open(
180     smb_request_t	*sr,
181     smb_node_t		*node,
182     struct open_param	*op,
183     uint16_t		ftype,
184     uint32_t		uniqid,
185     smb_error_t		*err)
186 {
187 	smb_tree_t	*tree = sr->tid_tree;
188 	smb_ofile_t	*of;
189 	uint16_t	fid;
190 	smb_attr_t	attr;
191 	int		rc;
192 
193 	if (smb_idpool_alloc(&tree->t_fid_pool, &fid)) {
194 		err->status = NT_STATUS_TOO_MANY_OPENED_FILES;
195 		err->errcls = ERRDOS;
196 		err->errcode = ERROR_TOO_MANY_OPEN_FILES;
197 		return (NULL);
198 	}
199 
200 	of = kmem_cache_alloc(smb_cache_ofile, KM_SLEEP);
201 	bzero(of, sizeof (smb_ofile_t));
202 	of->f_magic = SMB_OFILE_MAGIC;
203 
204 	mutex_init(&of->f_mutex, NULL, MUTEX_DEFAULT, NULL);
205 	list_create(&of->f_notify.nc_waiters, sizeof (smb_request_t),
206 	    offsetof(smb_request_t, sr_waiters));
207 
208 	of->f_state = SMB_OFILE_STATE_OPEN;
209 	of->f_refcnt = 1;
210 	of->f_fid = fid;
211 	of->f_uniqid = uniqid;
212 	of->f_opened_by_pid = sr->smb_pid;
213 	of->f_granted_access = op->desired_access;
214 	of->f_share_access = op->share_access;
215 	of->f_create_options = op->create_options;
216 	of->f_cr = (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT) ?
217 	    smb_user_getprivcred(sr->uid_user) : sr->uid_user->u_cred;
218 	crhold(of->f_cr);
219 	of->f_ftype = ftype;
220 	of->f_server = tree->t_server;
221 	of->f_session = tree->t_session;
222 
223 	/*
224 	 * grab a ref for of->f_user
225 	 * released in smb_ofile_delete()
226 	 */
227 	smb_user_hold_internal(sr->uid_user);
228 	of->f_user = sr->uid_user;
229 	of->f_tree = tree;
230 	of->f_node = node;
231 
232 	if (ftype == SMB_FTYPE_MESG_PIPE) {
233 		/* See smb_opipe_open. */
234 		of->f_pipe = op->pipe;
235 		smb_server_inc_pipes(of->f_server);
236 	} else {
237 		ASSERT(ftype == SMB_FTYPE_DISK); /* Regular file, not a pipe */
238 		ASSERT(node);
239 
240 		/*
241 		 * Note that the common open path often adds bits like
242 		 * READ_CONTROL, so the logic "is this open exec-only"
243 		 * needs to look at only the FILE_DATA_ALL bits.
244 		 */
245 		if ((of->f_granted_access & FILE_DATA_ALL) == FILE_EXECUTE)
246 			of->f_flags |= SMB_OFLAGS_EXECONLY;
247 
248 		/*
249 		 * This is an "internal" getattr because we need the
250 		 * UID and DOS attributes.  Don't want to fail here
251 		 * due to permissions, so use kcred.
252 		 */
253 		bzero(&attr, sizeof (smb_attr_t));
254 		attr.sa_mask = SMB_AT_UID | SMB_AT_DOSATTR;
255 		rc = smb_node_getattr(NULL, node, zone_kcred(), NULL, &attr);
256 		if (rc != 0) {
257 			err->status = NT_STATUS_INTERNAL_ERROR;
258 			err->errcls = ERRDOS;
259 			err->errcode = ERROR_INTERNAL_ERROR;
260 			goto errout;
261 		}
262 		if (crgetuid(of->f_cr) == attr.sa_vattr.va_uid) {
263 			/*
264 			 * Add this bit for the file's owner even if it's not
265 			 * specified in the request (Windows behavior).
266 			 */
267 			of->f_granted_access |= FILE_READ_ATTRIBUTES;
268 		}
269 
270 		if (smb_node_is_file(node)) {
271 			of->f_mode =
272 			    smb_fsop_amask_to_omode(of->f_granted_access);
273 			if (smb_fsop_open(node, of->f_mode, of->f_cr) != 0) {
274 				err->status = NT_STATUS_ACCESS_DENIED;
275 				err->errcls = ERRDOS;
276 				err->errcode = ERROR_ACCESS_DENIED;
277 				goto errout;
278 			}
279 		}
280 
281 		if (tree->t_flags & SMB_TREE_READONLY)
282 			of->f_flags |= SMB_OFLAGS_READONLY;
283 
284 		/*
285 		 * Note that if we created_readonly, that
286 		 * will _not_ yet show in attr.sa_dosattr
287 		 * so creating a readonly file gives the
288 		 * caller a writable handle as it should.
289 		 */
290 		if (attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)
291 			of->f_flags |= SMB_OFLAGS_READONLY;
292 
293 		smb_node_inc_open_ofiles(node);
294 		smb_node_add_ofile(node, of);
295 		smb_node_ref(node);
296 		smb_server_inc_files(of->f_server);
297 	}
298 	smb_llist_enter(&tree->t_ofile_list, RW_WRITER);
299 	smb_llist_insert_tail(&tree->t_ofile_list, of);
300 	smb_llist_exit(&tree->t_ofile_list);
301 	atomic_inc_32(&tree->t_open_files);
302 	atomic_inc_32(&of->f_session->s_file_cnt);
303 	return (of);
304 
305 errout:
306 	smb_user_release(of->f_user);
307 	crfree(of->f_cr);
308 
309 	list_destroy(&of->f_notify.nc_waiters);
310 	mutex_destroy(&of->f_mutex);
311 
312 	of->f_magic = 0;
313 	kmem_cache_free(smb_cache_ofile, of);
314 
315 	smb_idpool_free(&tree->t_fid_pool, fid);
316 
317 	return (NULL);
318 }
319 
320 /*
321  * smb_ofile_close
322  */
323 void
324 smb_ofile_close(smb_ofile_t *of, int32_t mtime_sec)
325 {
326 	smb_attr_t *pa;
327 	timestruc_t now;
328 	uint32_t flags = 0;
329 
330 	SMB_OFILE_VALID(of);
331 
332 	mutex_enter(&of->f_mutex);
333 	ASSERT(of->f_refcnt);
334 	if (of->f_state != SMB_OFILE_STATE_OPEN) {
335 		mutex_exit(&of->f_mutex);
336 		return;
337 	}
338 	of->f_state = SMB_OFILE_STATE_CLOSING;
339 	mutex_exit(&of->f_mutex);
340 
341 	switch (of->f_ftype) {
342 	case SMB_FTYPE_BYTE_PIPE:
343 	case SMB_FTYPE_MESG_PIPE:
344 		smb_opipe_close(of);
345 		smb_server_dec_pipes(of->f_server);
346 		break;
347 
348 	case SMB_FTYPE_DISK:
349 	case SMB_FTYPE_PRINTER:
350 		/*
351 		 * In here we make changes to of->f_pending_attr
352 		 * while not holding of->f_mutex.  This is OK
353 		 * because we've changed f_state to CLOSING,
354 		 * so no more threads will take this path.
355 		 */
356 		pa = &of->f_pending_attr;
357 		if (mtime_sec != 0) {
358 			pa->sa_vattr.va_mtime.tv_sec = mtime_sec;
359 			pa->sa_mask |= SMB_AT_MTIME;
360 		}
361 
362 		/*
363 		 * If we have ever modified data via this handle
364 		 * (write or truncate) and if the mtime was not
365 		 * set via this handle, update the mtime again
366 		 * during the close.  Windows expects this.
367 		 * [ MS-FSA 2.1.5.4 "Update Timestamps" ]
368 		 */
369 		if (of->f_written &&
370 		    (pa->sa_mask & SMB_AT_MTIME) == 0) {
371 			pa->sa_mask |= SMB_AT_MTIME;
372 			gethrestime(&now);
373 			pa->sa_vattr.va_mtime = now;
374 		}
375 
376 		if (of->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE) {
377 			if (smb_tree_has_feature(of->f_tree,
378 			    SMB_TREE_CATIA)) {
379 				flags |= SMB_CATIA;
380 			}
381 			(void) smb_node_set_delete_on_close(of->f_node,
382 			    of->f_cr, flags);
383 		}
384 		smb_fsop_unshrlock(of->f_cr, of->f_node, of->f_uniqid);
385 		smb_node_destroy_lock_by_ofile(of->f_node, of);
386 
387 		if (smb_node_is_file(of->f_node)) {
388 			(void) smb_fsop_close(of->f_node, of->f_mode,
389 			    of->f_cr);
390 			smb_oplock_release(of->f_node, of);
391 		} else {
392 			/*
393 			 * If there was an odir, close it.
394 			 */
395 			if (of->f_odir != NULL)
396 				smb_odir_close(of->f_odir);
397 			/*
398 			 * Cancel any notify change requests that
399 			 * might be watching this open file (dir),
400 			 * and unsubscribe it from node events.
401 			 *
402 			 * Can't hold f_mutex when calling smb_notify_ofile.
403 			 * Don't really need it when unsubscribing, but
404 			 * harmless, and consistent with subscribing.
405 			 */
406 			if (of->f_notify.nc_subscribed)
407 				smb_notify_ofile(of,
408 				    FILE_ACTION_HANDLE_CLOSED, NULL);
409 			mutex_enter(&of->f_mutex);
410 			if (of->f_notify.nc_subscribed) {
411 				of->f_notify.nc_subscribed = B_FALSE;
412 				smb_node_fcn_unsubscribe(of->f_node);
413 				of->f_notify.nc_filter = 0;
414 			}
415 			mutex_exit(&of->f_mutex);
416 		}
417 		if (smb_node_dec_open_ofiles(of->f_node) == 0) {
418 			/*
419 			 * Last close. The f_pending_attr has
420 			 * only times (atime,ctime,mtime) so
421 			 * we can borrow it to commit the
422 			 * n_pending_dosattr from the node.
423 			 */
424 			pa->sa_dosattr =
425 			    of->f_node->n_pending_dosattr;
426 			if (pa->sa_dosattr != 0)
427 				pa->sa_mask |= SMB_AT_DOSATTR;
428 			/* Let's leave this zero when not in use. */
429 			of->f_node->n_allocsz = 0;
430 			mutex_enter(&of->f_node->n_mutex);
431 			if (of->f_node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
432 				smb_node_delete_on_close(of->f_node);
433 				pa->sa_mask = 0;
434 			}
435 			mutex_exit(&of->f_node->n_mutex);
436 		}
437 		if (pa->sa_mask != 0) {
438 			/*
439 			 * Commit any pending attributes from
440 			 * the ofile we're closing.  Note that
441 			 * we pass NULL as the ofile to setattr
442 			 * so it will write to the file system
443 			 * and not keep anything on the ofile.
444 			 * This clears n_pending_dosattr if
445 			 * there are no opens, otherwise the
446 			 * dosattr will be pending again.
447 			 */
448 			(void) smb_node_setattr(NULL, of->f_node,
449 			    of->f_cr, NULL, pa);
450 		}
451 
452 		smb_server_dec_files(of->f_server);
453 		break;
454 	}
455 	atomic_dec_32(&of->f_tree->t_open_files);
456 
457 	mutex_enter(&of->f_mutex);
458 	ASSERT(of->f_refcnt);
459 	ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING);
460 	of->f_state = SMB_OFILE_STATE_CLOSED;
461 	mutex_exit(&of->f_mutex);
462 }
463 
464 /*
465  * smb_ofile_close_all
466  *
467  *
468  */
469 void
470 smb_ofile_close_all(
471     smb_tree_t		*tree)
472 {
473 	smb_ofile_t	*of;
474 
475 	ASSERT(tree);
476 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
477 
478 	smb_llist_enter(&tree->t_ofile_list, RW_READER);
479 	of = smb_llist_head(&tree->t_ofile_list);
480 	while (of) {
481 		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
482 		ASSERT(of->f_tree == tree);
483 		of = smb_ofile_close_and_next(of);
484 	}
485 	smb_llist_exit(&tree->t_ofile_list);
486 }
487 
488 /*
489  * smb_ofiles_close_by_pid
490  *
491  *
492  */
493 void
494 smb_ofile_close_all_by_pid(
495     smb_tree_t		*tree,
496     uint16_t		pid)
497 {
498 	smb_ofile_t	*of;
499 
500 	ASSERT(tree);
501 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
502 
503 	smb_llist_enter(&tree->t_ofile_list, RW_READER);
504 	of = smb_llist_head(&tree->t_ofile_list);
505 	while (of) {
506 		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
507 		ASSERT(of->f_tree == tree);
508 		if (of->f_opened_by_pid == pid) {
509 			of = smb_ofile_close_and_next(of);
510 		} else {
511 			of = smb_llist_next(&tree->t_ofile_list, of);
512 		}
513 	}
514 	smb_llist_exit(&tree->t_ofile_list);
515 }
516 
517 /*
518  * If the enumeration request is for ofile data, handle it here.
519  * Otherwise, return.
520  *
521  * This function should be called with a hold on the ofile.
522  */
523 int
524 smb_ofile_enum(smb_ofile_t *of, smb_svcenum_t *svcenum)
525 {
526 	uint8_t *pb;
527 	uint_t nbytes;
528 	int rc;
529 
530 	ASSERT(of);
531 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
532 	ASSERT(of->f_refcnt);
533 
534 	if (svcenum->se_type != SMB_SVCENUM_TYPE_FILE)
535 		return (0);
536 
537 	if (svcenum->se_nskip > 0) {
538 		svcenum->se_nskip--;
539 		return (0);
540 	}
541 
542 	if (svcenum->se_nitems >= svcenum->se_nlimit) {
543 		svcenum->se_nitems = svcenum->se_nlimit;
544 		return (0);
545 	}
546 
547 	pb = &svcenum->se_buf[svcenum->se_bused];
548 
549 	rc = smb_ofile_netinfo_encode(of, pb, svcenum->se_bavail,
550 	    &nbytes);
551 	if (rc == 0) {
552 		svcenum->se_bavail -= nbytes;
553 		svcenum->se_bused += nbytes;
554 		svcenum->se_nitems++;
555 	}
556 
557 	return (rc);
558 }
559 
560 /*
561  * Take a reference on an open file.
562  */
563 boolean_t
564 smb_ofile_hold(smb_ofile_t *of)
565 {
566 	ASSERT(of);
567 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
568 
569 	mutex_enter(&of->f_mutex);
570 
571 	if (of->f_state != SMB_OFILE_STATE_OPEN) {
572 		mutex_exit(&of->f_mutex);
573 		return (B_FALSE);
574 	}
575 	of->f_refcnt++;
576 
577 	mutex_exit(&of->f_mutex);
578 	return (B_TRUE);
579 }
580 
581 /*
582  * Release a reference on a file.  If the reference count falls to
583  * zero and the file has been closed, post the object for deletion.
584  * Object deletion is deferred to avoid modifying a list while an
585  * iteration may be in progress.
586  */
587 void
588 smb_ofile_release(smb_ofile_t *of)
589 {
590 	SMB_OFILE_VALID(of);
591 
592 	mutex_enter(&of->f_mutex);
593 	ASSERT(of->f_refcnt);
594 	of->f_refcnt--;
595 	switch (of->f_state) {
596 	case SMB_OFILE_STATE_OPEN:
597 	case SMB_OFILE_STATE_CLOSING:
598 		break;
599 
600 	case SMB_OFILE_STATE_CLOSED:
601 		if (of->f_refcnt == 0)
602 			smb_tree_post_ofile(of->f_tree, of);
603 		break;
604 
605 	default:
606 		ASSERT(0);
607 		break;
608 	}
609 	mutex_exit(&of->f_mutex);
610 }
611 
612 /*
613  * smb_ofile_request_complete
614  *
615  * During oplock acquisition, all other oplock requests on the node
616  * are blocked until the acquire request completes and the response
617  * is on the wire.
618  * Call smb_oplock_broadcast to notify the node that the request
619  * has completed.
620  *
621  * THIS MECHANISM RELIES ON THE FACT THAT THE OFILE IS NOT REMOVED
622  * FROM THE SR UNTIL REQUEST COMPLETION (when the sr is destroyed)
623  */
624 void
625 smb_ofile_request_complete(smb_ofile_t *of)
626 {
627 	SMB_OFILE_VALID(of);
628 
629 	switch (of->f_ftype) {
630 	case SMB_FTYPE_DISK:
631 		ASSERT(of->f_node);
632 		smb_oplock_broadcast(of->f_node);
633 		break;
634 	case SMB_FTYPE_MESG_PIPE:
635 		break;
636 	default:
637 		break;
638 	}
639 }
640 
641 /*
642  * smb_ofile_lookup_by_fid
643  *
644  * Find the open file whose fid matches the one specified in the request.
645  * If we can't find the fid or the shares (trees) don't match, we have a
646  * bad fid.
647  */
648 smb_ofile_t *
649 smb_ofile_lookup_by_fid(
650     smb_request_t	*sr,
651     uint16_t		fid)
652 {
653 	smb_tree_t	*tree = sr->tid_tree;
654 	smb_llist_t	*of_list;
655 	smb_ofile_t	*of;
656 
657 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
658 
659 	of_list = &tree->t_ofile_list;
660 
661 	smb_llist_enter(of_list, RW_READER);
662 	of = smb_llist_head(of_list);
663 	while (of) {
664 		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
665 		ASSERT(of->f_tree == tree);
666 		if (of->f_fid == fid)
667 			break;
668 		of = smb_llist_next(of_list, of);
669 	}
670 	if (of == NULL)
671 		goto out;
672 
673 	/*
674 	 * Only allow use of a given FID with the same UID that
675 	 * was used to open it.  MS-CIFS 3.3.5.14
676 	 */
677 	if (of->f_user != sr->uid_user) {
678 		of = NULL;
679 		goto out;
680 	}
681 
682 	mutex_enter(&of->f_mutex);
683 	if (of->f_state != SMB_OFILE_STATE_OPEN) {
684 		mutex_exit(&of->f_mutex);
685 		of = NULL;
686 		goto out;
687 	}
688 	of->f_refcnt++;
689 	mutex_exit(&of->f_mutex);
690 
691 out:
692 	smb_llist_exit(of_list);
693 	return (of);
694 }
695 
696 /*
697  * smb_ofile_lookup_by_uniqid
698  *
699  * Find the open file whose uniqid matches the one specified in the request.
700  */
701 smb_ofile_t *
702 smb_ofile_lookup_by_uniqid(smb_tree_t *tree, uint32_t uniqid)
703 {
704 	smb_llist_t	*of_list;
705 	smb_ofile_t	*of;
706 
707 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
708 
709 	of_list = &tree->t_ofile_list;
710 	smb_llist_enter(of_list, RW_READER);
711 	of = smb_llist_head(of_list);
712 
713 	while (of) {
714 		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
715 		ASSERT(of->f_tree == tree);
716 
717 		if (of->f_uniqid == uniqid) {
718 			if (smb_ofile_hold(of)) {
719 				smb_llist_exit(of_list);
720 				return (of);
721 			}
722 		}
723 
724 		of = smb_llist_next(of_list, of);
725 	}
726 
727 	smb_llist_exit(of_list);
728 	return (NULL);
729 }
730 
731 /*
732  * Disallow NetFileClose on certain ofiles to avoid side-effects.
733  * Closing a tree root is not allowed: use NetSessionDel or NetShareDel.
734  * Closing SRVSVC connections is not allowed because this NetFileClose
735  * request may depend on this ofile.
736  */
737 boolean_t
738 smb_ofile_disallow_fclose(smb_ofile_t *of)
739 {
740 	ASSERT(of);
741 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
742 	ASSERT(of->f_refcnt);
743 
744 	switch (of->f_ftype) {
745 	case SMB_FTYPE_DISK:
746 		ASSERT(of->f_tree);
747 		return (of->f_node == of->f_tree->t_snode);
748 
749 	case SMB_FTYPE_MESG_PIPE:
750 		ASSERT(of->f_pipe);
751 		if (smb_strcasecmp(of->f_pipe->p_name, "SRVSVC", 0) == 0)
752 			return (B_TRUE);
753 		break;
754 	default:
755 		break;
756 	}
757 
758 	return (B_FALSE);
759 }
760 
761 /*
762  * smb_ofile_set_flags
763  *
764  * Return value:
765  *
766  *	Current flags value
767  *
768  */
769 void
770 smb_ofile_set_flags(
771     smb_ofile_t		*of,
772     uint32_t		flags)
773 {
774 	ASSERT(of);
775 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
776 	ASSERT(of->f_refcnt);
777 
778 	mutex_enter(&of->f_mutex);
779 	of->f_flags |= flags;
780 	mutex_exit(&of->f_mutex);
781 }
782 
783 /*
784  * smb_ofile_seek
785  *
786  * Return value:
787  *
788  *	0		Success
789  *	EINVAL		Unknown mode
790  *	EOVERFLOW	offset too big
791  *
792  */
793 int
794 smb_ofile_seek(
795     smb_ofile_t		*of,
796     ushort_t		mode,
797     int32_t		off,
798     uint32_t		*retoff)
799 {
800 	u_offset_t	newoff = 0;
801 	int		rc = 0;
802 	smb_attr_t	attr;
803 
804 	ASSERT(of);
805 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
806 	ASSERT(of->f_refcnt);
807 
808 	mutex_enter(&of->f_mutex);
809 	switch (mode) {
810 	case SMB_SEEK_SET:
811 		if (off < 0)
812 			newoff = 0;
813 		else
814 			newoff = (u_offset_t)off;
815 		break;
816 
817 	case SMB_SEEK_CUR:
818 		if (off < 0 && (-off) > of->f_seek_pos)
819 			newoff = 0;
820 		else
821 			newoff = of->f_seek_pos + (u_offset_t)off;
822 		break;
823 
824 	case SMB_SEEK_END:
825 		bzero(&attr, sizeof (smb_attr_t));
826 		attr.sa_mask |= SMB_AT_SIZE;
827 		rc = smb_fsop_getattr(NULL, zone_kcred(), of->f_node, &attr);
828 		if (rc != 0) {
829 			mutex_exit(&of->f_mutex);
830 			return (rc);
831 		}
832 		if (off < 0 && (-off) > attr.sa_vattr.va_size)
833 			newoff = 0;
834 		else
835 			newoff = attr.sa_vattr.va_size + (u_offset_t)off;
836 		break;
837 
838 	default:
839 		mutex_exit(&of->f_mutex);
840 		return (EINVAL);
841 	}
842 
843 	/*
844 	 * See comments at the beginning of smb_seek.c.
845 	 * If the offset is greater than UINT_MAX, we will return an error.
846 	 */
847 
848 	if (newoff > UINT_MAX) {
849 		rc = EOVERFLOW;
850 	} else {
851 		of->f_seek_pos = newoff;
852 		*retoff = (uint32_t)newoff;
853 	}
854 	mutex_exit(&of->f_mutex);
855 	return (rc);
856 }
857 
858 /*
859  * smb_ofile_flush
860  *
861  * If writes on this file are not synchronous, flush it using the NFSv3
862  * commit interface.
863  *
864  * XXX - todo: Flush named pipe should drain writes.
865  */
866 void
867 smb_ofile_flush(struct smb_request *sr, struct smb_ofile *of)
868 {
869 	switch (of->f_ftype) {
870 	case SMB_FTYPE_DISK:
871 		if ((of->f_node->flags & NODE_FLAGS_WRITE_THROUGH) == 0)
872 			(void) smb_fsop_commit(sr, of->f_cr, of->f_node);
873 		break;
874 	default:
875 		break;
876 	}
877 }
878 
879 /*
880  * smb_ofile_is_open
881  */
882 boolean_t
883 smb_ofile_is_open(smb_ofile_t *of)
884 {
885 	boolean_t	rc;
886 
887 	SMB_OFILE_VALID(of);
888 
889 	mutex_enter(&of->f_mutex);
890 	rc = smb_ofile_is_open_locked(of);
891 	mutex_exit(&of->f_mutex);
892 	return (rc);
893 }
894 
895 /* *************************** Static Functions ***************************** */
896 
897 /*
898  * Determine whether or not an ofile is open.
899  * This function must be called with the mutex held.
900  */
901 static boolean_t
902 smb_ofile_is_open_locked(smb_ofile_t *of)
903 {
904 	switch (of->f_state) {
905 	case SMB_OFILE_STATE_OPEN:
906 		return (B_TRUE);
907 
908 	case SMB_OFILE_STATE_CLOSING:
909 	case SMB_OFILE_STATE_CLOSED:
910 		return (B_FALSE);
911 
912 	default:
913 		ASSERT(0);
914 		return (B_FALSE);
915 	}
916 }
917 
918 /*
919  * This function closes the file passed in (if appropriate) and returns the
920  * next open file in the list of open files of the tree of the open file passed
921  * in. It requires that the list of open files of the tree be entered in
922  * RW_READER mode before being called.
923  */
924 static smb_ofile_t *
925 smb_ofile_close_and_next(smb_ofile_t *of)
926 {
927 	smb_ofile_t	*next_of;
928 	smb_tree_t	*tree;
929 
930 	ASSERT(of);
931 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
932 
933 	mutex_enter(&of->f_mutex);
934 	switch (of->f_state) {
935 	case SMB_OFILE_STATE_OPEN:
936 		/* The file is still open. */
937 		of->f_refcnt++;
938 		ASSERT(of->f_refcnt);
939 		tree = of->f_tree;
940 		mutex_exit(&of->f_mutex);
941 		smb_llist_exit(&of->f_tree->t_ofile_list);
942 		smb_ofile_close(of, 0);
943 		smb_ofile_release(of);
944 		smb_llist_enter(&tree->t_ofile_list, RW_READER);
945 		next_of = smb_llist_head(&tree->t_ofile_list);
946 		break;
947 	case SMB_OFILE_STATE_CLOSING:
948 	case SMB_OFILE_STATE_CLOSED:
949 		/*
950 		 * The ofile exists but is closed or
951 		 * in the process being closed.
952 		 */
953 		mutex_exit(&of->f_mutex);
954 		next_of = smb_llist_next(&of->f_tree->t_ofile_list, of);
955 		break;
956 	default:
957 		ASSERT(0);
958 		mutex_exit(&of->f_mutex);
959 		next_of = smb_llist_next(&of->f_tree->t_ofile_list, of);
960 		break;
961 	}
962 	return (next_of);
963 }
964 
965 /*
966  * Delete an ofile.
967  *
968  * Remove the ofile from the tree list before freeing resources
969  * associated with the ofile.
970  */
971 void
972 smb_ofile_delete(void *arg)
973 {
974 	smb_tree_t	*tree;
975 	smb_ofile_t	*of = (smb_ofile_t *)arg;
976 
977 	SMB_OFILE_VALID(of);
978 	ASSERT(of->f_refcnt == 0);
979 	ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED);
980 	ASSERT(!SMB_OFILE_OPLOCK_GRANTED(of));
981 
982 	tree = of->f_tree;
983 	smb_llist_enter(&tree->t_ofile_list, RW_WRITER);
984 	smb_llist_remove(&tree->t_ofile_list, of);
985 	smb_idpool_free(&tree->t_fid_pool, of->f_fid);
986 	atomic_dec_32(&tree->t_session->s_file_cnt);
987 	smb_llist_exit(&tree->t_ofile_list);
988 
989 	/*
990 	 * Remove this ofile from the node's n_ofile_list so it
991 	 * can't be found by list walkers like notify or oplock.
992 	 * Keep the node ref. until later in this function so
993 	 * of->f_node remains valid while we destroy the ofile.
994 	 */
995 	if (of->f_ftype == SMB_FTYPE_DISK ||
996 	    of->f_ftype == SMB_FTYPE_PRINTER) {
997 		ASSERT(of->f_node != NULL);
998 		/*
999 		 * Note smb_ofile_close did smb_node_dec_open_ofiles()
1000 		 */
1001 		smb_node_rem_ofile(of->f_node, of);
1002 	}
1003 
1004 	mutex_enter(&of->f_mutex);
1005 	mutex_exit(&of->f_mutex);
1006 
1007 	switch (of->f_ftype) {
1008 	case SMB_FTYPE_BYTE_PIPE:
1009 	case SMB_FTYPE_MESG_PIPE:
1010 		smb_opipe_dealloc(of->f_pipe);
1011 		of->f_pipe = NULL;
1012 		break;
1013 	case SMB_FTYPE_DISK:
1014 		ASSERT(of->f_notify.nc_subscribed == B_FALSE);
1015 		MBC_FLUSH(&of->f_notify.nc_buffer);
1016 		if (of->f_odir != NULL)
1017 			smb_odir_release(of->f_odir);
1018 		/* FALLTHROUGH */
1019 	case SMB_FTYPE_PRINTER:
1020 		/*
1021 		 * Did smb_node_rem_ofile above.
1022 		 */
1023 		ASSERT(of->f_node != NULL);
1024 		smb_node_release(of->f_node);
1025 		break;
1026 	default:
1027 		ASSERT(!"f_ftype");
1028 		break;
1029 	}
1030 
1031 	of->f_magic = (uint32_t)~SMB_OFILE_MAGIC;
1032 	list_destroy(&of->f_notify.nc_waiters);
1033 	mutex_destroy(&of->f_mutex);
1034 	smb_user_release(of->f_user);
1035 	crfree(of->f_cr);
1036 	kmem_cache_free(smb_cache_ofile, of);
1037 }
1038 
1039 /*
1040  * smb_ofile_access
1041  *
1042  * This function will check to see if the access requested is granted.
1043  * Returns NT status codes.
1044  */
1045 uint32_t
1046 smb_ofile_access(smb_ofile_t *of, cred_t *cr, uint32_t access)
1047 {
1048 
1049 	if ((of == NULL) || (cr == zone_kcred()))
1050 		return (NT_STATUS_SUCCESS);
1051 
1052 	/*
1053 	 * If the request is for something
1054 	 * I don't grant it is an error
1055 	 */
1056 	if (~(of->f_granted_access) & access) {
1057 		if (!(of->f_granted_access & ACCESS_SYSTEM_SECURITY) &&
1058 		    (access & ACCESS_SYSTEM_SECURITY)) {
1059 			return (NT_STATUS_PRIVILEGE_NOT_HELD);
1060 		}
1061 		return (NT_STATUS_ACCESS_DENIED);
1062 	}
1063 
1064 	return (NT_STATUS_SUCCESS);
1065 }
1066 
1067 /*
1068  * smb_ofile_share_check
1069  *
1070  * Check if ofile was opened with share access NONE (0).
1071  * Returns: B_TRUE  - share access non-zero
1072  *          B_FALSE - share access NONE
1073  */
1074 boolean_t
1075 smb_ofile_share_check(smb_ofile_t *of)
1076 {
1077 	return (!SMB_DENY_ALL(of->f_share_access));
1078 }
1079 
1080 /*
1081  * check file sharing rules for current open request
1082  * against existing open instances of the same file
1083  *
1084  * Returns NT_STATUS_SHARING_VIOLATION if there is any
1085  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
1086  */
1087 uint32_t
1088 smb_ofile_open_check(smb_ofile_t *of, uint32_t desired_access,
1089     uint32_t share_access)
1090 {
1091 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
1092 
1093 	mutex_enter(&of->f_mutex);
1094 
1095 	if (of->f_state != SMB_OFILE_STATE_OPEN) {
1096 		mutex_exit(&of->f_mutex);
1097 		return (NT_STATUS_INVALID_HANDLE);
1098 	}
1099 
1100 	/* if it's just meta data */
1101 	if ((of->f_granted_access & FILE_DATA_ALL) == 0) {
1102 		mutex_exit(&of->f_mutex);
1103 		return (NT_STATUS_SUCCESS);
1104 	}
1105 
1106 	/*
1107 	 * Check requested share access against the
1108 	 * open granted (desired) access
1109 	 */
1110 	if (SMB_DENY_DELETE(share_access) && (of->f_granted_access & DELETE)) {
1111 		mutex_exit(&of->f_mutex);
1112 		return (NT_STATUS_SHARING_VIOLATION);
1113 	}
1114 
1115 	if (SMB_DENY_READ(share_access) &&
1116 	    (of->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE))) {
1117 		mutex_exit(&of->f_mutex);
1118 		return (NT_STATUS_SHARING_VIOLATION);
1119 	}
1120 
1121 	if (SMB_DENY_WRITE(share_access) &&
1122 	    (of->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) {
1123 		mutex_exit(&of->f_mutex);
1124 		return (NT_STATUS_SHARING_VIOLATION);
1125 	}
1126 
1127 	/* check requested desired access against the open share access */
1128 	if (SMB_DENY_DELETE(of->f_share_access) && (desired_access & DELETE)) {
1129 		mutex_exit(&of->f_mutex);
1130 		return (NT_STATUS_SHARING_VIOLATION);
1131 	}
1132 
1133 	if (SMB_DENY_READ(of->f_share_access) &&
1134 	    (desired_access & (FILE_READ_DATA | FILE_EXECUTE))) {
1135 		mutex_exit(&of->f_mutex);
1136 		return (NT_STATUS_SHARING_VIOLATION);
1137 	}
1138 
1139 	if (SMB_DENY_WRITE(of->f_share_access) &&
1140 	    (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) {
1141 		mutex_exit(&of->f_mutex);
1142 		return (NT_STATUS_SHARING_VIOLATION);
1143 	}
1144 
1145 	mutex_exit(&of->f_mutex);
1146 	return (NT_STATUS_SUCCESS);
1147 }
1148 
1149 /*
1150  * smb_ofile_rename_check
1151  *
1152  * This does the work described in MS-FSA 2.1.5.1.2.2 (Algorithm
1153  * to Check Sharing Access to an Existing Stream or Directory),
1154  * where the "open in-progress" has DesiredAccess = DELETE and
1155  * SharingMode = SHARE_READ | SHARE_WRITE | SHARE_DELETE.
1156  */
1157 
1158 uint32_t
1159 smb_ofile_rename_check(smb_ofile_t *of)
1160 {
1161 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
1162 
1163 	mutex_enter(&of->f_mutex);
1164 
1165 	if (of->f_state != SMB_OFILE_STATE_OPEN) {
1166 		mutex_exit(&of->f_mutex);
1167 		return (NT_STATUS_INVALID_HANDLE);
1168 	}
1169 
1170 	if ((of->f_granted_access & FILE_DATA_ALL) == 0) {
1171 		mutex_exit(&of->f_mutex);
1172 		return (NT_STATUS_SUCCESS);
1173 	}
1174 
1175 	if ((of->f_share_access & FILE_SHARE_DELETE) == 0) {
1176 		mutex_exit(&of->f_mutex);
1177 		return (NT_STATUS_SHARING_VIOLATION);
1178 	}
1179 
1180 	mutex_exit(&of->f_mutex);
1181 	return (NT_STATUS_SUCCESS);
1182 }
1183 
1184 /*
1185  * smb_ofile_delete_check
1186  *
1187  * An open file can be deleted only if opened for
1188  * accessing meta data. Share modes aren't important
1189  * in this case.
1190  *
1191  * NOTE: there is another mechanism for deleting an
1192  * open file that NT clients usually use.
1193  * That's setting "Delete on close" flag for an open
1194  * file.  In this way the file will be deleted after
1195  * last close. This flag can be set by SmbTrans2SetFileInfo
1196  * with FILE_DISPOSITION_INFO information level.
1197  * For setting this flag, the file should be opened by
1198  * DELETE access in the FID that is passed in the Trans2
1199  * request.
1200  */
1201 
1202 uint32_t
1203 smb_ofile_delete_check(smb_ofile_t *of)
1204 {
1205 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
1206 
1207 	mutex_enter(&of->f_mutex);
1208 
1209 	if (of->f_state != SMB_OFILE_STATE_OPEN) {
1210 		mutex_exit(&of->f_mutex);
1211 		return (NT_STATUS_INVALID_HANDLE);
1212 	}
1213 
1214 	if (of->f_granted_access &
1215 	    (FILE_READ_DATA | FILE_WRITE_DATA |
1216 	    FILE_APPEND_DATA | FILE_EXECUTE | DELETE)) {
1217 		mutex_exit(&of->f_mutex);
1218 		return (NT_STATUS_SHARING_VIOLATION);
1219 	}
1220 
1221 	mutex_exit(&of->f_mutex);
1222 	return (NT_STATUS_SUCCESS);
1223 }
1224 
1225 cred_t *
1226 smb_ofile_getcred(smb_ofile_t *of)
1227 {
1228 	return (of->f_cr);
1229 }
1230 
1231 /*
1232  * smb_ofile_set_delete_on_close
1233  *
1234  * Set the DeleteOnClose flag on the smb file. When the file is closed,
1235  * the flag will be transferred to the smb node, which will commit the
1236  * delete operation and inhibit subsequent open requests.
1237  *
1238  * When DeleteOnClose is set on an smb_node, the common open code will
1239  * reject subsequent open requests for the file. Observation of Windows
1240  * 2000 indicates that subsequent opens should be allowed (assuming
1241  * there would be no sharing violation) until the file is closed using
1242  * the fid on which the DeleteOnClose was requested.
1243  */
1244 void
1245 smb_ofile_set_delete_on_close(smb_ofile_t *of)
1246 {
1247 	mutex_enter(&of->f_mutex);
1248 	of->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE;
1249 	mutex_exit(&of->f_mutex);
1250 }
1251 
1252 /*
1253  * Encode open file information into a buffer; needed in user space to
1254  * support RPC requests.
1255  */
1256 static int
1257 smb_ofile_netinfo_encode(smb_ofile_t *of, uint8_t *buf, size_t buflen,
1258     uint32_t *nbytes)
1259 {
1260 	smb_netfileinfo_t	fi;
1261 	int			rc;
1262 
1263 	rc = smb_ofile_netinfo_init(of, &fi);
1264 	if (rc == 0) {
1265 		rc = smb_netfileinfo_encode(&fi, buf, buflen, nbytes);
1266 		smb_ofile_netinfo_fini(&fi);
1267 	}
1268 
1269 	return (rc);
1270 }
1271 
1272 static int
1273 smb_ofile_netinfo_init(smb_ofile_t *of, smb_netfileinfo_t *fi)
1274 {
1275 	smb_user_t	*user;
1276 	smb_tree_t	*tree;
1277 	smb_node_t	*node;
1278 	char		*path;
1279 	char		*buf;
1280 	int		rc;
1281 
1282 	ASSERT(of);
1283 	user = of->f_user;
1284 	tree = of->f_tree;
1285 	ASSERT(user);
1286 	ASSERT(tree);
1287 
1288 	buf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1289 
1290 	switch (of->f_ftype) {
1291 	case SMB_FTYPE_DISK:
1292 		node = of->f_node;
1293 		ASSERT(node);
1294 
1295 		fi->fi_permissions = of->f_granted_access;
1296 		fi->fi_numlocks = smb_lock_get_lock_count(node, of);
1297 
1298 		path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1299 
1300 		if (node != tree->t_snode) {
1301 			rc = smb_node_getshrpath(node, tree, path, MAXPATHLEN);
1302 			if (rc != 0)
1303 				(void) strlcpy(path, node->od_name, MAXPATHLEN);
1304 		}
1305 
1306 		(void) snprintf(buf, MAXPATHLEN, "%s:%s", tree->t_sharename,
1307 		    path);
1308 		kmem_free(path, MAXPATHLEN);
1309 		break;
1310 
1311 	case SMB_FTYPE_MESG_PIPE:
1312 		ASSERT(of->f_pipe);
1313 
1314 		fi->fi_permissions = FILE_READ_DATA | FILE_WRITE_DATA |
1315 		    FILE_EXECUTE;
1316 		fi->fi_numlocks = 0;
1317 		(void) snprintf(buf, MAXPATHLEN, "\\PIPE\\%s",
1318 		    of->f_pipe->p_name);
1319 		break;
1320 
1321 	default:
1322 		kmem_free(buf, MAXPATHLEN);
1323 		return (-1);
1324 	}
1325 
1326 	fi->fi_fid = of->f_fid;
1327 	fi->fi_uniqid = of->f_uniqid;
1328 	fi->fi_pathlen = strlen(buf) + 1;
1329 	fi->fi_path = smb_mem_strdup(buf);
1330 	kmem_free(buf, MAXPATHLEN);
1331 
1332 	fi->fi_namelen = user->u_domain_len + user->u_name_len + 2;
1333 	fi->fi_username = kmem_alloc(fi->fi_namelen, KM_SLEEP);
1334 	(void) snprintf(fi->fi_username, fi->fi_namelen, "%s\\%s",
1335 	    user->u_domain, user->u_name);
1336 	return (0);
1337 }
1338 
1339 static void
1340 smb_ofile_netinfo_fini(smb_netfileinfo_t *fi)
1341 {
1342 	if (fi == NULL)
1343 		return;
1344 
1345 	if (fi->fi_path)
1346 		smb_mem_free(fi->fi_path);
1347 	if (fi->fi_username)
1348 		kmem_free(fi->fi_username, fi->fi_namelen);
1349 
1350 	bzero(fi, sizeof (smb_netfileinfo_t));
1351 }
1352 
1353 /*
1354  * A query of user and group quotas may span multiple requests.
1355  * f_quota_resume is used to determine where the query should
1356  * be resumed, in a subsequent request. f_quota_resume contains
1357  * the SID of the last quota entry returned to the client.
1358  */
1359 void
1360 smb_ofile_set_quota_resume(smb_ofile_t *ofile, char *resume)
1361 {
1362 	ASSERT(ofile);
1363 	mutex_enter(&ofile->f_mutex);
1364 	if (resume == NULL)
1365 		bzero(ofile->f_quota_resume, SMB_SID_STRSZ);
1366 	else
1367 		(void) strlcpy(ofile->f_quota_resume, resume, SMB_SID_STRSZ);
1368 	mutex_exit(&ofile->f_mutex);
1369 }
1370 
1371 void
1372 smb_ofile_get_quota_resume(smb_ofile_t *ofile, char *buf, int bufsize)
1373 {
1374 	ASSERT(ofile);
1375 	mutex_enter(&ofile->f_mutex);
1376 	(void) strlcpy(buf, ofile->f_quota_resume, bufsize);
1377 	mutex_exit(&ofile->f_mutex);
1378 }
1379