1/*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
4 *
5 * Portions Copyright (C) 2001 - 2014 Apple Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *    This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/vnode.h>
38#include <sys/xattr.h>
39#include <sys/kernel.h>
40#include <sys/proc.h>
41#include <sys/fcntl.h>
42#include <sys/mount.h>
43#include <sys/unistd.h>
44#include <sys/lockf.h>
45#include <sys/stat.h>
46#include <sys/mman.h>
47#include <vfs/vfs_support.h>
48#include <sys/namei.h>
49#include <libkern/OSAtomic.h>
50#include <sys/attr.h>
51#include <sys/kauth.h>
52#include <sys/syslog.h>
53
54#include <sys/smb_apple.h>
55#include <sys/smb_byte_order.h>
56#include <sys/mchain.h>
57#include <sys/msfscc.h>
58
59#include <netsmb/smb.h>
60#include <netsmb/smb_2.h>
61#include <netsmb/smb_rq.h>
62#include <netsmb/smb_rq_2.h>
63#include <netsmb/smb_conn.h>
64#include <netsmb/smb_conn_2.h>
65#include <netsmb/smb_subr.h>
66
67#include <smbfs/smbfs.h>
68#include <smbfs/smbfs_node.h>
69#include <smbfs/smbfs_subr.h>
70#include <smbfs/smbfs_subr_2.h>
71#include <smbfs/smbfs_lockf.h>
72#include <netsmb/smb_converter.h>
73#include <smbfs/smbfs_security.h>
74#include <smbfs/smbfs_attrlist.h>
75
76#include <sys/buf.h>
77
78char smb_symmagic[SMB_SYMMAGICLEN] = {'X', 'S', 'y', 'm', '\n'};
79
80static int smbfs_setattr(struct smb_share *share, vnode_t vp, struct vnode_attr *vap,
81                         vfs_context_t context);
82static void smbfs_set_create_vap(struct smb_share *share, struct vnode_attr *vap, vnode_t vp,
83								 vfs_context_t context, int set_mode_now);
84static int smbfs_vnop_compound_open(struct vnop_compound_open_args *ap);
85static int smbfs_vnop_open(struct vnop_open_args *ap);
86
87/*
88 * We were doing an IO and received an error. Was the error caused because we were
89 * reconnecting to the server. If yes then see if we can reopen the file. If everything
90 * is ok and the file was reopened then get the fid we need for doing the IO.
91 *
92 * The calling routine must hold a reference on the share
93 *
94 */
95static int
96smbfs_io_reopen(struct smb_share *share, vnode_t vp, uio_t uio,
97				uint16_t accessMode, SMBFID *fid, int error,
98				vfs_context_t context)
99{
100	struct smbnode *np = VTOSMB(vp);
101
102	if (!(np->f_openState & kNeedReopen))
103		return(error);
104
105	error = smbfs_smb_reopen_file(share, np, context);
106	if (error)
107		return(error);
108
109	if (FindFileRef(vp, vfs_context_proc(context), accessMode, kCheckDenyOrLocks,
110                    uio_offset(uio), uio_resid(uio), NULL, fid)) {
111        *fid = np->f_fid;
112    }
113
114    /* Should always have a fid at this point */
115    DBG_ASSERT(*fid != 0);
116	return(0);
117}
118
119/*
120 * smbfs_update_cache
121 *
122 * General routine that will update the meta data cache for the vnode. If a vap
123 * is passed in it will get filled in with the correct information, otherwise it
124 * will be ignored.
125 *
126 * The calling routine must hold a reference on the share
127 *
128 */
129int
130smbfs_update_cache(struct smb_share *share, vnode_t vp,
131						struct vnode_attr *vap, vfs_context_t context)
132 {
133	 /* If we are in reconnect mode, then use cached data for now. */
134	 int use_cached_data = 0;
135	 struct smbfattr fattr;
136	 int error = 0;
137
138     /* If we are in reconnect, use cached data if we have it */
139     if (VTOSMB(vp)->attribute_cache_timer != 0) {
140         use_cached_data = (share->ss_flags & SMBS_RECONNECTING);
141     }
142
143	 error = smbfs_attr_cachelookup(share, vp, vap, context, use_cached_data);
144
145     SMB_LOG_KTRACE(SMB_DBG_SMBFS_UPDATE_CACHE | DBG_FUNC_START,
146                    error, 0, 0, 0, 0);
147
148	 if (error != ENOENT) {
149		 goto done;
150     }
151
152	 error = smbfs_lookup(share, VTOSMB(vp), NULL, NULL, &fattr, context);
153     SMB_LOG_KTRACE(SMB_DBG_SMBFS_UPDATE_CACHE | DBG_FUNC_NONE,
154                    0xabc001, error, 0, 0, 0);
155
156     if ((error == ETIMEDOUT) && (VTOSMB(vp)->attribute_cache_timer != 0)) {
157         /* Just return the cached data */
158         use_cached_data = TRUE;
159         goto use_cache;
160     }
161
162	 if (error) {
163		 goto done;
164     }
165
166     /*
167	  * At this point we have the data from the server, so we can
168	  * just use cached data for now. See <rdar://problem/13813721>.
169	  */
170     use_cached_data = TRUE;
171
172     /* Enter in the latest data from the server into the caches */
173	 smbfs_attr_cacheenter(share, vp, &fattr, TRUE, context);
174
175use_cache:
176     error = smbfs_attr_cachelookup(share, vp, vap, context, use_cached_data);
177
178done:
179     SMB_LOG_KTRACE(SMB_DBG_SMBFS_UPDATE_CACHE | DBG_FUNC_END, error, 0, 0, 0, 0);
180	 return (error);
181 }
182
183/*
184 * smbfs_close - The internal open routine, the vnode should be locked
185 * before this is called. We only handle VREG in this routine.
186 *
187 * The calling routine must hold a reference on the share
188 *
189 */
190int
191smbfs_close(struct smb_share *share, vnode_t vp, int openMode,
192			vfs_context_t context)
193{
194	struct smbnode		*np = VTOSMB(vp);
195	proc_t				p = vfs_context_proc(context);
196	struct fileRefEntry	*fndEntry = NULL;
197	struct fileRefEntry	*curr = NULL;
198	int			error = 0;
199	uint16_t		accessMode = 0;
200    SMBFID fid = 0;
201	int32_t			needOpenFile;
202	uint16_t		openAccessMode;
203	uint32_t		rights;
204    struct smbfattr *fap = NULL;
205
206	/*
207	 * We have more than one open, so before closing see if the file needs to
208	 * be reopened
209	 */
210	if ((np->f_refcnt > 1) && (smbfs_smb_reopen_file(share, np, context) == EIO)) {
211        lck_rw_lock_shared(&np->n_name_rwlock);
212		SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
213        lck_rw_unlock_shared(&np->n_name_rwlock);
214
215		np->f_refcnt--;
216		return (0);
217	}
218
219    SMB_LOG_KTRACE(SMB_DBG_SMBFS_CLOSE | DBG_FUNC_START,
220                   openMode, np->f_refcnt, 0, 0, 0);
221
222	if (openMode & FREAD)
223		accessMode |= kAccessRead;
224
225	if (openMode & FWRITE)
226		accessMode |= kAccessWrite;
227
228	/* Check the number of times Open() was called */
229	if (np->f_refcnt == 1) {
230		ubc_msync(vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC | UBC_INVALIDATE);
231		/*
232		 * This is the last Close() we will get, so close sharedForkRef
233		 * and any other forks created by ByteRangeLocks
234		 */
235		if (np->f_fid != 0) {
236			SMBFID oldFID = np->f_fid;
237
238			/* Close the shared file first. Clear out the refs to it
239			 * first so that no one else trys to use it while I'm waiting
240			 * for the close file reply to arrive.  There was a case
241			 * where cluster i/o was firing off after I sent the close
242			 * file req, but had not gotten the close file reply yet
243			 * and tyring to still use the shared file
244			 */
245			np->f_fid = 0;		/* clear the ref num */
246			np->f_accessMode = 0;
247			np->f_rights = 0;
248			np->f_openRWCnt = 0;
249			np->f_openRCnt = 0;
250			np->f_openWCnt = 0;
251			np->f_openTotalWCnt = 0;
252			np->f_needClose = 0;
253			np->f_clusterCloseError = 0;
254			/*
255			 * They didn't unlock the file before closing. A SMB close will remove
256			 * any locks so lets free the memory associated with that lock.
257			 */
258			if (np->f_smbflock) {
259				SMB_FREE(np->f_smbflock, M_LOCKF);
260				np->f_smbflock = NULL;
261			}
262			error = smbfs_smb_close(share, oldFID, context);
263			if (error) {
264				SMBWARNING("close file failed %d on fid %llx\n",
265                           error, oldFID);
266            }
267		 }
268
269		/* Remove forks that were opened due to ByteRangeLocks or DenyModes */
270		lck_mtx_lock(&np->f_openDenyListLock);
271		curr = np->f_openDenyList;
272		while (curr != NULL) {
273			error = smbfs_smb_close(share, curr->fid, context);
274			if (error) {
275				SMBWARNING("close file failed %d on fid %llx\n",
276                           error, curr->fid);
277            }
278			curr = curr->next;
279		}
280		lck_mtx_unlock(&np->f_openDenyListLock);
281		np->f_refcnt = 0;
282		RemoveFileRef (vp, NULL);		/* remove all file refs */
283
284		/*
285		 * We did the last close on the file. This file is
286		 * marked for deletion on close. So lets delete it
287		 * here. If we get an error then try again when the node
288		 * becomes inactive.
289		 */
290        if (np->n_flag & NDELETEONCLOSE) {
291            if (smbfs_smb_delete(share, np, VREG,
292                                 NULL, 0,
293                                 0, context) == 0) {
294                np->n_flag &= ~NDELETEONCLOSE;
295
296                /* Assume the file is now deleted on the server */
297                smb_vhashrem(np);
298
299                lck_rw_lock_shared(&np->n_parent_rwlock);
300                if (np->n_parent != NULL) {
301                    smbfs_attr_touchdir(np->n_parent, (share->ss_fstype == SMB_FS_FAT));
302                    np->n_parent->d_changecnt++;
303
304                    /* Remove any negative cache entries. */
305                    if (np->n_parent->n_flag & NNEGNCENTRIES) {
306                        np->n_parent->n_flag &= ~NNEGNCENTRIES;
307                        cache_purge_negatives(np->n_parent->n_vnode);
308                    }
309                }
310                lck_rw_unlock_shared(&np->n_parent_rwlock);
311            }
312        }
313
314		/*
315		 * It was not cacheable before, but now that all files are closed,
316		 * make it cacheable again (if its a valid cacheable file). If
317		 * we were caching should we remove attributes cache. Realy only
318		 * matters when we turn on cluster io?
319		 */
320		if (vnode_isnocache(vp))
321			vnode_clearnocache(vp);
322
323		/* Did we change the file during the open */
324		if (np->n_flag & NATTRCHANGED)
325			np->attribute_cache_timer = 0;
326
327		lck_mtx_lock(&np->f_openStateLock);
328		if (np->f_openState & kNeedRevoke)
329			error = 0;
330		/*
331		 * Clear all the f_openState flags, we are closed. If we have a pending
332		 * revoke clear that out, the file is closed no need to revoke it now.
333		 */
334		np->f_openState = 0;
335		lck_mtx_unlock(&np->f_openStateLock);
336
337		goto exit;
338	}
339
340	/* More than one open */
341
342	/*
343	 * See if we can match this Close() to a matching file that has byte range
344	 * locks or denyModes.
345	 *
346	 * NOTE: FHASLOCK can be set by open with O_EXCLUSIVE or O_SHARED which
347	 *	 maps to my deny modes or FHASLOCK could also have been set/cleared
348	 *	by calling flock directly.
349	 *
350	 * Cases that work are:
351	 *	1)  Carbon using deny modes and thus FHASLOCK maps to my deny modes.
352	 *	    No flock being used.
353	 *	2)  Cocoa using open with O_EXCLUSIVE or O_SHARED and not calling flock.
354	 *	3)  Cocoa using open, then calling flock and later calling flock
355	 *	    to unlock before close.
356	 *	4)  Cocoa open, then calling flock, but not calling flock to unlock
357	 *	    before close.  I would fall through to the shared fork code correctly.
358	 *
359	 * Cases that may not work are:
360	 *	1)  Carbon using deny modes and then calling flock to unlock, thus
361	 *	    clearing FHASLOCK flag.I would assume it was the shared file.
362	 *	2)  Cocoa open with O_EXCLUSIVE or O_SHARED and then calling flock
363	 *	    to lock and then unlock, then calling close.
364	 *	3)  ???
365	 */
366	if (openMode & FHASLOCK) {
367		uint16_t tempAccessMode = accessMode;
368
369		/* Try with denyWrite, if not found, then try with denyRead/denyWrite */
370		tempAccessMode |= kDenyWrite;
371		error = FindFileRef(vp, p, tempAccessMode, kExactMatch, 0, 0, &fndEntry,
372							&fid);
373		if (error != 0) {
374			tempAccessMode |= kDenyRead;
375			error = FindFileRef(vp, p, tempAccessMode, kExactMatch, 0, 0,
376								&fndEntry, &fid);
377		}
378		if (error == 0)
379			accessMode = tempAccessMode;
380
381        SMB_LOG_KTRACE(SMB_DBG_SMBFS_CLOSE | DBG_FUNC_NONE,
382                       0xabc001, error, 0, 0, 0);
383    } else {
384		/* No deny modes used, so look for any forks opened for byteRangeLocks */
385		error = FindFileRef(vp, p, accessMode, kExactMatch, 0, 0, &fndEntry, &fid);
386        SMB_LOG_KTRACE(SMB_DBG_SMBFS_CLOSE | DBG_FUNC_NONE,
387                       0xabc002, error, 0, 0, 0);
388	}
389
390	/* always decrement the count, dont care if got an error or not */
391    if (np->f_refcnt > 0) {
392        np->f_refcnt--;
393    }
394
395	/*
396	 * We have an Open Deny entry that is being used by more than one open call,
397	 * just decrement it and get out.
398     * This code should be combined with the code right below here.
399	 */
400	if ((error == 0) && fndEntry && (fndEntry->refcnt > 0)) {
401		fndEntry->refcnt--;
402        SMB_LOG_KTRACE(SMB_DBG_SMBFS_CLOSE | DBG_FUNC_NONE,
403                       0xabc003, error, 0, 0, 0);
404		goto exit;
405	}
406
407	/*
408	 * We have an Open Deny entry that is all done. Time to close it.
409     * This code should be combined with the code right above here.
410	 */
411	if ((error == 0) && fndEntry) {
412		error = smbfs_smb_close(share, fndEntry->fid, context);
413		/* We are not going to get another close, so always remove it from the list */
414		RemoveFileRef(vp, fndEntry);
415        SMB_LOG_KTRACE(SMB_DBG_SMBFS_CLOSE | DBG_FUNC_NONE,
416                       0xabc004, error, 0, 0, 0);
417		goto exit;
418	}
419
420	/*
421     * Not an open deny mode open.
422     *
423     * An oddity. If first open was read/write/denyWrite and then a second
424     * open of just read, then the second open will open the shared fork.
425     * Now, get a close on the "read" fork, the np->f_refcnt will be 2, and we
426     * will end up here. The np->f_refcnt will be decremented to 1 so the next
427     * close call will close everything. In the meantime, we end up leaving
428     * the shared fork open with "read" and thus we actually have two forks
429     * open, one for the read/write/denyWrite and the other is the shared fork.
430     * We have has this behavior for a long time and just have not noticed.
431     * Since its an edge case and no one has complained, we can leave it this
432     * way for now.
433     */
434	needOpenFile = 0;
435	openAccessMode = 0;
436	fid = 0;
437	rights = SMB2_READ_CONTROL;
438
439	/*
440	 * Just return 0 for no err, but dont close the file since another
441	 * process is still using it
442	 */
443	error = 0;
444
445	/* Check to downgrade access mode if needed */
446	switch (accessMode) {
447	case (kAccessRead | kAccessWrite):
448		np->f_openRWCnt -= 1;
449		if ((np->f_openRWCnt == 0) && (np->f_openRCnt > 0) && (np->f_openWCnt == 0)) {
450			/* drop from rw to read only */
451			needOpenFile = 1;
452			openAccessMode = kAccessRead;
453			rights |= SMB2_FILE_READ_DATA;
454		}
455		/* Dont ever downgrade to write only since Unix expects read/write */
456		break;
457	case kAccessRead:
458		np->f_openRCnt -= 1;
459		/* Dont ever downgrade to write only since Unix expects read/write */
460		break;
461	case kAccessWrite:
462		np->f_openWCnt -= 1;
463		if ( (np->f_openRCnt > 0) && (np->f_openRWCnt == 0) &&
464			(np->f_openWCnt == 0) ) {
465			/* drop from rw to read only */
466			needOpenFile = 1;
467			openAccessMode = kAccessRead;
468			rights |= SMB2_FILE_READ_DATA;
469		}
470		break;
471	}
472	/* set up for the open fork */
473	if (needOpenFile == 1) {
474        SMB_MALLOC(fap,
475                   struct smbfattr *,
476                   sizeof(struct smbfattr),
477                   M_SMBTEMP,
478                   M_WAITOK | M_ZERO);
479        if (fap == NULL) {
480            SMBERROR("SMB_MALLOC failed\n");
481            error = ENOMEM;
482            goto exit;
483        }
484
485        error = smbfs_smb_open_file(share, np,
486                                    rights, NTCREATEX_SHARE_ACCESS_ALL, &fid,
487                                    NULL, 0, FALSE,
488                                    fap, context);
489        SMB_LOG_KTRACE(SMB_DBG_SMBFS_CLOSE | DBG_FUNC_NONE,
490                       0xabc005, error, 0, 0, 0);
491		if (error == 0) {
492			SMBFID oldFID = np->f_fid;
493
494			/* We are downgrading the open flush it out any data */
495			ubc_msync(vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC | UBC_INVALIDATE);
496			/* Close the shared file first and use this new one now
497			 * Switch the ref before closing the old shared file so the
498			 * old file wont get used while its being closed.
499			 */
500			np->f_fid = fid;	/* reset the ref num */
501			np->f_accessMode = openAccessMode;
502			np->f_rights = rights;
503			error = smbfs_smb_close(share, oldFID, context);
504			if (error) {
505				SMBWARNING("close file failed %d on fid %llx\n", error, oldFID);
506            }
507            SMB_LOG_KTRACE(SMB_DBG_SMBFS_CLOSE | DBG_FUNC_NONE,
508                           0xabc006, error, 0, 0, 0);
509		}
510	}
511
512    SMB_LOG_KTRACE(SMB_DBG_SMBFS_CLOSE | DBG_FUNC_NONE,
513                   0xabc007,
514                   np->f_openRCnt,
515                   np->f_openWCnt,
516                   np->f_openRWCnt,
517                   0);
518
519exit:
520    if ((error == 0) && (openMode & FWRITE) && (np->f_openTotalWCnt > 0)) {
521        np->f_openTotalWCnt--;
522    }
523
524    if (fap != NULL) {
525        SMB_FREE(fap, M_SMBTEMP);
526    }
527
528    SMB_LOG_KTRACE(SMB_DBG_SMBFS_CLOSE | DBG_FUNC_END, error, 0, 0, 0, 0);
529
530	return (error);
531}
532
533/*
534 * smbfs_vnop_close - smbfs vnodeop entry point
535 *	vnode_t a_vp;
536 *	int a_fflags;
537 *	vfs_context_t a_context;
538 */
539static int
540smbfs_vnop_close(struct vnop_close_args *ap)
541{
542	vnode_t vp = ap->a_vp;
543	int error = 0;
544	struct smbnode *np;
545
546    if (smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK) != 0)
547        return (0);
548
549    SMB_LOG_KTRACE(SMB_DBG_CLOSE | DBG_FUNC_START, 0, 0, 0, 0, 0);
550
551	np = VTOSMB(vp);
552	np->n_lastvop = smbfs_vnop_close;
553
554	if (vnode_isdir(vp)) {
555		if (--np->d_refcnt) {
556			error = 0;
557		} else {
558			smbfs_closedirlookup(np, ap->a_context);
559		}
560	} else if ( vnode_isreg(vp) || vnode_islnk(vp) ) {
561		int clusterCloseError = np->f_clusterCloseError;
562		struct smb_share *share;
563
564		/* if its readonly volume, then no sense in trying to write out dirty data */
565		if (!vnode_vfsisrdonly(vp) && smbfsIsCacheable(vp)) {
566			if (np->n_flag & NISMAPPED) {
567				/* More expensive, but handles mmapped files */
568				ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
569			} else {
570				/* Less expensive, but does not handle mmapped files */
571				cluster_push(vp, IO_CLOSE);
572			}
573		}
574		share = smb_get_share_with_reference(VTOSMBFS(vp));
575
576        /* Do any pending set eof or flushes before closing the file */
577        smbfs_smb_fsync(share, np, ap->a_context);
578
579		error = smbfs_close(share, vp, ap->a_fflag, ap->a_context);
580		smb_share_rele(share, ap->a_context);
581		if (!error)
582			error = clusterCloseError;
583	}
584	smbnode_unlock(np);
585
586    SMB_LOG_KTRACE(SMB_DBG_CLOSE | DBG_FUNC_END, 0, 0, 0, 0, 0);
587    return (error);
588}
589
590static void
591smbfs_get_rights_shareMode(int fmode, uint32_t *rights, uint32_t *shareMode, uint16_t *accessMode)
592{
593	/*
594	 * We always ask for READ_CONTROL so we can always get the owner/group
595	 * IDs to satisfy a stat.
596	 */
597	*rights = SMB2_READ_CONTROL;
598	if (fmode & FREAD) {
599		*accessMode |= kAccessRead;
600		*rights |= SMB2_FILE_READ_DATA;
601	}
602	if (fmode & FWRITE) {
603		*accessMode |= kAccessWrite;
604		*rights |= SMB2_FILE_APPEND_DATA | SMB2_FILE_WRITE_DATA;
605	}
606
607	/*
608	 * O_EXLOCK -> denyRead/denyWrite is always cacheable since we have exclusive
609	 *			   access.
610	 * O_SHLOCK -> denyWrite is always cacheable since we are the only one who
611	 *			   can change the file.
612	 * denyNone -> is not cacheable if from Carbon (a FSCTL call from Carbon
613	 *			   will set the vnode to be non cacheable). It is always
614	 *			   cacheable from Unix since that is what home dirs mainly use.
615	 */
616	*shareMode = NTCREATEX_SHARE_ACCESS_ALL;
617	if (fmode & O_SHLOCK) {
618		*accessMode |= kDenyWrite;
619		/* Remove the wr shared access */
620		*shareMode &= ~NTCREATEX_SHARE_ACCESS_WRITE;
621	}
622
623	if (fmode & O_EXLOCK) {
624		*accessMode |= kDenyWrite;
625		*accessMode |= kDenyRead;
626		/* Remove the rdwr shared access */
627		*shareMode &= ~(NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_READ);
628	}
629}
630
631static void
632smbfs_update_RW_cnts(vnode_t vp, uint16_t accessMode)
633{
634	/* count nbr of opens with rw, r, w so can downgrade access in close if needed */
635	struct smbnode *np = VTOSMB(vp);
636
637	switch (accessMode) {
638		case (kAccessWrite | kAccessRead):
639			np->f_openRWCnt += 1;
640			break;
641		case kAccessRead:
642			np->f_openRCnt += 1;
643			break;
644		case kAccessWrite:
645			np->f_openWCnt += 1;
646			break;
647	}
648}
649
650static int
651smbfs_create_open(struct smb_share *share, vnode_t dvp, struct componentname *cnp,
652				  struct vnode_attr *vap,  uint32_t open_disp, int fmode,
653				  SMBFID *fidp, struct smbfattr *fattrp, vnode_t *vpp,
654				  vfs_context_t context)
655{
656	struct smbnode *dnp = VTOSMB(dvp);
657	struct smbmount *smp = VTOSMBFS(dvp);
658	vnode_t vp;
659	const char *name = cnp->cn_nameptr;
660	size_t nmlen = cnp->cn_namelen;
661	int error = 0;
662	uint32_t rights, addedReadRights, saved_rights;
663	uint16_t accessMode = 0;
664	uint16_t savedAccessMode = 0;
665	struct smbnode *np;
666	uint32_t shareMode = 0;
667	char *target = NULL;
668	size_t targetlen = 0;
669    struct smb2_durable_handle dur_handle;
670
671	/*
672	 * We have NO vnode for the target!
673	 * The target may or may not exist on the server.
674	 * The target could be a dir or a file.
675	 *
676	 * If its a dir, then it can not be a creation. Use vnop_mkdir instead.
677	 * It could be an open on a dir which SMB protocol allows.  Make sure
678	 *	to close the dir afterwards.
679	 *
680	 * If its a file, it cant be a symlink, use vnop_link instead.
681	 * It could be a create and open on a file.
682	 * Since a vnode was not found for the file, we know its not already open
683	 *	by this client. This means I know its the FIRST open call.
684	 *
685	 * dnp should be locked when this function is called
686	 */
687
688	*fidp = 0;
689
690	smbfs_get_rights_shareMode(fmode, &rights, &shareMode, &accessMode);
691	savedAccessMode = accessMode;	/* Save the original access requested */
692	/*
693	 * If opening with write only, try opening it with read/write. Unix
694	 * expects read/write access like open/map/close/PageIn. This also helps
695	 * the cluster code since if write only, the reads will fail in the
696	 * cluster code since it trys to page align the requests.
697	 *
698	 * NOTE: Since this call only creates items that are regular files we always
699	 * set the vtype to VREG. The smbfs_smb_ntcreatex only uses that on create.
700	 */
701	addedReadRights = (accessMode == kAccessWrite) ? SMB2_FILE_READ_DATA : 0;
702    saved_rights = rights | addedReadRights;
703
704    error = smbfs_smb_ntcreatex(share, dnp,
705                                rights | addedReadRights, shareMode, VREG,
706                                fidp, name, nmlen,
707                                open_disp, 0, fattrp,
708                                TRUE, NULL, context);
709
710	if (error && addedReadRights) {
711		addedReadRights = 0;
712        saved_rights = rights;
713
714		error = smbfs_smb_ntcreatex(share, dnp,
715                                    rights, shareMode, VREG,
716                                    fidp, name, nmlen,
717                                    open_disp, 0, fattrp,
718                                    TRUE, NULL, context);
719	}
720
721 	if (error) {
722		return error;
723	}
724
725    /* Reparse point need to get the reparse tag */
726	if (fattrp->fa_attr & SMB_EFA_REPARSE_POINT) {
727		error = smbfs_smb_get_reparse_tag(share, *fidp, &fattrp->fa_reparse_tag,
728										  &target, &targetlen, context);
729		if (error) {
730			(void) smbfs_smb_close(share, *fidp, context);
731			return error;
732		}
733	}
734
735	/* Create the vnode using fattr info and return the created vnode */
736	error = smbfs_nget(share, vnode_mount(dvp),
737                       dvp, name, nmlen,
738                       fattrp, &vp,
739                       cnp->cn_flags, SMBFS_NGET_CREATE_VNODE,
740                       context);
741	if (error) {
742        if (target) {
743            SMB_FREE(target, M_TEMP);
744        }
745		(void) smbfs_smb_close(share, *fidp, context);
746		return error;
747	}
748
749	/*
750	 * If they passed in a vnode then we no longer need it, so remove the
751	 * reference. The smbfs_nget always returns us a vnode with a reference. The
752	 * vnode could be the same or a new one.
753	 */
754	if (*vpp) {
755		vnode_put(*vpp);
756	}
757	*vpp = vp;
758	np = VTOSMB(vp);
759
760	/*
761	 * We treat directories, files and symlinks different. Since currently we
762	 * only handle reparse points as dfs triggers or symlinks we can ignore
763	 * treating reparse points special.
764	 */
765	if (vnode_isdir(vp)) {
766		/* We opened a directory, increment its ref count and close it */
767		np->d_refcnt++;
768		(void)smbfs_smb_close(share, *fidp, context);
769	} else if (vnode_islnk(vp)) {
770		/* We opened a symlink, close it */
771		(void)smbfs_smb_close(share, *fidp, context);
772		if (target && targetlen) {
773			smbfs_update_symlink_cache(np, target, targetlen);
774		}
775	} else if (vnode_isreg(vp)) {
776		/* We opened the file so bump ref count */
777		np->f_refcnt++;
778
779		np->f_rights = rights;
780		np->f_accessMode = accessMode;
781		if (addedReadRights) {
782			np->f_rights |= SMB2_FILE_READ_DATA;
783			np->f_accessMode |= kAccessRead;
784		}
785
786		/* if deny modes were used, save the file ref into file list */
787		if ((fmode & O_EXLOCK) || (fmode & O_SHLOCK)) {
788            error = smb2_smb_dur_handle_init(share, np, &dur_handle);
789            if (error == 0) {
790                /*
791                 * %%% TO DO - can we improve the performance of this?
792                 * Want to get a durable handle, but the lease key consists
793                 * of the file ID, so have to wait until the first create
794                 * succeeds which gets us the file ID, then close it and reopen
795                 * it but this time requesting the durable handle.
796                 */
797                (void) smbfs_smb_close(share, *fidp, context);
798
799                error = smbfs_smb_ntcreatex(share, dnp,
800                                            saved_rights, shareMode, VREG,
801                                            fidp, name, nmlen,
802                                            FILE_OPEN, 0, fattrp,
803                                            FALSE, &dur_handle, context);
804            }
805            else {
806                /*
807                 * Durable handles must not be supported by this server, just
808                 * use the earlier open which must have worked.
809                 * Clear the durable handle not supported error
810                 */
811                error = 0;
812            }
813
814            if (error == 0) {
815                /*
816                 * Either durable handles not supported or reopening the file
817                 * with durable handle worked so save file ref
818                 */
819                AddFileRef (vp, vfs_context_proc(context), accessMode, rights,
820                            *fidp, dur_handle, NULL);
821            }
822		}
823        else {
824            np->f_fid = *fidp;
825			smbfs_update_RW_cnts(vp, savedAccessMode);
826			if (accessMode == kAccessWrite) {
827				/* if opened with just write, then turn off cluster code */
828				vnode_setnocache(vp);
829			}
830		}
831	}
832
833	/* If it was allocated then free, since we are done with it now */
834    if (target) {
835        SMB_FREE(target, M_TEMP);
836    }
837
838	if (fattrp->fa_created_disp == FILE_CREATE) {
839		struct timespec ts;
840		/*
841		 * We just created the file, so we have no finder info and the resource fork
842		 * should be empty. So set our cache timers to reflect this information
843		 */
844		nanouptime(&ts);
845		VTOSMB(vp)->finfo_cache_timer = ts.tv_sec;
846		VTOSMB(vp)->rfrk_cache_timer = ts.tv_sec;
847
848		/*
849		 * On create, an initial ACL can be set.
850		 * If unix extensions are supported, then can set mode, owner, group.
851		 */
852		if (vap != NULL) {
853			smbfs_set_create_vap(share, vap, vp, context, TRUE);  /* Set the REAL create attributes NOW */
854		}
855
856		smbfs_attr_touchdir(dnp, (share->ss_fstype == SMB_FS_FAT));
857
858        dnp->d_changecnt++;
859
860		/* Remove any negative cache entries. */
861		if (dnp->n_flag & NNEGNCENTRIES) {
862			dnp->n_flag &= ~NNEGNCENTRIES;
863			cache_purge_negatives(dvp);
864		}
865
866		/* blow away statfs cache */
867		smp->sm_statfstime = 0;
868	}
869	/* smbfs_nget returns a locked node, unlock it */
870	smbnode_unlock(VTOSMB(vp));		/* Release the smbnode lock */
871
872	return (error);
873}
874
875/*
876 * smbfs_open -	The internal open routine, the vnode should be locked
877 *		before this is called.
878 *
879 * The calling routine must hold a reference on the share
880 *
881 */
882int
883smbfs_open(struct smb_share *share, vnode_t vp, int mode,
884		   vfs_context_t context)
885{
886	proc_t p = vfs_context_proc(context);
887	struct smbnode *np = VTOSMB(vp);
888	uint16_t accessMode = 0;
889	uint16_t savedAccessMode = 0;
890	uint32_t rights;
891	uint32_t shareMode;
892    SMBFID fid = 0;
893	int error = 0;
894	int	warning = 0;
895    struct smbfattr *fap = NULL;
896    struct smb2_durable_handle dur_handle, *dptr;
897	int do_create;
898    uint32_t disp;
899    struct fileRefEntry *fndEntry = NULL;
900
901    SMB_LOG_KTRACE(SMB_DBG_SMBFS_OPEN | DBG_FUNC_START, 0, 0, 0, 0, 0);
902
903	/* It was already open so see if the file needs to be reopened */
904	if ((np->f_refcnt) &&
905		((error = smbfs_smb_reopen_file(share, np, context)) != 0)) {
906        lck_rw_lock_shared(&np->n_name_rwlock);
907		SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
908        lck_rw_unlock_shared(&np->n_name_rwlock);
909
910		goto exit;
911	}
912
913    SMB_MALLOC(fap,
914               struct smbfattr *,
915               sizeof(struct smbfattr),
916               M_SMBTEMP,
917               M_WAITOK | M_ZERO);
918    if (fap == NULL) {
919        SMBERROR("SMB_MALLOC failed\n");
920        error = ENOMEM;
921        goto exit;
922    }
923
924	smbfs_get_rights_shareMode(mode, &rights, &shareMode, &accessMode);
925	savedAccessMode = accessMode;	/* Save the original access requested */
926
927	if ((mode & O_EXLOCK) || (mode & O_SHLOCK)) {
928		/*
929		 * if using deny modes and I had to open the file myself, then close
930		 * the file now so it does not interfere with the deny mode open.
931		 * We only do this in read.
932		 */
933		if (np->f_needClose) {
934			np->f_needClose = 0;
935			warning = smbfs_close(share, vp, FREAD, context);
936			if (warning) {
937                lck_rw_lock_shared(&np->n_name_rwlock);
938				SMBWARNING("error %d closing %s\n", warning, np->n_name);
939                lck_rw_unlock_shared(&np->n_name_rwlock);
940           }
941		}
942
943		/* Using deny modes, see if already in file list */
944		error = FindFileRef(vp, p, accessMode, kExactMatch, 0, 0, &fndEntry, &fid);
945		if (error == 0) {
946			/*
947			 * Already in list due to previous open with deny modes. Can't have
948			 * two exclusive or two write/denyWrite. Multiple read/denyWrites are
949			 * allowed.
950			 */
951            if ((accessMode & kDenyWrite) && (accessMode & kAccessWrite)) {
952                error = EBUSY;
953                goto exit;
954            }
955
956			if (mode & O_EXLOCK) {
957                if ((accessMode & kAccessRead) && !(accessMode & kAccessWrite)) {
958                    /*
959                     * Multiple r/dR/dW are allowed, see FindFileRef for
960                     * more details
961                     */
962                }
963                else {
964                    error = EBUSY;
965                    goto exit;
966                }
967            }
968
969            DBG_ASSERT(fndEntry);
970            /*
971             * We are going to reuse this Open Deny entry. Up the counter so
972             * we will know not to free it until the counter goes back to zero.
973             */
974            fndEntry->refcnt++;
975		}
976        else {
977            /*
978             * Check one more time looking for other pids that might already
979             * have the file open for exclusive or shared access that will
980             * cause this open to get denied. This is to reduce the number of
981             * times a handle lease break will occur with SMB 2/3. If we lose
982             * the handle lease, then reopening a durable handle reconnect will
983             * fail.
984             */
985            error = FindFileRef(vp, NULL, accessMode, kPreflightOpen, 0, 0, &fndEntry, &fid);
986            if (error == 0) {
987                /* Some other process has it open already */
988                error = EBUSY;
989                goto exit;
990            }
991
992			/* not in list, so open new file */
993
994            /* Request a durable handle */
995            dptr = NULL;
996            error = smb2_smb_dur_handle_init(share, np, &dur_handle);
997            if (!error) {
998                dptr = &dur_handle;
999            }
1000
1001            if (np->n_flag & N_ISRSRCFRK) {
1002                disp = FILE_OPEN_IF;
1003                do_create = TRUE;
1004            }
1005            else {
1006                disp = FILE_OPEN;
1007                do_create = FALSE;
1008            }
1009
1010            error = smbfs_smb_ntcreatex(share, np,
1011                                        rights, shareMode, VREG,
1012                                        &fid, NULL, 0,
1013                                        disp, FALSE, fap,
1014                                        do_create, dptr, context);
1015			if (error == 0) {
1016				/* if open worked, save the file ref into file list */
1017				AddFileRef (vp, p, accessMode, rights, fid, dur_handle, NULL);
1018			}
1019		}
1020		goto exit;
1021	}
1022
1023	/*
1024	 * If we get here, then deny modes are NOT being used. If the open call is
1025	 * coming in from Carbon, then Carbon will follow immediately with an FSCTL
1026	 * to turn off caching (I am assuming that denyNone means this file will
1027	 * be shared among multiple process and that ByteRangeLocking will be used).
1028	 *
1029	 * no deny modes, so use the shared file reference
1030	 *
1031	 */
1032	/* We have open file descriptor for non deny mode opens */
1033	if (np->f_fid != 0) {
1034        /* Already open check to make sure current access is sufficient */
1035		int needUpgrade = 0;
1036		switch (np->f_accessMode) {
1037		case (kAccessRead | kAccessWrite):
1038			/* Currently RW, can't do any better than that so dont open a new fork */
1039			break;
1040		case kAccessRead:
1041			/* Currently only have Read access, if they want Write too, then open as RW */
1042			if (accessMode & kAccessWrite) {
1043				needUpgrade = 1;
1044				accessMode |= kAccessRead; /* keep orginal mode */
1045				rights |= SMB2_FILE_READ_DATA;
1046			}
1047			break;
1048		case kAccessWrite:
1049			/*  Currently only have Write access, if they want Read too, then open as RW */
1050			if (accessMode & kAccessRead) {
1051				needUpgrade = 1;
1052				accessMode |= kAccessWrite;
1053				rights |= SMB2_FILE_APPEND_DATA | SMB2_FILE_WRITE_DATA;
1054			}
1055			break;
1056		}
1057		if (! needUpgrade)	/*  the existing open is good enough */
1058			goto ShareOpen;
1059	} else if (accessMode == kAccessWrite) {
1060        /*
1061         * If opening with write only, try opening it with read/write. Unix
1062         * expects read/write access like open/map/close/PageIn. This also helps
1063         * the cluster code since if write only, the reads will fail in the
1064         * cluster code since it trys to page align the requests.
1065         */
1066
1067        /*
1068         * Preflight for open deny to preserve handle lease. More details in
1069         * O_EXLOCK/O_SHLOCK code above.
1070         */
1071        error = FindFileRef(vp, NULL, accessMode | kAccessRead, kPreflightOpen,
1072                            0, 0, &fndEntry, &fid);
1073        if (error != 0) {
1074            /* Not already open locally, so try to open it */
1075            error = smbfs_smb_open_file(share, np,
1076                                        rights | SMB2_FILE_READ_DATA, shareMode, &fid,
1077                                        NULL, 0, FALSE,
1078                                        fap, context);
1079            if (error == 0) {
1080                np->f_fid = fid;
1081                np->f_rights = rights | SMB2_FILE_READ_DATA;
1082                np->f_accessMode = accessMode | kAccessRead;
1083                goto ShareOpen;
1084            }
1085        }
1086	}
1087
1088    /*
1089     * Preflight for open deny to preserve handle lease. More details in
1090     * O_EXLOCK/O_SHLOCK code above.
1091     */
1092    error = FindFileRef(vp, NULL, accessMode, kPreflightOpen, 0, 0, &fndEntry,
1093                        &fid);
1094    if (error == 0) {
1095        /* Some other process has it open already */
1096        error = EBUSY;
1097        goto exit;
1098    }
1099
1100    error = smbfs_smb_open_file(share, np,
1101                                rights, shareMode, &fid,
1102                                NULL, 0, FALSE,
1103                                fap, context);
1104	if (error)
1105		goto exit;
1106
1107	/*
1108	 * We already had it open (presumably because it was open with insufficient
1109	 * rights.) So now close the old open, if we already had it open.
1110	 */
1111	if (np->f_refcnt &&
1112        (np->f_fid != 0)) {
1113		warning = smbfs_smb_close(share, np->f_fid, context);
1114		if (warning) {
1115            lck_rw_lock_shared(&np->n_name_rwlock);
1116			SMBWARNING("error %d closing %s\n", warning, np->n_name);
1117            lck_rw_unlock_shared(&np->n_name_rwlock);
1118        }
1119	}
1120	np->f_fid = fid;
1121	np->f_rights = rights;
1122	np->f_accessMode = accessMode;
1123
1124ShareOpen:
1125	smbfs_update_RW_cnts(vp, savedAccessMode);
1126	if (accessMode == kAccessWrite) {
1127		/* if opened with just write, then turn off cluster code */
1128		vnode_setnocache(vp);
1129	}
1130exit:
1131	if (!error) {
1132        /* We opened the file or pretended too; either way bump the count */
1133		np->f_refcnt++;
1134
1135        /* keep track of how many opens for this file had write access */
1136        if (mode & FWRITE) {
1137            np->f_openTotalWCnt++;
1138        }
1139	}
1140
1141    if (fap != NULL) {
1142        SMB_FREE(fap, M_SMBTEMP);
1143    }
1144
1145    SMB_LOG_KTRACE(SMB_DBG_SMBFS_OPEN | DBG_FUNC_END, error, 0, 0, 0, 0);
1146	return (error);
1147}
1148
1149static int
1150smbfs_vnop_open_common(vnode_t vp, int mode, vfs_context_t context, void *n_lastvop)
1151{
1152	struct smbnode *np;
1153	int	error;
1154
1155	/* We only open files and directories and symlinks */
1156	if (!vnode_isreg(vp) && !vnode_isdir(vp) && !vnode_islnk(vp)) {
1157		return (EACCES);
1158    }
1159
1160	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
1161		return (error);
1162
1163	np = VTOSMB(vp);
1164	np->n_lastvop = n_lastvop;
1165
1166	/* Just mark that the directory was opened */
1167	if (vnode_isdir(vp)) {
1168		np->d_refcnt++;
1169		error = 0;
1170	} else {
1171		struct smb_share * share;
1172
1173		share = smb_get_share_with_reference(VTOSMBFS(vp));
1174
1175        if (mode & O_TRUNC) {
1176            /* If truncating the file on open, do any pending set eofs */
1177            smbfs_smb_fsync(share, np, context);
1178        }
1179
1180		error = smbfs_open(share, vp, mode, context);
1181		/*
1182		 * We created the file with different posix modes than request in
1183		 * smbfs_vnop_create. We need to correct that here, so set the posix
1184		 * modes to those request on create. See smbfs_set_create_vap for more
1185		 * details on this issue.
1186		 */
1187		if ((error == 0) && (np->set_create_va_mode) && (mode & O_CREAT)) {
1188			struct vnode_attr vap;
1189
1190			np->set_create_va_mode = FALSE;	/* Only try once */
1191			VATTR_INIT(&vap);
1192			VATTR_SET_ACTIVE(&vap, va_mode);
1193			vap.va_mode = np->create_va_mode;
1194			error = smbfs_setattr(share, vp, &vap, context);
1195			if (error)	/* Got an error close the file and return the error */
1196				(void)smbfs_close(share, vp, mode, context);
1197		}
1198		smb_share_rele(share, context);
1199	}
1200	if (error == EBUSY)
1201		error = EAGAIN;
1202
1203	smbnode_unlock(np);
1204	return(error);
1205}
1206
1207/*
1208 * smbfs_vnop_compound_open - smbfs vnodeop entry point
1209 *	vnode_t a_dvp;
1210 *	vnode_t *a_vpp;
1211 *	int a_fmode;
1212 *	struct componentname *a_cnp;
1213 *	vnode_attr *a_vap;
1214 *	uint32_t a_flags;
1215 *	uint32_t *a_status;
1216 *	vfs_context_t context;
1217 *	int (*a_open_create_authorizer);
1218 *	int (*a_open_existing_authorizer);
1219 *	void *a_reserved;
1220 *
1221 * In broad strokes, our compound Open VNOP will be able to act as a
1222 * VNOP_LOOKUP(), a VNOP_OPEN(), and possibly a VNOP_CREATE(), all in one trip
1223 * to the filesystem.  Depending on flags, it may execute an operation similar
1224 * to an open(2) with O_CREAT: lookup, create if not present, and open.  It may
1225 * also act as a simple open(2) without O_CREAT: lookup and open if present.
1226 * When it returns successfully, the file it has found or created will be "open"
1227 * and ready to be hooked into a file descriptor.  As we will discuss later, this
1228 * call may under some circumstances return to VFS with its operation unfinished,
1229 * to request help from VFS, or fail but nonetheless return a vnode.  Filesystems
1230 * will be responsible for calling the passed-in authorizer routines to make sure
1231 * that the caller can legitimately perform the requested action.
1232 *
1233 * Arguments in Detail
1234 *
1235 *		1.  a_dvp - The directory in which to open/create. The directory vnode is
1236 *			equivalent to what would be passed to VNOP_LOOKUP() or VNOP_CREATE():
1237 *			it is the directory in which we wish to open a file, possibly doing
1238 *			a create if the file is not already present.
1239 *		2.  a_vpp - Resulting vnode. This argument is a pointer to a "vnode_t"
1240 *			in which the filesystem can place a pointer to the vnode for a file
1241 *			it either looks up or creates. In the event of a hit in the name
1242 *			cache, VFS will pass a file to the filesystem in *a_vpp. In that
1243 *			case, the filesystem will be free to call vnode_put() on that vnode
1244 *			and replace it with another of its choosing.  In the event of a cache
1245 *			miss, *a_vpp will store NULLVP. On success, the pointer installed at
1246 *			this address shall point to an "opened" vnode. On failure, it may
1247 *			point to a vnode which is not open.  Because several facilities in
1248 *			the kernel--notably auditing and kdebug support for fs_usage--rely
1249 *			on examining vnodes between lookup and a subsequent VNOP, filesystems
1250 *			should make every effort to return a vnode with an iocount if a lookup
1251 *			would have succeeded for that file, regardless of whether the main
1252 *			operation has failed.  This subtlety will apply to all other compound
1253 *			VNOPs as well, including those which might fail with EEXIST (e.g. mkdir).
1254 *			An unopened vnode may also be returned because more help is required
1255 *			from VFS (EKEEPLOOKING).
1256 *		3.  a_fmode - Open mode. This field will contain open flags as normally
1257 *			passed to VNOP_OPEN(), e.g. O_TRUNC.  For filesystems implementing
1258 *			compound open, O_TRUNC must be handled as part of the compound open
1259 *			call--a subsequent VNOP_SETATTR() call will not be sent to set the size.
1260 *		4.  a_cnp - Path to look up. This field will contain a componentname, as
1261 *			passed to VNOP_LOOKUP() or VNOP_CREATE(), specifying the name of the
1262 *			file to look up and possibly create.
1263 *		5.  a_vap - Attributes with which to create, if appropriate. This field
1264 *			will contain a pointer to vnode attributes to be used in creating a
1265 *			file.  In the event of an open without O_CREAT, this field will be NULL.
1266 *			In the event of a cache hit, it will also be NULL, as we wish to take
1267 *			a fast path in this case which does not involve the heavyweight operation
1268 *			of initializing creation attributes.  This field can be ignored in
1269 *			the event that an existing file is detected.
1270 *		6.  a_flags - VNOP-control flags. This field will contain control flags
1271 *			specific to the compound open VNOP.  For now, there will be only one
1272 *			flag: VNOP_COMPOUND_OPEN_DO_CREATE  will indicate that if no existing
1273 *			file is found, a new one is to be created (authorization, etc. permitting).
1274 *		7.  a_status - Information about results. The filesystem will use this
1275 *			field to return information about the result of the VNOP.  At the moment,
1276 *			there will be only one flag: COMPOUND_OPEN_STATUS_DID_CREATE  will
1277 *			indicate that a file was created by this call.  The field will be set
1278 *			to zero before a pointer is passed to the filesystem, so the FS will
1279 *			be free (for now) to only touch it in the event of having done a
1280 *			create.  COMPOUND_OPEN_STATUS_DID_CREATE should never be set if
1281 *			VNOP_COMPOUND_OPEN_DO_CREATE was not set in a_flags.
1282 *		8.  a_context - Authorization context. This field is a vfs_context_t,
1283 *			just as is passed to most VNOPs.
1284 *		9.  a_open_create_authorizer - Authorizer for create case. This field
1285 *			will contain a pointer to a function to be called to authorize creating
1286 *			a file.  It need only be called if a file is to be created; for an
1287 *			existing file, a_open_existing_authorizer should be used.  The
1288 *			componentname and vnode_attr passed to this function should be exactly
1289 *			those which were passed to the VNOP, because opaque data in these
1290 *			structures, installed by VFS, will be interpreted in authorization
1291 *			(the same will apply to all other authorizer callbacks).  Some additional
1292 *			validation which is not authorization per se, but which is currently
1293 *			performed in VFS on behalf of the filesystem, will also be executed
1294 *			here.  As a result of that validation, a variety of errors may be
1295 *			returned; these should generally be passed back to VFS.  Filesystems
1296 *			which will attempt a compound RPC that may result in a file's being
1297 *			created should always call this function beforehand.  In that case,
1298 *			if authorization is denied, the filesystem should attempt an "open
1299 *			without O_CREAT," because an open of an existing file may succeed
1300 *			despite a denial of permission to create.  The reserved argument should
1301 *			currently always be NULL.
1302 *			NOTE:  The locking constraints with respect to this call, and all
1303 *			authorizer callbacks in this document must unfortunately be left
1304 *			somewhat ambiguous due to the unrestricted behavior of Kauth and
1305 *			MACF plugins.  However, I believe that it should be safe to call out
1306 *			with resources (iocounts, memory, references) held, and even with some
1307 *			kinds of locks (a lock preventing only remove of a file, for instance).
1308 *			The chief thing to avoid is holding big locks (directory lock, file lock)
1309 *			which would prevent stat(2) and similar operations which authorizers
1310 *			are likely to try to use.
1311 *		10. a_open_existing_authorizer - Authorizer for preexisting case. This
1312 *			field will contain a pointer to a function to be called to authorize
1313 *			opening an existing file.  It need only be called if a file has not
1314 *			been created.  The componentname passed to this function should be
1315 *			exactly that which was passed to the VNOP, because opaque data in
1316 *			this structure, installed by VFS, will be interpreted in authorization.
1317 *			Some additional validation which is not authorization per se, but which
1318 *			is currently performed in VFS on behalf of the filesystem, will also
1319 *			be executed here.  As a result of that validation, a variety of errors
1320 *			may be returned; these should generally be passed back to VFS.
1321 *			The reserved argument should currently always be NULL.  For networked
1322 *			filesystems, this routine can be used after going over the wire with a
1323 *			compound lookup+open RPC; if access is denied, the filesystem should
1324 *			clean up (e.g. issue a close over the wire) and return to VFS.
1325 *		11. a_reserved - This field is currently unused and should not be interpreted.
1326 *
1327 * Symlinks, Mountpoints, Trigger Points:
1328 *
1329 * int vnode_lookup_continue_needed(vnode_t vp, struct componentname *cnp);
1330 *
1331 * #define EKEEPLOOKING    (-7)
1332 *
1333 * As part of a compound operation, a file may be detected which the filesystem
1334 * is not equipped to handle--for instance, a mountpoint, a symlink if O_NOFOLLOW
1335 * is set (which may point to another volume), or a trigger point. VFS will
1336 * provide the above routine to determine if a given vnode is one which requires
1337 * additional VFS processing.  It will take a vnode (the preexisting file
1338 * discovered by a compound VNOP) and a componentname; the latter should be the
1339 * exact pointer which was passed to the filesystem by VFS, because opaque data
1340 * will be interpreted to make the decision.  If this routine returns a nonzero
1341 * value, the filesystem should return EKEEPLOOKING to VFS.
1342 * vnode_lookup_continue_needed() will also update an opaque field on the
1343 * componentname for interpretation by VFS--while unnecessary for VNOP_COMPOUND_OPEN(),
1344 * for a rename (where two lookups take place) that update will let VFS determine
1345 * which lookup needs to be continued.  This helper will be used in numerous
1346 * compound VNOPs.
1347 *
1348 * "Traditional"VNOPs, Dark Corners of the Kernel, and the Root of a Filesystem
1349 *
1350 * VNOP_LOOKUP() will still need to be supported to allow us to reach intermediate
1351 * components of a path.  Currently, we plan to require that filesystems continue
1352 * to support the "traditional" VNOP_CREATE() and VNOP_OPEN() (and correspondingly,
1353 * the traditional version of other namespace-changing operations).  The chief
1354 * reason for this is that there are numerous areas in the kernel that use these
1355 * old-style operations directly.  After some discussion with various filesystem
1356 * owners, I think that it is best that we gradually adjust those areas to be
1357 * able to use compound VNOPs, thereby limiting the instability from moving them
1358 * all at once.  When all internal code has been prepared to use a given compound
1359 * VNOP, filesystems will be able to remove their "traditional" implementation.
1360 * VNOP_OPEN() deserves a bit of special discussion.  There are some places in
1361 * the kernel where we "open" a vnode without doing a true lookup; the best example
1362 * is the root of a filesystem, which is never "looked up" the way other entries
1363 * in a volume are, but there are other places where we have in hand that a vnode
1364 * that was obtained at some point in the past.  I therefore think that we will
1365 * probably keep VNOP_OPEN() around for the long term, rather than increasing the
1366 * complexity of the spreadsheet of "which arguments can be NULL, and when" for
1367 * VNOP_COMPOUND_OPEN().
1368*/
1369static int
1370smbfs_vnop_compound_open(struct vnop_compound_open_args *ap)
1371{
1372	vnode_t dvp = ap->a_dvp;
1373	vnode_t *vpp = ap->a_vpp;
1374	vnode_t vp = (ap->a_vpp) ? *ap->a_vpp : NULL;
1375	vfs_context_t context = ap->a_context;
1376	struct componentname *cnp = ap->a_cnp;
1377	struct vnode_attr *vap = ap->a_vap;
1378	int fmode = ap->a_fmode;
1379	int error;
1380	int create_authorizer_error = 0;
1381	uint32_t open_disp = 0;
1382	struct smb_share *share = NULL;
1383	struct smbnode *dnp;
1384    SMBFID fid = 0;
1385	uint32_t vid;
1386    struct smbfattr *fap = NULL;
1387    const char *namep = cnp->cn_nameptr;
1388    size_t name_len = cnp->cn_namelen;
1389
1390
1391	if (vpp == NULL) {
1392		SMBWARNING("Calling us without a vpp\n");
1393		return ENOTSUP;
1394	}
1395
1396	/*
1397	 * Case 1:
1398	 *	They passed in a vnode they found in the name cache or we found
1399	 *	one in our hash table and its a symlink or reprase point. Not sure what
1400	 *	to do with reprase points yet. Symlinks are easy call vnode_lookup_continue_needed
1401	 * and let it tell us what to do.
1402	 *
1403	 * Case 2:
1404	 *	They passed in a vnode they found in the name cache or we found in our
1405	 *	hash table. If they don't have O_CREAT set or its already open then we
1406	 *	can just do a normaly open. We need to call a_open_existing_authorizer
1407	 *	before calling smbfs_vnop_open_common. If O_TRUNC is set then we need to
1408	 *	set the file size to zero. Even on error we need to return the vnode
1409	 *	with a reference.
1410	 *
1411	 * Case 3:
1412	 *	We have no vnode or they have O_CREAT set and we don't have it already
1413	 *	open. Set the correct open dispostion depending on the modes passed in
1414	 *	and what a_open_create_authorizer returns. We only call a_open_create_authorizer
1415	 *	if O_CREAT is set. Now we let smbfs_create_open handle all other cases.
1416	 *	Will use <rdar://problem/8574808> to update this comment and to make
1417	 *	reprase points and symlinks work correctly.
1418	 *
1419	 *
1420	 * Notes:
1421	 * 1) vap may be null, if null on create then thats not supported
1422	 * 2) if a_vpp is null and we return a vnode, dont do a vnode_put on it as the
1423	 *	vfs open code will call vnode_put on it for us.
1424	 */
1425
1426	/*
1427	 * We may have to create the item make sure it has a vap and they
1428	 * are creating a file. We only support create on files.
1429	 */
1430	if ((fmode & O_CREAT) && ((vap == NULL) || (vap->va_type != VREG))) {
1431		return (ENOTSUP);
1432	}
1433
1434    SMB_LOG_KTRACE(SMB_DBG_CMPD_OPEN | DBG_FUNC_START, fmode, 0, 0, 0, 0);
1435
1436    SMB_MALLOC(fap,
1437               struct smbfattr *,
1438               sizeof(struct smbfattr),
1439               M_SMBTEMP,
1440               M_WAITOK | M_ZERO);
1441    if (fap == NULL) {
1442        SMBERROR("SMB_MALLOC failed\n");
1443        error = ENOMEM;
1444        goto done;
1445    }
1446
1447	share = smb_get_share_with_reference(VTOSMBFS(dvp));
1448
1449	/* They didn't pass us a vnode, see if we have one in our hash */
1450	if (vp == NULLVP) {
1451        SMB_LOG_KTRACE(SMB_DBG_CMPD_OPEN | DBG_FUNC_NONE, 0xabc001, 0, 0, 0, 0);
1452
1453		if ((cnp->cn_nameptr[0] == '.') && (cnp->cn_namelen == 1)) {
1454			/*
1455			 * They didn't give us a vnode, but they want dot open, so
1456			 * get a reference on the parent node.
1457			 */
1458			vid = vnode_vid(dvp);
1459			error = vnode_getwithvid(dvp, vid);
1460			if (error) {
1461				goto done;
1462			}
1463			vp = dvp;
1464		}
1465        else {
1466            if (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS) {
1467                /*
1468                 * Server supports File IDs.
1469                 */
1470                if (fmode & O_CREAT) {
1471                   /*
1472                    * In this case a lookup was done earlier and we know the
1473                    * item does not exist so trying to get its File ID is
1474                    * useless. Just skip straight to not found */
1475                    goto not_found;
1476                }
1477
1478                /*
1479                 * Before we can see if vnode already exists in our hash,
1480                 * need to get the inode number first. Might as well get all
1481                 * the meta data too so we can update the vnode if its found
1482                 */
1483                if (SSTOVC(share)->vc_misc_flags & SMBV_NO_QUERYINFO) {
1484                    /*
1485                     * Server does not like Query Info on files, so use Query
1486                     * Dir instead.
1487                     *
1488                     * Should never be a named stream vnode
1489                     */
1490                    if ((VTOSMB(dvp)->n_vnode) && vnode_isnamedstream(VTOSMB(dvp)->n_vnode)) {
1491                        DBG_ASSERT(0);
1492                    }
1493
1494                    error = smb2fs_smb_cmpd_query_dir_one(share, VTOSMB(dvp),
1495                                                          namep, name_len,
1496                                                          fap, (char **) &namep, &name_len,
1497                                                          context);
1498                }
1499                else {
1500                    error = smbfs_smb_qpathinfo(share, VTOSMB(dvp), VREG,
1501                                                fap, SMB_QFILEINFO_ALL_INFO,
1502                                                &namep, &name_len,
1503                                                context);
1504                }
1505                SMB_LOG_KTRACE(SMB_DBG_CMPD_OPEN | DBG_FUNC_NONE,
1506                               0xabc002, error, 0, 0, 0);
1507
1508                if (error == 0) {
1509                    /* Lock the parent */
1510                    dnp = VTOSMB(dvp);
1511                    if (smbnode_lock(dnp, SMBFS_EXCLUSIVE_LOCK) != 0) {
1512                        error = ENOENT;
1513                        goto done;
1514                    }
1515
1516                    /*
1517                     * Found item on server, see if its in the hash.
1518                     * If it is in hash, then update its meta data and return vp
1519                     * If its not in hash, smbfs_nget will create it for us and
1520                     * return it in vp. Either way, we get back a vp.
1521                     */
1522                    if (smbfs_nget(share, vnode_mount(dvp),
1523                                   dvp, cnp->cn_nameptr, cnp->cn_namelen,
1524                                   fap, &vp,
1525                                   cnp->cn_flags, SMBFS_NGET_CREATE_VNODE,
1526                                   ap->a_context) == 0) {
1527                        /*
1528                         * Found one in our hash table unlock it, we just need
1529                         * the vnode reference at this point
1530                         */
1531                        smbnode_unlock(VTOSMB(vp));
1532                    }
1533
1534                    /* Unlock the parent */
1535                    dnp->n_lastvop = smbfs_vnop_compound_open;
1536                    smbnode_unlock(dnp);
1537
1538                    /*  If smbfs_smb_qpathinfo returned a new name, free it */
1539                    if (namep != cnp->cn_nameptr) {
1540                        SMB_FREE(namep, M_SMBNODENAME);
1541                    }
1542                }
1543                else {
1544                    /* Probably not found, either way vp is left at NULL */
1545                    goto not_found;
1546                }
1547            }
1548            else {
1549                /* Lock the parent */
1550                dnp = VTOSMB(dvp);
1551                if (smbnode_lock(dnp, SMBFS_EXCLUSIVE_LOCK) != 0) {
1552                    error = ENOENT;
1553                    goto done;
1554                }
1555
1556                /*
1557                 * Server does not support File IDs.
1558                 * Use the name for the hash value and try to find the vnode
1559                 * in the hash table with just the parent vnode and name. If its
1560                 * does not already exist in the hash,then smbfs_nget will
1561                 * return ENOENT (since fap == NULL) and vp will be left as NULL
1562                 *
1563                 * If server does support File IDs, we dont have the inode number
1564                 * at this time, so can not check the hash table at this time.
1565                 */
1566                if (smbfs_nget(share, vnode_mount(dvp),
1567                               dvp, cnp->cn_nameptr, cnp->cn_namelen,
1568                               NULL, &vp,
1569                               cnp->cn_flags, SMBFS_NGET_LOOKUP_ONLY,
1570                               ap->a_context) == 0) {
1571                    /*
1572                     * Found one in our hash table unlock it, we just need
1573                     * the vnode reference at this point
1574                     */
1575                    smbnode_unlock(VTOSMB(vp));
1576                }
1577
1578                /* Unlock the parent */
1579                dnp->n_lastvop = smbfs_vnop_compound_open;
1580                smbnode_unlock(dnp);
1581            }
1582        }
1583    }
1584
1585	/*
1586	 * Symlink or reparse point. Call vnode_lookup_continue_needed before
1587	 * proceeding.
1588	 */
1589	if (vp && (vnode_islnk(vp) || (VTOSMB(vp)->n_dosattr & SMB_EFA_REPARSE_POINT))) {
1590        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
1591		SMBDEBUG("symlink %s\n", VTOSMB(vp)->n_name);
1592        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
1593
1594		error = vnode_lookup_continue_needed(vp, cnp);
1595		if (error) {
1596			*vpp = vp;
1597			vp = NULL;
1598			goto done;
1599		}
1600		/* Let smbfs_vnop_open_common handle any open errors */
1601		fmode &= ~(O_CREAT | O_TRUNC); /* Can't create or truncate a symlink */
1602	}
1603
1604	/*
1605	 * Do a normal open:
1606	 * 1. We have a vnode and they just want to open the file or directory. The
1607	 *    O_CREAT/O_TRUNC is not set. NOTE they can't have O_CREAT set on a directory.
1608	 * 2. We have a vnode to a file and its already opened.
1609	 *
1610	 * NOTE: They could be opening a file with O_CREAT, we found a directory in
1611	 * our hash, yet it doesn't exist on the server. So we should create the file
1612	 * and remove the directory node from our hash table. In this case we should
1613	 * falldown to the create open code.
1614	 */
1615	if (vp && (!(fmode & (O_CREAT | O_TRUNC)) || (vnode_isreg(vp) && VTOSMB(vp)->f_refcnt))) {
1616
1617        if ((fmode & O_EXCL) && vnode_isreg(vp) && VTOSMB(vp)->f_refcnt) {
1618            /*
1619             * O_EXCL is set and we *know* the file exists (we have
1620             * a vp and it's opened). No need to go to the server,
1621             * since we know the result.
1622             */
1623            if (fmode & O_CREAT) {
1624                /* If O_CREAT and O_EXCL and file exists then EEXISTS */
1625                error = EEXIST;
1626            }
1627            else {
1628                error = EAGAIN;
1629            }
1630            *vpp = vp;
1631            vp = NULL;
1632            goto done;
1633        }
1634
1635		/* Call back and see if it is ok to be opened */
1636		error = ap->a_open_existing_authorizer(vp, cnp, fmode, context, NULL);
1637		if (!error) {
1638			error = smbfs_vnop_open_common(vp, fmode, context, smbfs_vnop_compound_open);
1639            SMB_LOG_KTRACE(SMB_DBG_CMPD_OPEN | DBG_FUNC_NONE,
1640                           0xabc003, error, 0, 0, 0);
1641		}
1642
1643		/* The file was already open, but they wanted us to truncate it. */
1644		if (!error && (fmode & O_TRUNC)){
1645			struct vnode_attr va;
1646
1647			memset(&va, 0, sizeof(va));
1648			VATTR_INIT(&va);
1649			VATTR_SET_ACTIVE(&va, va_data_size);
1650			error = smbfs_setattr(share, vp, &va, context);
1651			if (error)	{
1652				/* Got an error close the file and return the error */
1653				(void)smbfs_close(share, vp, fmode, context);
1654			}
1655		}
1656		/* Even if the truncate fails we need to return the vnode */
1657		*vpp = vp;
1658		vp = NULL;
1659		goto done;
1660	}
1661
1662not_found:
1663	/* Set the default create dispostion value */
1664	create_authorizer_error = 0;
1665
1666	if (fmode & O_TRUNC) {
1667		open_disp = FILE_OVERWRITE;
1668        if (vp) {
1669            /* If truncating the file on open, do any pending set eofs */
1670            smbfs_smb_fsync(share, VTOSMB(vp), context);
1671        }
1672	}
1673    else {
1674		open_disp = FILE_OPEN;
1675	}
1676
1677	if (fmode & O_CREAT) {
1678		/* Call back and see if it is ok to be created */
1679		create_authorizer_error = ap->a_open_create_authorizer(dvp, cnp, vap, context, NULL);
1680		if (!create_authorizer_error) {
1681			/* We can create so set the correct create dispostion value */
1682			if (fmode & O_EXCL) {
1683				open_disp = FILE_CREATE;
1684			} else if (fmode & O_TRUNC) {
1685				open_disp = FILE_OVERWRITE_IF;
1686			} else {
1687				open_disp = FILE_OPEN_IF;
1688			}
1689		}
1690	}
1691
1692	/* Lock the parent */
1693	if ((error = smbnode_lock(VTOSMB(dvp), SMBFS_EXCLUSIVE_LOCK))) {
1694		goto done;
1695	}
1696
1697	dnp = VTOSMB(dvp);
1698	dnp->n_lastvop = smbfs_vnop_compound_open;
1699
1700	/* Try to create/open the file */
1701	error = smbfs_create_open(share, dvp, cnp, vap, open_disp, fmode, &fid, fap, &vp, context);
1702	smbnode_unlock(dnp);
1703
1704    SMB_LOG_KTRACE(SMB_DBG_CMPD_OPEN | DBG_FUNC_NONE, 0xabc004, error, 0, 0, 0);
1705	if (error) {
1706		if (create_authorizer_error) {
1707			error = create_authorizer_error;
1708		}
1709	}
1710    else {
1711		if ((fap->fa_created_disp == FILE_CREATE) && (!(fmode & O_CREAT))) {
1712			/*
1713			 * The server says it was created, but we didn't request it to be
1714			 * created. The VFS layer can't handle this so just replace the
1715			 * FILE_CREATE with FILE_OPEN and log what happen. This should never
1716			 * happen, but it is better than the VFS panicing.
1717			 */
1718			fap->fa_created_disp = FILE_OPEN;
1719			SMBERROR("Server created %s when we only wanted it open, server error\n",
1720					 cnp->cn_nameptr);
1721		}
1722		if (fap->fa_created_disp == FILE_CREATE) {
1723			*ap->a_status = COMPOUND_OPEN_STATUS_DID_CREATE;
1724		} else {
1725			error = ap->a_open_existing_authorizer(vp, cnp, fmode, context, NULL);
1726			/* Error so close it */
1727			if (error) {
1728				(void)smbfs_smb_close(share, fid, context);
1729			}
1730			/* Not sure how to handle reparse yet, deal with that in <rdar://problem/8574808> */
1731			if (vnode_islnk(vp) || (VTOSMB(vp)->n_dosattr &  SMB_EFA_REPARSE_POINT)) {
1732				error = vnode_lookup_continue_needed(vp, cnp);
1733				if (!error && (vnode_islnk(vp))) {
1734					/* We never let them open a symlink */
1735					error = EACCES;
1736				}
1737			}
1738		}
1739		/* Note: Even on error, return the vnode */
1740		*vpp = vp;
1741		vp = NULL; /* Don't release the reference */
1742	}
1743
1744done:
1745    if (error) {
1746        if ((fmode & O_CREAT) && (error == ENOENT)) {
1747            SMBDEBUG("Creating %s returned ENOENT, resetting to EACCES\n", cnp->cn_nameptr);
1748            /*
1749             * Some servers (Samba) support an option called veto. This prevents
1750             * clients from creating or access these files. The server returns
1751             * an ENOENT error in these cases. The VFS layer will loop forever
1752             * if a ENOENT error is returned on create, so we convert this error
1753             * to EACCES.
1754             */
1755            error = EACCES;
1756        } else if ((fmode & O_EXCL) && (error != EEXIST)) {
1757            /*
1758             * Since O_EXCL is set, we really need to return EEXIST
1759             * if the file exists.
1760             * See <rdar://problem/10074916>
1761             */
1762            if ( (smbfs_smb_query_info(share, VTOSMB(dvp), VREG,
1763                                       cnp->cn_nameptr, cnp->cn_namelen,
1764                                       NULL, context) == 0)) {
1765                SMBDEBUG("%s: O_EXCL but error = %d, resetting to EEXIST.\n", __FUNCTION__, error);
1766                if (fmode & O_CREAT) {
1767                    /* If O_CREAT and O_EXCL and file exists then EEXISTS */
1768                    error = EEXIST;
1769                }
1770                else {
1771                    error = EAGAIN;
1772                }
1773            }
1774        }
1775    }
1776
1777    if (share) {
1778		smb_share_rele(share, context);
1779	}
1780
1781	/*
1782	 * We have an error and they didn't pass us in a vnode, then we found the
1783	 * vnode in our hash table. We need to remove our reference.
1784	 */
1785	if (error && (*vpp == NULLVP) && vp) {
1786		vnode_put(vp);
1787	}
1788
1789    if (fap) {
1790        SMB_FREE(fap, M_SMBTEMP);
1791    }
1792
1793    SMB_LOG_KTRACE(SMB_DBG_CMPD_OPEN | DBG_FUNC_END, error, 0, 0, 0, 0);
1794    return (error);
1795}
1796
1797/*
1798 * smbfs_vnop_open - smbfs vnodeop entry point
1799 *	vnode_t a_vp;
1800 *	int  a_mode;
1801 *	vfs_context_t a_context;
1802 */
1803static int
1804smbfs_vnop_open(struct vnop_open_args *ap)
1805{
1806    int error;
1807
1808    SMB_LOG_KTRACE(SMB_DBG_OPEN | DBG_FUNC_START, 0, 0, 0, 0, 0);
1809
1810	error = smbfs_vnop_open_common(ap->a_vp, ap->a_mode, ap->a_context, smbfs_vnop_open);
1811
1812    SMB_LOG_KTRACE(SMB_DBG_OPEN | DBG_FUNC_END, error, 0, 0, 0, 0);
1813	return (error);
1814}
1815
1816/*
1817 * smbfs_vnop_mmap - smbfs vnodeop entry point
1818 *	vnode_t a_vp;
1819 *	int a_fflags;
1820 *	vfs_context_t a_context;
1821 *
1822 * The mmap routine is a hint that we need to keep the file open. We can get
1823 * mutilple mmap before we get a mnomap. We only care about the first one. We
1824 * need to take a reference count on the open file and hold it open until we get
1825 * a mnomap call. The file should already be open when we get the mmap call and
1826 * with the correct open mode access.  So we shouldn't have to worry about
1827 * upgrading because the open should have  handled that for us. If the open was
1828 * done using an Open Deny mode then we need to mark the open deny entry as being
1829 * mmaped so the pagein, pageout, and mnomap routines can find.
1830 *
1831 * NOTE: On return all errors are ignored except EPERM.
1832 */
1833static int
1834smbfs_vnop_mmap(struct vnop_mmap_args *ap)
1835{
1836	vnode_t			vp = ap->a_vp;
1837	struct smbnode *np = NULL;
1838	int				error = 0;
1839	uint32_t		mode = (ap->a_fflags & PROT_WRITE) ? (FWRITE | FREAD) : FREAD;
1840	int				accessMode = (ap->a_fflags & PROT_WRITE) ? kAccessWrite : kAccessRead;
1841    SMBFID fid = 0;
1842	struct fileRefEntry *entry = NULL;
1843
1844	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
1845		return (EPERM);
1846
1847    SMB_LOG_KTRACE(SMB_DBG_MMAP | DBG_FUNC_START, 0, 0, 0, 0, 0);
1848
1849	np = VTOSMB(vp);
1850	np->n_lastvop = smbfs_vnop_mmap;
1851
1852	/* We already have it mapped, just ignore this one */
1853	if (np->n_flag & NISMAPPED)
1854	    goto out;
1855	/*
1856	 * Since we should already be open with the correct modes then we should never
1857	 * need to really open the file. For now we try these three cases.
1858	 *
1859	 * First try the simple case, we have a posix open with the correct access.
1860	 *
1861	 * Second see if we have a match in the open deny mode list. Still not 100% sure this
1862	 * will work ever time because they are passing the current context, which may not match
1863	 * the one passed to open. From taking to Joe he believe we will always be in the open
1864	 * context when call. From my testing this seems to be true.
1865	 *
1866	 * Third just return EPERM.
1867	 */
1868	if ((np->f_fid != 0) &&
1869        (np->f_accessMode & accessMode)) {
1870		np->f_refcnt++;
1871	} else if (FindFileRef(vp, vfs_context_proc(ap->a_context), accessMode,
1872							   kAnyMatch, 0, 0, &entry, &fid) == 0) {
1873		entry->refcnt++;
1874		entry->mmapped = TRUE;
1875		np->f_refcnt++;
1876	} else {
1877        lck_rw_lock_shared(&np->n_name_rwlock);
1878		SMBERROR("%s We could not find an open file with mode = 0x%x? \n", np->n_name, mode);
1879        lck_rw_unlock_shared(&np->n_name_rwlock);
1880
1881		error = EPERM;
1882		goto out;
1883	}
1884	np->n_flag |= NISMAPPED;
1885	np->f_mmapMode = mode;
1886out:
1887	smbnode_unlock(np);
1888
1889    SMB_LOG_KTRACE(SMB_DBG_MMAP | DBG_FUNC_END, error, 0, 0, 0, 0);
1890	return (error);
1891}
1892
1893/*
1894 * smbfs_vnop_mnomap - smbfs vnodeop entry point
1895 *	vnode_t a_vp;
1896 *	vfs_context_t a_context;
1897 *
1898 * When called this is a hint that we can now close the file. We will not get any
1899 * more pagein or pageout calls without another mmap call.  If our reference count
1900 * is down to one then all we have to do is call close and it will clean everything
1901 * up. Otherwise we have a little more work to do see below for more details.
1902 *
1903 * NOTE: All errors are ignored by the calling routine
1904 */
1905static int
1906smbfs_vnop_mnomap(struct vnop_mnomap_args *ap)
1907{
1908	vnode_t				vp = ap->a_vp;
1909	struct smbnode		*np;
1910	struct fileRefEntry *entry;
1911	int					error = 0;
1912
1913	if (smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK))
1914		return (EPERM);	/* Not sure what to do here, they ignore errors */
1915
1916    SMB_LOG_KTRACE(SMB_DBG_MNOMAP | DBG_FUNC_START, 0, 0, 0, 0, 0);
1917
1918    np = VTOSMB(vp);
1919	np->n_lastvop = smbfs_vnop_mnomap;
1920
1921	/* Only one open reference just call close and let it clean every thing up. */
1922	if (np->f_refcnt == 1) {
1923		struct smb_share *share;
1924
1925		share = smb_get_share_with_reference(VTOSMBFS(vp));
1926		error = smbfs_close(share, vp, np->f_mmapMode, ap->a_context);
1927		smb_share_rele(share, ap->a_context);
1928		if (error) {
1929            lck_rw_lock_shared(&np->n_name_rwlock);
1930			SMBWARNING("%s close failed with error = %d\n", np->n_name, error);
1931            lck_rw_unlock_shared(&np->n_name_rwlock);
1932        }
1933		goto out;
1934	} else {
1935        if (np->f_refcnt > 0) {
1936            np->f_refcnt--;
1937        }
1938	}
1939	/*
1940	 * We get passed the current context which may or may not be the the same as the one used
1941	 * in the open. So search the list and see if there are any mapped entries. Remember we only
1942	 * have one item mapped at a time.
1943	 */
1944	if (FindMappedFileRef(vp, &entry, NULL) == TRUE) {
1945		entry->mmapped = FALSE;
1946		if (entry->refcnt > 0)	/* This entry is still in use don't remove it yet. */
1947			entry->refcnt--;
1948		else /* Done with it remove it from the list */
1949		    RemoveFileRef(vp, entry);
1950	}
1951out:
1952	np->f_mmapMode = 0;
1953	np->n_flag &= ~NISMAPPED;
1954	smbnode_unlock(np);
1955
1956    SMB_LOG_KTRACE(SMB_DBG_MNOMAP | DBG_FUNC_END, error, 0, 0, 0, 0);
1957    return (error);
1958}
1959
1960/*
1961 * smbfs_vnop_inactive - smbfs vnodeop entry point
1962 *	vnode_t a_vp;
1963 *	vfs_context_t a_context;
1964 */
1965static int
1966smbfs_vnop_inactive(struct vnop_inactive_args *ap)
1967{
1968	vnode_t vp = ap->a_vp;
1969	struct smbnode *np;
1970	struct smb_share *share = NULL;
1971	int error = 0;
1972	int releaseLock = TRUE;
1973
1974    SMB_LOG_KTRACE(SMB_DBG_INACTIVE | DBG_FUNC_START, 0, 0, 0, 0, 0);
1975
1976	(void)smbnode_lock(VTOSMB(vp), SMBFS_RECLAIM_LOCK);
1977	np = VTOSMB(vp);
1978	np->n_lastvop = smbfs_vnop_inactive;
1979	share = smb_get_share_with_reference(VTOSMBFS(vp));
1980
1981
1982	/* Clear any symlink cache, always safe to do even on non symlinks */
1983    if (np->n_symlink_target) {
1984        SMB_FREE(np->n_symlink_target, M_TEMP);
1985    }
1986	np->n_symlink_target_len = 0;
1987	np->n_symlink_cache_timer = 0;
1988
1989	/* Node went inactive clear the ACL cache */
1990	if (!vnode_isnamedstream(vp))
1991		smbfs_clear_acl_cache(np);
1992
1993    /*
1994	 * Before we take the lock, someone could jump in and do an open and start using this vnode again.
1995	 * We now check for that and just skip out if it happens. We will get another inactive later, if
1996	 * this volume is not being force unmount. So check here to see if the vnode is in use and the
1997	 * volume is not being forced unmounted. Note that Kqueue opens will not be found by vnode_isinuse.
1998	 */
1999    if ((vnode_isinuse(vp, 0)) && !(vfs_isforce(vnode_mount(vp))))
2000        goto out;
2001
2002	if (vnode_isdir(vp)) {
2003		smbfs_closedirlookup(np, ap->a_context);
2004		np->d_refcnt = 0;
2005		if (np->d_kqrefcnt) {
2006			smbfs_stop_change_notify(share, np, TRUE, ap->a_context, &releaseLock);
2007		}
2008		goto out;
2009	}
2010
2011	/* its not in use are they don't care about it close it */
2012	if (np->f_refcnt) {
2013		np->f_refcnt = 1;
2014		error = smbfs_close(share, vp, FREAD, ap->a_context);
2015		if (error) {
2016            lck_rw_lock_shared(&np->n_name_rwlock);
2017			SMBDEBUG("error %d closing fid %llx file %s\n",
2018                     error, np->f_fid, np->n_name);
2019            lck_rw_unlock_shared(&np->n_name_rwlock);
2020		}
2021	}
2022
2023	/*
2024	 * Does the file need to be deleted on close. Make one more check here
2025	 * just in case.
2026	 */
2027	if (np->n_flag & NDELETEONCLOSE) {
2028		error = smbfs_smb_delete(share, np, VREG,
2029                                 NULL, 0,
2030                                 0, ap->a_context);
2031		if (error) {
2032            lck_rw_lock_shared(&np->n_name_rwlock);
2033			SMBWARNING("error %d deleting silly rename file %s\n",
2034					   error, np->n_name);
2035            lck_rw_unlock_shared(&np->n_name_rwlock);
2036        }
2037		else np->n_flag &= ~NDELETEONCLOSE;
2038	}
2039#ifdef SMB_DEBUG
2040	/* If the file is not in use then it should be closed. */
2041	DBG_ASSERT((np->f_refcnt == 0));
2042	DBG_ASSERT((np->f_openDenyList == NULL));
2043	DBG_ASSERT((np->f_smbflock == NULL));
2044#endif // SMB_DEBUG
2045
2046out:
2047	smb_share_rele(share, ap->a_context);
2048	if (releaseLock)
2049		smbnode_unlock(np);
2050
2051    SMB_LOG_KTRACE(SMB_DBG_INACTIVE | DBG_FUNC_END, 0, 0, 0, 0, 0);
2052	return (0);
2053}
2054
2055/*
2056 * Free smbnode, and give vnode back to system
2057 *		struct vnodeop_desc *a_desc;
2058 *		vnode_t a_vp;
2059 *		vfs_context_t a_context;
2060 */
2061static int smbfs_vnop_reclaim(struct vnop_reclaim_args *ap)
2062{
2063	vnode_t vp = ap->a_vp;
2064	vnode_t dvp;
2065	struct smbnode *np = NULL;
2066	struct smbmount *smp = NULL;
2067
2068    SMB_LOG_KTRACE(SMB_DBG_RECLAIM | DBG_FUNC_START, 0, 0, 0, 0, 0);
2069
2070	(void) smbnode_lock(VTOSMB(vp), SMBFS_RECLAIM_LOCK);
2071
2072	np = VTOSMB(vp);
2073	np->n_lastvop = smbfs_vnop_reclaim;
2074	smp = VTOSMBFS(vp);
2075
2076#ifdef SMB_DEBUG
2077	/* We should never have a file open at this point */
2078	if (vnode_isreg(vp)) {
2079		DBG_ASSERT((np->f_refcnt == 0));
2080	} else if (vnode_isdir(vp)) {
2081		DBG_ASSERT((np->d_kqrefcnt == 0));
2082		DBG_ASSERT((np->d_fctx == NULL));
2083	}
2084#endif // SMB_DEBUG
2085
2086    lck_rw_lock_exclusive(&np->n_parent_rwlock);
2087
2088    SET(np->n_flag, NTRANSIT);
2089
2090    dvp = ((np->n_parent && (np->n_flag & NREFPARENT)) &&
2091           ((np->n_parent->n_flag & NTRANSIT) != NTRANSIT)) ?
2092            np->n_parent->n_vnode : NULL;
2093
2094    if (dvp != NULL) {
2095        /* Parent exists and is not being reclaimed, remove child's refcount */
2096        OSDecrementAtomic(&VTOSMB(dvp)->n_child_refcnt);
2097        np->n_parent = NULL;
2098    }
2099
2100    lck_rw_unlock_exclusive(&np->n_parent_rwlock);
2101
2102    SMB_LOG_KTRACE(SMB_DBG_RECLAIM | DBG_FUNC_NONE,
2103                   0xabc001,
2104                   np->n_child_refcnt,
2105                   vfs_isforce(vnode_mount(vp)), 0, 0);
2106
2107    /* Child_refcnt should be zero */
2108	if (np->n_child_refcnt) {
2109        if (!(vfs_isforce(vnode_mount(vp)))) {
2110            /*
2111             * Forced unmounts are very brutal, and it's not unusual for a
2112             * parent node being reclaimed to have a non-zero child refcount.
2113             * So we only log an error if this is not a forced unmount, which
2114             * we do care about.
2115             */
2116            if (vnode_getname(vp) != NULL) {
2117                SMBERROR("%s: node: %s, n_child_refcnt not zero like it should be: %ld\n",
2118                         __FUNCTION__, vnode_getname(vp), (long) np->n_child_refcnt);
2119            }
2120            else {
2121                SMBERROR("%s: n_child_refcnt not zero like it should be: %ld\n",
2122                         __FUNCTION__, (long) np->n_child_refcnt);
2123            }
2124        }
2125
2126        /*
2127         * We hold sm_reclaim_lock to protect np->n_parent fields from a
2128         * race with other functions that walk all the parents up to the root
2129         * vnode. Always lock sm_reclaim_lock first and then individual
2130         * n_parent_rwlock/n_name_rwlock next.
2131         * See <rdar://problem/15707521>.
2132         */
2133        lck_mtx_lock(&smp->sm_reclaim_lock);
2134
2135		smbfs_ClearChildren(smp, np);
2136
2137        /*
2138         * In previous code - smb_vhashrem() was called after releasing
2139         * sm_reclaim_lock.
2140         * There was a small window between sm_reclaim_lock is released and
2141         * smbnode (say child) is deleted from hash.
2142         * During this window, child can be NTRANSIT and parent can acquire
2143         * sm_reclaim_lock, proceed further in reclaim to call
2144         * smbfs_ClearChildren(), but skips the above child (NTRASIT set),
2145         * gets deleted from hash before child gets deleted.
2146         * May not affect anything as such, but just to be safe, I am moving
2147         * smb_vhashrem() in the scope of the sm_reclaim_lock.
2148         * Most likely, this can happen during the force unmount.
2149         */
2150        smb_vhashrem(np);
2151
2152        lck_mtx_unlock(&smp->sm_reclaim_lock);
2153    }
2154    else {
2155        smb_vhashrem(np);
2156    }
2157
2158	cache_purge(vp);
2159	if (smp->sm_rvp == vp) {
2160		SMBVDEBUG("root vnode\n");
2161		smp->sm_rvp = NULL;
2162	}
2163
2164	/* Destroy the lock used for the open state, open deny list and resource size/timer */
2165	if (!vnode_isdir(vp)) {
2166		lck_mtx_destroy(&np->f_openDenyListLock, smbfs_mutex_group);
2167		lck_mtx_destroy(&np->f_openStateLock, smbfs_mutex_group);
2168		lck_mtx_destroy(&np->f_clusterWriteLock, smbfs_mutex_group);
2169		if (!vnode_isnamedstream(vp))
2170			lck_mtx_destroy(&np->rfrkMetaLock, smbfs_mutex_group);
2171	}
2172
2173	/* Clear any symlink cache, always safe to do even on non symlinks */
2174    if (np->n_symlink_target != NULL) {
2175        SMB_FREE(np->n_symlink_target, M_TEMP);
2176    }
2177	np->n_symlink_target_len = 0;
2178	np->n_symlink_cache_timer = 0;
2179
2180	/* We are done with the node clear the acl cache and destroy the acl cache lock  */
2181	if (!vnode_isnamedstream(vp)) {
2182		smbfs_clear_acl_cache(np);
2183		lck_mtx_destroy(&np->f_ACLCacheLock, smbfs_mutex_group);
2184	}
2185
2186	/* Free up both names before we unlock the node */
2187    lck_rw_lock_exclusive(&np->n_name_rwlock);
2188    if (np->n_name != NULL) {
2189        SMB_FREE(np->n_name, M_SMBNODENAME);
2190        np->n_name = NULL;
2191    }
2192
2193    if (np->n_sname != NULL) {
2194        SMB_FREE(np->n_sname, M_SMBNODENAME);
2195        np->n_sname = NULL;
2196    }
2197    lck_rw_unlock_exclusive(&np->n_name_rwlock);
2198
2199    /* Clear the private data pointer *before* unlocking the node, so we don't
2200     * race with another thread doing a 'np = VTOSMB(vp)'.
2201     */
2202    vnode_clearfsnode(vp);
2203	smbnode_unlock(np);
2204
2205	CLR(np->n_flag, (NALLOC|NTRANSIT));
2206	if (ISSET(np->n_flag, NWALLOC) || ISSET(np->n_flag, NWTRANSIT)) {
2207		CLR(np->n_flag, (NWALLOC|NWTRANSIT));
2208		wakeup(np);
2209	}
2210	lck_rw_destroy(&np->n_rwlock, smbfs_rwlock_group);
2211	lck_rw_destroy(&np->n_name_rwlock, smbfs_rwlock_group);
2212	lck_rw_destroy(&np->n_parent_rwlock, smbfs_rwlock_group);
2213	SMB_FREE(np, M_SMBNODE);
2214	if (dvp && (vnode_get(dvp) == 0)) {
2215		vnode_rele(dvp);
2216		vnode_put(dvp);
2217	}
2218
2219	SMB_LOG_KTRACE(SMB_DBG_RECLAIM | DBG_FUNC_END, 0, 0, 0, 0, 0);
2220    return 0;
2221}
2222
2223/*
2224 * smbfs_getattr call from vfs.
2225 *
2226 * The calling routine must hold a reference on the share
2227 *
2228 */
2229static int
2230smbfs_getattr(struct smb_share *share, vnode_t vp, struct vnode_attr *vap,
2231			  vfs_context_t context)
2232{
2233	if (share->ss_attributes & FILE_PERSISTENT_ACLS &&
2234	    (VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_guuid) ||
2235	     VATTR_IS_ACTIVE(vap, va_uuuid))) {
2236			DBG_ASSERT(!vnode_isnamedstream(vp));
2237			(void)smbfs_getsecurity(share, VTOSMB(vp), vap, context);
2238	}
2239	return smbfs_update_cache(share, vp, vap, context);
2240}
2241
2242/*
2243 * smbfs_vnop_getattr
2244 *
2245 * vnode_t	a_vp;
2246 * struct vnode_attr *a_vap;
2247 * vfs_context_t a_context;
2248 */
2249static int
2250smbfs_vnop_getattr(struct vnop_getattr_args *ap)
2251{
2252	int32_t error = 0;
2253	struct smb_share *share;
2254	struct smbnode *np;
2255
2256	if ((error = smbnode_lock(VTOSMB(ap->a_vp), SMBFS_SHARED_LOCK))) {
2257		return (error);
2258	}
2259
2260	SMB_LOG_KTRACE(SMB_DBG_GET_ATTR | DBG_FUNC_START, 0, 0, 0, 0, 0);
2261
2262    np = VTOSMB(ap->a_vp);
2263	np->n_lastvop = smbfs_vnop_getattr;
2264	share = smb_get_share_with_reference(VTOSMBFS(ap->a_vp));
2265
2266	/* Before updating see if it needs to be reopened. */
2267	if ((!vnode_isdir(ap->a_vp)) && (np->f_openState & kNeedReopen)) {
2268		/* smbfs_smb_reopen_file should check to see if the share changed? */
2269		(void)smbfs_smb_reopen_file(share, np, ap->a_context);
2270	}
2271
2272	error = smbfs_getattr(share, ap->a_vp, ap->a_vap, ap->a_context);
2273	smb_share_rele(share, ap->a_context);
2274	smbnode_unlock(np);
2275
2276    SMB_LOG_KTRACE(SMB_DBG_GET_ATTR | DBG_FUNC_END, error, 0, 0, 0, 0);
2277	return (error);
2278}
2279
2280/*
2281 * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
2282 * interval there were 8 regular years and 2 leap years.
2283 */
2284#define	SECONDSTO1980	(((8 * 365) + (2 * 366)) * (24 * 60 * 60))
2285static struct timespec fat1980_time = {SECONDSTO1980, 0};
2286
2287/*
2288* The calling routine must hold a reference on the share
2289*/
2290static int
2291smbfs_setattr(struct smb_share *share, vnode_t vp, struct vnode_attr *vap,
2292			  vfs_context_t context)
2293{
2294	struct smbnode *np = VTOSMB(vp);
2295	struct smbmount *smp = VTOSMBFS(vp);
2296	struct timespec *crtime, *mtime, *atime;
2297	u_quad_t tsize = 0;
2298	int error = 0, cerror, modified = 0;
2299    SMBFID fid = 0;
2300	uint32_t rights;
2301	Boolean useFatTimes = (share->ss_fstype == SMB_FS_FAT);
2302    enum vtype vnode_type = VREG;
2303
2304    SMB_LOG_KTRACE(SMB_DBG_SMBFS_SETATTR | DBG_FUNC_START, 0, 0, 0, 0, 0);
2305
2306    if (np == NULL) {
2307        SMBERROR("Null np \n");
2308        error = EINVAL;
2309        goto out;
2310    }
2311
2312    if ((np) && (np->n_vnode)) {
2313        /* Use vnode to determine type */
2314        vnode_type = vnode_isdir(np->n_vnode) ? VDIR : VREG;
2315    }
2316
2317	/* If this is a stream then they can only set the size */
2318	if ((vnode_isnamedstream(vp)) &&
2319		(vap->va_active & ~VNODE_ATTR_BIT(va_data_size))) {
2320        lck_rw_lock_shared(&np->n_name_rwlock);
2321		SMBDEBUG("Using stream node %s to set something besides the size?\n",
2322				 np->n_name);
2323        lck_rw_unlock_shared(&np->n_name_rwlock);
2324
2325		error = ENOTSUP;
2326		goto out;
2327	}
2328
2329	/*
2330	 * If our caller is trying to set multiple attributes, they
2331	 * can make no assumption about what order they are done in.
2332	 * Here we try to do them in order of decreasing likelihood
2333	 * of failure, just to minimize the chance we'll wind up
2334	 * with a partially complete request.
2335	 */
2336
2337	if (share->ss_attributes & FILE_PERSISTENT_ACLS &&
2338	    (VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_guuid) ||
2339	     VATTR_IS_ACTIVE(vap, va_uuuid))) {
2340		error = smbfs_setsecurity(share, vp, vap, context);
2341        SMB_LOG_KTRACE(SMB_DBG_SMBFS_SETATTR | DBG_FUNC_NONE,
2342                       0xabc001, error, 0, 0, 0);
2343		if (error)
2344			goto out;
2345		/*
2346		 * Failing to set VATTR_SET_SUPPORTED to something which was
2347		 * requested causes fallback to EAs, which we never want. This
2348		 * is done because of HFS, so if you support it you have to
2349		 * always return something, even if its wrong.
2350		 */
2351		if (VATTR_IS_ACTIVE(vap, va_acl))
2352			VATTR_SET_SUPPORTED(vap, va_acl);
2353		if (VATTR_IS_ACTIVE(vap, va_guuid))
2354			VATTR_SET_SUPPORTED(vap, va_guuid);
2355		if (VATTR_IS_ACTIVE(vap, va_uuuid))
2356			VATTR_SET_SUPPORTED(vap, va_uuuid);
2357		modified = 1;
2358	}
2359
2360	/*
2361	 * If the server supports the new UNIX extensions, then we can support
2362	 * changing the uid, gid, mode, and va_flags. Currently the uid and gid
2363	 * don't make any sense, but in the future we may add this support.
2364	 *
2365	 * The old code would check the users creditials here. There is no need for
2366	 * that in our case. The lower level will make sure the correct local user
2367	 * is using the vc and the server should protect us for any other case.
2368	 */
2369
2370	if ((VATTR_IS_ACTIVE(vap, va_mode)) || (VATTR_IS_ACTIVE(vap, va_flags))) {
2371		int supportUnixBSDFlags = ((UNIX_CAPS(share) & UNIX_SFILEINFO_UNIX_INFO2_CAP)) ? TRUE : FALSE;
2372		int supportUnixInfo2 = ((UNIX_CAPS(share) & UNIX_QFILEINFO_UNIX_INFO2_CAP)) ? TRUE : FALSE;
2373		int darwin = (SSTOVC(share)->vc_flags & SMBV_DARWIN) ? TRUE : FALSE;
2374		int dosattr = np->n_dosattr;
2375		uint32_t vaflags = 0;
2376		uint32_t vaflags_mask = SMB_FLAGS_NO_CHANGE;
2377		uint64_t vamode = SMB_MODE_NO_CHANGE;
2378
2379		if (VATTR_IS_ACTIVE(vap, va_flags)) {
2380			/*
2381			 * Here we are strict, stricter than ufs in not allowing users to
2382			 * attempt to set SF_SETTABLE bits or anyone to set unsupported bits.
2383			 * However, we ignore attempts to set ATTR_ARCHIVE for directories
2384			 * `cp -pr' from a more sensible file system attempts it a lot.
2385			 */
2386			if (vap->va_flags & ~(SF_ARCHIVED | SF_IMMUTABLE | UF_IMMUTABLE | UF_HIDDEN))
2387			{
2388				error = EINVAL;
2389				goto out;
2390			}
2391			/* Only set items we can change and the server supports */
2392			vaflags_mask = np->n_flags_mask & EXT_REQUIRED_BY_MAC;
2393
2394			/*
2395			 * Remember that SMB_EFA_ARCHIVE means the items needs to be
2396			 * archive and SF_ARCHIVED means the item has been archive.
2397			 */
2398			if (vap->va_flags & SF_ARCHIVED) {
2399				dosattr &= ~SMB_EFA_ARCHIVE;
2400				vaflags |= EXT_DO_NOT_BACKUP;
2401			} else {
2402				dosattr |= SMB_EFA_ARCHIVE;
2403			}
2404			/*
2405			 * SMB_EFA_RDONLY ~ UF_IMMUTABLE
2406			 *
2407			 * We treat the SMB_EFA_RDONLY as the immutable flag. This allows
2408			 * us to support the finder lock bit and makes us follow the
2409			 * MSDOS code model. See msdosfs project.
2410			 *
2411			 * NOTE: The ready-only flags does not exactly follow the
2412			 * lock/immutable bit also note the for directories its advisory only.
2413			 *
2414			 * We do not support the setting the read-only bit for folders if
2415			 * the server does not support the new UNIX extensions.
2416			 *
2417			 * See Radar 5582956 for more details.
2418			 */
2419            if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
2420                if (UNIX_SERVER(SSTOVC(share)) || (!vnode_isdir(vp))) {
2421                    if (vap->va_flags & (SF_IMMUTABLE | UF_IMMUTABLE)) {
2422                        dosattr |= SMB_EFA_RDONLY;
2423                        vaflags |= EXT_IMMUTABLE;
2424                    }
2425                    else {
2426                        dosattr &= ~SMB_EFA_RDONLY;
2427                    }
2428                }
2429           }
2430            else {
2431                if (supportUnixBSDFlags || darwin || (!vnode_isdir(vp))) {
2432                    if (vap->va_flags & (SF_IMMUTABLE | UF_IMMUTABLE)) {
2433                        dosattr |= SMB_EFA_RDONLY;
2434                        vaflags |= EXT_IMMUTABLE;
2435                    }
2436                    else {
2437                        dosattr &= ~SMB_EFA_RDONLY;
2438                    }
2439                }
2440            }
2441
2442			/*
2443			 * NOTE: Windows does not set ATTR_ARCHIVE bit for directories.
2444			 */
2445			if ((! supportUnixBSDFlags) && (vnode_isdir(vp)))
2446				dosattr &= ~SMB_EFA_ARCHIVE;
2447
2448			/* Now deal with the new Hidden bit */
2449			if (vap->va_flags & UF_HIDDEN) {
2450				dosattr |= SMB_EFA_HIDDEN;
2451				vaflags |= EXT_HIDDEN;
2452			} else {
2453				dosattr &= ~SMB_EFA_HIDDEN;
2454			}
2455		}
2456
2457		/*
2458		 * Currently we do not allow setting the uid, gid, or sticky bits. Also
2459		 * chmod on a symbolic link doesn't really make sense. BSD allows this
2460		 * with the lchmod and on create, but Samba doesn't support this because
2461		 * its not POSIX. If we try to chmod here it will get set on the target
2462		 * which would be bad. So ignore the fact that they made this request.
2463		 */
2464		if (VATTR_IS_ACTIVE(vap, va_mode)) {
2465			if (supportUnixInfo2 && (!vnode_islnk(vp))) {
2466				vamode = vap->va_mode & ACCESSPERMS;
2467			} else if ((share->ss_attributes & FILE_PERSISTENT_ACLS) &&
2468					   (darwin || !UNIX_CAPS(share))) {
2469				vamode = vap->va_mode & ACCESSPERMS;
2470			} else if (SSTOVC(share)->vc_server_caps & kAAPL_SUPPORTS_NFS_ACE) {
2471                /*
2472                 * For OS X <-> OS X PFS (where ACLs are off by default), we
2473                 * need a way to set Posix permissions. If the server supports
2474                 * the NFS ACE, then it will allow us to get the ACL and send
2475                 * it back with the desired Posix permissions in the NFS ACE.
2476                 */
2477				vamode = vap->va_mode & ACCESSPERMS;
2478            }
2479
2480		}
2481		if (dosattr == np->n_dosattr) {
2482			vaflags_mask = 0; /* Nothing really changes, no need to make the call */
2483		}
2484		if (vaflags_mask || (vamode != SMB_MODE_NO_CHANGE)) {
2485			if (!supportUnixInfo2) {
2486				/* Windows style server */
2487				if (vaflags_mask) {
2488					error = smbfs_smb_setpattr(share, np, vnode_type,
2489                                               NULL, 0,
2490                                               dosattr, context);
2491				}
2492				if (vamode != SMB_MODE_NO_CHANGE) {
2493					/* Should we report the error? */
2494					error = smbfs_set_ace_modes(share, np, vamode, context);
2495				}
2496			} else if (supportUnixBSDFlags) {
2497				/* Samba server that does support the BSD flags (Mac OS) */
2498				error = smbfs_set_unix_info2(share, np, NULL, NULL, NULL,
2499											 SMB_SIZE_NO_CHANGE,  vamode, vaflags,
2500											 vaflags_mask, context);
2501			} else {
2502				/* Samba server that doesn't support the BSD flags, Linux */
2503				if (vamode != SMB_MODE_NO_CHANGE) {
2504					/* Now set the posix modes, using unix info level */
2505					error = smbfs_set_unix_info2(share, np, NULL, NULL, NULL,
2506												 SMB_SIZE_NO_CHANGE, vamode,
2507												 SMB_FLAGS_NO_CHANGE, vaflags_mask,
2508												 context);
2509				}
2510				if (vaflags_mask) {
2511					/* Set the BSD flags using normal smb info level  */
2512					error = smbfs_smb_setpattr(share, np, vnode_type,
2513                                               NULL, 0,
2514                                               dosattr, context);
2515				}
2516			}
2517			if (error)
2518				goto out;
2519		}
2520		/* Everything work update the local cache and mark that we did the work */
2521		if (VATTR_IS_ACTIVE(vap, va_mode)) {
2522	    	if (vamode != SMB_MODE_NO_CHANGE) {
2523				np->n_mode = vamode;
2524				VATTR_SET_SUPPORTED(vap, va_mode);
2525			}
2526		}
2527		if (VATTR_IS_ACTIVE(vap, va_flags)) {
2528			np->n_dosattr = dosattr;
2529			VATTR_SET_SUPPORTED(vap, va_flags);
2530		}
2531	}
2532
2533	if (VATTR_IS_ACTIVE(vap, va_data_size) && (vnode_isreg(vp))) {
2534		uint32_t trycnt = 0;
2535
2536		ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
2537		/* The seteof call requires the file to be opened for write and append data. */
2538		rights = SMB2_FILE_WRITE_DATA | SMB2_FILE_APPEND_DATA;
2539		/*
2540		 * The connection could go down in the middle of setting the eof, in
2541		 * this case we will get a bad file descriptor error. Keep trying until
2542		 * the open fails or we get something besides EBADF.
2543		 *
2544		 * We now have a counter that keeps us from going into an infinite loop. Once
2545		 * we implement SMB 2/3 we should take a second look at how this should be done.
2546		 */
2547		do {
2548			error = smbfs_tmpopen(share, np, rights, &fid, context);
2549			if (error) {
2550                lck_rw_lock_shared(&np->n_name_rwlock);
2551				SMB_LOG_IO("%s seteof open failed %d\n", np->n_name, error);
2552                lck_rw_unlock_shared(&np->n_name_rwlock);
2553				/* The open failed, fail the seteof. */
2554				break;
2555			}
2556
2557			/* zero fill if needed, ignore any errors will catch them on the seteof call */
2558			tsize = np->n_size;
2559			if (tsize < vap->va_data_size) {
2560				error = smbfs_0extend(share, fid, tsize, vap->va_data_size, 0, context);
2561                SMB_LOG_KTRACE(SMB_DBG_SMBFS_SETATTR | DBG_FUNC_NONE,
2562                               0xabc002, error, 0, 0, 0);
2563			}
2564			/* Set the eof on the server */
2565			if (!error) {
2566				error = smbfs_seteof(share, np, fid, vap->va_data_size, context);
2567                SMB_LOG_KTRACE(SMB_DBG_SMBFS_SETATTR | DBG_FUNC_NONE,
2568                               0xabc003, error, 0, 0, 0);
2569			}
2570			if (error == EBADF) {
2571				trycnt++;
2572                lck_rw_lock_shared(&np->n_name_rwlock);
2573				SMB_LOG_IO("%s seteof failed because of reconnect, trying again.\n",
2574						   np->n_name);
2575                lck_rw_unlock_shared(&np->n_name_rwlock);
2576			}
2577			/*
2578			 * Windows FAT file systems require a flush, after a seteof. Until the
2579			 * the flush they will keep returning the old file size.
2580			 */
2581			if ((!error) && (share->ss_fstype == SMB_FS_FAT) &&
2582				(!UNIX_SERVER(SSTOVC(share)))) {
2583				error = smbfs_smb_flush(share, fid, context);
2584				if (!error)
2585					np->n_flag &= ~NNEEDS_FLUSH;
2586			}
2587			/* We ignore errors on close, not much we can do about it here */
2588			(void)smbfs_tmpclose(share, np, fid, context);
2589		} while ((error == EBADF) && (trycnt < SMB_MAX_REOPEN_CNT));
2590
2591        lck_rw_lock_shared(&np->n_name_rwlock);
2592		SMB_LOG_IO("%s: Calling smbfs_setsize, old eof = %lld  new eof = %lld\n",
2593				   np->n_name, tsize, vap->va_data_size);
2594        lck_rw_unlock_shared(&np->n_name_rwlock);
2595
2596		if (error) {
2597			smbfs_setsize(vp, (off_t)tsize);
2598			goto out;
2599		} else {
2600			smbfs_setsize(vp, (off_t)vap->va_data_size);
2601		}
2602        SMB_LOG_KTRACE(SMB_DBG_SMBFS_SETATTR | DBG_FUNC_NONE,
2603                       0xabc004, error, 0, 0, 0);
2604
2605		VATTR_SET_SUPPORTED(vap, va_data_size);
2606		/* Tell the stream's parent that something has changed */
2607		if (vnode_isnamedstream(vp)) {
2608			vnode_t parent_vp = smb_update_rsrc_and_getparent(vp, TRUE);
2609			/*
2610			 * We cannot always update the parents meta cache timer, so don't
2611			 * even try here
2612			 */
2613			if (parent_vp)
2614				vnode_put(parent_vp);
2615		}
2616
2617		modified = 1;
2618  	}
2619
2620	/*
2621	 * Note that it's up to the caller to provide (or not) a fallback for
2622	 * backup_time, as we don't support them.
2623	 *
2624	 */
2625	crtime = VATTR_IS_ACTIVE(vap, va_create_time) ? &vap->va_create_time : NULL;
2626	mtime = VATTR_IS_ACTIVE(vap, va_modify_time) ? &vap->va_modify_time : NULL;
2627	atime = VATTR_IS_ACTIVE(vap, va_access_time) ? &vap->va_access_time : NULL;
2628
2629	/*
2630	 * If they are just setting the time to the same value then just say we made
2631	 * the call. This will not hurt anything and will protect us from badly
2632	 * written applications. Here is what was happening in the case of the finder
2633	 * copy. The file gets copied, and the modify time and create time have been set to
2634	 * the current time by the server. The application is using utimes to set the
2635	 * modify time to the original file's modify time. This time is before the create time.
2636	 * So we set both the create and modify time to the same value. See the HFS note
2637	 * below. Now the applications wants to set the create time to be the same as the
2638	 * orignal file. In this case the original file has the same modify and create time. So
2639	 * we end up setting the create time twice to the same value. Even with this code the
2640	 * copy engine needs to be fixed, looking into that now. Looks like this will get fix
2641	 * with Radar 4385758. We should retest once that radar is completed.
2642	 */
2643	if (crtime && (timespeccmp(crtime, &np->n_crtime, ==))) {
2644		VATTR_SET_SUPPORTED(vap, va_create_time);
2645		crtime = NULL;
2646	}
2647	if (mtime && (timespeccmp(mtime, &np->n_mtime, ==))) {
2648		VATTR_SET_SUPPORTED(vap, va_modify_time);
2649		mtime = NULL;
2650	}
2651	if (atime && (timespeccmp(atime, &np->n_atime, ==))) {
2652		VATTR_SET_SUPPORTED(vap, va_access_time);
2653		atime = NULL;
2654	}
2655
2656	/*
2657	 * We sometimes get sent a zero access time. Did some testing and found
2658	 * out the following:
2659	 *
2660	 *	MSDOS	- The date gets set to Dec 30 17:31:44 1969
2661	 *	SMB FAT	- The date gets set to Jan  1 00:00:00 1980
2662	 *	UFS	- The date gets set to Dec 31 16:00:00 1969
2663	 *	SMB NTFS- The date gets set to Dec 31 16:00:00 1969
2664	 *	HFS	- The date displayed from ls is Dec 31 16:00:00 1969
2665	 *	HFS	- The getattrlist date is <no value>
2666	 *
2667	 * I believe this is from a utimes call where they are setting the
2668	 * modify time, but leaving the access time set to zero. We seem to be
2669	 * doing the same thing as everyone else so let them do it.
2670	 */
2671	/*
2672	 * The following comment came from the HFS code.
2673	 * The utimes system call can reset the modification time but it doesn't
2674	 * know about create times. So we need to ensure that the creation time
2675	 * is always at least as old as the modification time.
2676	 *
2677	 * The HFS code also checks to make sure it was not the root vnode. Don
2678	 * Brady said that the SMB code should not use that part of the check.
2679	 */
2680	if (!crtime && mtime && (timespeccmp(mtime, &np->n_crtime, <))) {
2681		crtime = mtime;
2682	}
2683
2684	if (!crtime && !mtime && !atime) {
2685		/* Nothing left to do here get out */
2686		goto out;
2687	}
2688retrySettingTime:
2689#if 0
2690    lck_rw_lock_shared(&np->n_name_rwlock);
2691	if (crtime && mtime) {
2692		SMBDEBUG("%s crtime = %ld:%ld mtime = %ld:%ld\n", np->n_name,
2693				 crtime->tv_sec, crtime->tv_nsec, mtime->tv_sec, mtime->tv_nsec);
2694	} else if (crtime) {
2695		SMBDEBUG("%s crtime = %ld:%ld\n", np->n_name, crtime->tv_sec, crtime->tv_nsec);
2696	} else if (mtime) {
2697		SMBDEBUG("%s mtime = %ld:%ld\n", np->n_name, mtime->tv_sec, mtime->tv_nsec);
2698	}
2699    lck_rw_unlock_shared(&np->n_name_rwlock);
2700#endif // SMB_DEBUG
2701	/*
2702	 * FAT file systems don't support dates earlier than 1980, reset the
2703	 * date to 1980. Now the Finder likes to set the create date to 1904 or 1946,
2704	 * should we treat this special? We could hold on to the original time
2705	 * and return that value until they reset it or the vnode goes away. Since
2706	 * we never had any reports lets not add any extra code.
2707	 */
2708	if (useFatTimes) {
2709		if (crtime && (timespeccmp(crtime, &fat1980_time, <))) {
2710			crtime = &fat1980_time;
2711            lck_rw_lock_shared(&np->n_name_rwlock);
2712			SMBDEBUG("%s FAT crtime.tv_sec = %ld crtime.tv_nsec = %ld\n",
2713					 np->n_name, crtime->tv_sec, crtime->tv_nsec);
2714            lck_rw_unlock_shared(&np->n_name_rwlock);
2715		}
2716		if (mtime && (timespeccmp(mtime, &fat1980_time, <))) {
2717			mtime = &fat1980_time;
2718            lck_rw_lock_shared(&np->n_name_rwlock);
2719			SMBDEBUG("%s FAT mtime.tv_sec = %ld mtime.tv_nsec = %ld\n",
2720					 np->n_name, mtime->tv_sec, mtime->tv_nsec);
2721            lck_rw_unlock_shared(&np->n_name_rwlock);
2722		}
2723		/* Never let them set the access time before 1980 */
2724		if (atime && (timespeccmp(atime, &fat1980_time, <))) {
2725			atime = NULL;
2726		}
2727	}
2728
2729	if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
2730       /* SMB 2/3 always has to open/set/close the file */
2731        error = smb2fs_smb_setpattrNT(share, np, vnode_type,
2732                                      NULL, 0,
2733                                      np->n_dosattr, crtime,
2734                                      mtime, atime,
2735                                      context);
2736        SMB_LOG_KTRACE(SMB_DBG_SMBFS_SETATTR | DBG_FUNC_NONE,
2737                       0xabc005, error, 0, 0, 0);
2738    }
2739    else {
2740        rights = SMB2_FILE_WRITE_ATTRIBUTES;
2741        /*
2742         * For Windows 95/98/Me/NT4 and all old dialects we must have
2743         * the item open before we can set the date and time. For all
2744         * other systems; if the item is already open then make sure it
2745         * has the correct open mode.
2746         *
2747         * We currently never do a NT style open with write attributes.
2748         * So for all systems except NT4 that spport the NTCreateAndX
2749         * call we will fall through and just use the set path method.
2750         * In the future we may decide to add open deny support. So if
2751         * we decide to add write atributes access then this code will
2752         * work without any other changes.
2753         */
2754        if ((SSTOVC(share)->vc_flags & SMBV_NT4) ||
2755            (smp->sm_flags & MNT_REQUIRES_FILEID_FOR_TIME) ||
2756            ((!vnode_isdir(vp)) && np->f_refcnt && (np->f_rights & rights))) {
2757
2758            /*
2759             * For NT systems we need the file open for write attributes.
2760             * Either write access or all access will work. If they
2761             * already have it open for all access just use that,
2762             * otherwise use write. We corrected tmpopen
2763             * to work correctly now. So just ask for the NT access.
2764             */
2765            error = smbfs_tmpopen(share, np, rights, &fid, context);
2766            if (error)
2767                goto out;
2768
2769            error = smbfs_smb_setfattrNT(share, np->n_dosattr, fid, crtime,
2770                                         mtime, atime, context);
2771            cerror = smbfs_tmpclose(share, np, fid, context);
2772            if (cerror) {
2773                lck_rw_lock_shared(&np->n_name_rwlock);
2774                SMBERROR("error %d closing fid %llx file %s\n",
2775                         cerror, fid, np->n_name);
2776                lck_rw_unlock_shared(&np->n_name_rwlock);
2777            }
2778
2779        } else {
2780            error = smbfs_smb_setpattrNT(share, np, vnode_type,
2781                                         NULL, 0,
2782                                         np->n_dosattr, crtime, mtime,
2783                                         atime, context);
2784            /* They don't support this call, we need to fallback to the old method; stupid NetApp */
2785            if (error == ENOTSUP) {
2786                SMBWARNING("Server does not support setting time by path, fallback to old method\n");
2787                smp->sm_flags |= MNT_REQUIRES_FILEID_FOR_TIME;	/* Never go down this path again */
2788                error = smbfs_tmpopen(share, np, rights, &fid, context);
2789                if (!error) {
2790                    error = smbfs_smb_setfattrNT(share, np->n_dosattr, fid,
2791                                                 crtime, mtime, atime, context);
2792                    (void)smbfs_tmpclose(share, np, fid, context);
2793                }
2794            }
2795        }
2796    }
2797	/*
2798	 * Some servers (NetApp) don't support setting time before 1970 and will
2799	 * return an error here. So if we get an error and we were trying to set
2800	 * the time to before 1970 lets try again, but this time lets treat them
2801	 * the same as a FAT file system.
2802	 */
2803	if (error && !useFatTimes &&
2804		((crtime && (crtime->tv_sec < 0)) || (mtime && (mtime->tv_sec < 0)))) {
2805		useFatTimes = TRUE;
2806		goto retrySettingTime;
2807	}
2808
2809	if (error)
2810		goto out;
2811
2812	if (crtime) {
2813		VATTR_SET_SUPPORTED(vap, va_create_time);
2814		np->n_crtime = *crtime;
2815	}
2816	if (mtime) {
2817		VATTR_SET_SUPPORTED(vap, va_modify_time);
2818		np->n_mtime = *mtime;
2819	}
2820	if (atime) {
2821		VATTR_SET_SUPPORTED(vap, va_access_time);
2822		np->n_atime = *atime;
2823	}
2824	/* Update the change time */
2825	if (crtime || mtime || atime)
2826		nanotime(&np->n_chtime); /* Need current date/time, so use nanotime */
2827
2828out:
2829	if (modified) {
2830		/*
2831		 * Invalidate attribute cache in case if server doesn't set
2832		 * required attributes.
2833		 */
2834		np->attribute_cache_timer = 0;	/* invalidate cache */
2835	}
2836
2837    SMB_LOG_KTRACE(SMB_DBG_SMBFS_SETATTR | DBG_FUNC_END, error, 0, 0, 0, 0);
2838	return (error);
2839}
2840
2841/*
2842 * smbfs_vnop_getattr
2843 *
2844 * vnode_t	a_vp;
2845 * struct vnode_attr *a_vap;
2846 * vfs_context_t a_context;
2847 */
2848static int
2849smbfs_vnop_setattr(struct vnop_setattr_args *ap)
2850{
2851	int32_t error = 0;
2852	struct smbnode *np;
2853	struct smb_share *share;
2854
2855	if ((error = smbnode_lock(VTOSMB(ap->a_vp), SMBFS_EXCLUSIVE_LOCK))) {
2856		return (error);
2857	}
2858
2859    SMB_LOG_KTRACE(SMB_DBG_SET_ATTR | DBG_FUNC_START, 0, 0, 0, 0, 0);
2860
2861	np = VTOSMB(ap->a_vp);
2862	np->n_lastvop = smbfs_vnop_setattr;
2863	share = smb_get_share_with_reference(VTOSMBFS(ap->a_vp));
2864	error = smbfs_setattr (share, ap->a_vp, ap->a_vap, ap->a_context);
2865	smb_share_rele(share, ap->a_context);
2866	smbnode_unlock(VTOSMB(ap->a_vp));
2867	/* If this is a stream try to update the parents meta cache timer. */
2868	if (vnode_isnamedstream(ap->a_vp)) {
2869		vnode_t parent_vp = vnode_getparent(ap->a_vp);
2870		if (parent_vp) {
2871			VTOSMB(parent_vp)->attribute_cache_timer = 0;
2872			vnode_put(parent_vp);
2873		}
2874	}
2875
2876	SMB_LOG_KTRACE(SMB_DBG_SET_ATTR | DBG_FUNC_END, error, 0, 0, 0, 0);
2877    return (error);
2878}
2879
2880/*
2881 * smbfs_vnop_blockmap
2882 *
2883 * vnode_t	a_vp;
2884 * off_t	a_foffset;
2885 * uint32_t a_size;
2886 * daddr64_t *a_bpn;
2887 * uint32_t *a_run;
2888 * void *a_poff;
2889 * int32_t a_flags;
2890 */
2891static int
2892smbfs_vnop_blockmap(struct vnop_blockmap_args *ap)
2893{
2894    /*
2895	 * Always match the VM page size.  At this time it is 4K which limits us
2896	 * to 44 bit file size instead of 64...???
2897	 */
2898	/* make sure we don't go past EOF */
2899	if (ap->a_run)
2900		*ap->a_run = ap->a_size;
2901
2902	/* divide it by block size, MUST match value in smbfs_strategy */
2903    *ap->a_bpn = (daddr64_t)(ap->a_foffset / PAGE_SIZE);
2904
2905	if (ap->a_poff)
2906		*(int32_t *)ap->a_poff = 0;
2907
2908    return (0);
2909}
2910
2911/*
2912 * smbfs_vnop_strategy
2913 *
2914 *	struct buf *a_bp;
2915 */
2916static int
2917smbfs_vnop_strategy(struct vnop_strategy_args *ap)
2918{
2919	struct buf *bp = ap->a_bp;
2920	vnode_t vp = buf_vnode(bp);
2921	int32_t bflags = buf_flags(bp);
2922	struct smbnode *np = VTOSMB(vp);
2923	caddr_t io_addr = 0;
2924	uio_t	uio = NULL;
2925	int32_t error;
2926    SMBFID fid = 0;
2927	struct smb_share *share;
2928	uint32_t trycnt = 0;
2929    struct smbfattr *fap = NULL;
2930
2931    SMB_LOG_KTRACE(SMB_DBG_STRATEGY | DBG_FUNC_START, 0, 0, 0, 0, 0);
2932
2933	if (np->f_openState & kNeedRevoke) {
2934        /* behave like the deadfs does */
2935        lck_rw_lock_shared(&np->n_name_rwlock);
2936        SMBERROR("%s waiting to be revoked\n", np->n_name);
2937        lck_rw_unlock_shared(&np->n_name_rwlock);
2938        error = EIO;
2939		buf_seterror(bp, error);
2940        goto exit;
2941    }
2942
2943	if (np->f_refcnt == 0) {
2944        /*
2945         * This happens when a file is open and mmapped, then server goes down
2946         * and calls start soft timing out with ETIMEDOUT. The reads/writes
2947         * error out, then the close gets called, it gets an error but clears
2948         * the f_refcnt.  When unmount comes along, it tries again to push
2949         * out the data and thats when we end up here.
2950         */
2951        lck_rw_lock_shared(&np->n_name_rwlock);
2952        SMBDEBUG("%s has no file refs\n", np->n_name);
2953        lck_rw_unlock_shared(&np->n_name_rwlock);
2954        error = EIO;
2955		buf_seterror(bp, error);
2956        goto exit;
2957    }
2958
2959    SMB_MALLOC(fap,
2960               struct smbfattr *,
2961               sizeof(struct smbfattr),
2962               M_SMBTEMP,
2963               M_WAITOK | M_ZERO);
2964    if (fap == NULL) {
2965        SMBERROR("SMB_MALLOC failed\n");
2966        error = ENOMEM;
2967        goto exit;
2968    }
2969
2970    /*
2971	 * Can't use the physical addresses passed in the vector list, so map it
2972	 * into the kernel address space
2973	 */
2974    if ((error = buf_map(bp, &io_addr))) {
2975        panic("smbfs_vnop_strategy: buf_map() failed with (%d)", error);
2976	}
2977
2978	uio = uio_create(1, ((off_t)buf_blkno(bp)) * PAGE_SIZE, UIO_SYSSPACE,
2979					 (bflags & B_READ) ? UIO_READ : UIO_WRITE);
2980	if (!uio) {
2981        panic("smbfs_vnop_strategy: uio_create() failed");
2982	}
2983
2984	uio_addiov(uio, CAST_USER_ADDR_T(io_addr), buf_count(bp));
2985	/*
2986	 * Remember that buf_proc(bp) can return NULL, but in that case this is
2987	 * coming from the kernel and is not associated with a particular proc.
2988	 * In fact it just may be the pager itself trying to free up space and there
2989	 * is no proc. I need to find any proc that already has the fork open for
2990	 * read or write to use for read/write to work. This is handled in the
2991	 * FindFileRef routine.
2992	 */
2993	if (FindFileRef(vp, buf_proc(bp), (bflags & B_READ) ? kAccessRead : kAccessWrite,
2994					kCheckDenyOrLocks, uio_offset(uio), uio_resid(uio), NULL, &fid)) {
2995		/* No matches or no pid to match, so just use the generic shared fork */
2996		fid = np->f_fid;	/* We should always have something at this point */
2997	}
2998	DBG_ASSERT(fid);
2999
3000    lck_rw_lock_shared(&np->n_name_rwlock);
3001	SMB_LOG_IO("%s: %s offset %lld, size %lld, bflags 0x%x\n",
3002			   (bflags & B_READ) ? "Read":"Write", np->n_name, uio_offset(uio),
3003			   uio_resid(uio), bflags);
3004    lck_rw_unlock_shared(&np->n_name_rwlock);
3005
3006	share = smb_get_share_with_reference(VTOSMBFS(vp));
3007	/*
3008	 * Since we have already authorized the user when we opened the file, just
3009	 * pass a NULL context down to the authorization code.
3010	 */
3011	if (bflags & B_READ) {
3012		error = smbfs_doread(share, (off_t)np->n_size, uio, fid, NULL);
3013	} else {
3014		error = smbfs_dowrite(share, (off_t)np->n_size, uio, fid, 0, NULL);
3015
3016        if (!error) {
3017            /* Save last time we wrote data */
3018            nanouptime(&np->n_last_write_time);
3019        }
3020	}
3021    SMB_LOG_KTRACE(SMB_DBG_STRATEGY | DBG_FUNC_NONE,
3022                   0xabc001, error, 0, 0, 0);
3023
3024	/*
3025	 * We can't handle reopens in the normal fashion, because we have no lock. A
3026	 * bad file descriptor error, could mean a reconnect happen. Since
3027	 * we revoke all opens with manatory locks or open deny mode, we can just
3028	 * do the open, read/write then close.
3029	 *
3030	 * We now have a counter that keeps us from going into an infinite loop. Once
3031	 * we implement SMB 2/3 we should take a second look at how this should be done.
3032	 */
3033	while ((error == EBADF) && (trycnt < SMB_MAX_REOPEN_CNT)) {
3034		lck_mtx_lock(&np->f_openStateLock);
3035
3036        lck_rw_lock_shared(&np->n_name_rwlock);
3037        SMB_LOG_IO("%s failed the %s, because of reconnect, openState = 0x%x. Try again.\n",
3038				   np->n_name, (bflags & B_READ) ? "READ" : "WRITE", np->f_openState);
3039        lck_rw_unlock_shared(&np->n_name_rwlock);
3040
3041		if (np->f_openState & kNeedRevoke) {
3042			lck_mtx_unlock(&np->f_openStateLock);
3043			break;
3044		}
3045
3046		np->f_openState |= (kNeedReopen | kInReopen);
3047		lck_mtx_unlock(&np->f_openStateLock);
3048
3049		/* Could be a dfs share make sure we have the correct share */
3050		smb_share_rele(share, NULL);
3051		share = smb_get_share_with_reference(VTOSMBFS(vp));
3052		/* Recreate the uio */
3053		uio_free(uio);
3054		uio = uio_create(1, ((off_t)buf_blkno(bp)) * PAGE_SIZE, UIO_SYSSPACE,
3055						 (bflags & B_READ) ? UIO_READ : UIO_WRITE);
3056		if (!uio) {
3057			error = ENOMEM;
3058		} else {
3059            uio_addiov(uio, CAST_USER_ADDR_T(io_addr), buf_count(bp));
3060
3061            error = smbfs_smb_open_file(share, np,
3062                                        np->f_rights, NTCREATEX_SHARE_ACCESS_ALL, &fid,
3063                                        NULL, 0, FALSE,
3064                                        fap, NULL);
3065        }
3066
3067        lck_mtx_lock(&np->f_openStateLock);
3068        np->f_openState &= ~kInReopen;
3069        lck_mtx_unlock(&np->f_openStateLock);
3070
3071		if (error) {
3072			break;
3073		}
3074		if (bflags & B_READ) {
3075			error = smbfs_doread(share, (off_t)np->n_size, uio, fid, NULL);
3076		} else {
3077			error = smbfs_dowrite(share, (off_t)np->n_size, uio, fid, 0, NULL);
3078
3079            if (!error) {
3080                /* Save last time we wrote data */
3081                nanouptime(&np->n_last_write_time);
3082            }
3083		}
3084        SMB_LOG_KTRACE(SMB_DBG_STRATEGY | DBG_FUNC_NONE,
3085                       0xabc002, error, 0, 0, 0);
3086
3087		(void)smbfs_smb_close(share, fid, NULL);
3088		trycnt++;
3089	}
3090
3091	if (bflags & B_READ) {
3092		/*
3093		 * If we were not able to read the entire page, check to
3094		 * see if we are at the end of the file, and if so, zero
3095		 * out the remaining part of the page.
3096		 */
3097		while ((error == 0) && (uio_resid(uio))) {
3098			size_t bytes_to_zero = (uio_resid(uio) > PAGE_SIZE) ? PAGE_SIZE : (size_t)uio_resid(uio);
3099
3100			bzero((caddr_t) (io_addr + buf_count(bp) - uio_resid(uio)), bytes_to_zero);
3101			uio_update(uio, bytes_to_zero);
3102		}
3103    } else {
3104		lck_mtx_lock(&np->f_clusterWriteLock);
3105		if ((u_quad_t)uio_offset(uio) >= np->n_size) {
3106			/* We finished writing past the eof reset the flag */
3107			nanouptime(&np->n_sizetime);
3108			np->waitOnClusterWrite = FALSE;
3109            lck_rw_lock_shared(&np->n_name_rwlock);
3110			SMB_LOG_IO("%s: TURNING OFF waitOnClusterWrite np->n_size = %lld\n",
3111					   np->n_name, np->n_size);
3112            lck_rw_unlock_shared(&np->n_name_rwlock);
3113		}
3114		lck_mtx_unlock(&np->f_clusterWriteLock);
3115    }
3116
3117	if (error) {
3118        lck_rw_lock_shared(&np->n_name_rwlock);
3119		SMBERROR("%s on %s failed with an error of %d\n",
3120				 (bflags & B_READ) ? "READ" : "WRITE", np->n_name, error);
3121        lck_rw_unlock_shared(&np->n_name_rwlock);
3122
3123		np->f_clusterCloseError = error;	/* Error to be returned on close */
3124
3125		if ( (error == ENOTCONN) || (error == EBADF) || (error == ETIMEDOUT) ) {
3126			/*
3127			 * VFS cluster code has now been changed to handle non transient
3128			 * errors see radar 2894150.  It should be safe to return ENXIO.
3129			 */
3130			SMB_LOG_IO("failed with %d, returning ENXIO instead\n", error);
3131			error = ENXIO;
3132		}
3133	}
3134	smb_share_rele(share, NULL);
3135    buf_seterror(bp, error);
3136
3137	/* Should be zero when all done with reading/writing file */
3138    buf_setresid(bp, (uint32_t)uio_resid(uio));
3139
3140    if ((error = buf_unmap(bp)))
3141        panic("smbfs_vnop_strategy: buf_unmap() failed with (%d)", error);
3142
3143
3144exit:
3145	if (error) {
3146        lck_rw_lock_shared(&np->n_name_rwlock);
3147		SMB_LOG_IO("%s: buf_resid(bp) %d, error = %d \n",
3148				   np->n_name, buf_resid(bp), error);
3149        lck_rw_unlock_shared(&np->n_name_rwlock);
3150	}
3151
3152	if (uio != NULL)
3153		uio_free(uio);
3154
3155    buf_biodone(bp);
3156
3157    if (fap != NULL) {
3158        SMB_FREE(fap, M_SMBTEMP);
3159    }
3160
3161    SMB_LOG_KTRACE(SMB_DBG_STRATEGY | DBG_FUNC_END, error, 0, 0, 0, 0);
3162    return (error);
3163}
3164
3165/*
3166 * smbfs_vnop_read
3167 *
3168 *	vnode_t a_vp;
3169 *	uio_t a_uio;
3170 *	int a_ioflag;
3171 *	vfs_context_t a_context;
3172 */
3173static int
3174smbfs_vnop_read(struct vnop_read_args *ap)
3175{
3176	vnode_t vp = ap->a_vp;
3177	uio_t uio = ap->a_uio;
3178	int error = 0;
3179	struct smbnode *np = NULL;
3180    SMBFID fid = 0;
3181	struct smb_share *share;
3182
3183	/* Preflight checks */
3184	if (!vnode_isreg(vp)) {
3185		/* can only read regular files */
3186		if (vnode_isdir(vp))
3187			return (EISDIR);
3188		else
3189			return (EPERM);
3190	}
3191
3192	if (uio_resid(uio) == 0)
3193		return (0);		/* Nothing left to do */
3194
3195	if (uio_offset(uio) < 0)
3196		return (EINVAL);	/* cant read from a negative offset */
3197
3198	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_SHARED_LOCK)))
3199		return (error);
3200
3201    SMB_LOG_KTRACE(SMB_DBG_READ | DBG_FUNC_START,
3202                   uio_offset(uio),
3203                   uio_resid(uio), 0, 0, 0);
3204
3205	np = VTOSMB(vp);
3206	np->n_lastvop = smbfs_vnop_read;
3207	share = smb_get_share_with_reference(VTOSMBFS(vp));
3208	/*
3209	 * History: FreeBSD vs Darwin VFS difference; we can get VNOP_READ without
3210 	 * preceeding open via the exec path, so do it implicitly.  VNOP_INACTIVE
3211	 * closes the extra network file handle, and decrements the open count.
3212	 *
3213	 * If we are in reconnect mode calling smbfs_open will handle any reconnect
3214	 * issues. So only if we have a f_refcnt do we call smbfs_smb_reopen_file.
3215 	 */
3216 	if (!np->f_refcnt) {
3217 		error = smbfs_open(share, vp, FREAD, ap->a_context);
3218 		if (error)
3219 			goto exit;
3220		else np->f_needClose = 1;
3221 	} else {
3222		error = smbfs_smb_reopen_file(share, np, ap->a_context);
3223		if (error) {
3224            lck_rw_lock_shared(&np->n_name_rwlock);
3225			SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
3226            lck_rw_unlock_shared(&np->n_name_rwlock);
3227			goto exit;
3228		}
3229	}
3230
3231    /*
3232	 * Note: smbfs_isCacheable checks to see if the file is globally non
3233	 * cacheable, but we also need to support non cacheable on a per file
3234	 * descriptor level for reads/writes. So also check the IO_NOCACHE flag.
3235	 *
3236	 * So IO_NOCACHE means the same thing as VNOCACHE_DATA but only for this IO.
3237	 * Now VNOCACHE_DATA has the following comment:
3238	 *		"don't keep data cached once it's been consumed"
3239	 * Which seems to imply we could use cluster_read, but we would need to
3240	 * push out any data first and then invalidate the range after we are done
3241	 * with the read? Byte range locking prevents us from using the cluster_read.
3242	 */
3243	if ( smbfsIsCacheable(vp) && !(ap->a_ioflag & IO_NOCACHE)) {
3244 		error = cluster_read(vp, uio, (off_t) np->n_size, ap->a_ioflag);
3245        SMB_LOG_KTRACE(SMB_DBG_READ | DBG_FUNC_NONE, 0xabc001, error, 0, 0, 0);
3246		if (error) {
3247            lck_rw_lock_shared(&np->n_name_rwlock);
3248			SMB_LOG_IO("%s failed cluster_read with an error of %d\n",
3249					   np->n_name, error);
3250            lck_rw_unlock_shared(&np->n_name_rwlock);
3251		}
3252		/*
3253		 * EACCES means a denyConflict occured and must have hit some other
3254		 * computer's byte range lock on that file. Mark the file as
3255		 * noncacheable and retry read again
3256		 *
3257		 * Need to check the error here, could be EIO/EPERM
3258		 *
3259		 * XXX - NOTE: The strategy routine is going to mark this vnode as needing
3260		 * to be revoked. So this code seems wrong. We should either correct
3261		 * the strategy routine or remove this code.
3262		 */
3263		if (error == EACCES) {
3264			if (np->n_flag & NISMAPPED) {
3265				/* More expensive, but handles mmapped files */
3266				ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
3267			} else {
3268				/* Less expensive, but does not handle mmapped files */
3269				cluster_push(vp, IO_SYNC);
3270			}
3271			ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_INVALIDATE);
3272			vnode_setnocache(vp);
3273			/* Fall through and try a non cached read */
3274			error = 0;
3275 		} else {
3276			goto exit;
3277		}
3278    }
3279
3280	if (error)
3281		goto exit;
3282
3283	/*
3284	 * AFP COMMENTS (<rdar://problem/5977339>) Be careful of a cacheable write
3285	 * that extends the eof, but leaves a hole between the old eof and the new
3286	 * eof.  It that is followed by a non cacheable read that starts before the
3287	 * old eof and extends into the hole (or starts in the hole), but does not
3288	 * extend past the hole, then msync for the read range will not find any
3289	 * dirty pages in the hole and thus no data will be pushed and thus the eof
3290	 * will not get extended which will cause the non cacheable read to get
3291	 * erroneous data.  cluster_push works around this  because it pushes all of
3292	 * the pages in the delayed clusters. msync for the entire range also works
3293	 * too.
3294	 */
3295	if (VTOSMB(vp)->n_flag & NISMAPPED) {
3296		/* More expensive, but handles mmapped files */
3297		ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
3298	} else {
3299		/* Less expensive, but does not handle mmapped files */
3300		cluster_push(vp, IO_SYNC);
3301	}
3302
3303	/*
3304	 * AFP doesn't invalidate the range here. That seems wrong, we should
3305	 * invalidate the range here.
3306	 */
3307	ubc_msync (vp, uio_offset(uio), uio_offset(uio)+ uio_resid(uio), NULL,
3308			   UBC_INVALIDATE);
3309
3310	if (FindFileRef(vp, vfs_context_proc(ap->a_context), kAccessRead,
3311					kCheckDenyOrLocks, uio_offset(uio), uio_resid(uio),
3312					NULL, &fid)) {
3313		/* No matches or no pid to match, so just use the generic shared fork */
3314		fid = np->f_fid;	/* We should always have something at this point */
3315	}
3316	DBG_ASSERT(fid);
3317
3318	error = smbfs_doread(share, (off_t)np->n_size, uio, fid, ap->a_context);
3319    SMB_LOG_KTRACE(SMB_DBG_READ | DBG_FUNC_NONE, 0xabc002, error, 0, 0, 0);
3320
3321	/*
3322	 * We got an error, did it happen on a reconnect, then retry. First see if
3323	 * we have a new share to use, then attmept to reopent the file, then try
3324	 * the read again.
3325	 */
3326	while (error == EBADF) {
3327        lck_rw_lock_shared(&np->n_name_rwlock);
3328		SMB_LOG_IO("%s failed the non cache read, because of reconnect. Try again.\n",
3329				   np->n_name);
3330        lck_rw_unlock_shared(&np->n_name_rwlock);
3331
3332		/* Could be a dfs share make sure we have the correct share */
3333		smb_share_rele(share, ap->a_context);
3334		share = smb_get_share_with_reference(VTOSMBFS(vp));
3335		/* The reopen code will handle the case of the node being revoked. */
3336		if (smbfs_io_reopen(share, vp, uio, kAccessRead, &fid, error, ap->a_context) == 0) {
3337			error = smbfs_doread(share, (off_t)np->n_size, uio, fid,
3338                                 ap->a_context);
3339            SMB_LOG_KTRACE(SMB_DBG_READ | DBG_FUNC_NONE,
3340                           0xabc003, error, 0, 0, 0);
3341		}
3342        else {
3343            lck_rw_lock_shared(&np->n_name_rwlock);
3344			SMB_LOG_IO("%s : The Read reopen failed.\n", np->n_name);
3345            lck_rw_unlock_shared(&np->n_name_rwlock);
3346			break;
3347		}
3348	}
3349
3350	if (error) {
3351        lck_rw_lock_shared(&np->n_name_rwlock);
3352		SMB_LOG_IO("%s failed non cached read with an error of %d\n", np->n_name, error);
3353        lck_rw_unlock_shared(&np->n_name_rwlock);
3354	}
3355
3356exit:
3357	smb_share_rele(share, ap->a_context);
3358	smbnode_unlock(np);
3359
3360	SMB_LOG_KTRACE(SMB_DBG_READ | DBG_FUNC_END, error, 0, 0, 0, 0);
3361    return (error);
3362}
3363
3364/*
3365 * smbfs_vnop_write
3366 *
3367 *	vnode_t a_vp;
3368 *	uio_t a_uio;
3369 *	int a_ioflag;
3370 *	vfs_context_t a_context;
3371 */
3372static int
3373smbfs_vnop_write(struct vnop_write_args *ap)
3374{
3375	vnode_t vp = ap->a_vp;
3376	vnode_t parent_vp = NULL;	/* Always null unless this is a stream node */
3377	struct smbnode *np = NULL;
3378	struct smb_share *share;
3379	uio_t uio = ap->a_uio;
3380	int error = 0;
3381    SMBFID fid = 0;
3382	u_quad_t originalEOF;
3383	user_size_t writeCount;
3384
3385	/* Preflight checks */
3386	if (!vnode_isreg(vp)) {
3387		/* can only read regular files */
3388		if (vnode_isdir(vp))
3389			return (EISDIR);
3390		else
3391			return (EPERM);
3392	}
3393
3394	if (uio_offset(uio) < 0)
3395		return (EINVAL);
3396
3397	if (uio_resid(uio) == 0)
3398		return (0);
3399
3400	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
3401		return (error);
3402
3403    SMB_LOG_KTRACE(SMB_DBG_WRITE | DBG_FUNC_START,
3404                   uio_offset(uio),
3405                   uio_resid(uio), 0, 0, 0);
3406
3407	np = VTOSMB(vp);
3408	np->n_lastvop = smbfs_vnop_write;
3409	share = smb_get_share_with_reference(VTOSMBFS(vp));
3410
3411	/* Before trying the write see if the file needs to be reopened */
3412	error = smbfs_smb_reopen_file(share, np, ap->a_context);
3413	if (error) {
3414        lck_rw_lock_shared(&np->n_name_rwlock);
3415		SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
3416        lck_rw_unlock_shared(&np->n_name_rwlock);
3417		goto exit;
3418	}
3419
3420	if (ap->a_ioflag & IO_APPEND)
3421		uio_setoffset(uio, np->n_size);
3422
3423	originalEOF = np->n_size;	/* Save off the orignial end of file */
3424
3425    /*
3426	 * Note: smbfs_isCacheable checks to see if the file is globally non
3427	 * cacheable, but we also need to support non cacheable on a per file
3428	 * descriptor level for reads/writes. So also check the IO_NOCACHE flag.
3429	 *
3430	 * So IO_NOCACHE means the same thing as VNOCACHE_DATA but only for this IO.
3431	 * Now VNOCACHE_DATA has the following comment:
3432	 *		"don't keep data cached once it's been consumed"
3433	 * Which seems to imply we could use cluster_write, but we would need to
3434	 * push out any data and then invalidate the range after we are done
3435	 * with the write? Byte range locking prevents us from using the cluster_write.
3436	 */
3437	if (smbfsIsCacheable(vp) && !(ap->a_ioflag & IO_NOCACHE)) {
3438		u_quad_t writelimit;
3439        u_quad_t newEOF;
3440        u_quad_t zero_head_off;
3441        u_quad_t zero_tail_off;
3442        int32_t   lflag;
3443
3444		lflag = ap->a_ioflag & ~(IO_TAILZEROFILL | IO_HEADZEROFILL |
3445								 IO_NOZEROVALID | IO_NOZERODIRTY);
3446		zero_head_off = 0;
3447		zero_tail_off = 0;
3448		writelimit = uio_offset(uio) + uio_resid(uio);
3449
3450		/*
3451		 * They are writing pass the eof, force a zero fill. What should we
3452		 * do for sparse files?
3453		 */
3454        if ((uint64_t)writelimit > np->n_size) {
3455			/* Save off the new eof */
3456            newEOF = writelimit;
3457            if ((uint64_t) uio_offset(uio) > np->n_size) {
3458                zero_head_off = np->n_size;
3459				/* Make sure we tell the kernel to zero fill the head */
3460                lflag |= IO_HEADZEROFILL;
3461            }
3462  			zero_tail_off = (writelimit + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64;
3463			if (zero_tail_off > newEOF) {
3464				zero_tail_off = newEOF;
3465			}
3466			if (zero_tail_off > writelimit) {
3467				/* Make sure we tell the kernel to zero fill the tail */
3468				lflag |= IO_TAILZEROFILL;
3469			}
3470        } else
3471            newEOF = np->n_size;
3472
3473		lck_mtx_lock(&np->f_clusterWriteLock);
3474		if (originalEOF < newEOF) {
3475			np->waitOnClusterWrite = TRUE;
3476			np->n_size = newEOF;
3477            lck_rw_lock_shared(&np->n_name_rwlock);
3478			SMB_LOG_IO("%s: TURNING ON waitOnClusterWrite old eof = %lld new eof = %lld\n",
3479					   np->n_name, originalEOF, newEOF);
3480            lck_rw_unlock_shared(&np->n_name_rwlock);
3481		}
3482		lck_mtx_unlock(&np->f_clusterWriteLock);
3483		/*
3484         * If the write starts beyond the current EOF then we we'll zero fill
3485		 * from the current EOF to where the write begins
3486         */
3487        error = cluster_write(vp, uio, originalEOF, newEOF, zero_head_off, zero_tail_off, lflag);
3488        SMB_LOG_KTRACE(SMB_DBG_WRITE | DBG_FUNC_NONE,
3489                       0xabc001, error, 0, 0, 0);
3490		if (error) {
3491			lck_mtx_lock(&np->f_clusterWriteLock);
3492			np->n_size = originalEOF; /* Set it back to the original eof */
3493			np->waitOnClusterWrite = FALSE;
3494			lck_mtx_unlock(&np->f_clusterWriteLock);
3495
3496            lck_rw_lock_shared(&np->n_name_rwlock);
3497            SMB_LOG_IO("%s failed cluster_write with an error of %d\n", np->n_name, error);
3498            lck_rw_unlock_shared(&np->n_name_rwlock);
3499		}
3500		/*
3501		 * EACCES means a denyConflict occured and must have hit some other
3502		 * computer's byte range lock on that file. Mark the file as
3503		 * noncacheable and retry read again
3504		 *
3505		 * Need to check the error here, could be EIO/EPERM
3506		 *
3507		 * XXX - NOTE: The stragey routine is going to mark this vnode as needing
3508		 * to be revokd. So this code seems wrong. We should either correct
3509		 * the stragey routine or remove this code.
3510		 */
3511		if (error == EACCES) {
3512			if (np->n_flag & NISMAPPED) {
3513				/* More expensive, but handles mmapped files */
3514				ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
3515			} else {
3516				/* Less expensive, but does not handle mmapped files */
3517				cluster_push(vp, IO_SYNC);
3518			}
3519			ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_INVALIDATE);
3520			vnode_setnocache(vp);
3521			/* Fall through and try a non cached write */
3522			error = 0;
3523 		} else {
3524			goto exit;
3525		}
3526    }
3527
3528	if (error)
3529		goto exit;
3530    /*
3531	 * If it is not cacheable, make sure to wipe out UBC since any of its
3532	 * data would be no be invalid.  Make sure to push out any dirty data
3533	 * first due to prev cached write.
3534	 */
3535	ubc_msync(vp, uio_offset(uio), uio_offset(uio)+ uio_resid(uio), NULL,
3536			   UBC_PUSHDIRTY | UBC_SYNC);
3537	ubc_msync(vp, uio_offset(uio), uio_offset(uio)+ uio_resid(uio), NULL,
3538			   UBC_INVALIDATE);
3539
3540
3541	if (FindFileRef(vp, vfs_context_proc(ap->a_context), kAccessWrite,
3542					kCheckDenyOrLocks, uio_offset(uio), uio_resid(uio), NULL, &fid)) {
3543		/* No matches or no pid to match, so just use the generic shared fork */
3544		fid = np->f_fid;	/* We should always have something at this point */
3545	}
3546	DBG_ASSERT(fid);
3547
3548	/* Total amount that we need to write */
3549	writeCount = uio_resid(ap->a_uio);
3550	do {
3551		if (uio && (uio != ap->a_uio)) {
3552			/* We allocated, need to free it */
3553			uio_free(uio);
3554		}
3555		/*
3556		 * We could get disconnected in the middle of a write, so we need to make
3557		 * a copy of the uio, just in case.
3558		 */
3559		uio = uio_duplicate(ap->a_uio);
3560		if (uio == NULL) {
3561			/* Failed, so just used the passed in uio */
3562			uio = ap->a_uio;
3563		}
3564		error = smbfs_dowrite(share, (off_t)np->n_size, uio, fid, ap->a_ioflag,
3565							  ap->a_context);
3566        SMB_LOG_KTRACE(SMB_DBG_WRITE | DBG_FUNC_NONE,
3567                       0xabc002, error, 0, 0, 0);
3568        if (!error) {
3569            /* Save last time we wrote data */
3570            nanouptime(&np->n_last_write_time);
3571        }
3572
3573		if (error == EBADF) {
3574			/* Could be a dfs share make sure we have the correct share */
3575			smb_share_rele(share, ap->a_context);
3576			share = smb_get_share_with_reference(VTOSMBFS(vp));
3577			if (smbfs_io_reopen(share, vp, uio, kAccessWrite, &fid,  error,
3578								ap->a_context) != 0) {
3579				/* The reopen failed, just get out nothing left to do here */
3580				break;
3581			}
3582		}
3583	} while ((error == EBADF) && (uio != ap->a_uio));
3584	/* Set the original uio to match the one passed into the write. */
3585	if (uio != ap->a_uio) {
3586		/* Total amount we were able to write */
3587		writeCount -= uio_resid(uio);
3588		/* Update the user's uio with that amount */
3589		uio_update( ap->a_uio, writeCount);
3590		uio_free(uio);
3591		uio = ap->a_uio;
3592	}
3593
3594	/*
3595	 * Mark that we need to send a flush if we didn't get an error and
3596	 * we didn't send a write though message. Remember if the IO_SYNC bit
3597	 * is set then we set the write though bit, which should do the same
3598	 * thing as a flush.
3599	 */
3600	if (!error && !(ap->a_ioflag & IO_SYNC)) {
3601		VTOSMB(vp)->n_flag |= NNEEDS_FLUSH;
3602	} else if (error) {
3603        lck_rw_lock_shared(&np->n_name_rwlock);
3604		SMB_LOG_IO("%s failed non cached write with an error of %d\n",
3605				   np->n_name, error);
3606        lck_rw_unlock_shared(&np->n_name_rwlock);
3607	}
3608exit:
3609	/* Wrote pass the eof, need to set the new file size */
3610	if (!error && ((uint64_t) uio_offset(uio) > originalEOF)) {
3611		/*
3612		 * Windows servers do not handle writing past the end of file the
3613		 * same as Unix servers. If we do a directory lookup before the file
3614		 * is closed then the server may return the old size. Setting the end of
3615		 * file here will prevent that from happening. Unix servers do not seem
3616		 * to have this problem so there is no reason to make this call in that
3617		 * case. So if the file size has changed and this is not a Unix server
3618		 * then set the eof of file to the new value.
3619		 */
3620		if (!UNIX_SERVER(SSTOVC(share))) {
3621            /*
3622             * Just set the flag to set EOF later. Otherwise for every write
3623             * on a cached file, a set EOF request will be sent to the server.
3624             * This will result in hundreds/thousands of set EOF requests being
3625             * sent constantly to the server.
3626             *
3627             * The file size is cached locally so sending the set EOF request
3628             * to the server can wait until system sync or vnop_sync time.
3629             */
3630            np->n_flag |= NNEEDS_EOF_SET;
3631
3632            /*
3633             * Windows FAT file systems require a flush, after a seteof. Until the
3634             * the flush they will keep returning the old file size.
3635             */
3636            if (share->ss_fstype == SMB_FS_FAT) {
3637                /* Do the flush later too */
3638                np->n_flag |= NNEEDS_FLUSH;
3639
3640            }
3641		}
3642
3643		smbfs_setsize(vp, uio_offset(uio));
3644
3645        lck_rw_lock_shared(&np->n_name_rwlock);
3646		SMB_LOG_IO("%s: Calling smbfs_setsize, old eof = %lld  new eof = %lld time %ld:%ld\n",
3647				   np->n_name, originalEOF, uio_offset(uio),
3648				   np->n_sizetime.tv_sec, np->n_sizetime.tv_nsec);
3649        lck_rw_unlock_shared(&np->n_name_rwlock);
3650
3651		/*
3652		 * We could have lost a cache update in the write. Since we wrote pass
3653		 * the eof, mark that the close should clear the cache timer. This way
3654		 * the cache will be update with the server. We clear this flag in cache
3655		 * entry so any lookups after this write will clear the flag.
3656		 */
3657		np->n_flag |= NATTRCHANGED;
3658	}
3659
3660	/* Tell the stream's parent that something has changed */
3661	if (vnode_isnamedstream(vp))
3662		parent_vp = smb_update_rsrc_and_getparent(vp, FALSE);
3663
3664	smb_share_rele(share, ap->a_context);
3665	smbnode_unlock(VTOSMB(vp));
3666	/* We have the parent vnode, so reset its meta data cache timer. */
3667	if (parent_vp) {
3668		VTOSMB(parent_vp)->attribute_cache_timer = 0;
3669		vnode_put(parent_vp);
3670	}
3671
3672    SMB_LOG_KTRACE(SMB_DBG_WRITE | DBG_FUNC_END, error, 0, 0, 0, 0);
3673	return (error);
3674}
3675
3676/*
3677 * This is an internal utility function called from our smbfs_mkdir and
3678 * smbfs_create to set the vnode_attr passed into those routines. The first
3679 * problem comes from the vfs layer. It wants to set things that the server will
3680 * set for us. So to stop taking a performance hit turn off those items that vfs
3681 * turn on. See vnode_authattr_new for what is getting set. Second there is a set
3682 * of items that we can't set anyways so clear them out and pretend we did it.
3683 * Third if they are setting ACLs then make sure we keep any inherited ACLs.
3684 *
3685 * Question should we ever error out in this routine? The old code never did, but
3686 * what if setting the mode, owner, group, or acl fails?
3687 *
3688 * The calling routine must hold a reference on the share
3689 *
3690 */
3691static void
3692smbfs_set_create_vap(struct smb_share *share, struct vnode_attr *vap, vnode_t vp,
3693					 vfs_context_t context, int set_mode_now)
3694{
3695	struct smbnode *np = VTOSMB(vp);
3696	struct smbmount *smp = np->n_mount;
3697	struct vnode_attr svrva;
3698	kauth_acl_t savedacl = NULL;
3699	int error;
3700    int has_posix_modes = ((UNIX_CAPS(share) & UNIX_QFILEINFO_UNIX_INFO2_CAP)) ? TRUE : FALSE;;
3701
3702    if ((!has_posix_modes) &&
3703        (SSTOVC(share)->vc_server_caps & kAAPL_SUPPORTS_NFS_ACE)) {
3704        /*
3705         * For OS X <-> OS X PFS (where ACLs are off by default), we
3706         * need a way to set Posix permissions. If the server supports
3707         * the NFS ACE, then it will allow us to get the ACL and send
3708         * it back with the desired Posix permissions in the NFS ACE.
3709         */
3710        has_posix_modes = TRUE;
3711    }
3712
3713	/*
3714	 * Initialize here so we know if it needs to be freed at the end. Also
3715	 * ask for everything since its the same performance hit and updates our
3716	 * nodes uid/gid cache. The following are not used unless the user is
3717	 * setting ACLs.
3718	 */
3719	VATTR_INIT(&svrva);
3720	VATTR_WANTED(&svrva, va_acl);
3721	VATTR_WANTED(&svrva, va_uuuid);
3722	VATTR_WANTED(&svrva, va_guuid);
3723
3724	/*
3725	 * This will be zero if vnode_authattr_new set it. Do not change
3726	 * this on create, the default is fine.
3727	 */
3728	if (VATTR_IS_ACTIVE(vap, va_flags) && (vap->va_flags == 0)) {
3729		VATTR_SET_SUPPORTED(vap, va_flags);
3730		VATTR_CLEAR_ACTIVE(vap, va_flags);
3731	}
3732	/* The server will set all times for us */
3733	if (VATTR_IS_ACTIVE(vap, va_create_time)) {
3734		VATTR_SET_SUPPORTED(vap, va_create_time);
3735		VATTR_CLEAR_ACTIVE(vap, va_create_time);
3736	}
3737	if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
3738		VATTR_SET_SUPPORTED(vap, va_modify_time);
3739		VATTR_CLEAR_ACTIVE(vap, va_modify_time);
3740	}
3741	if (VATTR_IS_ACTIVE(vap, va_access_time)) {
3742		VATTR_CLEAR_ACTIVE(vap, va_access_time);
3743		VATTR_SET_SUPPORTED(vap, va_access_time);
3744	}
3745	if (VATTR_IS_ACTIVE(vap, va_change_time)) {
3746		VATTR_CLEAR_ACTIVE(vap, va_change_time);
3747		VATTR_SET_SUPPORTED(vap, va_change_time);
3748	}
3749
3750	if (VATTR_IS_ACTIVE(vap, va_mode)) {
3751		if (set_mode_now == TRUE) {
3752			/* compound_vnop_open already has the file open so we can set the
3753			 Posix file modes if server supports Posix perms and reg file */
3754			VATTR_SET_SUPPORTED(vap, va_mode);
3755
3756			if ( !vnode_isreg(vp) || !has_posix_modes ) {
3757				VATTR_CLEAR_ACTIVE(vap, va_mode);
3758			}
3759		}
3760        else {
3761			/*
3762			 * This routine gets called from create. If this is a regular file they
3763			 * could be setting the posix file modes to something that doesn't allow
3764			 * them to open the file with the permissions they requested.
3765			 *		Example: open(path, O_WRONLY | O_CREAT | O_EXCL,  0400)
3766			 * We only care about this if the server supports setting/getting posix
3767			 * permissions. So if they are setting the owner with read/write access
3768			 * then save the settings until after the open. We will just pretend to
3769			 * set them here. The following radar will make this a mute point.
3770			 *
3771			 * <rdar://problem/5199099> Need a new VNOP_OPEN call that allows the
3772			 * create/lookup/open/access in one call
3773			 */
3774			if (vnode_isreg(vp) && has_posix_modes &&
3775				((vap->va_mode & (S_IRUSR | S_IWUSR)) != (S_IRUSR | S_IWUSR))) {
3776				np->create_va_mode = vap->va_mode;
3777				np->set_create_va_mode = TRUE;
3778				/* The server should always give us read/write on create */
3779				VATTR_SET_SUPPORTED(vap, va_mode);
3780				VATTR_CLEAR_ACTIVE(vap, va_mode);
3781			} else if (!has_posix_modes) {
3782				/* We can only set these if the server supports the unix extensions */
3783				VATTR_SET_SUPPORTED(vap, va_mode);
3784				VATTR_CLEAR_ACTIVE(vap, va_mode);
3785			}
3786		}
3787	}
3788
3789	/*
3790	 * We have never supported setting the uid, this is supported by the
3791	 * UNIX extensions and for other servers we could convert it using
3792	 * uid --> UUID --> SID translation. This just seems like a waste of
3793	 * time since they would only be able to set it to themself if they
3794	 * are already the owner. So just say we did, this is what we have
3795	 * always done.
3796	 */
3797	if (VATTR_IS_ACTIVE(vap, va_uid)) {
3798		VATTR_SET_SUPPORTED(vap, va_uid);
3799		VATTR_CLEAR_ACTIVE(vap, va_uid);
3800	}
3801
3802	/*
3803	 * We have never supported setting the gid, this is supported by the
3804	 * UNIX extensions and for other servers we could convert it using
3805	 * gid --> GUID --> SID translation. We may want to add the support
3806	 * in the future, but we should require that they do this by setting
3807	 * the va_guuid.
3808	 */
3809	if (VATTR_IS_ACTIVE(vap, va_gid)) {
3810		VATTR_SET_SUPPORTED(vap, va_gid);
3811		VATTR_CLEAR_ACTIVE(vap, va_gid);
3812		if (vap->va_gid != smp->sm_args.gid)
3813			SMB_LOG_ACCESS("They want to set the gid to %d from %d\n",
3814						   vap->va_gid, smp->sm_args.gid);
3815	}
3816
3817	/*
3818	 * If they have an ACE that allows them to take ownership then
3819	 * this call will work. Should we test to see before going any
3820	 * future.
3821	 */
3822	if (VATTR_IS_ACTIVE(vap, va_uuuid)) {
3823		VATTR_SET_SUPPORTED(vap, va_uuuid);
3824		/* We never let them set it if a  TEMP UUID */
3825		if (is_memberd_tempuuid(&vap->va_uuuid))
3826			VATTR_CLEAR_ACTIVE(vap, va_uuuid);
3827	}
3828
3829	/*
3830	 * If they have an ACE that allows them to make this change then
3831	 * this call will work. Should we test to see before going any
3832	 * future.
3833	 */
3834	if (VATTR_IS_ACTIVE(vap, va_guuid)) {
3835		VATTR_SET_SUPPORTED(vap, va_guuid);
3836		/* We never let them set it if a  TEMP UUID */
3837		if (is_memberd_tempuuid(&vap->va_guuid))
3838			VATTR_CLEAR_ACTIVE(vap, va_guuid);
3839	}
3840
3841	/*
3842	 * Make sure the VFS layer doesn't fall back to using EA, always say we set
3843	 * the ACL.
3844	 */
3845	if (VATTR_IS_ACTIVE(vap, va_acl)) {
3846		VATTR_SET_SUPPORTED(vap, va_acl);
3847		/* Nothing for us to do here */
3848		if ((vap->va_acl == NULL) || (vap->va_acl->acl_entrycount == 0))
3849			VATTR_CLEAR_ACTIVE(vap, va_acl);
3850	}
3851
3852	/* All we have left to do is call our setattr */
3853	if (!VATTR_IS_ACTIVE(vap, va_acl))
3854		goto do_setattr;
3855
3856	/* Get the inherited ACLs from the server */
3857	error = smbfs_getattr(share, vp, &svrva, context);
3858	if (error) {
3859		SMBWARNING("Error %d returned while gettting the inherit ACLs from the server\n",
3860				   error);
3861		goto out;
3862	}
3863
3864	/*
3865	 * if none created then just slam in the requested ACEs
3866	 */
3867	if (!VATTR_IS_SUPPORTED(&svrva, va_acl) || svrva.va_acl == NULL ||
3868	    svrva.va_acl->acl_entrycount == 0) {
3869		goto do_setattr;
3870	}
3871	error = smbfs_compose_create_acl(vap, &svrva, &savedacl);
3872	if (error)
3873		goto out;
3874
3875do_setattr:
3876	error = smbfs_setattr(share, vp, vap, context);
3877	if (error)
3878		SMBERROR("smbfs_setattr, error %d\n", error);
3879	if (savedacl) {
3880		kauth_acl_free(vap->va_acl);
3881		vap->va_acl = savedacl;
3882	}
3883out:
3884	if (VATTR_IS_SUPPORTED(&svrva, va_acl) && svrva.va_acl != NULL)
3885		kauth_acl_free(svrva.va_acl);
3886	return;
3887}
3888
3889/*
3890 * Create a regular file or a "symlink". In the symlink case we will have a target. Depending
3891 * on the sytle of symlink the target may be just what we set or we may need to encode it into
3892 * that wacky windows data
3893 *
3894 * The calling routine must hold a reference on the share
3895 *
3896 */
3897static int
3898smbfs_create(struct smb_share *share, struct vnop_create_args *ap, char *target,
3899			 size_t targetlen)
3900{
3901	vnode_t				dvp = ap->a_dvp;
3902	struct vnode_attr *vap = ap->a_vap;
3903	vnode_t			*vpp = ap->a_vpp;
3904	struct componentname *cnp = ap->a_cnp;
3905	struct smbnode *dnp = VTOSMB(dvp);
3906	struct smbmount *smp = VTOSMBFS(dvp);
3907	vnode_t 	vp;
3908	struct smbfattr fattr;
3909	const char *name = cnp->cn_nameptr;
3910	size_t nmlen = cnp->cn_namelen;
3911	int error;
3912	struct timespec ts;
3913	int unix_symlink = ((UNIX_CAPS(share) & UNIX_SFILEINFO_UNIX_LINK_CAP)) ? TRUE : FALSE;
3914
3915	*vpp = NULL;
3916	if (vap->va_type != VREG && vap->va_type != VLNK)
3917		return (ENOTSUP);
3918
3919    SMB_LOG_KTRACE(SMB_DBG_SMBFS_CREATE | DBG_FUNC_START,
3920                   vap->va_type, 0, 0, 0, 0);
3921
3922	if (vap->va_type == VLNK) {
3923        if (smp->sm_flags & MNT_SUPPORTS_REPARSE_SYMLINKS) {
3924			error = smbfs_smb_create_reparse_symlink(share, dnp, name, nmlen, target,
3925                                                     targetlen, &fattr, ap->a_context);
3926		} else if (unix_symlink) {
3927			error = smbfs_smb_create_unix_symlink(share, dnp, name, nmlen, target,
3928												  targetlen, &fattr, ap->a_context);
3929		} else {
3930			error = smbfs_smb_create_windows_symlink(share, dnp, name, nmlen, target,
3931												  targetlen, &fattr, ap->a_context);
3932		}
3933	} else {
3934		/* Now create the file, sending a null fid pointer will cause it to be closed */
3935		error = smbfs_smb_create(share, dnp, name, nmlen, SMB2_FILE_WRITE_DATA,
3936								 NULL, FILE_CREATE, 0, &fattr, ap->a_context);
3937	}
3938
3939    SMB_LOG_KTRACE(SMB_DBG_SMBFS_CREATE | DBG_FUNC_NONE,
3940                   0xabc001, error, 0, 0, 0);
3941
3942    if (error) {
3943		if (error == ENOENT) {
3944			SMBDEBUG("Creating %s returned ENOENT, resetting to EACCES\n", name);
3945			/*
3946			 * Some servers (Samba) support an option called veto. This prevents
3947			 * clients from creating or access these files. The server returns
3948			 * an ENOENT error in these cases. The VFS layer will loop forever
3949			 * if a ENOENT error is returned on create, so we convert this error
3950			 * to EACCES.
3951			 */
3952			error = EACCES;
3953		}
3954		return (error);
3955	}
3956	smbfs_attr_touchdir(dnp, (share->ss_fstype == SMB_FS_FAT));
3957
3958	/*
3959	 * We have smbfs_nget returning a lock so we need to unlock it when we
3960	 * are done with it. Would really like to clean this code up in the future.
3961	 * The whole create, mkdir and smblink create code should use the same code path.
3962	 */
3963	fattr.fa_vtype = vap->va_type;
3964	error = smbfs_nget(share, vnode_mount(dvp),
3965                       dvp, name, nmlen,
3966                       &fattr, &vp,
3967                       cnp->cn_flags, SMBFS_NGET_CREATE_VNODE,
3968                       ap->a_context);
3969	if (error) {
3970		/* Error, try to cleanup anything we created on the server */
3971		smbfs_smb_delete(share, dnp, VREG,
3972                         name, nmlen,
3973                         0, ap->a_context);
3974		goto bad;
3975	}
3976
3977	/*
3978	 * We just created the file, so we have no finder info and the resource fork
3979	 * should be empty. So set our cache timers to reflect this information
3980	 */
3981	nanouptime(&ts);
3982	VTOSMB(vp)->finfo_cache_timer = ts.tv_sec;
3983	VTOSMB(vp)->rfrk_cache_timer = ts.tv_sec;
3984
3985	smbfs_set_create_vap(share, vap, vp, ap->a_context, FALSE);
3986
3987	if (vap->va_type == VLNK) {
3988		smbfs_update_symlink_cache(VTOSMB(vp), target, targetlen);
3989		VTOSMB(vp)->n_size = targetlen;	/* Set it to the correct size */
3990		if (!unix_symlink)	/* Mark it as a Windows symlink */
3991			VTOSMB(vp)->n_flag |= NWINDOWSYMLNK;
3992	}
3993	*vpp = vp;
3994	smbnode_unlock(VTOSMB(vp));	/* Done with the smbnode unlock it. */
3995
3996    dnp->d_changecnt++;
3997
3998	/* Remove any negative cache entries. */
3999	if (dnp->n_flag & NNEGNCENTRIES) {
4000		dnp->n_flag &= ~NNEGNCENTRIES;
4001		cache_purge_negatives(dvp);
4002	}
4003
4004bad:
4005	/* if success, blow away statfs cache */
4006	if (!error)
4007		smp->sm_statfstime = 0;
4008
4009    SMB_LOG_KTRACE(SMB_DBG_SMBFS_CREATE | DBG_FUNC_END, error, 0, 0, 0, 0);
4010    return (error);
4011}
4012
4013/*
4014 * smbfs_vnop_create
4015 *
4016 * vnode_t a_dvp;
4017 * vnode_t *a_vpp;
4018 * struct componentname *a_cnp;
4019 * struct vnode_attr *a_vap;
4020 * vfs_context_t a_context;
4021 */
4022static int
4023smbfs_vnop_create(struct vnop_create_args *ap)
4024{
4025	vnode_t 	dvp = ap->a_dvp;
4026	int			error;
4027	struct smbnode *dnp;
4028	struct smb_share *share;
4029
4030    /* Make sure we lock the parent before calling smbfs_create */
4031    if ((error = smbnode_lock(VTOSMB(dvp), SMBFS_EXCLUSIVE_LOCK)))
4032        return (error);
4033
4034    SMB_LOG_KTRACE(SMB_DBG_CREATE | DBG_FUNC_START, 0, 0, 0, 0, 0);
4035
4036    dnp = VTOSMB(dvp);
4037    dnp->n_lastvop = smbfs_vnop_create;
4038    share = smb_get_share_with_reference(VTOSMBFS(dvp));
4039
4040    error = smbfs_create(share, ap, NULL, 0);
4041
4042    smb_share_rele(share, ap->a_context);
4043    smbnode_unlock(dnp);
4044
4045    SMB_LOG_KTRACE(SMB_DBG_CREATE | DBG_FUNC_END, error, 0, 0, 0, 0);
4046    return (error);
4047}
4048
4049/*
4050 * The calling routine must hold a reference on the share
4051 */
4052static int
4053smbfs_remove(struct smb_share *share, vnode_t dvp, vnode_t vp,
4054			 struct componentname *cnp, int flags, vfs_context_t context)
4055{
4056#pragma unused(cnp)
4057	struct smbnode *dnp = VTOSMB(dvp);
4058	proc_t p = vfs_context_proc(context);
4059	struct smbnode *np = VTOSMB(vp);
4060	struct smbmount *smp = VTOSMBFS(vp);
4061	int error;
4062    uint64_t hashval = 0;
4063
4064    SMB_LOG_KTRACE(SMB_DBG_SMBFS_REMOVE | DBG_FUNC_START, 0, 0, 0, 0, 0);
4065
4066	DBG_ASSERT((!vnode_isnamedstream(vp)))
4067	cache_purge(vp);
4068
4069	/*
4070	 * Carbon semantics prohibit deleting busy files.
4071	 * (enforced when NODELETEBUSY is requested) We just return
4072	 * EBUSY here. Do not print an error to system log in this
4073	 * case.
4074	 *
4075	 * NOTE: Kqueue opens will not be found by vnode_isinuse
4076	 */
4077	if (flags & VNODE_REMOVE_NODELETEBUSY) {
4078        if (vnode_isinuse(vp, 0)) {
4079            error = EBUSY; /* Do not print an error in this case */
4080            goto done;
4081        } else {
4082            /* Check if any streams associated with this vnode are opened */
4083            vnode_t svpp = smbfs_find_vgetstrm(smp, np, SFM_RESOURCEFORK_NAME,
4084                                               share->ss_maxfilenamelen);
4085            if (svpp) {
4086                if (vnode_isinuse(svpp, 0)) {
4087                    /*
4088                     *  This vnode has an opened stream associated with it,
4089                     *  we still need to return EBUSY here.
4090                     *  See <rdar://problem/9904683>
4091                     */
4092                    smbnode_unlock(VTOSMB(svpp));
4093                    vnode_put(svpp);
4094                    SMBDEBUG("%s: Cannot delete %s, resource fork in use\n", __FUNCTION__, vnode_getname(vp));
4095                    error = EBUSY; /* Do not print an error in this case */
4096                    goto done;
4097                } else {
4098                    smbnode_unlock(VTOSMB(svpp));
4099                    vnode_put(svpp);
4100                }
4101            }
4102        }
4103    }
4104
4105	/*
4106	 * Did we open this in our read routine. Then we should close it.
4107	 */
4108	if ((np->f_refcnt == 1) && np->f_needClose) {
4109		error = smbfs_close(share, vp, FREAD, context);
4110		if (error) {
4111            lck_rw_lock_shared(&np->n_name_rwlock);
4112			SMBWARNING("error %d closing %s\n", error, np->n_name);
4113            lck_rw_unlock_shared(&np->n_name_rwlock);
4114        }
4115	}
4116
4117    /*
4118     * The old code would check vnode_isinuse to see if the file was open,
4119     * but if the file was open by Kqueue then vnode_isinuse will not find it.
4120     * So at this point if the file is open then do the silly rename delete
4121     * trick if the server supports it.
4122     */
4123    if (np->f_refcnt) {
4124        error = smbfs_delete_openfile(share, dnp, np, context);
4125        SMB_LOG_KTRACE(SMB_DBG_SMBFS_REMOVE | DBG_FUNC_NONE,
4126                       0xabc001, error, 0, 0, 0);
4127        if (!error) {
4128            /* skip doing the vnode_recycle as file may still be on server */
4129            error = 0;
4130            goto done;
4131        }
4132
4133        goto out;
4134    }
4135
4136    /*
4137     * NetApp and Samba servers will reuse the File ID immediately after a
4138     * delete, so remove the smb node from the hash table before doing the
4139     * delete. If the delete fails, then we know the File ID is still valid
4140     * and it should be ok to reinsert the smbnode.
4141     */
4142    smb_vhashrem(np);
4143
4144	error = smbfs_smb_delete(share, np, VREG,
4145                             NULL, 0,
4146                             0, context);
4147    SMB_LOG_KTRACE(SMB_DBG_SMBFS_REMOVE | DBG_FUNC_NONE,
4148                   0xabc002, error, 0, 0, 0);
4149	if (error) {
4150        /*
4151         * Delete failed, add smbnode back into hash table.
4152         * Then leave as there is nothing else we can do at this point
4153         */
4154        lck_rw_lock_shared(&np->n_name_rwlock);
4155        hashval = smbfs_hash(share, np->n_ino, np->n_name, np->n_nmlen);
4156        lck_rw_unlock_shared(&np->n_name_rwlock);
4157
4158        smb_vhashadd(np, hashval);
4159
4160        goto out;
4161    }
4162
4163    smbfs_attr_touchdir(dnp, (share->ss_fstype == SMB_FS_FAT));
4164    dnp->d_changecnt++;
4165
4166	/* Remove any negative cache entries. */
4167	if (dnp->n_flag & NNEGNCENTRIES) {
4168		dnp->n_flag &= ~NNEGNCENTRIES;
4169		cache_purge_negatives(dvp);
4170	}
4171
4172out:
4173	if (error == EBUSY) {
4174		char errbuf[32];
4175
4176		(void)proc_name(proc_pid(p), &errbuf[0], 32);
4177
4178        lck_rw_lock_shared(&np->n_name_rwlock);
4179        SMBWARNING("warning: pid %d(%.*s) unlink open file(%s)\n", proc_pid(p),
4180				   32, &errbuf[0], np->n_name);
4181        lck_rw_unlock_shared(&np->n_name_rwlock);
4182	}
4183
4184	if (!error) {
4185		/* Not sure why we do this here. Leave it for now. */
4186		(void) vnode_recycle(vp);
4187		/* if success, blow away statfs cache */
4188		smp->sm_statfstime = 0;
4189	}
4190
4191done:
4192    SMB_LOG_KTRACE(SMB_DBG_SMBFS_REMOVE | DBG_FUNC_END, error, 0, 0, 0, 0);
4193	return (error);
4194}
4195
4196/*
4197 * smbfs_vnop_remove
4198 *
4199 * vnode_t a_dvp;
4200 * vnode_t a_vp;
4201 * struct componentname *a_cnp;
4202 * int a_flags;
4203 * vfs_context_t a_context;
4204 */
4205static int
4206smbfs_vnop_remove(struct vnop_remove_args *ap)
4207{
4208	vnode_t dvp = ap->a_dvp;
4209	vnode_t vp = ap->a_vp;
4210	int32_t error;
4211	struct smb_share *share;
4212
4213	if (dvp == vp)
4214		return (EINVAL);
4215
4216	/* Always put in the order of parent then child */
4217	if ((error = smbnode_lockpair(VTOSMB(dvp), VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
4218		return (error);
4219
4220    SMB_LOG_KTRACE(SMB_DBG_REMOVE | DBG_FUNC_START, 0, 0, 0, 0, 0);
4221
4222	VTOSMB(dvp)->n_lastvop = smbfs_vnop_remove;
4223	VTOSMB(vp)->n_lastvop = smbfs_vnop_remove;
4224	share = smb_get_share_with_reference(VTOSMBFS(dvp));
4225	error = smbfs_remove(share, dvp, vp, ap->a_cnp, ap->a_flags, ap->a_context);
4226	smb_share_rele(share, ap->a_context);
4227	smbnode_unlockpair(VTOSMB(dvp), VTOSMB(vp));
4228
4229	SMB_LOG_KTRACE(SMB_DBG_REMOVE | DBG_FUNC_END, error, 0, 0, 0, 0);
4230    return (error);
4231}
4232
4233/*
4234 * smbfs remove directory call
4235 *
4236 * The calling routine must hold a reference on the share
4237 *
4238 */
4239static int
4240smbfs_rmdir(struct smb_share *share, vnode_t dvp, vnode_t vp,
4241			struct componentname *cnp, vfs_context_t context)
4242{
4243#pragma unused(cnp)
4244	struct smbmount *smp = VTOSMBFS(vp);
4245	struct smbnode *dnp = VTOSMB(dvp);
4246	struct smbnode *np = VTOSMB(vp);
4247	int error;
4248    SMBFID fid = 0;
4249    uint64_t hashval = 0;
4250
4251	/* XXX other OSX fs test fs nodes here, not vnodes. Why? */
4252	if (dvp == vp) {
4253		error = EINVAL;
4254		goto bad;
4255	}
4256
4257    /* Close Query Dir Create FID if we need to */
4258    if ((np->d_fctx != NULL) && (np->d_fctx->f_need_close == TRUE)) {
4259        error = smb2_smb_close_fid(np->d_fctx->f_share,
4260                                   np->d_fctx->f_create_fid,
4261                                   NULL, NULL, context);
4262        if (error) {
4263            SMBDEBUG("smb2_smb_close_fid failed %d\n", error);
4264        }
4265        np->d_fctx->f_need_close = FALSE;
4266    }
4267
4268	/*
4269	 * We may still have a change notify on this node, close it so
4270	 * the item will get deleted on the server. Mark it not to be
4271	 * reopened first, then save off the fid, clear the node fid
4272	 * now close the file descriptor.
4273	 */
4274	np->d_needReopen = FALSE;
4275	fid = np->d_fid;
4276	np->d_fid = 0;
4277	if (fid != 0) {
4278		(void)smbfs_tmpclose(share, np, fid, context);
4279	}
4280
4281    cache_purge(vp);
4282
4283    /*
4284     * NetApp and Samba servers will reuse the File ID immediately after a
4285     * delete, so remove the smb node from the hash table before doing the
4286     * delete. If the delete fails, then we know the File ID is still valid
4287     * and it should be ok to reinsert the smbnode.
4288     */
4289    smb_vhashrem(np);
4290
4291	error = smbfs_smb_rmdir(share, np, context);
4292	if (error) {
4293        /*
4294         * Delete failed, add smbnode back into hash table.
4295         * Then leave as there is nothing else we can do at this point
4296         */
4297        lck_rw_lock_shared(&np->n_name_rwlock);
4298        hashval = smbfs_hash(share, np->n_ino, np->n_name, np->n_nmlen);
4299        lck_rw_unlock_shared(&np->n_name_rwlock);
4300
4301        smb_vhashadd(np, hashval);
4302	    goto bad;
4303    }
4304
4305	smbfs_attr_touchdir(dnp, (share->ss_fstype == SMB_FS_FAT));
4306    dnp->d_changecnt++;
4307
4308	/* Remove any negative cache entries. */
4309	if (dnp->n_flag & NNEGNCENTRIES) {
4310		dnp->n_flag &= ~NNEGNCENTRIES;
4311		cache_purge_negatives(dvp);
4312	}
4313
4314bad:
4315	/* if success, blow away statfs cache */
4316	if (!error) {
4317		smp->sm_statfstime = 0;
4318		(void) vnode_recycle(vp);
4319	}
4320	return (error);
4321}
4322
4323/*
4324 * smbfs_vnop_rmdir
4325 *
4326 * vnode_t a_dvp;
4327 * vnode_t a_vp;
4328 * struct componentname *a_cnp;
4329 * vfs_context_t a_context;
4330 */
4331static int smbfs_vnop_rmdir(struct vnop_rmdir_args *ap)
4332{
4333	vnode_t dvp = ap->a_dvp;
4334	vnode_t vp = ap->a_vp;
4335	int32_t error;
4336	struct smb_share *share;
4337
4338	if (!vnode_isdir(vp))
4339		return (ENOTDIR);
4340
4341	if (dvp == vp)
4342		return (EINVAL);
4343
4344	/* Always put in the order of parent then child */
4345	if ((error = smbnode_lockpair(VTOSMB(dvp), VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
4346		return (error);
4347
4348    SMB_LOG_KTRACE(SMB_DBG_RM_DIR | DBG_FUNC_START, 0, 0, 0, 0, 0);
4349
4350	VTOSMB(dvp)->n_lastvop = smbfs_vnop_rmdir;
4351	VTOSMB(vp)->n_lastvop = smbfs_vnop_rmdir;
4352	share = smb_get_share_with_reference(VTOSMBFS(dvp));
4353	error = smbfs_rmdir(share, dvp, vp, ap->a_cnp, ap->a_context);
4354	smb_share_rele(share, ap->a_context);
4355	smbnode_unlockpair(VTOSMB(dvp), VTOSMB(vp));
4356
4357    SMB_LOG_KTRACE(SMB_DBG_RM_DIR | DBG_FUNC_END, error, 0, 0, 0, 0);
4358	return (error);
4359}
4360
4361/*
4362 * smbfs_vnop_rename
4363 *
4364 * vnode_t a_fdvp;
4365 * vnode_t a_fvp;
4366 * struct componentname *a_fcnp;
4367 * vnode_t a_tdvp;
4368 * vnode_t a_tvp;
4369 * struct componentname *a_tcnp;
4370 * vfs_context_t a_context;
4371 */
4372static int
4373smbfs_vnop_rename(struct vnop_rename_args *ap)
4374{
4375	vnode_t 	fvp = ap->a_fvp;
4376	vnode_t 	tvp = ap->a_tvp;
4377	vnode_t 	fdvp = ap->a_fdvp;
4378	vnode_t 	tdvp = ap->a_tdvp;
4379	struct smbmount *smp = VFSTOSMBFS(vnode_mount(fvp));
4380	struct smb_share *share = NULL;
4381	struct componentname *tcnp = ap->a_tcnp;
4382	struct componentname *fcnp = ap->a_fcnp;
4383	proc_t p = vfs_context_proc(ap->a_context);
4384	int error = 0;
4385	struct smbnode *fnp = NULL;
4386	struct smbnode *tdnp = NULL;
4387	struct smbnode *fdnp = NULL;
4388	int vtype;
4389	struct smbnode * lock_order[4] = {NULL};
4390	int	lock_cnt = 0;
4391	int ii;
4392
4393	/* Check for cross-device rename */
4394	if ((vnode_mount(fvp) != vnode_mount(tdvp)) ||
4395		(tvp && (vnode_mount(fvp) != vnode_mount(tvp))))
4396		return (EXDEV);
4397
4398	vtype = vnode_vtype(fvp);
4399	if ( (vtype != VDIR) && (vtype != VREG) && (vtype != VLNK) )
4400		return (EINVAL);
4401
4402    SMB_LOG_KTRACE(SMB_DBG_RENAME | DBG_FUNC_START, 0, 0, 0, 0, 0);
4403
4404	/*
4405	 * First lets deal with the parents. If they are the same only lock the from
4406	 * vnode, otherwise see if one is the parent of the other. We always want
4407	 * to lock in parent child order if we can. If they are not the parent of
4408	 * each other then lock in address order.
4409	 */
4410
4411    if (fdvp != tdvp) {
4412        lck_rw_lock_shared(&VTOSMB(fdvp)->n_parent_rwlock);
4413        lck_rw_lock_shared(&VTOSMB(tdvp)->n_parent_rwlock);
4414    }
4415
4416	if (fdvp == tdvp)
4417		lock_order[lock_cnt++] = VTOSMB(fdvp);
4418	else if (VTOSMB(fdvp)->n_parent && (VTOSMB(fdvp)->n_parent == VTOSMB(tdvp))) {
4419		lock_order[lock_cnt++] = VTOSMB(tdvp);
4420		lock_order[lock_cnt++] = VTOSMB(fdvp);
4421	} else if (VTOSMB(tdvp)->n_parent && (VTOSMB(tdvp)->n_parent == VTOSMB(fdvp))) {
4422		lock_order[lock_cnt++] = VTOSMB(fdvp);
4423		lock_order[lock_cnt++] = VTOSMB(tdvp);
4424	} else if (VTOSMB(fdvp) < VTOSMB(tdvp)) {
4425		lock_order[lock_cnt++] = VTOSMB(fdvp);
4426		lock_order[lock_cnt++] = VTOSMB(tdvp);
4427	} else {
4428		lock_order[lock_cnt++] = VTOSMB(tdvp);
4429		lock_order[lock_cnt++] = VTOSMB(fdvp);
4430	}
4431
4432	/*
4433	 * Now lets deal with the children. If any of the following is true then just
4434	 * lock the from vnode:
4435	 *		1. The to vnode doesn't exist
4436	 *		2. The to vnode and from vnodes are the same
4437	 *		3. The to vnode and the from parent vnodes are the same, I know
4438	 *		   it's strange but can happen.
4439	 * Otherwise, lock in address order
4440	 */
4441	if ((tvp == NULL) || (tvp == fvp) || (tvp == fdvp))
4442		lock_order[lock_cnt++] = VTOSMB(fvp);
4443	else {
4444		if (VTOSMB(fvp) < VTOSMB(tvp)) {
4445			lock_order[lock_cnt++] = VTOSMB(fvp);
4446			lock_order[lock_cnt++] = VTOSMB(tvp);
4447		} else {
4448			lock_order[lock_cnt++] = VTOSMB(tvp);
4449			lock_order[lock_cnt++] = VTOSMB(fvp);
4450		}
4451	}
4452	/* Make sure there are no duplicates, this would be a design flaw */
4453	DBG_LOCKLIST_ASSERT(lock_cnt, lock_order);
4454
4455    if (fdvp != tdvp) {
4456        lck_rw_unlock_shared(&VTOSMB(tdvp)->n_parent_rwlock);
4457        lck_rw_unlock_shared(&VTOSMB(fdvp)->n_parent_rwlock);
4458    }
4459
4460	for (ii = 0; ii < lock_cnt; ii++) {
4461		if (error)
4462			lock_order[ii] = NULL;
4463		else if ((error = smbnode_lock(lock_order[ii], SMBFS_EXCLUSIVE_LOCK)))
4464			lock_order[ii] = NULL;
4465	}
4466	if (error)
4467		goto out;
4468
4469    /*
4470     * Make sure that we do not proceed if we get lock after parent is
4471     * reclaimed after forced unmount.
4472     */
4473    if (vfs_isforce(smp->sm_mp)) {
4474        error = ENXIO;
4475        goto out;
4476    }
4477
4478	fdnp = VTOSMB(fdvp);
4479	fnp = VTOSMB(fvp);
4480	tdnp = VTOSMB(tdvp);
4481
4482	fdnp->n_lastvop = smbfs_vnop_rename;
4483	fnp->n_lastvop = smbfs_vnop_rename;
4484	tdnp->n_lastvop = smbfs_vnop_rename;
4485	if (tvp != NULL)
4486		VTOSMB(tvp)->n_lastvop = smbfs_vnop_rename;
4487
4488    lck_rw_lock_shared(&fnp->n_parent_rwlock);
4489    if (fnp->n_parent != VTOSMB(fdvp)) {
4490        /*
4491         * We lost the race with another thread that just
4492         * changed the parent of fvp, so fdvp is stale and
4493         * we punt. See <rdar://problem/15313516>
4494         */
4495        lck_rw_unlock_shared(&fnp->n_parent_rwlock);
4496        error = ENOENT;
4497		goto out;
4498    }
4499    lck_rw_unlock_shared(&fnp->n_parent_rwlock);
4500
4501	share = smb_get_share_with_reference(smp);
4502	/*
4503	 * Check to see if the SMB_EFA_RDONLY/IMMUTABLE are set. If they are set
4504	 * then do not allow the rename. See HFS and AFP code.
4505	 */
4506	if (node_isimmutable(share, fvp, NULL)) {
4507        lck_rw_lock_shared(&fnp->n_name_rwlock);
4508		SMBWARNING( "%s is a locked file : Permissions error on delete\n",
4509				   fnp->n_name);
4510        lck_rw_unlock_shared(&fnp->n_name_rwlock);
4511		error = EPERM;
4512		goto out;
4513	}
4514
4515	/*
4516	 * Since there are no hard links (from our client point of view)
4517	 * fvp==tvp means the arguments are case-variants.  (If they
4518	 * were identical the rename syscall doesnt call us.)
4519	 */
4520	if (fvp == tvp)
4521		tvp = NULL;
4522
4523	/*
4524	 * The problem we have here is some servers will not return the correct
4525	 * case of the file name in the lookup. This can cause to have two vnodes
4526	 * that point to the same item. Very bad but nothing we can do about that
4527	 * in smb. So if the target exist, the parents are the same and the name is
4528	 * the same except for case, then don't delete the target.
4529	 */
4530    if (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS) {
4531        /* Server supports File IDs */
4532        if (tvp && (fdvp == tdvp) && (fnp->n_ino == VTOSMB(tvp)->n_ino)) {
4533            lck_rw_lock_shared(&fnp->n_name_rwlock);
4534            SMBWARNING("Not removing target, same file. %s \n",
4535                       fnp->n_name);
4536            lck_rw_unlock_shared(&fnp->n_name_rwlock);
4537
4538            smb_vhashrem(VTOSMB(tvp)); /* Remove it from our hash so it can't be found */
4539            (void) vnode_recycle(tvp);
4540            tvp = NULL;
4541        }
4542    }
4543    else {
4544        /* Server does not support File IDs */
4545        lck_rw_lock_shared(&fnp->n_name_rwlock);
4546
4547        if (tvp) {
4548            lck_rw_lock_shared(&VTOSMB(tvp)->n_name_rwlock);
4549        }
4550
4551        if (tvp && (fdvp == tdvp) && (fnp->n_nmlen == VTOSMB(tvp)->n_nmlen) &&
4552                    (strncasecmp((char *)fnp->n_name, (char *)VTOSMB(tvp)->n_name,
4553                                 fnp->n_nmlen) == 0)) {
4554            SMBWARNING("Not removing target, same file. %s ==> %s\n",
4555                       fnp->n_name, VTOSMB(tvp)->n_name);
4556            lck_rw_unlock_shared(&VTOSMB(tvp)->n_name_rwlock);
4557
4558            smb_vhashrem(VTOSMB(tvp)); /* Remove it from our hash so it can't be found */
4559            (void) vnode_recycle(tvp);
4560            tvp = NULL;
4561        }
4562
4563        if (tvp) {
4564            /* tvp might have been unlocked and null'd out above */
4565            lck_rw_unlock_shared(&VTOSMB(tvp)->n_name_rwlock);
4566        }
4567
4568        lck_rw_unlock_shared(&fnp->n_name_rwlock);
4569    }
4570
4571	/*
4572	 * If we are not doing Named Streams, they gave us a target to delete, and
4573	 * the source is a dot underscore file then make sure the source exist before
4574	 * deleting the target.
4575	 *
4576	 * This problem happens when going Mac to Mac and the share is FAT or some
4577	 * share that doesn't support streams. The remote VNOP_RENAME will rename
4578	 * the dot underscore file underneath the client. So when the cleint tries
4579	 * to rename the dot underscore it thinkis the target exist and needs to be
4580	 * deleted. So never delete the target if the source doesn't exist.
4581	 */
4582    lck_rw_lock_shared(&fnp->n_name_rwlock);
4583	if ((tvp) && (!(share->ss_attributes & FILE_NAMED_STREAMS)) &&
4584		(fnp->n_nmlen > 2) && (fnp->n_name[0] == '.') && (fnp->n_name[1] == '_')) {
4585		const char *name = (const char *)fnp->n_name;
4586		size_t nmlen = fnp->n_nmlen;
4587		struct smbfattr fattr;
4588
4589		error = smbfs_lookup(share, fdnp, &name, &nmlen, &fattr, ap->a_context);
4590		/* Should we check for any error or just ENOENT */
4591		if (error == ENOENT)
4592			tvp = NULL;
4593		/* smbfs_lookup could have replace the name, free it if did */
4594		if (name != (char *)fnp->n_name) {
4595			SMB_FREE(name, M_SMBNODENAME);
4596		}
4597	}
4598    lck_rw_unlock_shared(&fnp->n_name_rwlock);
4599
4600	/*
4601	 * If the destination exists then it needs to be removed.
4602	 */
4603	if (tvp) {
4604		if (vnode_isdir(tvp)) {
4605			/*
4606			 * From the man 2 rename
4607			 *
4608			 * CONFORMANCE
4609			 * The restriction on renaming a directory whose permissions disallow
4610			 * writing is based on the fact that UFS directories contain a ".."
4611			 * entry.  If renaming a directory would move it to another parent
4612			 * directory, this entry needs to be changed.
4613			 *
4614			 * This restriction has been generalized to disallow renaming of any
4615			 * write-disabled directory, even when this would not require a
4616			 * change to the ".." entry.  For consistency, HFS+ directories
4617			 * emulate this behavior.
4618			 *
4619			 * So if you are renaming a dir to an existing dir, you must have
4620			 * write access on the existing dir. Seems if the user is a super
4621			 * user then we can delete the existing directory.
4622			 *
4623			 * XXX - We need to remove the smb_check_posix_access and just do a
4624			 * vnop_access.
4625			 */
4626			if (share->ss_attributes & FILE_PERSISTENT_ACLS)
4627				error = smbfs_rmdir(share, tdvp, tvp, tcnp, ap->a_context);
4628			else if ((vfs_context_suser(ap->a_context) == 0) ||
4629					 (smb_check_posix_access(ap->a_context, VTOSMB(tvp), S_IWOTH)))
4630				error = smbfs_rmdir(share, tdvp, tvp, tcnp, ap->a_context);
4631			else
4632				error = EPERM;
4633		} else {
4634			error = smbfs_remove(share, tdvp, tvp, tcnp, 0, ap->a_context);
4635		}
4636		if (error)
4637			goto out;
4638	}
4639
4640	cache_purge(fvp);
4641
4642	/* Did we open this in our read routine. Then we should close it. */
4643	if ((!vnode_isdir(fvp)) && (!vnode_isinuse(fvp, 0)) &&
4644		(fnp->f_refcnt == 1) && fnp->f_needClose) {
4645		error = smbfs_close(share, fvp, FREAD, ap->a_context);
4646		if (error) {
4647            lck_rw_lock_shared(&fnp->n_name_rwlock);
4648			SMBWARNING("error %d closing %s\n", error, fnp->n_name);
4649            lck_rw_unlock_shared(&fnp->n_name_rwlock);
4650        }
4651	}
4652
4653	/*
4654	 * Windows Servers will not let you move a item that contains open items. So
4655	 * if we are moving an folder and the source folder has an open notification
4656	 * then close the notification, before doing the move.
4657	 */
4658	if (vnode_isdir(fvp) &&
4659        (fnp->d_fid != 0)) {
4660		(void)smbfs_tmpclose(share, fnp, fnp->d_fid, ap->a_context);
4661		/* Mark it to be reopen */
4662		fnp->d_needReopen = TRUE;
4663		fnp->d_fid = 0;
4664	}
4665
4666	/*
4667	 * Try to rename the file, this may fail if the file is open. Some
4668	 * SAMBA systems allow us to rename an open file, so try this case
4669	 * first.
4670	 *
4671	 * FYI: While working on Radar 4532498 I notice that you can move/rename
4672	 * an open file if it is open for read-only. Only tested this on Windows 2003.
4673	 */
4674	error = smbfs_smb_rename(share, fnp, tdnp, tcnp->cn_nameptr,
4675							 tcnp->cn_namelen, ap->a_context);
4676	/*
4677	 * The file could be open so lets try again. This call does not work on
4678	 * Windows 95/98/Me/NT4 systems. Since this call only allows you to
4679	 * rename in place do not even try it if they are moving the item.
4680	 */
4681	if ( (fdvp == tdvp) && error &&
4682		(VC_CAPS(SSTOVC(share)) & SMB_CAP_INFOLEVEL_PASSTHRU))
4683		error = smbfs_smb_t2rename(share, fnp, tcnp->cn_nameptr,
4684								   tcnp->cn_namelen, 1, NULL, ap->a_context);
4685
4686	/*
4687	 * We should really print a better description of the error to the
4688	 * system log. Thing we could print in the system log.
4689	 * 1. This server does not support renaming of an open file.
4690	 * 2. This server only supports renaming of an open file in place.
4691	 * 3. Renaming open file failed.
4692	 *
4693	 * Written up as Radar 4381236
4694	 */
4695	if (!error) {
4696		char *new_name;
4697		uint64_t hashval;
4698		uint32_t orig_flag = fnp->n_flag;
4699
4700		/*
4701		 * At this point we still have both parents and the children locked if
4702		 * they exist. Since the parents are locked we know that a lookup of the
4703		 * children cannot happen over the network. So we are safe to play with
4704		 * both names and the hash node entries. The old code would just remove
4705		 * the node from the hash table and then just change the nodes name, this
4706		 * was very bad and could cause the following to happen:
4707		 *
4708		 * RENAME HAPPENS ON VP1: vp1->np1->n_name = file1 gets renamed to vp1->np1->n_name = file2
4709		 *	1. vp1 is no longer in the name cache.
4710		 *  2. np1 is no longer in the hash table.
4711		 *  3. vp1 still has a ref taken on it and can still be used.
4712		 *
4713		 * LOOKUP HAPPNES ON file2: Which will cause a new vnode and smbnode to get created
4714		 *  1. vp1 is not found because its not in the name cache.
4715		 *  2. np1 is not found because its not in the hash table.
4716		 *  3. vp2 and np2 get created and vp2->np2->n_name = file2
4717		 *
4718		 * RENAME HAPPENS ON VP2: vp2->np2->n_name = file2 gets renamed to vp2->np2->n_name = file3
4719		 *	1. vp1 no longer has the correct name.
4720		 *	2. vp2 is no longer in the name cache.
4721		 *  3. np2 is no longer in the hash table.
4722		 *  4. vp2 still has a ref taken on it and can still be used.
4723		 *
4724		 * SOME OTHER OPERATION HAPPENS ON VP1: It will fail because VP1 now has the wrong name.
4725		 *	1. Now the whole thing can repeat, very bad!
4726		 */
4727
4728        if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) {
4729            /*
4730             * Server does not support File IDs.
4731             * Remove it from the hash, it doesn't exist under that name
4732             * anymore
4733             */
4734            smb_vhashrem(fnp);
4735        }
4736
4737		/* We always need the following code. */
4738		if (tdvp && (fdvp != tdvp)) {
4739            lck_rw_lock_exclusive(&fnp->n_parent_rwlock);
4740
4741			/* Take a ref count on the new parent */
4742			if (!vnode_isvroot(tdvp)) {
4743				if (vnode_get(tdvp) == 0) {
4744					if (vnode_ref(tdvp) == 0) {
4745						fnp->n_flag |= NREFPARENT;
4746
4747                        /* Increment new parent node's child refcnt */
4748                        OSIncrementAtomic(&tdnp->n_child_refcnt);
4749                    }
4750					else {
4751						fnp->n_flag &= ~NREFPARENT;
4752                    }
4753					vnode_put(tdvp);
4754				}
4755			}
4756			else
4757				fnp->n_flag &= ~NREFPARENT;
4758
4759			/* Remove the ref count off the old parent */
4760			if ((!vnode_isvroot(fdvp)) && (orig_flag & NREFPARENT)) {
4761				if (vnode_get(fdvp) == 0) {
4762					vnode_rele(fdvp);
4763					vnode_put(fdvp);
4764
4765                    /* Remove the child refcnt from old parent */
4766                    OSDecrementAtomic(&fdnp->n_child_refcnt);
4767				}
4768			}
4769
4770			fnp->n_parent = VTOSMB(tdvp);
4771
4772            lck_rw_unlock_exclusive(&fnp->n_parent_rwlock);
4773
4774            VTOSMB(tdvp)->d_changecnt++;
4775            VTOSMB(fdvp)->d_changecnt++;
4776		}
4777
4778		/*
4779		 * Now reset the name so path lookups will work and add the node back
4780		 * into the hash table, so other lookups can this node.
4781		 */
4782		new_name = smb_strndup(tcnp->cn_nameptr, tcnp->cn_namelen);
4783		if (new_name) {
4784			char * old_name = NULL;
4785
4786			lck_rw_lock_exclusive(&fnp->n_name_rwlock);
4787			old_name = fnp->n_name;
4788			fnp->n_name = new_name;
4789			fnp->n_nmlen = tcnp->cn_namelen;
4790
4791            if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) {
4792                /* Server does not support File IDs */
4793                hashval = smbfs_hash(NULL, 0, fnp->n_name, fnp->n_nmlen);
4794                smb_vhashadd(fnp, hashval);
4795            }
4796
4797			lck_rw_unlock_exclusive(&fnp->n_name_rwlock);
4798
4799			/* Now its safe to free the old name */
4800			SMB_FREE(old_name, M_SMBNODENAME);
4801		}
4802
4803        if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) {
4804            /*
4805             * Servers does not support File IDs
4806             * <10854595> Update the n_ino with the new name and/or parent
4807             */
4808            lck_rw_lock_shared(&fnp->n_parent_rwlock);
4809            lck_rw_lock_shared(&fnp->n_name_rwlock);
4810
4811            fnp->n_ino = smbfs_getino(fnp->n_parent, fnp->n_name, fnp->n_nmlen);
4812
4813            lck_rw_unlock_shared(&fnp->n_name_rwlock);
4814            lck_rw_unlock_shared(&fnp->n_parent_rwlock);
4815        }
4816
4817        /* Update time stamp of when we last did rename */
4818        nanouptime(&fnp->n_rename_time);
4819    }
4820
4821	/*
4822	 *	Source			Target
4823	 *	Dot	Hidden		Dot	HIDE
4824	 *	Dot	Unhidden	Dot	HIDE! (Puma recovery)
4825	 *	NoDot	Hidden		Dot	HIDE (Win hid it)
4826	 *	NoDot	Unhidden	Dot	HIDE
4827	 *	Dot	Hidden		NoDot	UNHIDE
4828	 *	Dot	Unhidden	NoDot	UNHIDE
4829	 *	NoDot	Hidden		NoDot	HIDE! (Win hid it)
4830	 *	NoDot	Unhidden	NoDot	UNHIDE
4831	 */
4832	if (!error) {
4833		int hiderr;
4834		Boolean hideItem = (tcnp->cn_nameptr[0] == '.');
4835		Boolean unHideItem = ((tcnp->cn_nameptr[0] != '.') &&
4836							  (fcnp->cn_nameptr[0] == '.'));
4837
4838		if (hideItem || unHideItem) {
4839			hiderr = smbfs_set_hidden_bit(share, tdnp, (vtype == VDIR) ? VDIR : VREG,
4840                                          tcnp->cn_nameptr, tcnp->cn_namelen,
4841                                          hideItem, ap->a_context);
4842			if (hiderr) {
4843				SMBWARNING("Error %d %s %s\n", hiderr, (hideItem) ? "hiding" :
4844						 "unhiding", tcnp->cn_nameptr);
4845			}
4846		}
4847	}
4848
4849	if (error == EBUSY) {
4850		char errbuf[32];
4851
4852		proc_name(proc_pid(p), &errbuf[0], 32);
4853
4854        lck_rw_lock_shared(&fnp->n_name_rwlock);
4855        SMBERROR("warning: pid %d(%.*s) rename open file(%s)\n", proc_pid(p),
4856				 32, &errbuf[0], fnp->n_name);
4857        lck_rw_unlock_shared(&fnp->n_name_rwlock);
4858	}
4859
4860	smbfs_attr_touchdir(fdnp, (share->ss_fstype == SMB_FS_FAT));
4861	if (tdvp != fdvp)
4862		smbfs_attr_touchdir(tdnp, (share->ss_fstype == SMB_FS_FAT));
4863	/* if success, blow away statfs cache */
4864	if (!error) {
4865		smp->sm_statfstime = 0;
4866
4867        /* Invalidate negative cache entries in destination dir */
4868		if (tdnp->n_flag & NNEGNCENTRIES) {
4869			tdnp->n_flag &= ~NNEGNCENTRIES;
4870			cache_purge_negatives(tdvp);
4871		}
4872	}
4873
4874out:
4875	/* We only have a share if we obtain a reference on it, so release it */
4876	if (share) {
4877		smb_share_rele(share, ap->a_context);
4878	}
4879	if (error == EBUSY) {
4880		char errbuf[32];
4881
4882		proc_name(proc_pid(p), &errbuf[0], 32);
4883
4884        lck_rw_lock_shared(&fnp->n_name_rwlock);
4885		SMBWARNING("warning: pid %d(%.*s) rename open file(%s)\n", proc_pid(p), 32, &errbuf[0], fnp->n_name);
4886        lck_rw_unlock_shared(&fnp->n_name_rwlock);
4887	}
4888	for (ii = 0; ii < lock_cnt; ii++)
4889		if (lock_order[ii])
4890			smbnode_unlock(lock_order[ii]);
4891
4892    SMB_LOG_KTRACE(SMB_DBG_RENAME | DBG_FUNC_END, error, 0, 0, 0, 0);
4893	return (error);
4894}
4895
4896/*
4897 * smbfs_vnop_link
4898 *
4899 * vnode_t a_vp;
4900 * vnode_t a_tdvp;
4901 * struct componentname *a_cnp;
4902 * vfs_context_t a_context;
4903 *
4904 * someday this will come true...
4905 */
4906static int
4907smbfs_vnop_link(struct vnop_link_args *ap)
4908{
4909	proc_t p = vfs_context_proc(ap->a_context);
4910	struct smbnode *np = VTOSMB(ap->a_vp);
4911	char errbuf[32];
4912
4913    SMB_LOG_KTRACE(SMB_DBG_LINK | DBG_FUNC_START, 0, 0, 0, 0, 0);
4914
4915	proc_name(proc_pid(p), &errbuf[0], 32);
4916
4917    lck_rw_lock_shared(&np->n_name_rwlock);
4918    SMBERROR("warning: pid %d(%.*s) hardlink(%s)\n", proc_pid(p), 32, &errbuf[0], np->n_name);
4919    lck_rw_unlock_shared(&np->n_name_rwlock);
4920
4921    SMB_LOG_KTRACE(SMB_DBG_LINK | DBG_FUNC_END, 0, 0, 0, 0, 0);
4922	return (err_link(ap));
4923}
4924
4925/*
4926 * smbfs_vnop_symlink link create call.
4927 *
4928 * vnode_t a_dvp;
4929 * vnode_t *a_vpp;
4930 * struct componentname *a_cnp;
4931 * struct vnode_attr *a_vap;
4932 *  char *a_target;
4933 *  vfs_context_t a_context;
4934 */
4935static int smbfs_vnop_symlink(struct vnop_symlink_args *ap)
4936{
4937	int error;
4938	struct vnop_create_args a;
4939	vnode_t 	dvp = ap->a_dvp;
4940	struct smbnode *dnp;
4941	struct smb_share *share;
4942
4943	/* Make sure we lock the parent before calling smbfs_create */
4944	if ((error = smbnode_lock(VTOSMB(dvp), SMBFS_EXCLUSIVE_LOCK)))
4945		return error;
4946
4947    SMB_LOG_KTRACE(SMB_DBG_SYM_LINK | DBG_FUNC_START, 0, 0, 0, 0, 0);
4948
4949	dnp = VTOSMB(dvp);
4950	dnp->n_lastvop = smbfs_vnop_symlink;
4951	a.a_dvp = dvp;
4952	a.a_vpp = ap->a_vpp;
4953	a.a_cnp = ap->a_cnp;
4954	a.a_vap = ap->a_vap;
4955	a.a_context = ap->a_context;
4956	/*
4957	 * We use PATH_MAX because we have no way currently to find out what is the
4958	 * max path on the server.
4959	 */
4960	share = smb_get_share_with_reference(VTOSMBFS(dvp));
4961
4962	error = smbfs_create(share, &a, ap->a_target, strnlen(ap->a_target, PATH_MAX+1));
4963
4964	smb_share_rele(share, ap->a_context);
4965	smbnode_unlock(dnp);
4966
4967	SMB_LOG_KTRACE(SMB_DBG_SYM_LINK | DBG_FUNC_END, error, 0, 0, 0, 0);
4968    return (error);
4969}
4970
4971/*
4972 * smbfs_vnop_readlink read symlink call.
4973 *
4974 * vnode_t *a_vpp;
4975 * struct componentname *a_cnp;
4976 * uio_t a_uio;
4977 *  vfs_context_t a_context;
4978 */
4979static int
4980smbfs_vnop_readlink(struct vnop_readlink_args *ap)
4981{
4982	vnode_t vp = ap->a_vp;
4983	struct smbnode *np = NULL;
4984	int error;
4985	struct smb_share *share;
4986	time_t attrtimeo;
4987	struct timespec ts;
4988	int use_cached_data = 0;
4989
4990	if (vnode_vtype(vp) != VLNK)
4991		return (EINVAL);
4992
4993	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
4994		return (error);
4995
4996    SMB_LOG_KTRACE(SMB_DBG_READ_LINK | DBG_FUNC_START, 0, 0, 0, 0, 0);
4997
4998	np = VTOSMB(vp);
4999	np->n_lastvop = smbfs_vnop_readlink;
5000	share = smb_get_share_with_reference(VTOSMBFS(vp));
5001
5002    /* If we are in reconnect, use cached data if we have it */
5003    if (np->n_symlink_cache_timer != 0) {
5004        use_cached_data = (share->ss_flags & SMBS_RECONNECTING);
5005    }
5006
5007    /* Check to see if the cache has timed out */
5008    SMB_CACHE_TIME(ts, np, attrtimeo);
5009
5010	if ((np->n_symlink_target) &&
5011        (use_cached_data || ((ts.tv_sec - np->n_symlink_cache_timer) <= attrtimeo))) {
5012        /* Cached data is still valid */
5013		error = uiomove(np->n_symlink_target, (int)np->n_symlink_target_len, ap->a_uio);
5014	} else if ((np->n_dosattr & SMB_EFA_REPARSE_POINT) &&
5015               (np->n_reparse_tag == IO_REPARSE_TAG_SYMLINK)) {
5016        error = smbfs_smb_reparse_read_symlink(share, np, ap->a_uio, ap->a_context);
5017	} else if (np->n_flag & NWINDOWSYMLNK) {
5018		error = smbfs_smb_windows_read_symlink(share, np, ap->a_uio, ap->a_context);
5019	} else {
5020		error = smbfs_smb_unix_read_symlink(share, np, ap->a_uio, ap->a_context);
5021	}
5022
5023    if ((error == ETIMEDOUT) && (np->n_symlink_cache_timer != 0)) {
5024        /* Just return the cached data */
5025		error = uiomove(np->n_symlink_target, (int)np->n_symlink_target_len, ap->a_uio);
5026    }
5027
5028	smb_share_rele(share, ap->a_context);
5029	smbnode_unlock(np);
5030
5031    SMB_LOG_KTRACE(SMB_DBG_READ_LINK | DBG_FUNC_END, error, 0, 0, 0, 0);
5032	return (error);
5033}
5034
5035/*
5036 * smbfs_vnop_mknod
5037 *
5038 * vnode_t a_dvp;
5039 * vnode_t *a_vpp;
5040 * struct componentname *a_cnp;
5041 * struct vnode_attr *a_vap;
5042 * vfs_context_t a_context;
5043 */
5044static int
5045smbfs_vnop_mknod(struct vnop_mknod_args *ap)
5046{
5047	proc_t p = vfs_context_proc(ap->a_context);
5048	char errbuf[32];
5049
5050    SMB_LOG_KTRACE(SMB_DBG_MKNODE | DBG_FUNC_START, 0, 0, 0, 0, 0);
5051
5052	proc_name(proc_pid(p), &errbuf[0], 32);
5053	SMBERROR("warning: pid %d(%.*s) mknod(%s)\n", proc_pid(p), 32, &errbuf[0],
5054			 ap->a_cnp->cn_nameptr);
5055
5056    SMB_LOG_KTRACE(SMB_DBG_MKNODE | DBG_FUNC_END, 0, 0, 0, 0, 0);
5057	return (err_mknod(ap));
5058}
5059
5060/*
5061 * smbfs_vnop_mkdir
5062 *
5063 * vnode_t a_dvp;
5064 * vnode_t *a_vpp;
5065 * struct componentname *a_cnp;
5066 * struct vnode_attr *a_vap;
5067 * vfs_context_t a_context;
5068 */
5069static int
5070smbfs_vnop_mkdir(struct vnop_mkdir_args *ap)
5071{
5072	vnode_t 	dvp = ap->a_dvp;
5073	struct vnode_attr *vap = ap->a_vap;
5074	vnode_t 	vp;
5075	struct componentname *cnp = ap->a_cnp;
5076	struct smbnode *dnp = NULL;
5077	struct smbmount *smp = NULL;
5078	struct smbfattr fattr;
5079	const char *name = cnp->cn_nameptr;
5080	size_t len = cnp->cn_namelen;
5081	int error;
5082	struct smb_share *share;
5083	struct timespec ts;
5084
5085	if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
5086		return (EEXIST);
5087
5088	if ((error = smbnode_lock(VTOSMB(dvp), SMBFS_EXCLUSIVE_LOCK)))
5089		return (error);
5090
5091	SMB_LOG_KTRACE(SMB_DBG_MKDIR | DBG_FUNC_START, 0, 0, 0, 0, 0);
5092
5093    dnp = VTOSMB(dvp);
5094	dnp->n_lastvop = smbfs_vnop_mkdir;
5095	smp = dnp->n_mount;
5096	share = smb_get_share_with_reference(smp);
5097	error = smbfs_smb_mkdir(share, dnp, name, len, &fattr, ap->a_context);
5098	if (error)
5099		goto exit;
5100
5101	smbfs_attr_touchdir(dnp, (share->ss_fstype == SMB_FS_FAT));
5102    dnp->d_changecnt++;
5103
5104	/*
5105	 * %%%
5106	 * Would really like to clean this code up in the future. The whole create,
5107	 * mkdir and smblink create code should use the same code path.
5108	 */
5109	error = smbfs_nget(share, vnode_mount(dvp),
5110                       dvp, name, len,
5111                       &fattr, &vp,
5112                       cnp->cn_flags, SMBFS_NGET_CREATE_VNODE,
5113                       ap->a_context);
5114	if (error)
5115		goto bad;
5116
5117	/*
5118	 * We just create the directory, so we have no finder info. So set our cache
5119	 * timer to reflect this information
5120	 */
5121	nanouptime(&ts);
5122	VTOSMB(vp)->finfo_cache_timer = ts.tv_sec;
5123	smbfs_set_create_vap(share, vap, vp, ap->a_context, FALSE);
5124	*ap->a_vpp = vp;
5125	smbnode_unlock(VTOSMB(vp));	/* Done with the smbnode unlock it. */
5126	error = 0;
5127	if (dnp->n_flag & NNEGNCENTRIES) {
5128		dnp->n_flag &= ~NNEGNCENTRIES;
5129		cache_purge_negatives(dvp);
5130	}
5131
5132bad:
5133	if (name != cnp->cn_nameptr) {
5134		SMB_FREE(name, M_SMBNODENAME);
5135	}
5136	/* if success, blow away statfs cache */
5137	smp->sm_statfstime = 0;
5138exit:
5139	smb_share_rele(share, ap->a_context);
5140	smbnode_unlock(dnp);
5141
5142    SMB_LOG_KTRACE(SMB_DBG_MKDIR | DBG_FUNC_END, error, 0, 0, 0, 0);
5143	return (error);
5144}
5145
5146/*
5147 * smbfs_vnop_readdir
5148 *
5149 * vnode_t a_vp;
5150 * struct uio *a_uio;
5151 * int a_flags;
5152 * int *a_eofflag;
5153 * int *a_numdirent;
5154 * vfs_context_t a_context;
5155 */
5156static int
5157smbfs_vnop_readdir(struct vnop_readdir_args *ap)
5158{
5159	vnode_t	vp = ap->a_vp;
5160	uio_t uio = ap->a_uio;
5161	int error;
5162	int32_t numdirent = 0;
5163
5164	if (uio_offset(uio) < 0)
5165		return (EINVAL);
5166
5167	if (!vnode_isdir(vp))
5168		return (EPERM);
5169
5170	if (ap->a_eofflag)
5171		*ap->a_eofflag = 0;
5172
5173	if (uio_resid(uio) == 0)
5174		return (0);
5175
5176	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
5177		return (error);
5178
5179	SMB_LOG_KTRACE(SMB_DBG_READ_DIR | DBG_FUNC_START, VTOSMB(vp)->d_fid, 0, 0, 0, 0);
5180
5181	VTOSMB(vp)->n_lastvop = smbfs_vnop_readdir;
5182
5183	error = smbfs_readvdir(vp, uio, ap->a_context, ap->a_flags, &numdirent);
5184	if (error == ENOENT) {
5185		/* We have reached the end of the search */
5186		if (ap->a_eofflag)
5187			*ap->a_eofflag = 1;
5188		error = 0;
5189	}
5190
5191	/* Return the number of entries from this lookup */
5192	if (ap->a_numdirent)
5193		*ap->a_numdirent = numdirent;
5194
5195	smbnode_unlock(VTOSMB(vp));
5196
5197    SMB_LOG_KTRACE(SMB_DBG_READ_DIR | DBG_FUNC_END, error, numdirent, 0, 0, 0);
5198	return (error);
5199}
5200
5201int32_t
5202smbfs_fsync(struct smb_share *share, vnode_t vp, int waitfor, int ubc_flags,
5203			vfs_context_t context)
5204{
5205#pragma unused(waitfor, ubc_flags)
5206	int error;
5207	off_t size;
5208
5209	if (!vnode_isreg(vp)) {
5210		return 0; /* Nothing to do here */
5211	}
5212
5213    SMB_LOG_KTRACE(SMB_DBG_SMBFS_FSYNC | DBG_FUNC_START, 0, 0, 0, 0, 0);
5214
5215	size = smb_ubc_getsize(vp);
5216	if ((size > 0) && smbfsIsCacheable(vp)) {
5217		if (VTOSMB(vp)->n_flag & NISMAPPED) {
5218			/* More expensive, but handles mmapped files */
5219			ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
5220		} else {
5221			/* Less expensive, but does not handle mmapped files */
5222			cluster_push(vp, IO_SYNC);
5223		}
5224	}
5225	error = smbfs_smb_fsync(share, VTOSMB(vp), context);
5226	if (!error)
5227		VTOSMBFS(vp)->sm_statfstime = 0;
5228
5229	SMB_LOG_KTRACE(SMB_DBG_SMBFS_FSYNC | DBG_FUNC_END, error, 0, 0, 0, 0);
5230    return (error);
5231}
5232
5233/*	smbfs_vnop_fsync
5234 *
5235 * vnode_t a_vp;
5236 * int32_t a_waitfor;
5237 * vfs_context_t a_context;
5238 */
5239static int32_t
5240smbfs_vnop_fsync(struct vnop_fsync_args *ap)
5241{
5242	int32_t error;
5243	struct smb_share *share;
5244
5245    /* If this is a read-only mount, there is nothing to do here */
5246    if (vfs_isrdonly(vnode_mount(ap->a_vp))) {
5247        return (0);
5248    }
5249
5250	error = smbnode_lock(VTOSMB(ap->a_vp), SMBFS_EXCLUSIVE_LOCK);
5251	if (error)
5252		return (0);
5253
5254	SMB_LOG_KTRACE(SMB_DBG_FSYNC | DBG_FUNC_START, 0, 0, 0, 0, 0);
5255
5256    VTOSMB(ap->a_vp)->n_lastvop = smbfs_vnop_fsync;
5257	share = smb_get_share_with_reference(VTOSMBFS(ap->a_vp));
5258	error = smbfs_fsync(share, ap->a_vp, ap->a_waitfor, 0, ap->a_context);
5259	smb_share_rele(share, ap->a_context);
5260	smbnode_unlock(VTOSMB(ap->a_vp));
5261
5262    SMB_LOG_KTRACE(SMB_DBG_FSYNC | DBG_FUNC_END, error, 0, 0, 0, 0);
5263    return (error);
5264}
5265
5266/*
5267 * smbfs_vnop_pathconf
5268 *
5269 *  vnode_t a_vp;
5270 *  int a_name;
5271 *  int32_t *a_retval;
5272 *  vfs_context_t a_context;
5273 */
5274static int smbfs_vnop_pathconf(struct vnop_pathconf_args *ap)
5275{
5276	struct smb_share *share;
5277	int32_t *retval = ap->a_retval;
5278	int error = 0;
5279
5280    SMB_LOG_KTRACE(SMB_DBG_PATHCONF | DBG_FUNC_START, ap->a_name, 0, 0, 0, 0);
5281
5282	share = smb_get_share_with_reference(VTOSMBFS(ap->a_vp));
5283	switch (ap->a_name) {
5284		case _PC_LINK_MAX:	/* Hard Link Support */
5285			*retval = 0; /* May support in the future. Depends on the server */
5286			break;
5287		case _PC_NAME_MAX:
5288			*retval = share->ss_maxfilenamelen;
5289			break;
5290		case _PC_PATH_MAX:
5291				/*
5292				 * XXX
5293				 * Most Windows system have a 255 limit, but you can configure
5294				 * them to support 1024. It would be nice if we could figure out
5295				 * the real value for this field.
5296				 */
5297				*retval = PATH_MAX;
5298				break;
5299		case _PC_CHOWN_RESTRICTED:
5300				*retval = 1;
5301				break;
5302		case _PC_NO_TRUNC:
5303				*retval = 0;
5304				break;
5305		case _PC_NAME_CHARS_MAX:
5306				*retval = share->ss_maxfilenamelen;
5307				break;
5308		case _PC_CASE_SENSITIVE:
5309            *retval = 0;
5310
5311            if (SSTOVC(share)->vc_misc_flags & SMBV_OSX_SERVER) {
5312                /* Its OS X Server so we know for sure */
5313                if (SSTOVC(share)->vc_volume_caps & kAAPL_CASE_SENSITIVE) {
5314                    SMBDEBUG("Volume is case sensitive\n");
5315                    *retval = 1;
5316                }
5317            }
5318            else {
5319                /*
5320                 * Thought about using FILE_CASE_SENSITIVE_SEARCH, but this
5321                 * really just means they will search by case. It does not mean
5322                 * this is a case sensitive file system. Currently we have no
5323                 * way of determining if this is a case sensitive or
5324                 * insensitive file system. We need to return a consistent
5325                 * answer between pathconf and vfs_getattr. We do not know the real
5326                 * answer for case sensitive, but lets default to what 90% of the
5327                 * servers have set. Also remember this fixes Radar 4057391 and 3530751.
5328                 */
5329                *retval = 0;
5330            }
5331			break;
5332		case _PC_CASE_PRESERVING:
5333			if (share->ss_attributes & FILE_CASE_PRESERVED_NAMES)
5334				*retval = 1;
5335			else *retval = 0;
5336			break;
5337		/*
5338		 * Handle by vn_pathconf.
5339		 *
5340		 * case _PC_EXTENDED_SECURITY_NP:
5341		 *		*retval = vfs_extendedsecurity(vnode_mount(vp)) ? 1 : 0;
5342		 *		break;
5343		 * case _PC_AUTH_OPAQUE_NP:
5344		 *		*retval = vfs_authopaque(vnode_mount(vp));
5345		 *		break;
5346		 * case _PC_2_SYMLINKS:
5347		 *		*retval = 1;
5348		 *		break;
5349		 * case _PC_ALLOC_SIZE_MIN:
5350		 *		*retval = 1;    // XXX lie: 1 byte
5351		 *		break;
5352		 * case _PC_ASYNC_IO:     // unistd.h: _POSIX_ASYNCHRONUS_IO
5353		 *		*retval = 1;    // [AIO] option is supported
5354		 *		break;
5355		 */
5356		case _PC_FILESIZEBITS:
5357			if (VC_CAPS(SSTOVC(share)) & SMB_CAP_LARGE_FILES)
5358				*retval = 64;	/* The server supports 64 bit offsets */
5359			else *retval = 32;	/* The server supports 32 bit offsets */
5360			break;
5361	    case _PC_XATTR_SIZE_BITS:
5362			if (!(share->ss_attributes & FILE_NAMED_STREAMS)) {
5363				/* Doesn't support named streams VFS handles this cases */
5364				error = EINVAL;
5365			} else if (VC_CAPS(SSTOVC(share)) & SMB_CAP_LARGE_FILES) {
5366				*retval = 64;	/* The server supports 64 bit offsets */
5367			} else {
5368				*retval = 32;	/* The server supports 32 bit offsets */
5369			}
5370			break;
5371		/*
5372		 * Handle by vn_pathconf.
5373		 *
5374		 * case _PC_PRIO_IO:       // unistd.h: _POSIX_PRIORITIZED_IO
5375		 *		 *retval = 0;    // [PIO] option is not supported
5376		 *		break;
5377		 * case _PC_REC_INCR_XFER_SIZE:
5378		 *		*retval = 4096; // XXX go from MIN to MAX 4K at a time
5379		 *		break;
5380		 * case _PC_REC_MIN_XFER_SIZE:
5381		 *		*retval = 4096; // XXX recommend 4K minimum reads/writes
5382		 *		break;
5383		 * case _PC_REC_MAX_XFER_SIZE: // Should we use SMB_IOMAX
5384		 *		*retval = 65536; // XXX recommend 64K maximum reads/writes
5385		 *		break;
5386		 * case _PC_REC_XFER_ALIGN:
5387		 *		*retval = 4096; // XXX recommend page aligned buffers
5388		 *		break;
5389		 * case _PC_SYMLINK_MAX:
5390		 *		*retval = 255;  // Minimum acceptable POSIX value
5391		 *		break;
5392		 * case _PC_SYNC_IO:       // unistd.h: _POSIX_SYNCHRONIZED_IO
5393		 *		*retval = 0;    // [SIO] option is not supported
5394		 *		break;
5395		 */
5396		default:
5397			error = EINVAL;
5398	}
5399	smb_share_rele(share, ap->a_context);
5400
5401    SMB_LOG_KTRACE(SMB_DBG_PATHCONF | DBG_FUNC_END, error, 0, 0, 0, 0);
5402    return (error);
5403}
5404
5405/*
5406 * smbfs_vnop_ioctl - smbfs vnodeop entry point
5407 *	vnode_t a_vp;
5408 *	int32_t  a_command;
5409 *	caddr_t  a_data;
5410 *	int32_t  a_fflag;
5411 *	vfs_context_t context;
5412 */
5413static int32_t smbfs_vnop_ioctl(struct vnop_ioctl_args *ap)
5414{
5415    vnode_t		vp = ap->a_vp;
5416    struct smbnode	*np;
5417    int32_t			error = 0;
5418	proc_t			p = vfs_context_proc(ap->a_context);
5419	struct smb_share *share;
5420	struct smbmount *smp;
5421
5422	error = smbnode_lock(VTOSMB(ap->a_vp), SMBFS_EXCLUSIVE_LOCK);
5423	if (error)
5424		return (error);
5425
5426    SMB_LOG_KTRACE(SMB_DBG_IOCTL | DBG_FUNC_START, ap->a_command, 0, 0, 0, 0);
5427
5428	np = VTOSMB(vp);
5429	np->n_lastvop = smbfs_vnop_ioctl;
5430	smp = VTOSMBFS(vp);
5431	share = smb_get_share_with_reference(VTOSMBFS(vp));
5432
5433	/*
5434	 * %%%
5435	 * Remove the IOCBASECMD case lines (OLD) when fsctl code in vfs_syscalls.c
5436	 * gets fixed to not use IOCBASECMD before calling VOP_IOCTL.
5437	 *
5438	 * The smbfsByteRangeLock2FSCTL call was made to support classic. We do
5439	 * not support classic, but the file manager will only make the
5440	 * smbfsByteRangeLock2FSCTL call. So for now support all the commands, but
5441	 * treat them all the same.
5442	 */
5443	switch (ap->a_command) {
5444	case smbfsGetVCSockaddrFSCTL:
5445	case smbfsGetVCSockaddrFSCTL_BASECMD: {
5446
5447		if (SSTOVC(share)->vc_saddr) {
5448			memcpy(ap->a_data, SSTOVC(share)->vc_saddr,
5449				   SSTOVC(share)->vc_saddr->sa_len);
5450		} else {
5451			error = EINVAL; /* Better never happen, but just in case */
5452		}
5453		break;
5454	}
5455	case smbfsUniqueShareIDFSCTL:
5456	case smbfsUniqueShareIDFSCTL_BASECMD: {
5457		struct UniqueSMBShareID *uniqueptr = (struct UniqueSMBShareID *)ap->a_data;
5458
5459		uniqueptr->error = 0;
5460		if ((uniqueptr->flags & SMBFS_GET_ACCESS_INFO) ||
5461			((uniqueptr->unique_id_len == smp->sm_args.unique_id_len) &&
5462			(bcmp(smp->sm_args.unique_id, uniqueptr->unique_id,
5463				  uniqueptr->unique_id_len) == 0))) {
5464
5465				/* In the future we should return the lsa name if we have one */
5466			uniqueptr->user[0] = 0;	/* Just in case we have no user name */
5467			if (SSTOVC(share)->vc_flags & SMBV_GUEST_ACCESS) {
5468				uniqueptr->connection_type = kConnectedByGuest;
5469				strlcpy(uniqueptr->user, kGuestAccountName, SMB_MAXUSERNAMELEN + 1);
5470			}
5471			else if (SSTOVC(share)->vc_username) {
5472				uniqueptr->connection_type = kConnectedByUser;
5473				strlcpy(uniqueptr->user, SSTOVC(share)->vc_username, SMB_MAXUSERNAMELEN + 1);
5474			} else {
5475				uniqueptr->connection_type = kConnectedByKerberos;
5476			}
5477			uniqueptr->error = EEXIST;
5478		}
5479	}
5480	break;
5481	case smbfsByteRangeLock2FSCTL:
5482	case smbfsByteRangeLock2FSCTL_BASECMD:
5483	case smbfsByteRangeLockFSCTL:
5484	case smbfsByteRangeLockFSCTL_BASECMD: {
5485		struct ByteRangeLockPB *pb = (struct ByteRangeLockPB *) ap->a_data;
5486		struct ByteRangeLockPB2 *pb2 = (struct ByteRangeLockPB2 *) ap->a_data;
5487		uint32_t lck_pid;
5488		uint32_t timo;
5489		SMBFID fid = 0;
5490		struct fileRefEntry *fndEntry = NULL;
5491		uint16_t accessMode = 0;
5492		int8_t flags;
5493        struct smbfattr *fap = NULL;
5494        struct smb2_durable_handle dur_handle, *dptr;
5495        int do_create;
5496        uint32_t disp;
5497
5498		/* make sure its a file */
5499		if (vnode_isdir(vp)) {
5500			error = EISDIR;
5501			goto exit;
5502		}
5503
5504		/* Before trying the lock see if the file needs to be reopened */
5505		error = smbfs_smb_reopen_file(share, np, ap->a_context);
5506		if (error) {
5507            lck_rw_lock_shared(&np->n_name_rwlock);
5508			SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
5509            lck_rw_unlock_shared(&np->n_name_rwlock);
5510			goto exit;
5511		}
5512
5513		/*
5514		 * If adding/removing a ByteRangeLock, thus this vnode should NEVER
5515		 * be cacheable since the page in/out may overlap a lock and get
5516		 * an error.
5517		 */
5518		if (smbfsIsCacheable(vp)) {
5519			if (np->n_flag & NISMAPPED) {
5520				/* More expensive, but handles mmapped files */
5521				ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
5522			} else {
5523				/* Less expensive, but does not handle mmapped files */
5524				cluster_push(vp, IO_SYNC);
5525			}
5526			ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_INVALIDATE);
5527			vnode_setnocache(vp);
5528		}
5529
5530		accessMode = np->f_accessMode;
5531
5532		/*
5533		 * Since we never get a smbfsByteRangeLockFSCTL call we could skip this
5534		 * check, but for now leave it.
5535		 */
5536		if ( (ap->a_command == smbfsByteRangeLock2FSCTL) ||
5537			(ap->a_command == smbfsByteRangeLock2FSCTL_BASECMD) ) {
5538			int32_t openMode = 0;
5539
5540			/*
5541			 * Not just for classic any more, could get this from Carbon.
5542			 *
5543			 * They will be using an extended BRL call that also passes in the
5544			 * open mode used that was used to open the file.  I will use the
5545			 * open access mode and pid to find the fork ref to do the lock on.
5546			 * Scenarios:
5547			 *	Open (R/W), BRL, Close (R/W)
5548			 *	Open (R/W/dW), BRL, Close (R/W/dW)
5549			 *	Open1 (R/W), Open2 (R), BRL1, BRL2, Close1 (R/W), Close2 (R)
5550			 *	Open1 (R/W/dW), Open2 (R), BRL1, BRL2, Close1 (R/W/dW), Close2 (R)
5551			 *	Open1 (R/dW), Open2 (R/dW), BRL1, BRL2, Close1 (R/dW), Close2 (R/dW)
5552			 */
5553			if ( (error = file_flags(pb2->fd, &openMode)) ) {
5554				goto exit;
5555			}
5556
5557			if (openMode & FREAD) {
5558				accessMode |= kAccessRead;
5559			}
5560			if (openMode & FWRITE) {
5561				accessMode |= kAccessWrite;
5562			}
5563
5564			/*
5565			 * See if we can find a matching fork that has byte range locks or
5566			 * denyModes
5567			 */
5568			if (openMode & FHASLOCK) {
5569				/*
5570				 * NOTE:  FHASLOCK can be set by open with O_EXCLUSIVE or
5571				 * O_SHARED which maps to my deny modes or FHASLOCK could also
5572				 * have been set/cleared by calling flock directly.  I assume
5573				 * that if they are using byte range locks, then they are Carbon
5574				 * and unlikely to be using flock.
5575				 *
5576				 * Assume it was opened with denyRead/denyWrite or just denyWrite.
5577				 * Try denyWrite first, if not found, try with denyRead and denyWrite
5578				 */
5579				accessMode |= kDenyWrite;
5580				error = FindFileRef(vp, p, accessMode, kExactMatch, 0, 0,
5581									&fndEntry, &fid);
5582				if (error != 0) {
5583					accessMode |= kDenyRead;
5584					error = FindFileRef(vp, p, accessMode, kExactMatch, 0, 0,
5585										 &fndEntry, &fid);
5586				}
5587				if (error != 0) {
5588					/* deny modes were used, but the fork ref cant be found, return error */
5589					error = EBADF;
5590					goto exit;
5591				}
5592			}
5593			else {
5594				/* no deny modes used, look for any forks opened previously for BRL */
5595				error = FindFileRef(vp, p, accessMode, kExactMatch, 0, 0,
5596									&fndEntry, &fid);
5597			}
5598		} else {
5599			error = FindFileRef(vp, p, kAccessRead | kAccessWrite, kAnyMatch,
5600								 0, 0, &fndEntry, &fid);
5601		}
5602		/*
5603		 * The process was not found or no list found
5604		 * Either case, we need to
5605		 *	1)  Open a new fork
5606		 *	2)  create a new OpenForkRefEntry entry and add it into the list
5607		 */
5608		if (error) {
5609			 uint32_t rights = 0;
5610			 uint32_t shareMode = NTCREATEX_SHARE_ACCESS_ALL;
5611			 proc_t p = vfs_context_proc(ap->a_context);
5612
5613			/* This is wrong, someone has to call open() before doing a byterange lock */
5614			if (np->f_refcnt <= 0) {
5615				error = EBADF;
5616				goto exit;
5617			}
5618
5619			/* We must find a matching lock in order to succeed at unlock */
5620			if (pb->unLockFlag == 1) {
5621				error = EINVAL;
5622				goto exit;
5623			}
5624
5625			/* Need to open the file here */
5626			if (accessMode & kAccessRead)
5627				rights |= SMB2_FILE_READ_DATA;
5628			if (accessMode & kAccessWrite)
5629				rights |= SMB2_FILE_APPEND_DATA | SMB2_FILE_WRITE_DATA;
5630
5631			if (accessMode & kDenyWrite)
5632				shareMode &= ~NTCREATEX_SHARE_ACCESS_WRITE; /* Remove the wr shared access */
5633			if (accessMode & kDenyRead)
5634				shareMode &= ~NTCREATEX_SHARE_ACCESS_READ; /* Remove the wr shared access */
5635
5636            SMB_MALLOC(fap,
5637                       struct smbfattr *,
5638                       sizeof(struct smbfattr),
5639                       M_SMBTEMP,
5640                       M_WAITOK | M_ZERO);
5641            if (fap == NULL) {
5642                SMBERROR("SMB_MALLOC failed\n");
5643                error = ENOMEM;
5644                goto exit;
5645            }
5646
5647            /* Request a durable handle */
5648            dptr = NULL;
5649            error = smb2_smb_dur_handle_init(share, np, &dur_handle);
5650            if (!error) {
5651                dptr = &dur_handle;
5652            }
5653
5654            if (np->n_flag & N_ISRSRCFRK) {
5655                disp = FILE_OPEN_IF;
5656                do_create = TRUE;
5657            }
5658            else {
5659                disp = FILE_OPEN;
5660                do_create = FALSE;
5661            }
5662
5663            error = smbfs_smb_ntcreatex(share, np,
5664                                        rights, shareMode, VREG,
5665                                        &fid, NULL, 0,
5666                                        disp, FALSE, fap,
5667                                        do_create, dptr, ap->a_context);
5668
5669			if (error != 0)
5670				goto exit;
5671
5672			AddFileRef(vp, p, accessMode, rights, fid, dur_handle, &fndEntry);
5673		}
5674
5675		/* Now I can do the ByteRangeLock */
5676		if (pb->startEndFlag) {
5677			/*
5678			 * SMB only allows you to lock relative to the begining of the
5679			 * file.  So, I need to convert offset base on the begining
5680			 * of the file.
5681			 */
5682			uint64_t fileSize = np->n_size;
5683
5684			pb->offset += fileSize;
5685			pb->startEndFlag = 0;
5686		}
5687
5688		flags = 0;
5689		if (pb->unLockFlag)
5690			flags |= SMB_LOCK_RELEASE;
5691		else
5692            flags |= SMB_LOCK_EXCL;
5693
5694		/* The problem here is that the lock pid must match the SMB Header PID.
5695		 * Some day it would be nice to pass a better value here. But for now
5696		 * always use the same value.
5697		 */
5698		lck_pid = 1;
5699		/*
5700		 * -1 infinite wait
5701		 * 0  no wait
5702		 * any other number is the number of milliseconds to wait.
5703		 */
5704		timo = 0;
5705
5706		error = smbfs_smb_lock(share, flags, fid, lck_pid, pb->offset,
5707							   pb->length, timo, ap->a_context);
5708		if (error == 0) {
5709			/* Save/remove lock info for use in read/write to determine what fork to use */
5710			AddRemoveByteRangeLockEntry (fndEntry, pb->offset, pb->length,
5711										 pb->unLockFlag, lck_pid);
5712			/* return the offset to the first byte of the lock */
5713			pb->retRangeStart = pb->offset;
5714		} else if ((!pb->unLockFlag) && (error == EACCES)) {
5715			/*
5716			 * Need to see if we are locking against ourself, so we can return
5717			 * the correct error.
5718			 */
5719			if (FindByteRangeLockEntry(fndEntry, pb->offset, pb->length, lck_pid))
5720				error = EAGAIN;
5721		}
5722	}
5723	break;
5724	default:
5725		error = ENOTSUP;
5726		goto exit;
5727    }
5728
5729exit:
5730	smb_share_rele(share, ap->a_context);
5731	smbnode_unlock(np);
5732
5733    SMB_LOG_KTRACE(SMB_DBG_IOCTL | DBG_FUNC_END, error, 0, 0, 0, 0);
5734	return (error);
5735}
5736
5737/*
5738 * SMB locks do not map to POSIX.1 advisory locks in several ways:
5739 * 1 - SMB provides no way to find an existing lock on the server.
5740 *     So, the F_GETLK operation can only report locks created by processes
5741 *     on this client.
5742 * 2 - SMB locks cannot overlap an existing locked region of a file. So,
5743 *     F_SETLK/F_SETLKW operations that establish locks cannot extend an
5744 *     existing lock.
5745 * 3 - When unlocking a SMB locked region, the region to unlock must correspond
5746 *     exactly to an existing locked region. So, F_SETLK F_UNLCK operations
5747 *     cannot split an existing lock or unlock more than was locked (this is
5748 *     especially important because whne files are closed, we receive a request
5749 *     to unlock the entire file: l_whence and l_start point to the beginning
5750 *     of the file, and l_len is zero).
5751 *
5752 * The result... SMB cannot support POSIX.1 advisory locks. It can however
5753 * support BSD flock() locks, so that's what this implementation will allow.
5754 *
5755 * Since we now support open deny modes we will only support flocks on files that
5756 * have no files open w
5757 *
5758 *		vnode_t a_vp;
5759 *		caddr_t  a_id;
5760 *		int  a_op;
5761 *		struct flock *a_fl;
5762 *		int  a_flags;
5763 *		vfs_context_t a_context;
5764 */
5765static int32_t
5766smbfs_vnop_advlock(struct vnop_advlock_args *ap)
5767{
5768	int		flags = ap->a_flags;
5769	vnode_t vp = ap->a_vp;
5770	struct smb_share *share;
5771	struct smbnode *np;
5772	int error = 0;
5773	uint32_t timo;
5774	off_t start = 0;
5775	uint64_t len = -1;
5776	uint32_t lck_pid;
5777
5778	/* Preflight checks */
5779	if (!vnode_isreg(vp)) {
5780		/* can only read regular files */
5781		if (vnode_isdir(vp))
5782			return (EISDIR);
5783		else
5784			return (EPERM);
5785	}
5786
5787	share = smb_get_share_with_reference(VTOSMBFS(vp));
5788	if ((flags & F_POSIX) && ((UNIX_CAPS(share) & CIFS_UNIX_FCNTL_LOCKS_CAP) == 0)) {
5789		/* Release the share reference before returning */
5790		smb_share_rele(share, ap->a_context);
5791		return(err_advlock(ap));
5792	}
5793
5794	if ((flags & (F_FLOCK | F_POSIX)) == 0) {
5795		/* Release the share reference before returning */
5796		smb_share_rele(share, ap->a_context);
5797		SMBWARNING("Lock flag we do not understand %x\n", flags);
5798		return(err_advlock(ap));
5799	}
5800
5801	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK))) {
5802		/* Release the share reference before returning */
5803		smb_share_rele(share, ap->a_context);
5804		return (error);
5805	}
5806
5807	SMB_LOG_KTRACE(SMB_DBG_ADVLOCK | DBG_FUNC_START, 0, 0, 0, 0, 0);
5808
5809    /* If we got here it must be a flock. Remember flocks lock the whole file. */
5810	np = VTOSMB(vp);
5811	np->n_lastvop = smbfs_vnop_advlock;
5812
5813	/*
5814	 * This vnode has a file open with open deny modes, so the file is really
5815	 * already locked. Remember that vn_open and vn_close will also call us here
5816	 * so to make them work for now, return no err. If the opened it for
5817	 * Open Deny then no one else should be allowed to use it. We could check
5818	 * the pid here, but the open call should have handled that for us.
5819	 */
5820	if (np->f_openDenyList) {
5821		error = 0;
5822		goto exit;
5823	}
5824
5825	/* Before trying the lock see if the file needs to be reopened */
5826	error = smbfs_smb_reopen_file(share, np, ap->a_context);
5827	if (error) {
5828        lck_rw_lock_shared(&np->n_name_rwlock);
5829		SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
5830        lck_rw_unlock_shared(&np->n_name_rwlock);
5831		goto exit;
5832	}
5833
5834	/*
5835	 * So if we got to this point we have a normal flock happening. We can have
5836	 * the following flags passed to us.
5837	 *
5838	 *	LOCK_SH - shared lock
5839	 *	LOCK_EX - exclusive lock
5840	 *	LOCK_NB - don't block when locking
5841	 *	LOCK_UN - unlock
5842	 *
5843	 * Currently we always allow the server handle blocking. We may want to
5844	 * re-look at this later. What if we have a lock that is blocked and
5845	 * the server goes down how long to we wait.
5846	 *
5847	 * The locking mechanism allows two types of locks: shared locks and
5848	 * exclusive locks.  At any time multiple shared locks may be applied to a
5849	 * file, but at no time are multiple exclusive, or both shared and exclusive,
5850	 * locks allowed simultaneously on a file.
5851	 *
5852	 * A shared lock may be upgraded to an exclusive lock, and vice versa, sim-
5853	 * ply by specifying the appropriate lock type; this results in the previous
5854	 * lock being released and the new lock applied (possibly after other processes
5855	 * have gained and released the lock).
5856	 *
5857	 * We currently treat LOCK_EX and LOCK_SH the same except we do not allow
5858	 * you to have more that one LOCK_EX.
5859	*/
5860	timo = (flags & F_WAIT) ? -1 : 0;
5861	/* The problem here is that the lock pid must match the SMB Header PID. Some
5862	 * day it would be nice to pass a better value here. But for now always
5863	 * use the same value.
5864	 */
5865	lck_pid = 1;
5866	/* Remember that we are always using the share open file at this point */
5867	switch(ap->a_op) {
5868	case F_SETLK:
5869		if (! np->f_smbflock) {
5870			error = smbfs_smb_lock(share, SMB_LOCK_EXCL, np->f_fid, lck_pid,
5871								   start, len, timo, ap->a_context);
5872			if (error)
5873				goto exit;
5874			SMB_MALLOC(np->f_smbflock, struct smbfs_flock *, sizeof *np->f_smbflock,
5875				   M_LOCKF, M_WAITOK);
5876			np->f_smbflock->refcnt = 1;
5877			np->f_smbflock->fl_type = ap->a_fl->l_type;
5878			np->f_smbflock->lck_pid = lck_pid;
5879			np->f_smbflock->start = start;
5880			np->f_smbflock->len = len;
5881			np->f_smbflock->flck_pid = proc_pid(vfs_context_proc(ap->a_context));
5882		} else if (np->f_smbflock->flck_pid == (uint32_t)proc_pid(vfs_context_proc(ap->a_context))) {
5883			/* First see if this is a upgrade or downgrade */
5884			if ((np->f_smbflock->refcnt == 1) &&
5885				(np->f_smbflock->fl_type != ap->a_fl->l_type)) {
5886					np->f_smbflock->fl_type = ap->a_fl->l_type;
5887					goto exit;
5888			}
5889			/* Trying to mismatch two different style of locks with the same process id bad! */
5890			if (np->f_smbflock->fl_type != ap->a_fl->l_type) {
5891				error = ENOTSUP;
5892				goto exit;
5893			}
5894			/*
5895			 * We know they have the same lock style from above, but they are
5896			 * asking for two exclusive. So from Terry comments it looks like
5897			 * this is ok.  Here's the issue: because what they are doing is
5898			 * upgrading an exclusive lock to an exclusive lock in the process
5899			 * that holds the previous lock, there are _not_ multiple locks
5900			 * involved; there's only the first lock and the lock that replaces
5901			 * it.
5902			 */
5903			if (np->f_smbflock->fl_type != F_WRLCK) {
5904				/*
5905				 * At no time are multiple exclusive locks allowed simultaneously
5906				 * on a file. So we can have only one refcnt. This is an upgrade
5907				 * not another lock.
5908				 */
5909			} else {
5910				np->f_smbflock->refcnt++;
5911			}
5912		} else {
5913			/*
5914			 * Radar 5572840
5915			 * F_WAIT is set we should sleep until the other flock
5916			 * gets free then to an upgrade or down grade. Not support
5917			 * with SMB yet.
5918			 */
5919			error = EWOULDBLOCK;
5920			goto exit;
5921		}
5922		break;
5923	case F_UNLCK:
5924		error = 0;
5925		if (! np->f_smbflock)	/* Got an  unlock and had no lock ignore */
5926			break;
5927		np->f_smbflock->refcnt--;
5928		/* remove the lock on the network and  */
5929		if (np->f_smbflock->refcnt <= 0) {
5930			error = smbfs_smb_lock(share, SMB_LOCK_RELEASE, np->f_fid, lck_pid,
5931								   start, len, timo, ap->a_context);
5932			if (error == 0) {
5933				SMB_FREE(np->f_smbflock, M_LOCKF);
5934				np->f_smbflock = NULL;
5935			}
5936		}
5937		break;
5938	default:
5939		error = EINVAL;
5940		break;
5941	}
5942exit:
5943	smb_share_rele(share, ap->a_context);
5944	smbnode_unlock(np);
5945
5946	SMB_LOG_KTRACE(SMB_DBG_ADVLOCK | DBG_FUNC_END, error, 0, 0, 0, 0);
5947	return (error);
5948}
5949
5950/*
5951 * The calling routine must hold a reference on the share
5952 */
5953static int
5954smbfs_pathcheck(struct smb_share *share, const char *name, size_t nmlen,
5955				uint32_t nameiop)
5956{
5957	const char *cp, *endp;
5958	int error;
5959
5960	/*
5961	 * We need to check the file name length. We now use ss_maxfilenamelen
5962	 * since that gives us a more accurate max file name length. If the
5963	 * server supports UNICODE we should do more checking. Since UTF8 can
5964	 * have three bytes per character just checking the length is not enough.
5965	 * We should convert it to UTF16 and see if the length is twice
5966	 * ss_maxfilenamelen.
5967	 *
5968	 */
5969	if ((uint32_t)nmlen > share->ss_maxfilenamelen) {
5970		if (SMB_UNICODE_STRINGS(SSTOVC(share))) {
5971			uint16_t *convbuf;
5972			size_t ntwrk_len;
5973			/*
5974			 * smb_strtouni needs an output buffer that is twice
5975			 * as large as the input buffer (name).
5976			 */
5977            SMB_MALLOC(convbuf, uint16_t *, nmlen * 2, M_SMBNODENAME, M_WAITOK);
5978			if (! convbuf)
5979				return ENAMETOOLONG;
5980			/*
5981			 * We need to get the UFT16 length, so just use smb_strtouni
5982			 * instead of smb_convert_to_network.
5983			 */
5984			ntwrk_len = smb_strtouni(convbuf, name,  nmlen,
5985						UTF_PRECOMPOSED | UTF_SFM_CONVERSIONS);
5986			SMB_FREE(convbuf, M_SMBNODENAME);
5987			if (ntwrk_len > (share->ss_maxfilenamelen * 2))
5988				return ENAMETOOLONG;
5989		} else {
5990			return ENAMETOOLONG;
5991		}
5992	} else if (! nmlen) {
5993		return ENAMETOOLONG;
5994	}
5995
5996	/* Check name only if CREATE, DELETE, or RENAME */
5997	if (nameiop == LOOKUP)
5998		return (0);
5999
6000	/*
6001	 * Winodws systems do not allow items that begin with "con" to be created.
6002	 * If this is not a UNIX server then stop the user from trying
6003	 * to create this file or folder. When trying to create a "con" folder or
6004	 * "con.xxx" file a windows system will report the following error:
6005	 * Cannot create or replace file: The filename you specified is too long.
6006	 * Specify a different filename.
6007	 *
6008	 * From my testing any name that matches "con" or begins with "con."
6009	 * should not be create.
6010	 *
6011	 * Should we be like windows and return ENAMETOOLONG or EACCES
6012	 */
6013	if ((! UNIX_SERVER(SSTOVC(share))) && CON_FILENAME(name, nmlen)) {
6014		if ((nmlen == 3) || ((nmlen > 3) && (*(name+3) == '.')))
6015			return (ENAMETOOLONG);
6016	}
6017
6018	/* If the server supports UNICODE then we are done checking the name. */
6019	if (SMB_UNICODE_STRINGS(SSTOVC(share)))
6020		return (0);
6021
6022	/*
6023	 * Normally, we'd return EINVAL when the name is syntactically invalid,
6024	 * but ENAMETOOLONG makes it clear that the name is the problem (and
6025	 * allows Carbon to return a more meaningful error).
6026	 */
6027	error = ENAMETOOLONG;
6028
6029	/*
6030	 * Note: This code does not prevent the smb file system client
6031	 * from creating filenames which are difficult to use with
6032	 * other clients. For example, you can create "  foo  " or
6033	 * "foo..." which cannot be moved, renamed, or deleted by some
6034	 * other clients.
6035	 */
6036
6037	/* check for illegal characters, if the server does not support UNICODE */
6038	for (cp = name, endp = name + nmlen; cp < endp; ++cp) {
6039		/*
6040		 * The set of illegal characters in long names is the same as
6041		 * 8.3 except the characters 0x20, 0x2b, 0x2c, 0x3b, 0x3d, 0x5b,
6042		 * and 0x5d are now legal, and the restrictions on periods was
6043		 * removed.
6044		 */
6045		switch (*cp) {
6046			case 0x20:	/* space */
6047			case 0x2B:	/* +     */
6048			case 0x2C:	/* ,     */
6049			case 0x3B:	/* ;     */
6050			case 0x3D:	/* =     */
6051			case 0x5B:	/* [     */
6052			case 0x5D:	/* ]     */
6053				break;
6054			case 0x22:	/* "     */
6055			case 0x2A:	/* *     */
6056			case 0x2F:	/* /     */
6057			case 0x3A:	/* :     */
6058			case 0x3C:	/* <     */
6059			case 0x3E:	/* >     */
6060			case 0x3F:	/* ?     */
6061			case 0x5C:	/* \     */
6062			case 0x7C:	/* |     */
6063				/* illegal character found */
6064				return (error);
6065				break;
6066			default:
6067				break;
6068		}
6069	}
6070	return (0);
6071}
6072
6073/*
6074 * smbfs_vnop_lookup
6075 *
6076 * struct vnodeop_desc *a_desc;
6077 * vnode_t a_dvp;
6078 * vnode_t *a_vpp;
6079 * struct componentname *a_cnp;
6080 * vfs_context_t a_context;
6081 */
6082static int
6083smbfs_vnop_lookup(struct vnop_lookup_args *ap)
6084{
6085	vfs_context_t context = ap->a_context;
6086	vnode_t dvp = ap->a_dvp;
6087	vnode_t *vpp = ap->a_vpp;
6088	vnode_t vp;
6089	struct smbnode *dnp = NULL;
6090	struct mount *mp = vnode_mount(dvp);
6091	struct smb_share *share = NULL;
6092	struct componentname *cnp = ap->a_cnp;
6093	const char *name = cnp->cn_nameptr;
6094	uint32_t flags = cnp->cn_flags;
6095	uint32_t nameiop = cnp->cn_nameiop;
6096	size_t nmlen = cnp->cn_namelen;
6097	struct smbfattr fattr, *fap = NULL;
6098	int wantparent, error, islastcn, isdot = FALSE;
6099	int parent_locked = FALSE;
6100
6101	/*
6102	 * We may want to move smbfs_pathcheck here, but we really should never
6103	 * find a bad name in the name cache lookup.
6104	 */
6105	if (!vnode_isdir(dvp))
6106		return (ENOTDIR);
6107
6108	if ((flags & ISDOTDOT) && vnode_isvroot(dvp)) {
6109		SMBERROR("invalid '..'\n");
6110		return (EIO);
6111	}
6112
6113	islastcn = (flags & ISLASTCN) ? TRUE : FALSE;
6114	if (islastcn && vfs_isrdonly(mp) && nameiop != LOOKUP)
6115		return (EROFS);
6116
6117    SMB_LOG_KTRACE(SMB_DBG_LOOKUP | DBG_FUNC_START,
6118                   VTOSMB(dvp)->d_fid, 0, 0, 0, 0);
6119
6120	wantparent = (flags & (LOCKPARENT|WANTPARENT)) ? TRUE : FALSE;
6121
6122	share = smb_get_share_with_reference(VTOSMBFS(dvp));
6123
6124	/*
6125	 * We need to make sure the negative name cache gets updated if
6126	 * needed. So if the parents cache has expired, then update the
6127	 * the parent's cache. This will cause the negative name cache to
6128	 * be flush if the parent's modify time has changed.
6129	 */
6130	if (smbnode_lock(VTOSMB(dvp), SMBFS_EXCLUSIVE_LOCK) == 0) {
6131		VTOSMB(dvp)->n_lastvop = smbfs_vnop_lookup;
6132		if (VTOSMB(dvp)->n_flag & NNEGNCENTRIES) {
6133			/* ignore any errors here we will catch them later */
6134			(void)smbfs_update_cache(share, dvp, NULL, context);
6135		}
6136		smbnode_unlock(VTOSMB(dvp));	/* Release the smbnode lock */
6137	}
6138
6139	*vpp = NULLVP;
6140	error = cache_lookup(dvp, vpp, cnp);
6141
6142    SMB_LOG_KTRACE(SMB_DBG_LOOKUP | DBG_FUNC_NONE,
6143                   0xabc001, error, 0, 0, 0);
6144
6145	switch (error) {
6146		case ENOENT:	/* negative cache entry */
6147			goto skipLookup;
6148		case 0:		/* cache miss */
6149			break;
6150		case -1:	/* cache hit */
6151			/*
6152			 * On CREATE we can't trust a cache hit as if it is stale
6153			 * and the object doesn't exist on the server returning zero
6154			 * here would cause the vfs layer to, for instance, EEXIST
6155			 * the mkdir.
6156			 */
6157			if (nameiop != CREATE) {
6158				error = 0;
6159				/* Check to see it the node's meta cache needs to be update */
6160				if (smbnode_lock(VTOSMB(*vpp), SMBFS_EXCLUSIVE_LOCK) == 0) {
6161					VTOSMB(*vpp)->n_lastvop = smbfs_vnop_lookup;
6162					error = smbfs_update_cache(share, *vpp, NULL, context);
6163					smbnode_unlock(VTOSMB(*vpp));	/* Release the smbnode lock */
6164				}
6165				/*
6166				 * At this point we only care if it exist or not so any other
6167				 * error should just get ignored
6168				 */
6169				if (error != ENOENT) {
6170					error =  0;
6171					goto done;
6172				}
6173				/*
6174				 * The item we had, no longer exists so fall through and see if
6175				 * it exist as a different item
6176				 */
6177			}
6178			if (*vpp) {
6179				cache_purge(*vpp);
6180				vnode_put(*vpp);
6181				*vpp = NULLVP;
6182			}
6183			break;
6184		default:	/* unknown & unexpected! */
6185			SMBWARNING("cache_lookup error=%d\n", error);
6186			goto done;
6187	}
6188
6189	/*
6190	 * entry is not in the name cache
6191	 *
6192	 * validate syntax of name.  ENAMETOOLONG makes it clear the name
6193	 * is the problem
6194	 */
6195	error = smbfs_pathcheck(share, cnp->cn_nameptr, cnp->cn_namelen, nameiop);
6196	if (error) {
6197		SMBWARNING("warning: bad filename %s\n", name);
6198		goto done;
6199	}
6200	dnp = VTOSMB(dvp);
6201
6202	/* lock the parent while we go look for the item on server */
6203	if (smbnode_lock(dnp, SMBFS_EXCLUSIVE_LOCK) != 0) {
6204		error = ENOENT;
6205		goto skipLookup;
6206	}
6207	parent_locked = TRUE;
6208	dnp->n_lastvop = smbfs_vnop_lookup;
6209
6210	isdot = (nmlen == 1 && name[0] == '.');
6211	fap = &fattr;
6212	/*
6213	 * This can allocate a new "name" do not return before the end of the
6214	 * routine from here on.
6215	 */
6216	if (flags & ISDOTDOT) {
6217        lck_rw_lock_shared(&dnp->n_parent_rwlock);
6218		error = smbfs_lookup(share, dnp->n_parent, NULL, NULL, fap, context);
6219        lck_rw_unlock_shared(&dnp->n_parent_rwlock);
6220	}
6221    else {
6222		error = smbfs_lookup(share, dnp, &name, &nmlen, fap, context);
6223	}
6224    SMB_LOG_KTRACE(SMB_DBG_LOOKUP | DBG_FUNC_NONE,
6225                   0xabc002, error, 0, 0, 0);
6226
6227	/*
6228	 * We use to unlock the parent here, but we really need it locked
6229	 * until after we do the smbfs_nget calls.
6230	 */
6231	/*
6232	 * We didn't find it and this is not a CREATE or RENAME operation so
6233	 * add it to the negative name cache.
6234	 */
6235	if ((error == ENOENT) && (cnp->cn_flags & MAKEENTRY) &&
6236		(!(((nameiop == CREATE) || (nameiop == RENAME)) && islastcn))) {
6237		/* add a negative entry in the name cache */
6238		cache_enter(dvp, NULL, cnp);
6239		dnp->n_flag |= NNEGNCENTRIES;
6240	}
6241
6242skipLookup:
6243	if (error) {
6244		/*
6245		 * note the EJUSTRETURN code in lookup()
6246		 */
6247		if (((nameiop == CREATE) || (nameiop == RENAME)) &&
6248			(error == ENOENT) && islastcn) {
6249			error = EJUSTRETURN;
6250		}
6251	} else if ((nameiop == RENAME) && islastcn && wantparent) {
6252		if (isdot) {
6253			error = EISDIR;
6254		} else {
6255			error = smbfs_nget(share, mp,
6256                               dvp, name, nmlen,
6257                               fap, &vp,
6258                               0, SMBFS_NGET_CREATE_VNODE,
6259                               context);
6260			if (!error) {
6261				smbnode_unlock(VTOSMB(vp));	/* Release the smbnode lock */
6262				*vpp = vp;
6263			}
6264		}
6265	} else if ((nameiop == DELETE) && islastcn) {
6266		if (isdot) {
6267			error = vnode_get(dvp);
6268			if (!error)
6269				*vpp = dvp;
6270		} else {
6271			error = smbfs_nget(share, mp,
6272                               dvp, name, nmlen,
6273                               fap, &vp,
6274                               0, SMBFS_NGET_CREATE_VNODE,
6275                               context);
6276			if (!error) {
6277				smbnode_unlock(VTOSMB(vp));	/* Release the smbnode lock */
6278				*vpp = vp;
6279			}
6280		}
6281	} else if (flags & ISDOTDOT) {
6282        if (dvp) {
6283            lck_rw_lock_shared(&VTOSMB(dvp)->n_parent_rwlock);
6284            if (VTOSMB(dvp)->n_parent) {
6285                vp = VTOSMB(dvp)->n_parent->n_vnode;
6286                error = vnode_get(vp);
6287                if (!error)
6288                    *vpp = vp;
6289            }
6290            lck_rw_unlock_shared(&VTOSMB(dvp)->n_parent_rwlock);
6291        }
6292	} else if (isdot) {
6293		error = vnode_get(dvp);
6294		if (!error)
6295			*vpp = dvp;
6296	} else {
6297		error = smbfs_nget(share, mp,
6298                           dvp, name, nmlen,
6299                           fap, &vp,
6300                           cnp->cn_flags, SMBFS_NGET_CREATE_VNODE,
6301                           context);
6302		if (!error) {
6303			smbnode_unlock(VTOSMB(vp));	/* Release the smbnode lock */
6304			*vpp = vp;
6305		}
6306	}
6307	if (name != cnp->cn_nameptr) {
6308		SMB_FREE(name, M_SMBNODENAME);
6309	}
6310	/* If the parent node is still lock then unlock it here. */
6311	if (parent_locked && dnp)
6312		smbnode_unlock(dnp);
6313done:
6314	smb_share_rele(share, context);
6315
6316    SMB_LOG_KTRACE(SMB_DBG_LOOKUP | DBG_FUNC_END, error, 0, 0, 0, 0);
6317	return (error);
6318}
6319
6320/*
6321 * smbfs_vnop_offtoblk
6322 *
6323 * vnode_t a_vp;
6324 * off_t a_offset;
6325 * daddr64_t *a_lblkno;
6326 * vfs_context_t a_context;
6327 *
6328 * ftoblk converts a file offset to a logical block number
6329 */
6330static int
6331smbfs_vnop_offtoblk(struct vnop_offtoblk_args *ap)
6332{
6333	*ap->a_lblkno = ap->a_offset / PAGE_SIZE_64;
6334	return (0);
6335}
6336
6337/*
6338 * smbfs_vnop_blktooff
6339 *
6340 * vnode_t a_vp;
6341 * off_t a_offset;
6342 * daddr64_t *a_lblkno;
6343 * off_t *a_offset;
6344 * vfs_context_t a_context;
6345 *
6346 * blktooff converts a logical block number to a file offset
6347 */
6348static int
6349smbfs_vnop_blktooff(struct vnop_blktooff_args *ap)
6350{
6351	*ap->a_offset = (off_t)ap->a_lblkno * PAGE_SIZE_64;
6352	return (0);
6353}
6354
6355/*
6356 * smbfs_vnop_pagein
6357 *
6358 *  vnode_t 	a_vp,
6359 *  upl_t		a_pl,
6360 *  vm_offset_t	a_pl_offset,
6361 *  off_t		a_f_offset,
6362 *  size_t		a_size,
6363 *  int			a_flags
6364 *  vfs_context_t a_context;
6365 *
6366 * NOTE: We no longer take a node lock in this routine.
6367 */
6368static int
6369smbfs_vnop_pagein(struct vnop_pagein_args *ap)
6370{
6371	vnode_t vp = ap->a_vp;
6372	struct smb_share *share;
6373	size_t size = ap->a_size;
6374	off_t f_offset = ap->a_f_offset;
6375	struct smbnode *np;
6376	int error;
6377
6378    SMB_LOG_KTRACE(SMB_DBG_PAGE_IN | DBG_FUNC_START, 0, 0, 0, 0, 0);
6379
6380	np = VTOSMB(vp);
6381
6382	if ((size <= 0) || (f_offset < 0) || (f_offset >= (off_t)np->n_size) ||
6383		(f_offset & PAGE_MASK_64) || (size & PAGE_MASK)) {
6384		error = err_pagein(ap);	/* behave like the deadfs does */
6385        goto done;
6386	}
6387	share = smb_get_share_with_reference(VTOSMBFS(vp));
6388	/* Before trying the read see if the file needs to be reopened */
6389	error = smbfs_smb_reopen_file(share, np, ap->a_context);
6390	if (error) {
6391        lck_rw_lock_shared(&np->n_name_rwlock);
6392		SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
6393        lck_rw_unlock_shared(&np->n_name_rwlock);
6394
6395		/* Release the share reference before returning */
6396		smb_share_rele(share, ap->a_context);
6397		error = err_pagein(ap);	/* behave like the deadfs does */
6398		goto done;
6399	}
6400	/*
6401	 * The old code would check to see if the node smbfsIsCacheable. If not then
6402	 * it would try to invalidate the page to force the cluster code to get a
6403	 * new copy from disk/network. Talked this over with Joe and this is not
6404	 * really need.
6405	 *
6406	 * The smbfs_vnop_pagein will only be called for extents of pages that do
6407	 * NOT already exist in the cache. When the UPL is created, the pages are
6408	 * acquired and locked down for the 'holes' that exist in the cache. Once
6409	 * those pages are locked into the UPL, there can be no other path by which
6410	 * the pages can be made valid. So... no reason to flush pages in the range
6411	 * being passed into you and then on to cluster_pagein.
6412	 */
6413	error = cluster_pagein(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset,
6414						   (int)ap->a_size, (off_t)np->n_size, ap->a_flags);
6415	if (error) {
6416        lck_rw_lock_shared(&np->n_name_rwlock);
6417		SMB_LOG_IO("%s failed cluster_pagein with an error of %d\n", np->n_name, error);
6418        lck_rw_unlock_shared(&np->n_name_rwlock);
6419	}
6420	smb_share_rele(share, ap->a_context);
6421
6422done:
6423    SMB_LOG_KTRACE(SMB_DBG_PAGE_IN | DBG_FUNC_END, error, 0, 0, 0, 0);
6424    return (error);
6425}
6426
6427/*
6428 * smbfs_vnop_pageout
6429 *
6430 *  vnode_t 	a_vp,
6431 *  upl_t		a_pl,
6432 *  vm_offset_t	a_pl_offset,
6433 *  off_t		a_f_offset,
6434 *  size_t		a_size,
6435 *  int			a_flags
6436 *  vfs_context_t a_context;
6437 *
6438 * NOTE: We no longer take a node lock in this routine.
6439 *
6440 */
6441static int
6442smbfs_vnop_pageout(struct vnop_pageout_args *ap)
6443{
6444	vnode_t vp = ap->a_vp;
6445	struct smbnode *np;
6446	struct smb_share *share;
6447	upl_t pl = ap->a_pl;
6448	size_t size = ap->a_size;
6449	off_t f_offset = ap->a_f_offset;
6450	int error;
6451
6452	if (vnode_vfsisrdonly(vp))
6453		return(EROFS);
6454
6455    SMB_LOG_KTRACE(SMB_DBG_PAGE_OUT | DBG_FUNC_START, 0, 0, 0, 0, 0);
6456
6457	np = VTOSMB(vp);
6458
6459	if (pl == (upl_t)NULL)
6460		panic("smbfs_vnop_pageout: no upl");
6461
6462	if ((size <= 0) || (f_offset < 0) || (f_offset >= (off_t)np->n_size) ||
6463	    (f_offset & PAGE_MASK_64) || (size & PAGE_MASK)) {
6464		error = err_pageout(ap);
6465        goto done;
6466	}
6467	share = smb_get_share_with_reference(VTOSMBFS(vp));
6468	/* Before trying the write see if the file needs to be reopened */
6469	error = smbfs_smb_reopen_file(share, np, ap->a_context);
6470	if (error) {
6471        lck_rw_lock_shared(&np->n_name_rwlock);
6472		SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
6473        lck_rw_unlock_shared(&np->n_name_rwlock);
6474
6475		/* Release the share reference before returning */
6476		smb_share_rele(share, ap->a_context);
6477		error = err_pageout(ap);
6478        goto done;
6479	}
6480
6481	error = cluster_pageout(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset,
6482							(int)ap->a_size, (off_t)np->n_size, ap->a_flags);
6483	if (error) {
6484        lck_rw_lock_shared(&np->n_name_rwlock);
6485		SMB_LOG_IO("%s failed cluster_pageout with an error of %d\n",
6486				   np->n_name, error);
6487        lck_rw_unlock_shared(&np->n_name_rwlock);
6488	}
6489
6490	smb_share_rele(share, ap->a_context);
6491	/* If we can get the parent vnode, reset its meta data cache timer. */
6492	if (vnode_isnamedstream(vp)) {
6493		vnode_t parent_vp = vnode_getparent(vp);
6494		if (parent_vp) {
6495			VTOSMB(parent_vp)->attribute_cache_timer = 0;
6496			vnode_put(parent_vp);
6497		}
6498	}
6499
6500done:
6501    SMB_LOG_KTRACE(SMB_DBG_PAGE_OUT | DBG_FUNC_END, error, 0, 0, 0, 0);
6502    return (error);
6503}
6504
6505/*
6506 * smbfs_vnop_copyfile
6507 *
6508 * vnode_t a_fvp;
6509 * vnode_t a_tdvp;
6510 * vnode_t a_tvp;
6511 * struct componentname *a_tcnp;
6512 * int a_flags;
6513 * vfs_context_t a_context;
6514 */
6515static int
6516smbfs_vnop_copyfile(struct vnop_copyfile_args *ap)
6517{
6518	vnode_t 	fvp = ap->a_fvp;
6519	vnode_t 	tvp = ap->a_tvp;
6520	vnode_t 	tdvp = ap->a_tdvp;
6521	struct smbmount *smp = VFSTOSMBFS(vnode_mount(fvp));
6522	struct smb_share *share = NULL;
6523	struct componentname *tcnp = ap->a_tcnp;
6524	struct smbnode *fnp = NULL;
6525	struct smbnode *tdnp = NULL;
6526	struct smbnode *tnp = NULL;
6527	int error = 0, vtype, need_unlock = 0;
6528
6529    /* VFS checks the following before calling us:
6530     *
6531     * tvp exists AND (ap->flags & CPF_OVERWRITE)
6532     * fvp AND tvp are not directories
6533     * KAUTH_VNODE_ADD_FILE authorized on tdvp
6534     * fvp != tvp
6535     * fvp != tdvp
6536     */
6537
6538    SMB_LOG_KTRACE(SMB_DBG_COPYFILE | DBG_FUNC_START, 0, 0, 0, 0, 0);
6539
6540    /* Check if this is an SMB 2/3 server (need COPYCHUNK IOCTL) */
6541    share = smb_get_share_with_reference(smp);
6542    if (!SSTOVC(share)->vc_flags & SMBV_SMB2) {
6543        SMBERROR("copyfile not supported on this server.\n");
6544        error = ENOTSUP;
6545        goto out;
6546    }
6547
6548	/* Check for cross-device copyfile */
6549	if ((vnode_mount(fvp) != vnode_mount(tdvp)) ||
6550		(tvp && (vnode_mount(fvp) != vnode_mount(tvp)))) {
6551        SMBERROR("cross-device copyfile not supported.\n");
6552		error = EXDEV;
6553        goto out;
6554    }
6555
6556    /* source file must be a directory, symbolic link, or regular file */
6557	vtype = vnode_vtype(fvp);
6558	if ( (vtype != VDIR) && (vtype != VREG) && (vtype != VLNK) ) {
6559        SMBERROR("copyfile not supported on vtype: %d\n", vtype);
6560		error = EINVAL;
6561        goto out;
6562    }
6563
6564    fnp = VTOSMB(fvp);
6565	tdnp = VTOSMB(tdvp);
6566    tnp = (tvp == NULL) ? NULL : VTOSMB(tvp);
6567
6568    /* Lock source file and target directory */
6569    smbnode_lockpair(fnp, tdnp, SMBFS_EXCLUSIVE_LOCK);
6570    need_unlock = 1;
6571
6572	fnp->n_lastvop = smbfs_vnop_copyfile;
6573	tdnp->n_lastvop = smbfs_vnop_copyfile;
6574	if (tnp != NULL)
6575		tnp->n_lastvop = smbfs_vnop_copyfile;
6576
6577	/*
6578	 * Do the copyfile operation.
6579	 */
6580    error = smb2fs_smb_copyfile(share, fnp, tdnp, tcnp->cn_nameptr,
6581                                tcnp->cn_namelen, ap->a_context);
6582    if (error) {
6583        SMBERROR("smb2fs_smb_copyfile returned: %d\n", error);
6584        goto out;
6585    }
6586
6587	smbfs_attr_touchdir(tdnp, (share->ss_fstype == SMB_FS_FAT));
6588
6589	/* blow away statfs cache */
6590    smp->sm_statfstime = 0;
6591
6592    /* Invalidate negative cache entries in destination dir */
6593    if (tdnp->n_flag & NNEGNCENTRIES) {
6594        tdnp->n_flag &= ~NNEGNCENTRIES;
6595        cache_purge_negatives(tdvp);
6596    }
6597
6598out:
6599	/* We only have a share if we obtain a reference on it, so release it */
6600	if (share) {
6601		smb_share_rele(share, ap->a_context);
6602	}
6603
6604    if (need_unlock) {
6605        smbnode_unlockpair(fnp, tdnp);
6606    }
6607
6608    SMB_LOG_KTRACE(SMB_DBG_COPYFILE | DBG_FUNC_END, error, 0, 0, 0, 0);
6609	return (error);
6610}
6611
6612static uint32_t emptyfinfo[8] = {0};
6613/*
6614 * DefaultFillAfpInfo
6615 *
6616 * Given a buffer fill in the default AfpInfo values.
6617 */
6618static void
6619DefaultFillAfpInfo(uint8_t *afpinfo)
6620{
6621	int ii = 0;
6622	bzero(afpinfo, AFP_INFO_SIZE);
6623		/* Signature is a DWORD. Must be *(PDWORDD)"AFP" */
6624	afpinfo[ii++] = 'A';
6625	afpinfo[ii++] = 'F';
6626	afpinfo[ii++] = 'P';
6627	afpinfo[ii++] = 0;
6628		/* Version is a DWORD. Must be 0x00010000 (byte swapped) */
6629	afpinfo[ii++] = 0;
6630	afpinfo[ii++] = 0;
6631	afpinfo[ii++] = 0x01;
6632	afpinfo[ii++] = 0;
6633		/* Reserved1 is a DWORD */
6634	ii += 4;
6635	/*
6636	 * Backup time is a DWORD. Backup time for the file/dir. Not set equals
6637	 * 0x80010000 (byte swapped)
6638	 */
6639	afpinfo[ii++] = 0;
6640	afpinfo[ii++] = 0;
6641	afpinfo[ii++] = 0;
6642	afpinfo[ii] = 0x80;
6643	/* Finder Info is 32 bytes. Calling process fills this in */
6644	/* ProDos Info is 6 bytes. Leave set to zero? */
6645	/* Reserved2 is 6 bytes */
6646}
6647
6648/*
6649 * xattr2sfm
6650 *
6651 * See if this xattr is really the resource fork or the finder info stream. If so
6652 * return the correct streams name otherwise just return the name passed to us.
6653 */
6654static const char *
6655xattr2sfm(const char *xa, enum stream_types *stype)
6656{
6657	/* Never let them use the SFM Stream Names */
6658	if (!bcmp(xa, SFM_RESOURCEFORK_NAME, sizeof(SFM_RESOURCEFORK_NAME))) {
6659		return(NULL);
6660	}
6661	if (!bcmp(xa, SFM_FINDERINFO_NAME, sizeof(SFM_FINDERINFO_NAME))) {
6662		return(NULL);
6663	}
6664	if (!bcmp(xa, SFM_DESKTOP_NAME, sizeof(SFM_DESKTOP_NAME))) {
6665		return(NULL);
6666	}
6667	if (!bcmp(xa, SFM_IDINDEX_NAME, sizeof(SFM_IDINDEX_NAME))) {
6668		return(NULL);
6669	}
6670
6671	if (!bcmp(xa, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME))) {
6672		*stype = kResourceFrk;
6673		return (SFM_RESOURCEFORK_NAME);
6674	}
6675	if (!bcmp(xa, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME))) {
6676		*stype = kFinderInfo;
6677		return (SFM_FINDERINFO_NAME);
6678	}
6679	*stype = kExtendedAttr;
6680	return (xa);
6681}
6682
6683/*
6684 * smbfs_vnop_setxattr
6685 *
6686 *	vnode_t a_vp;
6687 *	int8_t * a_name;
6688 *	uio_t a_uio;
6689 *	int32_t a_options;
6690 *	vfs_context_t a_context;
6691 */
6692static int
6693smbfs_vnop_setxattr(struct vnop_setxattr_args *ap)
6694{
6695	vnode_t vp = ap->a_vp;
6696	const char *sfmname;
6697	int error = 0;
6698	SMBFID fid = 0;
6699	uint32_t rights = SMB2_FILE_WRITE_DATA;
6700	struct smbnode *np = NULL;
6701	struct smb_share *share = NULL;
6702	enum stream_types stype = kNoStream;
6703	uint32_t	open_disp = 0;
6704	uio_t		afp_uio = NULL;
6705	uint8_t	afpinfo[60];
6706	struct smbfattr fattr;
6707
6708	DBG_ASSERT(!vnode_isnamedstream(vp));
6709
6710	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
6711		return (error);
6712
6713    SMB_LOG_KTRACE(SMB_DBG_SET_XATTR | DBG_FUNC_START, 0, 0, 0, 0, 0);
6714
6715	np = VTOSMB(vp);
6716	np->n_lastvop = smbfs_vnop_setxattr;
6717	share = smb_get_share_with_reference(VTOSMBFS(vp));
6718
6719	/*
6720	 * FILE_NAMED_STREAMS tells us the server supports streams.
6721	 * NOTE: This flag may have been overwriten by us in smbfs_mount. The default
6722	 * is for streams to be turn off. See the smbfs_mount for more details.
6723	 */
6724	if (!(share->ss_attributes & FILE_NAMED_STREAMS)) {
6725		error = ENOTSUP;
6726		goto exit;
6727	}
6728
6729	/* You cant have both of these set at the same time. */
6730	if ( (ap->a_options & XATTR_CREATE) && (ap->a_options & XATTR_REPLACE) ) {
6731		error = EINVAL;
6732		goto exit;
6733	}
6734
6735	/* SMB doesn't support having a slash in the xattr name */
6736	if (strchr(ap->a_name, '/')) {
6737		error = EINVAL;
6738
6739        lck_rw_lock_shared(&np->n_name_rwlock);
6740        SMBWARNING("Slash in xattr name not allowed: error %d %s:%s\n", error,
6741				   np->n_name, ap->a_name);
6742        lck_rw_unlock_shared(&np->n_name_rwlock);
6743		goto exit;
6744	}
6745	sfmname = xattr2sfm(ap->a_name, &stype);
6746	if (!sfmname) {
6747		error = EINVAL;
6748		goto exit;
6749	}
6750
6751	/*
6752	 * Need to add write attributes if we want to reset the modify time. We never do this
6753	 * for the resource fork. The file manager expects the modify time to change if the
6754	 * resource fork changes.
6755	 */
6756	if ((stype & kResourceFrk) != kResourceFrk)
6757		rights |= SMB2_FILE_WRITE_ATTRIBUTES;
6758
6759	/*
6760	 * We treat finder info differently than any other EA/Stream. Because of
6761	 * SFM we need to do things a little different. Remember the AFPInfo stream
6762	 * has more information in it than just the finder info. WARNING: SFM can
6763	 * get very confused if you do not handle this correctly!
6764	 */
6765	if (stype & kFinderInfo) {
6766		uint8_t finfo[FINDERINFOSIZE];
6767		time_t attrtimeo;
6768		struct timespec ts;
6769		size_t sizep;
6770		int len = (int)uio_resid(ap->a_uio);
6771
6772		/* Can't be larger that 32 bytes */
6773		if (len > FINDERINFOSIZE) {
6774			error = EINVAL;
6775			goto exit;
6776		}
6777
6778		error = uiomove((void *)finfo, len, ap->a_uio);
6779		if (error) {
6780			goto exit;
6781        }
6782
6783		SMB_CACHE_TIME(ts, np, attrtimeo);
6784		/*
6785		 * The Finder Info cache hasn't expired so check to see if they are
6786		 * setting it to something different or the same. If the same then skip
6787		 * setting it, this is what AFP does.
6788		 */
6789		if ((ts.tv_sec - np->finfo_cache_timer) <= attrtimeo) {
6790			if (bcmp(np->finfo, finfo, sizeof(finfo)) == 0)
6791				goto exit;
6792		}
6793
6794		/* We want to read also in this case.  */
6795		rights |= SMB2_FILE_READ_DATA;
6796
6797		/* Create a dummy uio structure */
6798		afp_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
6799		if (afp_uio)
6800			error = uio_addiov( afp_uio, CAST_USER_ADDR_T(afpinfo), sizeof(afpinfo));
6801		else
6802			error = ENOMEM;
6803		if (error)
6804			goto exit;
6805
6806		/* Now set the default afp info buffer */
6807		DefaultFillAfpInfo(afpinfo);
6808
6809		/* Open and read the data in, if an empty file we will still get an fid */
6810		error = smbfs_smb_openread(share, np,
6811                                   &fid, rights,
6812                                   afp_uio, &sizep, sfmname,
6813                                   &ts, ap->a_context);
6814
6815		SMB_LOG_KTRACE(SMB_DBG_SET_XATTR | DBG_FUNC_NONE,
6816                       0xabc001, error, stype, 0, 0);
6817
6818        /* Replace the finder info with the data that was passed down. */
6819		if (!error) {
6820			bcopy((void *)finfo, (void *)&afpinfo[AFP_INFO_FINDER_OFFSET], len);
6821			uio_reset(afp_uio, 0, UIO_SYSSPACE, UIO_WRITE );
6822			error = uio_addiov( afp_uio, CAST_USER_ADDR_T(afpinfo), sizeof(afpinfo));
6823		}
6824		if (error)
6825			goto out;
6826
6827		/* Truncate the stream if there is anything in it, this will wake up SFM */
6828		if (sizep && (VTOSMBFS(vp)->sm_flags & MNT_IS_SFM_VOLUME))	{
6829			 /* Ignore any errors, write will catch them */
6830			(void)smbfs_smb_seteof(share, fid, 0, ap->a_context);
6831		}
6832
6833		/* Now we can write the afp info back out with the new finder information */
6834		if (!error) {
6835			error = smb_smb_write(share, fid, afp_uio, 0, ap->a_context);
6836            SMB_LOG_KTRACE(SMB_DBG_SET_XATTR | DBG_FUNC_NONE,
6837                           0xabc002, error, stype, 0, 0);
6838		}
6839
6840		/*
6841		 * Try to set the modify time back to the original time, ignore any
6842		 * errors. Since we are using the open stream file descriptor to change
6843		 * the time remove the directory attribute bit if set.
6844		 */
6845		(void)smbfs_smb_setfattrNT(share, (np->n_dosattr & ~SMB_EFA_DIRECTORY),
6846								   fid, NULL, &ts, NULL, ap->a_context);
6847		/* Reset our cache timer and copy the new data into our cache */
6848		if (!error) {
6849			nanouptime(&ts);
6850			np->finfo_cache_timer = ts.tv_sec;
6851			bcopy((void *)&afpinfo[AFP_INFO_FINDER_OFFSET], np->finfo,
6852				  sizeof(np->finfo));
6853		}
6854		goto out;
6855	}
6856
6857	switch(ap->a_options & (XATTR_CREATE | XATTR_REPLACE)) {
6858		case XATTR_CREATE:	/* set the value, fail if attr already exists */
6859            /* if exists fail else create it */
6860			open_disp = FILE_CREATE;
6861			break;
6862		case XATTR_REPLACE:	/* set the value, fail if attr does not exist */
6863            /* if exists overwrite item else fail */
6864			open_disp = FILE_OVERWRITE;
6865			break;
6866		default:
6867			if ((stype & kResourceFrk) == kResourceFrk) {
6868				/* if resource fork then if it exists open it else create it */
6869				open_disp = FILE_OPEN_IF;
6870			} else {
6871				/* if anything else then if it exists overwrite it else create it */
6872				open_disp = FILE_OVERWRITE_IF;
6873			}
6874			break;
6875	}
6876
6877	/* Open/create the stream */
6878	error = smbfs_smb_create(share, np, sfmname,
6879							 strnlen(sfmname, share->ss_maxfilenamelen+1),
6880							 rights, &fid, open_disp, 1, &fattr, ap->a_context);
6881    SMB_LOG_KTRACE(SMB_DBG_SET_XATTR | DBG_FUNC_NONE,
6882                   0xabc003, error, stype, 0, 0);
6883	if (error) {
6884		goto exit;
6885	}
6886
6887	/* Now write out the stream data */
6888	error = smb_smb_write(share, fid, ap->a_uio, 0, ap->a_context);
6889    SMB_LOG_KTRACE(SMB_DBG_SET_XATTR | DBG_FUNC_NONE,
6890                   0xabc004, error, stype, 0, 0);
6891
6892	/*
6893	 * %%%
6894	 * Should we reset the modify time back to the original time? Never for the
6895	 * resource fork, but what about EAs? Could be a performance issue, really
6896	 * need a clearer message from the rest of the file system team.
6897	 *
6898	 * For now try to set the modify time back to the original time, ignore any
6899	 * errors. Since we are using the open stream file descriptor to change the
6900	 * time remove the directory attribute bit if set.
6901	 */
6902	if ((stype & kResourceFrk) != kResourceFrk) {
6903		(void)smbfs_smb_setfattrNT(share, (np->n_dosattr & ~SMB_EFA_DIRECTORY),
6904								   fid, NULL, &np->n_mtime, NULL, ap->a_context);
6905	}
6906
6907out:
6908	if (fid != 0) {
6909		(void)smbfs_smb_close(share, fid, ap->a_context);
6910    }
6911
6912exit:
6913	if (afp_uio)
6914		uio_free(afp_uio);
6915
6916	if (error == ENOENT)
6917		error = ENOATTR;
6918
6919	/* Check to see if its a normal error */
6920	if (error && (error != ENOTSUP) && (error != ENOATTR)) {
6921        lck_rw_lock_shared(&np->n_name_rwlock);
6922		SMBWARNING("error %d %s:%s\n", error, np->n_name, ap->a_name);
6923        lck_rw_unlock_shared(&np->n_name_rwlock);
6924
6925		/* Always make sure its a legit error, see man listxattr */
6926		if ((error != EROFS) && (error != EPERM) && (error != EINVAL) &&
6927			(error != ENOTDIR) && (error != EACCES) && (error != ELOOP) &&
6928			(error != EFAULT) && (error != EIO) && (error != ENAMETOOLONG) &&
6929			(error != EEXIST) && (error != ERANGE) &&
6930			(error != E2BIG) && (error != ENOSPC))
6931			error = EIO;	/* Not sure what else to do here */
6932	}
6933	if (!error) {
6934		/* We create a named stream, so remove the no stream flag  */
6935		np->n_fstatus &= ~kNO_SUBSTREAMS;
6936	}
6937	smb_share_rele(share, ap->a_context);
6938	smbnode_unlock(np);
6939
6940	SMB_LOG_KTRACE(SMB_DBG_SET_XATTR | DBG_FUNC_END, error, 0, 0, 0, 0);
6941    return (error);
6942}
6943
6944/*
6945 * smbfs_vnop_listxattr
6946 *
6947 *	vnode_t a_vp;
6948 *	uio_t a_uio;
6949 *	size_t *a_size;
6950 *	int32_t a_options;
6951 *	vfs_context_t a_context;
6952 */
6953static int
6954smbfs_vnop_listxattr(struct vnop_listxattr_args *ap)
6955{
6956	vnode_t vp = ap->a_vp;
6957	uio_t uio = ap->a_uio;
6958	size_t *sizep = ap->a_size;
6959	struct smbnode *np = NULL;
6960	struct smb_share *share = NULL;
6961	int error = 0;
6962    uint32_t stream_flags = 0;
6963    enum vtype vnode_type = VREG;
6964
6965	DBG_ASSERT(!vnode_isnamedstream(vp));
6966
6967	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
6968		return (error);
6969
6970    SMB_LOG_KTRACE(SMB_DBG_LIST_XATTR | DBG_FUNC_START, 0, 0, 0, 0, 0);
6971
6972	np = VTOSMB(vp);
6973	np->n_lastvop = smbfs_vnop_listxattr;
6974	share = smb_get_share_with_reference(VTOSMBFS(vp));
6975
6976	/*
6977	 * FILE_NAMED_STREAMS tells us the server supports streams.
6978	 * NOTE: This flag may have been overwriten by us in smbfs_mount. The default
6979	 * is for streams to be turn off. See the smbfs_mount for more details.
6980	 */
6981	if (!(share->ss_attributes & FILE_NAMED_STREAMS)) {
6982		error = ENOTSUP;
6983		goto exit;
6984	}
6985
6986	if (np->n_fstatus & kNO_SUBSTREAMS) {
6987		error = ENOATTR;
6988		goto exit;
6989	}
6990
6991    /* For listing xattrs, create is done on the item, not the stream */
6992    if ((np) && (np->n_vnode)) {
6993        /* Use vnode to determine type */
6994        vnode_type = vnode_isdir(np->n_vnode) ? VDIR : VREG;
6995    }
6996
6997	error = smbfs_smb_qstreaminfo(share, np, vnode_type,
6998                                  NULL, 0,
6999                                  NULL,
7000                                  uio, sizep,
7001                                  NULL, NULL,
7002                                  &stream_flags, NULL,
7003                                  ap->a_context);
7004
7005exit:
7006	/*
7007	 * From the man pages: If no accessible extended attributes are associated
7008	 * with the given path or fd, the function returns zero.
7009	*/
7010	if (error == ENOATTR)
7011		error = 0;
7012
7013	/* Check to see if its a normal error */
7014	if (error && (error != ENOTSUP)) {
7015        lck_rw_lock_shared(&np->n_name_rwlock);
7016		SMBWARNING("error %d %s\n", error, np->n_name);
7017        lck_rw_unlock_shared(&np->n_name_rwlock);
7018
7019		/* Always make sure its a legit error, see man listxattr */
7020		if ((error != ERANGE) && (error != EPERM) && (error != EINVAL) &&
7021			(error != ENOTDIR) && (error != EACCES) && (error != ELOOP) &&
7022			(error != EFAULT) && (error != EIO))
7023			error = 0;	/* Just pretend it doesn't exist */
7024	}
7025	smb_share_rele(share, ap->a_context);
7026	smbnode_unlock(np);
7027
7028	SMB_LOG_KTRACE(SMB_DBG_LIST_XATTR | DBG_FUNC_END, error, 0, 0, 0, 0);
7029    return (error);
7030}
7031
7032/*
7033 * vnop_removexattr_args
7034 *
7035 *	vnode_t a_vp;
7036 *	int8_t * a_name;
7037 *	int32_t a_options;
7038 *	vfs_context_t a_context;
7039 */
7040static int
7041smbfs_vnop_removexattr(struct vnop_removexattr_args *ap)
7042{
7043	vnode_t vp = ap->a_vp;
7044	const char *sfmname;
7045	int error = 0, saved_error = 0;
7046	struct smbnode *np = NULL;
7047	struct smb_share *share = NULL;
7048	enum stream_types stype = kNoStream;
7049	struct timespec ts;
7050
7051	DBG_ASSERT(!vnode_isnamedstream(vp));
7052
7053	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
7054		return (error);
7055
7056	SMB_LOG_KTRACE(SMB_DBG_RM_XATTR | DBG_FUNC_START, 0, 0, 0, 0, 0);
7057
7058    np = VTOSMB(vp);
7059	np->n_lastvop = smbfs_vnop_removexattr;
7060	share = smb_get_share_with_reference(VTOSMBFS(vp));
7061	/*
7062	 * FILE_NAMED_STREAMS tells us the server supports streams.
7063	 * NOTE: This flag may have been overwriten by us in smbfs_mount. The default
7064	 * is for streams to be turn off. See the smbfs_mount for more details.
7065	 */
7066	if (!(share->ss_attributes & FILE_NAMED_STREAMS)) {
7067		error = ENOTSUP;
7068		goto exit;
7069	}
7070
7071	/* SMB doesn't support having a slash in the xattr name */
7072	if (strchr(ap->a_name, '/')) {
7073		error = EINVAL;
7074
7075        lck_rw_lock_shared(&np->n_name_rwlock);
7076        SMBWARNING("Slash in xattr name not allowed: error %d %s:%s\n", error,
7077				   np->n_name, ap->a_name);
7078        lck_rw_unlock_shared(&np->n_name_rwlock);
7079		goto exit;
7080	}
7081
7082	sfmname = xattr2sfm(ap->a_name, &stype);
7083	if (!sfmname) {
7084		error = EINVAL;
7085		goto exit;
7086	}
7087
7088	if (stype & kFinderInfo) {
7089		if (VTOSMBFS(vp)->sm_flags & MNT_IS_SFM_VOLUME) {
7090			/*
7091			 * We do not allow them to remove the finder info stream on SFM
7092			 * Volume. It could hold other information used by SFM.
7093			 */
7094			error = ENOTSUP;
7095		}
7096        else {
7097			/*
7098			 * If the volume is just a normal NTFS Volume then deleting the named
7099			 * stream should be ok, but some servers (EMC) don't support deleting
7100			 * the named stream. In this case see if we can just zero out the
7101			 * finder info.
7102             *
7103             * Streams are always VREG since they are files
7104			 */
7105			error = smbfs_smb_delete(share, np, VREG,
7106                                     sfmname, strnlen(sfmname, share->ss_maxfilenamelen+1),
7107                                     1, ap->a_context);
7108            SMB_LOG_KTRACE(SMB_DBG_RM_XATTR | DBG_FUNC_NONE,
7109                           0xabc001, error, stype, 0, 0);
7110		}
7111
7112		/* SFM server or the server doesn't support deleting named streams */
7113		if (error) {
7114			uio_t afp_uio = NULL;
7115			uint8_t	afpinfo[60];
7116			SMBFID fid = 0;
7117			uint32_t rights = SMB2_FILE_WRITE_DATA | SMB2_FILE_READ_DATA | SMB2_FILE_WRITE_ATTRIBUTES;
7118
7119			/*
7120			 * Either a SFM volume or the server doesn't support deleting named
7121			 * streams. Try to zero out the finder info data.
7122			 */
7123            saved_error = error; /* save original failure error */
7124
7125			afp_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
7126			if (!afp_uio) {
7127				error = saved_error;
7128				goto exit;
7129			}
7130			error = uio_addiov( afp_uio, CAST_USER_ADDR_T(afpinfo), sizeof(afpinfo));
7131			if (error) {
7132				uio_free(afp_uio);
7133				error = saved_error;
7134				goto exit;
7135			}
7136
7137			/* open and read the data */
7138			error = smbfs_smb_openread(share, np,
7139                                       &fid, rights,
7140                                       afp_uio, NULL, sfmname,
7141                                       &ts, ap->a_context);
7142            SMB_LOG_KTRACE(SMB_DBG_RM_XATTR | DBG_FUNC_NONE,
7143                           0xabc002, error, stype, 0, 0);
7144
7145			/* clear out the finder info data */
7146			bzero(&afpinfo[AFP_INFO_FINDER_OFFSET], FINDERINFOSIZE);
7147
7148			if (!error)	{
7149                /* truncate the stream, this will wake up SFM */
7150				error = smbfs_smb_seteof(share, fid, 0, ap->a_context);
7151            }
7152
7153			/* Reset our uio */
7154			if (!error) {
7155				uio_reset(afp_uio, 0, UIO_SYSSPACE, UIO_WRITE );
7156				error = uio_addiov( afp_uio, CAST_USER_ADDR_T(afpinfo), sizeof(afpinfo));
7157			}
7158
7159			if (!error) {
7160				error = smb_smb_write(share, fid, afp_uio, 0, ap->a_context);
7161                SMB_LOG_KTRACE(SMB_DBG_RM_XATTR | DBG_FUNC_NONE,
7162                               0xabc003, error, stype, 0, 0);
7163            }
7164
7165            if (error) {
7166				error = saved_error; /* restore original error */
7167            }
7168
7169			/* Try to set the modify time back to the original time, ignore any errors */
7170			(void)smbfs_smb_setfattrNT(share, (np->n_dosattr & ~SMB_EFA_DIRECTORY), fid, NULL, &ts,
7171									   NULL, ap->a_context);
7172			if (fid != 0)
7173				(void)smbfs_smb_close(share, fid, ap->a_context);
7174			if (afp_uio) {
7175				uio_free(afp_uio);
7176			}
7177		}
7178	}
7179    else {
7180        /* Streams are always VREG since they are files */
7181		error = smbfs_smb_delete(share, np, VREG,
7182                                 sfmname, strnlen(sfmname, share->ss_maxfilenamelen+1),
7183                                 1, ap->a_context);
7184        SMB_LOG_KTRACE(SMB_DBG_RM_XATTR | DBG_FUNC_NONE,
7185                       0xabc004, error, stype, 0, 0);
7186	}
7187
7188	/* Finder info so reset our cache timer and zero out our cache */
7189	if ((stype & kFinderInfo) && !error) {
7190		nanouptime(&ts);
7191		np->finfo_cache_timer = ts.tv_sec;
7192		bzero(np->finfo, sizeof(np->finfo));
7193	}
7194
7195exit:
7196	if (error == ENOENT)
7197		error = ENOATTR;
7198
7199	/* Check to see if its a normal error */
7200	if (error && (error != ENOTSUP) && (error != ENOATTR)) {
7201        lck_rw_lock_shared(&np->n_name_rwlock);
7202		SMBWARNING("error %d %s:%s\n", error, np->n_name, ap->a_name);
7203        lck_rw_unlock_shared(&np->n_name_rwlock);
7204
7205		/* Always make sure its a legit error, see man listxattr */
7206		if ((error != EROFS) && (error != EPERM) && (error != EINVAL) &&
7207			(error != ENOTDIR) && (error != EACCES) && (error != ELOOP) &&
7208			(error != EFAULT) && (error != EIO) && (error != ENAMETOOLONG))
7209			error = ENOATTR;	/* Not sure what else to do here */
7210	}
7211	smb_share_rele(share, ap->a_context);
7212	smbnode_unlock(np);
7213
7214    SMB_LOG_KTRACE(SMB_DBG_RM_XATTR | DBG_FUNC_END, error, 0, 0, 0, 0);
7215    return (error);
7216}
7217
7218/*
7219 * smbfs_vnop_getxattr
7220 *
7221 *	vnode_t a_vp;
7222 *	int8_t * a_name;
7223 *	uio_t a_uio;
7224 *	size_t *a_size;
7225 *	int32_t a_options;
7226 *	vfs_context_t a_context;
7227 */
7228static int
7229smbfs_vnop_getxattr(struct vnop_getxattr_args *ap)
7230{
7231	vnode_t vp = ap->a_vp;
7232	const char *sfmname;
7233	uio_t uio = ap->a_uio;
7234	size_t *sizep = ap->a_size;
7235	SMBFID fid = 0;
7236	int error = 0;
7237	struct smbnode *np = NULL;
7238	struct smb_share *share = NULL;
7239	size_t rq_resid = (uio) ? (size_t)uio_resid(uio) : 0;
7240	uio_t afp_uio = NULL;
7241	enum stream_types stype = kNoStream;
7242	struct timespec ts;
7243	time_t attrtimeo;
7244    uint32_t stream_flags = 0;
7245	int use_cached_data = 0;
7246    uint64_t strmsize = 0;
7247    uint64_t strm_alloc_size = 0;
7248    size_t afpsize = 0;
7249    uint8_t	afpinfo[60];
7250    enum vtype vnode_type = VREG; /* Streams are always files */
7251
7252	DBG_ASSERT(!vnode_isnamedstream(vp));
7253
7254	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
7255		return (error);
7256
7257
7258    SMB_LOG_KTRACE(SMB_DBG_GET_XATTR | DBG_FUNC_START, 0, 0, 0, 0, 0);
7259
7260    np = VTOSMB(vp);
7261	np->n_lastvop = smbfs_vnop_getxattr;
7262	share = smb_get_share_with_reference(VTOSMBFS(vp));
7263
7264	/*
7265	 * FILE_NAMED_STREAMS tells us the server supports streams.
7266	 * NOTE: This flag may have been overwriten by us in smbfs_mount. The default
7267	 *	 is for streams to be turn off. See the smbfs_mount for more details.
7268	 */
7269	if (!(share->ss_attributes & FILE_NAMED_STREAMS)) {
7270		error = ENOTSUP;
7271		goto exit;
7272	}
7273
7274	/* SMB doesn't support having a slash in the xattr name */
7275	if (strchr(ap->a_name, '/')) {
7276		error = ENOTSUP;
7277        lck_rw_lock_shared(&np->n_name_rwlock);
7278		SMBWARNING("Slash in xattr name not allowed: error %d %s:%s\n", error,
7279				   np->n_name, ap->a_name);
7280        lck_rw_unlock_shared(&np->n_name_rwlock);
7281		goto exit;
7282	}
7283	if (np->n_fstatus & kNO_SUBSTREAMS) {
7284		error = ENOATTR;
7285		goto exit;
7286	}
7287
7288	sfmname = xattr2sfm(ap->a_name, &stype);
7289	if (!sfmname) {
7290		error = EINVAL;
7291		goto exit;
7292	}
7293
7294	/*
7295	 * They just want the size of the stream. */
7296	if ((uio == NULL) && !(stype & kFinderInfo)) {
7297		if (stype & kResourceFrk) {
7298			error = smb_get_rsrcfrk_size(share, vp, ap->a_context);
7299			lck_mtx_lock(&np->rfrkMetaLock);
7300			 /* The node's rfork size will have the correct value at this point */
7301			strmsize = np->rfrk_size;
7302			lck_mtx_unlock(&np->rfrkMetaLock);
7303		}
7304        else {
7305            /* For listing xattrs, create is done on the item, not the stream */
7306            if ((np) && (np->n_vnode)) {
7307                /* Use vnode to determine type */
7308                vnode_type = vnode_isdir(np->n_vnode) ? VDIR : VREG;
7309            }
7310
7311			error = smbfs_smb_qstreaminfo(share, np, vnode_type,
7312                                          NULL, 0,
7313                                          sfmname,
7314                                          NULL, NULL,
7315                                          &strmsize, &strm_alloc_size,
7316                                          &stream_flags, NULL,
7317                                          ap->a_context);
7318            SMB_LOG_KTRACE(SMB_DBG_GET_XATTR | DBG_FUNC_NONE,
7319                           0xabc001, error, stype, 0, 0);
7320		}
7321		if (sizep)
7322			*sizep = (size_t)strmsize;
7323		if (error)
7324			error = ENOATTR;
7325		goto exit;
7326	}
7327
7328	/*
7329	 * We treat finder info differently than any other EA/Stream. Because of SFM
7330	 * we need to do things a little different. Remember the AFPInfo stream has
7331	 * more information in it than just the finder info. WARNING: SFM can get
7332	 * very confused if you do not handle this correctly!
7333	 */
7334	if (stype & kFinderInfo) {
7335        /* If we are in reconnect, use cached data if we have it */
7336        if (np->finfo_cache_timer != 0) {
7337            use_cached_data = (share->ss_flags & SMBS_RECONNECTING);
7338        }
7339
7340        /* Check to see if the cache has timed out */
7341		SMB_CACHE_TIME(ts, np, attrtimeo);
7342		if (((ts.tv_sec - np->finfo_cache_timer) > attrtimeo) &&
7343            !use_cached_data) {
7344            /* Cache has expired go get the finder information. */
7345			afp_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
7346			if (afp_uio) {
7347				error = uio_addiov( afp_uio, CAST_USER_ADDR_T(afpinfo),
7348								   sizeof(afpinfo));
7349            }
7350			else {
7351                error = ENOMEM;
7352            }
7353
7354			if (error) {
7355				goto exit;
7356            }
7357
7358			uio_setoffset(afp_uio, 0);
7359
7360			/* open and read the data */
7361            if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
7362                /* SMB 2/3 will do create/read/close */
7363                error = smbfs_smb_openread(share, np,
7364                                           NULL, SMB2_FILE_READ_DATA,
7365                                           afp_uio, &afpsize, sfmname,
7366                                           NULL, ap->a_context);
7367                fid = 0;
7368            }
7369            else {
7370                /* SMB 1 will do create/read */
7371                error = smbfs_smb_openread(share, np,
7372                                           &fid, SMB2_FILE_READ_DATA,
7373                                           afp_uio, &afpsize, sfmname,
7374                                           NULL, ap->a_context);
7375            }
7376
7377            SMB_LOG_KTRACE(SMB_DBG_GET_XATTR | DBG_FUNC_NONE,
7378                           0xabc002, error, stype, 0, 0);
7379
7380            if ((error == ETIMEDOUT) && (np->finfo_cache_timer != 0)) {
7381                /* Just return the cached data */
7382                error = 0;
7383                goto done;
7384            }
7385
7386            /* Should never happen but just in case */
7387			if (afpsize != AFP_INFO_SIZE) {
7388				error = ENOENT;
7389            }
7390
7391            /* If ENOENT, return zero'd Finder Info, else return the info */
7392			if (error == ENOENT) {
7393				bzero(np->finfo, sizeof(np->finfo));
7394			}
7395            else {
7396				bcopy((void *)&afpinfo[AFP_INFO_FINDER_OFFSET], np->finfo,
7397					  sizeof(np->finfo));
7398			}
7399
7400            /* Cache the finder info as long as its not a copy in progress */
7401			if (vnode_isreg(vp) && (bcmp(np->finfo, "brokMACS", 8) == 0)) {
7402				np->finfo_cache_timer = 0;
7403				SMBDEBUG("Don't cache finder info, we have a finder copy in progress\n");
7404			}
7405            else {
7406				nanouptime(&ts);
7407				np->finfo_cache_timer = ts.tv_sec;
7408			}
7409		}
7410
7411done:
7412		/* If the finder info is all zero hide it, except if its a SFM volume */
7413		if ((!(VTOSMBFS(vp)->sm_flags & MNT_IS_SFM_VOLUME)) &&
7414			(bcmp(np->finfo, emptyfinfo, sizeof(emptyfinfo)) == 0)) {
7415				error = ENOENT;
7416		}
7417
7418		if (uio && !error) {
7419			error = uiomove((const char *)np->finfo, (int)sizeof(np->finfo), ap->a_uio);
7420		}
7421
7422		if (sizep && !error)
7423			*sizep = FINDERINFOSIZE;
7424	}
7425    else {
7426		error = smbfs_smb_openread(share, np,
7427                                   &fid, SMB2_FILE_READ_DATA,
7428                                   uio, sizep, sfmname,
7429                                   NULL, ap->a_context);
7430        SMB_LOG_KTRACE(SMB_DBG_GET_XATTR | DBG_FUNC_NONE,
7431                       0xabc003, error, stype, 0, 0);
7432	}
7433	 /* If ENOTSUP support is returned then do the open and read in two transactions.  */
7434	if (error != ENOTSUP)
7435		goto out;
7436
7437	/*
7438	 * May need to add an oplock to this open call, if this is a finder info open.
7439	 * Not sure I remember the exact details, something about deletes.
7440	 */
7441	error = smbfs_smb_open_xattr(share, np, SMB2_FILE_READ_DATA,
7442								 NTCREATEX_SHARE_ACCESS_ALL, &fid,
7443								 sfmname, sizep, ap->a_context);
7444
7445    SMB_LOG_KTRACE(SMB_DBG_GET_XATTR | DBG_FUNC_NONE,
7446                   0xabc004, error, stype, 0, 0);
7447	if (error)
7448		goto exit;
7449
7450	/*
7451	 * When reading finder-info, munge the uio so we read at offset 16 where the
7452	 * actual finder info is located. Also ensure we don't read past the 32 bytes,
7453	 * of finder info. Since we are just reading we really don't care about the
7454	 * rest of the data.
7455	 * This is only here in case a server does not support the chain message above.
7456	 * We do not cache in this case. Should never happen, but just to be safe.
7457	 */
7458	if (stype & kFinderInfo) {
7459		user_ssize_t r;
7460
7461		if (sizep)
7462			*sizep = FINDERINFOSIZE;
7463		/* Just wanted the size get out */
7464		if (uio == NULL)
7465			goto out;
7466
7467		r = uio_resid(uio);
7468		if (uio_offset(uio) >= FINDERINFOSIZE) {
7469			uio_setresid(uio, 0);
7470		} else if (uio_offset(uio) + r > FINDERINFOSIZE)
7471		uio_setresid(uio, FINDERINFOSIZE - uio_offset(uio));
7472		r = r - uio_resid(uio);
7473		uio_setoffset(uio, uio_offset(uio) + 4*4);
7474
7475		error = smb_smb_read(share, fid, uio, ap->a_context);
7476
7477		uio_setoffset(uio, uio_offset(uio) - 4*4);
7478		uio_setresid(uio, uio_resid(uio) + r);
7479	}
7480	else {
7481       error = smb_smb_read(share, fid, uio, ap->a_context);
7482    }
7483
7484    SMB_LOG_KTRACE(SMB_DBG_GET_XATTR | DBG_FUNC_NONE,
7485                   0xabc005, error, stype, 0, 0);
7486
7487out:;
7488	if (uio && sizep && (*sizep > rq_resid))
7489			error = ERANGE;
7490
7491    /* Even an error can leave the file open. */
7492	if (fid != 0)
7493		(void)smbfs_smb_close(share, fid, ap->a_context);
7494exit:
7495	/*
7496	 * So ENOENT just means ENOATTR.
7497	 * Note: SAMBA 4 will reutrn EISDIR for folders which is legit, but not
7498	 * expected by the finder
7499	 */
7500	if ((error == ENOENT) || ((error == EISDIR) && (stype & kFinderInfo)))
7501		error = ENOATTR;
7502
7503	if (afp_uio)
7504		uio_free(afp_uio);
7505
7506	/* Check to see if its a normal error */
7507	if (error && (error != ENOTSUP) && (error != ENOATTR)) {
7508        lck_rw_lock_shared(&np->n_name_rwlock);
7509		SMBWARNING("error %d %s:%s\n", error, np->n_name, ap->a_name);
7510        lck_rw_unlock_shared(&np->n_name_rwlock);
7511
7512		/* Nope make sure its a legit error, see man getxattr */
7513		if ((error != ERANGE) && (error != EPERM) && (error != EINVAL) &&
7514			(error != EISDIR) && (error != ENOTDIR) && (error != EACCES) &&
7515			(error != ELOOP) && (error != EFAULT) && (error != EIO))
7516			error = ENOATTR;
7517	}
7518	smb_share_rele(share, ap->a_context);
7519	smbnode_unlock(np);
7520
7521    SMB_LOG_KTRACE(SMB_DBG_GET_XATTR | DBG_FUNC_END, error, 0, 0, 0, 0);
7522    return (error);
7523}
7524
7525/*
7526 * smbfs_vnop_getnamedstream - Obtain the vnode for a stream.
7527 *
7528 *	vnode_t a_vp;
7529 *	vnode_t *a_svpp;
7530 *	const char *a_name;
7531	enum nsoperation a_operation; (NS_OPEN, NS_CREATE, NS_DELETE)
7532 *	vfs_context_t a_context;
7533 *
7534 */
7535static int
7536smbfs_vnop_getnamedstream(struct vnop_getnamedstream_args* ap)
7537{
7538	struct smb_share *share;
7539	vnode_t vp = ap->a_vp;
7540	vnode_t *svpp = ap->a_svpp;
7541	const char * streamname = ap->a_name;
7542	const char * sname = ap->a_name;
7543	struct smbnode *np = NULL;
7544	int error = 0;
7545	uint64_t strmsize = 0;
7546	uint64_t strm_alloc_size = 0;
7547	struct smbfattr fattr;
7548	struct vnode_attr vap;
7549	struct timespec ts;
7550	time_t attrtimeo;
7551	struct timespec reqtime;
7552    uint32_t stream_flags = 0;
7553	int use_cached_data = 0;
7554    enum vtype vnode_type = VREG;
7555
7556	/* Lock the parent while we look for the stream */
7557	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
7558		return (error);
7559
7560    SMB_LOG_KTRACE(SMB_DBG_GET_NSTREAM | DBG_FUNC_START, 0, 0, 0, 0, 0);
7561
7562	nanouptime(&reqtime);
7563	np = VTOSMB(vp);
7564	np->n_lastvop = smbfs_vnop_getnamedstream;
7565	share = smb_get_share_with_reference(VTOSMBFS(vp));
7566
7567	*svpp = NULL;
7568	/* Currently we only support the "com.apple.ResourceFork" stream. */
7569	if (bcmp(streamname, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
7570        lck_rw_lock_shared(&np->n_name_rwlock);
7571		SMBDEBUG("Wrong stream %s:$%s\n", np->n_name, streamname);
7572        lck_rw_unlock_shared(&np->n_name_rwlock);
7573
7574		error = ENOATTR;
7575		goto exit;
7576	} else {
7577	    sname = SFM_RESOURCEFORK_NAME;	/* This is the resource stream use the SFM name */
7578	}
7579	if ( !vnode_isreg(vp) ) {
7580        lck_rw_lock_shared(&np->n_name_rwlock);
7581		SMBDEBUG("%s not a file (EPERM)\n", np->n_name);
7582        lck_rw_unlock_shared(&np->n_name_rwlock);
7583
7584		error = EPERM;
7585		goto exit;
7586	}
7587
7588	/*
7589	 * %%%
7590	 * Since we have the parent node update its meta cache. Remember that
7591	 * smbfs_getattr will check to see if the cache has expired. May want to
7592	 * look at this and see  how it affects performance.
7593	 */
7594	VATTR_INIT(&vap);	/* Really don't care about the vap */
7595	error = smbfs_getattr(share, vp, &vap, ap->a_context);
7596	if (error) {
7597        lck_rw_lock_shared(&np->n_name_rwlock);
7598		SMBERROR("%s lookup failed %d\n", np->n_name, error);
7599        lck_rw_unlock_shared(&np->n_name_rwlock);
7600		goto exit;
7601	}
7602
7603	/*
7604	 * If we already have the stream vnode in our hash table and its cache timer
7605	 * has not expired then just return we are done.
7606	 */
7607	if ((*svpp = smbfs_find_vgetstrm(VTOSMBFS(vp), np, sname,
7608									 share->ss_maxfilenamelen)) != NULL) {
7609        /* If we are in reconnect, use cached data if we have it */
7610        if (np->attribute_cache_timer != 0) {
7611            use_cached_data = (share->ss_flags & SMBS_RECONNECTING);
7612        }
7613
7614		VTOSMB(*svpp)->n_mtime = np->n_mtime;	/* update the modify time */
7615
7616        /* Check to see if the cache has timed out */
7617        SMB_CACHE_TIME(ts, VTOSMB(*svpp), attrtimeo);
7618		if (((ts.tv_sec - VTOSMB(*svpp)->attribute_cache_timer) <= attrtimeo) ||
7619            use_cached_data) {
7620			/* The cache is up to date, we are done */
7621            goto exit;
7622        }
7623	}
7624
7625    if ((np) && (np->n_vnode)) {
7626        /* Use vnode to determine type */
7627        vnode_type = vnode_isdir(np->n_vnode) ? VDIR : VREG;
7628    }
7629
7630	/*
7631	 * Lookup the stream and get its size. This call will fail if the server
7632	 * tells us the stream does not exist.
7633	 *
7634	 * NOTE1: If this is the resource stream then making this call will update
7635	 * the the data fork  node's resource size and its resource cache timer.
7636	 *
7637	 * NOTE2: SAMBA will not return the resource stream if the size is zero.
7638	 *
7639	 * NOTE3: We always try to create the stream on an open. Because of note two.
7640	 *
7641	 * If smbfs_smb_qstreaminfo returns an error and we do not have the stream
7642	 * node in our hash table then it doesn't exist and they will have to create
7643	 * it.
7644	 *
7645	 * If smbfs_smb_qstreaminfo returns an error and we do  have the stream node
7646	 * in our hash table then it could exist so just pretend that it does for
7647	 * now. If they try to open it and it doesn't exist the open will create it.
7648	 *
7649	 * If smbfs_smb_qstreaminfo returns no error and we do have the stream node
7650	 * in our hash table then just update its size and cache timers.
7651	 *
7652	 * If smbfs_smb_qstreaminfo returns no error and we do not have the stream
7653	 * node in our hash table then create the stream node, using the data node
7654	 * to fill in all information except the size.
7655	 */
7656    error = smbfs_smb_qstreaminfo(share, np, vnode_type,
7657                                  NULL, 0,
7658                                  sname,
7659                                  NULL, NULL,
7660                                  &strmsize, &strm_alloc_size,
7661                                  &stream_flags, NULL,
7662                                  ap->a_context);
7663	if (error && (*svpp == NULL)) {
7664		error = ENOATTR;
7665		goto exit;
7666	}
7667
7668    if ((error == ETIMEDOUT) && (np->attribute_cache_timer != 0)) {
7669        /* Just return the cached data */
7670        error = 0;
7671        goto exit;
7672    }
7673
7674	/*
7675	 * We already have the stream vnode. If it doesn't exist we will attempt to
7676	 * create it on the open. In the SMB open you can say create it if it does
7677	 * not exist. Reset the size if the above called failed then set the size to
7678	 * zero.
7679	 */
7680	if (*svpp) {
7681		if (smbfs_update_size(VTOSMB(*svpp), &reqtime, strmsize) == TRUE) {
7682			/* Remember the only attribute for a stream is its size */
7683			nanouptime(&ts);
7684			VTOSMB(*svpp)->attribute_cache_timer = ts.tv_sec;
7685		}
7686		goto exit;	/* We have everything we need, so we are done */
7687	}
7688
7689	bzero(&fattr, sizeof(fattr));
7690	fattr.fa_vtype = VREG;		/* Streams are always regular files */
7691    fattr.fa_valid_mask |= FA_VTYPE_VALID;
7692	fattr.fa_size = strmsize;	/* Fill in the stream size */
7693	fattr.fa_data_alloc = 0;	/* %%% not sure this really matters */
7694	/* Now for the rest of the information we just use the data node information */
7695	fattr.fa_attr = np->n_dosattr;
7696	fattr.fa_atime = np->n_atime;	/* Access Time */
7697	fattr.fa_chtime = np->n_chtime;	/* Change Time */
7698	fattr.fa_mtime = np->n_mtime;	/* Modify Time */
7699	fattr.fa_crtime = np->n_crtime;	/* Create Time */
7700	/* Stream inode number has same inode number as data node */
7701    fattr.fa_ino = np->n_ino;
7702	nanouptime(&fattr.fa_reqtime);
7703	error = smbfs_vgetstrm(share, VTOSMBFS(vp), vp, svpp, &fattr, sname);
7704
7705exit:
7706	if (*svpp)
7707		smbnode_unlock(VTOSMB(*svpp));	/* We are done with the node unlock it. */
7708
7709	if (error && (error != ENOATTR)) {
7710        lck_rw_lock_shared(&np->n_name_rwlock);
7711		SMBWARNING(" %s:$%s Original Stream name %s error = %d\n", np->n_name,
7712				   sname, streamname, error);
7713        lck_rw_unlock_shared(&np->n_name_rwlock);
7714	}
7715	smb_share_rele(share, ap->a_context);
7716	smbnode_unlock(np);
7717
7718    SMB_LOG_KTRACE(SMB_DBG_GET_NSTREAM | DBG_FUNC_END, error, 0, 0, 0, 0);
7719	return (error);
7720}
7721
7722/*
7723 * smbfs_vnop_makenamedstream - Create a stream.
7724 *
7725 *	vnode_t a_vp;
7726 *	vnode_t *a_svpp;
7727 *	const char *a_name;
7728 *	vfs_context_t a_context;
7729 */
7730static int
7731smbfs_vnop_makenamedstream(struct vnop_makenamedstream_args* ap)
7732{
7733	struct smb_share *share;
7734	vnode_t vp = ap->a_vp;
7735	vnode_t *svpp = ap->a_svpp;
7736	const char * streamname = ap->a_name;
7737	struct smbnode *np = NULL;
7738	int error = 0;
7739	struct smbfattr fattr;
7740	struct timespec ts;
7741	int rsrcfrk = FALSE;
7742	size_t max_name_len;
7743
7744	/* Lock the parent while we create the stream */
7745	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
7746		return (error);
7747
7748	SMB_LOG_KTRACE(SMB_DBG_MAKE_NSTREAM | DBG_FUNC_START, 0, 0, 0, 0, 0);
7749
7750    np = VTOSMB(vp);
7751	np->n_lastvop = smbfs_vnop_makenamedstream;
7752	share = smb_get_share_with_reference(VTOSMBFS(vp));
7753
7754	*svpp = NULL;
7755
7756	/* Currently we only support the "com.apple.ResourceFork" stream. */
7757	if (bcmp(streamname, XATTR_RESOURCEFORK_NAME,
7758			 sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
7759        lck_rw_lock_shared(&np->n_name_rwlock);
7760		SMBDEBUG("Wrong stream %s:$%s\n", np->n_name, streamname);
7761        lck_rw_unlock_shared(&np->n_name_rwlock);
7762
7763		/* max_name_len = strnlen(streamname, share->ss_maxfilenamelen+1) */
7764		error = ENOATTR;
7765		goto exit;
7766	} else {
7767		max_name_len = sizeof(XATTR_RESOURCEFORK_NAME);
7768		/* This is the resource stream use the SFM name */
7769	    streamname = SFM_RESOURCEFORK_NAME;
7770	}
7771
7772	if ( !vnode_isreg(vp) ) {
7773        lck_rw_lock_shared(&np->n_name_rwlock);
7774		SMBDEBUG("%s not a file (EPERM)\n", np->n_name);
7775        lck_rw_unlock_shared(&np->n_name_rwlock);
7776
7777		error = EPERM;
7778		goto exit;
7779	}
7780
7781	/* Now create the stream, sending a null fid pointer will cause it to be closed */
7782	error = smbfs_smb_create(share, np, streamname, max_name_len,
7783							 SMB2_FILE_WRITE_DATA, NULL,
7784							 FILE_OPEN_IF, 1, &fattr, ap->a_context);
7785	if (error)
7786		goto exit;
7787
7788	/* We create a named stream, so remove the no stream flag  */
7789	np->n_fstatus &= ~kNO_SUBSTREAMS;
7790
7791	/* Stream inode number has same inode number as data node */
7792    fattr.fa_ino = np->n_ino;
7793
7794	error = smbfs_vgetstrm(share, VTOSMBFS(vp), vp, svpp, &fattr, streamname);
7795	if (error == 0) {
7796		if (rsrcfrk) /* Update the data nodes resource size */ {
7797			lck_mtx_lock(&np->rfrkMetaLock);
7798			np->rfrk_size = fattr.fa_size;
7799            /* assume alloc size is the same */
7800			np->rfrk_alloc_size = fattr.fa_size;
7801			nanouptime(&ts);
7802			np->rfrk_cache_timer = ts.tv_sec;
7803			lck_mtx_unlock(&np->rfrkMetaLock);
7804		}
7805		smbnode_unlock(VTOSMB(*svpp));	/* Done with the smbnode unlock it. */
7806	}
7807
7808exit:
7809	if (error) {
7810        lck_rw_lock_shared(&np->n_name_rwlock);
7811		SMBWARNING(" %s:$%s error = %d\n", np->n_name, streamname, error);
7812        lck_rw_unlock_shared(&np->n_name_rwlock);
7813    }
7814
7815	smb_share_rele(share, ap->a_context);
7816	smbnode_unlock(np);
7817
7818	SMB_LOG_KTRACE(SMB_DBG_MAKE_NSTREAM | DBG_FUNC_END, error, 0, 0, 0, 0);
7819    return (error);
7820}
7821
7822/*
7823 * smbfs_vnop_removenamedstream - Remove a stream.
7824 *
7825 *	vnode_t a_vp;
7826 *	vnode_t a_svpp;
7827 *	const char *a_name;
7828 *	vfs_context_t a_context;
7829 */
7830static int
7831smbfs_vnop_removenamedstream(struct vnop_removenamedstream_args* ap)
7832{
7833	vnode_t vp = ap->a_vp;
7834	vnode_t svp = ap->a_svp;
7835	const char * streamname = ap->a_name;
7836	struct smbnode *np = NULL;
7837	int error = 0;
7838	size_t max_name_len;
7839	struct smb_share *share = NULL;
7840
7841
7842	/* Lock the parent and stream while we delete the stream*/
7843	if ((error = smbnode_lockpair(VTOSMB(vp), VTOSMB(svp), SMBFS_EXCLUSIVE_LOCK)))
7844		return (error);
7845
7846	SMB_LOG_KTRACE(SMB_DBG_RM_NSTREAM | DBG_FUNC_START, 0, 0, 0, 0, 0);
7847
7848    np = VTOSMB(svp);
7849	np->n_lastvop = smbfs_vnop_removenamedstream;
7850	share = smb_get_share_with_reference(VTOSMBFS(vp));
7851
7852	/* Currently we only support the "com.apple.ResourceFork" stream. */
7853	if (bcmp(streamname, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
7854        lck_rw_lock_shared(&np->n_name_rwlock);
7855		SMBDEBUG("Wrong stream %s:$%s\n", np->n_name, streamname);
7856        lck_rw_unlock_shared(&np->n_name_rwlock);
7857
7858		/* max_name_len = strnlen(streamname, share->ss_maxfilenamelen+1) */
7859		error = ENOATTR;
7860		goto exit;
7861	}
7862    else {
7863		max_name_len = sizeof(XATTR_RESOURCEFORK_NAME);
7864		/* This is the resource stream use the SFM name */
7865	    streamname = SFM_RESOURCEFORK_NAME;
7866	}
7867
7868	if ( !vnode_isreg(vp) ) {
7869        lck_rw_lock_shared(&np->n_name_rwlock);
7870		SMBDEBUG("%s not a file (EPERM)\n", np->n_name);
7871        lck_rw_unlock_shared(&np->n_name_rwlock);
7872
7873		error = EPERM;
7874		goto exit;
7875	}
7876
7877    /* Streams are always VREG since they are files */
7878	error = smbfs_smb_delete(share, np, VREG,
7879                             streamname, max_name_len,
7880                             TRUE, ap->a_context);
7881	if (!error)
7882		smb_vhashrem(np);
7883exit:
7884	if (error) {
7885        lck_rw_lock_shared(&np->n_name_rwlock);
7886		SMBWARNING(" %s:$%s error = %d\n", np->n_name, streamname, error);
7887        lck_rw_unlock_shared(&np->n_name_rwlock);
7888    }
7889
7890	smb_share_rele(share, ap->a_context);
7891	smbnode_unlockpair(VTOSMB(vp), VTOSMB(svp));
7892
7893	SMB_LOG_KTRACE(SMB_DBG_RM_NSTREAM | DBG_FUNC_END, error, 0, 0, 0, 0);
7894    return (error);
7895}
7896
7897/*
7898 * smbfs_vnop_monitor - Monitor an item.
7899 *
7900 *	vnode_t a_vp;
7901 *  uint32_t a_unused_events;	- not used currently
7902 *  uint32_t a_flags;
7903 *				VNODE_MONITOR_BEGIN - setup notfication
7904 *				VNODE_MONITOR_END	- remove notfication
7905 *				VNODE_MONITOR_UPDATE	- change
7906 *	void *a_handle;
7907 *				struct knote *
7908 *  vfs_context_t a_context;
7909 *
7910 */
7911static int
7912smbfs_vnop_monitor(struct vnop_monitor_args *ap)
7913{
7914	struct smbnode *np;
7915	struct smb_share *share = NULL;
7916	int error = 0;
7917	int releaseLock = TRUE;
7918
7919	/* Currently we only support directories */
7920	if (! vnode_isdir(ap->a_vp))	{
7921        lck_rw_lock_shared(&VTOSMB(ap->a_vp)->n_name_rwlock);
7922		SMBDEBUG("%s is not a directory (ENOTSUP): node type = 0x%0x a_events = 0x%x, a_flags = 0x%x, a_handle = %p\n",
7923				 VTOSMB(ap->a_vp)->n_name, vnode_vtype(ap->a_vp),
7924				 ap->a_events, ap->a_flags, ap->a_handle);
7925        lck_rw_unlock_shared(&VTOSMB(ap->a_vp)->n_name_rwlock);
7926		return ENOTSUP;
7927	}
7928
7929	if ((error = smbnode_lock(VTOSMB(ap->a_vp), SMBFS_EXCLUSIVE_LOCK)))
7930		return (error);
7931
7932    SMB_LOG_KTRACE(SMB_DBG_MONITOR | DBG_FUNC_START, ap->a_flags, 0, 0, 0, 0);
7933
7934	np = VTOSMB(ap->a_vp);
7935	np->n_lastvop = smbfs_vnop_monitor;
7936	share = smb_get_share_with_reference(VTOSMBFS(ap->a_vp));
7937
7938    lck_rw_lock_shared(&np->n_name_rwlock);
7939    SMBDEBUG("%s a_events = 0x%x, a_flags = 0x%x, a_handle = %p\n",
7940			 np->n_name, ap->a_events, ap->a_flags, ap->a_handle);
7941    lck_rw_unlock_shared(&np->n_name_rwlock);
7942
7943	switch (ap->a_flags) {
7944		case VNODE_MONITOR_BEGIN:
7945			error = smbfs_start_change_notify(share, np, ap->a_context,
7946											  &releaseLock);
7947			break;
7948		case VNODE_MONITOR_END:
7949			error = smbfs_stop_change_notify(share, np, FALSE, ap->a_context,
7950											 &releaseLock);
7951			break;
7952		case VNODE_MONITOR_UPDATE: /* We no longer get called to update */
7953		default:
7954			error = ENOTSUP;
7955			break;
7956	}
7957	smb_share_rele(share, ap->a_context);
7958	if (releaseLock)
7959		smbnode_unlock(VTOSMB(ap->a_vp));
7960
7961	SMB_LOG_KTRACE(SMB_DBG_MONITOR | DBG_FUNC_END, error, 0, 0, 0, 0);
7962    return error;
7963}
7964
7965/*
7966 * smbfs_vnop_access - Check for access
7967 *
7968 *	vnode_t a_vp;
7969 *  int32_t a_action;
7970 *  vfs_context_t a_context;
7971 *
7972 */
7973static int
7974smbfs_vnop_access(struct vnop_access_args *ap)
7975{
7976	vnode_t vp = ap->a_vp;
7977	int32_t action = ap->a_action, write_rights;
7978	vfs_context_t context = ap->a_context;
7979	kauth_cred_t cred = vfs_context_ucred(context);
7980	struct smbmount *smp = VTOSMBFS(vp);
7981	struct smb_share *share;
7982	uint32_t maxAccessRights;
7983	int error = 0;
7984
7985    SMB_LOG_KTRACE(SMB_DBG_ACCESS | DBG_FUNC_START, action, 0, 0, 0, 0);
7986
7987	share = smb_get_share_with_reference(VTOSMBFS(vp));
7988	/*
7989	 * Not the root user, not the user that mounted the volume and the volume
7990	 * wasn't mounted as guest then refuse all access.
7991	 */
7992	if ((vfs_context_suser(context) != 0) &&
7993		(kauth_cred_getuid(cred) != smp->sm_args.uid) &&
7994		!SMBV_HAS_GUEST_ACCESS(SSTOVC(share))) {
7995        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
7996		SMB_LOG_ACCESS("%d not authorized to access %s : action = 0x%x\n",
7997				 kauth_cred_getuid(cred), VTOSMB(vp)->n_name, action);
7998        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
7999
8000		error = EACCES;
8001		goto done;
8002	}
8003
8004	/*
8005	 * If KAUTH_VNODE_ACCESS is not set then this is an authoritative request,
8006	 * we can't answer those correctly so always grant access. Now if they are
8007	 * asking about excute we should do some extra checking. If we have excute or
8008	 * read access then grant it otherwise fail the access request.
8009	 */
8010	if (((action & KAUTH_VNODE_ACCESS) != KAUTH_VNODE_ACCESS) &&
8011		(((action & KAUTH_VNODE_EXECUTE) != KAUTH_VNODE_EXECUTE) ||
8012		 (!vnode_isreg(vp)))) {
8013			goto done;
8014	}
8015
8016	/* Deal with the immutable bit, never allow write, delete or security changes. */
8017	write_rights = KAUTH_VNODE_WRITE_RIGHTS;
8018	/* Allow them to change the immutable, if they own it, we always allow */
8019	write_rights &= ~(KAUTH_VNODE_WRITE_ATTRIBUTES | KAUTH_VNODE_WRITE_EXTATTRIBUTES);
8020	/* Remove this one, we allow access if its set */
8021	write_rights &= ~KAUTH_VNODE_CHECKIMMUTABLE;
8022	if (node_isimmutable(share, vp, NULL) && (action & write_rights)) {
8023        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8024		SMB_LOG_ACCESS("%s action = 0x%x %s denied\n", VTOSMB(vp)->n_name, action,
8025                       vnode_isdir(vp) ? "IMMUTABLE_DIR" : "IMMUTABLE_FILE");
8026        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8027
8028		error = EPERM;
8029		goto done;
8030	}
8031
8032	/*
8033	 * Windows FAT file systems have no access check, so always grant access and
8034	 * let the server make the final call. We could have some strange server that
8035	 * supports ACLs on a FAT file system or has some kind of access model. See
8036	 * FAT on a UNIX/Mac. In that case lets see if they are returning the correct
8037	 * maximal access.
8038	 */
8039	if ((share->ss_fstype == SMB_FS_FAT) &&
8040		((share->ss_attributes & FILE_PERSISTENT_ACLS) != FILE_PERSISTENT_ACLS)) {
8041		SMB_LOG_ACCESS("FAT: Access call not supported by server\n");
8042		goto done;
8043	}
8044	/*
8045	 * We were mounted with guest access.
8046	 *
8047	 * 1. We turn off ACLs if mounted as guest. Without ACLs we can't determine
8048	 *    maximal access with Samba that includes our version. So in the samba
8049	 *	  case we always ask the server for the check.
8050	 * 2. Windows return us the correct maximal access, so we can return the
8051	 *    the correct value in that case.
8052	 *
8053	 */
8054#ifdef SMB_DEBUG_ACCESS
8055    lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8056	if (SMBV_HAS_GUEST_ACCESS(SSTOVC(share))) {
8057		SMB_LOG_ACCESS("SMBV_GUEST_ACCESS: %s action = 0x%x\n",
8058                       VTOSMB(vp)->n_name, action);
8059	}
8060    else {
8061		SMB_LOG_ACCESS("%s action = 0x%x\n", VTOSMB(vp)->n_name, action);
8062	}
8063    lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8064#endif // SMB_DEBUG_ACCESS
8065
8066	/*
8067	 * They are asking about a stream, how do we want to handle stream
8068	 * nodes. Windows will return this in the open, but we would need to change
8069	 * the open call to support getting it on stream.Streams have the same access
8070	 * as the parent (data stream). So lets get the parent and return whatever
8071	 * the parent supports.
8072	 */
8073	if (vnode_isnamedstream(vp)) {
8074		vnode_t parent_vp = vnode_getparent(vp);
8075		if (!parent_vp)
8076			return 0;	/* Can't get the parent, let the server make the call */
8077		maxAccessRights = smbfs_get_maximum_access(share, parent_vp, context);
8078		vnode_put(parent_vp);
8079	} else {
8080		maxAccessRights = smbfs_get_maximum_access(share, vp, context);
8081	}
8082
8083	/* KAUTH_VNODE_READ_DATA for files and KAUTH_VNODE_LIST_DIRECTORY for directories */
8084	if ((action & KAUTH_VNODE_READ_DATA) &&
8085		((maxAccessRights & SMB2_FILE_READ_DATA) != SMB2_FILE_READ_DATA)) {
8086        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8087		SMB_LOG_ACCESS("%s action = 0x%x %s denied\n", VTOSMB(vp)->n_name, action,
8088                       vnode_isdir(vp) ? "KAUTH_VNODE_LIST_DIRECTORY" : "KAUTH_VNODE_READ_DATA");
8089        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8090
8091		error = EACCES;
8092		goto done;
8093	}
8094
8095	/* KAUTH_VNODE_WRITE_DATA for files and KAUTH_VNODE_ADD_FILE for directories */
8096	if ((action & KAUTH_VNODE_WRITE_DATA) &&
8097		((maxAccessRights & SMB2_FILE_WRITE_DATA) != SMB2_FILE_WRITE_DATA)) {
8098        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8099		SMB_LOG_ACCESS("%s action = 0x%x %s denied\n", VTOSMB(vp)->n_name, action,
8100                       vnode_isdir(vp) ? "KAUTH_VNODE_ADD_FILE" : "KAUTH_VNODE_WRITE_DATA");
8101        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8102
8103		error = EACCES;
8104		goto done;
8105	}
8106
8107	/* KAUTH_VNODE_EXECUTE for files and KAUTH_VNODE_SEARCH for directories */
8108	if (action & KAUTH_VNODE_EXECUTE) {
8109		if ((vnode_isdir(vp)) &&
8110			((maxAccessRights & SMB2_FILE_TRAVERSE) != SMB2_FILE_TRAVERSE) &&
8111			((maxAccessRights & SMB2_FILE_LIST_DIRECTORY) != SMB2_FILE_LIST_DIRECTORY)) {
8112			/*
8113			 * See <rdar://problem/11151288> for more details, we use to require
8114			 * SMB2_FILE_TRAVERSE for granting directory search access, but now
8115			 * we also accept SMB2_FILE_LIST_DIRECTORY as well.
8116			 */
8117            lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8118			SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_SEARCH denied\n", VTOSMB(vp)->n_name, action);
8119            lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8120
8121			error = EACCES;
8122			goto done;
8123		} else if (!vnode_isdir(vp) &&
8124				   ((maxAccessRights & SMB2_FILE_EXECUTE) != SMB2_FILE_EXECUTE)) {
8125			/*
8126			 * If this authoritative request and they have execute or read access
8127			 * then grant the access.
8128			 */
8129			if (((action & KAUTH_VNODE_ACCESS) != KAUTH_VNODE_ACCESS) &&
8130				((maxAccessRights & SMB2_FILE_READ_DATA) == SMB2_FILE_READ_DATA)) {
8131				goto done;
8132			}
8133
8134			/*
8135			 * See <rdar://problem/7327306> for more details, but we use to say
8136			 * if the file had read access let them have execute access. Not sure
8137			 * why I did that and it broke  <rdar://problem/7327306> so removing
8138			 * that check.
8139			 */
8140            lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8141			SMB_LOG_ACCESS("%s action = 0x%x SMB2_FILE_EXECUTE denied\n",
8142                           VTOSMB(vp)->n_name, action);
8143            lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8144
8145			error = EACCES;
8146			goto done;
8147		}
8148	}
8149
8150	if ((action & KAUTH_VNODE_DELETE) &&
8151		((maxAccessRights & SMB2_DELETE) != SMB2_DELETE)) {
8152        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8153		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_DELETE denied\n",
8154                       VTOSMB(vp)->n_name, action);
8155        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8156
8157		error = EACCES;
8158		goto done;
8159	}
8160
8161	/* KAUTH_VNODE_APPEND_DATA for files and KAUTH_VNODE_ADD_SUBDIRECTORY for directories */
8162	if ((action & KAUTH_VNODE_APPEND_DATA) &&
8163		((maxAccessRights & SMB2_FILE_APPEND_DATA) != SMB2_FILE_APPEND_DATA)) {
8164        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8165		SMB_LOG_ACCESS("%s action = 0x%x %s denied\n", VTOSMB(vp)->n_name, action,
8166                       vnode_isdir(vp) ? "KAUTH_VNODE_ADD_SUBDIRECTORY" : "KAUTH_VNODE_APPEND_DATA");
8167        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8168
8169		error = EACCES;
8170		goto done;
8171	}
8172
8173#ifdef SMB_DEBUG_ACCESS
8174	/* Need to look at this some more, seems Apple and MS don't argree on this SMB2_FILE_DELETE_CHILD */
8175	if ((action & KAUTH_VNODE_DELETE_CHILD) &&
8176		((maxAccessRights & SMB2_FILE_DELETE_CHILD) != SMB2_FILE_DELETE_CHILD)) {
8177        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8178		SMB_LOG_ACCESS("%s action = 0x%x 0x%x KAUTH_VNODE_DELETE_CHILD should denied\n",
8179                       VTOSMB(vp)->n_name, action, KAUTH_VNODE_DELETE_CHILD);
8180        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8181	}
8182	/*
8183	 * Need to look at this some more, seems Apple and MS don't argree on what
8184	 * KAUTH_VNODE_READ_ATTRIBUTES allows and doesn't allow. Window still
8185	 * allow us to get some meta data?
8186	 */
8187	if ((action & KAUTH_VNODE_READ_ATTRIBUTES) &&
8188		((maxAccessRights & SMB2_FILE_READ_ATTRIBUTES) != SMB2_FILE_READ_ATTRIBUTES)) {
8189        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8190		SMB_LOG_ACCESS("%s action = 0x%x 0x%x KAUTH_VNODE_READ_ATTRIBUTES should denied\n",
8191                       VTOSMB(vp)->n_name, action, KAUTH_VNODE_READ_ATTRIBUTES);
8192        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8193	}
8194#endif // SMB_DEBUG_ACCESS
8195
8196	if ((action & KAUTH_VNODE_WRITE_ATTRIBUTES) &&
8197		((maxAccessRights & SMB2_FILE_WRITE_ATTRIBUTES) != SMB2_FILE_WRITE_ATTRIBUTES)) {
8198        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8199		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_WRITE_ATTRIBUTES denied\n",
8200                       VTOSMB(vp)->n_name, action);
8201        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8202
8203		error = EACCES;
8204		goto done;
8205	}
8206
8207	if ((action & KAUTH_VNODE_READ_EXTATTRIBUTES) &&
8208		((maxAccessRights & SMB2_FILE_READ_ATTRIBUTES) != SMB2_FILE_READ_ATTRIBUTES)) {
8209        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8210		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_READ_EXTATTRIBUTES denied\n",
8211                       VTOSMB(vp)->n_name, action);
8212        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8213
8214		error = EACCES;
8215		goto done;
8216	}
8217
8218	if ((action & KAUTH_VNODE_WRITE_EXTATTRIBUTES) &&
8219		((maxAccessRights & SMB2_FILE_WRITE_ATTRIBUTES) != SMB2_FILE_WRITE_ATTRIBUTES)) {
8220        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8221		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_WRITE_EXTATTRIBUTES denied\n",
8222                       VTOSMB(vp)->n_name, action);
8223        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8224
8225		error = EACCES;
8226		goto done;
8227	}
8228
8229	if ((action & KAUTH_VNODE_READ_SECURITY) &&
8230		((maxAccessRights & SMB2_READ_CONTROL) != SMB2_READ_CONTROL)) {
8231        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8232		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_READ_SECURITY denied\n",
8233                       VTOSMB(vp)->n_name, action);
8234        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8235
8236		error = EACCES;
8237		goto done;
8238	}
8239
8240	/* Check to see if the share acls allow access */
8241	if ((action & KAUTH_VNODE_WRITE_SECURITY) &&
8242		((share->maxAccessRights & SMB2_WRITE_DAC) != SMB2_WRITE_DAC)) {
8243        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8244		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_WRITE_SECURITY denied by Share ACL\n",
8245                       VTOSMB(vp)->n_name, action);
8246        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8247
8248		error = EACCES;
8249		goto done;
8250	}
8251
8252	/* Check to see if the share acls allow access */
8253	if ((action & KAUTH_VNODE_TAKE_OWNERSHIP) &&
8254		((share->maxAccessRights & SMB2_WRITE_OWNER) != SMB2_WRITE_OWNER)) {
8255        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8256		SMB_LOG_ACCESS("%s action = 0x%x SHARE KAUTH_VNODE_TAKE_OWNERSHIP by Share ACL\n",
8257                       VTOSMB(vp)->n_name, action);
8258        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8259
8260		error = EACCES;
8261		goto done;
8262	}
8263
8264	if ((action & KAUTH_VNODE_WRITE_SECURITY) &&
8265		((maxAccessRights & SMB2_WRITE_DAC) != SMB2_WRITE_DAC)) {
8266        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8267		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_WRITE_SECURITY denied\n",
8268                       VTOSMB(vp)->n_name, action);
8269        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8270
8271		error = EACCES;
8272		goto done;
8273	}
8274
8275	if ((action & KAUTH_VNODE_TAKE_OWNERSHIP) &&
8276		((maxAccessRights & SMB2_WRITE_OWNER) != SMB2_WRITE_OWNER)) {
8277        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8278		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_TAKE_OWNERSHIP denied\n",
8279                       VTOSMB(vp)->n_name, action);
8280        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8281
8282		error = EACCES;
8283		goto done;
8284	}
8285
8286done:
8287	if (error) {
8288        lck_rw_lock_shared(&VTOSMB(vp)->n_name_rwlock);
8289		SMB_LOG_ACCESS("%s action = 0x%x denied\n", VTOSMB(vp)->n_name, action);
8290        lck_rw_unlock_shared(&VTOSMB(vp)->n_name_rwlock);
8291	}
8292	smb_share_rele(share, ap->a_context);
8293
8294    SMB_LOG_KTRACE(SMB_DBG_ACCESS | DBG_FUNC_END, error, 0, 0, 0, 0);
8295	return error;
8296}
8297
8298
8299/*
8300 * smbfs_vnop_allocate -
8301 *
8302 *	vnode_t a_vp;
8303 *  off_t a_length;
8304 *	u_int32_t a_flags;
8305 *  off_t *a_bytesallocated;
8306 *  off_t a_offset;
8307 *  vfs_context_t a_context;
8308 *
8309 */
8310static int
8311smbfs_vnop_allocate(struct vnop_allocate_args *ap)
8312{
8313	vnode_t vp = ap->a_vp;
8314	u_int64_t length = (u_int64_t)ap->a_length;
8315	struct smbnode *np;
8316	int32_t error = 0;
8317	SMBFID fid = 0;
8318
8319	*(ap->a_bytesallocated) = 0;
8320
8321	/* Preflight checks */
8322	if (!vnode_isreg(vp)) {
8323		/* can only read regular files */
8324		if (vnode_isdir(vp))
8325			return (EISDIR);
8326		else
8327			return (EPERM);
8328	}
8329
8330	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK))) {
8331		return (error);
8332	}
8333
8334	SMB_LOG_KTRACE(SMB_DBG_ALLOCATE | DBG_FUNC_START, 0, 0, 0, 0, 0);
8335
8336    np = VTOSMB(vp);
8337	np->n_lastvop = smbfs_vnop_allocate;
8338
8339	if ((ap->a_flags & ALLOCATEFROMVOL) && (length < np->n_size)) {
8340		error = EINVAL;
8341		goto done;
8342	}
8343
8344    if (ap->a_flags & ALLOCATEFROMPEOF) {
8345		if (length > (UINT32_MAX - np->n_size)) {
8346			error = EINVAL;
8347			goto done;
8348		}
8349        length += np->n_size;
8350    }
8351
8352	if (FindFileRef(vp, vfs_context_proc(ap->a_context), kAccessWrite,
8353						  kAnyMatch, 0, 0, NULL, &fid)) {
8354		/* No matches or no pid to match, so just use the generic shared fork */
8355		fid = np->f_fid;
8356	}
8357
8358	if (fid == 0) {
8359		error = EBADF;
8360		goto done;
8361	}
8362
8363    /* If nothing is changing, then we're done */
8364    if (!length || (np->n_size == length)) {
8365        length = 0;
8366    }
8367    else {
8368		struct smb_share *share;
8369
8370		share = smb_get_share_with_reference(VTOSMBFS(vp));
8371		length = roundup(length, VTOSMBFS(vp)->sm_statfsbuf.f_bsize);
8372		error = smbfs_smb_set_allocation(share, fid, length, ap->a_context);
8373
8374        SMB_LOG_KTRACE(SMB_DBG_ALLOCATE | DBG_FUNC_NONE,
8375                       0xabc001, error, 0, 0, 0);
8376		smb_share_rele(share, ap->a_context);
8377	}
8378
8379	if (!error) {
8380		*(ap->a_bytesallocated) = length;
8381	}
8382
8383done:
8384	if (error) {
8385        lck_rw_lock_shared(&np->n_name_rwlock);
8386		SMBWARNING("%s: length = %lld, error = %d\n", np->n_name, length, error);
8387        lck_rw_unlock_shared(&np->n_name_rwlock);
8388	}
8389	smbnode_unlock(VTOSMB(ap->a_vp));
8390
8391	SMB_LOG_KTRACE(SMB_DBG_ALLOCATE | DBG_FUNC_END, error, 0, 0, 0, 0);
8392    return error;
8393}
8394
8395static char*
8396mountpointname(struct mount *mp)
8397{
8398    size_t namelength = strlen(vfs_statfs(mp)->f_mntonname);
8399    int foundchars = 0;
8400    char *c;
8401
8402    if (namelength == 0) {
8403        return (NULL);
8404    }
8405
8406    /*
8407     * Look backwards through the name string, looking for
8408     * the first slash encountered (which must precede the
8409     * last part of the pathname).
8410     */
8411    for (c = vfs_statfs(mp)->f_mntonname + namelength - 1;
8412         namelength > 0; --c, --namelength) {
8413        if (*c != '/') {
8414            foundchars = 1;
8415        } else if (foundchars) {
8416            return (c + 1);
8417        }
8418    }
8419
8420    return (vfs_statfs(mp)->f_mntonname);
8421}
8422
8423/*
8424 * The calling routine must hold a reference on the share
8425 */
8426static int
8427smbfs_pack_vap(struct smbmount *smp, struct smbfs_fctx *ctx,
8428               struct vnode_attr *vap, vfs_context_t context)
8429{
8430    uint32_t is_dir;
8431    uint64_t data_fork_size, data_fork_alloc;
8432    uint64_t rsrc_fork_size, rsrc_fork_alloc;
8433    uint64_t file_id;
8434    uid_t uid;
8435    gid_t gid;
8436    mode_t mode = 0;
8437    uint32_t flags = 0;
8438    int isroot = 0;
8439    uid_t cuid = 1;
8440    uint32_t cmn_user_rights = 0;
8441    char *mp_name = NULL;
8442    size_t mp_namelen = 0;
8443
8444    if ((!vap) || (!ctx) || (!smp)) {
8445        SMBERROR("Missing vap, ctx, or smp \n");
8446        return (EINVAL);
8447    }
8448
8449    is_dir = (ctx->f_attr.fa_attr & SMB_EFA_DIRECTORY) ? 1 : 0;
8450
8451    /* Use values from ctx */
8452    data_fork_size = ctx->f_attr.fa_size;
8453    data_fork_alloc = ctx->f_attr.fa_data_alloc;
8454    rsrc_fork_size = ctx->f_attr.fa_rsrc_size;
8455    rsrc_fork_alloc = ctx->f_attr.fa_rsrc_alloc;
8456
8457    /*
8458     * If there was a vnode np, then ctx->f_attr.fa_uid/fa_gid was set to
8459     * np->n_uid/n_gid which could have been updated by a Get ACL
8460     */
8461    uid = (uid_t) ctx->f_attr.fa_uid;
8462    gid = (gid_t) ctx->f_attr.fa_gid;
8463
8464    if (VATTR_IS_ACTIVE(vap, va_mode) ||
8465        VATTR_IS_ACTIVE(vap, va_uid) ||
8466        VATTR_IS_ACTIVE(vap, va_gid)) {
8467        /* This is used later in this function... */
8468        cuid = kauth_cred_getuid(vfs_context_ucred(context));
8469        isroot = cuid == 0;
8470
8471        /* Calculate uid, gid and mode from Query Dir results */
8472        if (is_dir) {
8473            flags |= SMBFS_GET_UGM_IS_DIR;
8474        }
8475
8476        if (!(ctx->f_attr.fa_valid_mask & FA_UNIX_MODES_VALID)) {
8477            /* Must not have had a vnode to get unix mode from */
8478            flags |= SMBFS_GET_UGM_REMOVE_POSIX_MODES;
8479        }
8480
8481        smb_get_uid_gid_mode(ctx->f_share, smp,
8482                             &ctx->f_attr, flags,
8483                             &uid, &gid, &mode);
8484    }
8485
8486    if (VATTR_IS_ACTIVE(vap, va_rdev)) {
8487        VATTR_RETURN(vap, va_rdev, 0);
8488    }
8489
8490    /*
8491     * The DIR_LINKCOUNT is the count of real directory hard links.
8492     * (i.e. its not the sum of the implied "." and ".." references
8493     *  typically used in stat's st_nlink field)
8494     */
8495    if (VATTR_IS_ACTIVE(vap, va_nlink)) {
8496        /* There ARE no hard links, at least not yet... */
8497        VATTR_RETURN(vap, va_nlink, 1);
8498    }
8499
8500    if (VATTR_IS_ACTIVE(vap, va_total_size)) {
8501        VATTR_RETURN(vap, va_total_size, data_fork_size + rsrc_fork_size);
8502    }
8503
8504    if (VATTR_IS_ACTIVE(vap, va_total_alloc)) {
8505        /* Should already be rounded up */
8506        VATTR_RETURN(vap, va_total_alloc, data_fork_alloc + rsrc_fork_alloc);
8507    }
8508
8509    if (VATTR_IS_ACTIVE(vap, va_data_size)) {
8510        VATTR_RETURN(vap, va_data_size, data_fork_size);
8511    }
8512
8513    if (VATTR_IS_ACTIVE(vap, va_data_alloc)) {
8514        VATTR_RETURN(vap, va_data_alloc, data_fork_alloc);
8515    }
8516
8517    if (VATTR_IS_ACTIVE(vap, va_iosize)) {
8518        VATTR_RETURN(vap, va_iosize, smp->sm_statfsbuf.f_bsize);
8519    }
8520
8521    if (VATTR_IS_ACTIVE(vap, va_uid)) {
8522        uid_t nuid;
8523
8524        if (SMBV_HAS_GUEST_ACCESS(SSTOVC(ctx->f_share))) {
8525            nuid = UNKNOWNUID;
8526        }
8527        else {
8528            /*
8529             * For servers that support the UNIX extensions we know the uid/gid.
8530             * For server that don't support ACLs then the node uid/gid will be
8531             * set to the mounted user's uid/gid. For all other servers we need
8532             * to get the ACL and translate the SID to a uid or gid. The uid/gid
8533             * really is for display purpose only and means nothing to us. We will
8534             * set the nodes ids if we get a request for the ACL, but otherwise
8535             * we leave them unset for performance reasons.
8536             */
8537            if (ctx->f_attr.fa_uid == KAUTH_UID_NONE) {
8538                nuid = smp->sm_args.uid;
8539            }
8540            else {
8541                nuid = uid;
8542            }
8543        }
8544
8545        if (!isroot) {
8546            if (((unsigned int)vfs_flags(smp->sm_mp)) & MNT_UNKNOWNPERMISSIONS)
8547                nuid = cuid;
8548            else if (nuid == UNKNOWNUID)
8549                nuid = cuid;
8550        }
8551
8552        VATTR_RETURN(vap, va_uid, nuid);
8553    }
8554
8555    if (VATTR_IS_ACTIVE(vap, va_gid)) {
8556        gid_t ngid;
8557
8558        if (SMBV_HAS_GUEST_ACCESS(SSTOVC(ctx->f_share))) {
8559            ngid = UNKNOWNGID;
8560        }
8561        else {
8562            /*
8563             * For servers that support the UNIX extensions we know the uid/gid.
8564             * For server that don't support ACLs then the node uid/gid will be
8565             * set to the mounted user's uid/gid. For all other servers we need
8566             * to get the ACL and translate the SID to a uid or gid. The uid/gid
8567             * really is for display purpose only and means nothing to us. We will
8568             * set the nodes ids if we get a request for the ACL, but otherwise
8569             * we leave them unset for performance reasons.
8570             */
8571            if (ctx->f_attr.fa_gid == KAUTH_GID_NONE) {
8572                ngid = smp->sm_args.gid;
8573            }
8574            else {
8575                ngid = gid;
8576            }
8577        }
8578
8579        if (!isroot) {
8580            gid_t cgid = kauth_cred_getgid(vfs_context_ucred(context));
8581            if (((unsigned int)vfs_flags(smp->sm_mp)) & MNT_UNKNOWNPERMISSIONS)
8582                ngid = cgid;
8583            else if (ngid == UNKNOWNUID)
8584                ngid = cgid;
8585        }
8586
8587        VATTR_RETURN(vap, va_gid, ngid);
8588    }
8589
8590    if (VATTR_IS_ACTIVE(vap, va_mode)) {
8591        if (ctx->f_attr.fa_vtype == VDIR) {
8592            VATTR_RETURN(vap, va_mode, (S_IFDIR | mode));
8593        }
8594
8595        if (ctx->f_attr.fa_vtype == VREG) {
8596            VATTR_RETURN(vap, va_mode, (S_IFREG | mode));
8597        }
8598
8599        if (ctx->f_attr.fa_vtype == VLNK) {
8600            VATTR_RETURN(vap, va_mode, (S_IFLNK | mode));
8601        }
8602    }
8603
8604    if (VATTR_IS_ACTIVE(vap, va_flags)) {
8605        uint32_t va_flags = 0;
8606
8607        if (ctx->f_attr.fa_attr & SMB_EFA_HIDDEN) {
8608            /*
8609             * Dont have to special case whether root vnode is hidden or not.
8610             * root volume doesn't show up in a readdirattr, I think?
8611             */
8612            va_flags |= UF_HIDDEN;
8613        }
8614
8615        /*
8616         * Remember that SMB_EFA_ARCHIVE means the items needs to be
8617         * archived and SF_ARCHIVED means the item has been archive.
8618         *
8619         * NOTE: Windows does not set ATTR_ARCHIVE bit for directories.
8620         */
8621        if ((ctx->f_attr.fa_vtype != VDIR) &&
8622            !(ctx->f_attr.fa_attr & SMB_EFA_ARCHIVE)) {
8623            va_flags |= SF_ARCHIVED;
8624        }
8625
8626		if (node_isimmutable(ctx->f_share, NULL, &ctx->f_attr)) {
8627            va_flags |= UF_IMMUTABLE;
8628        }
8629
8630        VATTR_RETURN(vap, va_flags, va_flags);
8631    }
8632
8633    /* va_acl is done in smbfs_vnop_getattrlistbulk() */
8634
8635    if (VATTR_IS_ACTIVE(vap, va_create_time)) {
8636        VATTR_RETURN(vap, va_create_time, ctx->f_attr.fa_crtime);
8637    }
8638
8639    if (VATTR_IS_ACTIVE(vap, va_access_time)) {
8640        VATTR_RETURN(vap, va_access_time, ctx->f_attr.fa_atime);
8641    }
8642
8643    if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
8644        VATTR_RETURN(vap, va_modify_time, ctx->f_attr.fa_mtime);
8645    }
8646
8647    if (VATTR_IS_ACTIVE(vap, va_change_time)) {
8648        if (ctx->f_share->ss_fstype == SMB_FS_FAT) {
8649            /*
8650             * FAT does not support change time, so just return the modify time.
8651             * Copied from the msdos code. SMB has no backup time so skip the
8652             * va_backup_time.
8653             */
8654            VATTR_RETURN(vap, va_change_time, ctx->f_attr.fa_mtime);
8655        }
8656        else {
8657            VATTR_RETURN(vap, va_change_time, ctx->f_attr.fa_chtime);
8658        }
8659    }
8660
8661    if (VATTR_IS_ACTIVE(vap, va_backup_time)) {
8662        /* Backup time not supported so return 0 */
8663        vap->va_backup_time.tv_sec = 0;
8664        vap->va_backup_time.tv_nsec = 0;
8665        VATTR_SET_SUPPORTED(vap, va_backup_time);
8666    }
8667
8668    if (VATTR_IS_ACTIVE(vap, va_fileid)) {
8669        file_id = smb2fs_smb_file_id_get(smp,
8670                                         ctx->f_attr.fa_ino,
8671                                         ctx->f_LocalName);
8672        VATTR_RETURN(vap, va_fileid, file_id);
8673    }
8674
8675    if (VATTR_IS_ACTIVE(vap, va_linkid)) {
8676        file_id = smb2fs_smb_file_id_get(smp,
8677                                         ctx->f_attr.fa_ino,
8678                                         ctx->f_LocalName);
8679        VATTR_RETURN(vap, va_linkid, file_id);
8680    }
8681
8682    if (VATTR_IS_ACTIVE(vap, va_parentid)) {
8683        lck_rw_lock_shared(&ctx->f_dnp->n_name_rwlock);
8684        file_id = smb2fs_smb_file_id_get(smp,
8685                                         ctx->f_dnp->n_ino,
8686                                         ctx->f_dnp->n_name);
8687        lck_rw_unlock_shared(&ctx->f_dnp->n_name_rwlock);
8688        VATTR_RETURN(vap, va_parentid, file_id);
8689    }
8690
8691    if (VATTR_IS_ACTIVE(vap, va_fsid)) {
8692        /* Copy AFP Client behavior */
8693        VATTR_RETURN(vap, va_fsid, vfs_statfs(vfs_statfs(smp->sm_mp)->f_fsid.val[0]));
8694    }
8695
8696    if (VATTR_IS_ACTIVE(vap, va_filerev)) {
8697        VATTR_RETURN(vap, va_filerev, 0);
8698    }
8699
8700    if (VATTR_IS_ACTIVE(vap, va_gen)) {
8701        VATTR_RETURN(vap, va_gen, 0);
8702    }
8703
8704    /*
8705     * We currently have no way to know the va_encoding. The VFS layer fills it
8706     * in with kTextEncodingMacUnicode = 0x7E, so use the same value;
8707     */
8708    if (VATTR_IS_ACTIVE(vap, va_encoding)) {
8709        VATTR_RETURN(vap, va_encoding, 0x7E);
8710    }
8711
8712    /*
8713     * If this is the root, let VFS find out the mount name, which may be
8714     * different from the real name
8715     */
8716    if (VATTR_IS_ACTIVE(vap, va_name)) {
8717        if (ctx->f_attr.fa_ino != smp->sm_root_ino) {
8718            strlcpy ((char*) vap->va_name, (char*) ctx->f_LocalName, MAXPATHLEN);
8719            VATTR_SET_SUPPORTED(vap, va_name);
8720        }
8721        else {
8722            /*
8723             * A cnode's name may be incorrect for the root of a mounted
8724             * filesystem (it can be mounted on a different directory name
8725             * than the name of the volume, such as "blah-1").  So for the
8726             * root directory, it's best to return the last element of the
8727             * location where the volume's mounted.
8728             */
8729            mp_name = mountpointname(vnode_mount(ctx->f_dnp->n_vnode));
8730            if (mp_name != NULL) {
8731                mp_namelen = strlen(mp_name);
8732
8733                /* Trim off any trailing slashes: */
8734                while ((mp_namelen > 0) && (mp_name[mp_namelen - 1] == '/')) {
8735                    --mp_namelen;
8736                }
8737
8738                /* If there's anything left, use it instead of the vol's name */
8739                if (mp_namelen > 0) {
8740                    strlcpy ((char*) vap->va_name, (char*) mp_name, MAXPATHLEN);
8741                    VATTR_SET_SUPPORTED(vap, va_name);
8742                }
8743                else {
8744                    SMBERROR("mountpointname failed to find a name\n");
8745                }
8746            }
8747            else {
8748                SMBERROR("mountpointname failed \n");
8749            }
8750        }
8751    }
8752
8753    /* va_uuuid, va_guuid is done in smbfs_vnop_getattrlistbulk() */
8754
8755    if (VATTR_IS_ACTIVE(vap, va_nchildren)) {
8756        /* Apparently 0 is a fine answer to return for a filesystem */
8757        VATTR_RETURN(vap, va_nchildren, 0);
8758    }
8759
8760    /* There ARE no hard links, at least not yet... */
8761    if (VATTR_IS_ACTIVE(vap, va_dirlinkcount)) {
8762        VATTR_RETURN(vap, va_dirlinkcount, 1);
8763    }
8764
8765    /*
8766     * We have no way to get:
8767     * va_addedtime,
8768     * va_dataprotect_class, va_dataprotect_flags, va_document_id
8769     */
8770
8771    /*
8772     * New fields added to the struct vnode_attr for the vnop_getattrlistbulk
8773     */
8774    if (VATTR_IS_ACTIVE(vap, va_devid)) {
8775        /* Copy AFP Client behavior */
8776        VATTR_RETURN(vap, va_devid, vfs_statfs(vfs_statfs(smp->sm_mp)->f_fsid.val[0]));
8777    }
8778
8779    if (VATTR_IS_ACTIVE(vap, va_objtype)) {
8780        /*
8781         * Because of the Steve/Conrad Symlinks we can never be completely
8782         * sure that we have the correct vnode type if its a file. Since we
8783         * don't support Steve/Conrad Symlinks with Darwin we can always count
8784         * on the vtype being correct. For directories we always know the
8785         * correct information.
8786         */
8787        VATTR_RETURN(vap, va_objtype, ctx->f_attr.fa_vtype);
8788    }
8789
8790    if (VATTR_IS_ACTIVE(vap, va_objtag)) {
8791        VATTR_RETURN(vap, va_objtag, VT_CIFS);
8792    }
8793
8794    if (VATTR_IS_ACTIVE(vap, va_user_access)) {
8795        /*
8796         * The effective permissions for the current user which we derive
8797         * from the max access
8798         */
8799        DBG_ASSERT(ctx->f_attr.fa_valid_mask & FA_MAX_ACCESS_VALID);
8800
8801        if (ctx->f_attr.fa_max_access & SMB2_FILE_READ_DATA) {
8802            cmn_user_rights |= R_OK;
8803        }
8804
8805        if (ctx->f_attr.fa_max_access & SMB2_FILE_WRITE_DATA) {
8806            cmn_user_rights |= W_OK;
8807        }
8808
8809        if (ctx->f_attr.fa_max_access & SMB2_FILE_EXECUTE) {
8810            cmn_user_rights |= X_OK;
8811        }
8812
8813        VATTR_RETURN(vap, va_user_access, cmn_user_rights);
8814    }
8815
8816    if (VATTR_IS_ACTIVE(vap, va_finderinfo)) {
8817        DBG_ASSERT(ctx->f_attr.fa_valid_mask & FA_FINDERINFO_VALID);
8818        bcopy(ctx->f_attr.fa_finder_info, vap->va_finderinfo, sizeof(u_int8_t) * 32);
8819        VATTR_SET_SUPPORTED(vap, va_finderinfo);
8820    }
8821
8822    if (VATTR_IS_ACTIVE(vap, va_rsrc_length)) {
8823        VATTR_RETURN(vap, va_rsrc_length, rsrc_fork_size);
8824    }
8825
8826    if (VATTR_IS_ACTIVE(vap, va_rsrc_alloc)) {
8827        VATTR_RETURN(vap, va_rsrc_alloc, rsrc_fork_alloc);
8828    }
8829
8830    if (VATTR_IS_ACTIVE(vap, va_fsid64)) {
8831        /* Copy AFP Client behavior */
8832        memcpy(&vap->va_fsid64, &(vfs_statfs(smp->sm_mp)->f_fsid), sizeof(vap->va_fsid64));
8833        VATTR_SET_SUPPORTED(vap, va_fsid64);
8834    }
8835
8836    return (0);
8837}
8838
8839/*
8840 * Check for any missing data in the ctx that we could not get from just
8841 * the enumeration and fill in the missing data. Missing data could be Resource
8842 * Fork Info, Finder Info, etc. Missing data can come from a pre existing
8843 * vnode, or retrieved from over the wire.
8844 */
8845static void
8846smbfs_update_ctx(struct vnode *vp,
8847                 struct vnode_attr *vap,
8848                 struct smbfs_fctx *ctx,
8849                 struct vfs_context *context)
8850{
8851    uint32_t is_dir;
8852    int error;
8853    uint32_t stream_flags = 0;
8854    struct smbnode *np = NULL;
8855    uint32_t need_rsrc_fork = 0;
8856    size_t afp_size = 0;
8857    uint8_t afp_info[60] = {0};
8858    uint8_t zero_finfo[32] = {0};
8859    uio_t afp_uio = NULL;
8860    SMBFID fid = 0;
8861    struct timespec ts;
8862    uint32_t rsrc_fork_from_cache = 0;
8863    uint32_t finder_info_from_cache = 0;
8864    uint32_t max_access_from_cache = 0;
8865    uint32_t need_finder_info = 0;
8866    uint32_t need_cmn_user_access = 0;
8867
8868    SMB_LOG_KTRACE(SMB_DBG_UPDATE_CTX | DBG_FUNC_START, vap->va_active, 0, 0, 0, 0);
8869
8870    /* Do we need Resource Fork info? */
8871    is_dir = (ctx->f_attr.fa_attr & SMB_EFA_DIRECTORY) ? 1 : 0;
8872    if ((!is_dir) &&
8873        (VATTR_IS_ACTIVE(vap, va_total_size) ||
8874         VATTR_IS_ACTIVE(vap, va_total_alloc) ||
8875         VATTR_IS_ACTIVE(vap, va_rsrc_length) ||
8876         VATTR_IS_ACTIVE(vap, va_rsrc_alloc))) {
8877            need_rsrc_fork = 1;
8878        }
8879
8880    if (VATTR_IS_ACTIVE(vap, va_finderinfo)) {
8881        need_finder_info = 1;
8882    }
8883
8884    if (VATTR_IS_ACTIVE(vap, va_user_access)) {
8885        need_cmn_user_access = 1;
8886    }
8887
8888    /*
8889     * We may already have all the meta data we need from Mac <-> Mac (not yet
8890     * implemented) or dont need Resource Fork, Finder Info, or Max Access data.
8891     * If we do have all the needed meta data, then just go update vnode caches
8892     * if we have a vnode and then pack the return attribute block.
8893     */
8894    if ((need_rsrc_fork && (ctx->f_attr.fa_valid_mask & FA_RSRC_FORK_VALID)) &&
8895        (need_finder_info && (ctx->f_attr.fa_valid_mask & FA_FINDERINFO_VALID)) &&
8896        (need_cmn_user_access && (ctx->f_attr.fa_valid_mask & FA_MAX_ACCESS_VALID))) {
8897        SMB_LOG_KTRACE(SMB_DBG_UPDATE_CTX | DBG_FUNC_NONE,
8898                       0xabc001, 0, 0, 0, 0);
8899        goto update_caches;
8900    }
8901
8902    /*
8903     * Figure out what attributes we are missing and then go get them from
8904     * either the vnode or from the server.
8905     */
8906
8907    /*
8908     * Do we have a vnode that already has the attributes we need?
8909     */
8910    if (vp != NULL) {
8911        np = VTOSMB(vp);
8912
8913        /* Check cached Resource Fork info */
8914        if ((need_rsrc_fork) &&
8915            !(ctx->f_attr.fa_valid_mask & FA_RSRC_FORK_VALID)) {
8916
8917            lck_mtx_lock(&np->rfrkMetaLock);
8918
8919            if (np->rfrk_cache_timer != 0) {
8920                /* Resource fork data is valid in vnode so use it */
8921                rsrc_fork_from_cache = 1;
8922                ctx->f_attr.fa_valid_mask |= FA_RSRC_FORK_VALID;
8923                ctx->f_attr.fa_rsrc_size = np->rfrk_size;
8924                ctx->f_attr.fa_rsrc_alloc = np->rfrk_alloc_size;
8925
8926                SMB_LOG_KTRACE(SMB_DBG_UPDATE_CTX | DBG_FUNC_NONE,
8927                               0xabc002, 0, 0, 0, 0);
8928            }
8929
8930            lck_mtx_unlock(&np->rfrkMetaLock);
8931        }
8932
8933        /* Check cached Finder Info */
8934        if (need_finder_info &&
8935            !(ctx->f_attr.fa_valid_mask & FA_FINDERINFO_VALID)) {
8936
8937            if (np->finfo_cache_timer != 0) {
8938                /* Finder Info data is valid in vnode so use it */
8939                finder_info_from_cache = 1;
8940                ctx->f_attr.fa_valid_mask |= FA_FINDERINFO_VALID;
8941                bcopy(&np->finfo, ctx->f_attr.fa_finder_info, sizeof(u_int8_t) * 32);
8942
8943                SMB_LOG_KTRACE(SMB_DBG_UPDATE_CTX | DBG_FUNC_NONE,
8944                               0xabc003, 0, 0, 0, 0);
8945            }
8946        }
8947
8948        /* Check cached Max Info */
8949        if (need_cmn_user_access &&
8950            !(ctx->f_attr.fa_valid_mask & FA_MAX_ACCESS_VALID)) {
8951            if (timespeccmp(&np->maxAccessRightChTime, &np->n_chtime, ==)) {
8952
8953                /* Max Access data is valid in vnode so use it */
8954                max_access_from_cache = 1;
8955                ctx->f_attr.fa_valid_mask |= FA_MAX_ACCESS_VALID;
8956                ctx->f_attr.fa_max_access = np->maxAccessRights;
8957
8958                SMB_LOG_KTRACE(SMB_DBG_UPDATE_CTX | DBG_FUNC_NONE,
8959                               0xabc004, 0, 0, 0, 0);
8960            }
8961        }
8962    }
8963
8964    /* Are we still missing attribute information? */
8965    if ((need_rsrc_fork && !(ctx->f_attr.fa_valid_mask & FA_RSRC_FORK_VALID)) ||
8966        (need_finder_info && !(ctx->f_attr.fa_valid_mask & FA_FINDERINFO_VALID)) ||
8967        (need_cmn_user_access && !(ctx->f_attr.fa_valid_mask & FA_MAX_ACCESS_VALID))) {
8968        /*
8969         * This will get us
8970         * 1) Resource Fork sizes
8971         * 2) Whether Finder Info exists or not on the item
8972         * 3) For SMB 2/3, gets the max access on the item
8973         *
8974         * If we have to ask the server for the resource fork info or the
8975         * user access, do it now as this will also tell us if there is any
8976         * Finder Info on the file or not. For SMB 2/3, it will also get us the
8977         * max access which is used for ATTR_CMN_USERACCESS.
8978         *
8979         * Best case (SMB 2/3) - Just this one call because no Finder Info found
8980         * Worst case (SMB 2/3) - This call and another call to read Finder Info
8981         *
8982         * Best case (SMB 1) - This call and 2 calls (Create/Read + Close) to
8983         *                       read Finder Info which will get the max access
8984         *                       for SMB 1
8985         * Worst case (SMB 1) - This call and 2 calls (Create + Close) to get
8986         *                        max access because there is no Finder Info
8987         */
8988        error = smbfs_smb_qstreaminfo(ctx->f_share, ctx->f_dnp, (is_dir) ? VDIR : VREG,
8989                                      ctx->f_LocalName, ctx->f_LocalNameLen,
8990                                      SFM_RESOURCEFORK_NAME,
8991                                      NULL, NULL,
8992                                      &ctx->f_attr.fa_rsrc_size, &ctx->f_attr.fa_rsrc_alloc,
8993                                      &stream_flags, &ctx->f_attr.fa_max_access,
8994                                      context);
8995
8996        SMB_LOG_KTRACE(SMB_DBG_UPDATE_CTX | DBG_FUNC_NONE,
8997                       0xabc005, error, 0, 0, 0);
8998
8999        if ((!error) || (error == ENOATTR)) {
9000            /* smbfs_smb_qstreaminfo worked */
9001
9002            if (stream_flags & SMB_NO_SUBSTREAMS) {
9003                /* No named streams at all on item */
9004                ctx->f_attr.fa_valid_mask |= FA_FSTATUS_VALID;
9005                ctx->f_attr.fa_fstatus = kNO_SUBSTREAMS;
9006            }
9007            else {
9008                /* At least one named stream on item */
9009                ctx->f_attr.fa_valid_mask |= FA_FSTATUS_VALID;
9010                ctx->f_attr.fa_fstatus = 0;
9011            }
9012
9013            /* Did we need Resource Fork info? */
9014            if (need_rsrc_fork &&
9015                !(ctx->f_attr.fa_valid_mask & FA_RSRC_FORK_VALID)) {
9016                /*
9017                 * Successfully got Resource Fork Info. Its either already in
9018                 * f_attr or no Resource Fork was found
9019                 */
9020                ctx->f_attr.fa_valid_mask |= FA_RSRC_FORK_VALID;
9021
9022                if (stream_flags & SMB_NO_RESOURCE_FORK) {
9023                    /* No Resource Fork, so set resource fork lengths to zero */
9024                    ctx->f_attr.fa_rsrc_size = 0;
9025                    ctx->f_attr.fa_rsrc_alloc = 0;
9026                }
9027                else {
9028                    /* SMBDEBUG("%s rsrc fork from qstreaminfo\n", ctx->f_LocalName); */
9029                }
9030            }
9031
9032            /* Did we need Finder Info? */
9033            if (need_finder_info &&
9034                !(ctx->f_attr.fa_valid_mask & FA_FINDERINFO_VALID)) {
9035                /*
9036                 * Now we know if there is Finder Info or not on the item
9037                 */
9038                if (stream_flags & SMB_NO_FINDER_INFO) {
9039                    /* No Finder Info, so set Finder Info to all zeros */
9040                    ctx->f_attr.fa_valid_mask |= FA_FINDERINFO_VALID;
9041                    bcopy(&zero_finfo, ctx->f_attr.fa_finder_info,
9042                          sizeof(u_int8_t) * 32);
9043                }
9044            }
9045
9046            /* Did we need Max Access? */
9047            if (need_cmn_user_access &&
9048                !(ctx->f_attr.fa_valid_mask & FA_MAX_ACCESS_VALID)) {
9049                if (SSTOVC(ctx->f_share)->vc_flags & SMBV_SMB2) {
9050                    /*
9051                     * Only SMB 2/3 can get max access from
9052                     * smbfs_smb_qstreaminfo call
9053                     */
9054                    ctx->f_attr.fa_valid_mask |= FA_MAX_ACCESS_VALID;
9055                }
9056            }
9057        }
9058        else {
9059            /* Got some sort of error. This shouldn't happen */
9060            SMBDEBUG("smbfs_smb_qstreaminfo failed %d for %s \n",
9061                     error, ctx->f_LocalName);
9062        }
9063    }
9064
9065    /*
9066     * Do we still need to get the Finder Info?  At this point we know
9067     * (1) Either no vnode or the cached finder info is not present
9068     * (2) smbfs_smb_qstreaminfo told us that there is Finder Info on the item
9069     *
9070     * <11615553> For SMB 1, we can NOT get both the Finder Info and max
9071     * access at the same time. Windows based servers will often give
9072     * "Unspecified error" when you do a CreateAndX with extended response (ie
9073     * max access) combined with Read of a named stream.
9074     */
9075    if (need_finder_info &&
9076        !(ctx->f_attr.fa_valid_mask & FA_FINDERINFO_VALID)) {
9077
9078        do {
9079            afp_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
9080            if (afp_uio == NULL) {
9081                SMBERROR("uio_create failed for %s \n", ctx->f_LocalName);
9082                break;
9083            }
9084
9085            error = uio_addiov(afp_uio, CAST_USER_ADDR_T(afp_info),
9086                               sizeof(afp_info));
9087            if (error) {
9088                SMBERROR("uio_addiov failed for %s \n", ctx->f_LocalName);
9089                break;
9090            }
9091
9092            uio_setoffset(afp_uio, 0);
9093
9094            /* Open/Read/Close the Finder Info */
9095            error = smbfs_smb_cmpd_create_read_close(ctx->f_share, ctx->f_dnp,
9096                                                     ctx->f_LocalName, ctx->f_LocalNameLen,
9097                                                     SFM_FINDERINFO_NAME, strlen(SFM_FINDERINFO_NAME),
9098                                                     afp_uio, &afp_size,
9099                                                     NULL,
9100                                                     context);
9101
9102            SMB_LOG_KTRACE(SMB_DBG_UPDATE_CTX | DBG_FUNC_NONE,
9103                           0xabc006, error, 0, 0, 0);
9104
9105            if (!error) {
9106                /* Successfully got Finder Info */
9107                ctx->f_attr.fa_valid_mask |= FA_FINDERINFO_VALID;
9108
9109                /* Verify returned size */
9110                if (afp_size != AFP_INFO_SIZE) {
9111                    /* Could be a 0 size returned meaning no Finder Info */
9112                    if (afp_size != 0) {
9113                        /* SMBDEBUG("%s Finder Info size mismatch %ld != %d \n",
9114                         ctx->f_LocalName, afp_size, AFP_INFO_SIZE); */
9115                    }
9116                    bcopy(&zero_finfo, ctx->f_attr.fa_finder_info,
9117                          sizeof(u_int8_t) * 32);
9118                }
9119                else {
9120                    /* Correct size, so just copy it in */
9121                    bcopy(&afp_info[AFP_INFO_FINDER_OFFSET],
9122                          ctx->f_attr.fa_finder_info,
9123                          sizeof(u_int8_t) * 32);
9124                    /* SMBDEBUG("Finder Info 0x%x 0x%x 0x%x 0x%x for %s \n",
9125                     afp_info[AFP_INFO_FINDER_OFFSET],
9126                     afp_info[AFP_INFO_FINDER_OFFSET + 1],
9127                     afp_info[AFP_INFO_FINDER_OFFSET + 2],
9128                     afp_info[AFP_INFO_FINDER_OFFSET + 3],
9129                     ctx->f_LocalName); */
9130                }
9131            }
9132            else {
9133                if (error != ENOENT) {
9134                    SMBDEBUG("smbfs_smb_cmpd_create_read_close failed %d for %s \n",
9135                             error, ctx->f_LocalName);
9136                }
9137            }
9138
9139            if (afp_uio) {
9140                uio_free(afp_uio);
9141            }
9142        } while (0);
9143    }
9144
9145    /* Do we still need Max Access and its SMB 1? */
9146    if (need_cmn_user_access &&
9147        !(ctx->f_attr.fa_valid_mask & FA_MAX_ACCESS_VALID) &&
9148        !(SSTOVC(ctx->f_share)->vc_flags & SMBV_SMB2))
9149    {
9150        error = smb1fs_smb_open_maxaccess(ctx->f_share, ctx->f_dnp,
9151                                          ctx->f_LocalName, ctx->f_LocalNameLen,
9152                                          &fid, &ctx->f_attr.fa_max_access,
9153                                          context);
9154        if (!error) {
9155            ctx->f_attr.fa_valid_mask |= FA_MAX_ACCESS_VALID;
9156        }
9157
9158        if (fid) {
9159            (void)smbfs_smb_close(ctx->f_share, fid, context);
9160        }
9161    }
9162
9163update_caches:
9164
9165    /* Update vnodes caches if the data did not come from the vnode caches */
9166    if (vp) {
9167        np = VTOSMB(vp);
9168
9169        if (ctx->f_attr.fa_valid_mask & FA_FSTATUS_VALID) {
9170            /* Update whether there is a named streams or not */
9171            np->n_fstatus = ctx->f_attr.fa_fstatus;
9172        }
9173
9174        /* Do we have updated resource fork info? */
9175        if ((rsrc_fork_from_cache == 0) &&
9176            need_rsrc_fork &&
9177            (ctx->f_attr.fa_valid_mask & FA_RSRC_FORK_VALID)) {
9178
9179            lck_mtx_lock(&np->rfrkMetaLock);
9180            np->rfrk_size = ctx->f_attr.fa_rsrc_size;
9181            np->rfrk_alloc_size = ctx->f_attr.fa_rsrc_alloc;
9182            nanouptime(&ts);
9183            np->rfrk_cache_timer = ts.tv_sec;
9184            lck_mtx_unlock(&np->rfrkMetaLock);
9185        }
9186
9187        /* Do we have updated Finder Info? */
9188        if ((finder_info_from_cache == 0) &&
9189            need_finder_info &&
9190            (ctx->f_attr.fa_valid_mask & FA_FINDERINFO_VALID)) {
9191
9192            bcopy(ctx->f_attr.fa_finder_info, &np->finfo,
9193                  sizeof(u_int8_t) * 32);
9194            nanouptime(&ts);
9195            np->finfo_cache_timer = ts.tv_sec;
9196        }
9197
9198        /* Do we have updated Max Access? */
9199        if ((max_access_from_cache == 0) &&
9200            need_cmn_user_access &&
9201            (ctx->f_attr.fa_valid_mask & FA_MAX_ACCESS_VALID)) {
9202
9203            np->maxAccessRights = ctx->f_attr.fa_max_access;
9204            np->maxAccessRightChTime = ctx->f_attr.fa_chtime;
9205        }
9206
9207        /* We can get the unix mode from the vnode */
9208        if (np->n_flag & NHAS_POSIXMODES) {
9209            ctx->f_attr.fa_permissions = np->n_mode;
9210            ctx->f_attr.fa_valid_mask |= FA_UNIX_MODES_VALID;
9211        }
9212
9213        /* We can get the uid/gid from the vnode */
9214        ctx->f_attr.fa_uid = np->n_uid;
9215        ctx->f_attr.fa_gid = np->n_gid;
9216    }
9217
9218    /*
9219     * Error Handling. At this point, we should have valid information and if
9220     * we do not, then some earlier error must have occurred, so fill in with
9221     * default values.
9222     */
9223    if (need_rsrc_fork &&
9224        !(ctx->f_attr.fa_valid_mask & FA_RSRC_FORK_VALID)) {
9225        /* Assume resource fork lengths of zero */
9226        ctx->f_attr.fa_valid_mask |= FA_RSRC_FORK_VALID;
9227        ctx->f_attr.fa_rsrc_size = 0;
9228        ctx->f_attr.fa_rsrc_alloc = 0;
9229    }
9230
9231    if (need_finder_info &&
9232        !(ctx->f_attr.fa_valid_mask & FA_FINDERINFO_VALID)) {
9233        /* Assume zero Finder Info */
9234        ctx->f_attr.fa_valid_mask |= FA_FINDERINFO_VALID;
9235        bcopy(&zero_finfo, ctx->f_attr.fa_finder_info, sizeof(u_int8_t) * 32);
9236    }
9237
9238    if (need_cmn_user_access &&
9239        !(ctx->f_attr.fa_valid_mask & FA_MAX_ACCESS_VALID)) {
9240        /* Assume full access */
9241        ctx->f_attr.fa_valid_mask |= FA_MAX_ACCESS_VALID;
9242        ctx->f_attr.fa_max_access = SA_RIGHT_FILE_ALL_ACCESS | STD_RIGHT_ALL_ACCESS;
9243    }
9244
9245    SMB_LOG_KTRACE(SMB_DBG_UPDATE_CTX | DBG_FUNC_END, 0, 0, 0, 0, 0);
9246}
9247
9248static int
9249smbfs_vnop_getattrlistbulk(struct vnop_getattrlistbulk_args *ap)
9250/* struct vnop_getattrlistbulk_args {
9251                                      struct vnodeop_desc *a_desc;
9252                                      vnode_t a_vp;
9253                                      struct attrlist *a_alist;
9254                                      struct vnode_attr *a_vap;
9255                                      struct uio *a_uio;
9256                                      void *a_private;
9257                                      uint64_t a_options;
9258                                      int32_t *a_eofflag;
9259                                      int32_t *a_actualcount;
9260                                      vfs_context_t a_context;
9261                                      } *ap; */
9262{
9263    struct vnode *vp = NULL;
9264    struct vnode *dvp = ap->a_vp;
9265    uio_t uio = ap->a_uio;
9266    vfs_context_t context = ap->a_context;
9267    struct smbnode *dnp = NULL;
9268    struct smbfs_fctx *ctx;
9269    off_t offset, orig_resid;
9270    int error = 0, tmp_error = 0;
9271    struct smb_share *share = NULL;
9272    struct smbmount *smp = NULL;
9273    struct vnode_attr *vap = ap->a_vap;
9274    char *name = NULL;
9275    int free_name = 0;
9276    ssize_t fixedlen = 0, maxfixed_len = 0;
9277    ssize_t variable_len = 0, acl_len = 0;
9278    enum vtype vnode_type = VREG;
9279
9280    /* Check for invalid buffer space. */
9281    if ((uio_resid(uio) <= 0) || (uio_iovcnt(uio) > 1)) {
9282        SMBDEBUG("Invalid buf size\n");
9283        return (EINVAL);
9284    }
9285
9286    *(ap->a_actualcount) = 0;
9287    *(ap->a_eofflag) = 0;
9288
9289    /*
9290     * Lock parent dir that we are enumerating
9291     */
9292    if ((error = smbnode_lock(VTOSMB(dvp), SMBFS_EXCLUSIVE_LOCK))) {
9293        return (error);
9294    }
9295
9296    VTOSMB(dvp)->n_lastvop = smbfs_vnop_getattrlistbulk;
9297
9298    dnp = VTOSMB(dvp);
9299    smp = VTOSMBFS(dvp);
9300
9301    SMB_LOG_KTRACE(SMB_DBG_GET_ATTRLIST_BULK | DBG_FUNC_START, dnp->d_fid, 0, 0, 0, 0);
9302
9303    /* Get Share reference */
9304    share = smb_get_share_with_reference(VTOSMBFS(dvp));
9305
9306    /* Non FAT Filesystem and named streams are required */
9307    if ((share->ss_fstype == SMB_FS_FAT) ||
9308        !(share->ss_attributes & FILE_NAMED_STREAMS)) {
9309        smb_share_rele(share, context);
9310        SMBDEBUG("FAT or no named streams so smbfs_vnop_getattrlistbulk not supported\n");
9311        error = ENOTSUP;
9312        goto done;
9313    }
9314
9315    /*
9316     * Do we need to start or restart the directory listing
9317     *
9318     * The uio_offset is actually just used to store whatever we want.  In HFS,
9319     * they store an index and a dir tag. For SMB, we will store just the offset
9320     */
9321    offset = uio_offset(uio);
9322    if (!dnp->d_fctx ||
9323        (dnp->d_fctx->f_share != share) ||
9324        (offset == 0) ||
9325        (offset != dnp->d_offset)) {
9326        smbfs_closedirlookup(dnp, context);
9327        error = smbfs_smb_findopen(share, dnp, "*", 1, &dnp->d_fctx, TRUE,
9328                                   context);
9329    }
9330
9331    /*
9332     * The directory fctx keeps a reference on the share so we can release our
9333     * reference on the share now.
9334     */
9335    smb_share_rele(share, context);
9336
9337    if (error) {
9338        lck_rw_lock_shared(&dnp->n_name_rwlock);
9339        SMBERROR("Can't open search for %s, error = %d", dnp->n_name, error);
9340        lck_rw_unlock_shared(&dnp->n_name_rwlock);
9341        goto done;
9342    }
9343    ctx = dnp->d_fctx;
9344
9345    /*
9346     * They are continuing from some point ahead of us in the buffer. Skip all
9347     * entries until we reach their point in the buffer.
9348     */
9349    while (dnp->d_offset < offset) {
9350        error = smbfs_findnext(ctx, context);
9351        if (error) {
9352            smbfs_closedirlookup(dnp, context);
9353            goto done;
9354        }
9355        dnp->d_offset++;
9356    }
9357
9358    /* Do we need to allocate va_name? */
9359    if (VATTR_IS_ACTIVE(vap, va_name)) {
9360        if (vap->va_name == NULL) {
9361            /* We need to allocate space for va_name */
9362            SMB_MALLOC(name,
9363                       char *,
9364                       MAXPATHLEN,
9365                       M_SMBTEMP,
9366                       M_WAITOK | M_ZERO);
9367            if (name == NULL) {
9368                SMBERROR("Malloc for va_name failed \n");
9369                error = ENOMEM;
9370                goto done;
9371            }
9372
9373            free_name = 1;
9374        }
9375        else {
9376            name = vap->va_name;
9377        }
9378
9379        /* Add name length for termination check */
9380        variable_len += MAXPATHLEN;
9381    }
9382
9383    /* Loop until we end the search or we don't have enough room for the max element */
9384    while (uio_resid(uio)) {
9385        /* Get one entry out of the buffer and fill in ctx with its info */
9386        error = smbfs_findnext(ctx, context);
9387        if (error) {
9388            break;
9389        }
9390
9391        /*
9392         * Get the vnode type. vfs_setup_vattr_from_attrlist() only cares if
9393         * its a dir or not.
9394         */
9395        vnode_type = (ctx->f_attr.fa_attr & SMB_EFA_DIRECTORY) ? VDIR : VREG;
9396
9397        /* Make sure the vap is zero'd out and set up correctly */
9398        bzero(vap, sizeof(struct vnode_attr));
9399        vfs_setup_vattr_from_attrlist(ap->a_alist, vap, vnode_type, &fixedlen,
9400                                      context);
9401        vap->va_name = name;
9402
9403        /* Calculate maxfixed_len for termination check */
9404        if (fixedlen > maxfixed_len) {
9405            maxfixed_len = fixedlen;
9406        }
9407
9408        /*
9409         * <14430881> If file IDs are supported by this server, skip any
9410         * child that has the same id as the current parent that we are
9411         * enumerating. Seems like snapshot dirs have the same id as the parent
9412         * and that will cause us to deadlock when we find the vnode with same
9413         * id and then try to lock it again (deadlock on parent id).
9414         */
9415        if (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS) {
9416            if (ctx->f_attr.fa_ino == dnp->n_ino) {
9417                SMBDEBUG("Skipping <%s> as it has same ID as parent\n",
9418                         ctx->f_LocalName);
9419                continue;
9420            }
9421        }
9422
9423        if ((ctx->f_share->ss_attributes & FILE_PERSISTENT_ACLS) &&
9424            (VATTR_IS_ACTIVE(vap, va_acl) ||
9425             VATTR_IS_ACTIVE(vap, va_guuid) ||
9426             VATTR_IS_ACTIVE(vap, va_uuuid))) {
9427                /*
9428                 * In order to get the ACL, we are going to need a vnode
9429                 * created. Someday, we may be able to get the ACL without
9430                 * a vnode, but that is a lot of code to change at this time.
9431                 */
9432                tmp_error = smbfs_nget(share, vnode_mount(dvp),
9433                                       dvp, ctx->f_LocalName, ctx->f_LocalNameLen,
9434                                       &ctx->f_attr, &vp,
9435                                       MAKEENTRY, SMBFS_NGET_CREATE_VNODE,
9436                                       context);
9437
9438                /* Calculate maxacl_len for termination check */
9439                if (!acl_len) {
9440                    acl_len = KAUTH_ACL_SIZE(KAUTH_ACL_MAX_ENTRIES);
9441                }
9442        }
9443        else {
9444            /*
9445             * Check to see if vnode already exists. If so, then can pull the
9446             * data from the inode instead of having to poll the server for
9447             * missing info
9448             *
9449             * <14985596> Go ahead and create the vnode if its not already
9450             * there. This improves Finder browsing performance
9451             */
9452            tmp_error = smbfs_nget(share, vnode_mount(dvp),
9453                                   dvp, ctx->f_LocalName, ctx->f_LocalNameLen,
9454                                   &ctx->f_attr, &vp,
9455                                   MAKEENTRY, SMBFS_NGET_CREATE_VNODE,
9456                                   context);
9457        }
9458
9459        SMB_LOG_KTRACE(SMB_DBG_GET_ATTRLIST_BULK | DBG_FUNC_NONE,
9460                       0xabc001, tmp_error, 0, 0, 0);
9461
9462        /* Dont care if we got an error or not, just whether vp == NULL or not */
9463        if (vp != NULL) {
9464            /*
9465             * Enumerates alway return the correct case of the name.
9466             * Update the name and parent if needed.
9467             */
9468            smbfs_update_name_par(ctx->f_share, dvp, vp,
9469                                  &ctx->f_attr.fa_reqtime,
9470                                  ctx->f_LocalName, ctx->f_LocalNameLen);
9471        }
9472
9473        /*
9474         * Is there enough buffer space remaining in the uio to add this?
9475         * Need at least 4 bytes for len, and then 4 bytes for one data element
9476         */
9477        if (uio_resid(uio) <= 8) {
9478            if (vp != NULL) {
9479                smbnode_unlock(VTOSMB(vp));
9480                vnode_put(vp);
9481            }
9482            break;
9483        }
9484
9485        /*
9486         * If there is any missing or stale data in the ctx, fill it in
9487         */
9488        smbfs_update_ctx(vp, vap, ctx, context);
9489
9490        /*
9491         * Fill in the ACL info here if needed. ACL data has to have a
9492         * vnode to use (at least for now).
9493         */
9494        if ((share->ss_attributes & FILE_PERSISTENT_ACLS) &&
9495            (vp != NULL) &&
9496            (VATTR_IS_ACTIVE(vap, va_acl) ||
9497             VATTR_IS_ACTIVE(vap, va_guuid) ||
9498             VATTR_IS_ACTIVE(vap, va_uuuid))) {
9499                DBG_ASSERT(!vnode_isnamedstream(vp));
9500                (void)smbfs_getsecurity(share, VTOSMB(vp), vap, context);
9501        }
9502
9503        /*
9504         * If we have a vnode, then it must be unlocked before calling
9505         * vfs_attr_pack
9506         */
9507        if (vp != NULL) {
9508            smbnode_unlock(VTOSMB(vp));
9509        }
9510
9511        /*
9512         * Fill in the vap using the data from the ctx
9513         */
9514        tmp_error = smbfs_pack_vap(smp, ctx, vap, context);
9515        if (tmp_error == 0) {
9516            /* Save current resid so can tell if uio is full */
9517            orig_resid = uio_resid(uio);
9518
9519            /* Copy info from vap into uio */
9520            tmp_error = vfs_attr_pack(vp, uio, ap->a_alist, ap->a_options,
9521                                      ap->a_vap, NULL, ap->a_context);
9522            if (tmp_error == 0) {
9523                if (orig_resid == uio_resid(uio)) {
9524                    /* No more space in uio */
9525                    tmp_error = ENOBUFS;
9526                }
9527                else {
9528                    /* Successfully added an entry */
9529                    *ap->a_actualcount += 1;
9530                    dnp->d_offset++;
9531
9532                    /*
9533                     * Termination check.
9534                     * Make sure the uio buffer has enough space
9535                     * for another entry.
9536                     */
9537                    if (uio_resid(uio) < (maxfixed_len + variable_len + acl_len)) {
9538                        tmp_error = ENOBUFS;
9539                    }
9540                }
9541            }
9542            else {
9543                SMBERROR("vfs_attr_pack() failed for %s, error %d",
9544                         ctx->f_LocalName, tmp_error);
9545            }
9546        }
9547        else {
9548            SMBERROR("smbfs_pack_vap() failed for %s, error %d",
9549                     ctx->f_LocalName, tmp_error);
9550        }
9551
9552        /* Done with the vp */
9553        if (vp != NULL) {
9554            vnode_put(vp);
9555        }
9556
9557        if (tmp_error) {
9558            /* Either got some error or uio is full so all done */
9559            break;
9560        }
9561
9562    } /* while loop */
9563
9564    if (error == ENOENT) {
9565        *(ap->a_eofflag) = TRUE;
9566        error = 0;
9567    }
9568
9569done:
9570    /* Last offset into uio_offset. */
9571    uio_setoffset(uio, dnp->d_offset);
9572
9573    /* If we allocated it, then we free it */
9574    if ((free_name == 1) && (name != NULL)) {
9575        SMB_FREE(name, M_SMBTEMP);
9576    }
9577
9578    smbnode_unlock(VTOSMB(dvp));
9579
9580    SMB_LOG_KTRACE(SMB_DBG_GET_ATTRLIST_BULK | DBG_FUNC_END,
9581                   error, *ap->a_actualcount, 0, 0, 0);
9582
9583    return (error);
9584}
9585
9586vnop_t **smbfs_vnodeop_p;
9587static struct vnodeopv_entry_desc smbfs_vnodeop_entries[] = {
9588	{ &vnop_default_desc,		(vnop_t *) vn_default_error },
9589	{ &vnop_advlock_desc,		(vnop_t *) smbfs_vnop_advlock },
9590	{ &vnop_close_desc,			(vnop_t *) smbfs_vnop_close },
9591	{ &vnop_create_desc,		(vnop_t *) smbfs_vnop_create },
9592	{ &vnop_fsync_desc,			(vnop_t *) smbfs_vnop_fsync },
9593	{ &vnop_getattr_desc,		(vnop_t *) smbfs_vnop_getattr },
9594	{ &vnop_pagein_desc,		(vnop_t *) smbfs_vnop_pagein },
9595	{ &vnop_inactive_desc,		(vnop_t *) smbfs_vnop_inactive },
9596	{ &vnop_ioctl_desc,			(vnop_t *) smbfs_vnop_ioctl },
9597	{ &vnop_link_desc,			(vnop_t *) smbfs_vnop_link },
9598	{ &vnop_lookup_desc,		(vnop_t *) smbfs_vnop_lookup },
9599	{ &vnop_mkdir_desc,			(vnop_t *) smbfs_vnop_mkdir },
9600	{ &vnop_mknod_desc,			(vnop_t *) smbfs_vnop_mknod },
9601	{ &vnop_mmap_desc,			(vnop_t *) smbfs_vnop_mmap },
9602	{ &vnop_mnomap_desc,		(vnop_t *) smbfs_vnop_mnomap },
9603	{ &vnop_open_desc,			(vnop_t *) smbfs_vnop_open },
9604	{ &vnop_compound_open_desc,	(vnop_t *) smbfs_vnop_compound_open },
9605	{ &vnop_pathconf_desc,		(vnop_t *) smbfs_vnop_pathconf },
9606	{ &vnop_pageout_desc,		(vnop_t *) smbfs_vnop_pageout },
9607    { &vnop_copyfile_desc,		(vnop_t *) smbfs_vnop_copyfile },
9608	{ &vnop_read_desc,			(vnop_t *) smbfs_vnop_read },
9609	{ &vnop_readdir_desc,		(vnop_t *) smbfs_vnop_readdir },
9610    { &vnop_readdirattr_desc,   (vnop_t *) smbfs_vnop_readdirattr },
9611    { &vnop_getattrlistbulk_desc, (vnop_t *) smbfs_vnop_getattrlistbulk },
9612	{ &vnop_readlink_desc,		(vnop_t *) smbfs_vnop_readlink },
9613	{ &vnop_reclaim_desc,		(vnop_t *) smbfs_vnop_reclaim },
9614	{ &vnop_remove_desc,		(vnop_t *) smbfs_vnop_remove },
9615	{ &vnop_rename_desc,		(vnop_t *) smbfs_vnop_rename },
9616	{ &vnop_rmdir_desc,			(vnop_t *) smbfs_vnop_rmdir },
9617	{ &vnop_setattr_desc,		(vnop_t *) smbfs_vnop_setattr },
9618	{ &vnop_symlink_desc,		(vnop_t *) smbfs_vnop_symlink },
9619	{ &vnop_write_desc,			(vnop_t *) smbfs_vnop_write },
9620	{ &vnop_blockmap_desc,		(vnop_t *) smbfs_vnop_blockmap },
9621	{ &vnop_strategy_desc,		(vnop_t *) smbfs_vnop_strategy },
9622	{ &vnop_searchfs_desc,		(vnop_t *) err_searchfs },
9623	{ &vnop_offtoblk_desc,		(vnop_t *) smbfs_vnop_offtoblk },
9624	{ &vnop_blktooff_desc,		(vnop_t *) smbfs_vnop_blktooff },
9625	{ &vnop_getxattr_desc,		(vnop_t *) smbfs_vnop_getxattr },
9626	{ &vnop_setxattr_desc,		(vnop_t *) smbfs_vnop_setxattr },
9627	{ &vnop_removexattr_desc,	(vnop_t *) smbfs_vnop_removexattr },
9628	{ &vnop_listxattr_desc,		(vnop_t *) smbfs_vnop_listxattr },
9629	{ &vnop_monitor_desc,		(vnop_t *) smbfs_vnop_monitor},
9630	{ &vnop_getnamedstream_desc, (vnop_t *) smbfs_vnop_getnamedstream },
9631    { &vnop_makenamedstream_desc, (vnop_t *) smbfs_vnop_makenamedstream },
9632    { &vnop_removenamedstream_desc, (vnop_t *) smbfs_vnop_removenamedstream },
9633	{ &vnop_access_desc,		(vnop_t *) smbfs_vnop_access },
9634	{ &vnop_allocate_desc,		(vnop_t *) smbfs_vnop_allocate },
9635	{ NULL, NULL }
9636};
9637
9638struct vnodeopv_desc smbfs_vnodeop_opv_desc =
9639	{ &smbfs_vnodeop_p, smbfs_vnodeop_entries };
9640