1/*
2 * Copyright (c) 2000-2001 Boris Popov
3 * All rights reserved.
4 *
5 * Portions Copyright (C) 2001 - 2013 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 useCacheData = (share->ss_flags & SMBS_RECONNECTING);
135	 struct smbfattr fattr;
136	 int error = smbfs_attr_cachelookup(share, vp, vap, context, useCacheData);
137
138	 if (error != ENOENT)
139		 return (error);
140	 error = smbfs_lookup(share, VTOSMB(vp), NULL, NULL, &fattr, context);
141	 if (error)
142		 return (error);
143
144     /*
145	  * At this point we have the data from the server, so we can
146	  * just use cached data for now. See <rdar://problem/13813721>.
147	  */
148     useCacheData = TRUE;
149
150	 smbfs_attr_cacheenter(share, vp, &fattr, TRUE, context);
151	 return (smbfs_attr_cachelookup(share, vp, vap, context, useCacheData));
152 }
153
154/*
155 * smbfs_close - The internal open routine, the vnode should be locked
156 * before this is called. We only handle VREG in this routine.
157 *
158 * The calling routine must hold a reference on the share
159 *
160 */
161int
162smbfs_close(struct smb_share *share, vnode_t vp, int openMode,
163			vfs_context_t context)
164{
165	struct smbnode		*np = VTOSMB(vp);
166	proc_t				p = vfs_context_proc(context);
167	struct fileRefEntry	*fndEntry = NULL;
168	struct fileRefEntry	*curr = NULL;
169	int			error = 0;
170	uint16_t		accessMode = 0;
171    SMBFID fid = 0;
172	int32_t			needOpenFile;
173	uint16_t		openAccessMode;
174	uint32_t		rights;
175    struct smbfattr *fap = NULL;
176
177	/*
178	 * We have more than one open, so before closing see if the file needs to
179	 * be reopened
180	 */
181	if ((np->f_refcnt > 1) && (smbfs_smb_reopen_file(share, np, context) == EIO)) {
182		SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
183		np->f_refcnt--;
184		return (0);
185	}
186
187	if (openMode & FREAD)
188		accessMode |= kAccessRead;
189
190	if (openMode & FWRITE)
191		accessMode |= kAccessWrite;
192
193	/* Check the number of times Open() was called */
194	if (np->f_refcnt == 1) {
195		ubc_msync(vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC | UBC_INVALIDATE);
196		/*
197		 * This is the last Close() we will get, so close sharedForkRef
198		 * and any other forks created by ByteRangeLocks
199		 */
200		if (np->f_fid != 0) {
201			SMBFID oldFID = np->f_fid;
202
203			/* Close the shared file first. Clear out the refs to it
204			 * first so that no one else trys to use it while I'm waiting
205			 * for the close file reply to arrive.  There was a case
206			 * where cluster i/o was firing off after I sent the close
207			 * file req, but had not gotten the close file reply yet
208			 * and tyring to still use the shared file
209			 */
210			np->f_fid = 0;		/* clear the ref num */
211			np->f_accessMode = 0;
212			np->f_rights = 0;
213			np->f_openRWCnt = 0;
214			np->f_openRCnt = 0;
215			np->f_openWCnt = 0;
216			np->f_openTotalWCnt = 0;
217			np->f_needClose = 0;
218			np->f_clusterCloseError = 0;
219			/*
220			 * They didn't unlock the file before closing. A SMB close will remove
221			 * any locks so lets free the memory associated with that lock.
222			 */
223			if (np->f_smbflock) {
224				SMB_FREE(np->f_smbflock, M_LOCKF);
225				np->f_smbflock = NULL;
226			}
227			error = smbfs_smb_close(share, oldFID, context);
228			if (error) {
229				SMBWARNING("close file failed %d on fid %llx\n",
230                           error, oldFID);
231            }
232		 }
233
234		/* Remove forks that were opened due to ByteRangeLocks or DenyModes */
235		lck_mtx_lock(&np->f_openDenyListLock);
236		curr = np->f_openDenyList;
237		while (curr != NULL) {
238			error = smbfs_smb_close(share, curr->fid, context);
239			if (error) {
240				SMBWARNING("close file failed %d on fid %llx\n",
241                           error, curr->fid);
242            }
243			curr = curr->next;
244		}
245		lck_mtx_unlock(&np->f_openDenyListLock);
246		np->f_refcnt = 0;
247		RemoveFileRef (vp, NULL);		/* remove all file refs */
248
249		/*
250		 * We did the last close on the file. This file is
251		 * marked for deletion on close. So lets delete it
252		 * here. If we get an error then try again when the node
253		 * becomes inactive.
254		 */
255        if (np->n_flag & NDELETEONCLOSE) {
256            if (smbfs_smb_delete(share, np, NULL, 0, 0, context) == 0) {
257                np->n_flag &= ~NDELETEONCLOSE;
258
259                /* Assume the file is now deleted on the server */
260                smb_vhashrem(np);
261
262                /* Lock protects np->n_parent. See <rdar://problem/11824956> */
263                lck_rw_lock_shared(&np->n_name_rwlock);
264                if (np->n_parent != NULL) {
265                    smbfs_attr_touchdir(np->n_parent, (share->ss_fstype == SMB_FS_FAT));
266                    np->n_parent->d_changecnt++;
267
268                    /* Remove any negative cache entries. */
269                    if (np->n_parent->n_flag & NNEGNCENTRIES) {
270                        np->n_parent->n_flag &= ~NNEGNCENTRIES;
271                        cache_purge_negatives(np->n_parent->n_vnode);
272                    }
273                }
274                lck_rw_unlock_shared(&np->n_name_rwlock);
275            }
276        }
277
278		/*
279		 * It was not cacheable before, but now that all files are closed,
280		 * make it cacheable again (if its a valid cacheable file). If
281		 * we were caching should we remove attributes cache. Realy only
282		 * matters when we turn on cluster io?
283		 */
284		if (vnode_isnocache(vp))
285			vnode_clearnocache(vp);
286
287		/* Did we change the file during the open */
288		if (np->n_flag & NATTRCHANGED)
289			np->attribute_cache_timer = 0;
290
291		lck_mtx_lock(&np->f_openStateLock);
292		if (np->f_openState & kNeedRevoke)
293			error = 0;
294		/*
295		 * Clear all the f_openState flags, we are closed. If we have a pending
296		 * revoke clear that out, the file is closed no need to revoke it now.
297		 */
298		np->f_openState = 0;
299		lck_mtx_unlock(&np->f_openStateLock);
300
301		goto exit;
302	}
303
304	/* More than one open */
305
306	/*
307	 * See if we can match this Close() to a matching file that has byte range
308	 * locks or denyModes.
309	 *
310	 * NOTE: FHASLOCK can be set by open with O_EXCLUSIVE or O_SHARED which
311	 *	 maps to my deny modes or FHASLOCK could also have been set/cleared
312	 *	by calling flock directly.
313	 *
314	 * Cases that work are:
315	 *	1)  Carbon using deny modes and thus FHASLOCK maps to my deny modes.
316	 *	    No flock being used.
317	 *	2)  Cocoa using open with O_EXCLUSIVE or O_SHARED and not calling flock.
318	 *	3)  Cocoa using open, then calling flock and later calling flock
319	 *	    to unlock before close.
320	 *	4)  Cocoa open, then calling flock, but not calling flock to unlock
321	 *	    before close.  I would fall through to the shared fork code correctly.
322	 *
323	 * Cases that may not work are:
324	 *	1)  Carbon using deny modes and then calling flock to unlock, thus
325	 *	    clearing FHASLOCK flag.I would assume it was the shared file.
326	 *	2)  Cocoa open with O_EXCLUSIVE or O_SHARED and then calling flock
327	 *	    to lock and then unlock, then calling close.
328	 *	3)  ???
329	 */
330	if (openMode & FHASLOCK) {
331		uint16_t tempAccessMode = accessMode;
332
333		/* Try with denyWrite, if not found, then try with denyRead/denyWrite */
334		tempAccessMode |= kDenyWrite;
335		error = FindFileRef(vp, p, tempAccessMode, kExactMatch, 0, 0, &fndEntry,
336							&fid);
337		if (error != 0) {
338			tempAccessMode |= kDenyRead;
339			error = FindFileRef(vp, p, tempAccessMode, kExactMatch, 0, 0,
340								&fndEntry, &fid);
341		}
342		if (error == 0)
343			accessMode = tempAccessMode;
344	} else {
345		/* No deny modes used, so look for any forks opened for byteRangeLocks */
346		error = FindFileRef(vp, p, accessMode, kExactMatch, 0, 0, &fndEntry, &fid);
347	}
348
349	/* always decrement the count, dont care if got an error or not */
350	np->f_refcnt--;
351
352	/*
353	 * We have an Open Deny entry that is being used by more than one open call,
354	 * just decrement it and get out.
355     * This code should be combined with the code right below here.
356	 */
357	if ((error == 0) && fndEntry && (fndEntry->refcnt > 0)) {
358		fndEntry->refcnt--;
359		goto exit;
360	}
361
362	/*
363	 * We have an Open Deny entry that is all done. Time to close it.
364     * This code should be combined with the code right above here.
365	 */
366	if ((error == 0) && fndEntry) {
367		error = smbfs_smb_close(share, fndEntry->fid, context);
368		/* We are not going to get another close, so always remove it from the list */
369		RemoveFileRef(vp, fndEntry);
370		goto exit;
371	}
372
373	/*
374     * Not an open deny mode open.
375     *
376     * An oddity. If first open was read/write/denyWrite and then a second
377     * open of just read, then the second open will open the shared fork.
378     * Now, get a close on the "read" fork, the np->f_refcnt will be 2, and we
379     * will end up here. The np->f_refcnt will be decremented to 1 so the next
380     * close call will close everything. In the meantime, we end up leaving
381     * the shared fork open with "read" and thus we actually have two forks
382     * open, one for the read/write/denyWrite and the other is the shared fork.
383     * We have has this behavior for a long time and just have not noticed.
384     * Since its an edge case and no one has complained, we can leave it this
385     * way for now.
386     */
387	needOpenFile = 0;
388	openAccessMode = 0;
389	fid = 0;
390	rights = SMB2_READ_CONTROL;
391
392	/*
393	 * Just return 0 for no err, but dont close the file since another
394	 * process is still using it
395	 */
396	error = 0;
397
398	/* Check to downgrade access mode if needed */
399	switch (accessMode) {
400	case (kAccessRead | kAccessWrite):
401		np->f_openRWCnt -= 1;
402		if ((np->f_openRWCnt == 0) && (np->f_openRCnt > 0) && (np->f_openWCnt == 0)) {
403			/* drop from rw to read only */
404			needOpenFile = 1;
405			openAccessMode = kAccessRead;
406			rights |= SMB2_FILE_READ_DATA;
407		}
408		/* Dont ever downgrade to write only since Unix expects read/write */
409		break;
410	case kAccessRead:
411		np->f_openRCnt -= 1;
412		/* Dont ever downgrade to write only since Unix expects read/write */
413		break;
414	case kAccessWrite:
415		np->f_openWCnt -= 1;
416		if ( (np->f_openRCnt > 0) && (np->f_openRWCnt == 0) &&
417			(np->f_openWCnt == 0) ) {
418			/* drop from rw to read only */
419			needOpenFile = 1;
420			openAccessMode = kAccessRead;
421			rights |= SMB2_FILE_READ_DATA;
422		}
423		break;
424	}
425	/* set up for the open fork */
426	if (needOpenFile == 1) {
427        SMB_MALLOC(fap,
428                   struct smbfattr *,
429                   sizeof(struct smbfattr),
430                   M_SMBTEMP,
431                   M_WAITOK | M_ZERO);
432        if (fap == NULL) {
433            SMBERROR("SMB_MALLOC failed\n");
434            error = ENOMEM;
435            goto exit;
436        }
437
438        error = smbfs_smb_open_file(share, np,
439                                    rights, NTCREATEX_SHARE_ACCESS_ALL, &fid,
440                                    NULL, 0, FALSE,
441                                    fap, context);
442		if (error == 0) {
443			SMBFID oldFID = np->f_fid;
444
445			/* We are downgrading the open flush it out any data */
446			ubc_msync(vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC | UBC_INVALIDATE);
447			/* Close the shared file first and use this new one now
448			 * Switch the ref before closing the old shared file so the
449			 * old file wont get used while its being closed.
450			 */
451			np->f_fid = fid;	/* reset the ref num */
452			np->f_accessMode = openAccessMode;
453			np->f_rights = rights;
454			error = smbfs_smb_close(share, oldFID, context);
455			if (error) {
456				SMBWARNING("close file failed %d on fid %llx\n", error, oldFID);
457            }
458		}
459	}
460
461exit:
462    if ((error == 0) && (openMode & FWRITE) && (np->f_openTotalWCnt > 0)) {
463        np->f_openTotalWCnt--;
464    }
465
466    if (fap != NULL) {
467        SMB_FREE(fap, M_SMBTEMP);
468    }
469
470	return (error);
471}
472
473/*
474 * smbfs_vnop_close - smbfs vnodeop entry point
475 *	vnode_t a_vp;
476 *	int a_fflags;
477 *	vfs_context_t a_context;
478 */
479static int
480smbfs_vnop_close(struct vnop_close_args *ap)
481{
482	vnode_t vp = ap->a_vp;
483	int error = 0;
484	struct smbnode *np;
485
486
487	if (smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK) != 0)
488		return (0);
489	np = VTOSMB(vp);
490	np->n_lastvop = smbfs_vnop_close;
491
492	if (vnode_isdir(vp)) {
493		if (--np->d_refcnt) {
494			error = 0;
495		} else {
496			smbfs_closedirlookup(np, ap->a_context);
497		}
498	} else if ( vnode_isreg(vp) || vnode_islnk(vp) ) {
499		int clusterCloseError = np->f_clusterCloseError;
500		struct smb_share *share;
501
502		/* if its readonly volume, then no sense in trying to write out dirty data */
503		if (!vnode_vfsisrdonly(vp) && smbfsIsCacheable(vp)) {
504			if (np->n_flag & NISMAPPED) {
505				/* More expensive, but handles mmapped files */
506				ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
507			} else {
508				/* Less expensive, but does not handle mmapped files */
509				cluster_push(vp, IO_CLOSE);
510			}
511		}
512		share = smb_get_share_with_reference(VTOSMBFS(vp));
513
514        /* Do any pending set eof or flushes before closing the file */
515        smbfs_smb_fsync(share, np, ap->a_context);
516
517		error = smbfs_close(share, vp, ap->a_fflag, ap->a_context);
518		smb_share_rele(share, ap->a_context);
519		if (!error)
520			error = clusterCloseError;
521	}
522	smbnode_unlock(np);
523	return (error);
524}
525
526static void
527smbfs_get_rights_shareMode(int fmode, uint32_t *rights, uint32_t *shareMode, uint16_t *accessMode)
528{
529	/*
530	 * We always ask for READ_CONTROL so we can always get the owner/group
531	 * IDs to satisfy a stat.
532	 */
533	*rights = SMB2_READ_CONTROL;
534	if (fmode & FREAD) {
535		*accessMode |= kAccessRead;
536		*rights |= SMB2_FILE_READ_DATA;
537	}
538	if (fmode & FWRITE) {
539		*accessMode |= kAccessWrite;
540		*rights |= SMB2_FILE_APPEND_DATA | SMB2_FILE_WRITE_DATA;
541	}
542
543	/*
544	 * O_EXLOCK -> denyRead/denyWrite is always cacheable since we have exclusive
545	 *			   access.
546	 * O_SHLOCK -> denyWrite is always cacheable since we are the only one who
547	 *			   can change the file.
548	 * denyNone -> is not cacheable if from Carbon (a FSCTL call from Carbon
549	 *			   will set the vnode to be non cacheable). It is always
550	 *			   cacheable from Unix since that is what home dirs mainly use.
551	 */
552	*shareMode = NTCREATEX_SHARE_ACCESS_ALL;
553	if (fmode & O_SHLOCK) {
554		*accessMode |= kDenyWrite;
555		/* Remove the wr shared access */
556		*shareMode &= ~NTCREATEX_SHARE_ACCESS_WRITE;
557	}
558
559	if (fmode & O_EXLOCK) {
560		*accessMode |= kDenyWrite;
561		*accessMode |= kDenyRead;
562		/* Remove the rdwr shared access */
563		*shareMode &= ~(NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_READ);
564	}
565}
566
567static void
568smbfs_update_RW_cnts(vnode_t vp, uint16_t accessMode)
569{
570	/* count nbr of opens with rw, r, w so can downgrade access in close if needed */
571	struct smbnode *np = VTOSMB(vp);
572
573	switch (accessMode) {
574		case (kAccessWrite | kAccessRead):
575			np->f_openRWCnt += 1;
576			break;
577		case kAccessRead:
578			np->f_openRCnt += 1;
579			break;
580		case kAccessWrite:
581			np->f_openWCnt += 1;
582			break;
583	}
584}
585
586static int
587smbfs_create_open(struct smb_share *share, vnode_t dvp, struct componentname *cnp,
588				  struct vnode_attr *vap,  uint32_t open_disp, int fmode,
589				  SMBFID *fidp, struct smbfattr *fattrp, vnode_t *vpp,
590				  vfs_context_t context)
591{
592	struct smbnode *dnp = VTOSMB(dvp);
593	struct smbmount *smp = VTOSMBFS(dvp);
594	vnode_t vp;
595	const char *name = cnp->cn_nameptr;
596	size_t nmlen = cnp->cn_namelen;
597	int error = 0;
598	uint32_t rights, addedReadRights, saved_rights;
599	uint16_t accessMode = 0;
600	uint16_t savedAccessMode = 0;
601	struct smbnode *np;
602	uint32_t shareMode = 0;
603	char *target = NULL;
604	size_t targetlen = 0;
605    struct smb2_durable_handle dur_handle;
606
607	/*
608	 * We have NO vnode for the target!
609	 * The target may or may not exist on the server.
610	 * The target could be a dir or a file.
611	 *
612	 * If its a dir, then it can not be a creation. Use vnop_mkdir instead.
613	 * It could be an open on a dir which SMB protocol allows.  Make sure
614	 *	to close the dir afterwards.
615	 *
616	 * If its a file, it cant be a symlink, use vnop_link instead.
617	 * It could be a create and open on a file.
618	 * Since a vnode was not found for the file, we know its not already open
619	 *	by this client. This means I know its the FIRST open call.
620	 *
621	 * dnp should be locked when this function is called
622	 */
623
624	*fidp = 0;
625
626	smbfs_get_rights_shareMode(fmode, &rights, &shareMode, &accessMode);
627	savedAccessMode = accessMode;	/* Save the original access requested */
628	/*
629	 * If opening with write only, try opening it with read/write. Unix
630	 * expects read/write access like open/map/close/PageIn. This also helps
631	 * the cluster code since if write only, the reads will fail in the
632	 * cluster code since it trys to page align the requests.
633	 *
634	 * NOTE: Since this call only creates items that are regular files we always
635	 * set the vtype to VREG. The smbfs_smb_ntcreatex only uses that on create.
636	 */
637	addedReadRights = (accessMode == kAccessWrite) ? SMB2_FILE_READ_DATA : 0;
638    saved_rights = rights | addedReadRights;
639
640    error = smbfs_smb_ntcreatex(share, dnp,
641                                rights | addedReadRights, shareMode, VREG,
642                                fidp, name, nmlen,
643                                open_disp, 0, fattrp,
644                                TRUE, NULL, context);
645
646	if (error && addedReadRights) {
647		addedReadRights = 0;
648        saved_rights = rights;
649
650		error = smbfs_smb_ntcreatex(share, dnp,
651                                    rights, shareMode, VREG,
652                                    fidp, name, nmlen,
653                                    open_disp, 0, fattrp,
654                                    TRUE, NULL, context);
655	}
656
657 	if (error) {
658		return error;
659	}
660
661    /* Reparse point need to get the reparse tag */
662	if (fattrp->fa_attr & SMB_EFA_REPARSE_POINT) {
663		error = smbfs_smb_get_reparse_tag(share, *fidp, &fattrp->fa_reparse_tag,
664										  &target, &targetlen, context);
665		if (error) {
666			(void) smbfs_smb_close(share, *fidp, context);
667			return error;
668		}
669	}
670
671	/* Create the vnode using fattr info and return the created vnode */
672	error = smbfs_nget(share, vnode_mount(dvp),
673                       dvp, name, nmlen,
674                       fattrp, &vp,
675                       cnp->cn_flags, SMBFS_NGET_CREATE_VNODE,
676                       context);
677	if (error) {
678        if (target) {
679            SMB_FREE(target, M_TEMP);
680        }
681		(void) smbfs_smb_close(share, *fidp, context);
682		return error;
683	}
684
685	/*
686	 * If they passed in a vnode then we no longer need it, so remove the
687	 * reference. The smbfs_nget always returns us a vnode with a reference. The
688	 * vnode could be the same or a new one.
689	 */
690	if (*vpp) {
691		vnode_put(*vpp);
692	}
693	*vpp = vp;
694	np = VTOSMB(vp);
695
696	/*
697	 * We treat directories, files and symlinks different. Since currently we
698	 * only handle reparse points as dfs triggers or symlinks we can ignore
699	 * treating reparse points special.
700	 */
701	if (vnode_isdir(vp)) {
702		/* We opened a directory, increment its ref count and close it */
703		np->d_refcnt++;
704		(void)smbfs_smb_close(share, *fidp, context);
705	} else if (vnode_islnk(vp)) {
706		/* We opened a symlink, close it */
707		(void)smbfs_smb_close(share, *fidp, context);
708		if (target && targetlen) {
709			smbfs_update_symlink_cache(np, target, targetlen);
710		}
711	} else if (vnode_isreg(vp)) {
712		/* We opened the file so bump ref count */
713		np->f_refcnt++;
714
715		np->f_rights = rights;
716		np->f_accessMode = accessMode;
717		if (addedReadRights) {
718			np->f_rights |= SMB2_FILE_READ_DATA;
719			np->f_accessMode |= kAccessRead;
720		}
721
722		/* if deny modes were used, save the file ref into file list */
723		if ((fmode & O_EXLOCK) || (fmode & O_SHLOCK)) {
724            error = smb2_smb_dur_handle_init(share, np, &dur_handle);
725            if (error == 0) {
726                /*
727                 * %%% TO DO - can we improve the performance of this?
728                 * Want to get a durable handle, but the lease key consists
729                 * of the file ID, so have to wait until the first create
730                 * succeeds which gets us the file ID, then close it and reopen
731                 * it but this time requesting the durable handle.
732                 */
733                (void) smbfs_smb_close(share, *fidp, context);
734
735                error = smbfs_smb_ntcreatex(share, dnp,
736                                            saved_rights, shareMode, VREG,
737                                            fidp, name, nmlen,
738                                            FILE_OPEN, 0, fattrp,
739                                            FALSE, &dur_handle, context);
740            }
741            else {
742                /*
743                 * Durable handles must not be supported by this server, just
744                 * use the earlier open which must have worked.
745                 * Clear the durable handle not supported error
746                 */
747                error = 0;
748            }
749
750            if (error == 0) {
751                /*
752                 * Either durable handles not supported or reopening the file
753                 * with durable handle worked so save file ref
754                 */
755                AddFileRef (vp, vfs_context_proc(context), accessMode, rights,
756                            *fidp, dur_handle, NULL);
757            }
758		}
759        else {
760            np->f_fid = *fidp;
761			smbfs_update_RW_cnts(vp, savedAccessMode);
762			if (accessMode == kAccessWrite) {
763				/* if opened with just write, then turn off cluster code */
764				vnode_setnocache(vp);
765			}
766		}
767	}
768
769	/* If it was allocated then free, since we are done with it now */
770    if (target) {
771        SMB_FREE(target, M_TEMP);
772    }
773
774	if (fattrp->fa_created_disp == FILE_CREATE) {
775		struct timespec ts;
776		/*
777		 * We just created the file, so we have no finder info and the resource fork
778		 * should be empty. So set our cache timers to reflect this information
779		 */
780		nanouptime(&ts);
781		VTOSMB(vp)->finfo_cache = ts.tv_sec;
782		VTOSMB(vp)->rfrk_cache_timer = ts.tv_sec;
783
784		/*
785		 * On create, an initial ACL can be set.
786		 * If unix extensions are supported, then can set mode, owner, group.
787		 */
788		if (vap != NULL) {
789			smbfs_set_create_vap(share, vap, vp, context, TRUE);  /* Set the REAL create attributes NOW */
790		}
791
792		smbfs_attr_touchdir(dnp, (share->ss_fstype == SMB_FS_FAT));
793
794        dnp->d_changecnt++;
795
796		/* Remove any negative cache entries. */
797		if (dnp->n_flag & NNEGNCENTRIES) {
798			dnp->n_flag &= ~NNEGNCENTRIES;
799			cache_purge_negatives(dvp);
800		}
801
802		/* blow away statfs cache */
803		smp->sm_statfstime = 0;
804	}
805	/* smbfs_nget returns a locked node, unlock it */
806	smbnode_unlock(VTOSMB(vp));		/* Release the smbnode lock */
807
808	return (error);
809}
810
811/*
812 * smbfs_open -	The internal open routine, the vnode should be locked
813 *		before this is called.
814 *
815 * The calling routine must hold a reference on the share
816 *
817 */
818int
819smbfs_open(struct smb_share *share, vnode_t vp, int mode,
820		   vfs_context_t context)
821{
822	proc_t p = vfs_context_proc(context);
823	struct smbnode *np = VTOSMB(vp);
824	uint16_t accessMode = 0;
825	uint16_t savedAccessMode = 0;
826	uint32_t rights;
827	uint32_t shareMode;
828    SMBFID fid = 0;
829	int error = 0;
830	int	warning = 0;
831    struct smbfattr *fap = NULL;
832    struct smb2_durable_handle dur_handle, *dptr;
833	int do_create;
834    uint32_t disp;
835    struct fileRefEntry *fndEntry = NULL;
836
837	/* It was already open so see if the file needs to be reopened */
838	if ((np->f_refcnt) &&
839		((error = smbfs_smb_reopen_file(share, np, context)) != 0)) {
840		SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
841		return (error);
842	}
843
844    SMB_MALLOC(fap,
845               struct smbfattr *,
846               sizeof(struct smbfattr),
847               M_SMBTEMP,
848               M_WAITOK | M_ZERO);
849    if (fap == NULL) {
850        SMBERROR("SMB_MALLOC failed\n");
851        error = ENOMEM;
852        goto exit;
853    }
854
855	smbfs_get_rights_shareMode(mode, &rights, &shareMode, &accessMode);
856	savedAccessMode = accessMode;	/* Save the original access requested */
857
858	if ((mode & O_EXLOCK) || (mode & O_SHLOCK)) {
859		/*
860		 * if using deny modes and I had to open the file myself, then close
861		 * the file now so it does not interfere with the deny mode open.
862		 * We only do this in read.
863		 */
864		if (np->f_needClose) {
865			np->f_needClose = 0;
866			warning = smbfs_close(share, vp, FREAD, context);
867			if (warning)
868				SMBWARNING("error %d closing %s\n", warning, np->n_name);
869		}
870
871		/* Using deny modes, see if already in file list */
872		error = FindFileRef(vp, p, accessMode, kExactMatch, 0, 0, &fndEntry, &fid);
873		if (error == 0) {
874			/*
875			 * Already in list due to previous open with deny modes. Can't have
876			 * two exclusive or two write/denyWrite. Multiple read/denyWrites are
877			 * allowed.
878			 */
879            if ((accessMode & kDenyWrite) && (accessMode & kAccessWrite)) {
880                error = EBUSY;
881                goto exit;
882            }
883
884			if (mode & O_EXLOCK) {
885                if ((accessMode & kAccessRead) && !(accessMode & kAccessWrite)) {
886                    /*
887                     * Multiple r/dR/dW are allowed, see FindFileRef for
888                     * more details
889                     */
890                }
891                else {
892                    error = EBUSY;
893                    goto exit;
894                }
895            }
896
897            DBG_ASSERT(fndEntry);
898            /*
899             * We are going to reuse this Open Deny entry. Up the counter so
900             * we will know not to free it until the counter goes back to zero.
901             */
902            fndEntry->refcnt++;
903		}
904        else {
905            /*
906             * Check one more time looking for other pids that might already
907             * have the file open for exclusive or shared access that will
908             * cause this open to get denied. This is to reduce the number of
909             * times a handle lease break will occur with SMB 2.x. If we lose
910             * the handle lease, then reopening a durable handle reconnect will
911             * fail.
912             */
913            error = FindFileRef(vp, NULL, accessMode, kPreflightOpen, 0, 0, &fndEntry, &fid);
914            if (error == 0) {
915                /* Some other process has it open already */
916                error = EBUSY;
917                goto exit;
918            }
919
920			/* not in list, so open new file */
921
922            /* Request a durable handle */
923            dptr = NULL;
924            error = smb2_smb_dur_handle_init(share, np, &dur_handle);
925            if (!error) {
926                dptr = &dur_handle;
927            }
928
929            if (np->n_flag & N_ISRSRCFRK) {
930                disp = FILE_OPEN_IF;
931                do_create = TRUE;
932            }
933            else {
934                disp = FILE_OPEN;
935                do_create = FALSE;
936            }
937
938            error = smbfs_smb_ntcreatex(share, np,
939                                        rights, shareMode, VREG,
940                                        &fid, NULL, 0,
941                                        disp, FALSE, fap,
942                                        do_create, dptr, context);
943			if (error == 0) {
944				/* if open worked, save the file ref into file list */
945				AddFileRef (vp, p, accessMode, rights, fid, dur_handle, NULL);
946			}
947		}
948		goto exit;
949	}
950
951	/*
952	 * If we get here, then deny modes are NOT being used. If the open call is
953	 * coming in from Carbon, then Carbon will follow immediately with an FSCTL
954	 * to turn off caching (I am assuming that denyNone means this file will
955	 * be shared among multiple process and that ByteRangeLocking will be used).
956	 *
957	 * no deny modes, so use the shared file reference
958	 *
959	 */
960	/* We have open file descriptor for non deny mode opens */
961	if (np->f_fid != 0) {
962        /* Already open check to make sure current access is sufficient */
963		int needUpgrade = 0;
964		switch (np->f_accessMode) {
965		case (kAccessRead | kAccessWrite):
966			/* Currently RW, can't do any better than that so dont open a new fork */
967			break;
968		case kAccessRead:
969			/* Currently only have Read access, if they want Write too, then open as RW */
970			if (accessMode & kAccessWrite) {
971				needUpgrade = 1;
972				accessMode |= kAccessRead; /* keep orginal mode */
973				rights |= SMB2_FILE_READ_DATA;
974			}
975			break;
976		case kAccessWrite:
977			/*  Currently only have Write access, if they want Read too, then open as RW */
978			if (accessMode & kAccessRead) {
979				needUpgrade = 1;
980				accessMode |= kAccessWrite;
981				rights |= SMB2_FILE_APPEND_DATA | SMB2_FILE_WRITE_DATA;
982			}
983			break;
984		}
985		if (! needUpgrade)	/*  the existing open is good enough */
986			goto ShareOpen;
987	} else if (accessMode == kAccessWrite) {
988        /*
989         * If opening with write only, try opening it with read/write. Unix
990         * expects read/write access like open/map/close/PageIn. This also helps
991         * the cluster code since if write only, the reads will fail in the
992         * cluster code since it trys to page align the requests.
993         */
994
995        /*
996         * Preflight for open deny to preserve handle lease. More details in
997         * O_EXLOCK/O_SHLOCK code above.
998         */
999        error = FindFileRef(vp, NULL, accessMode | kAccessRead, kPreflightOpen,
1000                            0, 0, &fndEntry, &fid);
1001        if (error != 0) {
1002            /* Not already open locally, so try to open it */
1003            error = smbfs_smb_open_file(share, np,
1004                                        rights | SMB2_FILE_READ_DATA, shareMode, &fid,
1005                                        NULL, 0, FALSE,
1006                                        fap, context);
1007            if (error == 0) {
1008                np->f_fid = fid;
1009                np->f_rights = rights | SMB2_FILE_READ_DATA;
1010                np->f_accessMode = accessMode | kAccessRead;
1011                goto ShareOpen;
1012            }
1013        }
1014	}
1015
1016    /*
1017     * Preflight for open deny to preserve handle lease. More details in
1018     * O_EXLOCK/O_SHLOCK code above.
1019     */
1020    error = FindFileRef(vp, NULL, accessMode, kPreflightOpen, 0, 0, &fndEntry,
1021                        &fid);
1022    if (error == 0) {
1023        /* Some other process has it open already */
1024        error = EBUSY;
1025        goto exit;
1026    }
1027
1028    error = smbfs_smb_open_file(share, np,
1029                                rights, shareMode, &fid,
1030                                NULL, 0, FALSE,
1031                                fap, context);
1032	if (error)
1033		goto exit;
1034
1035	/*
1036	 * We already had it open (presumably because it was open with insufficient
1037	 * rights.) So now close the old open, if we already had it open.
1038	 */
1039	if (np->f_refcnt &&
1040        (np->f_fid != 0)) {
1041		warning = smbfs_smb_close(share, np->f_fid, context);
1042		if (warning)
1043			SMBWARNING("error %d closing %s\n", warning, np->n_name);
1044	}
1045	np->f_fid = fid;
1046	np->f_rights = rights;
1047	np->f_accessMode = accessMode;
1048
1049ShareOpen:
1050	smbfs_update_RW_cnts(vp, savedAccessMode);
1051	if (accessMode == kAccessWrite) {
1052		/* if opened with just write, then turn off cluster code */
1053		vnode_setnocache(vp);
1054	}
1055exit:
1056	if (!error) {
1057        /* We opened the file or pretended too; either way bump the count */
1058		np->f_refcnt++;
1059
1060        /* keep track of how many opens for this file had write access */
1061        if (mode & FWRITE) {
1062            np->f_openTotalWCnt++;
1063        }
1064	}
1065
1066    if (fap != NULL) {
1067        SMB_FREE(fap, M_SMBTEMP);
1068    }
1069
1070	return (error);
1071}
1072
1073static int
1074smbfs_vnop_open_common(vnode_t vp, int mode, vfs_context_t context, void *n_lastvop)
1075{
1076	struct smbnode *np;
1077	int	error;
1078
1079	/* We only open files and directories and symlinks */
1080	if (!vnode_isreg(vp) && !vnode_isdir(vp) && !vnode_islnk(vp)) {
1081		return (EACCES);
1082    }
1083
1084	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
1085		return (error);
1086
1087	np = VTOSMB(vp);
1088	np->n_lastvop = n_lastvop;
1089
1090	/* Just mark that the directory was opened */
1091	if (vnode_isdir(vp)) {
1092		np->d_refcnt++;
1093		error = 0;
1094	} else {
1095		struct smb_share * share;
1096
1097		share = smb_get_share_with_reference(VTOSMBFS(vp));
1098
1099        if (mode & O_TRUNC) {
1100            /* If truncating the file on open, do any pending set eofs */
1101            smbfs_smb_fsync(share, np, context);
1102        }
1103
1104		error = smbfs_open(share, vp, mode, context);
1105		/*
1106		 * We created the file with different posix modes than request in
1107		 * smbfs_vnop_create. We need to correct that here, so set the posix
1108		 * modes to those request on create. See smbfs_set_create_vap for more
1109		 * details on this issue.
1110		 */
1111		if ((error == 0) && (np->set_create_va_mode) && (mode & O_CREAT)) {
1112			struct vnode_attr vap;
1113
1114			np->set_create_va_mode = FALSE;	/* Only try once */
1115			VATTR_INIT(&vap);
1116			VATTR_SET_ACTIVE(&vap, va_mode);
1117			vap.va_mode = np->create_va_mode;
1118			error = smbfs_setattr(share, vp, &vap, context);
1119			if (error)	/* Got an error close the file and return the error */
1120				(void)smbfs_close(share, vp, mode, context);
1121		}
1122		smb_share_rele(share, context);
1123	}
1124	if (error == EBUSY)
1125		error = EAGAIN;
1126
1127	smbnode_unlock(np);
1128	return(error);
1129}
1130
1131/*
1132 * smbfs_vnop_compound_open - smbfs vnodeop entry point
1133 *	vnode_t a_dvp;
1134 *	vnode_t *a_vpp;
1135 *	int a_fmode;
1136 *	struct componentname *a_cnp;
1137 *	vnode_attr *a_vap;
1138 *	uint32_t a_flags;
1139 *	uint32_t *a_status;
1140 *	vfs_context_t context;
1141 *	int (*a_open_create_authorizer);
1142 *	int (*a_open_existing_authorizer);
1143 *	void *a_reserved;
1144 *
1145 * In broad strokes, our compound Open VNOP will be able to act as a
1146 * VNOP_LOOKUP(), a VNOP_OPEN(), and possibly a VNOP_CREATE(), all in one trip
1147 * to the filesystem.  Depending on flags, it may execute an operation similar
1148 * to an open(2) with O_CREAT: lookup, create if not present, and open.  It may
1149 * also act as a simple open(2) without O_CREAT: lookup and open if present.
1150 * When it returns successfully, the file it has found or created will be "open"
1151 * and ready to be hooked into a file descriptor.  As we will discuss later, this
1152 * call may under some circumstances return to VFS with its operation unfinished,
1153 * to request help from VFS, or fail but nonetheless return a vnode.  Filesystems
1154 * will be responsible for calling the passed-in authorizer routines to make sure
1155 * that the caller can legitimately perform the requested action.
1156 *
1157 * Arguments in Detail
1158 *
1159 *		1.  a_dvp - The directory in which to open/create. The directory vnode is
1160 *			equivalent to what would be passed to VNOP_LOOKUP() or VNOP_CREATE():
1161 *			it is the directory in which we wish to open a file, possibly doing
1162 *			a create if the file is not already present.
1163 *		2.  a_vpp - Resulting vnode. This argument is a pointer to a "vnode_t"
1164 *			in which the filesystem can place a pointer to the vnode for a file
1165 *			it either looks up or creates. In the event of a hit in the name
1166 *			cache, VFS will pass a file to the filesystem in *a_vpp. In that
1167 *			case, the filesystem will be free to call vnode_put() on that vnode
1168 *			and replace it with another of its choosing.  In the event of a cache
1169 *			miss, *a_vpp will store NULLVP. On success, the pointer installed at
1170 *			this address shall point to an "opened" vnode. On failure, it may
1171 *			point to a vnode which is not open.  Because several facilities in
1172 *			the kernel--notably auditing and kdebug support for fs_usage--rely
1173 *			on examining vnodes between lookup and a subsequent VNOP, filesystems
1174 *			should make every effort to return a vnode with an iocount if a lookup
1175 *			would have succeeded for that file, regardless of whether the main
1176 *			operation has failed.  This subtlety will apply to all other compound
1177 *			VNOPs as well, including those which might fail with EEXIST (e.g. mkdir).
1178 *			An unopened vnode may also be returned because more help is required
1179 *			from VFS (EKEEPLOOKING).
1180 *		3.  a_fmode - Open mode. This field will contain open flags as normally
1181 *			passed to VNOP_OPEN(), e.g. O_TRUNC.  For filesystems implementing
1182 *			compound open, O_TRUNC must be handled as part of the compound open
1183 *			call--a subsequent VNOP_SETATTR() call will not be sent to set the size.
1184 *		4.  a_cnp - Path to look up. This field will contain a componentname, as
1185 *			passed to VNOP_LOOKUP() or VNOP_CREATE(), specifying the name of the
1186 *			file to look up and possibly create.
1187 *		5.  a_vap - Attributes with which to create, if appropriate. This field
1188 *			will contain a pointer to vnode attributes to be used in creating a
1189 *			file.  In the event of an open without O_CREAT, this field will be NULL.
1190 *			In the event of a cache hit, it will also be NULL, as we wish to take
1191 *			a fast path in this case which does not involve the heavyweight operation
1192 *			of initializing creation attributes.  This field can be ignored in
1193 *			the event that an existing file is detected.
1194 *		6.  a_flags - VNOP-control flags. This field will contain control flags
1195 *			specific to the compound open VNOP.  For now, there will be only one
1196 *			flag: VNOP_COMPOUND_OPEN_DO_CREATE  will indicate that if no existing
1197 *			file is found, a new one is to be created (authorization, etc. permitting).
1198 *		7.  a_status - Information about results. The filesystem will use this
1199 *			field to return information about the result of the VNOP.  At the moment,
1200 *			there will be only one flag: COMPOUND_OPEN_STATUS_DID_CREATE  will
1201 *			indicate that a file was created by this call.  The field will be set
1202 *			to zero before a pointer is passed to the filesystem, so the FS will
1203 *			be free (for now) to only touch it in the event of having done a
1204 *			create.  COMPOUND_OPEN_STATUS_DID_CREATE should never be set if
1205 *			VNOP_COMPOUND_OPEN_DO_CREATE was not set in a_flags.
1206 *		8.  a_context - Authorization context. This field is a vfs_context_t,
1207 *			just as is passed to most VNOPs.
1208 *		9.  a_open_create_authorizer - Authorizer for create case. This field
1209 *			will contain a pointer to a function to be called to authorize creating
1210 *			a file.  It need only be called if a file is to be created; for an
1211 *			existing file, a_open_existing_authorizer should be used.  The
1212 *			componentname and vnode_attr passed to this function should be exactly
1213 *			those which were passed to the VNOP, because opaque data in these
1214 *			structures, installed by VFS, will be interpreted in authorization
1215 *			(the same will apply to all other authorizer callbacks).  Some additional
1216 *			validation which is not authorization per se, but which is currently
1217 *			performed in VFS on behalf of the filesystem, will also be executed
1218 *			here.  As a result of that validation, a variety of errors may be
1219 *			returned; these should generally be passed back to VFS.  Filesystems
1220 *			which will attempt a compound RPC that may result in a file's being
1221 *			created should always call this function beforehand.  In that case,
1222 *			if authorization is denied, the filesystem should attempt an "open
1223 *			without O_CREAT," because an open of an existing file may succeed
1224 *			despite a denial of permission to create.  The reserved argument should
1225 *			currently always be NULL.
1226 *			NOTE:  The locking constraints with respect to this call, and all
1227 *			authorizer callbacks in this document must unfortunately be left
1228 *			somewhat ambiguous due to the unrestricted behavior of Kauth and
1229 *			MACF plugins.  However, I believe that it should be safe to call out
1230 *			with resources (iocounts, memory, references) held, and even with some
1231 *			kinds of locks (a lock preventing only remove of a file, for instance).
1232 *			The chief thing to avoid is holding big locks (directory lock, file lock)
1233 *			which would prevent stat(2) and similar operations which authorizers
1234 *			are likely to try to use.
1235 *		10. a_open_existing_authorizer - Authorizer for preexisting case. This
1236 *			field will contain a pointer to a function to be called to authorize
1237 *			opening an existing file.  It need only be called if a file has not
1238 *			been created.  The componentname passed to this function should be
1239 *			exactly that which was passed to the VNOP, because opaque data in
1240 *			this structure, installed by VFS, will be interpreted in authorization.
1241 *			Some additional validation which is not authorization per se, but which
1242 *			is currently performed in VFS on behalf of the filesystem, will also
1243 *			be executed here.  As a result of that validation, a variety of errors
1244 *			may be returned; these should generally be passed back to VFS.
1245 *			The reserved argument should currently always be NULL.  For networked
1246 *			filesystems, this routine can be used after going over the wire with a
1247 *			compound lookup+open RPC; if access is denied, the filesystem should
1248 *			clean up (e.g. issue a close over the wire) and return to VFS.
1249 *		11. a_reserved - This field is currently unused and should not be interpreted.
1250 *
1251 * Symlinks, Mountpoints, Trigger Points:
1252 *
1253 * int vnode_lookup_continue_needed(vnode_t vp, struct componentname *cnp);
1254 *
1255 * #define EKEEPLOOKING    (-7)
1256 *
1257 * As part of a compound operation, a file may be detected which the filesystem
1258 * is not equipped to handle--for instance, a mountpoint, a symlink if O_NOFOLLOW
1259 * is set (which may point to another volume), or a trigger point. VFS will
1260 * provide the above routine to determine if a given vnode is one which requires
1261 * additional VFS processing.  It will take a vnode (the preexisting file
1262 * discovered by a compound VNOP) and a componentname; the latter should be the
1263 * exact pointer which was passed to the filesystem by VFS, because opaque data
1264 * will be interpreted to make the decision.  If this routine returns a nonzero
1265 * value, the filesystem should return EKEEPLOOKING to VFS.
1266 * vnode_lookup_continue_needed() will also update an opaque field on the
1267 * componentname for interpretation by VFS--while unnecessary for VNOP_COMPOUND_OPEN(),
1268 * for a rename (where two lookups take place) that update will let VFS determine
1269 * which lookup needs to be continued.  This helper will be used in numerous
1270 * compound VNOPs.
1271 *
1272 * "Traditional"VNOPs, Dark Corners of the Kernel, and the Root of a Filesystem
1273 *
1274 * VNOP_LOOKUP() will still need to be supported to allow us to reach intermediate
1275 * components of a path.  Currently, we plan to require that filesystems continue
1276 * to support the "traditional" VNOP_CREATE() and VNOP_OPEN() (and correspondingly,
1277 * the traditional version of other namespace-changing operations).  The chief
1278 * reason for this is that there are numerous areas in the kernel that use these
1279 * old-style operations directly.  After some discussion with various filesystem
1280 * owners, I think that it is best that we gradually adjust those areas to be
1281 * able to use compound VNOPs, thereby limiting the instability from moving them
1282 * all at once.  When all internal code has been prepared to use a given compound
1283 * VNOP, filesystems will be able to remove their "traditional" implementation.
1284 * VNOP_OPEN() deserves a bit of special discussion.  There are some places in
1285 * the kernel where we "open" a vnode without doing a true lookup; the best example
1286 * is the root of a filesystem, which is never "looked up" the way other entries
1287 * in a volume are, but there are other places where we have in hand that a vnode
1288 * that was obtained at some point in the past.  I therefore think that we will
1289 * probably keep VNOP_OPEN() around for the long term, rather than increasing the
1290 * complexity of the spreadsheet of "which arguments can be NULL, and when" for
1291 * VNOP_COMPOUND_OPEN().
1292*/
1293static int
1294smbfs_vnop_compound_open(struct vnop_compound_open_args *ap)
1295{
1296	vnode_t dvp = ap->a_dvp;
1297	vnode_t *vpp = ap->a_vpp;
1298	vnode_t vp = (ap->a_vpp) ? *ap->a_vpp : NULL;
1299	vfs_context_t context = ap->a_context;
1300	struct componentname *cnp = ap->a_cnp;
1301	struct vnode_attr *vap = ap->a_vap;
1302	int fmode = ap->a_fmode;
1303	int error;
1304	int create_authorizer_error = 0;
1305	uint32_t open_disp = 0;
1306	struct smb_share *share = NULL;
1307	struct smbnode *dnp;
1308    SMBFID fid = 0;
1309	uint32_t vid;
1310    struct smbfattr *fap = NULL;
1311    const char *namep = cnp->cn_nameptr;
1312    size_t name_len = cnp->cn_namelen;
1313
1314
1315	if (vpp == NULL) {
1316		SMBWARNING("Calling us without a vpp\n");
1317		return ENOTSUP;
1318	}
1319	/*
1320	 * Case 1:
1321	 *	They passed in a vnode they found in the name cache or we found
1322	 *	one in our hash table and its a symlink or reprase point. Not sure what
1323	 *	to do with reprase points yet. Symlinks are easy call vnode_lookup_continue_needed
1324	 * and let it tell us what to do.
1325	 *
1326	 * Case 2:
1327	 *	They passed in a vnode they found in the name cache or we found in our
1328	 *	hash table. If they don't have O_CREAT set or its already open then we
1329	 *	can just do a normaly open. We need to call a_open_existing_authorizer
1330	 *	before calling smbfs_vnop_open_common. If O_TRUNC is set then we need to
1331	 *	set the file size to zero. Even on error we need to return the vnode
1332	 *	with a reference.
1333	 *
1334	 * Case 3:
1335	 *	We have no vnode or they have O_CREAT set and we don't have it already
1336	 *	open. Set the correct open dispostion depending on the modes passed in
1337	 *	and what a_open_create_authorizer returns. We only call a_open_create_authorizer
1338	 *	if O_CREAT is set. Now we let smbfs_create_open handle all other cases.
1339	 *	Will use <rdar://problem/8574808> to update this comment and to make
1340	 *	reprase points and symlinks work correctly.
1341	 *
1342	 *
1343	 * Notes:
1344	 * 1) vap may be null, if null on create then thats not supported
1345	 * 2) if a_vpp is null and we return a vnode, dont do a vnode_put on it as the
1346	 *	vfs open code will call vnode_put on it for us.
1347	 */
1348
1349	/*
1350	 * We may have to create the item make sure it has a vap and they
1351	 * are creating a file. We only support create on files.
1352	 */
1353	if ((fmode & O_CREAT) && ((vap == NULL) || (vap->va_type != VREG))) {
1354		return (ENOTSUP);
1355	}
1356
1357    SMB_MALLOC(fap,
1358               struct smbfattr *,
1359               sizeof(struct smbfattr),
1360               M_SMBTEMP,
1361               M_WAITOK | M_ZERO);
1362    if (fap == NULL) {
1363        SMBERROR("SMB_MALLOC failed\n");
1364        error = ENOMEM;
1365        goto done;
1366    }
1367
1368	share = smb_get_share_with_reference(VTOSMBFS(dvp));
1369
1370	/* They didn't pass us a vnode, see if we have one in our hash */
1371	if (vp == NULLVP) {
1372		if ((cnp->cn_nameptr[0] == '.') && (cnp->cn_namelen == 1)) {
1373			/*
1374			 * They didn't give us a vnode, but they want dot open, so
1375			 * get a reference on the parent node.
1376			 */
1377			vid = vnode_vid(dvp);
1378			error = vnode_getwithvid(dvp, vid);
1379			if (error) {
1380				goto done;
1381			}
1382			vp = dvp;
1383		}
1384        else {
1385            if (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS) {
1386                /*
1387                 * Server supports File IDs.
1388                 */
1389                if (fmode & O_CREAT) {
1390                   /*
1391                    * In this case a lookup was done earlier and we know the
1392                    * item does not exist so trying to get its File ID is
1393                    * useless. Just skip straight to not found */
1394                    goto not_found;
1395                }
1396
1397                /*
1398                 * Before we can see if vnode already exists in our hash,
1399                 * need to get the inode number first. Might as well get all
1400                 * the meta data too so we can update the vnode if its found
1401                 */
1402                if (SSTOVC(share)->vc_misc_flags & SMBV_NO_QUERYINFO) {
1403                    /*
1404                     * Server does not like Query Info on files, so use Query
1405                     * Dir instead.
1406                     *
1407                     * Should never be a named stream vnode
1408                     */
1409                    if ((VTOSMB(dvp)->n_vnode) && vnode_isnamedstream(VTOSMB(dvp)->n_vnode)) {
1410                        DBG_ASSERT(0);
1411                    }
1412
1413                    error = smb2fs_smb_cmpd_query_dir_one(share, VTOSMB(dvp),
1414                                                          namep, name_len,
1415                                                          fap, (char **) &namep, &name_len,
1416                                                          context);
1417                }
1418                else {
1419                    error = smbfs_smb_qpathinfo(share, VTOSMB(dvp),
1420                                                fap, SMB_QFILEINFO_ALL_INFO,
1421                                                &namep, &name_len,
1422                                                context);
1423                }
1424
1425                if (error == 0) {
1426                    /* Lock the parent */
1427                    dnp = VTOSMB(dvp);
1428                    if (smbnode_lock(dnp, SMBFS_EXCLUSIVE_LOCK) != 0) {
1429                        error = ENOENT;
1430                        goto done;
1431                    }
1432
1433                    /*
1434                     * Found item on server, see if its in the hash.
1435                     * If it is in hash, then update its meta data and return vp
1436                     * If its not in hash, smbfs_nget will create it for us and
1437                     * return it in vp. Either way, we get back a vp.
1438                     */
1439                    if (smbfs_nget(share, vnode_mount(dvp),
1440                                   dvp, cnp->cn_nameptr, cnp->cn_namelen,
1441                                   fap, &vp,
1442                                   cnp->cn_flags, SMBFS_NGET_CREATE_VNODE,
1443                                   ap->a_context) == 0) {
1444                        /*
1445                         * Found one in our hash table unlock it, we just need
1446                         * the vnode reference at this point
1447                         */
1448                        smbnode_unlock(VTOSMB(vp));
1449                    }
1450
1451                    /* Unlock the parent */
1452                    dnp->n_lastvop = smbfs_vnop_compound_open;
1453                    smbnode_unlock(dnp);
1454
1455                    /*  If smbfs_smb_qpathinfo returned a new name, free it */
1456                    if (namep != cnp->cn_nameptr) {
1457                        SMB_FREE(namep, M_SMBNODENAME);
1458                    }
1459                }
1460                else {
1461                    /* Probably not found, either way vp is left at NULL */
1462                    goto not_found;
1463                }
1464            }
1465            else {
1466                /* Lock the parent */
1467                dnp = VTOSMB(dvp);
1468                if (smbnode_lock(dnp, SMBFS_EXCLUSIVE_LOCK) != 0) {
1469                    error = ENOENT;
1470                    goto done;
1471                }
1472
1473                /*
1474                 * Server does not support File IDs.
1475                 * Use the name for the hash value and try to find the vnode
1476                 * in the hash table with just the parent vnode and name. If its
1477                 * does not already exist in the hash,then smbfs_nget will
1478                 * return ENOENT (since fap == NULL) and vp will be left as NULL
1479                 *
1480                 * If server does support File IDs, we dont have the inode number
1481                 * at this time, so can not check the hash table at this time.
1482                 */
1483                if (smbfs_nget(share, vnode_mount(dvp),
1484                               dvp, cnp->cn_nameptr, cnp->cn_namelen,
1485                               NULL, &vp,
1486                               cnp->cn_flags, SMBFS_NGET_LOOKUP_ONLY,
1487                               ap->a_context) == 0) {
1488                    /*
1489                     * Found one in our hash table unlock it, we just need
1490                     * the vnode reference at this point
1491                     */
1492                    smbnode_unlock(VTOSMB(vp));
1493                }
1494
1495                /* Unlock the parent */
1496                dnp->n_lastvop = smbfs_vnop_compound_open;
1497                smbnode_unlock(dnp);
1498            }
1499        }
1500    }
1501
1502	/*
1503	 * Symlink or reparse point. Call vnode_lookup_continue_needed before
1504	 * proceeding.
1505	 */
1506	if (vp && (vnode_islnk(vp) || (VTOSMB(vp)->n_dosattr & SMB_EFA_REPARSE_POINT))) {
1507		SMBDEBUG("symlink %s\n", VTOSMB(vp)->n_name);
1508		error = vnode_lookup_continue_needed(vp, cnp);
1509		if (error) {
1510			*vpp = vp;
1511			vp = NULL;
1512			goto done;
1513		}
1514		/* Let smbfs_vnop_open_common handle any open errors */
1515		fmode &= ~(O_CREAT | O_TRUNC); /* Can't create or truncate a symlink */
1516	}
1517
1518	/*
1519	 * Do a normal open:
1520	 * 1. We have a vnode and they just want to open the file or directory. The
1521	 *    O_CREAT/O_TRUNC is not set. NOTE they can't have O_CREAT set on a directory.
1522	 * 2. We have a vnode to a file and its already opened.
1523	 *
1524	 * NOTE: They could be opening a file with O_CREAT, we found a directory in
1525	 * our hash, yet it doesn't exist on the server. So we should create the file
1526	 * and remove the directory node from our hash table. In this case we should
1527	 * falldown to the create open code.
1528	 */
1529	if (vp && (!(fmode & (O_CREAT | O_TRUNC)) || (vnode_isreg(vp) && VTOSMB(vp)->f_refcnt))) {
1530
1531        if ((fmode & O_EXCL) && vnode_isreg(vp) && VTOSMB(vp)->f_refcnt) {
1532            /*
1533             * O_EXCL is set and we *know* the file exists (we have
1534             * a vp and it's opened). No need to go to the server,
1535             * since we know the result.
1536             */
1537            error = EEXIST;
1538            *vpp = vp;
1539            vp = NULL;
1540            goto done;
1541        }
1542
1543		/* Call back and see if it is ok to be opened */
1544		error = ap->a_open_existing_authorizer(vp, cnp, fmode, context, NULL);
1545		if (!error) {
1546			error = smbfs_vnop_open_common(vp, fmode, context, smbfs_vnop_compound_open);
1547		}
1548		/* The file was already open, but they wanted us to truncate it. */
1549		if (!error && (fmode & O_TRUNC)){
1550			struct vnode_attr va;
1551
1552			memset(&va, 0, sizeof(va));
1553			VATTR_INIT(&va);
1554			VATTR_SET_ACTIVE(&va, va_data_size);
1555			error = smbfs_setattr(share, vp, &va, context);
1556			if (error)	{
1557				/* Got an error close the file and return the error */
1558				(void)smbfs_close(share, vp, fmode, context);
1559			}
1560		}
1561		/* Even if the truncate fails we need to return the vnode */
1562		*vpp = vp;
1563		vp = NULL;
1564		goto done;
1565	}
1566
1567not_found:
1568	/* Set the default create dispostion value */
1569	create_authorizer_error = 0;
1570
1571	if (fmode & O_TRUNC) {
1572		open_disp = FILE_OVERWRITE;
1573        if (vp) {
1574            /* If truncating the file on open, do any pending set eofs */
1575            smbfs_smb_fsync(share, VTOSMB(vp), context);
1576        }
1577	}
1578    else {
1579		open_disp = FILE_OPEN;
1580	}
1581
1582	if (fmode & O_CREAT) {
1583		/* Call back and see if it is ok to be created */
1584		create_authorizer_error = ap->a_open_create_authorizer(dvp, cnp, vap, context, NULL);
1585		if (!create_authorizer_error) {
1586			/* We can create so set the correct create dispostion value */
1587			if (fmode & O_EXCL) {
1588				open_disp = FILE_CREATE;
1589			} else if (fmode & O_TRUNC) {
1590				open_disp = FILE_OVERWRITE_IF;
1591			} else {
1592				open_disp = FILE_OPEN_IF;
1593			}
1594		}
1595	}
1596
1597	/* Lock the parent */
1598	if ((error = smbnode_lock(VTOSMB(dvp), SMBFS_EXCLUSIVE_LOCK))) {
1599		goto done;
1600	}
1601
1602	dnp = VTOSMB(dvp);
1603	dnp->n_lastvop = smbfs_vnop_compound_open;
1604
1605	/* Try to create/open the file */
1606	error = smbfs_create_open(share, dvp, cnp, vap, open_disp, fmode, &fid, fap, &vp, context);
1607	smbnode_unlock(dnp);
1608	if (error) {
1609		if (create_authorizer_error) {
1610			error = create_authorizer_error;
1611		}
1612	}
1613    else {
1614		if ((fap->fa_created_disp == FILE_CREATE) && (!(fmode & O_CREAT))) {
1615			/*
1616			 * The server says it was created, but we didn't request it to be
1617			 * created. The VFS layer can't handle this so just replace the
1618			 * FILE_CREATE with FILE_OPEN and log what happen. This should never
1619			 * happen, but it is better than the VFS panicing.
1620			 */
1621			fap->fa_created_disp = FILE_OPEN;
1622			SMBERROR("Server created %s when we only wanted it open, server error\n",
1623					 cnp->cn_nameptr);
1624		}
1625		if (fap->fa_created_disp == FILE_CREATE) {
1626			*ap->a_status = COMPOUND_OPEN_STATUS_DID_CREATE;
1627		} else {
1628			error = ap->a_open_existing_authorizer(vp, cnp, fmode, context, NULL);
1629			/* Error so close it */
1630			if (error) {
1631				(void)smbfs_smb_close(share, fid, context);
1632			}
1633			/* Not sure how to handle reparse yet, deal with that in <rdar://problem/8574808> */
1634			if (vnode_islnk(vp) || (VTOSMB(vp)->n_dosattr &  SMB_EFA_REPARSE_POINT)) {
1635				error = vnode_lookup_continue_needed(vp, cnp);
1636				if (!error && (vnode_islnk(vp))) {
1637					/* We never let them open a symlink */
1638					error = EACCES;
1639				}
1640			}
1641		}
1642		/* Note: Even on error, return the vnode */
1643		*vpp = vp;
1644		vp = NULL; /* Don't release the reference */
1645	}
1646
1647done:
1648    if (error) {
1649        if ((fmode & O_CREAT) && (error == ENOENT)) {
1650            SMBDEBUG("Creating %s returned ENOENT, resetting to EACCES\n", cnp->cn_nameptr);
1651            /*
1652             * Some servers (Samba) support an option called veto. This prevents
1653             * clients from creating or access these files. The server returns
1654             * an ENOENT error in these cases. The VFS layer will loop forever
1655             * if a ENOENT error is returned on create, so we convert this error
1656             * to EACCES.
1657             */
1658            error = EACCES;
1659        } else if ((fmode & O_EXCL) && (error != EEXIST)) {
1660            /*
1661             * Since O_EXCL is set, we really need to return EEXIST
1662             * if the file exists.
1663             * See <rdar://problem/10074916>
1664             */
1665            if ( (smbfs_smb_query_info(share, VTOSMB(dvp), cnp->cn_nameptr, cnp->cn_namelen, NULL, context) == 0)) {
1666                SMBDEBUG("%s: O_EXCL but error = %d, resetting to EEXIST.\n", __FUNCTION__, error);
1667                error = EEXIST;
1668            }
1669        }
1670    }
1671
1672    if (share) {
1673		smb_share_rele(share, context);
1674	}
1675
1676	/*
1677	 * We have an error and they didn't pass us in a vnode, then we found the
1678	 * vnode in our hash table. We need to remove our reference.
1679	 */
1680	if (error && (*vpp == NULLVP) && vp) {
1681		vnode_put(vp);
1682	}
1683
1684    if (fap) {
1685        SMB_FREE(fap, M_SMBTEMP);
1686    }
1687
1688    return (error);
1689}
1690
1691/*
1692 * smbfs_vnop_open - smbfs vnodeop entry point
1693 *	vnode_t a_vp;
1694 *	int  a_mode;
1695 *	vfs_context_t a_context;
1696 */
1697static int
1698smbfs_vnop_open(struct vnop_open_args *ap)
1699{
1700	return ( smbfs_vnop_open_common(ap->a_vp, ap->a_mode, ap->a_context, smbfs_vnop_open) );
1701}
1702
1703/*
1704 * smbfs_vnop_mmap - smbfs vnodeop entry point
1705 *	vnode_t a_vp;
1706 *	int a_fflags;
1707 *	vfs_context_t a_context;
1708 *
1709 * The mmap routine is a hint that we need to keep the file open. We can get
1710 * mutilple mmap before we get a mnomap. We only care about the first one. We
1711 * need to take a reference count on the open file and hold it open until we get
1712 * a mnomap call. The file should already be open when we get the mmap call and
1713 * with the correct open mode access.  So we shouldn't have to worry about
1714 * upgrading because the open should have  handled that for us. If the open was
1715 * done using an Open Deny mode then we need to mark the open deny entry as being
1716 * mmaped so the pagein, pageout, and mnomap routines can find.
1717 *
1718 * NOTE: On return all errors are ignored except EPERM.
1719 */
1720static int
1721smbfs_vnop_mmap(struct vnop_mmap_args *ap)
1722{
1723	vnode_t			vp = ap->a_vp;
1724	struct smbnode *np = NULL;
1725	int				error = 0;
1726	uint32_t		mode = (ap->a_fflags & PROT_WRITE) ? (FWRITE | FREAD) : FREAD;
1727	int				accessMode = (ap->a_fflags & PROT_WRITE) ? kAccessWrite : kAccessRead;
1728    SMBFID fid = 0;
1729	struct fileRefEntry *entry = NULL;
1730
1731	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
1732		return (EPERM);
1733
1734	np = VTOSMB(vp);
1735	np->n_lastvop = smbfs_vnop_mmap;
1736
1737	/* We already have it mapped, just ignore this one */
1738	if (np->n_flag & NISMAPPED)
1739	    goto out;
1740	/*
1741	 * Since we should already be open with the correct modes then we should never
1742	 * need to really open the file. For now we try these three cases.
1743	 *
1744	 * First try the simple case, we have a posix open with the correct access.
1745	 *
1746	 * Second see if we have a match in the open deny mode list. Still not 100% sure this
1747	 * will work ever time because they are passing the current context, which may not match
1748	 * the one passed to open. From taking to Joe he believe we will always be in the open
1749	 * context when call. From my testing this seems to be true.
1750	 *
1751	 * Third just return EPERM.
1752	 */
1753	if ((np->f_fid != 0) &&
1754        (np->f_accessMode & accessMode)) {
1755		np->f_refcnt++;
1756	} else if (FindFileRef(vp, vfs_context_proc(ap->a_context), accessMode,
1757							   kAnyMatch, 0, 0, &entry, &fid) == 0) {
1758		entry->refcnt++;
1759		entry->mmapped = TRUE;
1760		np->f_refcnt++;
1761	} else {
1762		SMBERROR("%s We could not find an open file with mode = 0x%x? \n", np->n_name, mode);
1763		error = EPERM;
1764		goto out;
1765	}
1766	np->n_flag |= NISMAPPED;
1767	np->f_mmapMode = mode;
1768out:
1769	smbnode_unlock(np);
1770	return (error);
1771}
1772
1773/*
1774 * smbfs_vnop_mnomap - smbfs vnodeop entry point
1775 *	vnode_t a_vp;
1776 *	vfs_context_t a_context;
1777 *
1778 * When called this is a hint that we can now close the file. We will not get any
1779 * more pagein or pageout calls without another mmap call.  If our reference count
1780 * is down to one then all we have to do is call close and it will clean everything
1781 * up. Otherwise we have a little more work to do see below for more details.
1782 *
1783 * NOTE: All errors are ignored by the calling routine
1784 */
1785static int
1786smbfs_vnop_mnomap(struct vnop_mnomap_args *ap)
1787{
1788	vnode_t				vp = ap->a_vp;
1789	struct smbnode		*np;
1790	struct fileRefEntry *entry;
1791	int					error = 0;
1792
1793	if (smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK))
1794		return (EPERM);	/* Not sure what to do here, they ignore errors */
1795	np = VTOSMB(vp);
1796	np->n_lastvop = smbfs_vnop_mnomap;
1797
1798	/* Only one open reference just call close and let it clean every thing up. */
1799	if (np->f_refcnt == 1) {
1800		struct smb_share *share;
1801
1802		share = smb_get_share_with_reference(VTOSMBFS(vp));
1803		error = smbfs_close(share, vp, np->f_mmapMode, ap->a_context);
1804		smb_share_rele(share, ap->a_context);
1805		if (error)
1806			SMBWARNING("%s close failed with error = %d\n", np->n_name, error);
1807		goto out;
1808	} else {
1809		np->f_refcnt--;
1810	}
1811	/*
1812	 * We get passed the current context which may or may not be the the same as the one used
1813	 * in the open. So search the list and see if there are any mapped entries. Remember we only
1814	 * have one item mapped at a time.
1815	 */
1816	if (FindMappedFileRef(vp, &entry, NULL) == TRUE) {
1817		entry->mmapped = FALSE;
1818		if (entry->refcnt > 0)	/* This entry is still in use don't remove it yet. */
1819			entry->refcnt--;
1820		else /* Done with it remove it from the list */
1821		    RemoveFileRef(vp, entry);
1822	}
1823out:
1824	np->f_mmapMode = 0;
1825	np->n_flag &= ~NISMAPPED;
1826	smbnode_unlock(np);
1827	return (error);
1828}
1829
1830/*
1831 * smbfs_vnop_inactive - smbfs vnodeop entry point
1832 *	vnode_t a_vp;
1833 *	vfs_context_t a_context;
1834 */
1835static int
1836smbfs_vnop_inactive(struct vnop_inactive_args *ap)
1837{
1838	vnode_t vp = ap->a_vp;
1839	struct smbnode *np;
1840	struct smb_share *share = NULL;
1841	int error = 0;
1842	int releaseLock = TRUE;
1843
1844	(void)smbnode_lock(VTOSMB(vp), SMBFS_RECLAIM_LOCK);
1845	np = VTOSMB(vp);
1846	np->n_lastvop = smbfs_vnop_inactive;
1847	share = smb_get_share_with_reference(VTOSMBFS(vp));
1848
1849
1850	/* Clear any symlink cache, always safe to do even on non symlinks */
1851    if (np->n_symlink_target) {
1852        SMB_FREE(np->n_symlink_target, M_TEMP);
1853    }
1854	np->n_symlink_target_len = 0;
1855	np->n_symlink_cache_timer = 0;
1856
1857	/* Node went inactive clear the ACL cache */
1858	if (!vnode_isnamedstream(vp))
1859		smbfs_clear_acl_cache(np);
1860
1861    /*
1862	 * Before we take the lock, someone could jump in and do an open and start using this vnode again.
1863	 * We now check for that and just skip out if it happens. We will get another inactive later, if
1864	 * this volume is not being force unmount. So check here to see if the vnode is in use and the
1865	 * volume is not being forced unmounted. Note that Kqueue opens will not be found by vnode_isinuse.
1866	 */
1867    if ((vnode_isinuse(vp, 0)) && !(vfs_isforce(vnode_mount(vp))))
1868        goto out;
1869
1870	if (vnode_isdir(vp)) {
1871		smbfs_closedirlookup(np, ap->a_context);
1872		np->d_refcnt = 0;
1873		if (np->d_kqrefcnt) {
1874			smbfs_stop_change_notify(share, np, TRUE, ap->a_context, &releaseLock);
1875		}
1876		goto out;
1877	}
1878
1879	/* its not in use are they don't care about it close it */
1880	if (np->f_refcnt) {
1881		np->f_refcnt = 1;
1882		error = smbfs_close(share, vp, FREAD, ap->a_context);
1883		if (error) {
1884			SMBDEBUG("error %d closing fid %llx file %s\n",
1885                     error, np->f_fid, np->n_name);
1886		}
1887	}
1888
1889	/*
1890	 * Does the file need to be deleted on close. Make one more check here
1891	 * just in case.
1892	 */
1893	if (np->n_flag & NDELETEONCLOSE) {
1894		error = smbfs_smb_delete(share, np, NULL, 0, 0, ap->a_context);
1895		if (error)
1896			SMBWARNING("error %d deleting silly rename file %s\n",
1897					   error, np->n_name);
1898		else np->n_flag &= ~NDELETEONCLOSE;
1899	}
1900#ifdef SMB_DEBUG
1901	/* If the file is not in use then it should be closed. */
1902	DBG_ASSERT((np->f_refcnt == 0));
1903	DBG_ASSERT((np->f_openDenyList == NULL));
1904	DBG_ASSERT((np->f_smbflock == NULL));
1905#endif // SMB_DEBUG
1906
1907out:
1908	smb_share_rele(share, ap->a_context);
1909	if (releaseLock)
1910		smbnode_unlock(np);
1911	return (0);
1912}
1913
1914/*
1915 * Free smbnode, and give vnode back to system
1916 *		struct vnodeop_desc *a_desc;
1917 *		vnode_t a_vp;
1918 *		vfs_context_t a_context;
1919 */
1920static int smbfs_vnop_reclaim(struct vnop_reclaim_args *ap)
1921{
1922	vnode_t vp = ap->a_vp;
1923	vnode_t dvp;
1924	struct smbnode *np = NULL;
1925	struct smbmount *smp = NULL;
1926
1927	(void) smbnode_lock(VTOSMB(vp), SMBFS_RECLAIM_LOCK);
1928	np = VTOSMB(vp);
1929	np->n_lastvop = smbfs_vnop_reclaim;
1930	smp = VTOSMBFS(vp);
1931#ifdef SMB_DEBUG
1932	/* We should never have a file open at this point */
1933	if (vnode_isreg(vp)) {
1934		DBG_ASSERT((np->f_refcnt == 0));
1935	} else if (vnode_isdir(vp)) {
1936		DBG_ASSERT((np->d_kqrefcnt == 0));
1937		DBG_ASSERT((np->d_fctx == NULL));
1938	}
1939#endif // SMB_DEBUG
1940
1941    lck_mtx_lock(&smp->sm_reclaim_renamelock);
1942	SET(np->n_flag, NTRANSIT);
1943
1944    dvp = ( (np->n_parent && (np->n_flag & NREFPARENT)) &&
1945           ((np->n_parent->n_flag & NTRANSIT) != NTRANSIT)) ?
1946            np->n_parent->n_vnode : NULL;
1947
1948    if (dvp != NULL) {
1949        /* Parent exists and is not being reclaimed, remove child's refcount */
1950        OSDecrementAtomic(&VTOSMB(dvp)->n_child_refcnt);
1951        np->n_parent = NULL;
1952    }
1953
1954    /* child_refcnt better be zero */
1955    if (np->n_child_refcnt && !(vfs_isforce(vnode_mount(vp)))) {
1956        /*
1957         * Forced unmounts are very brutal, and it's not unusual for a parent
1958         * node being reclaimed to have a non-zero child refcount.  So we only
1959         * log an error if this is not a forced unmount, which we do care about.
1960         */
1961        if (vnode_getname(vp) != NULL) {
1962            SMBERROR("%s: node: %s, n_child_refcnt not zero like it should be: %ld\n",
1963                     __FUNCTION__, vnode_getname(vp), (long) np->n_child_refcnt);
1964        } else {
1965            SMBERROR("%s: n_child_refcnt not zero like it should be: %ld\n",
1966                     __FUNCTION__, (long) np->n_child_refcnt);
1967        }
1968    }
1969	if (np->n_child_refcnt) {
1970		smbfs_ClearChildren(smp, np);
1971	}
1972
1973	/*
1974 	 * In previous code - smb_vhashrem() was called after releasing
1975     * sm_reclaim_renamelock.
1976	 * There was a small window between sm_reclaim_renamelock is released and
1977     * smbnode (say child) is deleted from hash.
1978     * During this window, child can be NTRANSIT and parent can acquire
1979     * sm_reclaim_renamelock, proceed further in reclaim to call
1980     * smbfs_ClearChildren(), but skips the above child (NTRASIT set),
1981     * gets deleted from hash before child gets deleted.
1982     * May not affect anything as such, but just to be safe, I am moving
1983     * smb_vhashrem() in the scope of the sm_reclaim_renamelock.
1984     * Most likely, this can happen during the force unmount.
1985     */
1986    smb_vhashrem(np);
1987    lck_mtx_unlock(&smp->sm_reclaim_renamelock);
1988
1989	cache_purge(vp);
1990	if (smp->sm_rvp == vp) {
1991		SMBVDEBUG("root vnode\n");
1992		smp->sm_rvp = NULL;
1993	}
1994	/* Destroy the lock used for the open state, open deny list and resource size/timer */
1995	if (!vnode_isdir(vp)) {
1996		lck_mtx_destroy(&np->f_openDenyListLock, smbfs_mutex_group);
1997		lck_mtx_destroy(&np->f_openStateLock, smbfs_mutex_group);
1998		lck_mtx_destroy(&np->f_clusterWriteLock, smbfs_mutex_group);
1999		if (!vnode_isnamedstream(vp))
2000			lck_mtx_destroy(&np->rfrkMetaLock, smbfs_mutex_group);
2001	}
2002
2003	/* Clear any symlink cache, always safe to do even on non symlinks */
2004    if (np->n_symlink_target != NULL) {
2005        SMB_FREE(np->n_symlink_target, M_TEMP);
2006    }
2007	np->n_symlink_target_len = 0;
2008	np->n_symlink_cache_timer = 0;
2009
2010	/* We are done with the node clear the acl cache and destroy the acl cache lock  */
2011	if (!vnode_isnamedstream(vp)) {
2012		smbfs_clear_acl_cache(np);
2013		lck_mtx_destroy(&np->f_ACLCacheLock, smbfs_mutex_group);
2014	}
2015
2016	/* Free up both names before we unlock the node */
2017    if (np->n_name != NULL) {
2018        SMB_FREE(np->n_name, M_SMBNODENAME);
2019    }
2020    if (np->n_sname != NULL) {
2021        SMB_FREE(np->n_sname, M_SMBNODENAME);
2022    }
2023
2024    /* Clear the private data pointer *before* unlocking the node, so we don't
2025     * race with another thread doing a 'np = VTOSMB(vp)'.
2026     */
2027    vnode_clearfsnode(vp);
2028	smbnode_unlock(np);
2029
2030	CLR(np->n_flag, (NALLOC|NTRANSIT));
2031	if (ISSET(np->n_flag, NWALLOC) || ISSET(np->n_flag, NWTRANSIT)) {
2032		CLR(np->n_flag, (NWALLOC|NWTRANSIT));
2033		wakeup(np);
2034	}
2035	lck_rw_destroy(&np->n_rwlock, smbfs_rwlock_group);
2036	lck_rw_destroy(&np->n_name_rwlock, smbfs_rwlock_group);
2037	SMB_FREE(np, M_SMBNODE);
2038	if (dvp && (vnode_get(dvp) == 0)) {
2039		vnode_rele(dvp);
2040		vnode_put(dvp);
2041	}
2042	return 0;
2043}
2044
2045/*
2046 * smbfs_getattr call from vfs.
2047 *
2048 * The calling routine must hold a reference on the share
2049 *
2050 */
2051static int
2052smbfs_getattr(struct smb_share *share, vnode_t vp, struct vnode_attr *vap,
2053			  vfs_context_t context)
2054{
2055	if (share->ss_attributes & FILE_PERSISTENT_ACLS &&
2056	    (VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_guuid) ||
2057	     VATTR_IS_ACTIVE(vap, va_uuuid))) {
2058			DBG_ASSERT(!vnode_isnamedstream(vp));
2059			(void)smbfs_getsecurity(share, VTOSMB(vp), vap, context);
2060	}
2061	return smbfs_update_cache(share, vp, vap, context);
2062}
2063
2064/*
2065 * smbfs_vnop_getattr
2066 *
2067 * vnode_t	a_vp;
2068 * struct vnode_attr *a_vap;
2069 * vfs_context_t a_context;
2070 */
2071static int
2072smbfs_vnop_getattr(struct vnop_getattr_args *ap)
2073{
2074	int32_t error = 0;
2075	struct smb_share *share;
2076	struct smbnode *np;
2077
2078	if ((error = smbnode_lock(VTOSMB(ap->a_vp), SMBFS_SHARED_LOCK))) {
2079		return (error);
2080	}
2081	np = VTOSMB(ap->a_vp);
2082	np->n_lastvop = smbfs_vnop_getattr;
2083	share = smb_get_share_with_reference(VTOSMBFS(ap->a_vp));
2084	/* Before updating see if it needs to be reopened. */
2085	if ((!vnode_isdir(ap->a_vp)) && (np->f_openState & kNeedReopen)) {
2086		/* smbfs_smb_reopen_file should check to see if the share changed? */
2087		(void)smbfs_smb_reopen_file(share, np, ap->a_context);
2088	}
2089	error = smbfs_getattr(share, ap->a_vp, ap->a_vap, ap->a_context);
2090	smb_share_rele(share, ap->a_context);
2091	smbnode_unlock(np);
2092	return (error);
2093}
2094
2095/*
2096 * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
2097 * interval there were 8 regular years and 2 leap years.
2098 */
2099#define	SECONDSTO1980	(((8 * 365) + (2 * 366)) * (24 * 60 * 60))
2100static struct timespec fat1980_time = {SECONDSTO1980, 0};
2101
2102/*
2103* The calling routine must hold a reference on the share
2104*/
2105static int
2106smbfs_setattr(struct smb_share *share, vnode_t vp, struct vnode_attr *vap,
2107			  vfs_context_t context)
2108{
2109	struct smbnode *np = VTOSMB(vp);
2110	struct smbmount *smp = VTOSMBFS(vp);
2111	struct timespec *crtime, *mtime, *atime;
2112	u_quad_t tsize = 0;
2113	int error = 0, cerror, modified = 0;
2114    SMBFID fid = 0;
2115	uint32_t rights;
2116	Boolean useFatTimes = (share->ss_fstype == SMB_FS_FAT);
2117
2118	/* If this is a stream then they can only set the size */
2119	if ((vnode_isnamedstream(vp)) &&
2120		(vap->va_active & ~VNODE_ATTR_BIT(va_data_size))) {
2121		SMBDEBUG("Using stream node %s to set something besides the size?\n",
2122				 np->n_name);
2123		error = ENOTSUP;
2124		goto out;
2125	}
2126
2127	/*
2128	 * If our caller is trying to set multiple attributes, they
2129	 * can make no assumption about what order they are done in.
2130	 * Here we try to do them in order of decreasing likelihood
2131	 * of failure, just to minimize the chance we'll wind up
2132	 * with a partially complete request.
2133	 */
2134
2135	if (share->ss_attributes & FILE_PERSISTENT_ACLS &&
2136	    (VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_guuid) ||
2137	     VATTR_IS_ACTIVE(vap, va_uuuid))) {
2138		error = smbfs_setsecurity(share, vp, vap, context);
2139		if (error)
2140			goto out;
2141		/*
2142		 * Failing to set VATTR_SET_SUPPORTED to something which was
2143		 * requested causes fallback to EAs, which we never want. This
2144		 * is done because of HFS, so if you support it you have to
2145		 * always return something, even if its wrong.
2146		 */
2147		if (VATTR_IS_ACTIVE(vap, va_acl))
2148			VATTR_SET_SUPPORTED(vap, va_acl);
2149		if (VATTR_IS_ACTIVE(vap, va_guuid))
2150			VATTR_SET_SUPPORTED(vap, va_guuid);
2151		if (VATTR_IS_ACTIVE(vap, va_uuuid))
2152			VATTR_SET_SUPPORTED(vap, va_uuuid);
2153		modified = 1;
2154	}
2155
2156	/*
2157	 * If the server supports the new UNIX extensions, then we can support
2158	 * changing the uid, gid, mode, and va_flags. Currently the uid and gid
2159	 * don't make any sense, but in the future we may add this support.
2160	 *
2161	 * The old code would check the users creditials here. There is no need for
2162	 * that in our case. The lower level will make sure the correct local user
2163	 * is using the vc and the server should protect us for any other case.
2164	 */
2165
2166	if ((VATTR_IS_ACTIVE(vap, va_mode)) || (VATTR_IS_ACTIVE(vap, va_flags))) {
2167		int supportUnixBSDFlags = ((UNIX_CAPS(share) & UNIX_SFILEINFO_UNIX_INFO2_CAP)) ? TRUE : FALSE;
2168		int supportUnixInfo2 = ((UNIX_CAPS(share) & UNIX_QFILEINFO_UNIX_INFO2_CAP)) ? TRUE : FALSE;
2169		int darwin = (SSTOVC(share)->vc_flags & SMBV_DARWIN) ? TRUE : FALSE;
2170		int dosattr = np->n_dosattr;
2171		uint32_t vaflags = 0;
2172		uint32_t vaflags_mask = SMB_FLAGS_NO_CHANGE;
2173		uint64_t vamode = SMB_MODE_NO_CHANGE;
2174
2175		if (VATTR_IS_ACTIVE(vap, va_flags)) {
2176			/*
2177			 * Here we are strict, stricter than ufs in not allowing users to
2178			 * attempt to set SF_SETTABLE bits or anyone to set unsupported bits.
2179			 * However, we ignore attempts to set ATTR_ARCHIVE for directories
2180			 * `cp -pr' from a more sensible file system attempts it a lot.
2181			 */
2182			if (vap->va_flags & ~(SF_ARCHIVED | SF_IMMUTABLE | UF_IMMUTABLE | UF_HIDDEN))
2183			{
2184				error = EINVAL;
2185				goto out;
2186			}
2187			/* Only set items we can change and the server supports */
2188			vaflags_mask = np->n_flags_mask & EXT_REQUIRED_BY_MAC;
2189
2190			/*
2191			 * Remember that SMB_EFA_ARCHIVE means the items needs to be
2192			 * archive and SF_ARCHIVED means the item has been archive.
2193			 */
2194			if (vap->va_flags & SF_ARCHIVED) {
2195				dosattr &= ~SMB_EFA_ARCHIVE;
2196				vaflags |= EXT_DO_NOT_BACKUP;
2197			} else {
2198				dosattr |= SMB_EFA_ARCHIVE;
2199			}
2200			/*
2201			 * SMB_EFA_RDONLY ~ UF_IMMUTABLE
2202			 *
2203			 * We treat the SMB_EFA_RDONLY as the immutable flag. This allows
2204			 * us to support the finder lock bit and makes us follow the
2205			 * MSDOS code model. See msdosfs project.
2206			 *
2207			 * NOTE: The ready-only flags does not exactly follow the
2208			 * lock/immutable bit also note the for directories its advisory only.
2209			 *
2210			 * We do not support the setting the read-only bit for folders if
2211			 * the server does not support the new UNIX extensions.
2212			 *
2213			 * See Radar 5582956 for more details.
2214			 */
2215            if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
2216                if (UNIX_SERVER(SSTOVC(share)) || (!vnode_isdir(vp))) {
2217                    if (vap->va_flags & (SF_IMMUTABLE | UF_IMMUTABLE)) {
2218                        dosattr |= SMB_EFA_RDONLY;
2219                        vaflags |= EXT_IMMUTABLE;
2220                    }
2221                    else {
2222                        dosattr &= ~SMB_EFA_RDONLY;
2223                    }
2224                }
2225           }
2226            else {
2227                if (supportUnixBSDFlags || darwin || (!vnode_isdir(vp))) {
2228                    if (vap->va_flags & (SF_IMMUTABLE | UF_IMMUTABLE)) {
2229                        dosattr |= SMB_EFA_RDONLY;
2230                        vaflags |= EXT_IMMUTABLE;
2231                    }
2232                    else {
2233                        dosattr &= ~SMB_EFA_RDONLY;
2234                    }
2235                }
2236            }
2237
2238			/*
2239			 * NOTE: Windows does not set ATTR_ARCHIVE bit for directories.
2240			 */
2241			if ((! supportUnixBSDFlags) && (vnode_isdir(vp)))
2242				dosattr &= ~SMB_EFA_ARCHIVE;
2243
2244			/* Now deal with the new Hidden bit */
2245			if (vap->va_flags & UF_HIDDEN) {
2246				dosattr |= SMB_EFA_HIDDEN;
2247				vaflags |= EXT_HIDDEN;
2248			} else {
2249				dosattr &= ~SMB_EFA_HIDDEN;
2250			}
2251		}
2252
2253		/*
2254		 * Currently we do not allow setting the uid, gid, or sticky bits. Also
2255		 * chmod on a symbolic link doesn't really make sense. BSD allows this
2256		 * with the lchmod and on create, but Samba doesn't support this because
2257		 * its not POSIX. If we try to chmod here it will get set on the target
2258		 * which would be bad. So ignore the fact that they made this request.
2259		 */
2260		if (VATTR_IS_ACTIVE(vap, va_mode)) {
2261			if (supportUnixInfo2 && (!vnode_islnk(vp))) {
2262				vamode = vap->va_mode & ACCESSPERMS;
2263			} else if ((share->ss_attributes & FILE_PERSISTENT_ACLS) &&
2264					   (darwin || !UNIX_CAPS(share))) {
2265				vamode = vap->va_mode & ACCESSPERMS;
2266			} else if (SSTOVC(share)->vc_server_caps & kAAPL_SUPPORTS_NFS_ACE) {
2267                /*
2268                 * For OS X <-> OS X PFS (where ACLs are off by default), we
2269                 * need a way to set Posix permissions. If the server supports
2270                 * the NFS ACE, then it will allow us to get the ACL and send
2271                 * it back with the desired Posix permissions in the NFS ACE.
2272                 */
2273				vamode = vap->va_mode & ACCESSPERMS;
2274            }
2275
2276		}
2277		if (dosattr == np->n_dosattr) {
2278			vaflags_mask = 0; /* Nothing really changes, no need to make the call */
2279		}
2280		if (vaflags_mask || (vamode != SMB_MODE_NO_CHANGE)) {
2281			if (!supportUnixInfo2) {
2282				/* Windows style server */
2283				if (vaflags_mask) {
2284					error = smbfs_smb_setpattr(share, np, NULL, 0, dosattr, context);
2285				}
2286				if (vamode != SMB_MODE_NO_CHANGE) {
2287					/* Should we report the error? */
2288					error = smbfs_set_ace_modes(share, np, vamode, context);
2289				}
2290			} else if (supportUnixBSDFlags) {
2291				/* Samba server that does support the BSD flags (Mac OS) */
2292				error = smbfs_set_unix_info2(share, np, NULL, NULL, NULL,
2293											 SMB_SIZE_NO_CHANGE,  vamode, vaflags,
2294											 vaflags_mask, context);
2295			} else {
2296				/* Samba server that doesn't support the BSD flags, Linux */
2297				if (vamode != SMB_MODE_NO_CHANGE) {
2298					/* Now set the posix modes, using unix info level */
2299					error = smbfs_set_unix_info2(share, np, NULL, NULL, NULL,
2300												 SMB_SIZE_NO_CHANGE, vamode,
2301												 SMB_FLAGS_NO_CHANGE, vaflags_mask,
2302												 context);
2303				}
2304				if (vaflags_mask) {
2305					/* Set the BSD flags using normal smb info level  */
2306					error = smbfs_smb_setpattr(share, np, NULL, 0, dosattr, context);
2307				}
2308			}
2309			if (error)
2310				goto out;
2311		}
2312		/* Everything work update the local cache and mark that we did the work */
2313		if (VATTR_IS_ACTIVE(vap, va_mode)) {
2314	    	if (vamode != SMB_MODE_NO_CHANGE) {
2315				np->n_mode = vamode;
2316				VATTR_SET_SUPPORTED(vap, va_mode);
2317			}
2318		}
2319		if (VATTR_IS_ACTIVE(vap, va_flags)) {
2320			np->n_dosattr = dosattr;
2321			VATTR_SET_SUPPORTED(vap, va_flags);
2322		}
2323	}
2324
2325	if (VATTR_IS_ACTIVE(vap, va_data_size) && (vnode_isreg(vp))) {
2326		uint32_t trycnt = 0;
2327
2328		ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
2329		/* The seteof call requires the file to be opened for write and append data. */
2330		rights = SMB2_FILE_WRITE_DATA | SMB2_FILE_APPEND_DATA;
2331		/*
2332		 * The connection could go down in the middle of setting the eof, in
2333		 * this case we will get a bad file descriptor error. Keep trying until
2334		 * the open fails or we get something besides EBADF.
2335		 *
2336		 * We now have a counter that keeps us from going into an infinite loop. Once
2337		 * we implement SMB2 we should take a second look at how this should be done.
2338		 */
2339		do {
2340			error = smbfs_tmpopen(share, np, rights, &fid, context);
2341			if (error) {
2342				SMB_LOG_IO("%s seteof open failed %d\n", np->n_name, error);
2343				/* The open failed, fail the seteof. */
2344				break;
2345			}
2346
2347			/* zero fill if needed, ignore any errors will catch them on the seteof call */
2348			tsize = np->n_size;
2349			if (tsize < vap->va_data_size) {
2350				error = smbfs_0extend(share, fid, tsize, vap->va_data_size, 0, context);
2351			}
2352			/* Set the eof on the server */
2353			if (!error) {
2354				error = smbfs_seteof(share, np, fid, vap->va_data_size, context);
2355			}
2356			if (error == EBADF) {
2357				trycnt++;
2358				SMB_LOG_IO("%s seteof failed because of reconnect, trying again.\n",
2359						   np->n_name);
2360			}
2361			/*
2362			 * Windows FAT file systems require a flush, after a seteof. Until the
2363			 * the flush they will keep returning the old file size.
2364			 */
2365			if ((!error) && (share->ss_fstype == SMB_FS_FAT) &&
2366				(!UNIX_SERVER(SSTOVC(share)))) {
2367				error = smbfs_smb_flush(share, fid, context);
2368				if (!error)
2369					np->n_flag &= ~NNEEDS_FLUSH;
2370			}
2371			/* We ignore errors on close, not much we can do about it here */
2372			(void)smbfs_tmpclose(share, np, fid, context);
2373		} while ((error == EBADF) && (trycnt < SMB_MAX_REOPEN_CNT));
2374
2375		SMB_LOG_IO("%s: Calling smbfs_setsize, old eof = %lld  new eof = %lld\n",
2376				   np->n_name, tsize, vap->va_data_size);
2377		if (error) {
2378			smbfs_setsize(vp, (off_t)tsize);
2379			goto out;
2380		} else {
2381			smbfs_setsize(vp, (off_t)vap->va_data_size);
2382		}
2383
2384		VATTR_SET_SUPPORTED(vap, va_data_size);
2385		/* Tell the stream's parent that something has changed */
2386		if (vnode_isnamedstream(vp)) {
2387			vnode_t parent_vp = smb_update_rsrc_and_getparent(vp, TRUE);
2388			/*
2389			 * We cannot always update the parents meta cache timer, so don't
2390			 * even try here
2391			 */
2392			if (parent_vp)
2393				vnode_put(parent_vp);
2394		}
2395
2396		modified = 1;
2397  	}
2398
2399	/*
2400	 * Note that it's up to the caller to provide (or not) a fallback for
2401	 * backup_time, as we don't support them.
2402	 *
2403	 */
2404	crtime = VATTR_IS_ACTIVE(vap, va_create_time) ? &vap->va_create_time : NULL;
2405	mtime = VATTR_IS_ACTIVE(vap, va_modify_time) ? &vap->va_modify_time : NULL;
2406	atime = VATTR_IS_ACTIVE(vap, va_access_time) ? &vap->va_access_time : NULL;
2407
2408	/*
2409	 * If they are just setting the time to the same value then just say we made
2410	 * the call. This will not hurt anything and will protect us from badly
2411	 * written applications. Here is what was happening in the case of the finder
2412	 * copy. The file gets copied, and the modify time and create time have been set to
2413	 * the current time by the server. The application is using utimes to set the
2414	 * modify time to the original file's modify time. This time is before the create time.
2415	 * So we set both the create and modify time to the same value. See the HFS note
2416	 * below. Now the applications wants to set the create time to be the same as the
2417	 * orignal file. In this case the original file has the same modify and create time. So
2418	 * we end up setting the create time twice to the same value. Even with this code the
2419	 * copy engine needs to be fixed, looking into that now. Looks like this will get fix
2420	 * with Radar 4385758. We should retest once that radar is completed.
2421	 */
2422	if (crtime && (timespeccmp(crtime, &np->n_crtime, ==))) {
2423		VATTR_SET_SUPPORTED(vap, va_create_time);
2424		crtime = NULL;
2425	}
2426	if (mtime && (timespeccmp(mtime, &np->n_mtime, ==))) {
2427		VATTR_SET_SUPPORTED(vap, va_modify_time);
2428		mtime = NULL;
2429	}
2430	if (atime && (timespeccmp(atime, &np->n_atime, ==))) {
2431		VATTR_SET_SUPPORTED(vap, va_access_time);
2432		atime = NULL;
2433	}
2434
2435	/*
2436	 * We sometimes get sent a zero access time. Did some testing and found
2437	 * out the following:
2438	 *
2439	 *	MSDOS	- The date gets set to Dec 30 17:31:44 1969
2440	 *	SMB FAT	- The date gets set to Jan  1 00:00:00 1980
2441	 *	UFS	- The date gets set to Dec 31 16:00:00 1969
2442	 *	SMB NTFS- The date gets set to Dec 31 16:00:00 1969
2443	 *	HFS	- The date displayed from ls is Dec 31 16:00:00 1969
2444	 *	HFS	- The getattrlist date is <no value>
2445	 *
2446	 * I believe this is from a utimes call where they are setting the
2447	 * modify time, but leaving the access time set to zero. We seem to be
2448	 * doing the same thing as everyone else so let them do it.
2449	 */
2450	/*
2451	 * The following comment came from the HFS code.
2452	 * The utimes system call can reset the modification time but it doesn't
2453	 * know about create times. So we need to ensure that the creation time
2454	 * is always at least as old as the modification time.
2455	 *
2456	 * The HFS code also checks to make sure it was not the root vnode. Don
2457	 * Brady said that the SMB code should not use that part of the check.
2458	 */
2459	if (!crtime && mtime && (timespeccmp(mtime, &np->n_crtime, <))) {
2460		crtime = mtime;
2461	}
2462
2463	if (!crtime && !mtime && !atime) {
2464		/* Nothing left to do here get out */
2465		goto out;
2466	}
2467retrySettingTime:
2468#if 0
2469	if (crtime && mtime) {
2470		SMBDEBUG("%s crtime = %ld:%ld mtime = %ld:%ld\n", np->n_name,
2471				 crtime->tv_sec, crtime->tv_nsec, mtime->tv_sec, mtime->tv_nsec);
2472	} else if (crtime) {
2473		SMBDEBUG("%s crtime = %ld:%ld\n", np->n_name, crtime->tv_sec, crtime->tv_nsec);
2474	} else if (mtime) {
2475		SMBDEBUG("%s mtime = %ld:%ld\n", np->n_name, mtime->tv_sec, mtime->tv_nsec);
2476	}
2477#endif // SMB_DEBUG
2478	/*
2479	 * FAT file systems don't support dates earlier than 1980, reset the
2480	 * date to 1980. Now the Finder likes to set the create date to 1904 or 1946,
2481	 * should we treat this special? We could hold on to the original time
2482	 * and return that value until they reset it or the vnode goes away. Since
2483	 * we never had any reports lets not add any extra code.
2484	 */
2485	if (useFatTimes) {
2486		if (crtime && (timespeccmp(crtime, &fat1980_time, <))) {
2487			crtime = &fat1980_time;
2488			SMBDEBUG("%s FAT crtime.tv_sec = %ld crtime.tv_nsec = %ld\n",
2489					 np->n_name, crtime->tv_sec, crtime->tv_nsec);
2490		}
2491		if (mtime && (timespeccmp(mtime, &fat1980_time, <))) {
2492			mtime = &fat1980_time;
2493			SMBDEBUG("%s FAT mtime.tv_sec = %ld mtime.tv_nsec = %ld\n",
2494					 np->n_name, mtime->tv_sec, mtime->tv_nsec);
2495		}
2496		/* Never let them set the access time before 1980 */
2497		if (atime && (timespeccmp(atime, &fat1980_time, <))) {
2498			atime = NULL;
2499		}
2500	}
2501
2502	if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
2503       /* SMB2.x always has to open/set/close the file */
2504        error = smb2fs_smb_setpattrNT(share, np,
2505                                      NULL, 0,
2506                                      np->n_dosattr, crtime,
2507                                      mtime, atime,
2508                                      context);
2509    }
2510    else {
2511        rights = SMB2_FILE_WRITE_ATTRIBUTES;
2512        /*
2513         * For Windows 95/98/Me/NT4 and all old dialects we must have
2514         * the item open before we can set the date and time. For all
2515         * other systems; if the item is already open then make sure it
2516         * has the correct open mode.
2517         *
2518         * We currently never do a NT style open with write attributes.
2519         * So for all systems except NT4 that spport the NTCreateAndX
2520         * call we will fall through and just use the set path method.
2521         * In the future we may decide to add open deny support. So if
2522         * we decide to add write atributes access then this code will
2523         * work without any other changes.
2524         */
2525        if ((SSTOVC(share)->vc_flags & SMBV_NT4) ||
2526            (smp->sm_flags & MNT_REQUIRES_FILEID_FOR_TIME) ||
2527            ((!vnode_isdir(vp)) && np->f_refcnt && (np->f_rights & rights))) {
2528
2529            /*
2530             * For NT systems we need the file open for write attributes.
2531             * Either write access or all access will work. If they
2532             * already have it open for all access just use that,
2533             * otherwise use write. We corrected tmpopen
2534             * to work correctly now. So just ask for the NT access.
2535             */
2536            error = smbfs_tmpopen(share, np, rights, &fid, context);
2537            if (error)
2538                goto out;
2539
2540            error = smbfs_smb_setfattrNT(share, np->n_dosattr, fid, crtime,
2541                                         mtime, atime, context);
2542            cerror = smbfs_tmpclose(share, np, fid, context);
2543            if (cerror)
2544                SMBERROR("error %d closing fid %llx file %s\n",
2545                         cerror, fid, np->n_name);
2546
2547        } else {
2548            error = smbfs_smb_setpattrNT(share, np,
2549                                         NULL, 0,
2550                                         np->n_dosattr, crtime, mtime,
2551                                         atime, context);
2552            /* They don't support this call, we need to fallback to the old method; stupid NetApp */
2553            if (error == ENOTSUP) {
2554                SMBWARNING("Server does not support setting time by path, fallback to old method\n");
2555                smp->sm_flags |= MNT_REQUIRES_FILEID_FOR_TIME;	/* Never go down this path again */
2556                error = smbfs_tmpopen(share, np, rights, &fid, context);
2557                if (!error) {
2558                    error = smbfs_smb_setfattrNT(share, np->n_dosattr, fid,
2559                                                 crtime, mtime, atime, context);
2560                    (void)smbfs_tmpclose(share, np, fid, context);
2561                }
2562            }
2563        }
2564    }
2565	/*
2566	 * Some servers (NetApp) don't support setting time before 1970 and will
2567	 * return an error here. So if we get an error and we were trying to set
2568	 * the time to before 1970 lets try again, but this time lets treat them
2569	 * the same as a FAT file system.
2570	 */
2571	if (error && !useFatTimes &&
2572		((crtime && (crtime->tv_sec < 0)) || (mtime && (mtime->tv_sec < 0)))) {
2573		useFatTimes = TRUE;
2574		goto retrySettingTime;
2575	}
2576
2577	if (error)
2578		goto out;
2579
2580	if (crtime) {
2581		VATTR_SET_SUPPORTED(vap, va_create_time);
2582		np->n_crtime = *crtime;
2583	}
2584	if (mtime) {
2585		VATTR_SET_SUPPORTED(vap, va_modify_time);
2586		np->n_mtime = *mtime;
2587	}
2588	if (atime) {
2589		VATTR_SET_SUPPORTED(vap, va_access_time);
2590		np->n_atime = *atime;
2591	}
2592	/* Update the change time */
2593	if (crtime || mtime || atime)
2594		nanotime(&np->n_chtime); /* Need current date/time, so use nanotime */
2595
2596out:
2597	if (modified) {
2598		/*
2599		 * Invalidate attribute cache in case if server doesn't set
2600		 * required attributes.
2601		 */
2602		np->attribute_cache_timer = 0;	/* invalidate cache */
2603	}
2604	return (error);
2605}
2606
2607/*
2608 * smbfs_vnop_getattr
2609 *
2610 * vnode_t	a_vp;
2611 * struct vnode_attr *a_vap;
2612 * vfs_context_t a_context;
2613 */
2614static int
2615smbfs_vnop_setattr(struct vnop_setattr_args *ap)
2616{
2617	int32_t error = 0;
2618	struct smbnode *np;
2619	struct smb_share *share;
2620
2621	if ((error = smbnode_lock(VTOSMB(ap->a_vp), SMBFS_EXCLUSIVE_LOCK))) {
2622		return (error);
2623	}
2624	np = VTOSMB(ap->a_vp);
2625	np->n_lastvop = smbfs_vnop_setattr;
2626	share = smb_get_share_with_reference(VTOSMBFS(ap->a_vp));
2627	error = smbfs_setattr (share, ap->a_vp, ap->a_vap, ap->a_context);
2628	smb_share_rele(share, ap->a_context);
2629	smbnode_unlock(VTOSMB(ap->a_vp));
2630	/* If this is a stream try to update the parents meta cache timer. */
2631	if (vnode_isnamedstream(ap->a_vp)) {
2632		vnode_t parent_vp = vnode_getparent(ap->a_vp);
2633		if (parent_vp) {
2634			VTOSMB(parent_vp)->attribute_cache_timer = 0;
2635			vnode_put(parent_vp);
2636		}
2637	}
2638	return (error);
2639}
2640
2641/*
2642 * smbfs_vnop_blockmap
2643 *
2644 * vnode_t	a_vp;
2645 * off_t	a_foffset;
2646 * uint32_t a_size;
2647 * daddr64_t *a_bpn;
2648 * uint32_t *a_run;
2649 * void *a_poff;
2650 * int32_t a_flags;
2651 */
2652static int
2653smbfs_vnop_blockmap(struct vnop_blockmap_args *ap)
2654{
2655    /*
2656	 * Always match the VM page size.  At this time it is 4K which limits us
2657	 * to 44 bit file size instead of 64...???
2658	 */
2659	/* make sure we don't go past EOF */
2660	if (ap->a_run)
2661		*ap->a_run = ap->a_size;
2662
2663	/* divide it by block size, MUST match value in smbfs_strategy */
2664    *ap->a_bpn = (daddr64_t)(ap->a_foffset / PAGE_SIZE);
2665
2666	if (ap->a_poff)
2667		*(int32_t *)ap->a_poff = 0;
2668
2669    return (0);
2670}
2671
2672/*
2673 * smbfs_vnop_strategy
2674 *
2675 *	struct buf *a_bp;
2676 */
2677static int
2678smbfs_vnop_strategy(struct vnop_strategy_args *ap)
2679{
2680	struct buf *bp = ap->a_bp;
2681	vnode_t vp = buf_vnode(bp);
2682	int32_t bflags = buf_flags(bp);
2683	struct smbnode *np = VTOSMB(vp);
2684	caddr_t io_addr = 0;
2685	uio_t	uio = NULL;
2686	int32_t error;
2687    SMBFID fid = 0;
2688	struct smb_share *share;
2689	uint32_t trycnt = 0;
2690    struct smbfattr *fap = NULL;
2691
2692	if (np->f_openState & kNeedRevoke) {
2693        /* behave like the deadfs does */
2694        SMBERROR("%s waiting to be revoked\n", np->n_name);
2695        error = EIO;
2696		buf_seterror(bp, error);
2697        goto exit;
2698    }
2699
2700    SMB_MALLOC(fap,
2701               struct smbfattr *,
2702               sizeof(struct smbfattr),
2703               M_SMBTEMP,
2704               M_WAITOK | M_ZERO);
2705    if (fap == NULL) {
2706        SMBERROR("SMB_MALLOC failed\n");
2707        error = ENOMEM;
2708        goto exit;
2709    }
2710
2711    /*
2712	 * Can't use the physical addresses passed in the vector list, so map it
2713	 * into the kernel address space
2714	 */
2715    if ((error = buf_map(bp, &io_addr))) {
2716        panic("smbfs_vnop_strategy: buf_map() failed with (%d)", error);
2717	}
2718
2719	uio = uio_create(1, ((off_t)buf_blkno(bp)) * PAGE_SIZE, UIO_SYSSPACE,
2720					 (bflags & B_READ) ? UIO_READ : UIO_WRITE);
2721	if (!uio) {
2722        panic("smbfs_vnop_strategy: uio_create() failed");
2723	}
2724
2725	uio_addiov(uio, CAST_USER_ADDR_T(io_addr), buf_count(bp));
2726	/*
2727	 * Remember that buf_proc(bp) can return NULL, but in that case this is
2728	 * coming from the kernel and is not associated with a particular proc.
2729	 * In fact it just may be the pager itself trying to free up space and there
2730	 * is no proc. I need to find any proc that already has the fork open for
2731	 * read or write to use for read/write to work. This is handled in the
2732	 * FindFileRef routine.
2733	 */
2734	if (FindFileRef(vp, buf_proc(bp), (bflags & B_READ) ? kAccessRead : kAccessWrite,
2735					kCheckDenyOrLocks, uio_offset(uio), uio_resid(uio), NULL, &fid)) {
2736		/* No matches or no pid to match, so just use the generic shared fork */
2737		fid = np->f_fid;	/* We should always have something at this point */
2738	}
2739	DBG_ASSERT(fid);
2740
2741	SMB_LOG_IO("%s: %s offset %lld, size %lld, bflags 0x%x\n",
2742			   (bflags & B_READ) ? "Read":"Write", np->n_name, uio_offset(uio),
2743			   uio_resid(uio), bflags);
2744
2745	share = smb_get_share_with_reference(VTOSMBFS(vp));
2746	/*
2747	 * Since we have already authorized the user when we opened the file, just
2748	 * pass a NULL context down to the authorization code.
2749	 */
2750	if (bflags & B_READ) {
2751		error = smbfs_doread(share, (off_t)np->n_size, uio, fid, NULL);
2752	} else {
2753		error = smbfs_dowrite(share, (off_t)np->n_size, uio, fid, 0, NULL);
2754
2755        if (!error) {
2756            /* Save last time we wrote data */
2757            nanouptime(&np->n_last_write_time);
2758        }
2759	}
2760	/*
2761	 * We can't handle reopens in the normal fashion, because we have no lock. A
2762	 * bad file descriptor error, could mean a reconnect happen. Since
2763	 * we revoke all opens with manatory locks or open deny mode, we can just
2764	 * do the open, read/write then close.
2765	 *
2766	 * We now have a counter that keeps us from going into an infinite loop. Once
2767	 * we implement SMB2 we should take a second look at how this should be done.
2768	 */
2769	while ((error == EBADF) && (trycnt < SMB_MAX_REOPEN_CNT)) {
2770		lck_mtx_lock(&np->f_openStateLock);
2771		SMB_LOG_IO("%s failed the %s, because of reconnect, openState = 0x%x. Try again.\n",
2772				   np->n_name, (bflags & B_READ) ? "READ" : "WRITE", np->f_openState);
2773
2774		if (np->f_openState & kNeedRevoke) {
2775			lck_mtx_unlock(&np->f_openStateLock);
2776			break;
2777		}
2778
2779		np->f_openState |= (kNeedReopen | kInReopen);
2780		lck_mtx_unlock(&np->f_openStateLock);
2781
2782		/* Could be a dfs share make sure we have the correct share */
2783		smb_share_rele(share, NULL);
2784		share = smb_get_share_with_reference(VTOSMBFS(vp));
2785		/* Recreate the uio */
2786		uio_free(uio);
2787		uio = uio_create(1, ((off_t)buf_blkno(bp)) * PAGE_SIZE, UIO_SYSSPACE,
2788						 (bflags & B_READ) ? UIO_READ : UIO_WRITE);
2789		if (!uio) {
2790			error = ENOMEM;
2791		} else {
2792            uio_addiov(uio, CAST_USER_ADDR_T(io_addr), buf_count(bp));
2793
2794            error = smbfs_smb_open_file(share, np,
2795                                        np->f_rights, NTCREATEX_SHARE_ACCESS_ALL, &fid,
2796                                        NULL, 0, FALSE,
2797                                        fap, NULL);
2798        }
2799
2800        lck_mtx_lock(&np->f_openStateLock);
2801        np->f_openState &= ~kInReopen;
2802        lck_mtx_unlock(&np->f_openStateLock);
2803
2804		if (error) {
2805			break;
2806		}
2807		if (bflags & B_READ) {
2808			error = smbfs_doread(share, (off_t)np->n_size, uio, fid, NULL);
2809		} else {
2810			error = smbfs_dowrite(share, (off_t)np->n_size, uio, fid, 0, NULL);
2811
2812            if (!error) {
2813                /* Save last time we wrote data */
2814                nanouptime(&np->n_last_write_time);
2815            }
2816		}
2817		(void)smbfs_smb_close(share, fid, NULL);
2818		trycnt++;
2819	}
2820
2821
2822	if (bflags & B_READ) {
2823		/*
2824		 * If we were not able to read the entire page, check to
2825		 * see if we are at the end of the file, and if so, zero
2826		 * out the remaining part of the page.
2827		 */
2828		while ((error == 0) && (uio_resid(uio))) {
2829			size_t bytes_to_zero = (uio_resid(uio) > PAGE_SIZE) ? PAGE_SIZE : (size_t)uio_resid(uio);
2830
2831			bzero((caddr_t) (io_addr + buf_count(bp) - uio_resid(uio)), bytes_to_zero);
2832			uio_update(uio, bytes_to_zero);
2833		}
2834    } else {
2835		lck_mtx_lock(&np->f_clusterWriteLock);
2836		if ((u_quad_t)uio_offset(uio) >= np->n_size) {
2837			/* We finished writing past the eof reset the flag */
2838			nanouptime(&np->n_sizetime);
2839			np->waitOnClusterWrite = FALSE;
2840			SMB_LOG_IO("%s: TURNING OFF waitOnClusterWrite np->n_size = %lld\n",
2841					   np->n_name, np->n_size);
2842		}
2843		lck_mtx_unlock(&np->f_clusterWriteLock);
2844    }
2845
2846	if (error) {
2847		SMBERROR("%s on %s failed with an error of %d\n",
2848				 (bflags & B_READ) ? "READ" : "WRITE", np->n_name, error);
2849		np->f_clusterCloseError = error;	/* Error to be returned on close */
2850
2851		if ( (error == ENOTCONN) || (error == EBADF) || (error == ETIMEDOUT) ) {
2852			/*
2853			 * VFS cluster code has now been changed to handle non transient
2854			 * errors see radar 2894150.  It should be safe to return ENXIO.
2855			 */
2856			SMB_LOG_IO("failed with %d, returning ENXIO instead\n", error);
2857			error = ENXIO;
2858		}
2859	}
2860	smb_share_rele(share, NULL);
2861    buf_seterror(bp, error);
2862
2863	/* Should be zero when all done with reading/writing file */
2864    buf_setresid(bp, (uint32_t)uio_resid(uio));
2865
2866    if ((error = buf_unmap(bp)))
2867        panic("smbfs_vnop_strategy: buf_unmap() failed with (%d)", error);
2868
2869
2870exit:
2871	if (error) {
2872		SMB_LOG_IO("%s: buf_resid(bp) %d, error = %d \n",
2873				   np->n_name, buf_resid(bp), error);
2874	}
2875
2876	if (uio != NULL)
2877		uio_free(uio);
2878
2879    buf_biodone(bp);
2880
2881    if (fap != NULL) {
2882        SMB_FREE(fap, M_SMBTEMP);
2883    }
2884
2885    return (error);
2886}
2887
2888/*
2889 * smbfs_vnop_read
2890 *
2891 *	vnode_t a_vp;
2892 *	uio_t a_uio;
2893 *	int a_ioflag;
2894 *	vfs_context_t a_context;
2895 */
2896static int
2897smbfs_vnop_read(struct vnop_read_args *ap)
2898{
2899	vnode_t vp = ap->a_vp;
2900	uio_t uio = ap->a_uio;
2901	int error = 0;
2902	struct smbnode *np = NULL;
2903    SMBFID fid = 0;
2904	struct smb_share *share;
2905
2906	/* Preflight checks */
2907	if (!vnode_isreg(vp)) {
2908		/* can only read regular files */
2909		if (vnode_isdir(vp))
2910			return (EISDIR);
2911		else
2912			return (EPERM);
2913	}
2914
2915	if (uio_resid(uio) == 0)
2916		return (0);		/* Nothing left to do */
2917
2918	if (uio_offset(uio) < 0)
2919		return (EINVAL);	/* cant read from a negative offset */
2920
2921	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_SHARED_LOCK)))
2922		return (error);
2923
2924	np = VTOSMB(vp);
2925	np->n_lastvop = smbfs_vnop_read;
2926	share = smb_get_share_with_reference(VTOSMBFS(vp));
2927	/*
2928	 * History: FreeBSD vs Darwin VFS difference; we can get VNOP_READ without
2929 	 * preceeding open via the exec path, so do it implicitly.  VNOP_INACTIVE
2930	 * closes the extra network file handle, and decrements the open count.
2931	 *
2932	 * If we are in reconnect mode calling smbfs_open will handle any reconnect
2933	 * issues. So only if we have a f_refcnt do we call smbfs_smb_reopen_file.
2934 	 */
2935 	if (!np->f_refcnt) {
2936 		error = smbfs_open(share, vp, FREAD, ap->a_context);
2937 		if (error)
2938 			goto exit;
2939		else np->f_needClose = 1;
2940 	} else {
2941		error = smbfs_smb_reopen_file(share, np, ap->a_context);
2942		if (error) {
2943			SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
2944			goto exit;
2945		}
2946	}
2947    /*
2948	 * Note: smbfs_isCacheable checks to see if the file is globally non
2949	 * cacheable, but we also need to support non cacheable on a per file
2950	 * descriptor level for reads/writes. So also check the IO_NOCACHE flag.
2951	 *
2952	 * So IO_NOCACHE means the same thing as VNOCACHE_DATA but only for this IO.
2953	 * Now VNOCACHE_DATA has the following comment:
2954	 *		"don't keep data cached once it's been consumed"
2955	 * Which seems to imply we could use cluster_read, but we would need to
2956	 * push out any data first and then invalidate the range after we are done
2957	 * with the read? Byte range locking prevents us from using the cluster_read.
2958	 */
2959	if ( smbfsIsCacheable(vp) && !(ap->a_ioflag & IO_NOCACHE)) {
2960 		error = cluster_read(vp, uio, (off_t) np->n_size, ap->a_ioflag);
2961		if (error) {
2962			SMB_LOG_IO("%s failed cluster_read with an error of %d\n",
2963					   np->n_name, error);
2964		}
2965		/*
2966		 * EACCES means a denyConflict occured and must have hit some other
2967		 * computer's byte range lock on that file. Mark the file as
2968		 * noncacheable and retry read again
2969		 *
2970		 * Need to check the error here, could be EIO/EPERM
2971		 *
2972		 * XXX - NOTE: The strategy routine is going to mark this vnode as needing
2973		 * to be revoked. So this code seems wrong. We should either correct
2974		 * the strategy routine or remove this code.
2975		 */
2976		if (error == EACCES) {
2977			if (np->n_flag & NISMAPPED) {
2978				/* More expensive, but handles mmapped files */
2979				ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
2980			} else {
2981				/* Less expensive, but does not handle mmapped files */
2982				cluster_push(vp, IO_SYNC);
2983			}
2984			ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_INVALIDATE);
2985			vnode_setnocache(vp);
2986			/* Fall through and try a non cached read */
2987			error = 0;
2988 		} else {
2989			goto exit;
2990		}
2991    }
2992	if (error)
2993		goto exit;
2994	/*
2995	 * AFP COMMENTS (<rdar://problem/5977339>) Be careful of a cacheable write
2996	 * that extends the eof, but leaves a hole between the old eof and the new
2997	 * eof.  It that is followed by a non cacheable read that starts before the
2998	 * old eof and extends into the hole (or starts in the hole), but does not
2999	 * extend past the hole, then msync for the read range will not find any
3000	 * dirty pages in the hole and thus no data will be pushed and thus the eof
3001	 * will not get extended which will cause the non cacheable read to get
3002	 * erroneous data.  cluster_push works around this  because it pushes all of
3003	 * the pages in the delayed clusters. msync for the entire range also works
3004	 * too.
3005	 */
3006	if (VTOSMB(vp)->n_flag & NISMAPPED) {
3007		/* More expensive, but handles mmapped files */
3008		ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
3009	} else {
3010		/* Less expensive, but does not handle mmapped files */
3011		cluster_push(vp, IO_SYNC);
3012	}
3013	/*
3014	 * AFP doesn't invalidate the range here. That seems wrong, we should
3015	 * invalidate the range here.
3016	 */
3017	ubc_msync (vp, uio_offset(uio), uio_offset(uio)+ uio_resid(uio), NULL,
3018			   UBC_INVALIDATE);
3019
3020	if (FindFileRef(vp, vfs_context_proc(ap->a_context), kAccessRead,
3021					kCheckDenyOrLocks, uio_offset(uio), uio_resid(uio),
3022					NULL, &fid)) {
3023		/* No matches or no pid to match, so just use the generic shared fork */
3024		fid = np->f_fid;	/* We should always have something at this point */
3025	}
3026	DBG_ASSERT(fid);
3027
3028	error = smbfs_doread(share, (off_t)np->n_size, uio, fid, ap->a_context);
3029	/*
3030	 * We got an error, did it happen on a reconnect, then retry. First see if
3031	 * we have a new share to use, then attmept to reopent the file, then try
3032	 * the read again.
3033	 */
3034	while (error == EBADF) {
3035		SMB_LOG_IO("%s failed the non cache read, because of reconnect. Try again.\n",
3036				   np->n_name);
3037		/* Could be a dfs share make sure we have the correct share */
3038		smb_share_rele(share, ap->a_context);
3039		share = smb_get_share_with_reference(VTOSMBFS(vp));
3040		/* The reopen code will handle the case of the node being revoked. */
3041		if (smbfs_io_reopen(share, vp, uio, kAccessRead, &fid, error, ap->a_context) == 0) {
3042			error = smbfs_doread(share, (off_t)np->n_size, uio, fid,
3043                                 ap->a_context);
3044		} else {
3045			SMB_LOG_IO("%s : The Read reopen failed.\n", np->n_name);
3046			break;
3047		}
3048	}
3049
3050	if (error) {
3051		SMB_LOG_IO("%s failed non cached read with an error of %d\n", np->n_name, error);
3052	}
3053
3054exit:
3055	smb_share_rele(share, ap->a_context);
3056	smbnode_unlock(np);
3057	return (error);
3058}
3059
3060/*
3061 * smbfs_vnop_write
3062 *
3063 *	vnode_t a_vp;
3064 *	uio_t a_uio;
3065 *	int a_ioflag;
3066 *	vfs_context_t a_context;
3067 */
3068static int
3069smbfs_vnop_write(struct vnop_write_args *ap)
3070{
3071	vnode_t vp = ap->a_vp;
3072	vnode_t parent_vp = NULL;	/* Always null unless this is a stream node */
3073	struct smbnode *np = NULL;
3074	struct smb_share *share;
3075	uio_t uio = ap->a_uio;
3076	int error = 0;
3077    SMBFID fid = 0;
3078	u_quad_t originalEOF;
3079	user_size_t writeCount;
3080
3081	/* Preflight checks */
3082	if (!vnode_isreg(vp)) {
3083		/* can only read regular files */
3084		if (vnode_isdir(vp))
3085			return (EISDIR);
3086		else
3087			return (EPERM);
3088	}
3089
3090	if (uio_offset(uio) < 0)
3091		return (EINVAL);
3092
3093	if (uio_resid(uio) == 0)
3094		return (0);
3095
3096	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
3097		return (error);
3098
3099	np = VTOSMB(vp);
3100	np->n_lastvop = smbfs_vnop_write;
3101	share = smb_get_share_with_reference(VTOSMBFS(vp));
3102
3103	/* Before trying the write see if the file needs to be reopened */
3104	error = smbfs_smb_reopen_file(share, np, ap->a_context);
3105	if (error) {
3106		SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
3107		goto exit;
3108	}
3109
3110	if (ap->a_ioflag & IO_APPEND)
3111		uio_setoffset(uio, np->n_size);
3112
3113	originalEOF = np->n_size;	/* Save off the orignial end of file */
3114
3115    /*
3116	 * Note: smbfs_isCacheable checks to see if the file is globally non
3117	 * cacheable, but we also need to support non cacheable on a per file
3118	 * descriptor level for reads/writes. So also check the IO_NOCACHE flag.
3119	 *
3120	 * So IO_NOCACHE means the same thing as VNOCACHE_DATA but only for this IO.
3121	 * Now VNOCACHE_DATA has the following comment:
3122	 *		"don't keep data cached once it's been consumed"
3123	 * Which seems to imply we could use cluster_write, but we would need to
3124	 * push out any data and then invalidate the range after we are done
3125	 * with the write? Byte range locking prevents us from using the cluster_write.
3126	 */
3127	if (smbfsIsCacheable(vp) && !(ap->a_ioflag & IO_NOCACHE)) {
3128		u_quad_t writelimit;
3129        u_quad_t newEOF;
3130        u_quad_t zero_head_off;
3131        u_quad_t zero_tail_off;
3132        int32_t   lflag;
3133
3134		lflag = ap->a_ioflag & ~(IO_TAILZEROFILL | IO_HEADZEROFILL |
3135								 IO_NOZEROVALID | IO_NOZERODIRTY);
3136		zero_head_off = 0;
3137		zero_tail_off = 0;
3138		writelimit = uio_offset(uio) + uio_resid(uio);
3139
3140		/*
3141		 * They are writing pass the eof, force a zero fill. What should we
3142		 * do for sparse files?
3143		 */
3144        if ((uint64_t)writelimit > np->n_size) {
3145			/* Save off the new eof */
3146            newEOF = writelimit;
3147            if ((uint64_t) uio_offset(uio) > np->n_size) {
3148                zero_head_off = np->n_size;
3149				/* Make sure we tell the kernel to zero fill the head */
3150                lflag |= IO_HEADZEROFILL;
3151            }
3152  			zero_tail_off = (writelimit + (PAGE_SIZE_64 - 1)) & ~PAGE_MASK_64;
3153			if (zero_tail_off > newEOF) {
3154				zero_tail_off = newEOF;
3155			}
3156			if (zero_tail_off > writelimit) {
3157				/* Make sure we tell the kernel to zero fill the tail */
3158				lflag |= IO_TAILZEROFILL;
3159			}
3160        } else
3161            newEOF = np->n_size;
3162
3163		lck_mtx_lock(&np->f_clusterWriteLock);
3164		if (originalEOF < newEOF) {
3165			np->waitOnClusterWrite = TRUE;
3166			np->n_size = newEOF;
3167			SMB_LOG_IO("%s: TURNING ON waitOnClusterWrite old eof = %lld new eof = %lld\n",
3168					   np->n_name, originalEOF, newEOF);
3169		}
3170		lck_mtx_unlock(&np->f_clusterWriteLock);
3171		/*
3172         * If the write starts beyond the current EOF then we we'll zero fill
3173		 * from the current EOF to where the write begins
3174         */
3175        error = cluster_write(vp, uio, originalEOF, newEOF, zero_head_off, zero_tail_off, lflag);
3176		if (error) {
3177			lck_mtx_lock(&np->f_clusterWriteLock);
3178			np->n_size = originalEOF; /* Set it back to the original eof */
3179			np->waitOnClusterWrite = FALSE;
3180			lck_mtx_unlock(&np->f_clusterWriteLock);
3181			SMB_LOG_IO("%s failed cluster_write with an error of %d\n", np->n_name, error);
3182		}
3183		/*
3184		 * EACCES means a denyConflict occured and must have hit some other
3185		 * computer's byte range lock on that file. Mark the file as
3186		 * noncacheable and retry read again
3187		 *
3188		 * Need to check the error here, could be EIO/EPERM
3189		 *
3190		 * XXX - NOTE: The stragey routine is going to mark this vnode as needing
3191		 * to be revokd. So this code seems wrong. We should either correct
3192		 * the stragey routine or remove this code.
3193		 */
3194		if (error == EACCES) {
3195			if (np->n_flag & NISMAPPED) {
3196				/* More expensive, but handles mmapped files */
3197				ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
3198			} else {
3199				/* Less expensive, but does not handle mmapped files */
3200				cluster_push(vp, IO_SYNC);
3201			}
3202			ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_INVALIDATE);
3203			vnode_setnocache(vp);
3204			/* Fall through and try a non cached write */
3205			error = 0;
3206 		} else {
3207			goto exit;
3208		}
3209    }
3210	if (error)
3211		goto exit;
3212    /*
3213	 * If it is not cacheable, make sure to wipe out UBC since any of its
3214	 * data would be no be invalid.  Make sure to push out any dirty data
3215	 * first due to prev cached write.
3216	 */
3217	ubc_msync(vp, uio_offset(uio), uio_offset(uio)+ uio_resid(uio), NULL,
3218			   UBC_PUSHDIRTY | UBC_SYNC);
3219	ubc_msync(vp, uio_offset(uio), uio_offset(uio)+ uio_resid(uio), NULL,
3220			   UBC_INVALIDATE);
3221
3222
3223	if (FindFileRef(vp, vfs_context_proc(ap->a_context), kAccessWrite,
3224					kCheckDenyOrLocks, uio_offset(uio), uio_resid(uio), NULL, &fid)) {
3225		/* No matches or no pid to match, so just use the generic shared fork */
3226		fid = np->f_fid;	/* We should always have something at this point */
3227	}
3228	DBG_ASSERT(fid);
3229
3230	/* Total amount that we need to write */
3231	writeCount = uio_resid(ap->a_uio);
3232	do {
3233		if (uio && (uio != ap->a_uio)) {
3234			/* We allocated, need to free it */
3235			uio_free(uio);
3236		}
3237		/*
3238		 * We could get disconnected in the middle of a write, so we need to make
3239		 * a copy of the uio, just in case.
3240		 */
3241		uio = uio_duplicate(ap->a_uio);
3242		if (uio == NULL) {
3243			/* Failed, so just used the passed in uio */
3244			uio = ap->a_uio;
3245		}
3246		error = smbfs_dowrite(share, (off_t)np->n_size, uio, fid, ap->a_ioflag,
3247							  ap->a_context);
3248        if (!error) {
3249            /* Save last time we wrote data */
3250            nanouptime(&np->n_last_write_time);
3251        }
3252
3253		if (error == EBADF) {
3254			/* Could be a dfs share make sure we have the correct share */
3255			smb_share_rele(share, ap->a_context);
3256			share = smb_get_share_with_reference(VTOSMBFS(vp));
3257			if (smbfs_io_reopen(share, vp, uio, kAccessWrite, &fid,  error,
3258								ap->a_context) != 0) {
3259				/* The reopen failed, just get out nothing left to do here */
3260				break;
3261			}
3262		}
3263	} while ((error == EBADF) && (uio != ap->a_uio));
3264	/* Set the original uio to match the one passed into the write. */
3265	if (uio != ap->a_uio) {
3266		/* Total amount we were able to write */
3267		writeCount -= uio_resid(uio);
3268		/* Update the user's uio with that amount */
3269		uio_update( ap->a_uio, writeCount);
3270		uio_free(uio);
3271		uio = ap->a_uio;
3272	}
3273
3274	/*
3275	 * Mark that we need to send a flush if we didn't get an error and
3276	 * we didn't send a write though message. Remember if the IO_SYNC bit
3277	 * is set then we set the write though bit, which should do the same
3278	 * thing as a flush.
3279	 */
3280	if (!error && !(ap->a_ioflag & IO_SYNC)) {
3281		VTOSMB(vp)->n_flag |= NNEEDS_FLUSH;
3282	} else if (error) {
3283		SMB_LOG_IO("%s failed non cached write with an error of %d\n",
3284				   np->n_name, error);
3285	}
3286exit:
3287	/* Wrote pass the eof, need to set the new file size */
3288	if (!error && ((uint64_t) uio_offset(uio) > originalEOF)) {
3289		/*
3290		 * Windows servers do not handle writing past the end of file the
3291		 * same as Unix servers. If we do a directory lookup before the file
3292		 * is closed then the server may return the old size. Setting the end of
3293		 * file here will prevent that from happening. Unix servers do not seem
3294		 * to have this problem so there is no reason to make this call in that
3295		 * case. So if the file size has changed and this is not a Unix server
3296		 * then set the eof of file to the new value.
3297		 */
3298		if (!UNIX_SERVER(SSTOVC(share))) {
3299            /*
3300             * Just set the flag to set EOF later. Otherwise for every write
3301             * on a cached file, a set EOF request will be sent to the server.
3302             * This will result in hundreds/thousands of set EOF requests being
3303             * sent constantly to the server.
3304             *
3305             * The file size is cached locally so sending the set EOF request
3306             * to the server can wait until system sync or vnop_sync time.
3307             */
3308            np->n_flag |= NNEEDS_EOF_SET;
3309
3310            /*
3311             * Windows FAT file systems require a flush, after a seteof. Until the
3312             * the flush they will keep returning the old file size.
3313             */
3314            if (share->ss_fstype == SMB_FS_FAT) {
3315                /* Do the flush later too */
3316                np->n_flag |= NNEEDS_FLUSH;
3317
3318            }
3319		}
3320
3321		smbfs_setsize(vp, uio_offset(uio));
3322		SMB_LOG_IO("%s: Calling smbfs_setsize, old eof = %lld  new eof = %lld time %ld:%ld\n",
3323				   np->n_name, originalEOF, uio_offset(uio),
3324				   np->n_sizetime.tv_sec, np->n_sizetime.tv_nsec);
3325		/*
3326		 * We could have lost a cache update in the write. Since we wrote pass
3327		 * the eof, mark that the close should clear the cache timer. This way
3328		 * the cache will be update with the server. We clear this flag in cache
3329		 * entry so any lookups after this write will clear the flag.
3330		 */
3331		np->n_flag |= NATTRCHANGED;
3332	}
3333
3334	/* Tell the stream's parent that something has changed */
3335	if (vnode_isnamedstream(vp))
3336		parent_vp = smb_update_rsrc_and_getparent(vp, FALSE);
3337
3338	smb_share_rele(share, ap->a_context);
3339	smbnode_unlock(VTOSMB(vp));
3340	/* We have the parent vnode, so reset its meta data cache timer. */
3341	if (parent_vp) {
3342		VTOSMB(parent_vp)->attribute_cache_timer = 0;
3343		vnode_put(parent_vp);
3344	}
3345
3346	return (error);
3347}
3348
3349/*
3350 * This is an internal utility function called from our smbfs_mkdir and
3351 * smbfs_create to set the vnode_attr passed into those routines. The first
3352 * problem comes from the vfs layer. It wants to set things that the server will
3353 * set for us. So to stop taking a performance hit turn off those items that vfs
3354 * turn on. See vnode_authattr_new for what is getting set. Second there is a set
3355 * of items that we can't set anyways so clear them out and pretend we did it.
3356 * Third if they are setting ACLs then make sure we keep any inherited ACLs.
3357 *
3358 * Question should we ever error out in this routine? The old code never did, but
3359 * what if setting the mode, owner, group, or acl fails?
3360 *
3361 * The calling routine must hold a reference on the share
3362 *
3363 */
3364static void
3365smbfs_set_create_vap(struct smb_share *share, struct vnode_attr *vap, vnode_t vp,
3366					 vfs_context_t context, int set_mode_now)
3367{
3368	struct smbnode *np = VTOSMB(vp);
3369	struct smbmount *smp = np->n_mount;
3370	struct vnode_attr svrva;
3371	kauth_acl_t savedacl = NULL;
3372	int error;
3373    int has_posix_modes = ((UNIX_CAPS(share) & UNIX_QFILEINFO_UNIX_INFO2_CAP)) ? TRUE : FALSE;;
3374
3375    if ((!has_posix_modes) &&
3376        (SSTOVC(share)->vc_server_caps & kAAPL_SUPPORTS_NFS_ACE)) {
3377        /*
3378         * For OS X <-> OS X PFS (where ACLs are off by default), we
3379         * need a way to set Posix permissions. If the server supports
3380         * the NFS ACE, then it will allow us to get the ACL and send
3381         * it back with the desired Posix permissions in the NFS ACE.
3382         */
3383        has_posix_modes = TRUE;
3384    }
3385
3386	/*
3387	 * Initialize here so we know if it needs to be freed at the end. Also
3388	 * ask for everything since its the same performance hit and updates our
3389	 * nodes uid/gid cache. The following are not used unless the user is
3390	 * setting ACLs.
3391	 */
3392	VATTR_INIT(&svrva);
3393	VATTR_WANTED(&svrva, va_acl);
3394	VATTR_WANTED(&svrva, va_uuuid);
3395	VATTR_WANTED(&svrva, va_guuid);
3396
3397	/*
3398	 * This will be zero if vnode_authattr_new set it. Do not change
3399	 * this on create, the default is fine.
3400	 */
3401	if (VATTR_IS_ACTIVE(vap, va_flags) && (vap->va_flags == 0)) {
3402		VATTR_SET_SUPPORTED(vap, va_flags);
3403		VATTR_CLEAR_ACTIVE(vap, va_flags);
3404	}
3405	/* The server will set all times for us */
3406	if (VATTR_IS_ACTIVE(vap, va_create_time)) {
3407		VATTR_SET_SUPPORTED(vap, va_create_time);
3408		VATTR_CLEAR_ACTIVE(vap, va_create_time);
3409	}
3410	if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
3411		VATTR_SET_SUPPORTED(vap, va_modify_time);
3412		VATTR_CLEAR_ACTIVE(vap, va_modify_time);
3413	}
3414	if (VATTR_IS_ACTIVE(vap, va_access_time)) {
3415		VATTR_CLEAR_ACTIVE(vap, va_access_time);
3416		VATTR_SET_SUPPORTED(vap, va_access_time);
3417	}
3418	if (VATTR_IS_ACTIVE(vap, va_change_time)) {
3419		VATTR_CLEAR_ACTIVE(vap, va_change_time);
3420		VATTR_SET_SUPPORTED(vap, va_change_time);
3421	}
3422
3423	if (VATTR_IS_ACTIVE(vap, va_mode)) {
3424		if (set_mode_now == TRUE) {
3425			/* compound_vnop_open already has the file open so we can set the
3426			 Posix file modes if server supports Posix perms and reg file */
3427			VATTR_SET_SUPPORTED(vap, va_mode);
3428
3429			if ( !vnode_isreg(vp) || !has_posix_modes ) {
3430				VATTR_CLEAR_ACTIVE(vap, va_mode);
3431			}
3432		}
3433        else {
3434			/*
3435			 * This routine gets called from create. If this is a regular file they
3436			 * could be setting the posix file modes to something that doesn't allow
3437			 * them to open the file with the permissions they requested.
3438			 *		Example: open(path, O_WRONLY | O_CREAT | O_EXCL,  0400)
3439			 * We only care about this if the server supports setting/getting posix
3440			 * permissions. So if they are setting the owner with read/write access
3441			 * then save the settings until after the open. We will just pretend to
3442			 * set them here. The following radar will make this a mute point.
3443			 *
3444			 * <rdar://problem/5199099> Need a new VNOP_OPEN call that allows the
3445			 * create/lookup/open/access in one call
3446			 */
3447			if (vnode_isreg(vp) && has_posix_modes &&
3448				((vap->va_mode & (S_IRUSR | S_IWUSR)) != (S_IRUSR | S_IWUSR))) {
3449				np->create_va_mode = vap->va_mode;
3450				np->set_create_va_mode = TRUE;
3451				/* The server should always give us read/write on create */
3452				VATTR_SET_SUPPORTED(vap, va_mode);
3453				VATTR_CLEAR_ACTIVE(vap, va_mode);
3454			} else if (!has_posix_modes) {
3455				/* We can only set these if the server supports the unix extensions */
3456				VATTR_SET_SUPPORTED(vap, va_mode);
3457				VATTR_CLEAR_ACTIVE(vap, va_mode);
3458			}
3459		}
3460	}
3461
3462	/*
3463	 * We have never supported setting the uid, this is supported by the
3464	 * UNIX extensions and for other servers we could convert it using
3465	 * uid --> UUID --> SID translation. This just seems like a waste of
3466	 * time since they would only be able to set it to themself if they
3467	 * are already the owner. So just say we did, this is what we have
3468	 * always done.
3469	 */
3470	if (VATTR_IS_ACTIVE(vap, va_uid)) {
3471		VATTR_SET_SUPPORTED(vap, va_uid);
3472		VATTR_CLEAR_ACTIVE(vap, va_uid);
3473	}
3474
3475	/*
3476	 * We have never supported setting the gid, this is supported by the
3477	 * UNIX extensions and for other servers we could convert it using
3478	 * gid --> GUID --> SID translation. We may want to add the support
3479	 * in the future, but we should require that they do this by setting
3480	 * the va_guuid.
3481	 */
3482	if (VATTR_IS_ACTIVE(vap, va_gid)) {
3483		VATTR_SET_SUPPORTED(vap, va_gid);
3484		VATTR_CLEAR_ACTIVE(vap, va_gid);
3485		if (vap->va_gid != smp->sm_args.gid)
3486			SMB_LOG_ACCESS("They want to set the gid to %d from %d\n",
3487						   vap->va_gid, smp->sm_args.gid);
3488	}
3489
3490	/*
3491	 * If they have an ACE that allows them to take ownership then
3492	 * this call will work. Should we test to see before going any
3493	 * future.
3494	 */
3495	if (VATTR_IS_ACTIVE(vap, va_uuuid)) {
3496		VATTR_SET_SUPPORTED(vap, va_uuuid);
3497		/* We never let them set it if a  TEMP UUID */
3498		if (is_memberd_tempuuid(&vap->va_uuuid))
3499			VATTR_CLEAR_ACTIVE(vap, va_uuuid);
3500	}
3501
3502	/*
3503	 * If they have an ACE that allows them to make this change then
3504	 * this call will work. Should we test to see before going any
3505	 * future.
3506	 */
3507	if (VATTR_IS_ACTIVE(vap, va_guuid)) {
3508		VATTR_SET_SUPPORTED(vap, va_guuid);
3509		/* We never let them set it if a  TEMP UUID */
3510		if (is_memberd_tempuuid(&vap->va_guuid))
3511			VATTR_CLEAR_ACTIVE(vap, va_guuid);
3512	}
3513
3514	/*
3515	 * Make sure the VFS layer doesn't fall back to using EA, always say we set
3516	 * the ACL.
3517	 */
3518	if (VATTR_IS_ACTIVE(vap, va_acl)) {
3519		VATTR_SET_SUPPORTED(vap, va_acl);
3520		/* Nothing for us to do here */
3521		if ((vap->va_acl == NULL) || (vap->va_acl->acl_entrycount == 0))
3522			VATTR_CLEAR_ACTIVE(vap, va_acl);
3523	}
3524
3525	/* All we have left to do is call our setattr */
3526	if (!VATTR_IS_ACTIVE(vap, va_acl))
3527		goto do_setattr;
3528
3529	/* Get the inherited ACLs from the server */
3530	error = smbfs_getattr(share, vp, &svrva, context);
3531	if (error) {
3532		SMBWARNING("Error %d returned while gettting the inherit ACLs from the server\n",
3533				   error);
3534		goto out;
3535	}
3536
3537	/*
3538	 * if none created then just slam in the requested ACEs
3539	 */
3540	if (!VATTR_IS_SUPPORTED(&svrva, va_acl) || svrva.va_acl == NULL ||
3541	    svrva.va_acl->acl_entrycount == 0) {
3542		goto do_setattr;
3543	}
3544	error = smbfs_compose_create_acl(vap, &svrva, &savedacl);
3545	if (error)
3546		goto out;
3547
3548do_setattr:
3549	error = smbfs_setattr(share, vp, vap, context);
3550	if (error)
3551		SMBERROR("smbfs_setattr, error %d\n", error);
3552	if (savedacl) {
3553		kauth_acl_free(vap->va_acl);
3554		vap->va_acl = savedacl;
3555	}
3556out:
3557	if (VATTR_IS_SUPPORTED(&svrva, va_acl) && svrva.va_acl != NULL)
3558		kauth_acl_free(svrva.va_acl);
3559	return;
3560}
3561
3562/*
3563 * Create a regular file or a "symlink". In the symlink case we will have a target. Depending
3564 * on the sytle of symlink the target may be just what we set or we may need to encode it into
3565 * that wacky windows data
3566 *
3567 * The calling routine must hold a reference on the share
3568 *
3569 */
3570static int
3571smbfs_create(struct smb_share *share, struct vnop_create_args *ap, char *target,
3572			 size_t targetlen)
3573{
3574	vnode_t				dvp = ap->a_dvp;
3575	struct vnode_attr *vap = ap->a_vap;
3576	vnode_t			*vpp = ap->a_vpp;
3577	struct componentname *cnp = ap->a_cnp;
3578	struct smbnode *dnp = VTOSMB(dvp);
3579	struct smbmount *smp = VTOSMBFS(dvp);
3580	vnode_t 	vp;
3581	struct smbfattr fattr;
3582	const char *name = cnp->cn_nameptr;
3583	size_t nmlen = cnp->cn_namelen;
3584	int error;
3585	struct timespec ts;
3586	int unix_symlink = ((UNIX_CAPS(share) & UNIX_SFILEINFO_UNIX_LINK_CAP)) ? TRUE : FALSE;
3587
3588	*vpp = NULL;
3589	if (vap->va_type != VREG && vap->va_type != VLNK)
3590		return (ENOTSUP);
3591
3592	if (vap->va_type == VLNK) {
3593        if (smp->sm_flags & MNT_SUPPORTS_REPARSE_SYMLINKS) {
3594			error = smbfs_smb_create_reparse_symlink(share, dnp, name, nmlen, target,
3595                                                     targetlen, &fattr, ap->a_context);
3596		} else if (unix_symlink) {
3597			error = smbfs_smb_create_unix_symlink(share, dnp, name, nmlen, target,
3598												  targetlen, &fattr, ap->a_context);
3599		} else {
3600			error = smbfs_smb_create_windows_symlink(share, dnp, name, nmlen, target,
3601												  targetlen, &fattr, ap->a_context);
3602		}
3603	} else {
3604		/* Now create the file, sending a null fid pointer will cause it to be closed */
3605		error = smbfs_smb_create(share, dnp, name, nmlen, SMB2_FILE_WRITE_DATA,
3606								 NULL, FILE_CREATE, 0, &fattr, ap->a_context);
3607	}
3608	if (error) {
3609		if (error == ENOENT) {
3610			SMBDEBUG("Creating %s returned ENOENT, resetting to EACCES\n", name);
3611			/*
3612			 * Some servers (Samba) support an option called veto. This prevents
3613			 * clients from creating or access these files. The server returns
3614			 * an ENOENT error in these cases. The VFS layer will loop forever
3615			 * if a ENOENT error is returned on create, so we convert this error
3616			 * to EACCES.
3617			 */
3618			error = EACCES;
3619		}
3620		return (error);
3621	}
3622	smbfs_attr_touchdir(dnp, (share->ss_fstype == SMB_FS_FAT));
3623	/*
3624	 * We have smbfs_nget returning a lock so we need to unlock it when we
3625	 * are done with it. Would really like to clean this code up in the future.
3626	 * The whole create, mkdir and smblink create code should use the same code path.
3627	 */
3628	fattr.fa_vtype = vap->va_type;
3629	error = smbfs_nget(share, vnode_mount(dvp),
3630                       dvp, name, nmlen,
3631                       &fattr, &vp,
3632                       cnp->cn_flags, SMBFS_NGET_CREATE_VNODE,
3633                       ap->a_context);
3634	if (error) {
3635		/* Error, try to cleanup anything we created on the server */
3636		smbfs_smb_delete(share, dnp, name, nmlen, 0, ap->a_context);
3637		goto bad;
3638	}
3639
3640	/*
3641	 * We just created the file, so we have no finder info and the resource fork
3642	 * should be empty. So set our cache timers to reflect this information
3643	 */
3644	nanouptime(&ts);
3645	VTOSMB(vp)->finfo_cache = ts.tv_sec;
3646	VTOSMB(vp)->rfrk_cache_timer = ts.tv_sec;
3647
3648	smbfs_set_create_vap(share, vap, vp, ap->a_context, FALSE);
3649
3650	if (vap->va_type == VLNK) {
3651		smbfs_update_symlink_cache(VTOSMB(vp), target, targetlen);
3652		VTOSMB(vp)->n_size = targetlen;	/* Set it to the correct size */
3653		if (!unix_symlink)	/* Mark it as a Windows symlink */
3654			VTOSMB(vp)->n_flag |= NWINDOWSYMLNK;
3655	}
3656	*vpp = vp;
3657	smbnode_unlock(VTOSMB(vp));	/* Done with the smbnode unlock it. */
3658
3659    dnp->d_changecnt++;
3660
3661	/* Remove any negative cache entries. */
3662	if (dnp->n_flag & NNEGNCENTRIES) {
3663		dnp->n_flag &= ~NNEGNCENTRIES;
3664		cache_purge_negatives(dvp);
3665	}
3666
3667bad:
3668	/* if success, blow away statfs cache */
3669	if (!error)
3670		smp->sm_statfstime = 0;
3671	return (error);
3672}
3673
3674/*
3675 * smbfs_vnop_create
3676 *
3677 * vnode_t a_dvp;
3678 * vnode_t *a_vpp;
3679 * struct componentname *a_cnp;
3680 * struct vnode_attr *a_vap;
3681 * vfs_context_t a_context;
3682 */
3683static int
3684smbfs_vnop_create(struct vnop_create_args *ap)
3685{
3686	vnode_t 	dvp = ap->a_dvp;
3687	int			error;
3688	struct smbnode *dnp;
3689	struct smb_share *share;
3690
3691		/* Make sure we lock the parent before calling smbfs_create */
3692	if ((error = smbnode_lock(VTOSMB(dvp), SMBFS_EXCLUSIVE_LOCK)))
3693		return (error);
3694
3695	dnp = VTOSMB(dvp);
3696	dnp->n_lastvop = smbfs_vnop_create;
3697	share = smb_get_share_with_reference(VTOSMBFS(dvp));
3698
3699	error = smbfs_create(share, ap, NULL, 0);
3700
3701	smb_share_rele(share, ap->a_context);
3702	smbnode_unlock(dnp);
3703	return (error);
3704}
3705
3706/*
3707 * The calling routine must hold a reference on the share
3708 */
3709static int
3710smbfs_remove(struct smb_share *share, vnode_t dvp, vnode_t vp,
3711			 struct componentname *cnp, int flags, vfs_context_t context)
3712{
3713#pragma unused(cnp)
3714	struct smbnode *dnp = VTOSMB(dvp);
3715	proc_t p = vfs_context_proc(context);
3716	struct smbnode *np = VTOSMB(vp);
3717	struct smbmount *smp = VTOSMBFS(vp);
3718	int error;
3719    uint64_t hashval = 0;
3720
3721	DBG_ASSERT((!vnode_isnamedstream(vp)))
3722	cache_purge(vp);
3723
3724	/*
3725	 * Carbon semantics prohibit deleting busy files.
3726	 * (enforced when NODELETEBUSY is requested) We just return
3727	 * EBUSY here. Do not print an error to system log in this
3728	 * case.
3729	 *
3730	 * NOTE: Kqueue opens will not be found by vnode_isinuse
3731	 */
3732	if (flags & VNODE_REMOVE_NODELETEBUSY) {
3733        if (vnode_isinuse(vp, 0)) {
3734            return (EBUSY); /* Do not print an error in this case */
3735        } else {
3736            /* Check if any streams associated with this vnode are opened */
3737            vnode_t svpp = smbfs_find_vgetstrm(smp, np, SFM_RESOURCEFORK_NAME,
3738                                               share->ss_maxfilenamelen);
3739            if (svpp) {
3740                if (vnode_isinuse(svpp, 0)) {
3741                    /*
3742                     *  This vnode has an opened stream associated with it,
3743                     *  we still need to return EBUSY here.
3744                     *  See <rdar://problem/9904683>
3745                     */
3746                    smbnode_unlock(VTOSMB(svpp));
3747                    vnode_put(svpp);
3748                    SMBDEBUG("%s: Cannot delete %s, resource fork in use\n", __FUNCTION__, vnode_getname(vp));
3749                    return (EBUSY);  /* Do not print an error in this case */
3750                } else {
3751                    smbnode_unlock(VTOSMB(svpp));
3752                    vnode_put(svpp);
3753                }
3754            }
3755        }
3756    }
3757
3758	/*
3759	 * Did we open this in our read routine. Then we should close it.
3760	 */
3761	if ((np->f_refcnt == 1) && np->f_needClose) {
3762		error = smbfs_close(share, vp, FREAD, context);
3763		if (error)
3764			SMBWARNING("error %d closing %s\n", error, np->n_name);
3765	}
3766
3767    /*
3768     * The old code would check vnode_isinuse to see if the file was open,
3769     * but if the file was open by Kqueue then vnode_isinuse will not find it.
3770     * So at this point if the file is open then do the silly rename delete
3771     * trick if the server supports it.
3772     */
3773    if (np->f_refcnt) {
3774        error = smbfs_delete_openfile(share, dnp, np, context);
3775        if (!error) {
3776            /* skip doing the vnode_recycle as file may still be on server */
3777            return(0);
3778        }
3779
3780        goto out;
3781    }
3782
3783    /*
3784     * NetApp and Samba servers will reuse the File ID immediately after a
3785     * delete, so remove the smb node from the hash table before doing the
3786     * delete. If the delete fails, then we know the File ID is still valid
3787     * and it should be ok to reinsert the smbnode.
3788     */
3789    smb_vhashrem(np);
3790
3791	error = smbfs_smb_delete(share, np, NULL, 0, 0, context);
3792	if (error) {
3793        /*
3794         * Delete failed, add smbnode back into hash table.
3795         * Then leave as there is nothing else we can do at this point
3796         */
3797        hashval = smbfs_hash(share, np->n_ino, np->n_name, np->n_nmlen);
3798        smb_vhashadd(np, hashval);
3799
3800        goto out;
3801    }
3802
3803    smbfs_attr_touchdir(dnp, (share->ss_fstype == SMB_FS_FAT));
3804    dnp->d_changecnt++;
3805
3806	/* Remove any negative cache entries. */
3807	if (dnp->n_flag & NNEGNCENTRIES) {
3808		dnp->n_flag &= ~NNEGNCENTRIES;
3809		cache_purge_negatives(dvp);
3810	}
3811
3812out:
3813	if (error == EBUSY) {
3814		char errbuf[32];
3815
3816		(void)proc_name(proc_pid(p), &errbuf[0], 32);
3817		SMBWARNING("warning: pid %d(%.*s) unlink open file(%s)\n", proc_pid(p),
3818				   32, &errbuf[0], np->n_name);
3819	}
3820
3821	if (!error) {
3822		/* Not sure why we do this here. Leave it for now. */
3823		(void) vnode_recycle(vp);
3824		/* if success, blow away statfs cache */
3825		smp->sm_statfstime = 0;
3826	}
3827
3828	return (error);
3829}
3830
3831/*
3832 * smbfs_vnop_remove
3833 *
3834 * vnode_t a_dvp;
3835 * vnode_t a_vp;
3836 * struct componentname *a_cnp;
3837 * int a_flags;
3838 * vfs_context_t a_context;
3839 */
3840static int
3841smbfs_vnop_remove(struct vnop_remove_args *ap)
3842{
3843	vnode_t dvp = ap->a_dvp;
3844	vnode_t vp = ap->a_vp;
3845	int32_t error;
3846	struct smb_share *share;
3847
3848	if (dvp == vp)
3849		return (EINVAL);
3850
3851	/* Always put in the order of parent then child */
3852	if ((error = smbnode_lockpair(VTOSMB(dvp), VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
3853		return (error);
3854
3855	VTOSMB(dvp)->n_lastvop = smbfs_vnop_remove;
3856	VTOSMB(vp)->n_lastvop = smbfs_vnop_remove;
3857	share = smb_get_share_with_reference(VTOSMBFS(dvp));
3858	error = smbfs_remove(share, dvp, vp, ap->a_cnp, ap->a_flags, ap->a_context);
3859	smb_share_rele(share, ap->a_context);
3860	smbnode_unlockpair(VTOSMB(dvp), VTOSMB(vp));
3861	return (error);
3862
3863}
3864
3865/*
3866 * smbfs remove directory call
3867 *
3868 * The calling routine must hold a reference on the share
3869 *
3870 */
3871static int
3872smbfs_rmdir(struct smb_share *share, vnode_t dvp, vnode_t vp,
3873			struct componentname *cnp, vfs_context_t context)
3874{
3875#pragma unused(cnp)
3876	struct smbmount *smp = VTOSMBFS(vp);
3877	struct smbnode *dnp = VTOSMB(dvp);
3878	struct smbnode *np = VTOSMB(vp);
3879	int error;
3880    SMBFID fid = 0;
3881    uint64_t hashval = 0;
3882
3883	/* XXX other OSX fs test fs nodes here, not vnodes. Why? */
3884	if (dvp == vp) {
3885		error = EINVAL;
3886		goto bad;
3887	}
3888
3889    cache_purge(vp);
3890
3891    /*
3892     * NetApp and Samba servers will reuse the File ID immediately after a
3893     * delete, so remove the smb node from the hash table before doing the
3894     * delete. If the delete fails, then we know the File ID is still valid
3895     * and it should be ok to reinsert the smbnode.
3896     */
3897    smb_vhashrem(np);
3898
3899	error = smbfs_smb_rmdir(share, np, context);
3900	if (error) {
3901        /*
3902         * Delete failed, add smbnode back into hash table.
3903         * Then leave as there is nothing else we can do at this point
3904         */
3905        hashval = smbfs_hash(share, np->n_ino, np->n_name, np->n_nmlen);
3906        smb_vhashadd(np, hashval);
3907	    goto bad;
3908    }
3909
3910	smbfs_attr_touchdir(dnp, (share->ss_fstype == SMB_FS_FAT));
3911    dnp->d_changecnt++;
3912
3913	/*
3914	 * We may still have a change notify on this node, close it so
3915	 * the item will get delete on the server. Mark it not to be
3916	 * reopened first, then save off the fid, clear the node fid
3917	 * now close the file descriptor.
3918	 */
3919	np->d_needReopen = FALSE;
3920	fid = np->d_fid;
3921	np->d_fid = 0;
3922	if (fid != 0) {
3923		(void)smbfs_tmpclose(share, np, fid, context);
3924	}
3925
3926	/* Remove any negative cache entries. */
3927	if (dnp->n_flag & NNEGNCENTRIES) {
3928		dnp->n_flag &= ~NNEGNCENTRIES;
3929		cache_purge_negatives(dvp);
3930	}
3931
3932bad:
3933	/* if success, blow away statfs cache */
3934	if (!error) {
3935		smp->sm_statfstime = 0;
3936		(void) vnode_recycle(vp);
3937	}
3938	return (error);
3939}
3940
3941/*
3942 * smbfs_vnop_rmdir
3943 *
3944 * vnode_t a_dvp;
3945 * vnode_t a_vp;
3946 * struct componentname *a_cnp;
3947 * vfs_context_t a_context;
3948 */
3949static int smbfs_vnop_rmdir(struct vnop_rmdir_args *ap)
3950{
3951	vnode_t dvp = ap->a_dvp;
3952	vnode_t vp = ap->a_vp;
3953	int32_t error;
3954	struct smb_share *share;
3955
3956	if (!vnode_isdir(vp))
3957		return (ENOTDIR);
3958
3959	if (dvp == vp)
3960		return (EINVAL);
3961
3962	/* Always put in the order of parent then child */
3963	if ((error = smbnode_lockpair(VTOSMB(dvp), VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
3964		return (error);
3965
3966	VTOSMB(dvp)->n_lastvop = smbfs_vnop_rmdir;
3967	VTOSMB(vp)->n_lastvop = smbfs_vnop_rmdir;
3968	share = smb_get_share_with_reference(VTOSMBFS(dvp));
3969	error = smbfs_rmdir(share, dvp, vp, ap->a_cnp, ap->a_context);
3970	smb_share_rele(share, ap->a_context);
3971	smbnode_unlockpair(VTOSMB(dvp), VTOSMB(vp));
3972
3973	return (error);
3974}
3975
3976/*
3977 * smbfs_vnop_rename
3978 *
3979 * vnode_t a_fdvp;
3980 * vnode_t a_fvp;
3981 * struct componentname *a_fcnp;
3982 * vnode_t a_tdvp;
3983 * vnode_t a_tvp;
3984 * struct componentname *a_tcnp;
3985 * vfs_context_t a_context;
3986 */
3987static int
3988smbfs_vnop_rename(struct vnop_rename_args *ap)
3989{
3990	vnode_t 	fvp = ap->a_fvp;
3991	vnode_t 	tvp = ap->a_tvp;
3992	vnode_t 	fdvp = ap->a_fdvp;
3993	vnode_t 	tdvp = ap->a_tdvp;
3994	struct smbmount *smp = VFSTOSMBFS(vnode_mount(fvp));
3995	struct smb_share *share = NULL;
3996	struct componentname *tcnp = ap->a_tcnp;
3997	struct componentname *fcnp = ap->a_fcnp;
3998	proc_t p = vfs_context_proc(ap->a_context);
3999	int error = 0;
4000	struct smbnode *fnp = NULL;
4001	struct smbnode *tdnp = NULL;
4002	struct smbnode *fdnp = NULL;
4003	int vtype;
4004	struct smbnode * lock_order[4] = {NULL};
4005	int	lock_cnt = 0;
4006	int ii;
4007
4008	/* Check for cross-device rename */
4009	if ((vnode_mount(fvp) != vnode_mount(tdvp)) ||
4010		(tvp && (vnode_mount(fvp) != vnode_mount(tvp))))
4011		return (EXDEV);
4012
4013	vtype = vnode_vtype(fvp);
4014	if ( (vtype != VDIR) && (vtype != VREG) && (vtype != VLNK) )
4015		return (EINVAL);
4016
4017	/*
4018	 * First lets deal with the parents. If they are the same only lock the from
4019	 * vnode, otherwise see if one is the parent of the other. We always want
4020	 * to lock in parent child order if we can. If they are not the parent of
4021	 * each other then lock in address order.
4022	 */
4023	lck_mtx_lock(&smp->sm_reclaim_renamelock);
4024	if (fdvp == tdvp)
4025		lock_order[lock_cnt++] = VTOSMB(fdvp);
4026	else if (VTOSMB(fdvp)->n_parent && (VTOSMB(fdvp)->n_parent == VTOSMB(tdvp))) {
4027		lock_order[lock_cnt++] = VTOSMB(tdvp);
4028		lock_order[lock_cnt++] = VTOSMB(fdvp);
4029	} else if (VTOSMB(tdvp)->n_parent && (VTOSMB(tdvp)->n_parent == VTOSMB(fdvp))) {
4030		lock_order[lock_cnt++] = VTOSMB(fdvp);
4031		lock_order[lock_cnt++] = VTOSMB(tdvp);
4032	} else if (VTOSMB(fdvp) < VTOSMB(tdvp)) {
4033		lock_order[lock_cnt++] = VTOSMB(fdvp);
4034		lock_order[lock_cnt++] = VTOSMB(tdvp);
4035	} else {
4036		lock_order[lock_cnt++] = VTOSMB(tdvp);
4037		lock_order[lock_cnt++] = VTOSMB(fdvp);
4038	}
4039	/*
4040	 * Now lets deal with the children. If any of the following is true then just
4041	 * lock the from vnode:
4042	 *		1. The to vnode doesn't exist
4043	 *		2. The to vnode and from vnodes are the same
4044	 *		3. The to vnode and the from parent vnodes are the same, I know
4045	 *		   it's strange but can happen.
4046	 * Otherwise, lock in address order
4047	 */
4048	if ((tvp == NULL) || (tvp == fvp) || (tvp == fdvp))
4049		lock_order[lock_cnt++] = VTOSMB(fvp);
4050	else {
4051		if (VTOSMB(fvp) < VTOSMB(tvp)) {
4052			lock_order[lock_cnt++] = VTOSMB(fvp);
4053			lock_order[lock_cnt++] = VTOSMB(tvp);
4054		} else {
4055			lock_order[lock_cnt++] = VTOSMB(tvp);
4056			lock_order[lock_cnt++] = VTOSMB(fvp);
4057		}
4058	}
4059	/* Make sure there are now duplicates, this would be a design flaw */
4060	DBG_LOCKLIST_ASSERT(lock_cnt, lock_order);
4061
4062	lck_mtx_unlock(&smp->sm_reclaim_renamelock);
4063
4064	for (ii=0; ii<lock_cnt; ii++) {
4065		if (error)
4066			lock_order[ii] = NULL;
4067		else if ((error = smbnode_lock(lock_order[ii], SMBFS_EXCLUSIVE_LOCK)))
4068			lock_order[ii] = NULL;
4069	}
4070	if (error)
4071		goto out;
4072
4073    /*
4074     * Make sure that we do not proceed if we get lock after parent is
4075     * reclaimed after forced unmount.
4076     */
4077    if (vfs_isforce(smp->sm_mp)) {
4078        error = ENXIO;
4079        goto out;
4080    }
4081
4082	fdnp = VTOSMB(fdvp);
4083	fnp = VTOSMB(fvp);
4084	tdnp = VTOSMB(tdvp);
4085
4086	fdnp->n_lastvop = smbfs_vnop_rename;
4087	fnp->n_lastvop = smbfs_vnop_rename;
4088	tdnp->n_lastvop = smbfs_vnop_rename;
4089	if (tvp != NULL)
4090		VTOSMB(tvp)->n_lastvop = smbfs_vnop_rename;
4091
4092	share = smb_get_share_with_reference(smp);
4093	/*
4094	 * Check to see if the SMB_EFA_RDONLY/IMMUTABLE are set. If they are set
4095	 * then do not allow the rename. See HFS and AFP code.
4096	 */
4097	if (node_isimmutable(share, fvp)) {
4098		SMBWARNING( "%s is a locked file : Permissions error on delete\n",
4099				   fnp->n_name);
4100		error = EPERM;
4101		goto out;
4102	}
4103
4104	/*
4105	 * Since there are no hard links (from our client point of view)
4106	 * fvp==tvp means the arguments are case-variants.  (If they
4107	 * were identical the rename syscall doesnt call us.)
4108	 */
4109	if (fvp == tvp)
4110		tvp = NULL;
4111
4112	/*
4113	 * The problem we have here is some servers will not return the correct
4114	 * case of the file name in the lookup. This can cause to have two vnodes
4115	 * that point to the same item. Very bad but nothing we can do about that
4116	 * in smb. So if the target exist, the parents are the same and the name is
4117	 * the same except for case, then don't delete the target.
4118	 */
4119    if (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS) {
4120        /* Server supports File IDs */
4121        if (tvp && (fdvp == tdvp) && (fnp->n_ino == VTOSMB(tvp)->n_ino)) {
4122            SMBWARNING("Not removing target, same file. %s ==> %s\n",
4123                       fnp->n_name, VTOSMB(tvp)->n_name);
4124            smb_vhashrem(VTOSMB(tvp)); /* Remove it from our hash so it can't be found */
4125            (void) vnode_recycle(tvp);
4126            tvp = NULL;
4127        }
4128    }
4129    else {
4130        /* Server does not support File IDs */
4131        if (tvp && (fdvp == tdvp) &&  (fnp->n_nmlen == VTOSMB(tvp)->n_nmlen) &&
4132                    (strncasecmp((char *)fnp->n_name, (char *)VTOSMB(tvp)->n_name,
4133                                 fnp->n_nmlen) == 0)) {
4134            SMBWARNING("Not removing target, same file. %s ==> %s\n",
4135                       fnp->n_name, VTOSMB(tvp)->n_name);
4136            smb_vhashrem(VTOSMB(tvp)); /* Remove it from our hash so it can't be found */
4137            (void) vnode_recycle(tvp);
4138            tvp = NULL;
4139        }
4140    }
4141
4142	/*
4143	 * If we are not doing Named Streams, they gave us a target to delete, and
4144	 * the source is a dot underscore file then make sure the source exist before
4145	 * deleting the target.
4146	 *
4147	 * This problem happens when going Mac to Mac and the share is FAT or some
4148	 * share that doesn't support streams. The remote VNOP_RENAME will rename
4149	 * the dot underscore file underneath the client. So when the cleint tries
4150	 * to rename the dot underscore it thinkis the target exist and needs to be
4151	 * deleted. So never delete the target if the source doesn't exist.
4152	 */
4153	if ((tvp) && (!(share->ss_attributes & FILE_NAMED_STREAMS)) &&
4154		(fnp->n_nmlen > 2) && (fnp->n_name[0] == '.') && (fnp->n_name[1] == '_')) {
4155		const char *name = (const char *)fnp->n_name;
4156		size_t nmlen = fnp->n_nmlen;
4157		struct smbfattr fattr;
4158
4159		error = smbfs_lookup(share, fdnp, &name, &nmlen, &fattr, ap->a_context);
4160		/* Should we check for any error or just ENOENT */
4161		if (error == ENOENT)
4162			tvp = NULL;
4163		/* smbfs_lookup could have replace the name, free it if did */
4164		if (name != (char *)fnp->n_name) {
4165			SMB_FREE(name, M_SMBNODENAME);
4166		}
4167	}
4168
4169	/*
4170	 * If the destination exists then it needs to be removed.
4171	 */
4172	if (tvp) {
4173		if (vnode_isdir(tvp)) {
4174			/*
4175			 * From the man 2 rename
4176			 *
4177			 * CONFORMANCE
4178			 * The restriction on renaming a directory whose permissions disallow
4179			 * writing is based on the fact that UFS directories contain a ".."
4180			 * entry.  If renaming a directory would move it to another parent
4181			 * directory, this entry needs to be changed.
4182			 *
4183			 * This restriction has been generalized to disallow renaming of any
4184			 * write-disabled directory, even when this would not require a
4185			 * change to the ".." entry.  For consistency, HFS+ directories
4186			 * emulate this behavior.
4187			 *
4188			 * So if you are renaming a dir to an existing dir, you must have
4189			 * write access on the existing dir. Seems if the user is a super
4190			 * user then we can delete the existing directory.
4191			 *
4192			 * XXX - We need to remove the smb_check_posix_access and just do a
4193			 * vnop_access.
4194			 */
4195			if (share->ss_attributes & FILE_PERSISTENT_ACLS)
4196				error = smbfs_rmdir(share, tdvp, tvp, tcnp, ap->a_context);
4197			else if ((vfs_context_suser(ap->a_context) == 0) ||
4198					 (smb_check_posix_access(ap->a_context, VTOSMB(tvp), S_IWOTH)))
4199				error = smbfs_rmdir(share, tdvp, tvp, tcnp, ap->a_context);
4200			else
4201				error = EPERM;
4202		} else {
4203			error = smbfs_remove(share, tdvp, tvp, tcnp, 0, ap->a_context);
4204		}
4205		if (error)
4206			goto out;
4207	}
4208
4209	cache_purge(fvp);
4210
4211	/* Did we open this in our read routine. Then we should close it. */
4212	if ((!vnode_isdir(fvp)) && (!vnode_isinuse(fvp, 0)) &&
4213		(fnp->f_refcnt == 1) && fnp->f_needClose) {
4214		error = smbfs_close(share, fvp, FREAD, ap->a_context);
4215		if (error)
4216			SMBWARNING("error %d closing %s\n", error, fnp->n_name);
4217	}
4218
4219	/*
4220	 * Windows Servers will not let you move a item that contains open items. So
4221	 * if we are moving an folder and the source folder has an open notification
4222	 * then close the notification, before doing the move.
4223	 */
4224	if (vnode_isdir(fvp) &&
4225        (fnp->d_fid != 0)) {
4226		(void)smbfs_tmpclose(share, fnp, fnp->d_fid, ap->a_context);
4227		/* Mark it to be reopen */
4228		fnp->d_needReopen = TRUE;
4229		fnp->d_fid = 0;
4230	}
4231
4232	/*
4233	 * Try to rename the file, this may fail if the file is open. Some
4234	 * SAMBA systems allow us to rename an open file, so try this case
4235	 * first.
4236	 *
4237	 * FYI: While working on Radar 4532498 I notice that you can move/rename
4238	 * an open file if it is open for read-only. Only tested this on Windows 2003.
4239	 */
4240	error = smbfs_smb_rename(share, fnp, tdnp, tcnp->cn_nameptr,
4241							 tcnp->cn_namelen, ap->a_context);
4242	/*
4243	 * The file could be open so lets try again. This call does not work on
4244	 * Windows 95/98/Me/NT4 systems. Since this call only allows you to
4245	 * rename in place do not even try it if they are moving the item.
4246	 */
4247	if ( (fdvp == tdvp) && error &&
4248		(VC_CAPS(SSTOVC(share)) & SMB_CAP_INFOLEVEL_PASSTHRU))
4249		error = smbfs_smb_t2rename(share, fnp, tcnp->cn_nameptr,
4250								   tcnp->cn_namelen, 1, NULL, ap->a_context);
4251
4252	/*
4253	 * We should really print a better description of the error to the
4254	 * system log. Thing we could print in the system log.
4255	 * 1. This server does not support renaming of an open file.
4256	 * 2. This server only supports renaming of an open file in place.
4257	 * 3. Renaming open file failed.
4258	 *
4259	 * Written up as Radar 4381236
4260	 */
4261	if (!error) {
4262		char *new_name;
4263		uint64_t hashval;
4264		uint32_t orig_flag = fnp->n_flag;
4265
4266		/*
4267		 * At this point we still have both parents and the children locked if
4268		 * they exist. Since the parents are locked we know that a lookup of the
4269		 * children cannot happen over the network. So we are safe to play with
4270		 * both names and the hash node entries. The old code would just remove
4271		 * the node from the hash table and then just change the nodes name, this
4272		 * was very bad and could cause the following to happen:
4273		 *
4274		 * RENAME HAPPENS ON VP1: vp1->np1->n_name = file1 gets renamed to vp1->np1->n_name = file2
4275		 *	1. vp1 is no longer in the name cache.
4276		 *  2. np1 is no longer in the hash table.
4277		 *  3. vp1 still has a ref taken on it and can still be used.
4278		 *
4279		 * LOOKUP HAPPNES ON file2: Which will cause a new vnode and smbnode to get created
4280		 *  1. vp1 is not found because its not in the name cache.
4281		 *  2. np1 is not found because its not in the hash table.
4282		 *  3. vp2 and np2 get created and vp2->np2->n_name = file2
4283		 *
4284		 * RENAME HAPPENS ON VP2: vp2->np2->n_name = file2 gets renamed to vp2->np2->n_name = file3
4285		 *	1. vp1 no longer has the correct name.
4286		 *	2. vp2 is no longer in the name cache.
4287		 *  3. np2 is no longer in the hash table.
4288		 *  4. vp2 still has a ref taken on it and can still be used.
4289		 *
4290		 * SOME OTHER OPERATION HAPPENS ON VP1: It will fail because VP1 now has the wrong name.
4291		 *	1. Now the whole thing can repeat, very bad!
4292		 */
4293
4294        if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) {
4295            /*
4296             * Server does not support File IDs.
4297             * Remove it from the hash, it doesn't exist under that name
4298             * anymore
4299             */
4300            smb_vhashrem(fnp);
4301        }
4302
4303		/* We always need the following code. */
4304		if (tdvp && (fdvp != tdvp)) {
4305			/* Take a ref count on the new parent */
4306			if (!vnode_isvroot(tdvp)) {
4307				if (vnode_get(tdvp) == 0) {
4308					if (vnode_ref(tdvp) == 0) {
4309						fnp->n_flag |= NREFPARENT;
4310
4311                        /* Increment new parent node's child refcnt */
4312                        OSIncrementAtomic(&tdnp->n_child_refcnt);
4313                    }
4314					else {
4315						fnp->n_flag &= ~NREFPARENT;
4316                    }
4317					vnode_put(tdvp);
4318				}
4319			}
4320			else
4321				fnp->n_flag &= ~NREFPARENT;
4322			/* Remove the ref count off the old parent */
4323			if ((!vnode_isvroot(fdvp)) && (orig_flag & NREFPARENT)) {
4324				if (vnode_get(fdvp) == 0) {
4325					vnode_rele(fdvp);
4326					vnode_put(fdvp);
4327
4328                    /* Remove the child refcnt from old parent */
4329                    OSDecrementAtomic(&fdnp->n_child_refcnt);
4330				}
4331			}
4332
4333			fnp->n_parent = VTOSMB(tdvp);
4334
4335            VTOSMB(tdvp)->d_changecnt++;
4336            VTOSMB(fdvp)->d_changecnt++;
4337		}
4338
4339		/*
4340		 * Now reset the name so path lookups will work and add the node back
4341		 * into the hash table, so other lookups can this node.
4342		 */
4343		new_name = smb_strndup(tcnp->cn_nameptr, tcnp->cn_namelen);
4344		if (new_name) {
4345			char * old_name = fnp->n_name;
4346			lck_rw_lock_exclusive(&fnp->n_name_rwlock);
4347			fnp->n_name = new_name;
4348			fnp->n_nmlen = tcnp->cn_namelen;
4349			lck_rw_unlock_exclusive(&fnp->n_name_rwlock);
4350
4351            if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) {
4352                /* Server does not support File IDs */
4353                hashval = smbfs_hash(NULL, 0, fnp->n_name, fnp->n_nmlen);
4354                smb_vhashadd(fnp, hashval);
4355            }
4356
4357			/* Now its safe to free the old name */
4358			SMB_FREE(old_name, M_SMBNODENAME);
4359		}
4360
4361        if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS)) {
4362            /*
4363             * Servers does not support File IDs
4364             * <10854595> Update the n_ino with the new name and/or parent
4365             */
4366            fnp->n_ino = smbfs_getino(fnp->n_parent, fnp->n_name, fnp->n_nmlen);
4367        }
4368
4369        /* Update time stamp of when we last did rename */
4370        nanouptime(&fnp->n_rename_time);
4371    }
4372
4373	/*
4374	 *	Source			Target
4375	 *	Dot	Hidden		Dot	HIDE
4376	 *	Dot	Unhidden	Dot	HIDE! (Puma recovery)
4377	 *	NoDot	Hidden		Dot	HIDE (Win hid it)
4378	 *	NoDot	Unhidden	Dot	HIDE
4379	 *	Dot	Hidden		NoDot	UNHIDE
4380	 *	Dot	Unhidden	NoDot	UNHIDE
4381	 *	NoDot	Hidden		NoDot	HIDE! (Win hid it)
4382	 *	NoDot	Unhidden	NoDot	UNHIDE
4383	 */
4384	if (!error) {
4385		int hiderr;
4386		Boolean hideItem = (tcnp->cn_nameptr[0] == '.');
4387		Boolean unHideItem = ((tcnp->cn_nameptr[0] != '.') &&
4388							  (fcnp->cn_nameptr[0] == '.'));
4389
4390		if (hideItem || unHideItem) {
4391			hiderr = smbfs_set_hidden_bit(share, tdnp, tcnp->cn_nameptr,
4392										  tcnp->cn_namelen, hideItem,
4393                                          ap->a_context);
4394			if (hiderr) {
4395				SMBWARNING("Error %d %s %s\n", hiderr, (hideItem) ? "hiding" :
4396						 "unhiding", tcnp->cn_nameptr);
4397			}
4398		}
4399	}
4400
4401	if (error == EBUSY) {
4402		char errbuf[32];
4403
4404		proc_name(proc_pid(p), &errbuf[0], 32);
4405		SMBERROR("warning: pid %d(%.*s) rename open file(%s)\n", proc_pid(p),
4406				 32, &errbuf[0], fnp->n_name);
4407	}
4408	smbfs_attr_touchdir(fdnp, (share->ss_fstype == SMB_FS_FAT));
4409	if (tdvp != fdvp)
4410		smbfs_attr_touchdir(tdnp, (share->ss_fstype == SMB_FS_FAT));
4411	/* if success, blow away statfs cache */
4412	if (!error) {
4413		smp->sm_statfstime = 0;
4414
4415        /* Invalidate negative cache entries in destination dir */
4416		if (tdnp->n_flag & NNEGNCENTRIES) {
4417			tdnp->n_flag &= ~NNEGNCENTRIES;
4418			cache_purge_negatives(tdvp);
4419		}
4420	}
4421
4422out:
4423	/* We only have a share if we obtain a reference on it, so release it */
4424	if (share) {
4425		smb_share_rele(share, ap->a_context);
4426	}
4427	if (error == EBUSY) {
4428		char errbuf[32];
4429
4430		proc_name(proc_pid(p), &errbuf[0], 32);
4431		SMBWARNING("warning: pid %d(%.*s) rename open file(%s)\n", proc_pid(p), 32, &errbuf[0], fnp->n_name);
4432	}
4433	for (ii=0; ii<lock_cnt; ii++)
4434		if (lock_order[ii])
4435			smbnode_unlock(lock_order[ii]);
4436
4437	return (error);
4438}
4439
4440/*
4441 * smbfs_vnop_link
4442 *
4443 * vnode_t a_vp;
4444 * vnode_t a_tdvp;
4445 * struct componentname *a_cnp;
4446 * vfs_context_t a_context;
4447 *
4448 * someday this will come true...
4449 */
4450static int
4451smbfs_vnop_link(struct vnop_link_args *ap)
4452{
4453	proc_t p = vfs_context_proc(ap->a_context);
4454	struct smbnode *np = VTOSMB(ap->a_vp);
4455	char errbuf[32];
4456
4457	proc_name(proc_pid(p), &errbuf[0], 32);
4458	SMBERROR("warning: pid %d(%.*s) hardlink(%s)\n", proc_pid(p), 32, &errbuf[0], np->n_name);
4459	return (err_link(ap));
4460}
4461
4462/*
4463 * smbfs_vnop_symlink link create call.
4464 *
4465 * vnode_t a_dvp;
4466 * vnode_t *a_vpp;
4467 * struct componentname *a_cnp;
4468 * struct vnode_attr *a_vap;
4469 *  char *a_target;
4470 *  vfs_context_t a_context;
4471 */
4472static int smbfs_vnop_symlink(struct vnop_symlink_args *ap)
4473{
4474	int error;
4475	struct vnop_create_args a;
4476	vnode_t 	dvp = ap->a_dvp;
4477	struct smbnode *dnp;
4478	struct smb_share *share;
4479
4480	/* Make sure we lock the parent before calling smbfs_create */
4481	if ((error = smbnode_lock(VTOSMB(dvp), SMBFS_EXCLUSIVE_LOCK)))
4482		return error;
4483
4484	dnp = VTOSMB(dvp);
4485	dnp->n_lastvop = smbfs_vnop_symlink;
4486	a.a_dvp = dvp;
4487	a.a_vpp = ap->a_vpp;
4488	a.a_cnp = ap->a_cnp;
4489	a.a_vap = ap->a_vap;
4490	a.a_context = ap->a_context;
4491	/*
4492	 * We use PATH_MAX because we have no way currently to find out what is the
4493	 * max path on the server.
4494	 */
4495	share = smb_get_share_with_reference(VTOSMBFS(dvp));
4496
4497	error = smbfs_create(share, &a, ap->a_target, strnlen(ap->a_target, PATH_MAX+1));
4498
4499	smb_share_rele(share, ap->a_context);
4500	smbnode_unlock(dnp);
4501	return (error);
4502}
4503
4504/*
4505 * smbfs_vnop_readlink read symlink call.
4506 *
4507 * vnode_t *a_vpp;
4508 * struct componentname *a_cnp;
4509 * uio_t a_uio;
4510 *  vfs_context_t a_context;
4511 */
4512static int
4513smbfs_vnop_readlink(struct vnop_readlink_args *ap)
4514{
4515	vnode_t 	vp = ap->a_vp;
4516	struct smbnode *np = NULL;
4517	int error;
4518	struct smb_share *share;
4519	time_t symlinktimeo;
4520	struct timespec ts;
4521
4522	if (vnode_vtype(vp) != VLNK)
4523		return (EINVAL);
4524
4525	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
4526		return (error);
4527
4528	np = VTOSMB(vp);
4529	np->n_lastvop = smbfs_vnop_readlink;
4530	share = smb_get_share_with_reference(VTOSMBFS(vp));
4531	SMB_CACHE_TIME(ts, np, symlinktimeo);
4532
4533	if ((np->n_symlink_target) && ((share->ss_flags & SMBS_RECONNECTING) ||
4534		(symlinktimeo > (ts.tv_sec - np->n_symlink_cache_timer)))) {
4535		error = uiomove(np->n_symlink_target, (int)np->n_symlink_target_len, ap->a_uio);
4536	} else if ((np->n_dosattr &  SMB_EFA_REPARSE_POINT) &&
4537		(np->n_reparse_tag == IO_REPARSE_TAG_SYMLINK)) {
4538			error = smbfs_smb_reparse_read_symlink(share, np, ap->a_uio, ap->a_context);
4539	} else if (np->n_flag & NWINDOWSYMLNK) {
4540		error = smbfs_smb_windows_read_symlink(share, np, ap->a_uio, ap->a_context);
4541	} else {
4542		error = smbfs_smb_unix_read_symlink(share, np, ap->a_uio, ap->a_context);
4543	}
4544	smb_share_rele(share, ap->a_context);
4545	smbnode_unlock(np);
4546	return (error);
4547}
4548
4549/*
4550 * smbfs_vnop_mknod
4551 *
4552 * vnode_t a_dvp;
4553 * vnode_t *a_vpp;
4554 * struct componentname *a_cnp;
4555 * struct vnode_attr *a_vap;
4556 * vfs_context_t a_context;
4557 */
4558static int
4559smbfs_vnop_mknod(struct vnop_mknod_args *ap)
4560{
4561	proc_t p = vfs_context_proc(ap->a_context);
4562	char errbuf[32];
4563
4564	proc_name(proc_pid(p), &errbuf[0], 32);
4565	SMBERROR("warning: pid %d(%.*s) mknod(%s)\n", proc_pid(p), 32, &errbuf[0],
4566			 ap->a_cnp->cn_nameptr);
4567	return (err_mknod(ap));
4568}
4569
4570/*
4571 * smbfs_vnop_mkdir
4572 *
4573 * vnode_t a_dvp;
4574 * vnode_t *a_vpp;
4575 * struct componentname *a_cnp;
4576 * struct vnode_attr *a_vap;
4577 * vfs_context_t a_context;
4578 */
4579static int
4580smbfs_vnop_mkdir(struct vnop_mkdir_args *ap)
4581{
4582	vnode_t 	dvp = ap->a_dvp;
4583	struct vnode_attr *vap = ap->a_vap;
4584	vnode_t 	vp;
4585	struct componentname *cnp = ap->a_cnp;
4586	struct smbnode *dnp = NULL;
4587	struct smbmount *smp = NULL;
4588	struct smbfattr fattr;
4589	const char *name = cnp->cn_nameptr;
4590	size_t len = cnp->cn_namelen;
4591	int error;
4592	struct smb_share *share;
4593	struct timespec ts;
4594
4595	if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
4596		return (EEXIST);
4597
4598	if ((error = smbnode_lock(VTOSMB(dvp), SMBFS_EXCLUSIVE_LOCK)))
4599		return (error);
4600	dnp = VTOSMB(dvp);
4601	dnp->n_lastvop = smbfs_vnop_mkdir;
4602	smp = dnp->n_mount;
4603	share = smb_get_share_with_reference(smp);
4604	error = smbfs_smb_mkdir(share, dnp, name, len, &fattr, ap->a_context);
4605	if (error)
4606		goto exit;
4607
4608	smbfs_attr_touchdir(dnp, (share->ss_fstype == SMB_FS_FAT));
4609    dnp->d_changecnt++;
4610
4611	/*
4612	 * %%%
4613	 * Would really like to clean this code up in the future. The whole create,
4614	 * mkdir and smblink create code should use the same code path.
4615	 */
4616	error = smbfs_nget(share, vnode_mount(dvp),
4617                       dvp, name, len,
4618                       &fattr, &vp,
4619                       cnp->cn_flags, SMBFS_NGET_CREATE_VNODE,
4620                       ap->a_context);
4621	if (error)
4622		goto bad;
4623
4624	/*
4625	 * We just create the directory, so we have no finder info. So set our cache
4626	 * timer to reflect this information
4627	 */
4628	nanouptime(&ts);
4629	VTOSMB(vp)->finfo_cache = ts.tv_sec;
4630	smbfs_set_create_vap(share, vap, vp, ap->a_context, FALSE);
4631	*ap->a_vpp = vp;
4632	smbnode_unlock(VTOSMB(vp));	/* Done with the smbnode unlock it. */
4633	error = 0;
4634	if (dnp->n_flag & NNEGNCENTRIES) {
4635		dnp->n_flag &= ~NNEGNCENTRIES;
4636		cache_purge_negatives(dvp);
4637	}
4638
4639bad:
4640	if (name != cnp->cn_nameptr) {
4641		SMB_FREE(name, M_SMBNODENAME);
4642	}
4643	/* if success, blow away statfs cache */
4644	smp->sm_statfstime = 0;
4645exit:
4646	smb_share_rele(share, ap->a_context);
4647	smbnode_unlock(dnp);
4648	return (error);
4649}
4650
4651/*
4652 * smbfs_vnop_readdir
4653 *
4654 * vnode_t a_vp;
4655 * struct uio *a_uio;
4656 * int a_flags;
4657 * int *a_eofflag;
4658 * int *a_numdirent;
4659 * vfs_context_t a_context;
4660 */
4661static int
4662smbfs_vnop_readdir(struct vnop_readdir_args *ap)
4663{
4664	vnode_t	vp = ap->a_vp;
4665	uio_t uio = ap->a_uio;
4666	int error;
4667	int32_t numdirent = 0;
4668
4669	if (uio_offset(uio) < 0)
4670		return (EINVAL);
4671
4672	if (!vnode_isdir(vp))
4673		return (EPERM);
4674
4675	if (ap->a_eofflag)
4676		*ap->a_eofflag = 0;
4677
4678	if (uio_resid(uio) == 0)
4679		return (0);
4680
4681	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
4682		return (error);
4683	VTOSMB(vp)->n_lastvop = smbfs_vnop_readdir;
4684
4685	error = smbfs_readvdir(vp, uio, ap->a_context, ap->a_flags, &numdirent);
4686	if (error == ENOENT) {
4687		/* We have reached the end of the search */
4688		if (ap->a_eofflag)
4689			*ap->a_eofflag = 1;
4690		error = 0;
4691	}
4692	/* Return the number of entries from this lookup */
4693	if (ap->a_numdirent)
4694		*ap->a_numdirent = numdirent;
4695	smbnode_unlock(VTOSMB(vp));
4696	return (error);
4697}
4698
4699int32_t
4700smbfs_fsync(struct smb_share *share, vnode_t vp, int waitfor, int ubc_flags,
4701			vfs_context_t context)
4702{
4703#pragma unused(waitfor, ubc_flags)
4704	int error;
4705	off_t size;
4706
4707	if (!vnode_isreg(vp)) {
4708		return 0; /* Nothing to do here */
4709	}
4710	size = smb_ubc_getsize(vp);
4711	if ((size > 0) && smbfsIsCacheable(vp)) {
4712		if (VTOSMB(vp)->n_flag & NISMAPPED) {
4713			/* More expensive, but handles mmapped files */
4714			ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
4715		} else {
4716			/* Less expensive, but does not handle mmapped files */
4717			cluster_push(vp, IO_SYNC);
4718		}
4719	}
4720	error = smbfs_smb_fsync(share, VTOSMB(vp), context);
4721	if (!error)
4722		VTOSMBFS(vp)->sm_statfstime = 0;
4723	return (error);
4724}
4725
4726/*	smbfs_vnop_fsync
4727 *
4728 * vnode_t a_vp;
4729 * int32_t a_waitfor;
4730 * vfs_context_t a_context;
4731 */
4732static int32_t
4733smbfs_vnop_fsync(struct vnop_fsync_args *ap)
4734{
4735	int32_t error;
4736	struct smb_share *share;
4737
4738    /* If this is a read-only mount, there is nothing to do here */
4739    if (vfs_isrdonly(vnode_mount(ap->a_vp))) {
4740        return (0);
4741    }
4742
4743	error = smbnode_lock(VTOSMB(ap->a_vp), SMBFS_EXCLUSIVE_LOCK);
4744	if (error)
4745		return (0);
4746	VTOSMB(ap->a_vp)->n_lastvop = smbfs_vnop_fsync;
4747	share = smb_get_share_with_reference(VTOSMBFS(ap->a_vp));
4748	error = smbfs_fsync(share, ap->a_vp, ap->a_waitfor, 0, ap->a_context);
4749	smb_share_rele(share, ap->a_context);
4750	smbnode_unlock(VTOSMB(ap->a_vp));
4751	return (error);
4752}
4753
4754/*
4755 * smbfs_vnop_pathconf
4756 *
4757 *  vnode_t a_vp;
4758 *  int a_name;
4759 *  int32_t *a_retval;
4760 *  vfs_context_t a_context;
4761 */
4762static int smbfs_vnop_pathconf(struct vnop_pathconf_args *ap)
4763{
4764	struct smb_share *share;
4765	int32_t *retval = ap->a_retval;
4766	int error = 0;
4767
4768	share = smb_get_share_with_reference(VTOSMBFS(ap->a_vp));
4769	switch (ap->a_name) {
4770		case _PC_LINK_MAX:	/* Hard Link Support */
4771			*retval = 0; /* May support in the future. Depends on the server */
4772			break;
4773		case _PC_NAME_MAX:
4774			*retval = share->ss_maxfilenamelen;
4775			break;
4776		case _PC_PATH_MAX:
4777				/*
4778				 * XXX
4779				 * Most Windows system have a 255 limit, but you can configure
4780				 * them to support 1024. It would be nice if we could figure out
4781				 * the real value for this field.
4782				 */
4783				*retval = PATH_MAX;
4784				break;
4785		case _PC_CHOWN_RESTRICTED:
4786				*retval = 1;
4787				break;
4788		case _PC_NO_TRUNC:
4789				*retval = 0;
4790				break;
4791		case _PC_NAME_CHARS_MAX:
4792				*retval = share->ss_maxfilenamelen;
4793				break;
4794		case _PC_CASE_SENSITIVE:
4795            *retval = 0;
4796
4797            if (SSTOVC(share)->vc_misc_flags & SMBV_OSX_SERVER) {
4798                /* Its OS X Server so we know for sure */
4799                if (SSTOVC(share)->vc_volume_caps & kAAPL_CASE_SENSITIVE) {
4800                    SMBDEBUG("Volume is case sensitive\n");
4801                    *retval = 1;
4802                }
4803            }
4804            else {
4805                /*
4806                 * Thought about using FILE_CASE_SENSITIVE_SEARCH, but this
4807                 * really just means they will search by case. It does not mean
4808                 * this is a case sensitive file system. Currently we have no
4809                 * way of determining if this is a case sensitive or
4810                 * insensitive file system. We need to return a consistent
4811                 * answer between pathconf and vfs_getattr. We do not know the real
4812                 * answer for case sensitive, but lets default to what 90% of the
4813                 * servers have set. Also remember this fixes Radar 4057391 and 3530751.
4814                 */
4815                *retval = 0;
4816            }
4817			break;
4818		case _PC_CASE_PRESERVING:
4819			if (share->ss_attributes & FILE_CASE_PRESERVED_NAMES)
4820				*retval = 1;
4821			else *retval = 0;
4822			break;
4823		/*
4824		 * Handle by vn_pathconf.
4825		 *
4826		 * case _PC_EXTENDED_SECURITY_NP:
4827		 *		*retval = vfs_extendedsecurity(vnode_mount(vp)) ? 1 : 0;
4828		 *		break;
4829		 * case _PC_AUTH_OPAQUE_NP:
4830		 *		*retval = vfs_authopaque(vnode_mount(vp));
4831		 *		break;
4832		 * case _PC_2_SYMLINKS:
4833		 *		*retval = 1;
4834		 *		break;
4835		 * case _PC_ALLOC_SIZE_MIN:
4836		 *		*retval = 1;    // XXX lie: 1 byte
4837		 *		break;
4838		 * case _PC_ASYNC_IO:     // unistd.h: _POSIX_ASYNCHRONUS_IO
4839		 *		*retval = 1;    // [AIO] option is supported
4840		 *		break;
4841		 */
4842		case _PC_FILESIZEBITS:
4843			if (VC_CAPS(SSTOVC(share)) & SMB_CAP_LARGE_FILES)
4844				*retval = 64;	/* The server supports 64 bit offsets */
4845			else *retval = 32;	/* The server supports 32 bit offsets */
4846			break;
4847	    case _PC_XATTR_SIZE_BITS:
4848			if (!(share->ss_attributes & FILE_NAMED_STREAMS)) {
4849				/* Doesn't support named streams VFS handles this cases */
4850				error = EINVAL;
4851			} else if (VC_CAPS(SSTOVC(share)) & SMB_CAP_LARGE_FILES) {
4852				*retval = 64;	/* The server supports 64 bit offsets */
4853			} else {
4854				*retval = 32;	/* The server supports 32 bit offsets */
4855			}
4856			break;
4857		/*
4858		 * Handle by vn_pathconf.
4859		 *
4860		 * case _PC_PRIO_IO:       // unistd.h: _POSIX_PRIORITIZED_IO
4861		 *		 *retval = 0;    // [PIO] option is not supported
4862		 *		break;
4863		 * case _PC_REC_INCR_XFER_SIZE:
4864		 *		*retval = 4096; // XXX go from MIN to MAX 4K at a time
4865		 *		break;
4866		 * case _PC_REC_MIN_XFER_SIZE:
4867		 *		*retval = 4096; // XXX recommend 4K minimum reads/writes
4868		 *		break;
4869		 * case _PC_REC_MAX_XFER_SIZE: // Should we use SMB_IOMAX
4870		 *		*retval = 65536; // XXX recommend 64K maximum reads/writes
4871		 *		break;
4872		 * case _PC_REC_XFER_ALIGN:
4873		 *		*retval = 4096; // XXX recommend page aligned buffers
4874		 *		break;
4875		 * case _PC_SYMLINK_MAX:
4876		 *		*retval = 255;  // Minimum acceptable POSIX value
4877		 *		break;
4878		 * case _PC_SYNC_IO:       // unistd.h: _POSIX_SYNCHRONIZED_IO
4879		 *		*retval = 0;    // [SIO] option is not supported
4880		 *		break;
4881		 */
4882		default:
4883			error = EINVAL;
4884	}
4885	smb_share_rele(share, ap->a_context);
4886	return (error);
4887}
4888
4889/*
4890 * smbfs_vnop_ioctl - smbfs vnodeop entry point
4891 *	vnode_t a_vp;
4892 *	int32_t  a_command;
4893 *	caddr_t  a_data;
4894 *	int32_t  a_fflag;
4895 *	vfs_context_t context;
4896 */
4897static int32_t smbfs_vnop_ioctl(struct vnop_ioctl_args *ap)
4898{
4899    vnode_t		vp = ap->a_vp;
4900    struct smbnode	*np;
4901    int32_t			error = 0;
4902	proc_t			p = vfs_context_proc(ap->a_context);
4903	struct smb_share *share;
4904	struct smbmount *smp;
4905
4906	error = smbnode_lock(VTOSMB(ap->a_vp), SMBFS_EXCLUSIVE_LOCK);
4907	if (error)
4908		return (error);
4909
4910	np = VTOSMB(vp);
4911	np->n_lastvop = smbfs_vnop_ioctl;
4912	smp = VTOSMBFS(vp);
4913	share = smb_get_share_with_reference(VTOSMBFS(vp));
4914
4915	/*
4916	 * %%%
4917	 * Remove the IOCBASECMD case lines (OLD) when fsctl code in vfs_syscalls.c
4918	 * gets fixed to not use IOCBASECMD before calling VOP_IOCTL.
4919	 *
4920	 * The smbfsByteRangeLock2FSCTL call was made to support classic. We do
4921	 * not support classic, but the file manager will only make the
4922	 * smbfsByteRangeLock2FSCTL call. So for now support all the commands, but
4923	 * treat them all the same.
4924	 */
4925	switch (ap->a_command) {
4926	case smbfsGetVCSockaddrFSCTL:
4927	case smbfsGetVCSockaddrFSCTL_BASECMD: {
4928
4929		if (SSTOVC(share)->vc_saddr) {
4930			memcpy(ap->a_data, SSTOVC(share)->vc_saddr,
4931				   SSTOVC(share)->vc_saddr->sa_len);
4932		} else {
4933			error = EINVAL; /* Better never happen, but just in case */
4934		}
4935		break;
4936	}
4937	case smbfsUniqueShareIDFSCTL:
4938	case smbfsUniqueShareIDFSCTL_BASECMD: {
4939		struct UniqueSMBShareID *uniqueptr = (struct UniqueSMBShareID *)ap->a_data;
4940
4941		uniqueptr->error = 0;
4942		if ((uniqueptr->flags & SMBFS_GET_ACCESS_INFO) ||
4943			((uniqueptr->unique_id_len == smp->sm_args.unique_id_len) &&
4944			(bcmp(smp->sm_args.unique_id, uniqueptr->unique_id,
4945				  uniqueptr->unique_id_len) == 0))) {
4946
4947				/* In the future we should return the lsa name if we have one */
4948			uniqueptr->user[0] = 0;	/* Just in case we have no user name */
4949			if (SSTOVC(share)->vc_flags & SMBV_GUEST_ACCESS) {
4950				uniqueptr->connection_type = kConnectedByGuest;
4951				strlcpy(uniqueptr->user, kGuestAccountName, SMB_MAXUSERNAMELEN + 1);
4952			}
4953			else if (SSTOVC(share)->vc_username) {
4954				uniqueptr->connection_type = kConnectedByUser;
4955				strlcpy(uniqueptr->user, SSTOVC(share)->vc_username, SMB_MAXUSERNAMELEN + 1);
4956			} else {
4957				uniqueptr->connection_type = kConnectedByKerberos;
4958			}
4959			uniqueptr->error = EEXIST;
4960		}
4961	}
4962	break;
4963	case smbfsByteRangeLock2FSCTL:
4964	case smbfsByteRangeLock2FSCTL_BASECMD:
4965	case smbfsByteRangeLockFSCTL:
4966	case smbfsByteRangeLockFSCTL_BASECMD: {
4967		struct ByteRangeLockPB *pb = (struct ByteRangeLockPB *) ap->a_data;
4968		struct ByteRangeLockPB2 *pb2 = (struct ByteRangeLockPB2 *) ap->a_data;
4969		uint32_t lck_pid;
4970		uint32_t timo;
4971		SMBFID fid = 0;
4972		struct fileRefEntry *fndEntry = NULL;
4973		uint16_t accessMode = 0;
4974		int8_t flags;
4975        struct smbfattr *fap = NULL;
4976        struct smb2_durable_handle dur_handle, *dptr;
4977        int do_create;
4978        uint32_t disp;
4979
4980		/* make sure its a file */
4981		if (vnode_isdir(vp)) {
4982			error = EISDIR;
4983			goto exit;
4984		}
4985
4986		/* Before trying the lock see if the file needs to be reopened */
4987		error = smbfs_smb_reopen_file(share, np, ap->a_context);
4988		if (error) {
4989			SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
4990			goto exit;
4991		}
4992
4993		/*
4994		 * If adding/removing a ByteRangeLock, thus this vnode should NEVER
4995		 * be cacheable since the page in/out may overlap a lock and get
4996		 * an error.
4997		 */
4998		if (smbfsIsCacheable(vp)) {
4999			if (np->n_flag & NISMAPPED) {
5000				/* More expensive, but handles mmapped files */
5001				ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_PUSHDIRTY | UBC_SYNC);
5002			} else {
5003				/* Less expensive, but does not handle mmapped files */
5004				cluster_push(vp, IO_SYNC);
5005			}
5006			ubc_msync (vp, 0, ubc_getsize(vp), NULL, UBC_INVALIDATE);
5007			vnode_setnocache(vp);
5008		}
5009
5010		accessMode = np->f_accessMode;
5011
5012		/*
5013		 * Since we never get a smbfsByteRangeLockFSCTL call we could skip this
5014		 * check, but for now leave it.
5015		 */
5016		if ( (ap->a_command == smbfsByteRangeLock2FSCTL) ||
5017			(ap->a_command == smbfsByteRangeLock2FSCTL_BASECMD) ) {
5018			int32_t openMode = 0;
5019
5020			/*
5021			 * Not just for classic any more, could get this from Carbon.
5022			 *
5023			 * They will be using an extended BRL call that also passes in the
5024			 * open mode used that was used to open the file.  I will use the
5025			 * open access mode and pid to find the fork ref to do the lock on.
5026			 * Scenarios:
5027			 *	Open (R/W), BRL, Close (R/W)
5028			 *	Open (R/W/dW), BRL, Close (R/W/dW)
5029			 *	Open1 (R/W), Open2 (R), BRL1, BRL2, Close1 (R/W), Close2 (R)
5030			 *	Open1 (R/W/dW), Open2 (R), BRL1, BRL2, Close1 (R/W/dW), Close2 (R)
5031			 *	Open1 (R/dW), Open2 (R/dW), BRL1, BRL2, Close1 (R/dW), Close2 (R/dW)
5032			 */
5033			if ( (error = file_flags(pb2->fd, &openMode)) ) {
5034				goto exit;
5035			}
5036
5037			if (openMode & FREAD) {
5038				accessMode |= kAccessRead;
5039			}
5040			if (openMode & FWRITE) {
5041				accessMode |= kAccessWrite;
5042			}
5043
5044			/*
5045			 * See if we can find a matching fork that has byte range locks or
5046			 * denyModes
5047			 */
5048			if (openMode & FHASLOCK) {
5049				/*
5050				 * NOTE:  FHASLOCK can be set by open with O_EXCLUSIVE or
5051				 * O_SHARED which maps to my deny modes or FHASLOCK could also
5052				 * have been set/cleared by calling flock directly.  I assume
5053				 * that if they are using byte range locks, then they are Carbon
5054				 * and unlikely to be using flock.
5055				 *
5056				 * Assume it was opened with denyRead/denyWrite or just denyWrite.
5057				 * Try denyWrite first, if not found, try with denyRead and denyWrite
5058				 */
5059				accessMode |= kDenyWrite;
5060				error = FindFileRef(vp, p, accessMode, kExactMatch, 0, 0,
5061									&fndEntry, &fid);
5062				if (error != 0) {
5063					accessMode |= kDenyRead;
5064					error = FindFileRef(vp, p, accessMode, kExactMatch, 0, 0,
5065										 &fndEntry, &fid);
5066				}
5067				if (error != 0) {
5068					/* deny modes were used, but the fork ref cant be found, return error */
5069					error = EBADF;
5070					goto exit;
5071				}
5072			}
5073			else {
5074				/* no deny modes used, look for any forks opened previously for BRL */
5075				error = FindFileRef(vp, p, accessMode, kExactMatch, 0, 0,
5076									&fndEntry, &fid);
5077			}
5078		} else {
5079			error = FindFileRef(vp, p, kAccessRead | kAccessWrite, kAnyMatch,
5080								 0, 0, &fndEntry, &fid);
5081		}
5082		/*
5083		 * The process was not found or no list found
5084		 * Either case, we need to
5085		 *	1)  Open a new fork
5086		 *	2)  create a new OpenForkRefEntry entry and add it into the list
5087		 */
5088		if (error) {
5089			 uint32_t rights = 0;
5090			 uint32_t shareMode = NTCREATEX_SHARE_ACCESS_ALL;
5091			 proc_t p = vfs_context_proc(ap->a_context);
5092
5093			/* This is wrong, someone has to call open() before doing a byterange lock */
5094			if (np->f_refcnt <= 0) {
5095				error = EBADF;
5096				goto exit;
5097			}
5098
5099			/* We must find a matching lock in order to succeed at unlock */
5100			if (pb->unLockFlag == 1) {
5101				error = EINVAL;
5102				goto exit;
5103			}
5104
5105			/* Need to open the file here */
5106			if (accessMode & kAccessRead)
5107				rights |= SMB2_FILE_READ_DATA;
5108			if (accessMode & kAccessWrite)
5109				rights |= SMB2_FILE_APPEND_DATA | SMB2_FILE_WRITE_DATA;
5110
5111			if (accessMode & kDenyWrite)
5112				shareMode &= ~NTCREATEX_SHARE_ACCESS_WRITE; /* Remove the wr shared access */
5113			if (accessMode & kDenyRead)
5114				shareMode &= ~NTCREATEX_SHARE_ACCESS_READ; /* Remove the wr shared access */
5115
5116            SMB_MALLOC(fap,
5117                       struct smbfattr *,
5118                       sizeof(struct smbfattr),
5119                       M_SMBTEMP,
5120                       M_WAITOK | M_ZERO);
5121            if (fap == NULL) {
5122                SMBERROR("SMB_MALLOC failed\n");
5123                error = ENOMEM;
5124                goto exit;
5125            }
5126
5127            /* Request a durable handle */
5128            dptr = NULL;
5129            error = smb2_smb_dur_handle_init(share, np, &dur_handle);
5130            if (!error) {
5131                dptr = &dur_handle;
5132            }
5133
5134            if (np->n_flag & N_ISRSRCFRK) {
5135                disp = FILE_OPEN_IF;
5136                do_create = TRUE;
5137            }
5138            else {
5139                disp = FILE_OPEN;
5140                do_create = FALSE;
5141            }
5142
5143            error = smbfs_smb_ntcreatex(share, np,
5144                                        rights, shareMode, VREG,
5145                                        &fid, NULL, 0,
5146                                        disp, FALSE, fap,
5147                                        do_create, dptr, ap->a_context);
5148
5149			if (error != 0)
5150				goto exit;
5151
5152			AddFileRef(vp, p, accessMode, rights, fid, dur_handle, &fndEntry);
5153		}
5154
5155		/* Now I can do the ByteRangeLock */
5156		if (pb->startEndFlag) {
5157			/*
5158			 * SMB only allows you to lock relative to the begining of the
5159			 * file.  So, I need to convert offset base on the begining
5160			 * of the file.
5161			 */
5162			uint64_t fileSize = np->n_size;
5163
5164			pb->offset += fileSize;
5165			pb->startEndFlag = 0;
5166		}
5167
5168		flags = 0;
5169		if (pb->unLockFlag)
5170			flags |= SMB_LOCK_RELEASE;
5171		else
5172            flags |= SMB_LOCK_EXCL;
5173
5174		/* The problem here is that the lock pid must match the SMB Header PID.
5175		 * Some day it would be nice to pass a better value here. But for now
5176		 * always use the same value.
5177		 */
5178		lck_pid = 1;
5179		/*
5180		 * -1 infinite wait
5181		 * 0  no wait
5182		 * any other number is the number of milliseconds to wait.
5183		 */
5184		timo = 0;
5185
5186		error = smbfs_smb_lock(share, flags, fid, lck_pid, pb->offset,
5187							   pb->length, timo, ap->a_context);
5188		if (error == 0) {
5189			/* Save/remove lock info for use in read/write to determine what fork to use */
5190			AddRemoveByteRangeLockEntry (fndEntry, pb->offset, pb->length,
5191										 pb->unLockFlag, lck_pid);
5192			/* return the offset to the first byte of the lock */
5193			pb->retRangeStart = pb->offset;
5194		} else if ((!pb->unLockFlag) && (error == EACCES)) {
5195			/*
5196			 * Need to see if we are locking against ourself, so we can return
5197			 * the correct error.
5198			 */
5199			if (FindByteRangeLockEntry(fndEntry, pb->offset, pb->length, lck_pid))
5200				error = EAGAIN;
5201		}
5202	}
5203	break;
5204	default:
5205		error = ENOTSUP;
5206		goto exit;
5207    }
5208
5209exit:
5210	smb_share_rele(share, ap->a_context);
5211	smbnode_unlock(np);
5212	return (error);
5213}
5214
5215/*
5216 * SMB locks do not map to POSIX.1 advisory locks in several ways:
5217 * 1 - SMB provides no way to find an existing lock on the server.
5218 *     So, the F_GETLK operation can only report locks created by processes
5219 *     on this client.
5220 * 2 - SMB locks cannot overlap an existing locked region of a file. So,
5221 *     F_SETLK/F_SETLKW operations that establish locks cannot extend an
5222 *     existing lock.
5223 * 3 - When unlocking a SMB locked region, the region to unlock must correspond
5224 *     exactly to an existing locked region. So, F_SETLK F_UNLCK operations
5225 *     cannot split an existing lock or unlock more than was locked (this is
5226 *     especially important because whne files are closed, we receive a request
5227 *     to unlock the entire file: l_whence and l_start point to the beginning
5228 *     of the file, and l_len is zero).
5229 *
5230 * The result... SMB cannot support POSIX.1 advisory locks. It can however
5231 * support BSD flock() locks, so that's what this implementation will allow.
5232 *
5233 * Since we now support open deny modes we will only support flocks on files that
5234 * have no files open w
5235 *
5236 *		vnode_t a_vp;
5237 *		caddr_t  a_id;
5238 *		int  a_op;
5239 *		struct flock *a_fl;
5240 *		int  a_flags;
5241 *		vfs_context_t a_context;
5242 */
5243static int32_t
5244smbfs_vnop_advlock(struct vnop_advlock_args *ap)
5245{
5246	int		flags = ap->a_flags;
5247	vnode_t vp = ap->a_vp;
5248	struct smb_share *share;
5249	struct smbnode *np;
5250	int error = 0;
5251	uint32_t timo;
5252	off_t start = 0;
5253	uint64_t len = -1;
5254	uint32_t lck_pid;
5255
5256	/* Preflight checks */
5257	if (!vnode_isreg(vp)) {
5258		/* can only read regular files */
5259		if (vnode_isdir(vp))
5260			return (EISDIR);
5261		else
5262			return (EPERM);
5263	}
5264
5265	share = smb_get_share_with_reference(VTOSMBFS(vp));
5266	if ((flags & F_POSIX) && ((UNIX_CAPS(share) & CIFS_UNIX_FCNTL_LOCKS_CAP) == 0)) {
5267		/* Release the share reference before returning */
5268		smb_share_rele(share, ap->a_context);
5269		return(err_advlock(ap));
5270	}
5271	if ((flags & (F_FLOCK | F_POSIX)) == 0) {
5272		/* Release the share reference before returning */
5273		smb_share_rele(share, ap->a_context);
5274		SMBWARNING("Lock flag we do not understand %x\n", flags);
5275		return(err_advlock(ap));
5276	}
5277
5278	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK))) {
5279		/* Release the share reference before returning */
5280		smb_share_rele(share, ap->a_context);
5281		return (error);
5282	}
5283	/* If we got here it must be a flock. Remember flocks lock the whole file. */
5284	np = VTOSMB(vp);
5285	np->n_lastvop = smbfs_vnop_advlock;
5286
5287	/*
5288	 * This vnode has a file open with open deny modes, so the file is really
5289	 * already locked. Remember that vn_open and vn_close will also call us here
5290	 * so to make them work for now, return no err. If the opened it for
5291	 * Open Deny then no one else should be allowed to use it. We could check
5292	 * the pid here, but the open call should have handled that for us.
5293	 */
5294	if (np->f_openDenyList) {
5295		error = 0;
5296		goto exit;
5297	}
5298
5299	/* Before trying the lock see if the file needs to be reopened */
5300	error = smbfs_smb_reopen_file(share, np, ap->a_context);
5301	if (error) {
5302		SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
5303		goto exit;
5304	}
5305
5306	/*
5307	 * So if we got to this point we have a normal flock happening. We can have
5308	 * the following flags passed to us.
5309	 *
5310	 *	LOCK_SH - shared lock
5311	 *	LOCK_EX - exclusive lock
5312	 *	LOCK_NB - don't block when locking
5313	 *	LOCK_UN - unlock
5314	 *
5315	 * Currently we always allow the server handle blocking. We may want to
5316	 * re-look at this later. What if we have a lock that is blocked and
5317	 * the server goes down how long to we wait.
5318	 *
5319	 * The locking mechanism allows two types of locks: shared locks and
5320	 * exclusive locks.  At any time multiple shared locks may be applied to a
5321	 * file, but at no time are multiple exclusive, or both shared and exclusive,
5322	 * locks allowed simultaneously on a file.
5323	 *
5324	 * A shared lock may be upgraded to an exclusive lock, and vice versa, sim-
5325	 * ply by specifying the appropriate lock type; this results in the previous
5326	 * lock being released and the new lock applied (possibly after other processes
5327	 * have gained and released the lock).
5328	 *
5329	 * We currently treat LOCK_EX and LOCK_SH the same except we do not allow
5330	 * you to have more that one LOCK_EX.
5331	*/
5332	timo = (flags & F_WAIT) ? -1 : 0;
5333	/* The problem here is that the lock pid must match the SMB Header PID. Some
5334	 * day it would be nice to pass a better value here. But for now always
5335	 * use the same value.
5336	 */
5337	lck_pid = 1;
5338	/* Remember that we are always using the share open file at this point */
5339	switch(ap->a_op) {
5340	case F_SETLK:
5341		if (! np->f_smbflock) {
5342			error = smbfs_smb_lock(share, SMB_LOCK_EXCL, np->f_fid, lck_pid,
5343								   start, len, timo, ap->a_context);
5344			if (error)
5345				goto exit;
5346			SMB_MALLOC(np->f_smbflock, struct smbfs_flock *, sizeof *np->f_smbflock,
5347				   M_LOCKF, M_WAITOK);
5348			np->f_smbflock->refcnt = 1;
5349			np->f_smbflock->fl_type = ap->a_fl->l_type;
5350			np->f_smbflock->lck_pid = lck_pid;
5351			np->f_smbflock->start = start;
5352			np->f_smbflock->len = len;
5353			np->f_smbflock->flck_pid = proc_pid(vfs_context_proc(ap->a_context));
5354		} else if (np->f_smbflock->flck_pid == (uint32_t)proc_pid(vfs_context_proc(ap->a_context))) {
5355			/* First see if this is a upgrade or downgrade */
5356			if ((np->f_smbflock->refcnt == 1) &&
5357				(np->f_smbflock->fl_type != ap->a_fl->l_type)) {
5358					np->f_smbflock->fl_type = ap->a_fl->l_type;
5359					goto exit;
5360			}
5361			/* Trying to mismatch two different style of locks with the same process id bad! */
5362			if (np->f_smbflock->fl_type != ap->a_fl->l_type) {
5363				error = ENOTSUP;
5364				goto exit;
5365			}
5366			/*
5367			 * We know they have the same lock style from above, but they are
5368			 * asking for two exclusive. So from Terry comments it looks like
5369			 * this is ok.  Here's the issue: because what they are doing is
5370			 * upgrading an exclusive lock to an exclusive lock in the process
5371			 * that holds the previous lock, there are _not_ multiple locks
5372			 * involved; there's only the first lock and the lock that replaces
5373			 * it.
5374			 */
5375			if (np->f_smbflock->fl_type != F_WRLCK) {
5376				/*
5377				 * At no time are multiple exclusive locks allowed simultaneously
5378				 * on a file. So we can have only one refcnt. This is an upgrade
5379				 * not another lock.
5380				 */
5381			} else {
5382				np->f_smbflock->refcnt++;
5383			}
5384		} else {
5385			/*
5386			 * Radar 5572840
5387			 * F_WAIT is set we should sleep until the other flock
5388			 * gets free then to an upgrade or down grade. Not support
5389			 * with SMB yet.
5390			 */
5391			error = EWOULDBLOCK;
5392			goto exit;
5393		}
5394		break;
5395	case F_UNLCK:
5396		error = 0;
5397		if (! np->f_smbflock)	/* Got an  unlock and had no lock ignore */
5398			break;
5399		np->f_smbflock->refcnt--;
5400		/* remove the lock on the network and  */
5401		if (np->f_smbflock->refcnt <= 0) {
5402			error = smbfs_smb_lock(share, SMB_LOCK_RELEASE, np->f_fid, lck_pid,
5403								   start, len, timo, ap->a_context);
5404			if (error == 0) {
5405				SMB_FREE(np->f_smbflock, M_LOCKF);
5406				np->f_smbflock = NULL;
5407			}
5408		}
5409		break;
5410	default:
5411		error = EINVAL;
5412		break;
5413	}
5414exit:
5415	smb_share_rele(share, ap->a_context);
5416	smbnode_unlock(np);
5417	return (error);
5418}
5419
5420/*
5421 * The calling routine must hold a reference on the share
5422 */
5423static int
5424smbfs_pathcheck(struct smb_share *share, const char *name, size_t nmlen,
5425				uint32_t nameiop)
5426{
5427	const char *cp, *endp;
5428	int error;
5429
5430	/*
5431	 * We need to check the file name length. We now use ss_maxfilenamelen
5432	 * since that gives us a more accurate max file name length. If the
5433	 * server supports UNICODE we should do more checking. Since UTF8 can
5434	 * have three bytes per character just checking the length is not enough.
5435	 * We should convert it to UTF16 and see if the length is twice
5436	 * ss_maxfilenamelen.
5437	 *
5438	 */
5439	if ((uint32_t)nmlen > share->ss_maxfilenamelen) {
5440		if (SMB_UNICODE_STRINGS(SSTOVC(share))) {
5441			uint16_t *convbuf;
5442			size_t ntwrk_len;
5443			/*
5444			 * smb_strtouni needs an output buffer that is twice
5445			 * as large as the input buffer (name).
5446			 */
5447            SMB_MALLOC(convbuf, uint16_t *, nmlen * 2, M_SMBNODENAME, M_WAITOK);
5448			if (! convbuf)
5449				return ENAMETOOLONG;
5450			/*
5451			 * We need to get the UFT16 length, so just use smb_strtouni
5452			 * instead of smb_convert_to_network.
5453			 */
5454			ntwrk_len = smb_strtouni(convbuf, name,  nmlen,
5455						UTF_PRECOMPOSED | UTF_SFM_CONVERSIONS);
5456			SMB_FREE(convbuf, M_SMBNODENAME);
5457			if (ntwrk_len > (share->ss_maxfilenamelen * 2))
5458				return ENAMETOOLONG;
5459		} else {
5460			return ENAMETOOLONG;
5461		}
5462	} else if (! nmlen) {
5463		return ENAMETOOLONG;
5464	}
5465
5466	/* Check name only if CREATE, DELETE, or RENAME */
5467	if (nameiop == LOOKUP)
5468		return (0);
5469
5470	/*
5471	 * Winodws systems do not allow items that begin with "con" to be created.
5472	 * If this is not a UNIX server then stop the user from trying
5473	 * to create this file or folder. When trying to create a "con" folder or
5474	 * "con.xxx" file a windows system will report the following error:
5475	 * Cannot create or replace file: The filename you specified is too long.
5476	 * Specify a different filename.
5477	 *
5478	 * From my testing any name that matches "con" or begins with "con."
5479	 * should not be create.
5480	 *
5481	 * Should we be like windows and return ENAMETOOLONG or EACCES
5482	 */
5483	if ((! UNIX_SERVER(SSTOVC(share))) && CON_FILENAME(name, nmlen)) {
5484		if ((nmlen == 3) || ((nmlen > 3) && (*(name+3) == '.')))
5485			return (ENAMETOOLONG);
5486	}
5487
5488	/* If the server supports UNICODE then we are done checking the name. */
5489	if (SMB_UNICODE_STRINGS(SSTOVC(share)))
5490		return (0);
5491
5492	/*
5493	 * Normally, we'd return EINVAL when the name is syntactically invalid,
5494	 * but ENAMETOOLONG makes it clear that the name is the problem (and
5495	 * allows Carbon to return a more meaningful error).
5496	 */
5497	error = ENAMETOOLONG;
5498
5499	/*
5500	 * Note: This code does not prevent the smb file system client
5501	 * from creating filenames which are difficult to use with
5502	 * other clients. For example, you can create "  foo  " or
5503	 * "foo..." which cannot be moved, renamed, or deleted by some
5504	 * other clients.
5505	 */
5506
5507	/* check for illegal characters, if the server does not support UNICODE */
5508	for (cp = name, endp = name + nmlen; cp < endp; ++cp) {
5509		/*
5510		 * The set of illegal characters in long names is the same as
5511		 * 8.3 except the characters 0x20, 0x2b, 0x2c, 0x3b, 0x3d, 0x5b,
5512		 * and 0x5d are now legal, and the restrictions on periods was
5513		 * removed.
5514		 */
5515		switch (*cp) {
5516			case 0x20:	/* space */
5517			case 0x2B:	/* +     */
5518			case 0x2C:	/* ,     */
5519			case 0x3B:	/* ;     */
5520			case 0x3D:	/* =     */
5521			case 0x5B:	/* [     */
5522			case 0x5D:	/* ]     */
5523				break;
5524			case 0x22:	/* "     */
5525			case 0x2A:	/* *     */
5526			case 0x2F:	/* /     */
5527			case 0x3A:	/* :     */
5528			case 0x3C:	/* <     */
5529			case 0x3E:	/* >     */
5530			case 0x3F:	/* ?     */
5531			case 0x5C:	/* \     */
5532			case 0x7C:	/* |     */
5533				/* illegal character found */
5534				return (error);
5535				break;
5536			default:
5537				break;
5538		}
5539	}
5540	return (0);
5541}
5542
5543/*
5544 * smbfs_vnop_lookup
5545 *
5546 * struct vnodeop_desc *a_desc;
5547 * vnode_t a_dvp;
5548 * vnode_t *a_vpp;
5549 * struct componentname *a_cnp;
5550 * vfs_context_t a_context;
5551 */
5552static int
5553smbfs_vnop_lookup(struct vnop_lookup_args *ap)
5554{
5555	vfs_context_t context = ap->a_context;
5556	vnode_t dvp = ap->a_dvp;
5557	vnode_t *vpp = ap->a_vpp;
5558	vnode_t vp;
5559	struct smbnode *dnp = NULL;
5560	struct mount *mp = vnode_mount(dvp);
5561	struct smb_share *share = NULL;
5562	struct componentname *cnp = ap->a_cnp;
5563	const char *name = cnp->cn_nameptr;
5564	uint32_t flags = cnp->cn_flags;
5565	uint32_t nameiop = cnp->cn_nameiop;
5566	size_t nmlen = cnp->cn_namelen;
5567	struct smbfattr fattr, *fap = NULL;
5568	int wantparent, error, islastcn, isdot = FALSE;
5569	int parent_locked = FALSE;
5570
5571	/*
5572	 * We may want to move smbfs_pathcheck here, but we really should never
5573	 * find a bad name in the name cache lookup.
5574	 */
5575	if (!vnode_isdir(dvp))
5576		return (ENOTDIR);
5577	if ((flags & ISDOTDOT) && vnode_isvroot(dvp)) {
5578		SMBFSERR("invalid '..'\n");
5579		return (EIO);
5580	}
5581	islastcn = (flags & ISLASTCN) ? TRUE : FALSE;
5582	if (islastcn && vfs_isrdonly(mp) && nameiop != LOOKUP)
5583		return (EROFS);
5584	wantparent = (flags & (LOCKPARENT|WANTPARENT)) ? TRUE : FALSE;
5585
5586	share = smb_get_share_with_reference(VTOSMBFS(dvp));
5587	/*
5588	 * We need to make sure the negative name cache gets updated if
5589	 * needed. So if the parents cache has expired, then update the
5590	 * the parent's cache. This will cause the negative name cache to
5591	 * be flush if the parent's modify time has changed.
5592	 */
5593	if (smbnode_lock(VTOSMB(dvp), SMBFS_EXCLUSIVE_LOCK) == 0) {
5594		VTOSMB(dvp)->n_lastvop = smbfs_vnop_lookup;
5595		if (VTOSMB(dvp)->n_flag & NNEGNCENTRIES) {
5596			/* ignore any errors here we will catch them later */
5597			(void)smbfs_update_cache(share, dvp, NULL, context);
5598		}
5599		smbnode_unlock(VTOSMB(dvp));	/* Release the smbnode lock */
5600	}
5601
5602	*vpp = NULLVP;
5603	error = cache_lookup(dvp, vpp, cnp);
5604	switch (error) {
5605		case ENOENT:	/* negative cache entry */
5606			goto skipLookup;
5607		case 0:		/* cache miss */
5608			break;
5609		case -1:	/* cache hit */
5610			/*
5611			 * On CREATE we can't trust a cache hit as if it is stale
5612			 * and the object doesn't exist on the server returning zero
5613			 * here would cause the vfs layer to, for instance, EEXIST
5614			 * the mkdir.
5615			 */
5616			if (nameiop != CREATE) {
5617				error = 0;
5618				/* Check to see it the node's meta cache needs to be update */
5619				if (smbnode_lock(VTOSMB(*vpp), SMBFS_EXCLUSIVE_LOCK) == 0) {
5620					VTOSMB(*vpp)->n_lastvop = smbfs_vnop_lookup;
5621					error =  smbfs_update_cache(share, *vpp, NULL, context);
5622					smbnode_unlock(VTOSMB(*vpp));	/* Release the smbnode lock */
5623				}
5624				/*
5625				 * At this point we only care if it exist or not so any other
5626				 * error should just get ignored
5627				 */
5628				if (error != ENOENT) {
5629					error =  0;
5630					goto done;
5631				}
5632				/*
5633				 * The item we had, no longer exists so fall through and see if
5634				 * it exist as a different item
5635				 */
5636			}
5637			if (*vpp) {
5638				cache_purge(*vpp);
5639				vnode_put(*vpp);
5640				*vpp = NULLVP;
5641			}
5642			break;
5643		default:	/* unknown & unexpected! */
5644			SMBWARNING("cache_lookup error=%d\n", error);
5645			goto done;
5646	}
5647	/*
5648	 * entry is not in the name cache
5649	 *
5650	 * validate syntax of name.  ENAMETOOLONG makes it clear the name
5651	 * is the problem
5652	 */
5653	error = smbfs_pathcheck(share, cnp->cn_nameptr, cnp->cn_namelen, nameiop);
5654	if (error) {
5655		SMBWARNING("warning: bad filename %s\n", name);
5656		goto done;
5657	}
5658	dnp = VTOSMB(dvp);
5659
5660	/* lock the parent while we go look for the item on server */
5661	if (smbnode_lock(dnp, SMBFS_EXCLUSIVE_LOCK) != 0) {
5662		error = ENOENT;
5663		goto skipLookup;
5664	}
5665	parent_locked = TRUE;
5666	dnp->n_lastvop = smbfs_vnop_lookup;
5667
5668	isdot = (nmlen == 1 && name[0] == '.');
5669	fap = &fattr;
5670	/*
5671	 * This can allocate a new "name" do not return before the end of the
5672	 * routine from here on.
5673	 */
5674	if (flags & ISDOTDOT) {
5675        /* Lock protects dnp->n_parent. See <rdar://problem/11824956> */
5676        lck_rw_lock_shared(&dnp->n_name_rwlock);
5677		error = smbfs_lookup(share, dnp->n_parent, NULL, NULL, fap, context);
5678        lck_rw_unlock_shared(&dnp->n_name_rwlock);
5679	} else {
5680		error = smbfs_lookup(share, dnp, &name, &nmlen, fap, context);
5681	}
5682	/*
5683	 * We use to unlock the parent here, but we really need it locked
5684	 * until after we do the smbfs_nget calls.
5685	 */
5686	/*
5687	 * We didn't find it and this is not a CREATE or RENAME operation so
5688	 * add it to the negative name cache.
5689	 */
5690	if ((error == ENOENT) && (cnp->cn_flags & MAKEENTRY) &&
5691		(!(((nameiop == CREATE) || (nameiop == RENAME)) && islastcn))) {
5692		/* add a negative entry in the name cache */
5693		cache_enter(dvp, NULL, cnp);
5694		dnp->n_flag |= NNEGNCENTRIES;
5695	}
5696
5697skipLookup:
5698	if (error) {
5699		/*
5700		 * note the EJUSTRETURN code in lookup()
5701		 */
5702		if (((nameiop == CREATE) || (nameiop == RENAME)) &&
5703			(error == ENOENT) && islastcn) {
5704			error = EJUSTRETURN;
5705		}
5706	} else if ((nameiop == RENAME) && islastcn && wantparent) {
5707		if (isdot) {
5708			error = EISDIR;
5709		} else {
5710			error = smbfs_nget(share, mp,
5711                               dvp, name, nmlen,
5712                               fap, &vp,
5713                               0, SMBFS_NGET_CREATE_VNODE,
5714                               context);
5715			if (!error) {
5716				smbnode_unlock(VTOSMB(vp));	/* Release the smbnode lock */
5717				*vpp = vp;
5718			}
5719		}
5720	} else if ((nameiop == DELETE) && islastcn) {
5721		if (isdot) {
5722			error = vnode_get(dvp);
5723			if (!error)
5724				*vpp = dvp;
5725		} else {
5726			error = smbfs_nget(share, mp,
5727                               dvp, name, nmlen,
5728                               fap, &vp,
5729                               0, SMBFS_NGET_CREATE_VNODE,
5730                               context);
5731			if (!error) {
5732				smbnode_unlock(VTOSMB(vp));	/* Release the smbnode lock */
5733				*vpp = vp;
5734			}
5735		}
5736	} else if (flags & ISDOTDOT) {
5737        if (dvp) {
5738            /* Lock protects dvp->n_parent. See <rdar://problem/11824956> */
5739            lck_rw_lock_shared(&VTOSMB(dvp)->n_name_rwlock);
5740            if (VTOSMB(dvp)->n_parent) {
5741                vp = VTOSMB(dvp)->n_parent->n_vnode;
5742                error = vnode_get(vp);
5743                if (!error)
5744                    *vpp = vp;
5745            }
5746            lck_rw_unlock_shared(&VTOSMB(dvp)->n_name_rwlock);
5747        }
5748	} else if (isdot) {
5749		error = vnode_get(dvp);
5750		if (!error)
5751			*vpp = dvp;
5752	} else {
5753		error = smbfs_nget(share, mp,
5754                           dvp, name, nmlen,
5755                           fap, &vp,
5756                           cnp->cn_flags, SMBFS_NGET_CREATE_VNODE,
5757                           context);
5758		if (!error) {
5759			smbnode_unlock(VTOSMB(vp));	/* Release the smbnode lock */
5760			*vpp = vp;
5761		}
5762	}
5763	if (name != cnp->cn_nameptr) {
5764		SMB_FREE(name, M_SMBNODENAME);
5765	}
5766	/* If the parent node is still lock then unlock it here. */
5767	if (parent_locked && dnp)
5768		smbnode_unlock(dnp);
5769done:
5770	smb_share_rele(share, context);
5771	return (error);
5772}
5773
5774/*
5775 * smbfs_vnop_offtoblk
5776 *
5777 * vnode_t a_vp;
5778 * off_t a_offset;
5779 * daddr64_t *a_lblkno;
5780 * vfs_context_t a_context;
5781 *
5782 * ftoblk converts a file offset to a logical block number
5783 */
5784static int
5785smbfs_vnop_offtoblk(struct vnop_offtoblk_args *ap)
5786{
5787	*ap->a_lblkno = ap->a_offset / PAGE_SIZE_64;
5788	return (0);
5789}
5790
5791/*
5792 * smbfs_vnop_blktooff
5793 *
5794 * vnode_t a_vp;
5795 * off_t a_offset;
5796 * daddr64_t *a_lblkno;
5797 * off_t *a_offset;
5798 * vfs_context_t a_context;
5799 *
5800 * blktooff converts a logical block number to a file offset
5801 */
5802static int
5803smbfs_vnop_blktooff(struct vnop_blktooff_args *ap)
5804{
5805	*ap->a_offset = (off_t)ap->a_lblkno * PAGE_SIZE_64;
5806	return (0);
5807}
5808
5809/*
5810 * smbfs_vnop_pagein
5811 *
5812 *  vnode_t 	a_vp,
5813 *  upl_t		a_pl,
5814 *  vm_offset_t	a_pl_offset,
5815 *  off_t		a_f_offset,
5816 *  size_t		a_size,
5817 *  int			a_flags
5818 *  vfs_context_t a_context;
5819 *
5820 * NOTE: We no longer take a node lock in this routine.
5821 */
5822static int
5823smbfs_vnop_pagein(struct vnop_pagein_args *ap)
5824{
5825	vnode_t vp = ap->a_vp;
5826	struct smb_share *share;
5827	size_t size = ap->a_size;
5828	off_t f_offset = ap->a_f_offset;
5829	struct smbnode *np;
5830	int error;
5831
5832	np = VTOSMB(vp);
5833
5834	if ((size <= 0) || (f_offset < 0) || (f_offset >= (off_t)np->n_size) ||
5835		(f_offset & PAGE_MASK_64) || (size & PAGE_MASK)) {
5836		return err_pagein(ap);	/* behave like the deadfs does */
5837	}
5838	share = smb_get_share_with_reference(VTOSMBFS(vp));
5839	/* Before trying the read see if the file needs to be reopened */
5840	error = smbfs_smb_reopen_file(share, np, ap->a_context);
5841	if (error) {
5842		SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
5843		/* Release the share reference before returning */
5844		smb_share_rele(share, ap->a_context);
5845		error = err_pagein(ap);	/* behave like the deadfs does */
5846		return error;
5847	}
5848	/*
5849	 * The old code would check to see if the node smbfsIsCacheable. If not then
5850	 * it would try to invalidate the page to force the cluster code to get a
5851	 * new copy from disk/network. Talked this over with Joe and this is not
5852	 * really need.
5853	 *
5854	 * The smbfs_vnop_pagein will only be called for extents of pages that do
5855	 * NOT already exist in the cache. When the UPL is created, the pages are
5856	 * acquired and locked down for the 'holes' that exist in the cache. Once
5857	 * those pages are locked into the UPL, there can be no other path by which
5858	 * the pages can be made valid. So... no reason to flush pages in the range
5859	 * being passed into you and then on to cluster_pagein.
5860	 */
5861	error = cluster_pagein(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset,
5862						   (int)ap->a_size, (off_t)np->n_size, ap->a_flags);
5863	if (error) {
5864		SMB_LOG_IO("%s failed cluster_pagein with an error of %d\n", np->n_name, error);
5865	}
5866	smb_share_rele(share, ap->a_context);
5867	return (error);
5868}
5869
5870/*
5871 * smbfs_vnop_pageout
5872 *
5873 *  vnode_t 	a_vp,
5874 *  upl_t		a_pl,
5875 *  vm_offset_t	a_pl_offset,
5876 *  off_t		a_f_offset,
5877 *  size_t		a_size,
5878 *  int			a_flags
5879 *  vfs_context_t a_context;
5880 *
5881 * NOTE: We no longer take a node lock in this routine.
5882 *
5883 */
5884static int
5885smbfs_vnop_pageout(struct vnop_pageout_args *ap)
5886{
5887	vnode_t vp = ap->a_vp;
5888	struct smbnode *np;
5889	struct smb_share *share;
5890	upl_t pl = ap->a_pl;
5891	size_t size = ap->a_size;
5892	off_t f_offset = ap->a_f_offset;
5893	int error;
5894
5895	if (vnode_vfsisrdonly(vp))
5896		return(EROFS);
5897
5898	np = VTOSMB(vp);
5899
5900	if (pl == (upl_t)NULL)
5901		panic("smbfs_vnop_pageout: no upl");
5902
5903	if ((size <= 0) || (f_offset < 0) || (f_offset >= (off_t)np->n_size) ||
5904	    (f_offset & PAGE_MASK_64) || (size & PAGE_MASK)) {
5905		return err_pageout(ap);
5906	}
5907	share = smb_get_share_with_reference(VTOSMBFS(vp));
5908	/* Before trying the write see if the file needs to be reopened */
5909	error = smbfs_smb_reopen_file(share, np, ap->a_context);
5910	if (error) {
5911		SMBDEBUG(" %s waiting to be revoked\n", np->n_name);
5912		/* Release the share reference before returning */
5913		smb_share_rele(share, ap->a_context);
5914		return err_pageout(ap);
5915	}
5916
5917	error = cluster_pageout(vp, ap->a_pl, ap->a_pl_offset, ap->a_f_offset,
5918							(int)ap->a_size, (off_t)np->n_size, ap->a_flags);
5919	if (error) {
5920		SMB_LOG_IO("%s failed cluster_pageout with an error of %d\n",
5921				   np->n_name, error);
5922	}
5923
5924	smb_share_rele(share, ap->a_context);
5925	/* If we can get the parent vnode, reset its meta data cache timer. */
5926	if (vnode_isnamedstream(vp)) {
5927		vnode_t parent_vp = vnode_getparent(vp);
5928		if (parent_vp) {
5929			VTOSMB(parent_vp)->attribute_cache_timer = 0;
5930			vnode_put(parent_vp);
5931		}
5932	}
5933	return (error);
5934}
5935
5936/*
5937 * smbfs_vnop_copyfile
5938 *
5939 * vnode_t a_fvp;
5940 * vnode_t a_tdvp;
5941 * vnode_t a_tvp;
5942 * struct componentname *a_tcnp;
5943 * int a_flags;
5944 * vfs_context_t a_context;
5945 */
5946static int
5947smbfs_vnop_copyfile(struct vnop_copyfile_args *ap)
5948{
5949	vnode_t 	fvp = ap->a_fvp;
5950	vnode_t 	tvp = ap->a_tvp;
5951	vnode_t 	tdvp = ap->a_tdvp;
5952	struct smbmount *smp = VFSTOSMBFS(vnode_mount(fvp));
5953	struct smb_share *share = NULL;
5954	struct componentname *tcnp = ap->a_tcnp;
5955	struct smbnode *fnp = NULL;
5956	struct smbnode *tdnp = NULL;
5957	struct smbnode *tnp = NULL;
5958	int error = 0, vtype, need_unlock = 0;
5959
5960    /* VFS checks the following before calling us:
5961     *
5962     * tvp exists AND (ap->flags & CPF_OVERWRITE)
5963     * fvp AND tvp are not directories
5964     * KAUTH_VNODE_ADD_FILE authorized on tdvp
5965     * fvp != tvp
5966     * fvp != tdvp
5967     */
5968
5969    /* Check if this is an SMB2 server (need COPYCHUNK IOCTL) */
5970    share = smb_get_share_with_reference(smp);
5971    if (!SSTOVC(share)->vc_flags & SMBV_SMB2) {
5972        SMBERROR("copyfile not supported on this server.\n");
5973        error = ENOTSUP;
5974        goto out;
5975    }
5976
5977	/* Check for cross-device copyfile */
5978	if ((vnode_mount(fvp) != vnode_mount(tdvp)) ||
5979		(tvp && (vnode_mount(fvp) != vnode_mount(tvp)))) {
5980        SMBERROR("cross-device copyfile not supported.\n");
5981		error = EXDEV;
5982        goto out;
5983    }
5984
5985    /* source file must be a directory, symbolic link, or regular file */
5986	vtype = vnode_vtype(fvp);
5987	if ( (vtype != VDIR) && (vtype != VREG) && (vtype != VLNK) ) {
5988        SMBERROR("copyfile not supported on vtype: %d\n", vtype);
5989		error = EINVAL;
5990        goto out;
5991    }
5992
5993    fnp = VTOSMB(fvp);
5994	tdnp = VTOSMB(tdvp);
5995    tnp = (tvp == NULL) ? NULL : VTOSMB(tvp);
5996
5997    /* Lock source file and target directory */
5998    smbnode_lockpair(fnp, tdnp, SMBFS_EXCLUSIVE_LOCK);
5999    need_unlock = 1;
6000
6001	fnp->n_lastvop = smbfs_vnop_copyfile;
6002	tdnp->n_lastvop = smbfs_vnop_copyfile;
6003	if (tnp != NULL)
6004		tnp->n_lastvop = smbfs_vnop_copyfile;
6005
6006	/*
6007	 * Do the copyfile operation.
6008	 */
6009    error = smb2fs_smb_copyfile(share, fnp, tdnp, tcnp->cn_nameptr,
6010                                tcnp->cn_namelen, ap->a_context);
6011    if (error) {
6012        SMBERROR("smb2fs_smb_copyfile returned: %d\n", error);
6013        goto out;
6014    }
6015
6016	smbfs_attr_touchdir(tdnp, (share->ss_fstype == SMB_FS_FAT));
6017
6018	/* blow away statfs cache */
6019    smp->sm_statfstime = 0;
6020
6021    /* Invalidate negative cache entries in destination dir */
6022    if (tdnp->n_flag & NNEGNCENTRIES) {
6023        tdnp->n_flag &= ~NNEGNCENTRIES;
6024        cache_purge_negatives(tdvp);
6025    }
6026
6027out:
6028	/* We only have a share if we obtain a reference on it, so release it */
6029	if (share) {
6030		smb_share_rele(share, ap->a_context);
6031	}
6032
6033    if (need_unlock) {
6034        smbnode_unlockpair(fnp, tdnp);
6035    }
6036
6037	return (error);
6038}
6039
6040static uint32_t emptyfinfo[8] = {0};
6041/*
6042 * DefaultFillAfpInfo
6043 *
6044 * Given a buffer fill in the default AfpInfo values.
6045 */
6046static void
6047DefaultFillAfpInfo(uint8_t *afpinfo)
6048{
6049	int ii = 0;
6050	bzero(afpinfo, AFP_INFO_SIZE);
6051		/* Signature is a DWORD. Must be *(PDWORDD)"AFP" */
6052	afpinfo[ii++] = 'A';
6053	afpinfo[ii++] = 'F';
6054	afpinfo[ii++] = 'P';
6055	afpinfo[ii++] = 0;
6056		/* Version is a DWORD. Must be 0x00010000 (byte swapped) */
6057	afpinfo[ii++] = 0;
6058	afpinfo[ii++] = 0;
6059	afpinfo[ii++] = 0x01;
6060	afpinfo[ii++] = 0;
6061		/* Reserved1 is a DWORD */
6062	ii += 4;
6063	/*
6064	 * Backup time is a DWORD. Backup time for the file/dir. Not set equals
6065	 * 0x80010000 (byte swapped)
6066	 */
6067	afpinfo[ii++] = 0;
6068	afpinfo[ii++] = 0;
6069	afpinfo[ii++] = 0;
6070	afpinfo[ii] = 0x80;
6071	/* Finder Info is 32 bytes. Calling process fills this in */
6072	/* ProDos Info is 6 bytes. Leave set to zero? */
6073	/* Reserved2 is 6 bytes */
6074}
6075
6076/*
6077 * xattr2sfm
6078 *
6079 * See if this xattr is really the resource fork or the finder info stream. If so
6080 * return the correct streams name otherwise just return the name passed to us.
6081 */
6082static const char *
6083xattr2sfm(const char *xa, enum stream_types *stype)
6084{
6085	/* Never let them use the SFM Stream Names */
6086	if (!bcmp(xa, SFM_RESOURCEFORK_NAME, sizeof(SFM_RESOURCEFORK_NAME))) {
6087		return(NULL);
6088	}
6089	if (!bcmp(xa, SFM_FINDERINFO_NAME, sizeof(SFM_FINDERINFO_NAME))) {
6090		return(NULL);
6091	}
6092	if (!bcmp(xa, SFM_DESKTOP_NAME, sizeof(SFM_DESKTOP_NAME))) {
6093		return(NULL);
6094	}
6095	if (!bcmp(xa, SFM_IDINDEX_NAME, sizeof(SFM_IDINDEX_NAME))) {
6096		return(NULL);
6097	}
6098
6099	if (!bcmp(xa, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME))) {
6100		*stype = kResourceFrk;
6101		return (SFM_RESOURCEFORK_NAME);
6102	}
6103	if (!bcmp(xa, XATTR_FINDERINFO_NAME, sizeof(XATTR_FINDERINFO_NAME))) {
6104		*stype = kFinderInfo;
6105		return (SFM_FINDERINFO_NAME);
6106	}
6107	*stype = kExtendedAttr;
6108	return (xa);
6109}
6110
6111/*
6112 * smbfs_vnop_setxattr
6113 *
6114 *	vnode_t a_vp;
6115 *	int8_t * a_name;
6116 *	uio_t a_uio;
6117 *	int32_t a_options;
6118 *	vfs_context_t a_context;
6119 */
6120static int
6121smbfs_vnop_setxattr(struct vnop_setxattr_args *ap)
6122{
6123	vnode_t vp = ap->a_vp;
6124	const char *sfmname;
6125	int error = 0;
6126	SMBFID fid = 0;
6127	uint32_t rights = SMB2_FILE_WRITE_DATA;
6128	struct smbnode *np = NULL;
6129	struct smb_share *share = NULL;
6130	enum stream_types stype = kNoStream;
6131	uint32_t	open_disp = 0;
6132	uio_t		afp_uio = NULL;
6133	uint8_t	afpinfo[60];
6134	struct smbfattr fattr;
6135
6136	DBG_ASSERT(!vnode_isnamedstream(vp));
6137
6138	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
6139		return (error);
6140	np = VTOSMB(vp);
6141	np->n_lastvop = smbfs_vnop_setxattr;
6142	share = smb_get_share_with_reference(VTOSMBFS(vp));
6143
6144	/*
6145	 * FILE_NAMED_STREAMS tells us the server supports streams.
6146	 * NOTE: This flag may have been overwriten by us in smbfs_mount. The default
6147	 * is for streams to be turn off. See the smbfs_mount for more details.
6148	 */
6149	if (!(share->ss_attributes & FILE_NAMED_STREAMS)) {
6150		error = ENOTSUP;
6151		goto exit;
6152	}
6153
6154	/* You cant have both of these set at the same time. */
6155	if ( (ap->a_options & XATTR_CREATE) && (ap->a_options & XATTR_REPLACE) ) {
6156		error = EINVAL;
6157		goto exit;
6158	}
6159
6160	/* SMB doesn't support having a slash in the xattr name */
6161	if (strchr(ap->a_name, '/')) {
6162		error = EINVAL;
6163		SMBWARNING("Slash in xattr name not allowed: error %d %s:%s\n", error,
6164				   np->n_name, ap->a_name);
6165		goto exit;
6166	}
6167	sfmname = xattr2sfm(ap->a_name, &stype);
6168	if (!sfmname) {
6169		error = EINVAL;
6170		goto exit;
6171	}
6172
6173	/*
6174	 * Need to add write attributes if we want to reset the modify time. We never do this
6175	 * for the resource fork. The file manager expects the modify time to change if the
6176	 * resource fork changes.
6177	 */
6178	if ((stype & kResourceFrk) != kResourceFrk)
6179		rights |= SMB2_FILE_WRITE_ATTRIBUTES;
6180
6181	/*
6182	 * We treat finder info differently than any other EA/Stream. Because of
6183	 * SFM we need to do things a little different. Remember the AFPInfo stream
6184	 * has more information in it than just the finder info. WARNING: SFM can
6185	 * get very confused if you do not handle this correctly!
6186	 */
6187	if (stype & kFinderInfo) {
6188		uint8_t finfo[FINDERINFOSIZE];
6189		time_t attrtimeo;
6190		struct timespec ts;
6191		size_t sizep;
6192		int len = (int)uio_resid(ap->a_uio);
6193
6194		/* Can't be larger that 32 bytes */
6195		if (len > FINDERINFOSIZE) {
6196			error = EINVAL;
6197			goto exit;
6198		}
6199		error = uiomove((void *)finfo, len, ap->a_uio);
6200		if (error)
6201			goto exit;
6202		SMB_CACHE_TIME(ts, np, attrtimeo);
6203		/*
6204		 * The Finder Info cache hasn't expired so check to see if they are
6205		 * setting it to something different or the same. If the same then skip
6206		 * setting it, this is what AFP does.
6207		 */
6208		if ((ts.tv_sec - np->finfo_cache) <= attrtimeo) {
6209			if (bcmp(np->finfo, finfo, sizeof(finfo)) == 0)
6210				goto exit;
6211		}
6212		/* We want to read also in this case.  */
6213		rights |= SMB2_FILE_READ_DATA;
6214		/* Create a dummy uio structure */
6215		afp_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
6216		if (afp_uio)
6217			error = uio_addiov( afp_uio, CAST_USER_ADDR_T(afpinfo), sizeof(afpinfo));
6218		else
6219			error = ENOMEM;
6220		if (error)
6221			goto exit;
6222		/* Now set the default afp info buffer */
6223		DefaultFillAfpInfo(afpinfo);
6224		/* Open and read the data in, if an empty file we will still get an fid */
6225		error = smbfs_smb_openread(share, np, &fid, rights, afp_uio, &sizep,
6226								   sfmname, &ts, ap->a_context);
6227		/* Replace the finder info with the data that was passed down. */
6228		if (!error) {
6229			bcopy((void *)finfo, (void *)&afpinfo[AFP_INFO_FINDER_OFFSET], len);
6230			uio_reset(afp_uio, 0, UIO_SYSSPACE, UIO_WRITE );
6231			error = uio_addiov( afp_uio, CAST_USER_ADDR_T(afpinfo), sizeof(afpinfo));
6232		}
6233		if (error)
6234			goto out;
6235		/* Truncate the stream if there is anything in it, this will wake up SFM */
6236		if (sizep && (VTOSMBFS(vp)->sm_flags & MNT_IS_SFM_VOLUME))	{
6237			 /* Ignore any errors, write will catch them */
6238			(void)smbfs_smb_seteof(share, fid, 0, ap->a_context);
6239		}
6240		/* Now we can write the afp info back out with the new finder information */
6241		if (!error) {
6242			error = smb_smb_write(share, fid, afp_uio, 0, ap->a_context);
6243		}
6244		/*
6245		 * Try to set the modify time back to the original time, ignore any
6246		 * errors. Since we are using the open stream file descriptor to change
6247		 * the time remove the directory attribute bit if set.
6248		 */
6249		(void)smbfs_smb_setfattrNT(share, (np->n_dosattr & ~SMB_EFA_DIRECTORY),
6250								   fid, NULL, &ts, NULL, ap->a_context);
6251		/* Reset our cache timer and copy the new data into our cache */
6252		if (!error) {
6253			nanouptime(&ts);
6254			np->finfo_cache = ts.tv_sec;
6255			bcopy((void *)&afpinfo[AFP_INFO_FINDER_OFFSET], np->finfo,
6256				  sizeof(np->finfo));
6257		}
6258		goto out;
6259	}
6260
6261	switch(ap->a_options & (XATTR_CREATE | XATTR_REPLACE)) {
6262		case XATTR_CREATE:	/* set the value, fail if attr already exists */
6263            /* if exists fail else create it */
6264			open_disp = FILE_CREATE;
6265			break;
6266		case XATTR_REPLACE:	/* set the value, fail if attr does not exist */
6267            /* if exists overwrite item else fail */
6268			open_disp = FILE_OVERWRITE;
6269			break;
6270		default:
6271			if ((stype & kResourceFrk) == kResourceFrk) {
6272				/* if resource fork then if it exists open it else create it */
6273				open_disp = FILE_OPEN_IF;
6274			} else {
6275				/* if anything else then if it exists overwrite it else create it */
6276				open_disp = FILE_OVERWRITE_IF;
6277			}
6278			break;
6279	}
6280	/* Open/create the stream */
6281	error = smbfs_smb_create(share, np, sfmname,
6282							 strnlen(sfmname, share->ss_maxfilenamelen+1),
6283							 rights, &fid, open_disp, 1, &fattr, ap->a_context);
6284	if (error) {
6285		goto exit;
6286	}
6287	/* Now write out the stream data */
6288	error = smb_smb_write(share, fid, ap->a_uio, 0, ap->a_context);
6289	/*
6290	 * %%%
6291	 * Should we reset the modify time back to the original time? Never for the
6292	 * resource fork, but what about EAs? Could be a performance issue, really
6293	 * need a clearer message from the rest of the file system team.
6294	 *
6295	 * For now try to set the modify time back to the original time, ignore any
6296	 * errors. Since we are using the open stream file descriptor to change the
6297	 * time remove the directory attribute bit if set.
6298	 */
6299	if ((stype & kResourceFrk) != kResourceFrk) {
6300		(void)smbfs_smb_setfattrNT(share, (np->n_dosattr & ~SMB_EFA_DIRECTORY),
6301								   fid, NULL, &np->n_mtime, NULL, ap->a_context);
6302	}
6303
6304out:
6305	if (fid != 0) {
6306		(void)smbfs_smb_close(share, fid, ap->a_context);
6307    }
6308
6309exit:
6310	if (afp_uio)
6311		uio_free(afp_uio);
6312
6313	if (error == ENOENT)
6314		error = ENOATTR;
6315
6316	/* Check to see if its a normal error */
6317	if (error && (error != ENOTSUP) && (error != ENOATTR)) {
6318		SMBWARNING("error %d %s:%s\n", error, np->n_name, ap->a_name);
6319		/* Always make sure its a legit error, see man listxattr */
6320		if ((error != EROFS) && (error != EPERM) && (error != EINVAL) &&
6321			(error != ENOTDIR) && (error != EACCES) && (error != ELOOP) &&
6322			(error != EFAULT) && (error != EIO) && (error != ENAMETOOLONG) &&
6323			(error != EEXIST) && (error != ERANGE) &&
6324			(error != E2BIG) && (error != ENOSPC))
6325			error = EIO;	/* Not sure what else to do here */
6326	}
6327	if (!error) {
6328		/* We create a named stream, so remove the no stream flag  */
6329		np->n_fstatus &= ~kNO_SUBSTREAMS;
6330	}
6331	smb_share_rele(share, ap->a_context);
6332	smbnode_unlock(np);
6333	return (error);
6334}
6335
6336/*
6337 * smbfs_vnop_listxattr
6338 *
6339 *	vnode_t a_vp;
6340 *	uio_t a_uio;
6341 *	size_t *a_size;
6342 *	int32_t a_options;
6343 *	vfs_context_t a_context;
6344 */
6345static int
6346smbfs_vnop_listxattr(struct vnop_listxattr_args *ap)
6347{
6348	vnode_t vp = ap->a_vp;
6349	uio_t uio = ap->a_uio;
6350	size_t *sizep = ap->a_size;
6351	struct smbnode *np = NULL;
6352	struct smb_share *share = NULL;
6353	int error = 0;
6354    uint32_t stream_flags = 0;
6355
6356	DBG_ASSERT(!vnode_isnamedstream(vp));
6357
6358	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
6359		return (error);
6360	np = VTOSMB(vp);
6361	np->n_lastvop = smbfs_vnop_listxattr;
6362	share = smb_get_share_with_reference(VTOSMBFS(vp));
6363	/*
6364	 * FILE_NAMED_STREAMS tells us the server supports streams.
6365	 * NOTE: This flag may have been overwriten by us in smbfs_mount. The default
6366	 * is for streams to be turn off. See the smbfs_mount for more details.
6367	 */
6368	if (!(share->ss_attributes & FILE_NAMED_STREAMS)) {
6369		error = ENOTSUP;
6370		goto exit;
6371	}
6372	if (np->n_fstatus & kNO_SUBSTREAMS) {
6373		error = ENOATTR;
6374		goto exit;
6375	}
6376	error = smbfs_smb_qstreaminfo(share, np,
6377                                  NULL, 0,
6378                                  NULL,
6379                                  uio, sizep,
6380                                  NULL, NULL,
6381                                  &stream_flags, NULL,
6382                                  ap->a_context);
6383
6384exit:
6385
6386	/*
6387	 * From the man pages: If no accessible extended attributes are associated
6388	 * with the given path or fd, the function returns zero.
6389	*/
6390	if (error == ENOATTR)
6391		error = 0;
6392
6393	/* Check to see if its a normal error */
6394	if (error && (error != ENOTSUP)) {
6395		SMBWARNING("error %d %s\n", error, np->n_name);
6396		/* Always make sure its a legit error, see man listxattr */
6397		if ((error != ERANGE) && (error != EPERM) && (error != EINVAL) &&
6398			(error != ENOTDIR) && (error != EACCES) && (error != ELOOP) &&
6399			(error != EFAULT) && (error != EIO))
6400			error = 0;	/* Just pretend it doesn't exist */
6401	}
6402	smb_share_rele(share, ap->a_context);
6403	smbnode_unlock(np);
6404	return (error);
6405}
6406
6407/*
6408 * vnop_removexattr_args
6409 *
6410 *	vnode_t a_vp;
6411 *	int8_t * a_name;
6412 *	int32_t a_options;
6413 *	vfs_context_t a_context;
6414 */
6415static int
6416smbfs_vnop_removexattr(struct vnop_removexattr_args *ap)
6417{
6418	vnode_t vp = ap->a_vp;
6419	const char *sfmname;
6420	int error = 0, saved_error = 0;
6421	struct smbnode *np = NULL;
6422	struct smb_share *share = NULL;
6423	enum stream_types stype = kNoStream;
6424	struct timespec ts;
6425
6426	DBG_ASSERT(!vnode_isnamedstream(vp));
6427
6428	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
6429		return (error);
6430	np = VTOSMB(vp);
6431	np->n_lastvop = smbfs_vnop_removexattr;
6432	share = smb_get_share_with_reference(VTOSMBFS(vp));
6433	/*
6434	 * FILE_NAMED_STREAMS tells us the server supports streams.
6435	 * NOTE: This flag may have been overwriten by us in smbfs_mount. The default
6436	 * is for streams to be turn off. See the smbfs_mount for more details.
6437	 */
6438	if (!(share->ss_attributes & FILE_NAMED_STREAMS)) {
6439		error = ENOTSUP;
6440		goto exit;
6441	}
6442
6443	/* SMB doesn't support having a slash in the xattr name */
6444	if (strchr(ap->a_name, '/')) {
6445		error = EINVAL;
6446		SMBWARNING("Slash in xattr name not allowed: error %d %s:%s\n", error,
6447				   np->n_name, ap->a_name);
6448		goto exit;
6449	}
6450
6451	sfmname = xattr2sfm(ap->a_name, &stype);
6452	if (!sfmname) {
6453		error = EINVAL;
6454		goto exit;
6455	}
6456
6457	if (stype & kFinderInfo) {
6458		if (VTOSMBFS(vp)->sm_flags & MNT_IS_SFM_VOLUME) {
6459			/*
6460			 * We do not allow them to remove the finder info stream on SFM
6461			 * Volume. It could hold other information used by SFM.
6462			 */
6463			error = ENOTSUP;
6464		} else {
6465			/*
6466			 * If the volume is just a normal NTFS Volume then deleting the named
6467			 * stream should be ok, but some servers (EMC) don't support deleting
6468			 * the named stream. In this case see if we can just zero out the
6469			 * finder info.
6470			 */
6471			error = smbfs_smb_delete(share, np, sfmname,
6472									 strnlen(sfmname, share->ss_maxfilenamelen+1),
6473                                     1, ap->a_context);
6474		}
6475		/* SFM server or the server doesn't support deleting named streams */
6476		if (error) {
6477			uio_t afp_uio = NULL;
6478			uint8_t	afpinfo[60];
6479			SMBFID fid = 0;
6480			uint32_t rights = SMB2_FILE_WRITE_DATA | SMB2_FILE_READ_DATA | SMB2_FILE_WRITE_ATTRIBUTES;
6481
6482			/*
6483			 * Either a SFM volume or the server doesn't support deleting named
6484			 * streams. Try to zero out the finder info data.
6485			 */
6486            saved_error = error; /* save original failure error */
6487
6488			afp_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
6489			if (!afp_uio) {
6490				error = saved_error;
6491				goto exit;
6492			}
6493			error = uio_addiov( afp_uio, CAST_USER_ADDR_T(afpinfo), sizeof(afpinfo));
6494			if (error) {
6495				uio_free(afp_uio);
6496				error = saved_error;
6497				goto exit;
6498			}
6499
6500			/* open and read the data */
6501			error = smbfs_smb_openread(share, np, &fid, rights, afp_uio, NULL,
6502									   sfmname, &ts, ap->a_context);
6503			/* clear out the finder info data */
6504			bzero(&afpinfo[AFP_INFO_FINDER_OFFSET], FINDERINFOSIZE);
6505
6506			if (!error)	{
6507                /* truncate the stream, this will wake up SFM */
6508				error = smbfs_smb_seteof(share, fid, 0, ap->a_context);
6509            }
6510			/* Reset our uio */
6511			if (!error) {
6512				uio_reset(afp_uio, 0, UIO_SYSSPACE, UIO_WRITE );
6513				error = uio_addiov( afp_uio, CAST_USER_ADDR_T(afpinfo), sizeof(afpinfo));
6514			}
6515
6516			if (!error)
6517				error = smb_smb_write(share, fid, afp_uio, 0, ap->a_context);
6518            if (error) {
6519				error = saved_error; /* restore original error */
6520            }
6521
6522			/* Try to set the modify time back to the original time, ignore any errors */
6523			(void)smbfs_smb_setfattrNT(share, np->n_dosattr, fid, NULL, &ts,
6524									   NULL, ap->a_context);
6525			if (fid != 0)
6526				(void)smbfs_smb_close(share, fid, ap->a_context);
6527			if (afp_uio) {
6528				uio_free(afp_uio);
6529			}
6530		}
6531	} else {
6532		error = smbfs_smb_delete(share, np, sfmname,
6533								 strnlen(sfmname, share->ss_maxfilenamelen+1),
6534                                 1, ap->a_context);
6535	}
6536
6537	/* Finder info so reset our cache timer and zero out our cache */
6538	if ((stype & kFinderInfo) && !error) {
6539		nanouptime(&ts);
6540		np->finfo_cache = ts.tv_sec;
6541		bzero(np->finfo, sizeof(np->finfo));
6542	}
6543
6544exit:
6545
6546	if (error == ENOENT)
6547		error = ENOATTR;
6548
6549	/* Check to see if its a normal error */
6550	if (error && (error != ENOTSUP) && (error != ENOATTR)) {
6551		SMBWARNING("error %d %s:%s\n", error, np->n_name, ap->a_name);
6552		/* Always make sure its a legit error, see man listxattr */
6553		if ((error != EROFS) && (error != EPERM) && (error != EINVAL) &&
6554			(error != ENOTDIR) && (error != EACCES) && (error != ELOOP) &&
6555			(error != EFAULT) && (error != EIO) && (error != ENAMETOOLONG))
6556			error = ENOATTR;	/* Not sure what else to do here */
6557	}
6558	smb_share_rele(share, ap->a_context);
6559	smbnode_unlock(np);
6560	return (error);
6561}
6562
6563/*
6564 * smbfs_vnop_getxattr
6565 *
6566 *	vnode_t a_vp;
6567 *	int8_t * a_name;
6568 *	uio_t a_uio;
6569 *	size_t *a_size;
6570 *	int32_t a_options;
6571 *	vfs_context_t a_context;
6572 */
6573static int
6574smbfs_vnop_getxattr(struct vnop_getxattr_args *ap)
6575{
6576	vnode_t vp = ap->a_vp;
6577	const char *sfmname;
6578	uio_t uio = ap->a_uio;
6579	size_t *sizep = ap->a_size;
6580	SMBFID fid = 0;
6581	int error = 0;
6582	struct smbnode *np = NULL;
6583	struct smb_share *share = NULL;
6584	size_t rq_resid = (uio) ? (size_t)uio_resid(uio) : 0;
6585	uio_t afp_uio = NULL;
6586	enum stream_types stype = kNoStream;
6587	struct timespec ts;
6588	time_t attrtimeo;
6589    uint32_t stream_flags = 0;
6590
6591	DBG_ASSERT(!vnode_isnamedstream(vp));
6592
6593	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
6594		return (error);
6595	np = VTOSMB(vp);
6596	np->n_lastvop = smbfs_vnop_getxattr;
6597	share = smb_get_share_with_reference(VTOSMBFS(vp));
6598	/*
6599	 * FILE_NAMED_STREAMS tells us the server supports streams.
6600	 * NOTE: This flag may have been overwriten by us in smbfs_mount. The default
6601	 *	 is for streams to be turn off. See the smbfs_mount for more details.
6602	 */
6603	if (!(share->ss_attributes & FILE_NAMED_STREAMS)) {
6604		error = ENOTSUP;
6605		goto exit;
6606	}
6607
6608	/* SMB doesn't support having a slash in the xattr name */
6609	if (strchr(ap->a_name, '/')) {
6610		error = ENOTSUP;
6611		SMBWARNING("Slash in xattr name not allowed: error %d %s:%s\n", error,
6612				   np->n_name, ap->a_name);
6613		goto exit;
6614	}
6615	if (np->n_fstatus & kNO_SUBSTREAMS) {
6616		error = ENOATTR;
6617		goto exit;
6618	}
6619
6620	sfmname = xattr2sfm(ap->a_name, &stype);
6621	if (!sfmname) {
6622		error = EINVAL;
6623		goto exit;
6624	}
6625
6626	/*
6627	 * They just want the size of the stream. */
6628	if ((uio == NULL) && !(stype & kFinderInfo)) {
6629		uint64_t strmsize = 0;
6630		uint64_t strm_alloc_size = 0;
6631
6632		if (stype & kResourceFrk) {
6633			error = smb_get_rsrcfrk_size(share, vp, ap->a_context);
6634			lck_mtx_lock(&np->rfrkMetaLock);
6635			 /* The node's rfork size will have the correct value at this point */
6636			strmsize = np->rfrk_size;
6637			lck_mtx_unlock(&np->rfrkMetaLock);
6638		}
6639        else {
6640			error = smbfs_smb_qstreaminfo(share, np,
6641                                          NULL, 0,
6642                                          sfmname,
6643                                          NULL, NULL,
6644                                          &strmsize, &strm_alloc_size,
6645                                          &stream_flags, NULL,
6646                                          ap->a_context);
6647		}
6648		if (sizep)
6649			*sizep = (size_t)strmsize;
6650		if (error)
6651			error = ENOATTR;
6652		goto exit;
6653	}
6654
6655	/*
6656	 * We treat finder info differently than any other EA/Stream. Because of SFM
6657	 * we need to do things a little different. Remember the AFPInfo stream has
6658	 * more information in it than just the finder info. WARNING: SFM can get
6659	 * very confused if you do not handle this correctly!
6660	 */
6661	if (stype & kFinderInfo) {
6662		SMB_CACHE_TIME(ts, np, attrtimeo);
6663		/* Cache has expired go get the finder information. */
6664		if ((ts.tv_sec - np->finfo_cache) > attrtimeo) {
6665			size_t afpsize = 0;
6666			uint8_t	afpinfo[60];
6667
6668			afp_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
6669			if (afp_uio)
6670				error = uio_addiov( afp_uio, CAST_USER_ADDR_T(afpinfo),
6671								   sizeof(afpinfo));
6672			else error = ENOMEM;
6673
6674			if (error)
6675				goto exit;
6676
6677			uio_setoffset(afp_uio, 0);
6678			/* open and read the data */
6679			error = smbfs_smb_openread(share, np, &fid, SMB2_FILE_READ_DATA,
6680									   afp_uio, &afpsize, sfmname, NULL,
6681									   ap->a_context);
6682			/* Should never happen but just in case */
6683			if (afpsize != AFP_INFO_SIZE)
6684				error = ENOENT;
6685
6686			if (error == ENOENT) {
6687				bzero(np->finfo, sizeof(np->finfo));
6688			} else {
6689				bcopy((void *)&afpinfo[AFP_INFO_FINDER_OFFSET], np->finfo,
6690					  sizeof(np->finfo));
6691			}
6692			if (vnode_isreg(vp) && (bcmp(np->finfo, "brokMACS", 8) == 0)) {
6693				np->finfo_cache = 0;
6694				SMBDEBUG("Don't cache finder info, we have a finder copy in progress\n");
6695			} else {
6696				nanouptime(&ts);
6697				np->finfo_cache = ts.tv_sec;
6698			}
6699		}
6700		/* If the finder info is all zero hide it, except if its a SFM volume */
6701		if ((!(VTOSMBFS(vp)->sm_flags & MNT_IS_SFM_VOLUME)) &&
6702			(bcmp(np->finfo, emptyfinfo, sizeof(emptyfinfo)) == 0)) {
6703				error = ENOENT;
6704		}
6705		if (uio && !error) {
6706			error = uiomove((const char *)np->finfo, (int)sizeof(np->finfo), ap->a_uio);
6707		}
6708		if (sizep && !error)
6709			*sizep = FINDERINFOSIZE;
6710	} else {
6711		error = smbfs_smb_openread(share, np, &fid, SMB2_FILE_READ_DATA, uio,
6712								   sizep, sfmname, NULL, ap->a_context);
6713	}
6714	 /* If ENOTSUP support is returned then do the open and read in two transactions.  */
6715	if (error != ENOTSUP)
6716		goto out;
6717
6718	/*
6719	 * May need to add an oplock to this open call, if this is a finder info open.
6720	 * Not sure I remember the exact details, something about deletes.
6721	 */
6722	error = smbfs_smb_open_xattr(share, np, SMB2_FILE_READ_DATA,
6723								 NTCREATEX_SHARE_ACCESS_ALL, &fid,
6724								 sfmname, sizep, ap->a_context);
6725	if (error)
6726		goto exit;
6727
6728	/*
6729	 * When reading finder-info, munge the uio so we read at offset 16 where the
6730	 * actual finder info is located. Also ensure we don't read past the 32 bytes,
6731	 * of finder info. Since we are just reading we really don't care about the
6732	 * rest of the data.
6733	 * This is only here in case a server does not support the chain message above.
6734	 * We do not cache in this case. Should never happen, but just to be safe.
6735	 */
6736	if (stype & kFinderInfo) {
6737		user_ssize_t r;
6738
6739		if (sizep)
6740			*sizep = FINDERINFOSIZE;
6741		/* Just wanted the size get out */
6742		if (uio == NULL)
6743			goto out;
6744
6745		r = uio_resid(uio);
6746		if (uio_offset(uio) >= FINDERINFOSIZE) {
6747			uio_setresid(uio, 0);
6748		} else if (uio_offset(uio) + r > FINDERINFOSIZE)
6749		uio_setresid(uio, FINDERINFOSIZE - uio_offset(uio));
6750		r = r - uio_resid(uio);
6751		uio_setoffset(uio, uio_offset(uio) + 4*4);
6752
6753		error = smb_smb_read(share, fid, uio, ap->a_context);
6754
6755		uio_setoffset(uio, uio_offset(uio) - 4*4);
6756		uio_setresid(uio, uio_resid(uio) + r);
6757	}
6758	else error = smb_smb_read(share, fid, uio, ap->a_context);
6759
6760out:;
6761	if (uio && sizep && (*sizep > rq_resid))
6762			error = ERANGE;
6763
6764    /* Even an error can leave the file open. */
6765	if (fid != 0)
6766		(void)smbfs_smb_close(share, fid, ap->a_context);
6767exit:
6768	/*
6769	 * So ENOENT just means ENOATTR.
6770	 * Note: SAMBA 4 will reutrn EISDIR for folders which is legit, but not
6771	 * expected by the finder
6772	 */
6773	if ((error == ENOENT) || ((error == EISDIR) && (stype & kFinderInfo)))
6774		error = ENOATTR;
6775
6776	if (afp_uio)
6777		uio_free(afp_uio);
6778
6779	/* Check to see if its a normal error */
6780	if (error && (error != ENOTSUP) && (error != ENOATTR)) {
6781		SMBWARNING("error %d %s:%s\n", error, np->n_name, ap->a_name);
6782		/* Nope make sure its a legit error, see man getxattr */
6783		if ((error != ERANGE) && (error != EPERM) && (error != EINVAL) &&
6784			(error != EISDIR) && (error != ENOTDIR) && (error != EACCES) &&
6785			(error != ELOOP) && (error != EFAULT) && (error != EIO))
6786			error = ENOATTR;
6787	}
6788	smb_share_rele(share, ap->a_context);
6789	smbnode_unlock(np);
6790	return (error);
6791}
6792
6793/*
6794 * smbfs_vnop_getnamedstream - Obtain the vnode for a stream.
6795 *
6796 *	vnode_t a_vp;
6797 *	vnode_t *a_svpp;
6798 *	const char *a_name;
6799	enum nsoperation a_operation; (NS_OPEN, NS_CREATE, NS_DELETE)
6800 *	vfs_context_t a_context;
6801 *
6802 */
6803static int
6804smbfs_vnop_getnamedstream(struct vnop_getnamedstream_args* ap)
6805{
6806	struct smb_share *share;
6807	vnode_t vp = ap->a_vp;
6808	vnode_t *svpp = ap->a_svpp;
6809	const char * streamname = ap->a_name;
6810	const char * sname = ap->a_name;
6811	struct smbnode *np = NULL;
6812	int error = 0;
6813	uint64_t strmsize = 0;
6814	uint64_t strm_alloc_size = 0;
6815	struct smbfattr fattr;
6816	struct vnode_attr vap;
6817	struct timespec ts;
6818	time_t attrtimeo;
6819	struct timespec reqtime;
6820    uint32_t stream_flags = 0;
6821
6822	/* Lock the parent while we look for the stream */
6823	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
6824		return (error);
6825
6826	nanouptime(&reqtime);
6827	np = VTOSMB(vp);
6828	np->n_lastvop = smbfs_vnop_getnamedstream;
6829	share = smb_get_share_with_reference(VTOSMBFS(vp));
6830
6831	*svpp = NULL;
6832	/* Currently we only support the "com.apple.ResourceFork" stream. */
6833	if (bcmp(streamname, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
6834		SMBDEBUG("Wrong stream %s:$%s\n", np->n_name, streamname);
6835		error = ENOATTR;
6836		goto exit;
6837	} else {
6838	    sname = SFM_RESOURCEFORK_NAME;	/* This is the resource stream use the SFM name */
6839	}
6840	if ( !vnode_isreg(vp) ) {
6841		SMBDEBUG("%s not a file (EPERM)\n",  np->n_name);
6842		error = EPERM;
6843		goto exit;
6844	}
6845
6846	/*
6847	 * %%%
6848	 * Since we have the parent node update its meta cache. Remember that
6849	 * smbfs_getattr will check to see if the cache has expired. May want to
6850	 * look at this and see  how it affects performance.
6851	 */
6852	VATTR_INIT(&vap);	/* Really don't care about the vap */
6853	error = smbfs_getattr(share, vp, &vap, ap->a_context);
6854	if (error) {
6855		SMBERROR("%s lookup failed %d\n", np->n_name, error);
6856		goto exit;
6857	}
6858
6859	/*
6860	 * If we already have the stream vnode in our hash table and its cache timer
6861	 * has not expired then just return we are done.
6862	 */
6863	if ((*svpp = smbfs_find_vgetstrm(VTOSMBFS(vp), np, sname,
6864									 share->ss_maxfilenamelen)) != NULL) {
6865		VTOSMB(*svpp)->n_mtime = np->n_mtime;	/* update the modify time */
6866		SMB_CACHE_TIME(ts, VTOSMB(*svpp), attrtimeo);
6867		if ((ts.tv_sec - VTOSMB(*svpp)->attribute_cache_timer) <= attrtimeo)
6868			goto exit;			/* The cache is up to date, we are done */
6869	}
6870
6871	/*
6872	 * Lookup the stream and get its size. This call will fail if the server
6873	 * tells us the stream does not exist.
6874	 *
6875	 * NOTE1: If this is the resource stream then making this call will update
6876	 * the the data fork  node's resource size and its resource cache timer.
6877	 *
6878	 * NOTE2: SAMBA will not return the resource stream if the size is zero.
6879	 *
6880	 * NOTE3: We always try to create the stream on an open. Because of note two.
6881	 *
6882	 * If smbfs_smb_qstreaminfo returns an error and we do not have the stream
6883	 * node in our hash table then it doesn't exist and they will have to create
6884	 * it.
6885	 *
6886	 * If smbfs_smb_qstreaminfo returns an error and we do  have the stream node
6887	 * in our hash table then it could exist so just pretend that it does for
6888	 * now. If they try to open it and it doesn't exist the open will create it.
6889	 *
6890	 * If smbfs_smb_qstreaminfo returns no error and we do have the stream node
6891	 * in our hash table then just update its size and cache timers.
6892	 *
6893	 * If smbfs_smb_qstreaminfo returns no error and we do not have the stream
6894	 * node in our hash table then create the stream node, using the data node
6895	 * to fill in all information except the size.
6896	 */
6897	if ((smbfs_smb_qstreaminfo(share, np,
6898                               NULL, 0,
6899                               sname,
6900                               NULL, NULL,
6901                               &strmsize, &strm_alloc_size,
6902                               &stream_flags, NULL,
6903                               ap->a_context)) && (*svpp == NULL)) {
6904		error = ENOATTR;
6905		goto exit;
6906	}
6907	/*
6908	 * We already have the stream vnode. If it doesn't exist we will attempt to
6909	 * create it on the open. In the SMB open you can say create it if it does
6910	 * not exist. Reset the size if the above called failed then set the size to
6911	 * zero.
6912	 */
6913	if (*svpp) {
6914		if (smbfs_update_size(VTOSMB(*svpp), &reqtime, strmsize) == TRUE) {
6915			/* Remember the only attribute for a stream is its size */
6916			nanouptime(&ts);
6917			VTOSMB(*svpp)->attribute_cache_timer = ts.tv_sec;
6918		}
6919		goto exit;	/* We have everything we need, so we are done */
6920	}
6921
6922	bzero(&fattr, sizeof(fattr));
6923	fattr.fa_vtype = VREG;		/* Streams are always regular files */
6924	fattr.fa_size = strmsize;	/* Fill in the stream size */
6925	fattr.fa_data_alloc = 0;	/* %%% not sure this really matters */
6926	/* Now for the rest of the information we just use the data node information */
6927	fattr.fa_attr = np->n_dosattr;
6928	fattr.fa_atime = np->n_atime;	/* Access Time */
6929	fattr.fa_chtime = np->n_chtime;	/* Change Time */
6930	fattr.fa_mtime = np->n_mtime;	/* Modify Time */
6931	fattr.fa_crtime = np->n_crtime;	/* Create Time */
6932	/* Stream inode number has same inode number as data node */
6933    fattr.fa_ino = np->n_ino;
6934	nanouptime(&fattr.fa_reqtime);
6935	error = smbfs_vgetstrm(share, VTOSMBFS(vp), vp, svpp, &fattr, sname);
6936
6937exit:
6938	if (*svpp)
6939		smbnode_unlock(VTOSMB(*svpp));	/* We are done with the node unlock it. */
6940
6941	if (error && (error != ENOATTR)) {
6942		SMBWARNING(" %s:$%s Original Stream name %s error = %d\n", np->n_name,
6943				   sname, streamname, error);
6944	}
6945	smb_share_rele(share, ap->a_context);
6946	smbnode_unlock(np);
6947	return (error);
6948}
6949
6950/*
6951 * smbfs_vnop_makenamedstream - Create a stream.
6952 *
6953 *	vnode_t a_vp;
6954 *	vnode_t *a_svpp;
6955 *	const char *a_name;
6956 *	vfs_context_t a_context;
6957 */
6958static int
6959smbfs_vnop_makenamedstream(struct vnop_makenamedstream_args* ap)
6960{
6961	struct smb_share *share;
6962	vnode_t vp = ap->a_vp;
6963	vnode_t *svpp = ap->a_svpp;
6964	const char * streamname = ap->a_name;
6965	struct smbnode *np = NULL;
6966	int error = 0;
6967	struct smbfattr fattr;
6968	struct timespec ts;
6969	int rsrcfrk = FALSE;
6970	size_t max_name_len;
6971
6972	/* Lock the parent while we create the stream */
6973	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK)))
6974		return (error);
6975	np = VTOSMB(vp);
6976	np->n_lastvop = smbfs_vnop_makenamedstream;
6977	share = smb_get_share_with_reference(VTOSMBFS(vp));
6978
6979	*svpp = NULL;
6980	/* Currently we only support the "com.apple.ResourceFork" stream. */
6981	if (bcmp(streamname, XATTR_RESOURCEFORK_NAME,
6982			 sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
6983		SMBDEBUG("Wrong stream %s:$%s\n", np->n_name, streamname);
6984		/* max_name_len = strnlen(streamname, share->ss_maxfilenamelen+1) */
6985		error = ENOATTR;
6986		goto exit;
6987	} else {
6988		max_name_len = sizeof(XATTR_RESOURCEFORK_NAME);
6989		/* This is the resource stream use the SFM name */
6990	    streamname = SFM_RESOURCEFORK_NAME;
6991	}
6992
6993	if ( !vnode_isreg(vp) ) {
6994		SMBDEBUG("%s not a file (EPERM)\n",  np->n_name);
6995		error = EPERM;
6996		goto exit;
6997	}
6998
6999	/* Now create the stream, sending a null fid pointer will cause it to be closed */
7000	error = smbfs_smb_create(share, np, streamname, max_name_len,
7001							 SMB2_FILE_WRITE_DATA, NULL,
7002							 FILE_OPEN_IF, 1, &fattr, ap->a_context);
7003	if (error)
7004		goto exit;
7005
7006	/* We create a named stream, so remove the no stream flag  */
7007	np->n_fstatus &= ~kNO_SUBSTREAMS;
7008
7009	/* Stream inode number has same inode number as data node */
7010    fattr.fa_ino = np->n_ino;
7011
7012	error = smbfs_vgetstrm(share, VTOSMBFS(vp), vp, svpp, &fattr, streamname);
7013	if (error == 0) {
7014		if (rsrcfrk) /* Update the data nodes resource size */ {
7015			lck_mtx_lock(&np->rfrkMetaLock);
7016			np->rfrk_size = fattr.fa_size;
7017            /* assume alloc size is the same */
7018			np->rfrk_alloc_size = fattr.fa_size;
7019			nanouptime(&ts);
7020			np->rfrk_cache_timer = ts.tv_sec;
7021			lck_mtx_unlock(&np->rfrkMetaLock);
7022		}
7023		smbnode_unlock(VTOSMB(*svpp));	/* Done with the smbnode unlock it. */
7024	}
7025
7026exit:
7027	if (error)
7028		SMBWARNING(" %s:$%s error = %d\n", np->n_name, streamname, error);
7029	smb_share_rele(share, ap->a_context);
7030	smbnode_unlock(np);
7031	return (error);
7032}
7033
7034/*
7035 * smbfs_vnop_removenamedstream - Remove a stream.
7036 *
7037 *	vnode_t a_vp;
7038 *	vnode_t a_svpp;
7039 *	const char *a_name;
7040 *	vfs_context_t a_context;
7041 */
7042static int
7043smbfs_vnop_removenamedstream(struct vnop_removenamedstream_args* ap)
7044{
7045	vnode_t vp = ap->a_vp;
7046	vnode_t svp = ap->a_svp;
7047	const char * streamname = ap->a_name;
7048	struct smbnode *np = NULL;
7049	int error = 0;
7050	size_t max_name_len;
7051	struct smb_share *share = NULL;
7052
7053
7054	/* Lock the parent and stream while we delete the stream*/
7055	if ((error = smbnode_lockpair(VTOSMB(vp), VTOSMB(svp), SMBFS_EXCLUSIVE_LOCK)))
7056		return (error);
7057	np = VTOSMB(svp);
7058	np->n_lastvop = smbfs_vnop_removenamedstream;
7059	share = smb_get_share_with_reference(VTOSMBFS(vp));
7060	/* Currently we only support the "com.apple.ResourceFork" stream. */
7061	if (bcmp(streamname, XATTR_RESOURCEFORK_NAME, sizeof(XATTR_RESOURCEFORK_NAME)) != 0) {
7062		SMBDEBUG("Wrong stream %s:$%s\n", np->n_name, streamname);
7063		/* max_name_len = strnlen(streamname, share->ss_maxfilenamelen+1) */
7064		error = ENOATTR;
7065		goto exit;
7066	} else {
7067		max_name_len = sizeof(XATTR_RESOURCEFORK_NAME);
7068		/* This is the resource stream use the SFM name */
7069	    streamname = SFM_RESOURCEFORK_NAME;
7070	}
7071
7072	if ( !vnode_isreg(vp) ) {
7073		SMBDEBUG("%s not a file (EPERM)\n",  np->n_name);
7074		error = EPERM;
7075		goto exit;
7076	}
7077	error = smbfs_smb_delete(share, np, streamname, max_name_len, TRUE,
7078                             ap->a_context);
7079	if (!error)
7080		smb_vhashrem(np);
7081exit:
7082	if (error)
7083		SMBWARNING(" %s:$%s error = %d\n", np->n_name, streamname, error);
7084	smb_share_rele(share, ap->a_context);
7085	smbnode_unlockpair(VTOSMB(vp), VTOSMB(svp));
7086	return (error);
7087}
7088
7089/*
7090 * smbfs_vnop_monitor - Monitor an item.
7091 *
7092 *	vnode_t a_vp;
7093 *  uint32_t a_unused_events;	- not used currently
7094 *  uint32_t a_flags;
7095 *				VNODE_MONITOR_BEGIN - setup notfication
7096 *				VNODE_MONITOR_END	- remove notfication
7097 *				VNODE_MONITOR_UPDATE	- change
7098 *	void *a_handle;
7099 *				struct knote *
7100 *  vfs_context_t a_context;
7101 *
7102 */
7103static int
7104smbfs_vnop_monitor(struct vnop_monitor_args *ap)
7105{
7106	struct smbnode *np;
7107	struct smb_share *share = NULL;
7108	int error = 0;
7109	int releaseLock = TRUE;
7110
7111	/* Currently we only support directories */
7112	if (! vnode_isdir(ap->a_vp))	{
7113		SMBDEBUG("%s is not a directory (ENOTSUP): node type = 0x%0x a_events = 0x%x, a_flags = 0x%x, a_handle = %p\n",
7114				 VTOSMB(ap->a_vp)->n_name, vnode_vtype(ap->a_vp),
7115				 ap->a_events, ap->a_flags, ap->a_handle);
7116		return ENOTSUP;
7117	}
7118
7119	if ((error = smbnode_lock(VTOSMB(ap->a_vp), SMBFS_EXCLUSIVE_LOCK)))
7120		return (error);
7121
7122	np = VTOSMB(ap->a_vp);
7123	np->n_lastvop = smbfs_vnop_monitor;
7124	share = smb_get_share_with_reference(VTOSMBFS(ap->a_vp));
7125	SMBDEBUG("%s a_events = 0x%x, a_flags = 0x%x, a_handle = %p\n",
7126			 np->n_name, ap->a_events, ap->a_flags, ap->a_handle);
7127
7128	switch (ap->a_flags) {
7129		case VNODE_MONITOR_BEGIN:
7130			error = smbfs_start_change_notify(share, np, ap->a_context,
7131											  &releaseLock);
7132			break;
7133		case VNODE_MONITOR_END:
7134			error = smbfs_stop_change_notify(share, np, FALSE, ap->a_context,
7135											 &releaseLock);
7136			break;
7137		case VNODE_MONITOR_UPDATE: /* We no longer get called to update */
7138		default:
7139			error = ENOTSUP;
7140			break;
7141	}
7142	smb_share_rele(share, ap->a_context);
7143	if (releaseLock)
7144		smbnode_unlock(VTOSMB(ap->a_vp));
7145	return error;
7146}
7147
7148/*
7149 * smbfs_vnop_access - Check for access
7150 *
7151 *	vnode_t a_vp;
7152 *  int32_t a_action;
7153 *  vfs_context_t a_context;
7154 *
7155 */
7156static int
7157smbfs_vnop_access(struct vnop_access_args *ap)
7158{
7159	vnode_t vp = ap->a_vp;
7160	int32_t action = ap->a_action, write_rights;
7161	vfs_context_t context = ap->a_context;
7162	kauth_cred_t cred = vfs_context_ucred(context);
7163	struct smbmount *smp = VTOSMBFS(vp);
7164	struct smb_share *share;
7165	uint32_t maxAccessRights;
7166	int error = 0;
7167
7168	share = smb_get_share_with_reference(VTOSMBFS(vp));
7169	/*
7170	 * Not the root user, not the user that mounted the volume and the volume
7171	 * wasn't mounted as guest then refuse all access.
7172	 */
7173	if ((vfs_context_suser(context) != 0) &&
7174		(kauth_cred_getuid(cred) != smp->sm_args.uid) &&
7175		!SMBV_HAS_GUEST_ACCESS(SSTOVC(share))) {
7176		SMB_LOG_ACCESS("%d not authorized to access %s : action = 0x%x\n",
7177				 kauth_cred_getuid(cred), VTOSMB(vp)->n_name, action);
7178		error = EACCES;
7179		goto done;
7180	}
7181
7182	/*
7183	 * If KAUTH_VNODE_ACCESS is not set then this is an authoritative request,
7184	 * we can't answer those correctly so always grant access. Now if they are
7185	 * asking about excute we should do some extra checking. If we have excute or
7186	 * read access then grant it otherwise fail the access request.
7187	 */
7188	if (((action & KAUTH_VNODE_ACCESS) != KAUTH_VNODE_ACCESS) &&
7189		(((action & KAUTH_VNODE_EXECUTE) != KAUTH_VNODE_EXECUTE) ||
7190		 (!vnode_isreg(vp)))) {
7191			goto done;
7192	}
7193
7194	/* Deal with the immutable bit, never allow write, delete or security changes. */
7195	write_rights = KAUTH_VNODE_WRITE_RIGHTS;
7196	/* Allow them to change the immutable, if they own it, we always allow */
7197	write_rights &= ~(KAUTH_VNODE_WRITE_ATTRIBUTES | KAUTH_VNODE_WRITE_EXTATTRIBUTES);
7198	/* Remove this one, we allow access if its set */
7199	write_rights &= ~KAUTH_VNODE_CHECKIMMUTABLE;
7200	if (node_isimmutable(share, vp) && (action & write_rights)) {
7201		SMB_LOG_ACCESS("%s action = 0x%x %s denied\n", VTOSMB(vp)->n_name, action,
7202                       vnode_isdir(vp) ? "IMMUTABLE_DIR" : "IMMUTABLE_FILE");
7203		error = EPERM;
7204		goto done;
7205	}
7206
7207	/*
7208	 * Windows FAT file systems have no access check, so always grant access and
7209	 * let the server make the final call. We could have some strange server that
7210	 * supports ACLs on a FAT file system or has some kind of access model. See
7211	 * FAT on a UNIX/Mac. In that case lets see if they are returning the correct
7212	 * maximal access.
7213	 */
7214	if ((share->ss_fstype == SMB_FS_FAT) &&
7215		((share->ss_attributes & FILE_PERSISTENT_ACLS) != FILE_PERSISTENT_ACLS)) {
7216		SMB_LOG_ACCESS("FAT: Access call not supported by server\n");
7217		goto done;
7218	}
7219	/*
7220	 * We were mounted with guest access.
7221	 *
7222	 * 1. We turn off ACLs if mounted as guest. Without ACLs we can't determine
7223	 *    maximal access with Samba that includes our version. So in the samba
7224	 *	  case we always ask the server for the check.
7225	 * 2. Windows return us the correct maximal access, so we can return the
7226	 *    the correct value in that case.
7227	 *
7228	 */
7229#ifdef SMB_DEBUG_ACCESS
7230	if (SMBV_HAS_GUEST_ACCESS(SSTOVC(share))) {
7231		SMB_LOG_ACCESS("SMBV_GUEST_ACCESS: %s action = 0x%x\n",
7232                       VTOSMB(vp)->n_name, action);
7233	} else {
7234		SMB_LOG_ACCESS("%s action = 0x%x\n", VTOSMB(vp)->n_name, action);
7235	}
7236#endif // SMB_DEBUG_ACCESS
7237
7238	/*
7239	 * They are asking about a stream, how do we want to handle stream
7240	 * nodes. Windows will return this in the open, but we would need to change
7241	 * the open call to support getting it on stream.Streams have the same access
7242	 * as the parent (data stream). So lets get the parent and return whatever
7243	 * the parent supports.
7244	 */
7245	if (vnode_isnamedstream(vp)) {
7246		vnode_t parent_vp = vnode_getparent(vp);
7247		if (!parent_vp)
7248			return 0;	/* Can't get the parent, let the server make the call */
7249		maxAccessRights = smbfs_get_maximum_access(share, parent_vp, context);
7250		vnode_put(parent_vp);
7251	} else {
7252		maxAccessRights = smbfs_get_maximum_access(share, vp, context);
7253	}
7254
7255	/* KAUTH_VNODE_READ_DATA for files and KAUTH_VNODE_LIST_DIRECTORY for directories */
7256	if ((action & KAUTH_VNODE_READ_DATA) &&
7257		((maxAccessRights & SMB2_FILE_READ_DATA) != SMB2_FILE_READ_DATA)) {
7258		SMB_LOG_ACCESS("%s action = 0x%x %s denied\n", VTOSMB(vp)->n_name, action,
7259                       vnode_isdir(vp) ? "KAUTH_VNODE_LIST_DIRECTORY" : "KAUTH_VNODE_READ_DATA");
7260		error = EACCES;
7261		goto done;
7262	}
7263	/* KAUTH_VNODE_WRITE_DATA for files and KAUTH_VNODE_ADD_FILE for directories */
7264	if ((action & KAUTH_VNODE_WRITE_DATA) &&
7265		((maxAccessRights & SMB2_FILE_WRITE_DATA) != SMB2_FILE_WRITE_DATA)) {
7266		SMB_LOG_ACCESS("%s action = 0x%x %s denied\n", VTOSMB(vp)->n_name, action,
7267                       vnode_isdir(vp) ? "KAUTH_VNODE_ADD_FILE" : "KAUTH_VNODE_WRITE_DATA");
7268		error = EACCES;
7269		goto done;
7270	}
7271
7272	/* KAUTH_VNODE_EXECUTE for files and KAUTH_VNODE_SEARCH for directories */
7273	if (action & KAUTH_VNODE_EXECUTE) {
7274		if ((vnode_isdir(vp)) &&
7275			((maxAccessRights & SMB2_FILE_TRAVERSE) != SMB2_FILE_TRAVERSE) &&
7276			((maxAccessRights & SMB2_FILE_LIST_DIRECTORY) != SMB2_FILE_LIST_DIRECTORY)) {
7277			/*
7278			 * See <rdar://problem/11151288> for more details, we use to require
7279			 * SMB2_FILE_TRAVERSE for granting directory search access, but now
7280			 * we also accept SMB2_FILE_LIST_DIRECTORY as well.
7281			 */
7282			SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_SEARCH denied\n", VTOSMB(vp)->n_name, action);
7283			error = EACCES;
7284			goto done;
7285		} else if (!vnode_isdir(vp) &&
7286				   ((maxAccessRights & SMB2_FILE_EXECUTE) != SMB2_FILE_EXECUTE)) {
7287			/*
7288			 * If this authoritative request and they have execute or read access
7289			 * then grant the access.
7290			 */
7291			if (((action & KAUTH_VNODE_ACCESS) != KAUTH_VNODE_ACCESS) &&
7292				((maxAccessRights & SMB2_FILE_READ_DATA) == SMB2_FILE_READ_DATA)) {
7293				goto done;
7294			}
7295
7296			/*
7297			 * See <rdar://problem/7327306> for more details, but we use to say
7298			 * if the file had read access let them have execute access. Not sure
7299			 * why I did that and it broke  <rdar://problem/7327306> so removing
7300			 * that check.
7301			 */
7302			SMB_LOG_ACCESS("%s action = 0x%x SMB2_FILE_EXECUTE denied\n",
7303                           VTOSMB(vp)->n_name, action);
7304			error = EACCES;
7305			goto done;
7306		}
7307	}
7308	if ((action & KAUTH_VNODE_DELETE) &&
7309		((maxAccessRights & SMB2_DELETE) != SMB2_DELETE)) {
7310		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_DELETE denied\n",
7311                       VTOSMB(vp)->n_name, action);
7312		error = EACCES;
7313		goto done;
7314	}
7315	/* KAUTH_VNODE_APPEND_DATA for files and KAUTH_VNODE_ADD_SUBDIRECTORY for directories */
7316	if ((action & KAUTH_VNODE_APPEND_DATA) &&
7317		((maxAccessRights & SMB2_FILE_APPEND_DATA) != SMB2_FILE_APPEND_DATA)) {
7318		SMB_LOG_ACCESS("%s action = 0x%x %s denied\n", VTOSMB(vp)->n_name, action,
7319                       vnode_isdir(vp) ? "KAUTH_VNODE_ADD_SUBDIRECTORY" : "KAUTH_VNODE_APPEND_DATA");
7320		error = EACCES;
7321		goto done;
7322	}
7323#ifdef SMB_DEBUG_ACCESS
7324	/* Need to look at this some more, seems Apple and MS don't argree on this SMB2_FILE_DELETE_CHILD */
7325	if ((action & KAUTH_VNODE_DELETE_CHILD) &&
7326		((maxAccessRights & SMB2_FILE_DELETE_CHILD) != SMB2_FILE_DELETE_CHILD)) {
7327		SMB_LOG_ACCESS("%s action = 0x%x 0x%x KAUTH_VNODE_DELETE_CHILD should denied\n",
7328                       VTOSMB(vp)->n_name, action, KAUTH_VNODE_DELETE_CHILD);
7329	}
7330	/*
7331	 * Need to look at this some more, seems Apple and MS don't argree on what
7332	 * KAUTH_VNODE_READ_ATTRIBUTES allows and doesn't allow. Window still
7333	 * allow us to get some meta data?
7334	 */
7335	if ((action & KAUTH_VNODE_READ_ATTRIBUTES) &&
7336		((maxAccessRights & SMB2_FILE_READ_ATTRIBUTES) != SMB2_FILE_READ_ATTRIBUTES)) {
7337		SMB_LOG_ACCESS("%s action = 0x%x 0x%x KAUTH_VNODE_READ_ATTRIBUTES should denied\n",
7338                       VTOSMB(vp)->n_name, action, KAUTH_VNODE_READ_ATTRIBUTES);
7339	}
7340#endif // SMB_DEBUG_ACCESS
7341	if ((action & KAUTH_VNODE_WRITE_ATTRIBUTES) &&
7342		((maxAccessRights & SMB2_FILE_WRITE_ATTRIBUTES) != SMB2_FILE_WRITE_ATTRIBUTES)) {
7343		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_WRITE_ATTRIBUTES denied\n",
7344                       VTOSMB(vp)->n_name, action);
7345		error = EACCES;
7346		goto done;
7347	}
7348	if ((action & KAUTH_VNODE_READ_EXTATTRIBUTES) &&
7349		((maxAccessRights & SMB2_FILE_READ_ATTRIBUTES) != SMB2_FILE_READ_ATTRIBUTES)) {
7350		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_READ_EXTATTRIBUTES denied\n",
7351                       VTOSMB(vp)->n_name, action);
7352		error = EACCES;
7353		goto done;
7354	}
7355	if ((action & KAUTH_VNODE_WRITE_EXTATTRIBUTES) &&
7356		((maxAccessRights & SMB2_FILE_WRITE_ATTRIBUTES) != SMB2_FILE_WRITE_ATTRIBUTES)) {
7357		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_WRITE_EXTATTRIBUTES denied\n",
7358                       VTOSMB(vp)->n_name, action);
7359		error = EACCES;
7360		goto done;
7361	}
7362	if ((action & KAUTH_VNODE_READ_SECURITY) &&
7363		((maxAccessRights & SMB2_READ_CONTROL) != SMB2_READ_CONTROL)) {
7364		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_READ_SECURITY denied\n",
7365                       VTOSMB(vp)->n_name, action);
7366		error = EACCES;
7367		goto done;
7368	}
7369	/* Check to see if the share acls allow access */
7370	if ((action & KAUTH_VNODE_WRITE_SECURITY) &&
7371		((share->maxAccessRights & SMB2_WRITE_DAC) != SMB2_WRITE_DAC)) {
7372		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_WRITE_SECURITY denied by Share ACL\n",
7373                       VTOSMB(vp)->n_name, action);
7374		error = EACCES;
7375		goto done;
7376	}
7377	/* Check to see if the share acls allow access */
7378	if ((action & KAUTH_VNODE_TAKE_OWNERSHIP) &&
7379		((share->maxAccessRights & SMB2_WRITE_OWNER) != SMB2_WRITE_OWNER)) {
7380		SMB_LOG_ACCESS("%s action = 0x%x SHARE KAUTH_VNODE_TAKE_OWNERSHIP by Share ACL\n",
7381                       VTOSMB(vp)->n_name, action);
7382		error = EACCES;
7383		goto done;
7384	}
7385	if ((action & KAUTH_VNODE_WRITE_SECURITY) &&
7386		((maxAccessRights & SMB2_WRITE_DAC) != SMB2_WRITE_DAC)) {
7387		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_WRITE_SECURITY denied\n",
7388                       VTOSMB(vp)->n_name, action);
7389		error = EACCES;
7390		goto done;
7391	}
7392	if ((action & KAUTH_VNODE_TAKE_OWNERSHIP) &&
7393		((maxAccessRights & SMB2_WRITE_OWNER) != SMB2_WRITE_OWNER)) {
7394		SMB_LOG_ACCESS("%s action = 0x%x KAUTH_VNODE_TAKE_OWNERSHIP denied\n",
7395                       VTOSMB(vp)->n_name, action);
7396		error = EACCES;
7397		goto done;
7398	}
7399done:
7400	if (error) {
7401		SMB_LOG_ACCESS("%s action = 0x%x denied\n", VTOSMB(vp)->n_name, action);
7402	}
7403	smb_share_rele(share, ap->a_context);
7404	return error;
7405}
7406
7407
7408/*
7409 * smbfs_vnop_allocate -
7410 *
7411 *	vnode_t a_vp;
7412 *  off_t a_length;
7413 *	u_int32_t a_flags;
7414 *  off_t *a_bytesallocated;
7415 *  off_t a_offset;
7416 *  vfs_context_t a_context;
7417 *
7418 */
7419static int
7420smbfs_vnop_allocate(struct vnop_allocate_args *ap)
7421{
7422	vnode_t vp = ap->a_vp;
7423	u_int64_t length = (u_int64_t)ap->a_length;
7424	struct smbnode *np;
7425	int32_t error = 0;
7426	SMBFID fid = 0;
7427
7428	*(ap->a_bytesallocated) = 0;
7429
7430	/* Preflight checks */
7431	if (!vnode_isreg(vp)) {
7432		/* can only read regular files */
7433		if (vnode_isdir(vp))
7434			return (EISDIR);
7435		else
7436			return (EPERM);
7437	}
7438
7439	if ((error = smbnode_lock(VTOSMB(vp), SMBFS_EXCLUSIVE_LOCK))) {
7440		return (error);
7441	}
7442	np = VTOSMB(vp);
7443	np->n_lastvop = smbfs_vnop_allocate;
7444
7445	if ((ap->a_flags & ALLOCATEFROMVOL) && (length < np->n_size)) {
7446		error = EINVAL;
7447		goto done;
7448	}
7449    if (ap->a_flags & ALLOCATEFROMPEOF) {
7450		if (length > (UINT32_MAX - np->n_size)) {
7451			error = EINVAL;
7452			goto done;
7453		}
7454        length += np->n_size;
7455    }
7456
7457	if (FindFileRef(vp, vfs_context_proc(ap->a_context), kAccessWrite,
7458						  kAnyMatch, 0, 0, NULL, &fid)) {
7459		/* No matches or no pid to match, so just use the generic shared fork */
7460		fid = np->f_fid;
7461	}
7462	if (fid == 0) {
7463		error = EBADF;
7464		goto done;
7465	}
7466    /* If nothing is changing, then we're done */
7467    if (!length || (np->n_size == length)) {
7468        length = 0;
7469    } else {
7470		struct smb_share *share;
7471
7472		share = smb_get_share_with_reference(VTOSMBFS(vp));
7473		length = roundup(length, VTOSMBFS(vp)->sm_statfsbuf.f_bsize);
7474		error = smbfs_smb_set_allocation(share, fid, length, ap->a_context);
7475		smb_share_rele(share, ap->a_context);
7476	}
7477	if (!error) {
7478		*(ap->a_bytesallocated) = length;
7479	}
7480
7481done:
7482	if (error) {
7483		SMBWARNING("%s: length = %lld, error = %d\n", np->n_name, length, error);
7484	}
7485	smbnode_unlock(VTOSMB(ap->a_vp));
7486	return error;
7487}
7488
7489vnop_t **smbfs_vnodeop_p;
7490static struct vnodeopv_entry_desc smbfs_vnodeop_entries[] = {
7491	{ &vnop_default_desc,		(vnop_t *) vn_default_error },
7492	{ &vnop_advlock_desc,		(vnop_t *) smbfs_vnop_advlock },
7493	{ &vnop_close_desc,			(vnop_t *) smbfs_vnop_close },
7494	{ &vnop_create_desc,		(vnop_t *) smbfs_vnop_create },
7495	{ &vnop_fsync_desc,			(vnop_t *) smbfs_vnop_fsync },
7496	{ &vnop_getattr_desc,		(vnop_t *) smbfs_vnop_getattr },
7497	{ &vnop_pagein_desc,		(vnop_t *) smbfs_vnop_pagein },
7498	{ &vnop_inactive_desc,		(vnop_t *) smbfs_vnop_inactive },
7499	{ &vnop_ioctl_desc,			(vnop_t *) smbfs_vnop_ioctl },
7500	{ &vnop_link_desc,			(vnop_t *) smbfs_vnop_link },
7501	{ &vnop_lookup_desc,		(vnop_t *) smbfs_vnop_lookup },
7502	{ &vnop_mkdir_desc,			(vnop_t *) smbfs_vnop_mkdir },
7503	{ &vnop_mknod_desc,			(vnop_t *) smbfs_vnop_mknod },
7504	{ &vnop_mmap_desc,			(vnop_t *) smbfs_vnop_mmap },
7505	{ &vnop_mnomap_desc,		(vnop_t *) smbfs_vnop_mnomap },
7506	{ &vnop_open_desc,			(vnop_t *) smbfs_vnop_open },
7507	{ &vnop_compound_open_desc,	(vnop_t *) smbfs_vnop_compound_open },
7508	{ &vnop_pathconf_desc,		(vnop_t *) smbfs_vnop_pathconf },
7509	{ &vnop_pageout_desc,		(vnop_t *) smbfs_vnop_pageout },
7510    { &vnop_copyfile_desc,		(vnop_t *) smbfs_vnop_copyfile },
7511	{ &vnop_read_desc,			(vnop_t *) smbfs_vnop_read },
7512	{ &vnop_readdir_desc,		(vnop_t *) smbfs_vnop_readdir },
7513    { &vnop_readdirattr_desc,   (vnop_t *) smbfs_vnop_readdirattr },
7514	{ &vnop_readlink_desc,		(vnop_t *) smbfs_vnop_readlink },
7515	{ &vnop_reclaim_desc,		(vnop_t *) smbfs_vnop_reclaim },
7516	{ &vnop_remove_desc,		(vnop_t *) smbfs_vnop_remove },
7517	{ &vnop_rename_desc,		(vnop_t *) smbfs_vnop_rename },
7518	{ &vnop_rmdir_desc,			(vnop_t *) smbfs_vnop_rmdir },
7519	{ &vnop_setattr_desc,		(vnop_t *) smbfs_vnop_setattr },
7520	{ &vnop_symlink_desc,		(vnop_t *) smbfs_vnop_symlink },
7521	{ &vnop_write_desc,			(vnop_t *) smbfs_vnop_write },
7522	{ &vnop_blockmap_desc,		(vnop_t *) smbfs_vnop_blockmap },
7523	{ &vnop_strategy_desc,		(vnop_t *) smbfs_vnop_strategy },
7524	{ &vnop_searchfs_desc,		(vnop_t *) err_searchfs },
7525	{ &vnop_offtoblk_desc,		(vnop_t *) smbfs_vnop_offtoblk },
7526	{ &vnop_blktooff_desc,		(vnop_t *) smbfs_vnop_blktooff },
7527	{ &vnop_getxattr_desc,		(vnop_t *) smbfs_vnop_getxattr },
7528	{ &vnop_setxattr_desc,		(vnop_t *) smbfs_vnop_setxattr },
7529	{ &vnop_removexattr_desc,	(vnop_t *) smbfs_vnop_removexattr },
7530	{ &vnop_listxattr_desc,		(vnop_t *) smbfs_vnop_listxattr },
7531	{ &vnop_monitor_desc,		(vnop_t *) smbfs_vnop_monitor},
7532	{ &vnop_getnamedstream_desc, (vnop_t *) smbfs_vnop_getnamedstream },
7533    { &vnop_makenamedstream_desc, (vnop_t *) smbfs_vnop_makenamedstream },
7534    { &vnop_removenamedstream_desc, (vnop_t *) smbfs_vnop_removenamedstream },
7535	{ &vnop_access_desc,		(vnop_t *) smbfs_vnop_access },
7536	{ &vnop_allocate_desc,		(vnop_t *) smbfs_vnop_allocate },
7537	{ NULL, NULL }
7538};
7539
7540struct vnodeopv_desc smbfs_vnodeop_opv_desc =
7541	{ &smbfs_vnodeop_p, smbfs_vnodeop_entries };
7542