xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_ofile.c (revision 5cb2894a4e6bdb3bf08605e4bc819421f53c5b36)
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 2017 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 		smb_node_inc_open_ofiles(node);
282 		smb_node_add_ofile(node, of);
283 		smb_node_ref(node);
284 		smb_server_inc_files(of->f_server);
285 	}
286 	smb_llist_enter(&tree->t_ofile_list, RW_WRITER);
287 	smb_llist_insert_tail(&tree->t_ofile_list, of);
288 	smb_llist_exit(&tree->t_ofile_list);
289 	atomic_inc_32(&tree->t_open_files);
290 	atomic_inc_32(&of->f_session->s_file_cnt);
291 	return (of);
292 
293 errout:
294 	smb_user_release(of->f_user);
295 	crfree(of->f_cr);
296 
297 	list_destroy(&of->f_notify.nc_waiters);
298 	mutex_destroy(&of->f_mutex);
299 
300 	of->f_magic = 0;
301 	kmem_cache_free(smb_cache_ofile, of);
302 
303 	smb_idpool_free(&tree->t_fid_pool, fid);
304 
305 	return (NULL);
306 }
307 
308 /*
309  * smb_ofile_close
310  */
311 void
312 smb_ofile_close(smb_ofile_t *of, int32_t mtime_sec)
313 {
314 	smb_attr_t *pa;
315 	timestruc_t now;
316 	uint32_t flags = 0;
317 
318 	SMB_OFILE_VALID(of);
319 
320 	mutex_enter(&of->f_mutex);
321 	ASSERT(of->f_refcnt);
322 	if (of->f_state != SMB_OFILE_STATE_OPEN) {
323 		mutex_exit(&of->f_mutex);
324 		return;
325 	}
326 	of->f_state = SMB_OFILE_STATE_CLOSING;
327 	mutex_exit(&of->f_mutex);
328 
329 	switch (of->f_ftype) {
330 	case SMB_FTYPE_BYTE_PIPE:
331 	case SMB_FTYPE_MESG_PIPE:
332 		smb_opipe_close(of);
333 		smb_server_dec_pipes(of->f_server);
334 		break;
335 
336 	case SMB_FTYPE_DISK:
337 	case SMB_FTYPE_PRINTER:
338 		/*
339 		 * In here we make changes to of->f_pending_attr
340 		 * while not holding of->f_mutex.  This is OK
341 		 * because we've changed f_state to CLOSING,
342 		 * so no more threads will take this path.
343 		 */
344 		pa = &of->f_pending_attr;
345 		if (mtime_sec != 0) {
346 			pa->sa_vattr.va_mtime.tv_sec = mtime_sec;
347 			pa->sa_mask |= SMB_AT_MTIME;
348 		}
349 
350 		/*
351 		 * If we have ever modified data via this handle
352 		 * (write or truncate) and if the mtime was not
353 		 * set via this handle, update the mtime again
354 		 * during the close.  Windows expects this.
355 		 * [ MS-FSA 2.1.5.4 "Update Timestamps" ]
356 		 */
357 		if (of->f_written &&
358 		    (pa->sa_mask & SMB_AT_MTIME) == 0) {
359 			pa->sa_mask |= SMB_AT_MTIME;
360 			gethrestime(&now);
361 			pa->sa_vattr.va_mtime = now;
362 		}
363 
364 		if (of->f_flags & SMB_OFLAGS_SET_DELETE_ON_CLOSE) {
365 			if (smb_tree_has_feature(of->f_tree,
366 			    SMB_TREE_CATIA)) {
367 				flags |= SMB_CATIA;
368 			}
369 			(void) smb_node_set_delete_on_close(of->f_node,
370 			    of->f_cr, flags);
371 		}
372 		smb_fsop_unshrlock(of->f_cr, of->f_node, of->f_uniqid);
373 		smb_node_destroy_lock_by_ofile(of->f_node, of);
374 
375 		if (smb_node_is_file(of->f_node)) {
376 			(void) smb_fsop_close(of->f_node, of->f_mode,
377 			    of->f_cr);
378 			smb_oplock_release(of->f_node, of);
379 		} else {
380 			/*
381 			 * If there was an odir, close it.
382 			 */
383 			if (of->f_odir != NULL)
384 				smb_odir_close(of->f_odir);
385 			/*
386 			 * Cancel any notify change requests that
387 			 * might be watching this open file (dir),
388 			 * and unsubscribe it from node events.
389 			 *
390 			 * Can't hold f_mutex when calling smb_notify_ofile.
391 			 * Don't really need it when unsubscribing, but
392 			 * harmless, and consistent with subscribing.
393 			 */
394 			if (of->f_notify.nc_subscribed)
395 				smb_notify_ofile(of,
396 				    FILE_ACTION_HANDLE_CLOSED, NULL);
397 			mutex_enter(&of->f_mutex);
398 			if (of->f_notify.nc_subscribed) {
399 				of->f_notify.nc_subscribed = B_FALSE;
400 				smb_node_fcn_unsubscribe(of->f_node);
401 				of->f_notify.nc_filter = 0;
402 			}
403 			mutex_exit(&of->f_mutex);
404 		}
405 		if (smb_node_dec_open_ofiles(of->f_node) == 0) {
406 			/*
407 			 * Last close.  If we're not deleting
408 			 * the file, apply any pending attrs.
409 			 * Leave allocsz zero when no open files,
410 			 * just to avoid confusion, because it's
411 			 * only updated when there are opens.
412 			 */
413 			mutex_enter(&of->f_node->n_mutex);
414 			if (of->f_node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
415 				smb_node_delete_on_close(of->f_node);
416 				pa->sa_mask = 0;
417 			}
418 			of->f_node->n_allocsz = 0;
419 			mutex_exit(&of->f_node->n_mutex);
420 		}
421 		if (pa->sa_mask != 0) {
422 			/*
423 			 * Commit any pending attributes from
424 			 * the ofile we're closing.  Note that
425 			 * we pass NULL as the ofile to setattr
426 			 * so it will write to the file system
427 			 * and not keep anything on the ofile.
428 			 */
429 			(void) smb_node_setattr(NULL, of->f_node,
430 			    of->f_cr, NULL, pa);
431 		}
432 
433 		smb_server_dec_files(of->f_server);
434 		break;
435 	}
436 	atomic_dec_32(&of->f_tree->t_open_files);
437 
438 	mutex_enter(&of->f_mutex);
439 	ASSERT(of->f_refcnt);
440 	ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING);
441 	of->f_state = SMB_OFILE_STATE_CLOSED;
442 	mutex_exit(&of->f_mutex);
443 }
444 
445 /*
446  * smb_ofile_close_all
447  *
448  *
449  */
450 void
451 smb_ofile_close_all(
452     smb_tree_t		*tree)
453 {
454 	smb_ofile_t	*of;
455 
456 	ASSERT(tree);
457 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
458 
459 	smb_llist_enter(&tree->t_ofile_list, RW_READER);
460 	of = smb_llist_head(&tree->t_ofile_list);
461 	while (of) {
462 		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
463 		ASSERT(of->f_tree == tree);
464 		of = smb_ofile_close_and_next(of);
465 	}
466 	smb_llist_exit(&tree->t_ofile_list);
467 }
468 
469 /*
470  * smb_ofiles_close_by_pid
471  *
472  *
473  */
474 void
475 smb_ofile_close_all_by_pid(
476     smb_tree_t		*tree,
477     uint16_t		pid)
478 {
479 	smb_ofile_t	*of;
480 
481 	ASSERT(tree);
482 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
483 
484 	smb_llist_enter(&tree->t_ofile_list, RW_READER);
485 	of = smb_llist_head(&tree->t_ofile_list);
486 	while (of) {
487 		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
488 		ASSERT(of->f_tree == tree);
489 		if (of->f_opened_by_pid == pid) {
490 			of = smb_ofile_close_and_next(of);
491 		} else {
492 			of = smb_llist_next(&tree->t_ofile_list, of);
493 		}
494 	}
495 	smb_llist_exit(&tree->t_ofile_list);
496 }
497 
498 /*
499  * If the enumeration request is for ofile data, handle it here.
500  * Otherwise, return.
501  *
502  * This function should be called with a hold on the ofile.
503  */
504 int
505 smb_ofile_enum(smb_ofile_t *of, smb_svcenum_t *svcenum)
506 {
507 	uint8_t *pb;
508 	uint_t nbytes;
509 	int rc;
510 
511 	ASSERT(of);
512 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
513 	ASSERT(of->f_refcnt);
514 
515 	if (svcenum->se_type != SMB_SVCENUM_TYPE_FILE)
516 		return (0);
517 
518 	if (svcenum->se_nskip > 0) {
519 		svcenum->se_nskip--;
520 		return (0);
521 	}
522 
523 	if (svcenum->se_nitems >= svcenum->se_nlimit) {
524 		svcenum->se_nitems = svcenum->se_nlimit;
525 		return (0);
526 	}
527 
528 	pb = &svcenum->se_buf[svcenum->se_bused];
529 
530 	rc = smb_ofile_netinfo_encode(of, pb, svcenum->se_bavail,
531 	    &nbytes);
532 	if (rc == 0) {
533 		svcenum->se_bavail -= nbytes;
534 		svcenum->se_bused += nbytes;
535 		svcenum->se_nitems++;
536 	}
537 
538 	return (rc);
539 }
540 
541 /*
542  * Take a reference on an open file.
543  */
544 boolean_t
545 smb_ofile_hold(smb_ofile_t *of)
546 {
547 	ASSERT(of);
548 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
549 
550 	mutex_enter(&of->f_mutex);
551 
552 	if (of->f_state != SMB_OFILE_STATE_OPEN) {
553 		mutex_exit(&of->f_mutex);
554 		return (B_FALSE);
555 	}
556 	of->f_refcnt++;
557 
558 	mutex_exit(&of->f_mutex);
559 	return (B_TRUE);
560 }
561 
562 /*
563  * Release a reference on a file.  If the reference count falls to
564  * zero and the file has been closed, post the object for deletion.
565  * Object deletion is deferred to avoid modifying a list while an
566  * iteration may be in progress.
567  */
568 void
569 smb_ofile_release(smb_ofile_t *of)
570 {
571 	SMB_OFILE_VALID(of);
572 
573 	mutex_enter(&of->f_mutex);
574 	ASSERT(of->f_refcnt);
575 	of->f_refcnt--;
576 	switch (of->f_state) {
577 	case SMB_OFILE_STATE_OPEN:
578 	case SMB_OFILE_STATE_CLOSING:
579 		break;
580 
581 	case SMB_OFILE_STATE_CLOSED:
582 		if (of->f_refcnt == 0)
583 			smb_tree_post_ofile(of->f_tree, of);
584 		break;
585 
586 	default:
587 		ASSERT(0);
588 		break;
589 	}
590 	mutex_exit(&of->f_mutex);
591 }
592 
593 /*
594  * smb_ofile_request_complete
595  *
596  * During oplock acquisition, all other oplock requests on the node
597  * are blocked until the acquire request completes and the response
598  * is on the wire.
599  * Call smb_oplock_broadcast to notify the node that the request
600  * has completed.
601  *
602  * THIS MECHANISM RELIES ON THE FACT THAT THE OFILE IS NOT REMOVED
603  * FROM THE SR UNTIL REQUEST COMPLETION (when the sr is destroyed)
604  */
605 void
606 smb_ofile_request_complete(smb_ofile_t *of)
607 {
608 	SMB_OFILE_VALID(of);
609 
610 	switch (of->f_ftype) {
611 	case SMB_FTYPE_DISK:
612 		ASSERT(of->f_node);
613 		smb_oplock_broadcast(of->f_node);
614 		break;
615 	case SMB_FTYPE_MESG_PIPE:
616 		break;
617 	default:
618 		break;
619 	}
620 }
621 
622 /*
623  * smb_ofile_lookup_by_fid
624  *
625  * Find the open file whose fid matches the one specified in the request.
626  * If we can't find the fid or the shares (trees) don't match, we have a
627  * bad fid.
628  */
629 smb_ofile_t *
630 smb_ofile_lookup_by_fid(
631     smb_request_t	*sr,
632     uint16_t		fid)
633 {
634 	smb_tree_t	*tree = sr->tid_tree;
635 	smb_llist_t	*of_list;
636 	smb_ofile_t	*of;
637 
638 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
639 
640 	of_list = &tree->t_ofile_list;
641 
642 	smb_llist_enter(of_list, RW_READER);
643 	of = smb_llist_head(of_list);
644 	while (of) {
645 		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
646 		ASSERT(of->f_tree == tree);
647 		if (of->f_fid == fid)
648 			break;
649 		of = smb_llist_next(of_list, of);
650 	}
651 	if (of == NULL)
652 		goto out;
653 
654 	/*
655 	 * Only allow use of a given FID with the same UID that
656 	 * was used to open it.  MS-CIFS 3.3.5.14
657 	 */
658 	if (of->f_user != sr->uid_user) {
659 		of = NULL;
660 		goto out;
661 	}
662 
663 	mutex_enter(&of->f_mutex);
664 	if (of->f_state != SMB_OFILE_STATE_OPEN) {
665 		mutex_exit(&of->f_mutex);
666 		of = NULL;
667 		goto out;
668 	}
669 	of->f_refcnt++;
670 	mutex_exit(&of->f_mutex);
671 
672 out:
673 	smb_llist_exit(of_list);
674 	return (of);
675 }
676 
677 /*
678  * smb_ofile_lookup_by_uniqid
679  *
680  * Find the open file whose uniqid matches the one specified in the request.
681  */
682 smb_ofile_t *
683 smb_ofile_lookup_by_uniqid(smb_tree_t *tree, uint32_t uniqid)
684 {
685 	smb_llist_t	*of_list;
686 	smb_ofile_t	*of;
687 
688 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
689 
690 	of_list = &tree->t_ofile_list;
691 	smb_llist_enter(of_list, RW_READER);
692 	of = smb_llist_head(of_list);
693 
694 	while (of) {
695 		ASSERT(of->f_magic == SMB_OFILE_MAGIC);
696 		ASSERT(of->f_tree == tree);
697 
698 		if (of->f_uniqid == uniqid) {
699 			if (smb_ofile_hold(of)) {
700 				smb_llist_exit(of_list);
701 				return (of);
702 			}
703 		}
704 
705 		of = smb_llist_next(of_list, of);
706 	}
707 
708 	smb_llist_exit(of_list);
709 	return (NULL);
710 }
711 
712 /*
713  * Disallow NetFileClose on certain ofiles to avoid side-effects.
714  * Closing a tree root is not allowed: use NetSessionDel or NetShareDel.
715  * Closing SRVSVC connections is not allowed because this NetFileClose
716  * request may depend on this ofile.
717  */
718 boolean_t
719 smb_ofile_disallow_fclose(smb_ofile_t *of)
720 {
721 	ASSERT(of);
722 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
723 	ASSERT(of->f_refcnt);
724 
725 	switch (of->f_ftype) {
726 	case SMB_FTYPE_DISK:
727 		ASSERT(of->f_tree);
728 		return (of->f_node == of->f_tree->t_snode);
729 
730 	case SMB_FTYPE_MESG_PIPE:
731 		ASSERT(of->f_pipe);
732 		if (smb_strcasecmp(of->f_pipe->p_name, "SRVSVC", 0) == 0)
733 			return (B_TRUE);
734 		break;
735 	default:
736 		break;
737 	}
738 
739 	return (B_FALSE);
740 }
741 
742 /*
743  * smb_ofile_set_flags
744  *
745  * Return value:
746  *
747  *	Current flags value
748  *
749  */
750 void
751 smb_ofile_set_flags(
752     smb_ofile_t		*of,
753     uint32_t		flags)
754 {
755 	ASSERT(of);
756 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
757 	ASSERT(of->f_refcnt);
758 
759 	mutex_enter(&of->f_mutex);
760 	of->f_flags |= flags;
761 	mutex_exit(&of->f_mutex);
762 }
763 
764 /*
765  * smb_ofile_seek
766  *
767  * Return value:
768  *
769  *	0		Success
770  *	EINVAL		Unknown mode
771  *	EOVERFLOW	offset too big
772  *
773  */
774 int
775 smb_ofile_seek(
776     smb_ofile_t		*of,
777     ushort_t		mode,
778     int32_t		off,
779     uint32_t		*retoff)
780 {
781 	u_offset_t	newoff = 0;
782 	int		rc = 0;
783 	smb_attr_t	attr;
784 
785 	ASSERT(of);
786 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
787 	ASSERT(of->f_refcnt);
788 
789 	mutex_enter(&of->f_mutex);
790 	switch (mode) {
791 	case SMB_SEEK_SET:
792 		if (off < 0)
793 			newoff = 0;
794 		else
795 			newoff = (u_offset_t)off;
796 		break;
797 
798 	case SMB_SEEK_CUR:
799 		if (off < 0 && (-off) > of->f_seek_pos)
800 			newoff = 0;
801 		else
802 			newoff = of->f_seek_pos + (u_offset_t)off;
803 		break;
804 
805 	case SMB_SEEK_END:
806 		bzero(&attr, sizeof (smb_attr_t));
807 		attr.sa_mask |= SMB_AT_SIZE;
808 		rc = smb_fsop_getattr(NULL, zone_kcred(), of->f_node, &attr);
809 		if (rc != 0) {
810 			mutex_exit(&of->f_mutex);
811 			return (rc);
812 		}
813 		if (off < 0 && (-off) > attr.sa_vattr.va_size)
814 			newoff = 0;
815 		else
816 			newoff = attr.sa_vattr.va_size + (u_offset_t)off;
817 		break;
818 
819 	default:
820 		mutex_exit(&of->f_mutex);
821 		return (EINVAL);
822 	}
823 
824 	/*
825 	 * See comments at the beginning of smb_seek.c.
826 	 * If the offset is greater than UINT_MAX, we will return an error.
827 	 */
828 
829 	if (newoff > UINT_MAX) {
830 		rc = EOVERFLOW;
831 	} else {
832 		of->f_seek_pos = newoff;
833 		*retoff = (uint32_t)newoff;
834 	}
835 	mutex_exit(&of->f_mutex);
836 	return (rc);
837 }
838 
839 /*
840  * smb_ofile_flush
841  *
842  * If writes on this file are not synchronous, flush it using the NFSv3
843  * commit interface.
844  *
845  * XXX - todo: Flush named pipe should drain writes.
846  */
847 void
848 smb_ofile_flush(struct smb_request *sr, struct smb_ofile *of)
849 {
850 	switch (of->f_ftype) {
851 	case SMB_FTYPE_DISK:
852 		if ((of->f_node->flags & NODE_FLAGS_WRITE_THROUGH) == 0)
853 			(void) smb_fsop_commit(sr, of->f_cr, of->f_node);
854 		break;
855 	default:
856 		break;
857 	}
858 }
859 
860 /*
861  * smb_ofile_is_open
862  */
863 boolean_t
864 smb_ofile_is_open(smb_ofile_t *of)
865 {
866 	boolean_t	rc;
867 
868 	SMB_OFILE_VALID(of);
869 
870 	mutex_enter(&of->f_mutex);
871 	rc = smb_ofile_is_open_locked(of);
872 	mutex_exit(&of->f_mutex);
873 	return (rc);
874 }
875 
876 /* *************************** Static Functions ***************************** */
877 
878 /*
879  * Determine whether or not an ofile is open.
880  * This function must be called with the mutex held.
881  */
882 static boolean_t
883 smb_ofile_is_open_locked(smb_ofile_t *of)
884 {
885 	switch (of->f_state) {
886 	case SMB_OFILE_STATE_OPEN:
887 		return (B_TRUE);
888 
889 	case SMB_OFILE_STATE_CLOSING:
890 	case SMB_OFILE_STATE_CLOSED:
891 		return (B_FALSE);
892 
893 	default:
894 		ASSERT(0);
895 		return (B_FALSE);
896 	}
897 }
898 
899 /*
900  * This function closes the file passed in (if appropriate) and returns the
901  * next open file in the list of open files of the tree of the open file passed
902  * in. It requires that the list of open files of the tree be entered in
903  * RW_READER mode before being called.
904  */
905 static smb_ofile_t *
906 smb_ofile_close_and_next(smb_ofile_t *of)
907 {
908 	smb_ofile_t	*next_of;
909 	smb_tree_t	*tree;
910 
911 	ASSERT(of);
912 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
913 
914 	mutex_enter(&of->f_mutex);
915 	switch (of->f_state) {
916 	case SMB_OFILE_STATE_OPEN:
917 		/* The file is still open. */
918 		of->f_refcnt++;
919 		ASSERT(of->f_refcnt);
920 		tree = of->f_tree;
921 		mutex_exit(&of->f_mutex);
922 		smb_llist_exit(&of->f_tree->t_ofile_list);
923 		smb_ofile_close(of, 0);
924 		smb_ofile_release(of);
925 		smb_llist_enter(&tree->t_ofile_list, RW_READER);
926 		next_of = smb_llist_head(&tree->t_ofile_list);
927 		break;
928 	case SMB_OFILE_STATE_CLOSING:
929 	case SMB_OFILE_STATE_CLOSED:
930 		/*
931 		 * The ofile exists but is closed or
932 		 * in the process being closed.
933 		 */
934 		mutex_exit(&of->f_mutex);
935 		next_of = smb_llist_next(&of->f_tree->t_ofile_list, of);
936 		break;
937 	default:
938 		ASSERT(0);
939 		mutex_exit(&of->f_mutex);
940 		next_of = smb_llist_next(&of->f_tree->t_ofile_list, of);
941 		break;
942 	}
943 	return (next_of);
944 }
945 
946 /*
947  * Delete an ofile.
948  *
949  * Remove the ofile from the tree list before freeing resources
950  * associated with the ofile.
951  */
952 void
953 smb_ofile_delete(void *arg)
954 {
955 	smb_tree_t	*tree;
956 	smb_ofile_t	*of = (smb_ofile_t *)arg;
957 
958 	SMB_OFILE_VALID(of);
959 	ASSERT(of->f_refcnt == 0);
960 	ASSERT(of->f_state == SMB_OFILE_STATE_CLOSED);
961 	ASSERT(!SMB_OFILE_OPLOCK_GRANTED(of));
962 
963 	tree = of->f_tree;
964 	smb_llist_enter(&tree->t_ofile_list, RW_WRITER);
965 	smb_llist_remove(&tree->t_ofile_list, of);
966 	smb_idpool_free(&tree->t_fid_pool, of->f_fid);
967 	atomic_dec_32(&tree->t_session->s_file_cnt);
968 	smb_llist_exit(&tree->t_ofile_list);
969 
970 	/*
971 	 * Remove this ofile from the node's n_ofile_list so it
972 	 * can't be found by list walkers like notify or oplock.
973 	 * Keep the node ref. until later in this function so
974 	 * of->f_node remains valid while we destroy the ofile.
975 	 */
976 	if (of->f_ftype == SMB_FTYPE_DISK ||
977 	    of->f_ftype == SMB_FTYPE_PRINTER) {
978 		ASSERT(of->f_node != NULL);
979 		/*
980 		 * Note smb_ofile_close did smb_node_dec_open_ofiles()
981 		 */
982 		smb_node_rem_ofile(of->f_node, of);
983 	}
984 
985 	mutex_enter(&of->f_mutex);
986 	mutex_exit(&of->f_mutex);
987 
988 	switch (of->f_ftype) {
989 	case SMB_FTYPE_BYTE_PIPE:
990 	case SMB_FTYPE_MESG_PIPE:
991 		smb_opipe_dealloc(of->f_pipe);
992 		of->f_pipe = NULL;
993 		break;
994 	case SMB_FTYPE_DISK:
995 		ASSERT(of->f_notify.nc_subscribed == B_FALSE);
996 		MBC_FLUSH(&of->f_notify.nc_buffer);
997 		if (of->f_odir != NULL)
998 			smb_odir_release(of->f_odir);
999 		/* FALLTHROUGH */
1000 	case SMB_FTYPE_PRINTER:
1001 		/*
1002 		 * Did smb_node_rem_ofile above.
1003 		 */
1004 		ASSERT(of->f_node != NULL);
1005 		smb_node_release(of->f_node);
1006 		break;
1007 	default:
1008 		ASSERT(!"f_ftype");
1009 		break;
1010 	}
1011 
1012 	of->f_magic = (uint32_t)~SMB_OFILE_MAGIC;
1013 	list_destroy(&of->f_notify.nc_waiters);
1014 	mutex_destroy(&of->f_mutex);
1015 	smb_user_release(of->f_user);
1016 	crfree(of->f_cr);
1017 	kmem_cache_free(smb_cache_ofile, of);
1018 }
1019 
1020 /*
1021  * smb_ofile_access
1022  *
1023  * This function will check to see if the access requested is granted.
1024  * Returns NT status codes.
1025  */
1026 uint32_t
1027 smb_ofile_access(smb_ofile_t *of, cred_t *cr, uint32_t access)
1028 {
1029 
1030 	if ((of == NULL) || (cr == zone_kcred()))
1031 		return (NT_STATUS_SUCCESS);
1032 
1033 	/*
1034 	 * If the request is for something
1035 	 * I don't grant it is an error
1036 	 */
1037 	if (~(of->f_granted_access) & access) {
1038 		if (!(of->f_granted_access & ACCESS_SYSTEM_SECURITY) &&
1039 		    (access & ACCESS_SYSTEM_SECURITY)) {
1040 			return (NT_STATUS_PRIVILEGE_NOT_HELD);
1041 		}
1042 		return (NT_STATUS_ACCESS_DENIED);
1043 	}
1044 
1045 	return (NT_STATUS_SUCCESS);
1046 }
1047 
1048 /*
1049  * smb_ofile_share_check
1050  *
1051  * Check if ofile was opened with share access NONE (0).
1052  * Returns: B_TRUE  - share access non-zero
1053  *          B_FALSE - share access NONE
1054  */
1055 boolean_t
1056 smb_ofile_share_check(smb_ofile_t *of)
1057 {
1058 	return (!SMB_DENY_ALL(of->f_share_access));
1059 }
1060 
1061 /*
1062  * check file sharing rules for current open request
1063  * against existing open instances of the same file
1064  *
1065  * Returns NT_STATUS_SHARING_VIOLATION if there is any
1066  * sharing conflict, otherwise returns NT_STATUS_SUCCESS.
1067  */
1068 uint32_t
1069 smb_ofile_open_check(smb_ofile_t *of, uint32_t desired_access,
1070     uint32_t share_access)
1071 {
1072 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
1073 
1074 	mutex_enter(&of->f_mutex);
1075 
1076 	if (of->f_state != SMB_OFILE_STATE_OPEN) {
1077 		mutex_exit(&of->f_mutex);
1078 		return (NT_STATUS_INVALID_HANDLE);
1079 	}
1080 
1081 	/* if it's just meta data */
1082 	if ((of->f_granted_access & FILE_DATA_ALL) == 0) {
1083 		mutex_exit(&of->f_mutex);
1084 		return (NT_STATUS_SUCCESS);
1085 	}
1086 
1087 	/*
1088 	 * Check requested share access against the
1089 	 * open granted (desired) access
1090 	 */
1091 	if (SMB_DENY_DELETE(share_access) && (of->f_granted_access & DELETE)) {
1092 		mutex_exit(&of->f_mutex);
1093 		return (NT_STATUS_SHARING_VIOLATION);
1094 	}
1095 
1096 	if (SMB_DENY_READ(share_access) &&
1097 	    (of->f_granted_access & (FILE_READ_DATA | FILE_EXECUTE))) {
1098 		mutex_exit(&of->f_mutex);
1099 		return (NT_STATUS_SHARING_VIOLATION);
1100 	}
1101 
1102 	if (SMB_DENY_WRITE(share_access) &&
1103 	    (of->f_granted_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) {
1104 		mutex_exit(&of->f_mutex);
1105 		return (NT_STATUS_SHARING_VIOLATION);
1106 	}
1107 
1108 	/* check requested desired access against the open share access */
1109 	if (SMB_DENY_DELETE(of->f_share_access) && (desired_access & DELETE)) {
1110 		mutex_exit(&of->f_mutex);
1111 		return (NT_STATUS_SHARING_VIOLATION);
1112 	}
1113 
1114 	if (SMB_DENY_READ(of->f_share_access) &&
1115 	    (desired_access & (FILE_READ_DATA | FILE_EXECUTE))) {
1116 		mutex_exit(&of->f_mutex);
1117 		return (NT_STATUS_SHARING_VIOLATION);
1118 	}
1119 
1120 	if (SMB_DENY_WRITE(of->f_share_access) &&
1121 	    (desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) {
1122 		mutex_exit(&of->f_mutex);
1123 		return (NT_STATUS_SHARING_VIOLATION);
1124 	}
1125 
1126 	mutex_exit(&of->f_mutex);
1127 	return (NT_STATUS_SUCCESS);
1128 }
1129 
1130 /*
1131  * smb_ofile_rename_check
1132  *
1133  * This does the work described in MS-FSA 2.1.5.1.2.2 (Algorithm
1134  * to Check Sharing Access to an Existing Stream or Directory),
1135  * where the "open in-progress" has DesiredAccess = DELETE and
1136  * SharingMode = SHARE_READ | SHARE_WRITE | SHARE_DELETE.
1137  */
1138 
1139 uint32_t
1140 smb_ofile_rename_check(smb_ofile_t *of)
1141 {
1142 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
1143 
1144 	mutex_enter(&of->f_mutex);
1145 
1146 	if (of->f_state != SMB_OFILE_STATE_OPEN) {
1147 		mutex_exit(&of->f_mutex);
1148 		return (NT_STATUS_INVALID_HANDLE);
1149 	}
1150 
1151 	if ((of->f_granted_access & FILE_DATA_ALL) == 0) {
1152 		mutex_exit(&of->f_mutex);
1153 		return (NT_STATUS_SUCCESS);
1154 	}
1155 
1156 	if ((of->f_share_access & FILE_SHARE_DELETE) == 0) {
1157 		mutex_exit(&of->f_mutex);
1158 		return (NT_STATUS_SHARING_VIOLATION);
1159 	}
1160 
1161 	mutex_exit(&of->f_mutex);
1162 	return (NT_STATUS_SUCCESS);
1163 }
1164 
1165 /*
1166  * smb_ofile_delete_check
1167  *
1168  * An open file can be deleted only if opened for
1169  * accessing meta data. Share modes aren't important
1170  * in this case.
1171  *
1172  * NOTE: there is another mechanism for deleting an
1173  * open file that NT clients usually use.
1174  * That's setting "Delete on close" flag for an open
1175  * file.  In this way the file will be deleted after
1176  * last close. This flag can be set by SmbTrans2SetFileInfo
1177  * with FILE_DISPOSITION_INFO information level.
1178  * For setting this flag, the file should be opened by
1179  * DELETE access in the FID that is passed in the Trans2
1180  * request.
1181  */
1182 
1183 uint32_t
1184 smb_ofile_delete_check(smb_ofile_t *of)
1185 {
1186 	ASSERT(of->f_magic == SMB_OFILE_MAGIC);
1187 
1188 	mutex_enter(&of->f_mutex);
1189 
1190 	if (of->f_state != SMB_OFILE_STATE_OPEN) {
1191 		mutex_exit(&of->f_mutex);
1192 		return (NT_STATUS_INVALID_HANDLE);
1193 	}
1194 
1195 	if (of->f_granted_access &
1196 	    (FILE_READ_DATA | FILE_WRITE_DATA |
1197 	    FILE_APPEND_DATA | FILE_EXECUTE | DELETE)) {
1198 		mutex_exit(&of->f_mutex);
1199 		return (NT_STATUS_SHARING_VIOLATION);
1200 	}
1201 
1202 	mutex_exit(&of->f_mutex);
1203 	return (NT_STATUS_SUCCESS);
1204 }
1205 
1206 cred_t *
1207 smb_ofile_getcred(smb_ofile_t *of)
1208 {
1209 	return (of->f_cr);
1210 }
1211 
1212 /*
1213  * smb_ofile_set_delete_on_close
1214  *
1215  * Set the DeleteOnClose flag on the smb file. When the file is closed,
1216  * the flag will be transferred to the smb node, which will commit the
1217  * delete operation and inhibit subsequent open requests.
1218  *
1219  * When DeleteOnClose is set on an smb_node, the common open code will
1220  * reject subsequent open requests for the file. Observation of Windows
1221  * 2000 indicates that subsequent opens should be allowed (assuming
1222  * there would be no sharing violation) until the file is closed using
1223  * the fid on which the DeleteOnClose was requested.
1224  */
1225 void
1226 smb_ofile_set_delete_on_close(smb_ofile_t *of)
1227 {
1228 	mutex_enter(&of->f_mutex);
1229 	of->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE;
1230 	mutex_exit(&of->f_mutex);
1231 }
1232 
1233 /*
1234  * Encode open file information into a buffer; needed in user space to
1235  * support RPC requests.
1236  */
1237 static int
1238 smb_ofile_netinfo_encode(smb_ofile_t *of, uint8_t *buf, size_t buflen,
1239     uint32_t *nbytes)
1240 {
1241 	smb_netfileinfo_t	fi;
1242 	int			rc;
1243 
1244 	rc = smb_ofile_netinfo_init(of, &fi);
1245 	if (rc == 0) {
1246 		rc = smb_netfileinfo_encode(&fi, buf, buflen, nbytes);
1247 		smb_ofile_netinfo_fini(&fi);
1248 	}
1249 
1250 	return (rc);
1251 }
1252 
1253 static int
1254 smb_ofile_netinfo_init(smb_ofile_t *of, smb_netfileinfo_t *fi)
1255 {
1256 	smb_user_t	*user;
1257 	smb_tree_t	*tree;
1258 	smb_node_t	*node;
1259 	char		*path;
1260 	char		*buf;
1261 	int		rc;
1262 
1263 	ASSERT(of);
1264 	user = of->f_user;
1265 	tree = of->f_tree;
1266 	ASSERT(user);
1267 	ASSERT(tree);
1268 
1269 	buf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1270 
1271 	switch (of->f_ftype) {
1272 	case SMB_FTYPE_DISK:
1273 		node = of->f_node;
1274 		ASSERT(node);
1275 
1276 		fi->fi_permissions = of->f_granted_access;
1277 		fi->fi_numlocks = smb_lock_get_lock_count(node, of);
1278 
1279 		path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
1280 
1281 		if (node != tree->t_snode) {
1282 			rc = smb_node_getshrpath(node, tree, path, MAXPATHLEN);
1283 			if (rc != 0)
1284 				(void) strlcpy(path, node->od_name, MAXPATHLEN);
1285 		}
1286 
1287 		(void) snprintf(buf, MAXPATHLEN, "%s:%s", tree->t_sharename,
1288 		    path);
1289 		kmem_free(path, MAXPATHLEN);
1290 		break;
1291 
1292 	case SMB_FTYPE_MESG_PIPE:
1293 		ASSERT(of->f_pipe);
1294 
1295 		fi->fi_permissions = FILE_READ_DATA | FILE_WRITE_DATA |
1296 		    FILE_EXECUTE;
1297 		fi->fi_numlocks = 0;
1298 		(void) snprintf(buf, MAXPATHLEN, "\\PIPE\\%s",
1299 		    of->f_pipe->p_name);
1300 		break;
1301 
1302 	default:
1303 		kmem_free(buf, MAXPATHLEN);
1304 		return (-1);
1305 	}
1306 
1307 	fi->fi_fid = of->f_fid;
1308 	fi->fi_uniqid = of->f_uniqid;
1309 	fi->fi_pathlen = strlen(buf) + 1;
1310 	fi->fi_path = smb_mem_strdup(buf);
1311 	kmem_free(buf, MAXPATHLEN);
1312 
1313 	fi->fi_namelen = user->u_domain_len + user->u_name_len + 2;
1314 	fi->fi_username = kmem_alloc(fi->fi_namelen, KM_SLEEP);
1315 	(void) snprintf(fi->fi_username, fi->fi_namelen, "%s\\%s",
1316 	    user->u_domain, user->u_name);
1317 	return (0);
1318 }
1319 
1320 static void
1321 smb_ofile_netinfo_fini(smb_netfileinfo_t *fi)
1322 {
1323 	if (fi == NULL)
1324 		return;
1325 
1326 	if (fi->fi_path)
1327 		smb_mem_free(fi->fi_path);
1328 	if (fi->fi_username)
1329 		kmem_free(fi->fi_username, fi->fi_namelen);
1330 
1331 	bzero(fi, sizeof (smb_netfileinfo_t));
1332 }
1333 
1334 /*
1335  * A query of user and group quotas may span multiple requests.
1336  * f_quota_resume is used to determine where the query should
1337  * be resumed, in a subsequent request. f_quota_resume contains
1338  * the SID of the last quota entry returned to the client.
1339  */
1340 void
1341 smb_ofile_set_quota_resume(smb_ofile_t *ofile, char *resume)
1342 {
1343 	ASSERT(ofile);
1344 	mutex_enter(&ofile->f_mutex);
1345 	if (resume == NULL)
1346 		bzero(ofile->f_quota_resume, SMB_SID_STRSZ);
1347 	else
1348 		(void) strlcpy(ofile->f_quota_resume, resume, SMB_SID_STRSZ);
1349 	mutex_exit(&ofile->f_mutex);
1350 }
1351 
1352 void
1353 smb_ofile_get_quota_resume(smb_ofile_t *ofile, char *buf, int bufsize)
1354 {
1355 	ASSERT(ofile);
1356 	mutex_enter(&ofile->f_mutex);
1357 	(void) strlcpy(buf, ofile->f_quota_resume, bufsize);
1358 	mutex_exit(&ofile->f_mutex);
1359 }
1360