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 <stdint.h>
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/kernel.h>
39#include <sys/malloc.h>
40#include <sys/proc.h>
41#include <sys/lock.h>
42#include <sys/vnode.h>
43#include <sys/xattr.h>
44#include <sys/kpi_mbuf.h>
45#include <sys/mount.h>
46
47#include <sys/kauth.h>
48
49#include <sys/smb_apple.h>
50#include <sys/msfscc.h>
51
52#include <netsmb/smb.h>
53#include <netsmb/smb_2.h>
54#include <netsmb/smb_subr.h>
55#include <netsmb/smb_rq.h>
56#include <netsmb/smb_rq_2.h>
57#include <netsmb/smb_conn.h>
58#include <netsmb/smb_conn_2.h>
59
60#include <smbfs/smbfs.h>
61#include <smbfs/smbfs_node.h>
62#include <smbfs/smbfs_subr.h>
63#include <smbfs/smbfs_subr_2.h>
64#include <smbfs/smbfs_lockf.h>
65#include <netsmb/smb_converter.h>
66#include <smbfs/smbfs_security.h>
67#include <smbclient/ntstatus.h>
68#include <libkern/crypto/md5.h>
69
70#define SMBFS_DELETE_PREFIX	".smbdeleteAAA"
71#define MAKE_DELETED_NAME(NAME, SIZE, FID) \
72(void) snprintf((NAME), SIZE, "%s%llx", SMBFS_DELETE_PREFIX, (FID))
73
74/*
75 * Lack of inode numbers leads us to the problem of generating them.
76 * Partially this problem can be solved by having a dir/file cache
77 * with inode numbers generated from the incremented by one counter.
78 * However this way will require too much kernel memory, gives all
79 * sorts of locking and consistency problems, not to mention counter overflows.
80 * So, I'm decided to use a hash function to generate pseudo random (and unique)
81 * inode numbers.
82 *
83 * SMB 2/3 - if server supports File IDs, then use inode number from the server
84 * and never call this function.
85 * SMB 1 and SMB 2/3 servers that do not support File IDs still hashes the
86 * name and thus still calls this function.
87 */
88uint64_t
89smbfs_getino(struct smbnode *dnp, const char *name, size_t nmlen)
90{
91	uint64_t ino;
92
93	ino = dnp->n_ino + smbfs_hash(NULL, 0, name, nmlen);
94	if (ino <= SMBFS_ROOT_INO)
95		ino += 3;
96	return ino;
97}
98
99/*
100 * The calling routine must hold a reference on the share
101 *
102 * [MS-CIFS]
103 * This command is used to explicitly lock and/or unlock a contiguous range of
104 * bytes in a regular file. More than one non-overlapping byte range MAY be
105 * locked and/or unlocked on an open file. Locks prevent attempts to lock, read,
106 * or write the locked portion of the file by other processes using a separate
107 * file handle (FID). Any process using the same FID specified in the request
108 * that obtained the lock has access to the locked bytes.
109 *
110 * So we handle the pid issue at our level, curently that code is broken and
111 * needs to be fixed. We should fix that as part of <rdar://problem/7946972>.
112 * We need to hold on to the local users pid and not the network user pid in
113 * the byterange locking list.
114 *
115 * Since we always use the fid that open the file to take the lock the network
116 * code should always work, even if we change the network pid.
117 */
118int
119smb1fs_smb_lock(struct smb_share *share, int op, SMBFID fid, uint32_t pid,
120			   off_t start, uint64_t len, uint32_t timo, vfs_context_t context)
121{
122#pragma unused(pid)
123	struct smb_rq rq, *rqp = &rq;
124	struct mbchain *mbp;
125	u_char ltype = 0;
126	int error;
127    uint16_t smb1_fid = (uint16_t) fid; /* cast to SMB 1 fid */
128
129	if (op == SMB_LOCK_SHARED)
130		ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
131		/* Do they support large offsets */
132	if (VC_CAPS(SSTOVC(share)) & SMB_CAP_LARGE_FILES)
133		ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
134	error = smb_rq_init(rqp, SSTOCP(share), SMB_COM_LOCKING_ANDX, 0, context);
135	if (error)
136		return error;
137	smb_rq_getrequest(rqp, &mbp);
138	smb_rq_wstart(rqp);
139	mb_put_uint8(mbp, 0xff);	/* secondary command */
140	mb_put_uint8(mbp, 0);		/* MBZ */
141	mb_put_uint16le(mbp, 0);
142	mb_put_mem(mbp, (caddr_t)&smb1_fid, sizeof(smb1_fid), MB_MSYSTEM);
143	mb_put_uint8(mbp, ltype);	/* locktype */
144	mb_put_uint8(mbp, 0);		/* oplocklevel - 0 seems is NO_OPLOCK */
145	mb_put_uint32le(mbp, timo);	/* 0 nowait, -1 infinite wait */
146	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
147	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
148	smb_rq_wend(rqp);
149	smb_rq_bstart(rqp);
150	/* Always keep it in sync with the pid in the smb header */
151	mb_put_uint16le(mbp, rqp->sr_pidLow);
152	if (ltype & SMB_LOCKING_ANDX_LARGE_FILES) {
153		mb_put_uint16le(mbp, 0); /* pad */
154		mb_put_uint32le(mbp, (uint32_t)(start >> 32)); /* OffsetHigh */
155		mb_put_uint32le(mbp, (uint32_t)(start & 0xffffffff)); /* OffsetLow */
156		mb_put_uint32le(mbp, (uint32_t)(len >> 32)); /* LengthHigh */
157		mb_put_uint32le(mbp, (uint32_t)(len & 0xffffffff)); /* LengthLow */
158	} else {
159		mb_put_uint32le(mbp, (uint32_t)(start & 0xffffffff));
160		mb_put_uint32le(mbp, (uint32_t)(len & 0xffffffff));
161	}
162	smb_rq_bend(rqp);
163	error = smb_rq_simple(rqp);
164	/*
165	 * This may seem strange, but both Windows and Samba do the following:
166	 *
167	 * Lock a region, try to lock it again you get STATUS_LOCK_NOT_GRANTED,
168	 * try to lock it a third time you get STATUS_FILE_LOCK_CONFLICT. Seems
169	 * the first lock error is always STATUS_LOCK_NOT_GRANTED and the second
170	 * time you get a STATUS_FILE_LOCK_CONFLICT.
171	 *
172	 * For IO they always return STATUS_FILE_LOCK_CONFLICT, which we convert
173	 * to EIO, becasue there are multiple IO routines and only one lock routine.
174	 * So we want this to be EACCES in the lock cases. So we need to convert
175	 * that error here.
176	 *
177	 */
178	if ((error == EIO) && (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS)) {
179		if (rqp->sr_ntstatus == STATUS_FILE_LOCK_CONFLICT)
180			error = EACCES;
181	}
182	smb_rq_done(rqp);
183	return error;
184}
185
186/*
187 * The calling routine must hold a reference on the share
188 */
189int
190smb1fs_smb_qpathinfo(struct smb_share *share,
191                     struct smbnode *np,
192                     struct smbfattr *fap,
193                     short infolevel,
194                     const char **namep,
195                     size_t *nmlenp,
196                     vfs_context_t context)
197{
198	struct smb_t2rq *t2p;
199	int error;
200	struct mbchain *mbp;
201	struct mdchain *mdp;
202	uint64_t llint;
203	uint32_t size, dattr, eaSize;
204	const char *name = (namep ? *namep : NULL);
205	size_t nmlen = (nmlenp ? *nmlenp : 0);
206	char *ntwrkname = NULL;
207	char *filename;
208	uint8_t sep = '\\';
209    char *snamep = NULL;
210
211	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_QUERY_PATH_INFORMATION, 1, context, &t2p);
212	if (error)
213		return error;
214	mbp = &t2p->t2_tparam;
215	mb_init(mbp);
216	mb_put_uint16le(mbp, infolevel);
217	mb_put_uint32le(mbp, 0);
218	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
219	if ((np->n_vnode) && vnode_isnamedstream(np->n_vnode)) {
220		DBG_ASSERT((namep == NULL));
221
222        lck_rw_lock_shared(&np->n_name_rwlock);
223        snamep = smb_strndup(np->n_sname, np->n_snmlen);
224        name = snamep;
225        lck_rw_unlock_shared(&np->n_name_rwlock);
226
227		nmlen = np->n_snmlen;
228		sep = ':';
229	}
230	error = smbfs_fullpath(mbp, np, name, &nmlen, UTF_SFM_CONVERSIONS,
231						   SMB_UNICODE_STRINGS(SSTOVC(share)), sep);
232
233	if (error) {
234		smb_t2_done(t2p);
235		goto done;
236	}
237	t2p->t2_maxpcount = 2;
238	t2p->t2_maxdcount = SSTOVC(share)->vc_txmax;
239	error = smb_t2_request(t2p);
240	if (error) {
241		smb_t2_done(t2p);
242		goto done;
243	}
244	mdp = &t2p->t2_rdata;
245	/*
246	 * At this point md_cur and md_top have the same value. Now all the md_get
247	 * routines will will check for null, but just to be safe we check here.
248	 */
249	if (mdp->md_cur == NULL) {
250		SMBWARNING("Parsing error reading the message\n");
251		smb_t2_done(t2p);
252		error = EBADRPC;
253        goto done;
254	}
255	switch (infolevel) {
256	case SMB_QFILEINFO_ALL_INFO:
257		md_get_uint64le(mdp, &llint);	/* creation time */
258		if (llint) {
259			smb_time_NT2local(llint, &fap->fa_crtime);
260		}
261		md_get_uint64le(mdp, &llint);
262		if (llint) {			/* access time */
263			smb_time_NT2local(llint, &fap->fa_atime);
264		}
265		md_get_uint64le(mdp, &llint);
266		if (llint) {			/* write time */
267			smb_time_NT2local(llint, &fap->fa_mtime);
268		}
269		md_get_uint64le(mdp, &llint);
270		if (llint) {			/* change time */
271			smb_time_NT2local(llint, &fap->fa_chtime);
272		}
273		/*
274		 * SNIA CIFS Technical Reference is wrong, this should be
275		 * a ULONG
276		 */
277		md_get_uint32le(mdp, &dattr);	/* Attributes */
278		fap->fa_attr = dattr;
279		/*
280		 * Because of the Steve/Conrad Symlinks we can never be completely
281		 * sure that we have the correct vnode type if its a file. For
282		 * directories we always know the correct information.
283		 */
284		if (fap->fa_attr & SMB_EFA_DIRECTORY) {
285			fap->fa_valid_mask |= FA_VTYPE_VALID;
286		}
287		fap->fa_vtype = (fap->fa_attr & SMB_EFA_DIRECTORY) ? VDIR : VREG;
288
289		/*
290		 * SNIA CIFS Technical Reference is wrong, this should be
291		 * a ULONG PAD
292		 */
293		md_get_uint32le(mdp, NULL);
294
295		md_get_uint64le(mdp, &llint); /* allocation size */
296		fap->fa_data_alloc = llint;
297
298		md_get_uint64le(mdp, &llint);	/* file size */
299		fap->fa_size = llint;
300
301		md_get_uint32le(mdp, NULL);	/* Number of hard links */
302		md_get_uint8(mdp, NULL);	/* Delete Pending */
303		error = md_get_uint8(mdp, NULL);	/* Directory or File */
304		if (error)
305			goto bad;
306		fap->fa_ino = np->n_ino;
307		/*
308		 * At this point the SNIA CIFS Technical Reference is wrong.
309		 * It should have the following:
310		 *			USHORT		Unknown;
311		 *			ULONG		EASize;
312		 *			ULONG		PathNameLength;
313		 *			STRING		FullPath;
314		 * We need to be carefull just in case someone followed the
315		 * Technical Reference.
316		 */
317		md_get_uint16(mdp, NULL);	/* Unknown */
318		/*
319		 * Confirmed from MS:
320		 * When the attribute has the Reparse Point bit set then the EASize
321		 * contains the reparse tag info. This behavior is consistent for
322		 * Full, Both, FullId, or BothId query dir calls.  It will pack the
323		 * reparse tag into the EaSize value if ATTRIBUTE_REPARSE_POINT is set.
324		 * I verified with local MS Engineers, and they also checking to make
325		 * sure the behavior is covered in MS-FSA.
326		 *
327		 * EAs and reparse points cannot both be in a file at the same
328		 * time. We return different information for each case.
329		 *
330		 * NOTE: This is not true for this call (SMB_QFILEINFO_ALL_INFO), they
331		 * return the reparse bit but the eaSize size is always zero?
332		 */
333		md_get_uint32le(mdp, &eaSize);	/* extended attributes size */
334
335        /*
336		 * We don't care about the name, so we can skip getting it.
337		 *
338		 * NOTE: When accessing the root node the name may not be what you would
339		 * expect. Windows will return a back slash if the item being shared is
340		 * a drive and in all other cases the name of the directory being shared.
341		 * We never ask for the name in the root node case so this should never
342		 * be an issue.
343		 */
344		if (namep == NULL)
345			break;	/* We are done */
346
347		error = md_get_uint32le(mdp, &size);	/* Path name lengh */
348		if (error)
349			goto bad;
350		/*
351		 * Make sure it is something in reason. Don't allocate it,
352		 * if it doesn't make sense.
353		 */
354		if (size <= 0 || size >= t2p->t2_maxdcount) {
355			error = EINVAL;
356			goto bad;
357		}
358		/*
359		 * Since the SNIA CIFS Technical Reference is wrong, we would
360		 * like to do as much checking as possible. The whole message
361		 * should be the file name length + 72 bytes. If we get
362		 * something bigger print it out. In the worst case situation
363		 * we would end up with a bogus name. We have found that the
364		 * Snap servers follows the Technical Reference. So in their
365		 * case the file name length is bogus. This is not a problem
366		 * because they always return zero in that location. So this
367		 * would error out above. NT returns the correct information
368		 * but does put 4 bytes of zero padd at the end. So now add
369		 * 4 bytes to our check.
370		 */
371        m_fixhdr(mdp->md_top);
372		if (mbuf_pkthdr_len(mdp->md_top) > (size+72+4)) {
373			SMBERROR("SMB_QFILEINFO_ALL_INFO: wrong size %ld\n",
374					mbuf_pkthdr_len((mbuf_t)mdp->md_top));
375		}
376
377		nmlen = size;
378
379		/* Since this is a full path only check SMB_MAXFNAMELEN length
380		 * until we get the component. We just allocate what we need
381		 * need here.
382		 */
383        SMB_MALLOC(ntwrkname, char *, nmlen, M_SMBFSDATA, M_WAITOK);
384		if (ntwrkname == NULL)
385			error = ENOMEM;
386		else
387			error = md_get_mem(mdp, (void *)ntwrkname, nmlen,
388					MB_MSYSTEM);	/* Full path name */
389
390		if (error)
391			goto bad;
392
393		/*
394		 * Here is the problem. They return the full path when we only
395		 * need the last component. So we need to find the last back
396		 * slash. So first remove any trailing nulls from the path.
397		 * Now start at the end of the path name and work our way back
398		 * stopping when we find the first back slash. For UTF-16 make
399		 * sure there is a null byte after the back slash.
400		 */
401		if (SMB_UNICODE_STRINGS(SSTOVC(share))) {
402			/* Don't count any trailing nulls in the name. */
403			if (nmlen > 1 && ntwrkname[nmlen - 1] == 0 &&
404				ntwrkname[nmlen - 2] == 0)
405				nmlen -= 2;
406			/*
407			 * Now get the file name. We need to start at the end
408			 * and work our way backwards.
409			 */
410			if (nmlen > 1)
411				filename = &ntwrkname[nmlen-2];
412			else filename = ntwrkname;
413			 /* Work backwards until we reach the begining */
414			while (filename > ntwrkname) {
415				if ((*filename == 0x5c) && (*(filename+1) == 0x00))
416					break;
417				filename -= 2;
418			}
419			/*
420			 * Found a back slash move passed it and now we have
421			 * the real file name.
422			 */
423			if ((*filename == 0x5c) && (*(filename+1) == 0x00))
424				filename += 2;
425		} else {
426			/* Don't count any trailing null in the name. */
427			if (nmlen && ntwrkname[nmlen - 1] == 0)
428				nmlen--;
429			/*
430			 * Now get the file name. We need to start at the end
431			 * and work our way bacckwards.
432			 */
433			if (nmlen)
434				filename = &ntwrkname[nmlen-1];
435			else filename = ntwrkname;
436			/* Work backwards until we reach the begining */
437			while ((filename > ntwrkname) && (*filename != 0x5c))
438				filename--;
439			/*
440			 * Found a back slash move passed it and now we have
441			 * the real file name.
442			 */
443			if (*filename == 0x5c)
444				filename++;
445		}
446		/* Reset the name length */
447		nmlen = &ntwrkname[nmlen] - filename;
448		/* Convert the name to a UTF-8 string  */
449		filename = smbfs_ntwrkname_tolocal((const char *)filename, &nmlen,
450										   SMB_UNICODE_STRINGS(SSTOVC(share)));
451		/* Done with the network buffer so free it */
452		SMB_FREE(ntwrkname, M_SMBFSDATA);
453		/* Now reasign it so we free the correct buffer */
454		ntwrkname = filename;
455
456		if (ntwrkname == NULL) {
457			error = EINVAL;
458			SMBERROR("smbfs_ntwrkname_tolocal return NULL\n");
459			goto bad;
460		}
461		if (nmlen > SMB_MAXFNAMELEN) {
462			error = EINVAL;
463			SMBERROR("Filename  %s nmlen = %ld\n", ntwrkname, nmlen);
464			goto bad;
465		}
466		*namep = smb_strndup(filename, nmlen);
467		if (nmlenp)	/* Return the name length */
468			*nmlenp = nmlen;
469		if (*namep && nmlenp)	/* SMB 1 only. Create the inode number */
470			fap->fa_ino = smbfs_getino(np, *namep, *nmlenp);
471bad:
472		/* Free the buffer that holds the name from the network */
473		SMB_FREE(ntwrkname, M_SMBFSDATA);
474		break;
475	case SMB_QFILEINFO_UNIX_INFO2:
476
477		md_get_uint64le(mdp, &llint);	/* file size */
478		fap->fa_size = llint;
479
480		md_get_uint64le(mdp, &llint); /* allocation size */
481		fap->fa_data_alloc = llint;
482
483		md_get_uint64le(mdp, &llint);	/* change time */
484		if (llint)
485			smb_time_NT2local(llint, &fap->fa_chtime);
486
487		md_get_uint64le(mdp, &llint);	/* access time */
488		if (llint)
489			smb_time_NT2local(llint, &fap->fa_atime);
490
491		md_get_uint64le(mdp, &llint);	/* write time */
492		if (llint)
493			smb_time_NT2local(llint, &fap->fa_mtime);
494
495		md_get_uint64le(mdp, &llint);	/* Numeric user id for the owner */
496		fap->fa_uid = llint;
497
498		md_get_uint64le(mdp, &llint);	/* Numeric group id for the owner */
499		fap->fa_gid = llint;
500
501		md_get_uint32le(mdp, &dattr);	/* Enumeration specifying the file type, st_mode */
502		fap->fa_valid_mask |= FA_VTYPE_VALID;
503		/* Make sure the dos attributes are correct */
504		if (dattr & EXT_UNIX_DIR) {
505			fap->fa_attr |= SMB_EFA_DIRECTORY;
506			fap->fa_vtype = VDIR;
507		} else if (dattr & EXT_UNIX_SYMLINK) {
508			fap->fa_vtype = VLNK;
509		} else {
510			fap->fa_vtype = VREG;
511		}
512
513		md_get_uint64le(mdp, &llint);	/* Major device number if type is device */
514		md_get_uint64le(mdp, &llint);	/* Minor device number if type is device */
515		md_get_uint64le(mdp, &llint);	/* This is a server-assigned unique id */
516		md_get_uint64le(mdp, &llint);	/* Standard UNIX permissions */
517		fap->fa_permissions = llint;
518		fap->fa_valid_mask |= FA_UNIX_MODES_VALID;
519		md_get_uint64le(mdp, &llint);	/* Number of hard link */
520		fap->fa_nlinks = llint;
521
522		md_get_uint64le(mdp, &llint);	/* creation time */
523		if (llint)
524			smb_time_NT2local(llint, &fap->fa_crtime);
525
526		md_get_uint32le(mdp, &dattr);	/* File flags enumeration */
527		error = md_get_uint32le(mdp, &fap->fa_flags_mask);	/* Mask of valid flags */
528		if (error)
529			break;
530		/* Make sure the dos attributes are correct */
531		if (fap->fa_flags_mask & EXT_HIDDEN) {
532			if (dattr & EXT_HIDDEN)
533				fap->fa_attr |= SMB_EFA_HIDDEN;
534			else
535				fap->fa_attr &= ~SMB_EFA_HIDDEN;
536		}
537		if (fap->fa_flags_mask & EXT_IMMUTABLE) {
538			if (dattr & EXT_IMMUTABLE)
539				fap->fa_attr |= SMB_EFA_RDONLY;
540			else
541				fap->fa_attr &= ~SMB_EFA_RDONLY;
542		}
543		if (fap->fa_flags_mask & SMB_EFA_ARCHIVE) {
544			if (dattr & EXT_DO_NOT_BACKUP)
545				fap->fa_attr &= ~SMB_EFA_ARCHIVE;
546			else
547				fap->fa_attr |= SMB_EFA_ARCHIVE;
548		}
549		fap->fa_unix = TRUE;
550        if (namep == NULL) {
551            fap->fa_ino = np->n_ino;
552        }
553        else {
554            if ((*namep) && nmlenp)  {
555                /* np is actually the parent dnp */
556                fap->fa_ino = smbfs_getino(np, *namep, *nmlenp);
557            }
558            else {
559                /* Should not ever happen */
560                SMBERROR("Missing namep or nmlenp, so inode left at 0\n");
561            }
562        }
563		break;
564	default:
565		SMBERROR("unexpected info level %d\n", infolevel);
566		error = EINVAL;
567		break;
568	}
569	smb_t2_done(t2p);
570
571done:
572    if (snamep) {
573        SMB_FREE(snamep, M_SMBSTR);
574    }
575
576    return error;
577}
578
579int
580smbfs_smb_undollardata(const char *fname, char *name, size_t *nmlen,
581                       uint32_t *is_data)
582{
583    char *cp;
584    size_t len = sizeof(SMB_DATASTREAM) - 1;
585
586    /*
587     * Example stream names
588     * ::$DATA
589     * :AFP_AfpInfo:$DATA
590     * :AFP_Resource:$DATA
591     */
592
593    *is_data = 0;
594
595    /* Sanity check for a stream name */
596    if (!name) {
597        goto bad;
598    }
599
600    /* Has to be "::$DATA" at a minimum length */
601    if (*nmlen < len + 1) {
602        goto bad;
603    }
604
605    /* Has to have a leading colon */
606    if (*name != ':') {
607        goto bad;
608    }
609
610    /* Point to 2nd colon */
611    cp =  &name[*nmlen - len];
612
613    /* Has to end with $DATA */
614    if (bcmp(cp, SMB_DATASTREAM, len)) {
615        goto bad;
616    }
617
618    /* Merely the data fork? */
619    if (*nmlen == (len + 1)) {
620        /* Skip returning it. */
621        *is_data = 1;
622        return (0);
623    }
624
625	/* We can not return more than 128 bytes */
626    if ((*nmlen - len) > (XATTR_MAXNAMELEN + 1)) {
627        goto bad;
628    }
629
630    /*
631     * Un-count a colon and the $DATA, then the
632     * 2nd colon is replaced by a terminating null.
633     */
634    *nmlen -= len;
635    *cp = '\0';
636
637    /* Skip protected system attrs */
638    if ((*nmlen >= 17) && (xattr_protected(name + 1))) {
639        return (0);
640    }
641
642    /*
643     * Return the stream name. Examples:
644     * :AFP_AfpInfo
645     * :AFP_Resource
646     */
647    return (1);
648
649bad:
650    /*
651     * If the name exist then we malloc it so we can print it
652     * out. So just make sure it exist before printing.
653     */
654    SMBWARNING("file \"%s\" has bad stream \"%s\"\n", fname, (name) ? name : "");
655    return (0);
656}
657
658/*
659 * smbfs_smb_markfordelete
660 *
661 * We have an open file that they want to delete. This call will tell the
662 * server to delete the file when the last close happens. Currenly we know that
663 * XP, Windows 2000 and Windows 2003 support this call. SAMBA does support the
664 * call, but currently has a bug that prevents it from working.
665 *
666 * The calling routine must hold a reference on the share
667 *
668 */
669int
670smb1fs_smb_markfordelete(struct smb_share *share, SMBFID fid,
671                         vfs_context_t context)
672{
673	struct smb_t2rq *t2p;
674	struct mbchain *mbp;
675	int error;
676    uint16_t smb1_fid = (uint16_t) fid; /* cast to SMB 1 fid */
677
678	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_SET_FILE_INFORMATION, 1,
679                         context, &t2p);
680	if (error) {
681		return error;
682	}
683	mbp = &t2p->t2_tparam;
684	mb_init(mbp);
685    /* SMB 1 fid in volatile */
686	mb_put_mem(mbp, (caddr_t)&smb1_fid, sizeof(smb1_fid), MB_MSYSTEM);
687	if (VC_CAPS(SSTOVC(share)) & SMB_CAP_INFOLEVEL_PASSTHRU)
688		mb_put_uint16le(mbp, SMB_SFILEINFO_DISPOSITION_INFORMATION);
689	else
690		mb_put_uint16le(mbp, SMB_SFILEINFO_DISPOSITION_INFO);
691	mb_put_uint16le(mbp, 0);
692	mbp = &t2p->t2_tdata;
693	mb_init(mbp);
694	mb_put_uint8(mbp, 1);
695	t2p->t2_maxpcount = 2;
696	t2p->t2_maxdcount = 0;
697	error = smb_t2_request(t2p);
698	smb_t2_done(t2p);
699	return error;
700}
701
702/*
703 * Create the data required for a faked up symbolic link. This is Conrad and Steve
704 * French method for storing and reading symlinks on Window Servers.
705 */
706static void *
707smbfs_create_windows_symlink_data(const char *target, size_t targetlen,
708								  uint32_t *rtlen)
709{
710	MD5_CTX md5;
711	uint32_t state[4];
712	uint32_t datalen, filelen;
713	char *wbuf, *wp;
714	int	 maxwplen;
715	uint32_t targlen = (uint32_t)targetlen;
716
717	datalen = SMB_SYMHDRLEN + targlen;
718	filelen = SMB_SYMLEN;
719	maxwplen = filelen;
720
721	SMB_MALLOC(wbuf, void *, filelen, M_TEMP, M_WAITOK);
722
723	wp = wbuf;
724	bcopy(smb_symmagic, wp, SMB_SYMMAGICLEN);
725	wp += SMB_SYMMAGICLEN;
726	maxwplen -= SMB_SYMMAGICLEN;
727	(void)snprintf(wp, maxwplen, "%04d\n", targlen);
728	wp += SMB_SYMLENLEN;
729	maxwplen -= SMB_SYMLENLEN;
730	MD5Init(&md5);
731	MD5Update(&md5, (unsigned char *)target, targlen);
732	MD5Final((u_char *)state, &md5);
733	(void)snprintf(wp, maxwplen, "%08x%08x%08x%08x\n", htobel(state[0]),
734				   htobel(state[1]), htobel(state[2]), htobel(state[3]));
735	wp += SMB_SYMMD5LEN;
736	bcopy(target, wp, targlen);
737	wp += targlen;
738	if (datalen < filelen) {
739		*wp++ = '\n';
740		datalen++;
741		if (datalen < filelen)
742			memset((caddr_t)wp, ' ', filelen - datalen);
743	}
744	*rtlen = filelen;
745	return wbuf;
746}
747
748/*
749 * Create a UNIX style symlink using the UNIX extension. This uses the smb trans2
750 * set path info call with a unix link info level. The server will create the symlink
751 * using the path, the data portion of the trans2 message will contain the target.
752 * The target will be a UNIX style target including using forward slashes as the
753 * delemiter.
754 *
755 * The calling routine must hold a reference on the share
756 */
757static int
758smb_setfile_unix_symlink(struct smb_share *share, struct smbnode *dnp,
759							 const char *name, size_t nmlen, char *target,
760							 size_t targetlen, vfs_context_t context)
761{
762	struct smb_t2rq *t2p = NULL;
763	struct mbchain *mbp;
764	int error;
765	char *ntwrkpath = NULL;
766	size_t ntwrkpathlen = targetlen * 2; /* UTF8 to UTF16 can be twice as big */
767
768	SMB_MALLOC(ntwrkpath, char *, ntwrkpathlen, M_SMBFSDATA, M_WAITOK | M_ZERO);
769	/* smb_convert_path_to_network sets the precomosed flag */
770	error = smb_convert_path_to_network(target, targetlen, ntwrkpath,
771										&ntwrkpathlen, '/', NO_SFM_CONVERSIONS,
772										SMB_UNICODE_STRINGS(SSTOVC(share)));
773	if (! error) {
774		error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_SET_PATH_INFORMATION, 1,
775							 context, &t2p);
776	}
777	if (error) {
778		goto done;
779	}
780	mbp = &t2p->t2_tparam;
781	mb_init(mbp);
782	mb_put_uint16le(mbp, SMB_SFILEINFO_UNIX_LINK);
783	mb_put_uint32le(mbp, 0);		/* MBZ */
784	error = smbfs_fullpath(mbp, dnp, name, &nmlen, UTF_SFM_CONVERSIONS,
785						   SMB_UNICODE_STRINGS(SSTOVC(share)), '\\');
786	if (error) {
787		goto done;
788	}
789	mbp = &t2p->t2_tdata;
790	mb_init(mbp);
791	mb_put_mem(mbp, (caddr_t)(ntwrkpath), ntwrkpathlen, MB_MSYSTEM);
792	t2p->t2_maxpcount = 2;
793	t2p->t2_maxdcount = SSTOVC(share)->vc_txmax;
794	error = smb_t2_request(t2p);
795
796done:
797	SMB_FREE(ntwrkpath, M_SMBFSDATA);
798	if (t2p) {
799		smb_t2_done(t2p);
800	}
801	return error;
802
803}
804
805static int
806smbfs_smb_fsctl(struct smb_share *share,  uint32_t fsctl, SMBFID fid,
807				uint32_t datacnt, struct mbchain *mbp, struct mdchain *mdp,
808				Boolean * moreDataRequired, vfs_context_t context)
809{
810	struct smb_ntrq *ntp = NULL;
811    int error;
812    uint16_t smb1_fid = (uint16_t) fid; /* cast to SMB 1 fid */
813
814	error = smb_nt_alloc(SSTOCP(share), NT_TRANSACT_IOCTL, context, &ntp);
815	if (error) {
816		goto done;
817	}
818	/*
819	 * TotalParameterCount (4 bytes):
820	 * ULONG This field MUST be set to 0x0000.
821	 *
822	 * MaxParameterCount (4 bytes):
823	 * ULONG This field MUST be set to 0x0000.
824	 *
825	 * ParameterCount (4 bytes) :
826	 * ULONG This field MUST be set to 0x0000.
827	 */
828	/*
829	 * MaxDataCount (4 bytes):
830	 * ULONG The max data that can be returned.
831	 */
832	ntp->nt_maxdcount = datacnt;
833
834	/* The NT_TRANSACT_IOCTL setup structure */
835	mb_init(&ntp->nt_tsetup);
836
837	/*
838	 * FunctionCode (4 bytes):
839	 * ULONG Windows NT device or file system control code.
840	 */
841	mb_put_uint32le(&ntp->nt_tsetup, fsctl);
842
843	/* FID (2 bytes):
844	 * USHORT MUST contain a valid FID obtained from a previously successful
845	 * SMB open command. The FID MUST be for either an I/O device or for a
846	 * file system control device. The type of FID being supplied is specified
847	 * by IsFctl.
848	 */
849	mb_put_uint16le(&ntp->nt_tsetup, smb1_fid);
850
851	/*
852	 * IsFctl (1 byte):
853	 * BOOLEAN This field is TRUE if the command is a file system control
854	 * command and the FID is a file system control device. Otherwise, the
855	 * command is a device control command and FID is an I/O device.
856	 *
857	 * Currently always set to true
858	 */
859	mb_put_uint8(&ntp->nt_tsetup, 1);
860
861	/*
862	 * IsFlags (1 byte):
863	 * BOOLEAN If bit 0 is set, the command is to be applied to a share root
864	 * handle. The share MUST be a Distributed File System (DFS) type.
865	 *
866	 * Currently always set to false
867	 */
868	mb_put_uint8(&ntp->nt_tsetup, 0);
869
870	/*
871	 * NT_Trans_Parameters (variable): (0 bytes):
872	 * No NT_Trans parameters are sent in this request.
873	 */
874	/*
875	 * NT_Trans_Data (variable):
876	 * The raw bytes that are passed to the fsctl or ioctl function as the
877	 * input buffer.
878	 */
879	if (mbp) {
880		/* Use the mbchain passed in */
881		ntp->nt_tdata = *mbp;
882		memset(mbp, 0, sizeof(*mbp));
883	}
884
885	error = smb_nt_request(ntp);
886	if (error) {
887		/* The data buffer wasn't big enough. Caller will have to retry. */
888		if (moreDataRequired && (ntp->nt_flags & SMBT2_MOREDATA)) {
889			*moreDataRequired = TRUE;
890		}
891		goto done;
892	}
893	if (ntp->nt_rdata.md_top && mdp) {
894		SMBSYMDEBUG("Repase data size = %d\n", (int)datalen);
895		/* Store the mbuf info into their mdchain */
896		md_initm(mdp, ntp->nt_rdata.md_top);
897		/* Clear it out so we don't free the mbuf */
898		memset(&ntp->nt_rdata, 0, sizeof(ntp->nt_rdata));
899	}
900
901done:
902	if (ntp) {
903		smb_nt_done(ntp);
904	}
905
906	return error;
907
908}
909
910void
911smbfs_update_symlink_cache(struct smbnode *np, char *target, size_t targetlen)
912{
913	struct timespec ts;
914	if (np->n_symlink_target != NULL) {
915        SMB_FREE(np->n_symlink_target, M_TEMP);
916    }
917	np->n_symlink_target_len = 0;
918	np->n_symlink_target = smb_strndup(target, targetlen);
919	if (np->n_symlink_target) {
920		np->n_symlink_target_len = targetlen;
921		nanouptime(&ts);
922		np->n_symlink_cache_timer = ts.tv_sec;
923	}
924}
925
926/*
927 * Create a symbolic link since the server supports the UNIX extensions. This
928 * allows us to access and share symbolic links with AFP and NFS.
929 *
930 * The calling routine must hold a reference on the share
931 */
932int
933smbfs_smb_create_unix_symlink(struct smb_share *share, struct smbnode *dnp,
934							  const char *in_name, size_t in_nmlen, char *target,
935							  size_t targetlen, struct smbfattr *fap,
936							  vfs_context_t context)
937{
938	const char *name = in_name;
939	size_t nmlen = in_nmlen;
940	int error;
941
942	memset(fap, 0, sizeof(*fap));
943	error = smb_setfile_unix_symlink(share, dnp, name, nmlen, target,
944										 targetlen, context);
945	if (error) {
946		goto done;
947	}
948	/*
949	 * The smb_setfile_unix_symlink call does not return any meta data
950	 * info that includes the inode number of the item. We could just dummy up
951	 * these values, but that wouldn't be correct and besides we would
952	 * just need invalidate the cache, which would cause a lookup anyways.
953	 *
954	 * Seems if wide links are turned off Snow Leopard servers will return
955	 * access denied on any lookup of the symbolic link. So for now dummy up
956	 * the file's attribute if an error is returned on the lookup. If this gets
957	 * fixed in the future then we could remove this code, but we need to cleanup
958	 * on failure.
959	 *
960	 * We should cleanup on failure, but we don't do that in any of the
961	 * other failure case. See <rdar://problem/8498673>
962	 */
963	error = smbfs_lookup(share, dnp, &name, &nmlen, fap, context);
964	if (error) {
965		struct smbmount *smp = dnp->n_mount;
966
967		fap->fa_attr = SMB_EFA_NORMAL;
968		fap->fa_size = targetlen;
969		fap->fa_data_alloc = roundup(fap->fa_size, smp->sm_statfsbuf.f_bsize);
970		nanotime(&fap->fa_crtime);	/* Need current date/time, so use nanotime */
971		fap->fa_atime = fap->fa_crtime;
972		fap->fa_chtime = fap->fa_crtime;
973		fap->fa_mtime = fap->fa_crtime;
974		fap->fa_ino = smbfs_getino(dnp, in_name, in_nmlen); /* SMB 1 only */
975		nanouptime(&fap->fa_reqtime);
976		fap->fa_valid_mask |= FA_VTYPE_VALID;
977		fap->fa_vtype = VLNK;
978		fap->fa_nlinks = 1;
979		fap->fa_flags_mask = EXT_REQUIRED_BY_MAC;
980		fap->fa_unix = TRUE;
981		error = 0;
982	}
983done:
984	/* If lookup returned a new name free it we never need that name */
985	if (name != in_name) {
986		SMB_FREE(name, M_SMBNODENAME);
987	}
988	if (error) {
989		SMBWARNING("Creating symlink for %s failed! error = %d\n", name, error);
990	}
991	return error;
992}
993
994/*
995 * This server doesn't support UNIX or reparse point style symbolic links, so
996 * create a faked up symbolic link, using the Conrad and Steve French method
997 * for storing and reading symlinks on Window Servers.
998 *
999 * NOTE: We should remove creating these in the future, but first we need to see
1000 * if we can get reparse point style symbolic links working.
1001 *
1002 * The calling routine must hold a reference on the share
1003 */
1004int
1005smbfs_smb_create_windows_symlink(struct smb_share *share, struct smbnode *dnp,
1006                                 const char *name, size_t nmlen,
1007                                 char *target, size_t targetlen,
1008                                 struct smbfattr *fap, vfs_context_t context)
1009{
1010    uint32_t wlen = 0;
1011    uio_t uio = NULL;
1012    char *wdata = NULL;
1013    int error;
1014    SMBFID fid = 0;
1015    uint64_t create_flags = SMB2_CREATE_DO_CREATE | SMB2_CREATE_GET_MAX_ACCESS;
1016
1017    wdata = smbfs_create_windows_symlink_data(target, targetlen, &wlen);
1018    if (!wdata) {
1019        error = ENOMEM;
1020        goto done;
1021    }
1022
1023    uio = uio_create(1, 0, UIO_SYSSPACE, UIO_WRITE);
1024    if (uio == NULL) {
1025        error = ENOMEM;
1026        goto done;
1027    }
1028
1029    uio_addiov(uio, CAST_USER_ADDR_T(wdata), wlen);
1030
1031    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
1032        /* SMB 2/3  - compound Create/Write/Close */
1033        error = smb2fs_smb_cmpd_create_write(share, dnp,
1034                                             name, nmlen,
1035                                             NULL, 0,
1036                                             SMB2_FILE_WRITE_DATA, fap,
1037                                             create_flags, uio,
1038                                             NULL, 0,
1039                                             context);
1040    }
1041    else {
1042        /* SMB 1 */
1043        error = smbfs_smb_create(share, dnp, name, nmlen, SMB2_FILE_WRITE_DATA,
1044                                 &fid, FILE_CREATE, 0, fap, context);
1045        if (error) {
1046            goto done;
1047        }
1048
1049        error = smb_smb_write(share, fid, uio, 0, context);
1050
1051        (void) smbfs_smb_close(share, fid, context);
1052    }
1053
1054    if (!error)	{
1055        /* We just changed the size of the file */
1056        fap->fa_size = wlen;
1057    }
1058
1059done:
1060    if (uio != NULL) {
1061        uio_free(uio);
1062    }
1063
1064    if (wdata) {
1065        SMB_FREE(wdata, M_TEMP);
1066    }
1067
1068    if (error) {
1069        SMBWARNING("Creating symlink for %s failed! error = %d\n", name, error);
1070    }
1071
1072    return error;
1073}
1074
1075/*
1076 * This server support reparse point style symbolic links, This allows us to
1077 * access and share symbolic links with AFP and NFS.
1078 *
1079 * The calling routine must hold a reference on the share
1080 */
1081int
1082smb1fs_smb_create_reparse_symlink(struct smb_share *share, struct smbnode *dnp,
1083                                  const char *name, size_t nmlen, char *target,
1084                                  size_t targetlen, struct smbfattr *fap,
1085                                  vfs_context_t context)
1086{
1087	struct smbmount *smp = dnp->n_mount;
1088	int error;
1089    SMBFID fid = 0;
1090	struct mbchain	mbp;
1091	size_t path_len;
1092	char *path;
1093	uint16_t reparseLen;
1094	uint16_t SubstituteNameOffset, SubstituteNameLength;
1095	uint16_t PrintNameOffset, PrintNameLength;
1096    int need_close = 0;
1097    uint32_t rights = SMB2_FILE_WRITE_DATA |  SMB2_FILE_WRITE_ATTRIBUTES | SMB2_DELETE;
1098
1099	error = smbfs_smb_ntcreatex(share, dnp,
1100                                rights, NTCREATEX_SHARE_ACCESS_ALL, VLNK,
1101                                &fid, name, nmlen,
1102                                FILE_CREATE, FALSE, fap,
1103                                TRUE, NULL, context);
1104	if (error) {
1105		goto done;
1106	}
1107    need_close = 1;
1108
1109	path_len = (targetlen * 2) + 2;	/* Start with the max possible size */
1110	SMB_MALLOC(path, char *, path_len, M_TEMP, M_WAITOK | M_ZERO);
1111	if (path == NULL) {
1112		error = ENOMEM;
1113		goto done;
1114	}
1115	/* Convert it to a network style path */
1116	error = smb_convert_path_to_network(target, targetlen, path, &path_len,
1117										'\\', SMB_UTF_SFM_CONVERSIONS,
1118										SMB_UNICODE_STRINGS(SSTOVC(share)));
1119	if (error) {
1120		SMB_FREE(path, M_TEMP);
1121		goto done;
1122	}
1123	SubstituteNameLength = path_len;
1124	SubstituteNameOffset = 0;
1125	PrintNameOffset = SubstituteNameLength;
1126	PrintNameLength = SubstituteNameLength;
1127	reparseLen = SubstituteNameLength + PrintNameLength + 12;
1128	mb_init(&mbp);
1129	mb_put_uint32le(&mbp, IO_REPARSE_TAG_SYMLINK);
1130	mb_put_uint16le(&mbp, reparseLen);
1131	mb_put_uint16le(&mbp, 0);	/* Reserved */
1132	mb_put_uint16le(&mbp, SubstituteNameOffset);
1133	mb_put_uint16le(&mbp, SubstituteNameLength);
1134	mb_put_uint16le(&mbp, PrintNameOffset);
1135	mb_put_uint16le(&mbp, PrintNameLength);
1136	/*
1137	 * Flags field can be either SYMLINK_FLAG_ABSOLUTE or SYMLINK_FLAG_RELATIVE.
1138	 * If the target starts with a slash assume its absolute otherwise it must
1139	 * me realative.
1140	 */
1141	if (*target == '/') {
1142		mb_put_uint32le(&mbp, SYMLINK_FLAG_ABSOLUTE);
1143	} else {
1144		mb_put_uint32le(&mbp, SYMLINK_FLAG_RELATIVE);
1145	}
1146	mb_put_mem(&mbp, path, SubstituteNameLength, MB_MSYSTEM);
1147	mb_put_mem(&mbp, path, PrintNameLength, MB_MSYSTEM);
1148	SMB_FREE(path, M_TEMP);
1149	error = smbfs_smb_fsctl(share, FSCTL_SET_REPARSE_POINT, fid, 0, &mbp,
1150							NULL, NULL, context);
1151	mb_done(&mbp);
1152	/*
1153	 * Windows systems requires special user access to create a reparse symlinks.
1154	 * They default to only allow administrator symlink create access. This can
1155	 * be changed on the server, but we are going to run into this issue. So if
1156	 * we get an access error on the fsctl then we assume this user doesn't have
1157	 * create symlink rights and we need to fallback to the old Conrad/Steve
1158	 * symlinks. Since the create work we know the user has access to the file
1159	 * system, they just don't have create symlink rights. We never fallback if
1160	 * the server is running darwin.
1161	 */
1162	if ((error == EACCES) && !(SSTOVC(share)->vc_flags & SMBV_DARWIN)) {
1163		smp->sm_flags &= ~MNT_SUPPORTS_REPARSE_SYMLINKS;
1164	}
1165
1166	if (error) {
1167		/* Failed to create the symlink, remove the file on close */
1168		(void)smbfs_smb_markfordelete(share, fid, context);
1169	} else {
1170		/* Reset any other fap information */
1171		fap->fa_size = targetlen;
1172		/* The FSCTL_SET_REPARSE_POINT succeeded, so mark it as a reparse point */
1173		fap->fa_attr |= SMB_EFA_REPARSE_POINT;
1174		fap->fa_valid_mask |= FA_REPARSE_TAG_VALID;
1175		fap->fa_reparse_tag = IO_REPARSE_TAG_SYMLINK;
1176		fap->fa_valid_mask |= FA_VTYPE_VALID;
1177		fap->fa_vtype = VLNK;
1178	}
1179
1180done:
1181	if (need_close) {
1182		(void)smbfs_smb_close(share, fid, context);
1183	}
1184
1185	/*
1186	 * This user doesn't have access to create a reparse symlink, create the
1187	 * old style symlink.
1188	 */
1189	if ((error == EACCES) && !(smp->sm_flags & MNT_SUPPORTS_REPARSE_SYMLINKS)) {
1190		error = smbfs_smb_create_windows_symlink(share, dnp, name, nmlen, target,
1191												 targetlen, fap, context);
1192	}
1193
1194	if (error) {
1195		SMBWARNING("Creating symlink for %s failed! error = %d\n", name, error);
1196	}
1197	return error;
1198}
1199
1200/*
1201 * Get the reparse tag and if its a symlink get the target and target size.
1202 *
1203 * The calling routine must hold a reference on the share
1204 *
1205 */
1206int
1207smbfs_smb_get_reparse_tag(struct smb_share *share, SMBFID fid,
1208                          uint32_t *reparseTag, char **outTarget,
1209                          size_t *outTargetlen, vfs_context_t context)
1210{
1211	int error;
1212	Boolean moreDataRequired = FALSE;
1213	uint32_t rdatacnt = SSTOVC(share)->vc_txmax;
1214	struct mdchain mdp;
1215	uint16_t reparseLen = 0;
1216	uint16_t SubstituteNameOffset = 0;
1217	uint16_t SubstituteNameLength = 0;
1218	uint16_t PrintNameOffset = 0;
1219	uint16_t PrintNameLength = 0;
1220	uint32_t Flags = 0;
1221	char *ntwrkname = NULL;
1222	char *target = NULL;
1223	size_t targetlen;
1224
1225	memset(&mdp, 0, sizeof(mdp));
1226
1227	error = smbfs_smb_fsctl(share, FSCTL_GET_REPARSE_POINT, fid, rdatacnt, NULL,
1228							&mdp, &moreDataRequired, context);
1229	if (!error && !mdp.md_top) {
1230		error = ENOENT;
1231	}
1232	if (error) {
1233		goto done;
1234	}
1235
1236	md_get_uint32le(&mdp, reparseTag);
1237	/* Should have checked to make sure the node reparse tag matches */
1238	if (*reparseTag != IO_REPARSE_TAG_SYMLINK) {
1239		md_done(&mdp);
1240		goto done;
1241	}
1242	md_get_uint16le(&mdp, &reparseLen);
1243	md_get_uint16le(&mdp, NULL);	/* Reserved */
1244	md_get_uint16le(&mdp, &SubstituteNameOffset);
1245	md_get_uint16le(&mdp, &SubstituteNameLength);
1246	md_get_uint16le(&mdp, &PrintNameOffset);
1247	md_get_uint16le(&mdp, &PrintNameLength);
1248	/*
1249	 * Flags field can be either SYMLINK_FLAG_ABSOLUTE or SYMLINK_FLAG_RELATIVE,
1250	 * in either case we don't care and just ignore it for now.
1251	 */
1252	md_get_uint32le(&mdp, &Flags);
1253	SMBSYMDEBUG("reparseLen = %d SubstituteNameOffset = %d SubstituteNameLength = %d PrintNameOffset = %d PrintNameLength = %d Flags = %d\n",
1254				reparseLen,
1255				SubstituteNameOffset, SubstituteNameLength,
1256				PrintNameOffset, PrintNameLength, Flags);
1257	/*
1258	 * Mount Point Reparse Data Buffer
1259	 * A mount point has a substitute name and a print name associated with it.
1260	 * The substitute name is a pathname (section 2.1.5) identifying the target
1261	 * of the mount point. The print name SHOULD be an informative pathname
1262	 * (section 2.1.5), suitable for display to a user, that also identifies the
1263	 * target of the mount point. Neither of these pathnames can contain dot
1264	 * directory names.
1265	 *
1266	 * So the above implies that we should always use the substitute name, but
1267	 * my guess is they are always the same in symbolic link case.
1268	 */
1269	/* Never allocate more than our transcation size buffer */
1270	if ((SubstituteNameLength == 0) || (SubstituteNameLength > SSTOVC(share)->vc_txmax)) {
1271		error = ENOMEM;
1272		SMBSYMDEBUG("SubstituteNameLength too large or zero %d \n", SubstituteNameLength);
1273		md_done(&mdp);
1274		goto done;
1275	}
1276
1277	if (SubstituteNameOffset) {
1278		md_get_mem(&mdp, NULL, SubstituteNameOffset, MB_MSYSTEM);
1279	}
1280
1281	SMB_MALLOC(ntwrkname, char *, (size_t)SubstituteNameLength, M_TEMP, M_WAITOK | M_ZERO);
1282	if (ntwrkname == NULL) {
1283		error = ENOMEM;
1284	} else {
1285		error = md_get_mem(&mdp, (void *)ntwrkname, (size_t)SubstituteNameLength, MB_MSYSTEM);
1286	}
1287	md_done(&mdp);
1288	if (error) {
1289		goto done;
1290	}
1291	targetlen = SubstituteNameLength * 9 + 1;
1292	SMB_MALLOC(target, char *, targetlen, M_TEMP, M_WAITOK | M_ZERO);
1293	if (target == NULL) {
1294		error = ENOMEM;
1295	} else {
1296		error = smb_convert_network_to_path(ntwrkname, SubstituteNameLength, target,
1297											&targetlen, '\\', UTF_SFM_CONVERSIONS,
1298											SMB_UNICODE_STRINGS(SSTOVC(share)));
1299	}
1300	if (!error) {
1301		*outTarget = target;
1302		*outTargetlen = targetlen;
1303		target = NULL;
1304	}
1305
1306done:
1307	SMB_FREE(ntwrkname, M_TEMP);
1308	SMB_FREE(target, M_TEMP);
1309	return error;
1310
1311}
1312
1313/*
1314 * The symbolic link is stored in a reparse point, support by some windows servers
1315 * and Darwin servers.
1316 *
1317 * The calling routine must hold a reference on the share
1318 *
1319 */
1320int
1321smb1fs_smb_reparse_read_symlink(struct smb_share *share, struct smbnode *np,
1322                                struct uio *uiop, vfs_context_t context)
1323{
1324	int error;
1325	uint32_t reparseTag = 0;
1326    SMBFID fid = 0;
1327	char *target = NULL;
1328	size_t targetlen = 0;
1329    int need_close = 0;
1330
1331	error = smbfs_tmpopen(share, np,
1332                          SMB2_FILE_READ_DATA | SMB2_FILE_READ_ATTRIBUTES,
1333                          &fid, context);
1334	if (error) {
1335		goto done;
1336	}
1337    need_close = 1;
1338
1339	error = smbfs_smb_get_reparse_tag(share, fid, &reparseTag, &target,
1340                                      &targetlen, context);
1341	if (!error && (reparseTag != IO_REPARSE_TAG_SYMLINK)) {
1342		error = ENOENT;
1343	} else if (!error && (target == NULL)) {
1344		error = EINVAL;
1345	}
1346	if (error) {
1347		goto done;
1348	}
1349
1350	/* smbfs_update_symlink_cache will deal with the null pointer */
1351    SMBSYMDEBUG_LOCK(np, "%s --> %s\n", np->n_name, target);
1352
1353	smbfs_update_symlink_cache(np, target, targetlen);
1354	error = uiomove(target, (int)targetlen, uiop);
1355
1356done:
1357	SMB_FREE(target, M_TEMP);
1358
1359	if (need_close == 1) {
1360		(void)smbfs_tmpclose(share, np, fid, context);
1361	}
1362
1363	if (error) {
1364		SMBWARNING_LOCK(np, "%s failed %d\n", np->n_name, error);
1365	}
1366
1367	return error;
1368}
1369
1370/*
1371 * Supports reading a faked up symbolic link. This is Conrad and Steve
1372 * French method for storing and reading symlinks on Window Servers.
1373 *
1374 * The calling routine must hold a reference on the share
1375 *
1376 */
1377int
1378smbfs_smb_windows_read_symlink(struct smb_share *share, struct smbnode *np,
1379							   struct uio *uiop, vfs_context_t context)
1380{
1381	unsigned char *wbuf, *cp;
1382	unsigned len, flen;
1383	uio_t uio;
1384	int error;
1385    SMBFID fid = 0;
1386	char *target = NULL;
1387
1388	flen = SMB_SYMLEN;
1389	SMB_MALLOC(wbuf, void *, flen, M_TEMP, M_WAITOK);
1390
1391	error = smbfs_tmpopen(share, np, SMB2_FILE_READ_DATA, &fid, context);
1392	if (error)
1393		goto out;
1394
1395	uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
1396	uio_addiov(uio, CAST_USER_ADDR_T(wbuf), flen);
1397	error = smb_smb_read(share, fid, uio, context);
1398	uio_free(uio);
1399
1400	(void)smbfs_tmpclose(share, np, fid, context);
1401	if (error)
1402		goto out;
1403
1404	for (len = 0, cp = wbuf + SMB_SYMMAGICLEN;
1405	     cp < wbuf + SMB_SYMMAGICLEN + SMB_SYMLENLEN-1; cp++) {
1406		if (*cp < '0' || *cp > '9') {
1407			SMBWARNING("symlink length nonnumeric: %c (0x%x)\n", *cp, *cp);
1408			return (EINVAL);
1409		}
1410		len *= 10;
1411		len += *cp - '0';
1412	}
1413	if (len != np->n_size) {
1414		SMBWARNING("symlink length payload changed from %u to %u\n",
1415				   (unsigned)np->n_size, len);
1416		np->n_size = len;
1417	}
1418    /* %%% is this function valid for SMB 2/3, note the SMBHDRLEN below */
1419	target = (char *)(wbuf + SMB_SYMHDRLEN);
1420
1421    SMBSYMDEBUG_LOCK(np, "%s --> %s\n", np->n_name, target);
1422
1423	smbfs_update_symlink_cache(np, target, len);
1424	error = uiomove(target, (int)len, uiop);
1425out:
1426	SMB_FREE(wbuf, M_TEMP);
1427
1428	if (error) {
1429		SMBWARNING_LOCK(np, "%s failed %d\n", np->n_name, error);
1430	}
1431	return (error);
1432}
1433
1434/*
1435 * Support for reading a symbolic link that resides on a UNIX server. This allows
1436 * us to access and share symbolic links with AFP and NFS.
1437 *
1438 * The calling routine must hold a reference on the share
1439 *
1440 */
1441int
1442smbfs_smb_unix_read_symlink(struct smb_share *share, struct smbnode *np,
1443					   struct uio *uiop, vfs_context_t context)
1444{
1445	struct smb_t2rq *t2p;
1446	int error;
1447	struct mbchain *mbp;
1448	struct mdchain *mdp;
1449	char *ntwrkname = NULL;
1450	char *target;
1451	size_t targetlen;
1452	size_t nmlen;
1453
1454    /* %%% To Do - implement for SMB 2/3 */
1455    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
1456        SMBERROR("smbfs_smb_unix_read_symlink not supported by SMB 2/3\n");
1457        error = ENOTSUP;
1458        return error;
1459    }
1460
1461	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_QUERY_PATH_INFORMATION, 1, context, &t2p);
1462	if (error)
1463		return error;
1464	mbp = &t2p->t2_tparam;
1465	mb_init(mbp);
1466	mb_put_uint16le(mbp, SMB_QFILEINFO_UNIX_LINK);
1467	mb_put_uint32le(mbp, 0);
1468	error = smbfs_fullpath(mbp, np, NULL, NULL, UTF_SFM_CONVERSIONS,
1469						   SMB_UNICODE_STRINGS(SSTOVC(share)), '\\');
1470	if (error)
1471	    goto out;
1472	t2p->t2_maxpcount = 2;
1473	t2p->t2_maxdcount = SSTOVC(share)->vc_txmax;
1474	error = smb_t2_request(t2p);
1475	if (error)
1476	    goto out;
1477	mdp = &t2p->t2_rdata;
1478	/*
1479	 * At this point md_cur and md_top have the same value. Now all the md_get
1480	 * routines will will check for null, but just to be safe we check here
1481	 */
1482	if (mdp->md_top == NULL) {
1483		error = EIO;
1484	    goto out;
1485	}
1486	/* Get the size of the data that contains the symbolic link */
1487    m_fixhdr(mdp->md_top);
1488	nmlen = mbuf_pkthdr_len(mdp->md_top);
1489	SMBSYMDEBUG("network len of the symbolic link = %ld\n", nmlen);
1490	SMB_MALLOC(ntwrkname, char *, nmlen, M_TEMP, M_WAITOK);
1491	if (ntwrkname == NULL) {
1492		error = ENOMEM;
1493	} else {
1494		/* Read in the data that contains the symbolic link */
1495		error = md_get_mem(mdp, (void *)ntwrkname, nmlen, MB_MSYSTEM);
1496	}
1497	if (error)
1498	    goto out;
1499#ifdef DEBUG_SYMBOLIC_LINKS
1500	smb_hexdump(__FUNCTION__, "Symlink: ", (u_char *)ntwrkname, nmlen);
1501#endif // DEBUG_SYMBOLIC_LINKS
1502	/*
1503	 * The Symbolic link data is a UNIX style symbolic link, except it is in UTF16
1504	 * format. The unix slash is the delemter used. The path should end with two
1505	 * null bytes as a terminator. The smb_convert_network_to_path  does not expect
1506	 * nmlen to include those bytes, so we can just back those bytes out. Nothiing
1507	 * in the reference states that the null bytes are require, but this would be
1508	 * the normal way to handle this type of string in SMB.
1509	 */
1510	nmlen -= 2;
1511	targetlen = nmlen * 9 + 1;
1512	SMB_MALLOC(target, char *, targetlen, M_TEMP, M_WAITOK | M_ZERO);
1513	error = smb_convert_network_to_path(ntwrkname, nmlen, target,
1514											&targetlen, '/', UTF_SFM_CONVERSIONS,
1515											SMB_UNICODE_STRINGS(SSTOVC(share)));
1516	if (!error) {
1517		SMBSYMDEBUG_LOCK(np, "%s --> %s\n", np->n_name, target);
1518		smbfs_update_symlink_cache(np, target, targetlen);
1519		error = uiomove(target, (int)targetlen, uiop);
1520	}
1521
1522	SMB_FREE(target, M_TEMP);
1523
1524out:
1525	SMB_FREE(ntwrkname, M_TEMP);
1526	smb_t2_done(t2p);
1527	if (error) {
1528		SMBWARNING_LOCK(np, "%s failed %d\n", np->n_name, error);
1529	}
1530	return error;
1531}
1532
1533/*
1534 * When calling this routine be very careful when passing the arguments.
1535 * Depending on the arguments different actions will be taken with this routine.
1536 *
1537 * The calling routine must hold a reference on the share
1538 *
1539 */
1540int
1541smb1fs_smb_qstreaminfo(struct smb_share *share, struct smbnode *np,
1542                       const char *namep, size_t name_len,
1543                       const char *strmname,
1544                       uio_t uio, size_t *sizep,
1545                       uint64_t *strmsize, uint64_t *strmsize_alloc,
1546                       uint32_t *stream_flagsp,
1547                       vfs_context_t context)
1548{
1549	struct smb_t2rq *t2p;
1550	int error;
1551	struct mbchain *mbp;
1552	struct mdchain *mdp;
1553	uint32_t next, nlen, used;
1554	uint64_t stream_size, stream_alloc_size;
1555	enum stream_types stype = kNoStream;
1556	struct timespec ts;
1557	int foundStream = (strmname) ? FALSE : TRUE; /* Are they looking for a specific stream */
1558	char *streamName = NULL;		/* current file name */
1559	size_t streamNameLen = 0;	/* name len */
1560    size_t in_name_len = name_len;
1561    const char *fname;
1562    uint32_t is_data_stream = 0;
1563    int n_name_locked = 0;
1564
1565    /*
1566     * Two usage cases:
1567     * 1) Given np and namep == NULL. Query the path of np
1568     * 2) Given np and namep (must be readdirattr). Query PARENT np and
1569     * child namep. In this case, do not update vnode np as that is the parent.
1570     *
1571     * In both cases, Query for a list of streams and if streams are found,
1572     * see if they match stream_namep that was passed in.
1573     */
1574
1575    if (namep == NULL) {
1576        /* Not readdirattr case */
1577        if ((np->n_fstatus & kNO_SUBSTREAMS) ||
1578            (np->n_dosattr & SMB_EFA_REPARSE_POINT)) {
1579            foundStream = FALSE;
1580            error = ENOATTR;
1581            goto done;
1582        }
1583    }
1584
1585	if (sizep)
1586		*sizep = 0;
1587
1588	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_QUERY_PATH_INFORMATION, 1, context, &t2p);
1589	if (error)
1590		return (error);
1591
1592	mbp = &t2p->t2_tparam;
1593	mb_init(mbp);
1594	/*
1595	 * SAMBA only supports the SMB_QFILEINFO_STREAM_INFORMATION level. Samba declined to
1596	 * support the older info level with a comment claiming doing so caused a BSOD. Not sure
1597	 * what that is all about. I have never seen that happen, but there is no differences
1598	 * between the two levels. So if the server supports the new levels then use it.
1599	 */
1600	if (VC_CAPS(SSTOVC(share)) & SMB_CAP_INFOLEVEL_PASSTHRU)
1601		mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFORMATION);
1602	else
1603		mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO);
1604	mb_put_uint32le(mbp, 0);
1605
1606	error = smbfs_fullpath(mbp, np, namep, &in_name_len, UTF_SFM_CONVERSIONS,
1607						   SMB_UNICODE_STRINGS(SSTOVC(share)), '\\');
1608	if (error)
1609		goto out;
1610	t2p->t2_maxpcount = 2;
1611	t2p->t2_maxdcount = SSTOVC(share)->vc_txmax;
1612	error = smb_t2_request(t2p);
1613	if (error)
1614		goto out;
1615
1616	/*
1617	 * Should never happen since we test for UNICODE CAPS when mounting, but
1618	 * just to be safe never let them send us a Query Stream call that doesn't
1619	 * have the UNICODE bit set in the flags field. See <rdar://problem/7653132>
1620	 */
1621	if (!SMB_UNICODE_STRINGS(SSTOVC(share))) {
1622		error = ENOTSUP;
1623		goto out;
1624	}
1625	mdp = &t2p->t2_rdata;
1626	/*
1627	 * There could be no streams info associated with the item. You will find this with directory
1628	 * or items copied from FAT file systems. Nothing to process just get out.
1629	 */
1630	if (mdp->md_cur == NULL)
1631		goto out;
1632
1633	do {
1634		char *ntwrk_name = NULL;
1635
1636		stream_size = 0;
1637        stream_alloc_size = 0;
1638		if ((error = md_get_uint32le(mdp, &next)))
1639			goto out;
1640		used = 4;
1641		if ((error = md_get_uint32le(mdp, &nlen))) /* name length */
1642			goto out;
1643		used += 4;
1644		/* If this is the resource fork should we save this information */
1645		if ((error = md_get_uint64le(mdp, &stream_size))) /* stream size */
1646			goto out;
1647		used += 8;
1648		if ((error = md_get_uint64le(mdp, &stream_alloc_size))) /* alloc size */
1649			goto out;
1650		used += 8;
1651		/*
1652		 * Sanity check to limit DoS or buffer overrun attempts.
1653		 * Make sure the length is not bigger than our max buffers size.
1654		 */
1655		if (nlen > SSTOVC(share)->vc_txmax) {
1656			error = EBADRPC;
1657			goto out;
1658		}
1659		SMB_MALLOC(ntwrk_name, char *, nlen, M_SMBFSDATA, M_WAITOK | M_ZERO);
1660		if ((error = md_get_mem(mdp, ntwrk_name, nlen, MB_MSYSTEM))) {
1661			SMB_FREE(ntwrk_name, M_SMBFSDATA);
1662			goto out;
1663		}
1664		used += nlen;
1665
1666		/*
1667		 * Ignore any trailing null, not that we expect them
1668		 * NOTE: MS-CIFS states that the stream name is alway in UNICODE. We
1669		 * only support streams if the server supports UNICODE.
1670		 */
1671		if ((nlen > 1) && !ntwrk_name[nlen - 1] && !ntwrk_name[nlen - 2])
1672			nlen -= 2;
1673		streamNameLen = nlen;
1674		streamName = smbfs_ntwrkname_tolocal(ntwrk_name, &streamNameLen,
1675											 SMB_UNICODE_STRINGS(SSTOVC(share)));
1676		SMB_FREE(ntwrk_name, M_SMBFSDATA);
1677		/*
1678		 * We should now have a name in the form : <foo> :$DATA Where <foo> is
1679		 * UTF-8 w/o null termination. If it isn't in that form we want to LOG it
1680		 * and skip it. Note we want to skip w/o logging the "data fork" entry,
1681		 * which is simply ::$DATA Otherwise we want to uiomove out <foo> with a null added.
1682		 */
1683        if (namep == NULL) {
1684            lck_rw_lock_shared(&np->n_name_rwlock);
1685            n_name_locked = 1;
1686            fname = np->n_name;
1687        }
1688        else {
1689            /* readdirattr case - parent np and child namep */
1690            fname = namep;
1691        }
1692
1693		if (smbfs_smb_undollardata(fname, streamName, &streamNameLen,
1694                                   &is_data_stream)) {
1695			const char *s;
1696
1697            if (n_name_locked) {
1698                lck_rw_unlock_shared(&np->n_name_rwlock);
1699                n_name_locked = 0;
1700            }
1701
1702			/* the "+ 1" skips over the leading colon */
1703			s = streamName + 1;
1704
1705			/* Check for special case streams (resource fork and finder info */
1706			if ((streamNameLen >= sizeof(SFM_RESOURCEFORK_NAME)) &&
1707				(!strncasecmp(s, SFM_RESOURCEFORK_NAME, sizeof(SFM_RESOURCEFORK_NAME)))) {
1708				stype |= kResourceFrk;
1709
1710                if (namep == NULL) {
1711                    /* We always get the resource fork size and cache it here. */
1712                    lck_mtx_lock(&np->rfrkMetaLock);
1713                    np->rfrk_size = stream_size;
1714                    np->rfrk_alloc_size = stream_alloc_size;
1715                    nanouptime(&ts);
1716                    np->rfrk_cache_timer = ts.tv_sec;
1717                    lck_mtx_unlock(&np->rfrkMetaLock);
1718                }
1719
1720				/*
1721				 * The Resource fork and Finder info names are special and get
1722				 * translated between stream names and extended attribute names.
1723				 * In this case we need to make sure the correct name gets used.
1724				 * So we are looking for a specfic stream use its stream name
1725				 * otherwise use its extended attribute name.
1726				 */
1727				if ((uio == NULL) && strmname && (sizep == NULL)) {
1728					s = SFM_RESOURCEFORK_NAME;
1729					streamNameLen = sizeof(SFM_RESOURCEFORK_NAME);
1730				} else {
1731					s = XATTR_RESOURCEFORK_NAME;
1732					streamNameLen = sizeof(XATTR_RESOURCEFORK_NAME);
1733				}
1734				/*
1735				 * The uio means we are gettting this from a listxattr call, never
1736				 * display zero length resource forks. Resource forks should
1737				 * always contain a resource map. Seems CoreService never deleted
1738				 * the resource fork, they just set the eof to zero. We need to
1739				 * handle these resource forks here.
1740				 */
1741				if (uio && (stream_size == 0))
1742					goto skipentry;
1743
1744			} else if ((streamNameLen >= sizeof(SFM_FINDERINFO_NAME)) &&
1745					(!strncasecmp(s, SFM_FINDERINFO_NAME, sizeof(SFM_FINDERINFO_NAME)))) {
1746				/*
1747				 * They have an AFP_Info stream and it has no size must be a Samba
1748				 * server. We treat this the same as if the file has no Finder Info
1749				 */
1750				if (stream_size == 0)
1751					goto skipentry;
1752
1753				stype |= kFinderInfo;
1754				/*
1755				 * The Resource fork and Finder info names are special and get
1756				 * translated between stream names and extended attribute names.
1757				 * In this case we need to make sure the correct name gets used.
1758				 * So we are looking for a specfic stream use its stream name
1759				 * otherwise use its extended attribute name.
1760				 */
1761				if ((uio == NULL) && strmname && (sizep == NULL)) {
1762					s = SFM_FINDERINFO_NAME;
1763					streamNameLen = sizeof(SFM_FINDERINFO_NAME);
1764				}
1765				else {
1766					s = XATTR_FINDERINFO_NAME;
1767					streamNameLen = sizeof(XATTR_FINDERINFO_NAME);
1768				}
1769			 }
1770
1771			/*
1772			 * Depending on what is passed in we handle the data in two different ways.
1773			 *	1. If they have a uio then just put all the stream names into the uio buffer.
1774			 *	2. If they pass in a stream name then they just want the size of that stream.
1775			 *
1776			 * NOTE: If there is nothing in the stream we will not return it in the list. This
1777			 *       allows us to hide empty streams from copy engines.
1778			 *
1779			 * We never return SFM_DESKTOP_NAME or SFM_IDINDEX_NAME streams.
1780			 */
1781			if (( (streamNameLen >= sizeof(SFM_DESKTOP_NAME)) &&
1782				(!strncasecmp(s, SFM_DESKTOP_NAME, sizeof(SFM_DESKTOP_NAME)))) ||
1783				((streamNameLen >= sizeof(SFM_IDINDEX_NAME)) &&
1784				(!strncasecmp(s, SFM_IDINDEX_NAME, sizeof(SFM_IDINDEX_NAME))))) {
1785				/*  Is this a SFM Volume */
1786				if (strmname && (!strncasecmp(SFM_DESKTOP_NAME, strmname, sizeof(SFM_DESKTOP_NAME)))) {
1787					foundStream = TRUE;
1788				}
1789				goto skipentry;
1790			} else if (uio)
1791				uiomove(s, (int)streamNameLen, uio);
1792			else if (!foundStream && strmname && strmsize) {
1793				/* They are looking for a specific stream name and we havn't found it yet. */
1794				nlen = (uint32_t)strnlen(strmname, share->ss_maxfilenamelen+1);
1795				if ((streamNameLen >= nlen) && (!strncasecmp(s, strmname, nlen))) {
1796					*strmsize = stream_size;
1797                    *strmsize_alloc = stream_alloc_size;
1798					foundStream = TRUE;
1799				}
1800			}
1801			/*
1802			 * They could just want to know the buffer size they will need when
1803			 * requesting a list. This has several problem, but we cannot solve
1804			 * them all here. First someone can create a stream/EA between this
1805			 * call and the one they make to get the data. Second this will cause
1806			 * an extra round of traffic. We could cache all of this, but how
1807			 * long would we keep this information around. Could require a large buffer.
1808			 */
1809			if (sizep)
1810				*sizep += streamNameLen;
1811		}
1812
1813        if (n_name_locked) {
1814            lck_rw_unlock_shared(&np->n_name_rwlock);
1815            n_name_locked = 0;
1816        }
1817
1818skipentry:
1819		SMB_FREE(streamName, M_SMBFSDATA);
1820		/*
1821		 * Next should be the offset to the next entry. We have already move into
1822		 * the buffer used bytes. So now need to move pass any remaining pad bytes.
1823		 * So if the value next is larger than the value used, then we need to move
1824		 * that many more bytes into the buffer. If that value is larger than
1825		 * our buffer get out.
1826		 */
1827		if (next > used) {
1828			next -= used;
1829			if (next > SSTOVC(share)->vc_txmax) {
1830				error = EBADRPC;
1831				goto out;
1832			}
1833			md_get_mem(mdp, NULL, next, MB_MSYSTEM);
1834		}
1835	} while (next && !error);
1836
1837out:
1838    if (streamName != NULL) {
1839        SMB_FREE(streamName, M_SMBFSDATA);
1840    }
1841	smb_t2_done(t2p);
1842
1843done:
1844	/*
1845     * If we searched the entire list and did not find a finder info stream,
1846     * then reset the cache timer.
1847     */
1848    if ((stype & kFinderInfo) != kFinderInfo) {
1849        /* set stream_flag indicating no Finder Info */
1850        *stream_flagsp |= SMB_NO_FINDER_INFO;
1851
1852        if (namep == NULL) {
1853            /* Negative cache the Finder Info in the vnode */
1854            bzero(np->finfo, sizeof(np->finfo));
1855            nanouptime(&ts);
1856            np->finfo_cache_timer = ts.tv_sec;
1857        }
1858    }
1859
1860    /*
1861     * If we searched the entire list and did not find a resource stream,
1862     * then reset the cache timer.
1863     */
1864    if ((stype & kResourceFrk) != kResourceFrk) {
1865        /* set stream_flag indicating no Resource Fork */
1866        *stream_flagsp |= SMB_NO_RESOURCE_FORK;
1867
1868        if (namep == NULL) {
1869            /* Negative cache the resource fork in the vnode */
1870            lck_mtx_lock(&np->rfrkMetaLock);
1871
1872            nanouptime(&ts);
1873            np->rfrk_size = 0;
1874            np->rfrk_alloc_size = 0;
1875            np->rfrk_cache_timer = ts.tv_sec;
1876
1877            lck_mtx_unlock(&np->rfrkMetaLock);
1878        }
1879    }
1880
1881	if ((foundStream == FALSE) || (error == ENOENT))	/* We did not find the stream we were looking for */
1882		error = ENOATTR;
1883	return (error);
1884}
1885
1886/*
1887 * The SMB_QFS_POSIX_WHOAMI allows us to find out who the server thinks we are
1888 * and what groups we are in.
1889 *
1890 * The calling routine must hold a reference on the share
1891 *
1892 */
1893void
1894smbfs_unix_whoami(struct smb_share *share, struct smbmount *smp, vfs_context_t context)
1895{
1896	struct smb_t2rq *t2p;
1897	struct mbchain *mbp;
1898	struct mdchain *mdp;
1899	int error;
1900	uint32_t ii;
1901	uint32_t reserved;
1902	size_t total_bytes;
1903	uint32_t ntwrk_sids_cnt;
1904	uint32_t ntwrk_sid_size;
1905
1906	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_QUERY_FS_INFORMATION, 1, context, &t2p);
1907	if (error)
1908		return;
1909
1910	mbp = &t2p->t2_tparam;
1911	mb_init(mbp);
1912	mb_put_uint16le(mbp, SMB_QFS_POSIX_WHOAMI);
1913	t2p->t2_maxpcount = 4;
1914	t2p->t2_maxdcount = SSTOVC(share)->vc_txmax;
1915	error = smb_t2_request(t2p);
1916	if (error)
1917		goto done;
1918
1919	mdp = &t2p->t2_rdata;
1920	/*
1921	 * At this point md_cur and md_top have the same value. Now all the md_get
1922	 * routines will will check for null, but just to be safe we check here
1923	 */
1924	if (mdp->md_cur == NULL) {
1925		error = EBADRPC;
1926		goto done;
1927	}
1928	/* Currently only tells us if we logged in as guest, we should already know this by now */
1929	md_get_uint32le(mdp,  NULL); 	/* Mapping flags, currently only used for guest */
1930	md_get_uint32le(mdp,  NULL); /* Mask of valid mapping flags */
1931	md_get_uint64le(mdp,  &smp->ntwrk_uid);	/* Primary user ID */
1932	md_get_uint64le(mdp,  &smp->ntwrk_gid);	/* Primary group ID */
1933	md_get_uint32le(mdp,  &smp->ntwrk_cnt_gid); /* number of supplementary GIDs */
1934	md_get_uint32le(mdp,  &ntwrk_sids_cnt); /* number of SIDs */
1935	md_get_uint32le(mdp,  &ntwrk_sid_size); /* size of the list of SIDs */
1936	error = md_get_uint32le(mdp,  &reserved); /* Reserved (should be zero) */
1937	if (error)
1938		goto done;
1939	SMBWARNING("network uid = %lld network gid = %lld supplementary group cnt  = %d SID cnt = %d\n",
1940			 smp->ntwrk_uid, smp->ntwrk_gid, smp->ntwrk_cnt_gid, ntwrk_sids_cnt);
1941	/*
1942	 * If we can't get the reserved field then the buffer is not big enough. Both the
1943	 * group count and sid count must set to zero if no groups or sids are return.
1944	 * Added a little safty net here, we do not allow these fields to be negative.
1945	 */
1946	if (error || (reserved != 0) || ((int32_t)smp->ntwrk_cnt_gid < 0) || ((int32_t)ntwrk_sids_cnt < 0)) {
1947		if (! error)
1948			error = EBADRPC;
1949		goto done;
1950	}
1951
1952	/* No group list see if there is a sid list */
1953	if (smp->ntwrk_cnt_gid == 0)
1954		goto sid_groups;
1955
1956	/* Now check to make sure we don't have an integer overflow */
1957	total_bytes = smp->ntwrk_cnt_gid * sizeof(uint64_t);
1958	if ((total_bytes / sizeof(uint64_t)) != smp->ntwrk_cnt_gid) {
1959		error = EBADRPC;
1960		goto done;
1961	}
1962
1963	/* Make sure we are not allocating more than we said we could handle */
1964	if (total_bytes > SSTOVC(share)->vc_txmax) {
1965		error = EBADRPC;
1966		goto done;
1967	}
1968
1969	SMB_MALLOC(smp->ntwrk_gids, uint64_t *, total_bytes, M_TEMP, M_WAITOK);
1970	/* Should never happen, but just to be safe */
1971	if (smp->ntwrk_gids == NULL) {
1972		error = ENOMEM;
1973		goto done;
1974	}
1975	for (ii = 0; ii < smp->ntwrk_cnt_gid; ii++) {
1976		error = md_get_uint64le(mdp,  &smp->ntwrk_gids[ii]);
1977		if (error)
1978			goto done;
1979		SMBDEBUG("smp->ntwrk_gids[%d] = %lld\n", ii, smp->ntwrk_gids[ii]);
1980	}
1981	UNIX_CAPS(share) |= UNIX_QFS_POSIX_WHOAMI_CAP;
1982	/*
1983	 * At this point we have everything we really need. So any errors from this
1984	 * point on should be ignored. If we error out below we should just pretend
1985	 * that we didn't get any network sids.
1986	 */
1987sid_groups:
1988	if (share->ss_attributes & FILE_PERSISTENT_ACLS) {
1989		smb_get_sid_list(share, smp, mdp,ntwrk_sids_cnt, ntwrk_sid_size);
1990	}
1991
1992done:
1993	smb_t2_done(t2p);
1994	if (error == EBADRPC)
1995		SMBERROR("Parsing error reading the message\n");
1996
1997	if (error && smp->ntwrk_gids) {
1998		SMB_FREE(smp->ntwrk_gids, M_TEMP);
1999		smp->ntwrk_gids = NULL;
2000		smp->ntwrk_cnt_gid = 0;
2001	}
2002}
2003
2004/*
2005 * This is a  UNIX server get its UNIX capiblities
2006 *
2007 * The calling routine must hold a reference on the share
2008 *
2009 */
2010void
2011smbfs_unix_qfsattr(struct smb_share *share, vfs_context_t context)
2012{
2013	struct smb_t2rq *t2p;
2014	struct mbchain *mbp;
2015	struct mdchain *mdp;
2016	uint16_t majorv;
2017	uint16_t minorv;
2018	uint64_t cap;
2019	int error;
2020
2021	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_QUERY_FS_INFORMATION, 1, context, &t2p);
2022	if (error)
2023		return;
2024
2025	mbp = &t2p->t2_tparam;
2026	mb_init(mbp);
2027	mb_put_uint16le(mbp, SMB_QFS_UNIX_INFO);
2028	t2p->t2_maxpcount = 4;
2029	t2p->t2_maxdcount = 12;
2030	error = smb_t2_request(t2p);
2031	if (error)
2032		goto done;
2033
2034	mdp = &t2p->t2_rdata;
2035	/*
2036	 * At this point md_cur and md_top have the same value. Now all the md_get
2037	 * routines will will check for null, but just to be safe we check here
2038	 */
2039	if (mdp->md_cur == NULL) {
2040		SMBWARNING("Parsing error reading the message\n");
2041		goto done;
2042	}
2043	md_get_uint16le(mdp,  &majorv);
2044	md_get_uint16le(mdp, &minorv);
2045	md_get_uint64le(mdp, &cap);
2046	SMBWARNING("version %x.%x cap = %llx\n", majorv, minorv, cap);
2047	UNIX_CAPS(share) = UNIX_QFS_UNIX_INFO_CAP | (cap & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP);
2048
2049	if (UNIX_CAPS(share) & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP) {
2050		UNIX_CAPS(share) |= UNIX_QFILEINFO_UNIX_LINK_CAP | UNIX_SFILEINFO_UNIX_LINK_CAP |
2051								UNIX_QFILEINFO_UNIX_INFO2_CAP | UNIX_SFILEINFO_UNIX_INFO2_CAP;
2052		/*
2053		 * Seems Leopard Servers don't handle the posix unlink call correctly.
2054		 * They support the call and say it work, but they don't really delete
2055		 * the item. So until we stop supporting Leopard don't set this unless
2056		 * the server doesn't support the BSD flags. Mac servers support the
2057		 * BSD flags, but Linux servers don't. So in mount_smbfs we will turn
2058		 * this back on if we determine its a linux server.
2059		 * NOTE: Snow Leopard seems to work correctly
2060		 *
2061		 * UNIX_CAPS(share) |= UNIX_SFILEINFO_POSIX_UNLINK_CAP;
2062		 */
2063	}
2064done:
2065	smb_t2_done(t2p);
2066}
2067
2068/*
2069 * Since the first thing we do is set the default values there is no longer
2070 * any reason to return an error for this routine. Some servers may not support
2071 * this call. We should not fail the mount just because they do not support this
2072 * call.
2073 *
2074 * The calling routine must hold a reference on the share
2075 *
2076 */
2077void
2078smb1fs_qfsattr(struct smb_share *share, vfs_context_t context)
2079{
2080	struct smb_t2rq *t2p;
2081	struct mbchain *mbp;
2082	struct mdchain *mdp;
2083	uint32_t nlen = 0;
2084	int error;
2085	size_t fs_nmlen;	/* The sized malloced for fs_name */
2086	char *fsname = NULL;
2087
2088	/* Start with the default values */
2089	share->ss_fstype = SMB_FS_FAT;	/* default to FAT File System */
2090	share->ss_attributes = 0;
2091	share->ss_maxfilenamelen = 255;
2092
2093	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_QUERY_FS_INFORMATION, 1, context, &t2p);
2094	if (error) {
2095		return;
2096    }
2097
2098	mbp = &t2p->t2_tparam;
2099	mb_init(mbp);
2100	mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO);
2101	t2p->t2_maxpcount = 4;
2102	t2p->t2_maxdcount = 4 * 3 + 512;
2103	error = smb_t2_request(t2p);
2104	if (error) {
2105		goto done;
2106    }
2107
2108	mdp = &t2p->t2_rdata;
2109	/*
2110	 * At this point md_cur and md_top have the same value. Now all the md_get
2111	 * routines will will check for null, but just to be safe we check here
2112	 */
2113	if (mdp->md_cur == NULL) {
2114		error = EBADRPC;
2115    }
2116	else {
2117		md_get_uint32le(mdp,  &share->ss_attributes);
2118
2119        /*
2120         * Make sure Max Name Length is a reasonable value.
2121         * See <rdar://problem/12171424>.
2122         */
2123        md_get_uint32le(mdp, &share->ss_maxfilenamelen);   /* max name length */
2124        if (share->ss_maxfilenamelen > (SMB_MAXFNAMELEN * 2)) {
2125            SMBERROR("Illegal file name len %u\n", share->ss_maxfilenamelen);
2126            share->ss_maxfilenamelen = 255;
2127        }
2128
2129		error = md_get_uint32le(mdp, &nlen);	/* fs name length */
2130	}
2131	if (error) {
2132		/* This is a very bad server */
2133		SMBWARNING("Server returned a bad SMB_QFS_ATTRIBUTE_INFO message\n");
2134		/* Don't believe them when they say they are unix */
2135		SSTOVC(share)->vc_sopt.sv_caps &= ~SMB_CAP_UNIX;
2136		goto done;
2137	}
2138	if ((nlen > 0) && (nlen < PATH_MAX)) {
2139		char *ntwrkName;
2140
2141		SMB_MALLOC(ntwrkName, char *, nlen, M_SMBFSDATA, M_WAITOK | M_ZERO);
2142		md_get_mem(mdp, ntwrkName, nlen, MB_MSYSTEM);
2143		/*
2144		 * Just going from memory, I believe this is really just a
2145		 * WCHAR not a STRING value. I know that both Windows 98
2146		 * and SNAP return it as WCHAR and neither supports
2147		 * UNICODE. So if they do not support UNICODE then lets
2148		 * do some test and see if we can get the file system name.
2149		 */
2150
2151        fs_nmlen = nlen;
2152        fsname = smbfs_ntwrkname_tolocal(ntwrkName, &fs_nmlen,
2153                                        SMB_UNICODE_STRINGS(SSTOVC(share)));
2154        SMB_FREE(ntwrkName, M_SMBFSDATA);
2155
2156		if (fsname == NULL) {
2157			goto done;	/* Should never happen, but just to be safe */
2158		}
2159
2160		fs_nmlen += 1; /* Include the null byte for the compare */
2161		/*
2162		 * Let's start keeping track of the file system type. Most
2163		 * things we need to do differently really depend on the
2164		 * file system type. As an example we know that FAT file systems
2165		 * do not update the modify time on drectories.
2166		 */
2167		if (strncmp(fsname, "FAT", fs_nmlen) == 0)
2168			share->ss_fstype = SMB_FS_FAT;
2169		else if (strncmp(fsname, "FAT12", fs_nmlen) == 0)
2170			share->ss_fstype = SMB_FS_FAT;
2171		else if (strncmp(fsname, "FAT16", fs_nmlen) == 0)
2172			share->ss_fstype = SMB_FS_FAT;
2173		else if (strncmp(fsname, "FAT32", fs_nmlen) == 0)
2174			share->ss_fstype = SMB_FS_FAT;
2175		else if (strncmp(fsname, "CDFS", fs_nmlen) == 0)
2176			share->ss_fstype = SMB_FS_CDFS;
2177		else if (strncmp(fsname, "UDF", fs_nmlen) == 0)
2178			share->ss_fstype = SMB_FS_UDF;
2179		else if (strncmp(fsname, "NTFS", fs_nmlen) == 0)
2180			share->ss_fstype = SMB_FS_NTFS_UNKNOWN;	/* Could be lying */
2181
2182		SMBWARNING("%s/%s type '%s', attr 0x%x, maxfilename %d\n",
2183				   SSTOVC(share)->vc_srvname, share->ss_name, fsname,
2184				   share->ss_attributes, share->ss_maxfilenamelen);
2185		/*
2186		 * NT4 will not return the FILE_NAMED_STREAMS bit in the ss_attributes
2187		 * even though they support streams. So if its a NT4 server and a
2188		 * NTFS file format then turn on the streams flag.
2189		 */
2190		 if ((SSTOVC(share)->vc_flags & SMBV_NT4) && (share->ss_fstype & SMB_FS_NTFS_UNKNOWN))
2191			share->ss_attributes |= FILE_NAMED_STREAMS;
2192		 /*
2193		  * The server says they support streams and they say they are NTFS. So mark
2194		  * the subtype as NTFS. Remember a lot of non Windows servers pretend
2195		  * their NTFS so they can support ACLs, but they aren't really because they have
2196		  * no stream support. This allows us to tell the difference.
2197		  */
2198		 if ((share->ss_fstype == SMB_FS_NTFS_UNKNOWN) && (share->ss_attributes & FILE_NAMED_STREAMS))
2199			 share->ss_fstype = SMB_FS_NTFS;	/* Real NTFS Volume */
2200		 else if ((share->ss_fstype == SMB_FS_NTFS_UNKNOWN) && (UNIX_SERVER(SSTOVC(share))))
2201			 share->ss_fstype = SMB_FS_NTFS_UNIX;	/* UNIX system lying about being NTFS */
2202		 /* Some day mark it as being Mac OS X */
2203	}
2204done:
2205	SMB_FREE(fsname, M_SMBSTR);
2206	smb_t2_done(t2p);
2207}
2208
2209/*
2210 * The calling routine must hold a reference on the share
2211 */
2212int
2213smb1fs_statfs(struct smb_share *share, struct vfsstatfs *sbp, vfs_context_t context)
2214{
2215	struct smb_t2rq *t2p;
2216	struct mbchain *mbp;
2217	struct mdchain *mdp;
2218	uint32_t bpu, bsize32;
2219	uint64_t s, t, f;
2220	int error;
2221	size_t xmax;
2222
2223	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_QUERY_FS_INFORMATION, 1, context, &t2p);
2224	if (error)
2225		return error;
2226	mbp = &t2p->t2_tparam;
2227	mb_init(mbp);
2228
2229    /* SMB_QFS_SIZE_INFO info level allows us to return large volume sizes.
2230     *
2231     *		Total number of allocated units as a 64 bit value
2232     *		Number of free units as a 64 bit value
2233     *		Number of sectors in each unit as a 32 bit value
2234     *		Number of bytes in each sector as a 32 bit value
2235     */
2236    mb_put_uint16le(mbp, SMB_QFS_SIZE_INFO);
2237    t2p->t2_maxpcount = 4;
2238    /* The call returns two 64 bit values and two 32 bit value */
2239    t2p->t2_maxdcount = (8 * 2) + (4 * 2);
2240
2241	error = smb_t2_request(t2p);
2242	if (error) {
2243		smb_t2_done(t2p);
2244		return error;
2245	}
2246	mdp = &t2p->t2_rdata;
2247	/*
2248	 * At this point md_cur and md_top have the same value. Now all the md_get
2249	 * routines will will check for null, but just to be safe we check here
2250	 */
2251	if (mdp->md_cur == NULL) {
2252		SMBWARNING("Parsing error reading the message\n");
2253		smb_t2_done(t2p);
2254		return EBADRPC;
2255	}
2256	/* Now retrieve the correct inforamtion. */
2257    md_get_uint64le(mdp, &t); /* Total number of allocated units */
2258    md_get_uint64le(mdp, &f); /* Number of free units */
2259    md_get_uint32le(mdp, &bpu); /* Number of sectors in each unit */
2260    md_get_uint32le(mdp, &bsize32);	/* Number of bytes in a sector */
2261    s = bsize32;
2262    s *= bpu;
2263	/*
2264	 * Don't allow over-large blocksizes as they determine
2265	 * Finder List-view size granularities.  On the other
2266	 * hand, we mustn't let the block count overflow the
2267	 * 31 bits available.
2268	 */
2269	while (s > 16 * 1024) {
2270		if (t > LONG_MAX)
2271			break;
2272		s /= 2;
2273		t *= 2;
2274		f *= 2;
2275	}
2276	while (t > LONG_MAX) {
2277		t /= 2;
2278		f /= 2;
2279		s *= 2;
2280	}
2281	sbp->f_bsize = (uint32_t)s;	/* fundamental file system block size */
2282	sbp->f_blocks= t;	/* total data blocks in file system */
2283	sbp->f_bfree = f;	/* free blocks in fs */
2284	sbp->f_bavail= f;	/* free blocks avail to non-superuser */
2285	sbp->f_files = (-1);	/* total file nodes in file system */
2286	sbp->f_ffree = (-1);	/* free file nodes in fs */
2287	smb_t2_done(t2p);
2288
2289	/* Done with the network stuff now get the iosize, this code was moved from smbfs_vfs_getattr to here */
2290
2291	/*
2292	 *  Now get the iosize, this code was down in smbfs_vfs_getattr, but now we do it here
2293	 *
2294	 * The Finder will in general use the f_iosize as its i/o buffer size.  We want to give it the
2295	 * largest size which is less than the UBC/UPL limit (SMB_IOMAX) but is also a multiple of our
2296	 * maximum xfer size in a single smb. If possible we would like for every offset to be on a PAGE_SIZE
2297	 * boundary. So the way to force that is make sure the f_iosize always ends up on a PAGE_SIZE boundary.
2298	 * Our second goal is to use as many smb xfer as possible, but also have the f_iosize end on a xfer
2299	 * boundary. We can do this in all cases, but they smb xfer must be on a 1K boundary.
2300	 *
2301	 * NOTE: Remember that if the server sets the SMB_CAP_LARGE bit then we have complete control of the
2302	 * xmax size. So our goal here is to work with those systems and do the best we can for others. So currently
2303	 * we we have two different numbers for SMB_CAP_LARGE servers, 60K for Windows and 126K for the others. Since
2304	 * this will affect most systems we are dealing with make sure are numbers always work in those two cases. For
2305	 * all other cases just do the best we can do.
2306	 *
2307	 * NOTE: We always make sure that vc_rxmax and vc_wxmax are on a 1k boundary!
2308	 */
2309
2310	xmax = max(SSTOVC(share)->vc_rxmax, SSTOVC(share)->vc_wxmax);
2311
2312    /*
2313     * Now we want to make sure it will land on both a PAGE_SIZE boundary and a
2314     * smb xfer size boundary. So first mod the xfer size by the page size, then
2315     * subtract that from page size. This will give us the extra amount that
2316     * will be needed to get it on a page boundary. Now divide the page size by
2317     * this amount. This will give us the number of xmax it will take to make
2318     * f_iosize land on a page size and xfer boundary.
2319     */
2320	xmax = (PAGE_SIZE / (PAGE_SIZE - (xmax % PAGE_SIZE))) * xmax;
2321	if (xmax > SMB_IOMAX)
2322		sbp->f_iosize = SMB_IOMAX;
2323	else
2324		sbp->f_iosize = (SMB_IOMAX/xmax) * xmax;
2325	/*
2326	 * Examples:
2327	 * Windows (xfer is 60K) - f_iosize
2328	 * (4 / (4 - (60 % 4))) * 60 = 60
2329	 * (1024 / 60) * 60 = 1020
2330	 * (1020 / PAGE_SIZE) = exactly 255 pages
2331	 * (1020 / 60) = exactly 17 xfer
2332	 *
2333	 * Snow (xfer is 126K) - f_iosize
2334	 * (4 / (4 - (126 % 4))) * 126 = 252
2335	 * (1024 / 252) * 252 = 1008
2336	 * (1008 / PAGE_SIZE) = exactly 252 pages
2337	 * (1008 / 126) = exactly 8 xfer
2338	 *
2339	 * Lion (xfer is 128K) - f_iosize
2340	 * (4 / (4 - (128 % 4))) * 128 = 128
2341	 * (1024 / 128) * 128 = 1024
2342	 * (1024 / PAGE_SIZE) = exactly 256 pages
2343	 * (1024 / 128) = exactly 8 xfer
2344	 */
2345
2346	return 0;
2347}
2348
2349/*
2350 * The calling routine must hold a reference on the share
2351 */
2352int
2353smbfs_smb_t2rename(struct smb_share *share, struct smbnode *np,
2354                   const char *tname, size_t tnmlen, int overwrite,
2355                   SMBFID *infid, vfs_context_t context)
2356{
2357	struct smb_t2rq *t2p;
2358	struct mbchain *mbp;
2359	int32_t *ucslenp;
2360	size_t	outLen = 0;
2361	int error, cerror;
2362    SMBFID fid = 0;
2363    int need_close = 0;
2364    uint16_t smb1_fid = 0;
2365
2366    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
2367        SMBERROR("smbfs_smb_t2rename not supported by SMB 2/3\n");
2368        error = ENOTSUP;
2369        return error;
2370    }
2371
2372    if (infid) {
2373        fid = *infid;
2374        smb1_fid = (uint16_t) fid;
2375    }
2376    else {
2377        fid = 0;
2378    }
2379
2380	/*
2381	 * We will continue to return not supported here. If the calling routine
2382	 * needs a different error then it needs to make this check before calling
2383	 * this routine.
2384	 */
2385	if (!(VC_CAPS(SSTOVC(share)) & SMB_CAP_INFOLEVEL_PASSTHRU))
2386		return (ENOTSUP);
2387	/*
2388	 * Rember that smb_t2_alloc allocates t2p. We need to call
2389	 * smb_t2_done to free it.
2390	 */
2391	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_SET_FILE_INFORMATION, 1, context, &t2p);
2392	if (error)
2393		return error;
2394
2395	if (!infid) {
2396		/*
2397		 * See if we can open the item with delete access. Requesting
2398		 * delete access can mean more then just requesting to delete
2399		 * the file. It is used to mark the item for deletion on close
2400		 * and for renaming an open file. If I find any other uses for
2401		 * it I will add them to this comment.
2402		 */
2403		error = smbfs_tmpopen(share, np, SMB2_DELETE, &fid, context);
2404		if (error)
2405			goto exit;
2406        need_close = 1;
2407        smb1_fid = fid;
2408	}
2409	mbp = &t2p->t2_tparam;
2410	mb_init(mbp);
2411	mb_put_mem(mbp, (caddr_t)&smb1_fid, sizeof(smb1_fid), MB_MSYSTEM);
2412	mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
2413	mb_put_uint16le(mbp, 0); /* reserved, nowadays */
2414	mbp = &t2p->t2_tdata;
2415	mb_init(mbp);
2416	mb_put_uint32le(mbp, overwrite);
2417	mb_put_uint32le(mbp, 0); /* Root fid, not used */
2418	/* Reserve file name location */
2419	ucslenp = (int32_t *)mb_reserve(mbp, sizeof(int32_t));
2420	error = smb_put_dmem(mbp, tname, tnmlen, UTF_SFM_CONVERSIONS,
2421						 SMB_UNICODE_STRINGS(SSTOVC(share)), &outLen);
2422	if (!error)
2423		error = mb_put_uint16le(mbp, 0);
2424	if (error)
2425		goto exit;
2426	/* Now we can put the file name length into the buffer */
2427	*ucslenp = htolel((int32_t)outLen);
2428	t2p->t2_maxpcount = 2;
2429	t2p->t2_maxdcount = 0;
2430	error = smb_t2_request(t2p);
2431exit:;
2432	if (need_close == 1) {
2433		cerror = smbfs_tmpclose(share, np, fid, context);
2434		if (cerror) {
2435			SMBWARNING("error %d closing fid %llx\n", cerror, fid);
2436		}
2437	}
2438	smb_t2_done(t2p);
2439	return (error);
2440}
2441
2442/*
2443 * smbfs_delete_openfile
2444 *
2445 * We have an open file that they want to delete. Use the NFS silly rename
2446 * trick, but try to do better than NFS. The picking of the name came from the
2447 * NFS code. So we first open the file for deletion. Now come up with a new
2448 * name and rename the file. Make the file hidden if we can. Now lets mark
2449 * it for deletion and close the file. If the rename fails then the whole call
2450 * should fail. If the mark for deletion call fails just set a flag on the
2451 * vnode and delete it when we close.
2452 *
2453 * The calling routine must hold a reference on the share
2454 *
2455 */
2456int
2457smbfs_delete_openfile(struct smb_share *share, struct smbnode *dnp,
2458					  struct smbnode *np, vfs_context_t context)
2459{
2460    struct proc	*p;
2461    SMBFID fid = 0;
2462    int	error, cerror;
2463    char s_name[32];	/* make sure that sillyrename_name will fit */
2464    size_t s_namlen;
2465    int	i, j, k;
2466    int need_close = 0;
2467    int need_hide = 0;
2468    int samba_bug = 0;
2469	struct smbmount *smp = np->n_mount;
2470    uint64_t ino = 0;
2471    uint64_t hashval = 0;
2472    char *new_name = NULL;
2473    char *old_name = NULL;
2474
2475    /* Should never happen, but just to be safe */
2476    if (context == NULL) {
2477        return ENOTSUP;
2478    }
2479    p = vfs_context_proc(context);
2480
2481    if (!(SSTOVC(share)->vc_flags & SMBV_SMB2)) {
2482        /*
2483         * SMB 1
2484         *
2485         * smbfs_smb_t2rename requires passthru, so just return EBUSY since we
2486         * are attempting to delete an open file.
2487         */
2488        if (!(VC_CAPS(SSTOVC(share)) & SMB_CAP_INFOLEVEL_PASSTHRU)) {
2489            return EBUSY;
2490        }
2491
2492        error = smbfs_tmpopen(share, np, SMB2_DELETE, &fid, context);
2493        if (error) {
2494            return (error);
2495        }
2496        need_close = 1;
2497
2498        /* SMB 2/3 will not hide the file as I deem it unnecessary work */
2499        need_hide = 1;
2500    }
2501
2502    if (SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS) {
2503        /*
2504         * Use the unique File ID to create a unique name
2505         */
2506        lck_rw_lock_shared(&np->n_name_rwlock);
2507        ino = smb2fs_smb_file_id_get(smp, np->n_ino, np->n_name);
2508        lck_rw_unlock_shared(&np->n_name_rwlock);
2509
2510        /* Just try once to rename in the same dir */
2511        MAKE_DELETED_NAME((char*) s_name, sizeof(s_name), ino);
2512        s_namlen = strlen((char *) s_name);
2513
2514        error = smbfs_smb_rename(share, np, dnp, s_name, s_namlen, context);
2515    }
2516    else {
2517        /*
2518         * No File IDs, so have to use NFS naming convention to find unique
2519         * name. Get the first silly name
2520         */
2521        s_namlen = snprintf(s_name, sizeof(s_name), ".smbdeleteAAA%04x4.4",
2522                            proc_pid(p));
2523        if (s_namlen >= sizeof(s_name)) {
2524            error = ENOENT;
2525            goto out;
2526        }
2527
2528        /* Try rename until we get one that isn't there */
2529        i = j = k = 0;
2530
2531        do {
2532            if ((SSTOVC(share)->vc_flags & SMBV_SMB2) ||
2533                (samba_bug == 1)) {
2534                /* SMB 2/3 or dealing with SAMBA buggy server */
2535                error = smbfs_smb_rename(share, np, dnp, s_name, s_namlen,
2536                                         context);
2537            }
2538            else {
2539                /* SMB 1 */
2540                error = smbfs_smb_t2rename(share, np, s_name, s_namlen, 0, &fid,
2541                                           context);
2542
2543                if (((error == ENOENT) || (error == ENOTSUP)) &&
2544                    SMBTOV(dnp) &&
2545                    (samba_bug == 0)) {
2546                    /*
2547                     * SAMBA Bug:
2548                     *
2549                     * Some times the SAMBA code gets confused and fails the
2550                     * above rename with an ENOENT error. We need to make sure
2551                     * this code works with all SAMBA servers, so try again
2552                     * with the old rename call. SAMBA allows us to rename an
2553                     * open file with this call, but not with delete access.
2554                     * So close it, rename it and hide it. Once the SAMBA
2555                     * server is in this state, it will always return an error,
2556                     * so just use the old rename from now on.
2557                     */
2558                    if (need_close == 1) {
2559                        (void)smbfs_tmpclose(share, np, fid, context);
2560                        need_close = 0;
2561                    }
2562
2563                    /* loop around and try with old rename */
2564                    samba_bug = 1;
2565                    continue;
2566                }
2567            }
2568
2569            if (error && (error != EEXIST)) {
2570                /*
2571                 * They returned an error we did not expect. If the silly name
2572                 * file exists then we want to keep trying. So do a look up and
2573                 * if the file exists, keep trying otherwise just get out since
2574                 * there is nothing else for us to do.
2575                 */
2576                if (smbfs_smb_query_info(share, dnp, VREG,
2577                                         s_name, s_namlen, NULL, context) == 0) {
2578                    /* That name exists on server, keep trying for a new name */
2579                    error = EEXIST;
2580                }
2581                else {
2582                    break;
2583                }
2584            }
2585
2586            /*
2587             * The file name already exists, try another one. This code was
2588             * taken from NFS. NFS tested by doing a lookup, we use the rename
2589             * call, see above for how we handle strange errors. If the rename
2590             * call fails, keep trying till we run out of names.
2591             */
2592            if (error) {
2593                if (s_name[10]++ >= 'z')
2594                    s_name[10] = 'A';
2595                if (++i > ('z' - 'A' + 1)) {
2596                    i = 0;
2597                    if (s_name[11]++ >= 'z')
2598                        s_name[11] = 'A';
2599                    if (++j > ('z' - 'A' + 1)) {
2600                        j = 0;
2601                        if (s_name[12]++ >= 'z')
2602                            s_name[12] = 'A';
2603                        if (++k > ('z' - 'A' + 1)) {
2604                            error = EINVAL;
2605                        }
2606                    }
2607                }
2608            }
2609        } while (error == EEXIST);
2610    }
2611
2612    if (error) {
2613        goto out;
2614    }
2615
2616    /*
2617     * At this point, the file has been successfully renamed on the server.
2618     */
2619
2620    if (need_hide) {
2621        /* ignore any errors return from hiding the item */
2622        (void)smbfs_set_hidden_bit(share, dnp, VREG,
2623                                   s_name, s_namlen,
2624                                   TRUE, context);
2625    }
2626
2627    if ((SSTOVC(share)->vc_flags & SMBV_SMB2) || (samba_bug == 1)) {
2628        /*
2629         * SMB 2/3 will always just wait until last close to do the delete.
2630         * This matches AFP behavior.
2631         * If we hit the SAMBA bug, then the file is closed so cant set the
2632         * Delete on Close because we have no fid.
2633         */
2634        np->n_flag |= NDELETEONCLOSE;
2635    }
2636    else {
2637        /* SMB 1 - Set file for Delete on Close */
2638        cerror = smbfs_smb_markfordelete(share, fid, context);
2639        if (cerror) {
2640            /*
2641             * Failed to delete it now, so just wait until last close to do
2642             * the delete. Could be SAMBA misbehaving.
2643             */
2644            np->n_flag |= NDELETEONCLOSE;
2645        }
2646    }
2647
2648out:
2649    if (need_close == 1) {
2650        cerror = smbfs_tmpclose(share, np, fid, context);
2651        if (cerror) {
2652            SMBWARNING("error %d closing fid %llx\n", cerror, fid);
2653        }
2654    }
2655
2656    if (!error) {
2657        lck_rw_lock_exclusive(&np->n_name_rwlock);
2658
2659        new_name = smb_strndup(s_name, s_namlen);
2660        old_name = np->n_name;
2661
2662        if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS) ||
2663            !(np->n_flag & NDELETEONCLOSE)) {
2664            /*
2665             * If no File IDs OR if we deleted it now, then remove the node
2666             * from hash table
2667             */
2668            smb_vhashrem(np);
2669        }
2670
2671        /* Now reset the name, so other path lookups can use it. */
2672        if (new_name) {
2673            np->n_name = new_name;
2674            np->n_nmlen = s_namlen;
2675
2676            /* Mark smb node so Meta data cache never expires */
2677            np->n_flag |= NMARKEDFORDLETE;
2678
2679            if (!(SSTOVC(share)->vc_misc_flags & SMBV_HAS_FILEIDS) &&
2680                !(np->n_flag & NDELETEONCLOSE)) {
2681                /*
2682                 * If no File IDs AND the file has not been deleted yet, then
2683                 * add it back into hash table.
2684                 */
2685                hashval = smbfs_hash(NULL, 0, np->n_name, np->n_nmlen);
2686                smb_vhashadd(np, hashval);
2687            }
2688
2689            /* Now its safe to free the old name */
2690            SMB_FREE(old_name, M_SMBNODENAME);
2691        }
2692
2693        lck_rw_unlock_exclusive(&np->n_name_rwlock);
2694    }
2695    else {
2696        /* All errors are mapped to EBUSY */
2697        error = EBUSY;
2698    }
2699
2700    return(error);
2701}
2702
2703/*
2704 * This routine will send a flush across the wire to the server. This is an expensive
2705 * operation that should only be done when the user request it.
2706 *
2707 * The calling routine must hold a reference on the share
2708 *
2709 */
2710int
2711smb1fs_smb_flush(struct smb_share *share, SMBFID fid, vfs_context_t context)
2712{
2713	struct smb_rq rq, *rqp = &rq;
2714	struct mbchain *mbp;
2715	int error;
2716    uint16_t smb1_fid = (uint16_t) fid;
2717
2718	error = smb_rq_init(rqp, SSTOCP(share), SMB_COM_FLUSH, 0, context);
2719	if (error) {
2720		goto done;
2721	}
2722	smb_rq_getrequest(rqp, &mbp);
2723	smb_rq_wstart(rqp);
2724	mb_put_mem(mbp, (caddr_t)&smb1_fid, sizeof(smb1_fid), MB_MSYSTEM);
2725	smb_rq_wend(rqp);
2726	smb_rq_bstart(rqp);
2727	smb_rq_bend(rqp);
2728	error = smb_rq_simple(rqp);
2729	/*
2730	 * Flushed failed on a reconnect. The server will flush the file when it
2731	 * closes the file after the connection goes down. Ignore the error in this case.
2732	 */
2733	if ((error == EBADF) && (rqp->sr_flags & SMBR_REXMIT))
2734		error = 0;
2735	smb_rq_done(rqp);
2736done:
2737	if (error) {
2738		SMBWARNING("smbfs_smb_flush failed error = %d\n", error);
2739	}
2740	return (error);
2741}
2742
2743/*
2744 * This routine will send a seteof across the wire to the server.
2745 *
2746 * The calling routine must hold a reference on the share
2747 *
2748 */
2749int
2750smb1fs_seteof(struct smb_share *share, SMBFID fid, uint64_t newsize,
2751              vfs_context_t context)
2752{
2753	struct mbchain *mbp;
2754	int error;
2755    uint16_t smb1_fid = (uint16_t) fid;
2756    struct smb_t2rq *t2p;
2757
2758    error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_SET_FILE_INFORMATION, 1, context, &t2p);
2759    if (error)
2760        return error;
2761    mbp = &t2p->t2_tparam;
2762    mb_init(mbp);
2763    mb_put_mem(mbp, (caddr_t)&smb1_fid, sizeof(smb1_fid), MB_MSYSTEM);
2764    if (VC_CAPS(SSTOVC(share)) & SMB_CAP_INFOLEVEL_PASSTHRU)
2765        mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
2766    else
2767        mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO);
2768    mb_put_uint16le(mbp, 0);
2769    mbp = &t2p->t2_tdata;
2770    mb_init(mbp);
2771    mb_put_uint64le(mbp, newsize);
2772    t2p->t2_maxpcount = 2;
2773    t2p->t2_maxdcount = 0;
2774    error = smb_t2_request(t2p);
2775    smb_t2_done(t2p);
2776
2777	return error;
2778}
2779
2780
2781/*
2782 * This routine will send an allocation across the wire to the server.
2783 *
2784 * The calling routine must hold a reference on the share
2785 *
2786 */
2787int
2788smb1fs_set_allocation(struct smb_share *share, SMBFID fid, uint64_t newsize,
2789                     vfs_context_t context)
2790{
2791	struct smb_t2rq *t2p;
2792	struct mbchain *mbp;
2793	int error;
2794    uint16_t smb1_fid = (uint16_t) fid;
2795
2796	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_SET_FILE_INFORMATION, 1, context, &t2p);
2797	if (error)
2798		return error;
2799	mbp = &t2p->t2_tparam;
2800	mb_init(mbp);
2801	mb_put_mem(mbp, (caddr_t)&smb1_fid, sizeof(smb1_fid), MB_MSYSTEM);
2802	if (VC_CAPS(SSTOVC(share)) & SMB_CAP_INFOLEVEL_PASSTHRU)
2803		mb_put_uint16le(mbp, SMB_SFILEINFO_ALLOCATION_INFORMATION);
2804	else
2805		mb_put_uint16le(mbp, SMB_SFILEINFO_ALLOCATION_INFO);
2806	mb_put_uint16le(mbp, 0);
2807	mbp = &t2p->t2_tdata;
2808	mb_init(mbp);
2809	mb_put_uint64le(mbp, newsize);
2810	t2p->t2_maxpcount = 2;
2811	t2p->t2_maxdcount = 0;
2812	error = smb_t2_request(t2p);
2813	smb_t2_done(t2p);
2814	return error;
2815}
2816
2817/*
2818 * Set the eof and clear and set the node flags required,
2819 *
2820 * The calling routine must hold a reference on the share
2821 *
2822 */
2823int
2824smbfs_seteof(struct smb_share *share, struct smbnode *np, SMBFID fid,
2825             uint64_t newsize, vfs_context_t context)
2826{
2827	int error;
2828
2829	error = smbfs_smb_seteof(share, fid, newsize, context);
2830	if (error && (error != EBADF)) {
2831		/* Not a reconnect error then report it */
2832		SMBWARNING("smbfs_node_seteof failed error = %d\n", error);
2833	} else if (!error) {
2834		np->n_flag &= ~NNEEDS_EOF_SET;
2835		np->n_flag |= NNEEDS_FLUSH;
2836	}
2837	return error;
2838}
2839
2840/*
2841 * See if we have a pending seteof or need to flush the file.
2842 *
2843 * The calling routine must hold a reference on the share
2844 *
2845 */
2846int
2847smbfs_smb_fsync(struct smb_share *share, struct smbnode *np, vfs_context_t context)
2848{
2849	int error;
2850    SMBFID fid = 0;
2851
2852    SMB_LOG_KTRACE(SMB_DBG_SMB_FSYNC | DBG_FUNC_START, np->n_flag, 0, 0, 0, 0);
2853
2854	if ((np->n_flag & (NNEEDS_EOF_SET | NNEEDS_FLUSH)) == 0) {
2855		/* Nothing to do here just return */
2856		error = 0;
2857        goto done;
2858	}
2859
2860	if ((np->f_refcnt <= 0) || (!SMBTOV(np)) || (!vnode_isreg(SMBTOV(np)))) {
2861		error = 0; /* not a regular open file */
2862        goto done;
2863    }
2864
2865	/* Before trying the flush see if the file needs to be reopened */
2866	error = smbfs_smb_reopen_file(share, np, context);
2867	if (error) {
2868		SMBDEBUG_LOCK(np, " %s waiting to be revoked\n", np->n_name);
2869	    goto done;
2870	}
2871    SMB_LOG_KTRACE(SMB_DBG_SMB_FSYNC | DBG_FUNC_NONE, 0xabc001, error, 0, 0, 0);
2872
2873	/* See if the file is opened for write access */
2874	if (FindFileRef(SMBTOV(np), vfs_context_proc(context), kAccessWrite,
2875                    kCheckDenyOrLocks, 0, 0, NULL, &fid)) {
2876		fid = np->f_fid;	/* Nope use the shared fid */
2877		if ((fid == 0) ||
2878            ((np->f_accessMode & kAccessWrite) != kAccessWrite)) {
2879			error = 0;	/* Nothing to do here get out */
2880            SMB_LOG_KTRACE(SMB_DBG_SMB_FSYNC | DBG_FUNC_NONE,
2881                           0xabc002, error, 0, 0, 0);
2882            goto done;
2883        }
2884	}
2885	/* We have a set eof pending do it here and clear the flag */
2886	if (np->n_flag & NNEEDS_EOF_SET) {
2887		error = smbfs_seteof(share, np, fid, np->n_size, context);
2888        SMB_LOG_KTRACE(SMB_DBG_SMB_FSYNC | DBG_FUNC_NONE,
2889                       0xabc003, error, 0, 0, 0);
2890		if (error) {
2891			goto done;
2892		}
2893	}
2894	error = smbfs_smb_flush(share, fid, context);
2895	if (!error)
2896		np->n_flag &= ~NNEEDS_FLUSH;
2897
2898    SMB_LOG_KTRACE(SMB_DBG_SMB_FSYNC | DBG_FUNC_NONE, 0xabc004, error, 0, 0, 0);
2899
2900done:
2901	SMB_LOG_KTRACE(SMB_DBG_SMB_FSYNC | DBG_FUNC_END, error, 0, 0, 0, 0);
2902    return error;
2903}
2904
2905/*
2906 * We should replace it with something more modern. See <rdar://problem/7595213>.
2907 * This routine is only used to test the existence of an item or to get its
2908 * DOS attributes when changing the status of the HIDDEN bit.
2909 *
2910 * The calling routine must hold a reference on the share
2911 *
2912 * Eventually, smb1fs_smb_query_info will just go away and we wont have to worry
2913 * about it using an old call any more.
2914 */
2915int
2916smb1fs_smb_query_info(struct smb_share *share, struct smbnode *np,
2917                      const char *name, size_t len, uint32_t *in_attr,
2918                      vfs_context_t context)
2919{
2920	struct smb_rq rq, *rqp = &rq;
2921	struct mbchain *mbp;
2922	struct mdchain *mdp;
2923	uint8_t wc = 0;
2924	int error;
2925    uint16_t attr;
2926
2927	error = smb_rq_init(rqp, SSTOCP(share), SMB_COM_QUERY_INFORMATION, 0, context);
2928	if (error)
2929		return error;
2930	smb_rq_getrequest(rqp, &mbp);
2931	smb_rq_wstart(rqp);
2932	smb_rq_wend(rqp);
2933	smb_rq_bstart(rqp);
2934	mb_put_uint8(mbp, SMB_DT_ASCII);
2935	error = smbfs_fullpath(mbp, np, name, &len, UTF_SFM_CONVERSIONS,
2936						   SMB_UNICODE_STRINGS(SSTOVC(share)), '\\');
2937	if (!error) {
2938		smb_rq_bend(rqp);
2939		error = smb_rq_simple(rqp);
2940	}
2941	if (!error && in_attr) {
2942		smb_rq_getreply(rqp, &mdp);
2943		md_get_uint8(mdp, &wc);
2944		error = md_get_uint16le(mdp, &attr);
2945        *in_attr = attr;
2946	}
2947	smb_rq_done(rqp);
2948	return error;
2949}
2950
2951/*
2952 * Set DOS file attributes, may want to replace with a more modern call
2953 *
2954 * The calling routine must hold a reference on the share
2955 *
2956 */
2957int
2958smb1fs_smb_setpattr(struct smb_share *share, struct smbnode *np,
2959                    const char *name, size_t len,
2960                    uint16_t attr, vfs_context_t context)
2961{
2962	struct smb_rq rq, *rqp = &rq;
2963	struct mbchain *mbp;
2964	uint32_t time;
2965	int error;
2966
2967	error = smb_rq_init(rqp, SSTOCP(share), SMB_COM_SET_INFORMATION, 0, context);
2968	if (error)
2969		return error;
2970	smb_rq_getrequest(rqp, &mbp);
2971	smb_rq_wstart(rqp);
2972	mb_put_uint16le(mbp, attr);
2973	time = 0;
2974	mb_put_uint32le(mbp, time);		/* mtime */
2975	mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
2976	smb_rq_wend(rqp);
2977	smb_rq_bstart(rqp);
2978	mb_put_uint8(mbp, SMB_DT_ASCII);
2979	do {
2980		error = smbfs_fullpath(mbp, np, name, &len, UTF_SFM_CONVERSIONS,
2981							   SMB_UNICODE_STRINGS(SSTOVC(share)), '\\');
2982		if (error)
2983			break;
2984		if (SMB_UNICODE_STRINGS(SSTOVC(share))) {
2985			mb_put_padbyte(mbp);
2986			mb_put_uint8(mbp, 0);	/* 1st byte of NULL Unicode char */
2987		}
2988		mb_put_uint8(mbp, 0);
2989		smb_rq_bend(rqp);
2990		error = smb_rq_simple(rqp);
2991		if (error)
2992			break;
2993	} while(0);
2994	smb_rq_done(rqp);
2995	return error;
2996}
2997
2998/*
2999 * The calling routine must hold a reference on the share
3000 */
3001int
3002smbfs_set_hidden_bit(struct smb_share *share, struct smbnode *dnp, enum vtype vnode_type,
3003                     const char *name, size_t len,
3004                     Boolean hideit, vfs_context_t context)
3005{
3006	int error;
3007	uint32_t attr;
3008
3009	/* Look it up and get the dos attributes */
3010	error = smbfs_smb_query_info(share, dnp, vnode_type,
3011                                 name, len,
3012                                 &attr, context);
3013	if (error) {
3014		return error;
3015	}
3016
3017	if (hideit && !(attr & SMB_EFA_HIDDEN)) {
3018		attr |= SMB_EFA_HIDDEN;
3019	} else if (!hideit && (attr & SMB_EFA_HIDDEN)) {
3020		attr &= ~SMB_EFA_HIDDEN;
3021	} else {
3022		return 0; /* Nothing to do here */
3023	}
3024
3025	return smbfs_smb_setpattr(share, dnp, vnode_type,
3026                              name, len,
3027                              attr, context);
3028}
3029
3030/*
3031 * The calling routine must hold a reference on the share
3032 */
3033int
3034smbfs_set_unix_info2(struct smb_share *share, struct smbnode *np,
3035					 struct timespec *crtime, struct timespec *mtime,
3036					 struct timespec *atime, uint64_t fsize,  uint64_t perms,
3037					 uint32_t FileFlags, uint32_t FileFlagsMask, vfs_context_t context)
3038{
3039	struct smb_t2rq *t2p;
3040	struct mbchain *mbp;
3041	uint64_t tm;
3042	uint32_t ftype;
3043	int error;
3044
3045	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_SET_PATH_INFORMATION, 1, context, &t2p);
3046	if (error)
3047		return error;
3048	mbp = &t2p->t2_tparam;
3049	mb_init(mbp);
3050	mb_put_uint16le(mbp, SMB_SFILEINFO_UNIX_INFO2);
3051	mb_put_uint32le(mbp, 0);		/* MBZ */
3052	error = smbfs_fullpath(mbp, np, NULL, NULL, UTF_SFM_CONVERSIONS,
3053						   SMB_UNICODE_STRINGS(SSTOVC(share)), '\\');
3054	if (error) {
3055		smb_t2_done(t2p);
3056		return error;
3057	}
3058
3059	mbp = &t2p->t2_tdata;
3060	mb_init(mbp);
3061	/* File size */
3062	mb_put_uint64le(mbp, fsize);
3063	/* Number of blocks used on disk */
3064	tm = SMB_SIZE_NO_CHANGE;
3065	mb_put_uint64le(mbp, tm);
3066
3067	/* Set the change time, not allowed */
3068	mb_put_uint64le(mbp, 0);
3069
3070	/* set the access time */
3071	if (atime)
3072		smb_time_local2NT(atime, &tm, FALSE);
3073	else
3074	     tm = 0;
3075	mb_put_uint64le(mbp, tm);
3076
3077	/* set the write/modify time */
3078	if (mtime)
3079		smb_time_local2NT(mtime, &tm, FALSE);
3080	else
3081	     tm = 0;
3082	mb_put_uint64le(mbp, tm);
3083
3084	/* Numeric user id for the owner */
3085	tm = SMB_UID_NO_CHANGE;
3086	mb_put_uint64le(mbp, tm);
3087	/* Numeric group id of owner */
3088	tm = SMB_GID_NO_CHANGE;
3089	mb_put_uint64le(mbp, tm);
3090	/* Enumeration specifying the file type */
3091	ftype = SMB_DEFAULT_NO_CHANGE;
3092	mb_put_uint32le(mbp, ftype);
3093	/* Major device number if type is device */
3094	tm = SMB_DEFAULT_NO_CHANGE;
3095	mb_put_uint64le(mbp, tm);
3096	/* Minor device number if type is device */
3097	tm = SMB_DEFAULT_NO_CHANGE;
3098	mb_put_uint64le(mbp, tm);
3099	/* This is a server-assigned unique id */
3100	tm = SMB_DEFAULT_NO_CHANGE;
3101	mb_put_uint64le(mbp, tm);
3102	/* Standard UNIX permissions */
3103	mb_put_uint64le(mbp, perms);
3104	/* Number of hard link */
3105	tm = SMB_DEFAULT_NO_CHANGE;
3106	mb_put_uint64le(mbp, tm);
3107	/* set the creation time */
3108	if (crtime)
3109		smb_time_local2NT(crtime, &tm, FALSE);
3110	else
3111	    tm = 0;
3112	mb_put_uint64le(mbp, tm);
3113	/* File flags enumeration */
3114	mb_put_uint32le(mbp, FileFlags);
3115	/* Mask of valid flags */
3116	mb_put_uint32le(mbp, FileFlagsMask);
3117
3118	t2p->t2_maxpcount = 24;
3119	t2p->t2_maxdcount = 116;
3120	error = smb_t2_request(t2p);
3121
3122	smb_t2_done(t2p);
3123	return error;
3124
3125}
3126
3127/*
3128 * BASIC_INFO works with Samba, but Win2K servers say it is an invalid information
3129 * level on a SET_PATH_INFO.  Note Win2K does support *BASIC_INFO on a SET_FILE_INFO,
3130 * and they support the equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure.
3131 *
3132 * The calling routine must hold a reference on the share
3133 *
3134 */
3135int
3136smb1fs_smb_setpattrNT(struct smb_share *share, struct smbnode *np,
3137                      uint32_t attr, struct timespec *crtime,
3138                      struct timespec *mtime, struct timespec *atime,
3139                      vfs_context_t context)
3140{
3141	struct smb_t2rq *t2p;
3142	struct mbchain *mbp;
3143	uint64_t tm;
3144	int error;
3145
3146	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_SET_PATH_INFORMATION, 1, context, &t2p);
3147	if (error)
3148		return error;
3149	mbp = &t2p->t2_tparam;
3150	mb_init(mbp);
3151	if (VC_CAPS(SSTOVC(share)) & SMB_CAP_INFOLEVEL_PASSTHRU)
3152		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION);
3153	else
3154		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO);
3155	mb_put_uint32le(mbp, 0);		/* MBZ */
3156	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
3157	error = smbfs_fullpath(mbp, np, NULL, NULL, UTF_SFM_CONVERSIONS,
3158						   SMB_UNICODE_STRINGS(SSTOVC(share)), '\\');
3159	if (error) {
3160		smb_t2_done(t2p);
3161		return error;
3162	}
3163
3164	mbp = &t2p->t2_tdata;
3165	mb_init(mbp);
3166
3167	/* set the creation time */
3168	tm = 0;
3169	if (crtime) {
3170		smb_time_local2NT(crtime, &tm, (share->ss_fstype == SMB_FS_FAT));
3171	}
3172	mb_put_uint64le(mbp, tm);
3173
3174	/* set the access time */
3175	tm = 0;
3176	if (atime) {
3177		smb_time_local2NT(atime, &tm, (share->ss_fstype == SMB_FS_FAT));
3178	}
3179	mb_put_uint64le(mbp, tm);
3180
3181	/* set the write/modify time */
3182	tm = 0;
3183	if (mtime) {
3184		smb_time_local2NT(mtime, &tm, (share->ss_fstype == SMB_FS_FAT));
3185	}
3186	mb_put_uint64le(mbp, tm);
3187
3188	/* Never let them set the change time */
3189	tm = 0;
3190	mb_put_uint64le(mbp, tm);
3191
3192	mb_put_uint32le(mbp, attr);		/* attr */
3193	mb_put_uint32le(mbp, 0);	/* undocumented padding */
3194	t2p->t2_maxpcount = 24;
3195	t2p->t2_maxdcount = 56;
3196	error = smb_t2_request(t2p);
3197
3198	smb_t2_done(t2p);
3199	return error;
3200}
3201
3202/*
3203 * Same as above except with a file hanlde. Note once we remove Windows 98
3204 * support we can remove passing the node into this routine.
3205 *
3206 * The calling routine must hold a reference on the share
3207 *
3208 */
3209int
3210smb1fs_smb_setfattrNT(struct smb_share *share, uint32_t attr, SMBFID fid,
3211                      struct timespec *crtime, struct timespec *mtime,
3212                      struct timespec *atime, vfs_context_t context)
3213{
3214	struct smb_t2rq *t2p;
3215	struct mbchain *mbp;
3216	uint64_t tm;
3217	int error;
3218    uint16_t smb1_fid = (uint16_t) fid;
3219
3220	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_SET_FILE_INFORMATION, 1, context, &t2p);
3221	if (error)
3222		return error;
3223	mbp = &t2p->t2_tparam;
3224	mb_init(mbp);
3225	mb_put_mem(mbp, (caddr_t)&smb1_fid, sizeof(smb1_fid), MB_MSYSTEM);
3226	if (VC_CAPS(SSTOVC(share)) & SMB_CAP_INFOLEVEL_PASSTHRU)
3227		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION);
3228	else
3229		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO);
3230	mb_put_uint16le(mbp, 0);
3231	mbp = &t2p->t2_tdata;
3232	mb_init(mbp);
3233
3234	/* set the creation time */
3235	tm = 0;
3236	if (crtime) {
3237		smb_time_local2NT(crtime, &tm, (share->ss_fstype == SMB_FS_FAT));
3238	}
3239	mb_put_uint64le(mbp, tm);
3240
3241	/* set the access time */
3242	tm = 0;
3243	if (atime) {
3244		smb_time_local2NT(atime, &tm, (share->ss_fstype == SMB_FS_FAT));
3245	}
3246	mb_put_uint64le(mbp, tm);
3247
3248	/* set the write/modify time */
3249	tm = 0;
3250	if (mtime) {
3251		smb_time_local2NT(mtime, &tm, (share->ss_fstype == SMB_FS_FAT));
3252	}
3253	mb_put_uint64le(mbp, tm);
3254
3255	/* We never allow anyone to set the change time */
3256	tm = 0;
3257	mb_put_uint64le(mbp, tm);
3258
3259	mb_put_uint32le(mbp, attr);
3260	mb_put_uint32le(mbp, 0);			/* padding */
3261	t2p->t2_maxpcount = 2;
3262	t2p->t2_maxdcount = 0;
3263	error = smb_t2_request(t2p);
3264	smb_t2_done(t2p);
3265	return error;
3266}
3267
3268/*
3269 * Modern create/open of file or directory.
3270 *
3271 * If disp is FILE_OPEN then this is an open attempt, and:
3272 *   If xattr then name is the stream to be opened at np,
3273 *   Else np should be opened.
3274 *   ...we won't touch *fidp,
3275 * Else this is a creation attempt, and:
3276 *   If xattr then name is the stream to create at np,
3277 *   Else name is the thing to create under directory np.
3278 *   ...we will return *fidp,
3279 *
3280 * The calling routine must hold a reference on the share
3281 *
3282 * Either pass in np which is the file/dir to open OR
3283 * pass in dnp and a name
3284 *
3285 */
3286int
3287smb1fs_smb_ntcreatex(struct smb_share *share, struct smbnode *np,
3288                     uint32_t rights, uint32_t shareMode, enum vtype vt,
3289                     SMBFID *fidp, const char *name, size_t in_nmlen,
3290                     uint32_t disp, int xattr, struct smbfattr *fap,
3291                     int do_create, vfs_context_t context)
3292{
3293	struct smb_rq rq, *rqp = &rq;
3294	int unix_info2 = ((UNIX_CAPS(share) & UNIX_QFILEINFO_UNIX_INFO2_CAP)) ? TRUE : FALSE;
3295	struct mbchain *mbp;
3296	struct mdchain *mdp;
3297	uint8_t wc;
3298	uint32_t lint, createopt, efa;
3299	uint64_t llint;
3300	int error;
3301	uint16_t fid, *namelenp;
3302	size_t nmlen = in_nmlen;	/* Don't change the input name length, we need it for making the ino number */
3303    int need_close = 0;
3304    SMBFID temp_fid = 0;
3305    char *snamep = NULL;
3306
3307	DBG_ASSERT(fap); /* Should never happen */
3308	bzero(fap, sizeof(*fap));
3309	nanouptime(&fap->fa_reqtime);
3310	error = smb_rq_init(rqp, SSTOCP(share), SMB_COM_NT_CREATE_ANDX, 0, context);
3311	if (error)
3312		return error;
3313	smb_rq_getrequest(rqp, &mbp);
3314	smb_rq_wstart(rqp);
3315	mb_put_uint8(mbp, 0xff);	/* secondary command */
3316	mb_put_uint8(mbp, 0);		/* MBZ */
3317	mb_put_uint16le(mbp, 0);	/* offset to next command (none) */
3318	mb_put_uint8(mbp, 0);		/* MBZ */
3319	namelenp = (uint16_t *)mb_reserve(mbp, sizeof(uint16_t));
3320	/*
3321	 * XP to W2K Server never sets the NTCREATEX_FLAGS_OPEN_DIRECTORY
3322	 * for creating nor for opening a directory. Samba ignores the bit.
3323	 *
3324	 * Request the extended reply to get maximal access
3325	 */
3326	mb_put_uint32le(mbp, NTCREATEX_FLAGS_EXTENDED);	/* NTCREATEX_FLAGS_* */
3327	mb_put_uint32le(mbp, 0);	/* FID - basis for path if not root */
3328	mb_put_uint32le(mbp, rights);
3329	mb_put_uint64le(mbp, 0);	/* "initial allocation size" */
3330	efa = (vt == VDIR) ? SMB_EFA_DIRECTORY : SMB_EFA_NORMAL;
3331	if (disp != FILE_OPEN && !xattr) {
3332		if (efa == SMB_EFA_NORMAL)
3333			efa |= SMB_EFA_ARCHIVE;
3334		if (name && (*name == '.'))
3335			efa |= SMB_EFA_HIDDEN;
3336	}
3337	mb_put_uint32le(mbp, efa);
3338	/*
3339	 * To rename an open file we need delete shared access. We currently always
3340	 * allow delete access.
3341	 */
3342	mb_put_uint32le(mbp, shareMode);
3343	mb_put_uint32le(mbp, disp);
3344	createopt = 0;
3345	if (disp != FILE_OPEN) {
3346		if (vt == VDIR)
3347			createopt |= NTCREATEX_OPTIONS_DIRECTORY;
3348		/* (other create options currently not useful) */
3349	}
3350	/*
3351	 * The server supports reparse points so open the item with a reparse point
3352	 * and bypass normal reparse point processing for the file.
3353	 */
3354	if (share->ss_attributes & FILE_SUPPORTS_REPARSE_POINTS) {
3355		createopt |= NTCREATEX_OPTIONS_OPEN_REPARSE_POINT;
3356
3357		if (np && (np->n_dosattr & SMB_EFA_OFFLINE)) {
3358		/*
3359		 * File has been moved to offline storage, do not open with a
3360		 * reparse point in this case.  See <rdar://problem/10836961>.
3361		 */
3362		createopt &= ~NTCREATEX_OPTIONS_OPEN_REPARSE_POINT;
3363		}
3364	}
3365
3366	mb_put_uint32le(mbp, createopt);
3367	mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */
3368	mb_put_uint8(mbp, 0);   /* security flags (?) */
3369	smb_rq_wend(rqp);
3370	smb_rq_bstart(rqp);
3371	do {
3372		uint16_t resourceType = 0;
3373		uint8_t sep = xattr ? ':' : '\\';
3374		/* Do they want to open the resource fork? */
3375		if ((np->n_vnode) && (vnode_isnamedstream(np->n_vnode)) && (!name) && (!xattr)) {
3376            lck_rw_lock_shared(&np->n_name_rwlock);
3377            snamep = smb_strndup(np->n_sname, np->n_snmlen);
3378            name = snamep;
3379            lck_rw_unlock_shared(&np->n_name_rwlock);
3380
3381			nmlen = np->n_snmlen;
3382			sep = ':';
3383		}
3384		if (name == NULL)
3385			nmlen = 0;
3386		error = smbfs_fullpath(mbp, np, name, &nmlen, UTF_SFM_CONVERSIONS,
3387							   SMB_UNICODE_STRINGS(SSTOVC(share)), sep);
3388		if (error)
3389			break;
3390		*namelenp = htoles(nmlen); /* doesn't includes null */
3391		smb_rq_bend(rqp);
3392		error = smb_rq_simple(rqp);
3393		if (error)
3394			break;
3395		smb_rq_getreply(rqp, &mdp);
3396		/*
3397		 * Spec say 26 for word count, but 34 words are defined and observed from
3398		 * all servers.
3399		 *
3400		 * The spec is wrong and word count should always be 34 unless we request
3401		 * the extended reply. Now some server will always return 42 even it the
3402		 * NTCREATEX_FLAGS_EXTENDED flag is not set.
3403		 *
3404		 * From the MS-SMB document concern the extend response:
3405		 *
3406		 * The word count for this response MUST be 0x2A (42). WordCount in this
3407		 * case is not used as the count of parameter words but is just a number.
3408		 */
3409        error = md_get_uint8(mdp, &wc);
3410        if (!error) {
3411            md_get_uint8(mdp, NULL);	/* secondary cmd */
3412            md_get_uint8(mdp, NULL);	/* mbz */
3413            md_get_uint16le(mdp, NULL);     /* andxoffset */
3414            md_get_uint8(mdp, NULL);	/* oplock lvl granted */
3415            error = md_get_uint16(mdp, &fid);       /* yes, leaving it LE */
3416            need_close = 1;
3417        }
3418
3419        if (error) {
3420            error = EBADRPC;
3421            break;
3422        }
3423
3424		if ( (wc != NTCREATEX_NORMAL_WDCNT) && (wc != NTCREATEX_EXTENDED_WDCNT) &&
3425                (wc != NTCREATEX_BRKEN_SPEC_26_WDCNT) ) {
3426            if (need_close == 1) {
3427                /* not much we can do if the close fails */
3428                temp_fid = fid;    /* cast SMB 1 fid to full smb fid */
3429                smbfs_smb_close(share, temp_fid, context);
3430            }
3431
3432			error = EBADRPC;
3433			break;
3434		}
3435
3436		md_get_uint32le(mdp, &fap->fa_created_disp);     /* create disposition */
3437		md_get_uint64le(mdp, &llint);   /* creation time */
3438		if (llint) {
3439			smb_time_NT2local(llint, &fap->fa_crtime);
3440		}
3441		md_get_uint64le(mdp, &llint);   /* access time */
3442		if (llint) {
3443			smb_time_NT2local(llint, &fap->fa_atime);
3444		}
3445		md_get_uint64le(mdp, &llint);   /* write time */
3446		if (llint) {
3447			smb_time_NT2local(llint, &fap->fa_mtime);
3448		}
3449		md_get_uint64le(mdp, &llint);   /* change time */
3450		if (llint) {
3451			smb_time_NT2local(llint, &fap->fa_chtime);
3452		}
3453		md_get_uint32le(mdp, &lint);    /* attributes */
3454		fap->fa_attr = lint;
3455		/*
3456		 * Because of the Steve/Conrad Symlinks we can never be completely
3457		 * sure that we have the correct vnode type if its a file. For
3458		 * directories we always know the correct information.
3459		 */
3460		if (fap->fa_attr & SMB_EFA_DIRECTORY) {
3461			fap->fa_valid_mask |= FA_VTYPE_VALID;
3462		}
3463		fap->fa_vtype = (fap->fa_attr & SMB_EFA_DIRECTORY) ? VDIR : VREG;
3464		md_get_uint64le(mdp, &llint);     /* allocation size */
3465		fap->fa_data_alloc = llint;
3466		md_get_uint64le(mdp, &llint);   /* EOF */
3467		fap->fa_size = llint;
3468		md_get_uint16le(mdp, &resourceType);     /* Resource Type */
3469		/*
3470		 * Never trust UNIX Servers when it comes to the FileStatus flags, they
3471		 * lie and always return a hard coded 7. We make an exception for Darwin
3472		 * servers, since they treat this field correctly.
3473		 */
3474		if ((resourceType == kFileTypeDisk) &&
3475			((!UNIX_SERVER(SSTOVC(share))) || (SSTOVC(share)->vc_flags & SMBV_DARWIN))) {
3476			/*
3477			 * If device type has NO_SUBSTREAMS then spec says: The file or directory
3478			 * has no data streams other than the main data stream.
3479			 *
3480			 * If NO_EAS, then spec says: The file or directory has no extended
3481			 * attributes.
3482			 */
3483			md_get_uint16le(mdp, &fap->fa_fstatus);	/* FileStatus Flags */
3484			fap->fa_valid_mask |= FA_FSTATUS_VALID;	/* Mark that this field is valid */
3485		} else {
3486			md_get_uint16le(mdp, NULL);     /* NMPipeStatus */
3487		}
3488
3489		md_get_uint8(mdp, NULL);	/* directory (boolean) */
3490		/*
3491		 * We want maximal access if we are opening up the node, if we have a
3492		 * name then ignore. This means we will never update the stream node,
3493		 * but currently we always use the main node for checking access.
3494		 */
3495		if (name)
3496			break;
3497
3498		/* Supports the maximal access rights, so lets get them */
3499		if (wc == NTCREATEX_EXTENDED_WDCNT) {
3500			int maxAccessRightsError;
3501			uint8_t VolumeGID[16];
3502			uint64_t fileID = 0;
3503			uint32_t guestMaxAccessRights = 0;
3504
3505			md_get_mem(mdp, (caddr_t)VolumeGID, sizeof(VolumeGID), MB_MSYSTEM);
3506			md_get_uint64le(mdp, &fileID);   /* File ID */
3507			/* We only care about maximal access rights currently, so check for any errors */
3508			maxAccessRightsError = md_get_uint32le(mdp, &np->maxAccessRights);
3509			if (!maxAccessRightsError)
3510				maxAccessRightsError = md_get_uint32le(mdp, &guestMaxAccessRights);
3511			if (maxAccessRightsError) {
3512				np->n_flag |= NO_EXTENDEDOPEN;
3513				SMB_LOG_AUTH_LOCK(np, "Error %d getting extended reply for %s\n", maxAccessRightsError, np->n_name);
3514			} else {
3515				SMB_LOG_AUTH_LOCK(np, "%s fileID = %llx maxAccessRights = 0x%x guestMaxAccessRights = 0x%x\n",
3516                                  np->n_name, fileID, np->maxAccessRights, guestMaxAccessRights);
3517				np->n_flag &= ~NO_EXTENDEDOPEN;
3518				/*
3519				 * We weren't granted delete access, but the parent allows delete child
3520				 * so say we have delete access on the item. If no parent then just
3521				 * say we have delete access (let the server control it).
3522				 */
3523
3524                lck_rw_lock_shared(&np->n_parent_rwlock);
3525				if (((np->maxAccessRights & SMB2_DELETE) != SMB2_DELETE) &&
3526					(!np->n_parent || (np->n_parent->maxAccessRights & SMB2_FILE_DELETE_CHILD))) {
3527					np->maxAccessRights |= SMB2_DELETE;
3528				}
3529                lck_rw_unlock_shared(&np->n_parent_rwlock);
3530			}
3531		} else {
3532			np->n_flag |= NO_EXTENDEDOPEN;
3533		}
3534		/*
3535		 * They don't support maximal access rights, so set it to all access rights
3536		 * and let the server handle any deny issues.
3537		 */
3538		if (np->n_flag & NO_EXTENDEDOPEN) {
3539			np->maxAccessRights = SA_RIGHT_FILE_ALL_ACCESS | STD_RIGHT_ALL_ACCESS;
3540			SMBDEBUG_LOCK(np, "Extended reply not supported: %s setting maxAccessRights to 0x%x rights = 0x%x\n",
3541                          np->n_name, np->maxAccessRights, rights);
3542		}
3543        np->maxAccessRightChTime = fap->fa_chtime;
3544	} while(0);
3545	smb_rq_done(rqp);
3546	if (error) {
3547        if (snamep) {
3548            SMB_FREE(snamep, M_SMBSTR);
3549        }
3550
3551		return error;
3552    }
3553
3554	if (fidp) {
3555        /* note fid is in native form */
3556        *fidp = fid;       /* save SMB 1 fid */
3557    }
3558
3559    /*
3560     * If not a directory, check if node needs to be reopened,
3561     * if so, then don't update anything at this point.
3562     * See <rdar://problem/11366143>.
3563     */
3564    if (vt != VDIR) {
3565        lck_mtx_lock(&np->f_openStateLock);
3566        if (np->f_openState & kInReopen) {
3567            lck_mtx_unlock(&np->f_openStateLock);
3568            goto WeAreDone;
3569        }
3570        lck_mtx_unlock(&np->f_openStateLock);
3571    }
3572
3573	if (xattr)	{
3574		/* If an EA or Stream then we are done */
3575		goto WeAreDone;
3576	}
3577
3578	/* We are creating the item so create the ino number */
3579	if (do_create == TRUE) {
3580		DBG_ASSERT(name != NULL);	/* This is a create so better have a name */
3581		fap->fa_ino = smbfs_getino(np, name, in_nmlen); /* SMB 1 only */
3582		goto WeAreDone;
3583	}
3584
3585	/* If this is a SYMLINK, then n_vnode could be set to NULL */
3586	if (np->n_vnode == NULL) {
3587		goto WeAreDone;
3588	}
3589	/*
3590	 * We only get to this point if the n_vnode exist and we are doing a normal
3591	 * open. If we are using UNIX extensions then we can't trust some of the
3592	 * values returned from this open response. We need to reset some of the
3593	 * value back to what we found in in the UNIX Info2 lookup.
3594	 */
3595	if (unix_info2) {
3596		/* Reset it to look like a UNIX Info2 lookup */
3597		fap->fa_unix = TRUE;
3598		fap->fa_flags_mask = EXT_REQUIRED_BY_MAC;
3599		fap->fa_nlinks = np->n_nlinks;
3600		/*
3601		 * Samba servers will return the read only bit when the posix modes
3602		 * are set to read only. This is not the same as the immutable bit,
3603		 * so don't believe what they say here about the read only bit. Keep
3604		 * the value we have store in the node we can  update from the unix
3605		 * info level.if
3606		 */
3607		fap->fa_attr &= ~SMB_EFA_RDONLY;
3608		fap->fa_attr |= (np->n_dosattr & SMB_EFA_RDONLY);
3609		fap->fa_valid_mask |= FA_VTYPE_VALID;
3610		fap->fa_vtype = vnode_vtype(np->n_vnode);
3611		/* Make sure we have the correct fa_attr setting */
3612		if (vnode_isdir(np->n_vnode))
3613			fap->fa_attr |= SMB_EFA_DIRECTORY;
3614		else
3615			fap->fa_attr &= ~SMB_EFA_DIRECTORY;
3616		/*
3617		 * Samba will return the modify time for the change time in this
3618		 * call. So if we are doing unix extensions never trust the change
3619		 * time retrieved from this call.
3620		 */
3621		fap->fa_chtime = np->n_chtime;
3622	}
3623
3624	/*
3625 	 * We have all the meta data attributes so update the cache. If the
3626	 * calling routine is setting an attribute it should not change the
3627	 * smb node value until after the open has completed. NOTE: The old
3628	 * code would only update the cache if the mtime, attributes and size
3629	 * haven't changed.
3630 	 */
3631	smbfs_attr_cacheenter(share, np->n_vnode, fap, TRUE, context);
3632
3633WeAreDone:
3634    if (snamep) {
3635        SMB_FREE(snamep, M_SMBSTR);
3636    }
3637
3638	return (0);
3639}
3640
3641/*
3642 * The calling routine must hold a reference on the share
3643 */
3644int
3645smbfs_tmpopen(struct smb_share *share, struct smbnode *np, uint32_t rights,
3646              SMBFID *fidp, vfs_context_t context)
3647{
3648	int		searchOpenFiles;
3649	int		error = 0;
3650	struct smbfattr fattr;
3651
3652	/* If no vnode or the vnode is a directory then don't use already open items */
3653	if (!np->n_vnode || vnode_isdir(np->n_vnode))
3654		searchOpenFiles = FALSE;
3655	else {
3656		/* Check to see if the file needs to be reopened */
3657		error = smbfs_smb_reopen_file(share, np, context);
3658		if (error) {
3659			SMBDEBUG_LOCK(np, " %s waiting to be revoked\n", np->n_name);
3660			return(error);
3661		}
3662
3663		/*
3664		 * A normal open can have the following rights
3665		 *	SMB2_READ_CONTROL - always set
3666		 *	SMB2_FILE_READ_DATA
3667		 *	SMB2_FILE_APPEND_DATA
3668		 *	SMB2_FILE_WRITE_DATA
3669		 *
3670		 * A normal open will never have the following rights
3671		 *	SMB2_DELETE
3672		 *	SMB2_WRITE_DAC
3673		 *	SMB2_WRITE_OWNER
3674		 *	SMB2_FILE_WRITE_ATTRIBUTES
3675		 *
3676		 */
3677		if (rights & (SMB2_DELETE | SMB2_WRITE_DAC | SMB2_WRITE_OWNER))
3678			searchOpenFiles = FALSE;
3679		else if (rights & SMB2_FILE_WRITE_ATTRIBUTES)
3680			searchOpenFiles = FALSE;
3681		else
3682			searchOpenFiles = TRUE;
3683	}
3684
3685	/*
3686	 * Remember we could have been called before the vnode is create. Conrads
3687	 * crazy symlink code. So if we have no vnode then we cannot borrow the
3688	 * fid. Only borrow a fid if the requested access modes could have been
3689	 * made on an open call.
3690	 */
3691	if (searchOpenFiles && SMBTOV(np)) {
3692		uint16_t accessMode = 0;
3693
3694		if (rights & (SMB2_READ_CONTROL | SMB2_FILE_READ_DATA))
3695			accessMode |= kAccessRead;
3696		if (rights & (SMB2_FILE_APPEND_DATA | SMB2_FILE_WRITE_DATA))
3697			accessMode |= kAccessWrite;
3698			/* Must be a Windows 98 system */
3699		if (rights & SMB2_FILE_WRITE_ATTRIBUTES)
3700			accessMode |= kAccessWrite;
3701		/* First check the non deny mode opens, if we have one up the refcnt */
3702		if ( (np->f_fid != 0)
3703            && ((accessMode & np->f_accessMode) == accessMode) ) {
3704			np->f_refcnt++;
3705			*fidp = np->f_fid;
3706			return (0);
3707		}
3708		/* Now check the deny mode opens, if we find one up the refcnt */
3709		if (np->f_refcnt && context &&
3710			(FindFileRef(SMBTOV(np), vfs_context_proc(context), accessMode,
3711							   kAnyMatch, 0, 0, NULL, fidp) == 0)) {
3712			np->f_refcnt++;
3713			return (0);
3714		}
3715	}
3716	/*
3717	 * For temp opens we give unixy semantics of permitting everything not forbidden
3718	 * by permissions.  Ie denial is up to server with clients/openers needing to use
3719	 * advisory locks for further control.
3720	 */
3721    uint32_t shareMode = NTCREATEX_SHARE_ACCESS_ALL;
3722
3723    error = smbfs_smb_ntcreatex(share, np,
3724                                rights, shareMode, (np->n_vnode && vnode_isdir(np->n_vnode)) ? VDIR : VREG,
3725                                fidp, NULL, 0,
3726                                FILE_OPEN, FALSE, &fattr,
3727                                FALSE, NULL, context);
3728	if (error) {
3729		SMBWARNING_LOCK(np, "%s failed to open: error = %d\n", np->n_name, error);
3730    }
3731
3732	return (error);
3733}
3734
3735/*
3736 * The calling routine must hold a reference on the share
3737 */
3738int
3739smbfs_tmpclose(struct smb_share *share, struct smbnode *np, SMBFID fid,
3740			   vfs_context_t context)
3741{
3742	struct fileRefEntry *entry = NULL;
3743	vnode_t vp = SMBTOV(np);
3744
3745	/*
3746	 * Remember we could have been called before the vnode is created. Conrads
3747	 * crazy symlink code. So if we have no vnode then we did not borrow the
3748	 * fid. If we did not borrow the fid then just close the fid and get out.
3749	 *
3750	 * If no vnode or the vnode is a directory then just close it, we are not
3751	 * sharing the open.
3752	 */
3753	if (!vp || vnode_isdir(vp) ||
3754        ((fid != np->f_fid) &&
3755         (FindFileEntryByFID(vp, fid, &entry)))) {
3756		return(smbfs_smb_close(share, fid, context));
3757	}
3758	/*
3759	 * OK we borrowed the fid do we have the last reference count on it. If
3760	 * yes, then we need to close up every thing. smbfs_close can handle this
3761	 * for us.
3762	 */
3763	if (np->f_refcnt == 1) {
3764		/* Open Mode does not matter becasue we closing everything */
3765		return(smbfs_close(share, vp, 0, context));
3766	}
3767
3768	/* We borrowed the fid decrement the ref count */
3769    if (np->f_refcnt > 0) {
3770        np->f_refcnt--;
3771    }
3772
3773	return (0);
3774}
3775
3776/*
3777 * This routine chains the open and read into one message. This routine is used only
3778 * for reading data out of a stream. If we decided to use it for something else then
3779 * we will need to make some changes.
3780 *
3781 * The calling routine must hold a reference on the share
3782 *
3783 */
3784int
3785smb1fs_smb_openread(struct smb_share *share, struct smbnode *np, SMBFID *fid,
3786				   uint32_t rights, uio_t uio, size_t *sizep, const char *name,
3787				   struct timespec *mtime, vfs_context_t context)
3788{
3789	struct smb_rq rq, *rqp = &rq;
3790	struct mbchain *mbp;
3791	struct mdchain *mdp;
3792	uint8_t wc, cmd;
3793	int error = 0;
3794	uint16_t *namelenp, *nextWdCntOffset, nextOffset;
3795	uint64_t eof;
3796	uint16_t residhi, residlo, off, doff;
3797	uint32_t resid;
3798	uint32_t len = (uint32_t)uio_resid(uio);
3799	size_t nmlen = strnlen(name, share->ss_maxfilenamelen+1);
3800    uint16_t smb1_fid;
3801
3802	/*
3803	 * Make sure the whole response message will fit in our max buffer size. Since
3804	 * we use the CreateAndX open call make sure the server supports that call.
3805	 * The calling routine must handle this routine returning ENOTSUP.
3806	 */
3807	if ((SSTOVC(share)->vc_txmax - SMB_MAX_CHAIN_READ) < len)
3808		return(ENOTSUP);
3809
3810	/* encode the CreateAndX request */
3811	error = smb_rq_init(rqp, SSTOCP(share), SMB_COM_NT_CREATE_ANDX, 0, context);
3812	if (error)
3813		return error;
3814	smb_rq_getrequest(rqp, &mbp);
3815	smb_rq_wstart(rqp);
3816	mb_put_uint8(mbp, SMB_COM_READ_ANDX);	/* next chain command will be a read */
3817	mb_put_uint8(mbp, 0);					/* MBZ */
3818	/*
3819	 * The next command offset is the numbers of bytes from the smb header to
3820	 * the location ofthe next commands word count field. Save that location so
3821	 * we can fill it in later.
3822	 */
3823	nextWdCntOffset = (uint16_t *)mb_reserve(mbp, sizeof(uint16_t)); /* offset to next command */
3824	mb_put_uint8(mbp, 0);		/* MBZ */
3825	/* Save off the name length field so we can fill it in later */
3826	namelenp = (uint16_t *)mb_reserve(mbp, sizeof(uint16_t));
3827
3828	mb_put_uint32le(mbp, 0);	/* Oplock?  NTCREATEX_FLAGS_REQUEST_OPLOCK */
3829	mb_put_uint32le(mbp, 0);	/* Root fid not used */
3830	mb_put_uint32le(mbp, rights);
3831	mb_put_uint64le(mbp, 0);	/* "initial allocation size" */
3832	mb_put_uint32le(mbp, SMB_EFA_NORMAL);
3833	/* Deny write access if they want write access */
3834	if (rights & SMB2_FILE_WRITE_DATA) {
3835		mb_put_uint32le(mbp, (NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE));
3836		mb_put_uint32le(mbp, FILE_OPEN_IF);
3837	} else {
3838		mb_put_uint32le(mbp, NTCREATEX_SHARE_ACCESS_ALL);
3839		mb_put_uint32le(mbp, FILE_OPEN);
3840	}
3841	mb_put_uint32le(mbp, 0);
3842	mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION);
3843	mb_put_uint8(mbp, 0);   /* security flags */
3844	smb_rq_wend(rqp);
3845	smb_rq_bstart(rqp);
3846	/* Put in the path name here */
3847	error = smbfs_fullpath(mbp, np, name, &nmlen, UTF_SFM_CONVERSIONS,
3848						   SMB_UNICODE_STRINGS(SSTOVC(share)), ':');
3849	if (error)
3850		goto exit;
3851
3852	*namelenp = htoles(nmlen); /* doesn't include the null bytes */
3853	smb_rq_bend(rqp);
3854
3855	mb_put_padbyte(mbp); /* make sure the next message is on an even boundry */
3856	*nextWdCntOffset = htoles(mb_fixhdr(mbp));
3857
3858	/* now add the read request */
3859	smb_rq_wstart(rqp);
3860	mb_put_uint8(mbp, 0xff); /* no secondary command */
3861	mb_put_uint8(mbp, 0);
3862	mb_put_uint16le(mbp, 0); /* offset to secondary, no more chain items */
3863	mb_put_uint16le(mbp, 0); /* set fid field to zero the server fills this in */
3864
3865	mb_put_uint32le(mbp, (uint32_t)uio_offset(uio)); /* Lower offset */
3866	mb_put_uint16le(mbp, (uint16_t)len); /* MaxCount */
3867	mb_put_uint16le(mbp, (uint16_t)len); /* MinCount (only indicates blocking) */
3868	mb_put_uint32le(mbp, len >> 16); /* MaxCountHigh */
3869	mb_put_uint16le(mbp, (uint16_t)len); /* Remaining ("obsolete") */
3870	mb_put_uint32le(mbp, (uint32_t)(uio_offset(uio) >> 32)); /* high offset */
3871
3872	smb_rq_wend(rqp);
3873	smb_rq_bstart(rqp);
3874	smb_rq_bend(rqp);
3875	/* Send the message */
3876	error = smb_rq_simple(rqp);
3877	if (error)
3878		goto exit;
3879	smb_rq_getreply(rqp, &mdp);
3880
3881	/*
3882	 * I know there are some servers that return word counts of 42, but I don't
3883	 * remember exactly why (Not Windows Systems). Shouldn't matter to us because
3884	 * the offset to the read message will eat any extra bytes.
3885	*/
3886	if (md_get_uint8(mdp, &wc) != 0 || (wc != 34 && wc != 42)) {
3887		error = EINVAL;
3888		goto exit;
3889	}
3890	md_get_uint8(mdp, &cmd);	/* secondary cmd */
3891
3892	md_get_uint8(mdp, NULL);	/* mbz */
3893	/* Contains the offset from the start of the message to the read message. */
3894	md_get_uint16le(mdp, &nextOffset);     /* andxoffset */
3895	md_get_uint8(mdp, NULL);	/* oplock lvl granted */
3896	md_get_uint16(mdp, &smb1_fid);       /* Get the fid */
3897    *fid = smb1_fid;       /* save SMB 1 fid */
3898	md_get_uint32le(mdp, NULL);     /* create_action */
3899	md_get_uint64le(mdp, NULL);   /* creation time */
3900	md_get_uint64le(mdp, NULL);   /* access time */
3901	if (mtime) {
3902		uint64_t llint;
3903
3904		md_get_uint64le(mdp, &llint);   /* write time */
3905		if (llint)
3906			smb_time_NT2local(llint, mtime);
3907	}
3908	else
3909		md_get_uint64le(mdp, NULL);   /* write time */
3910
3911	md_get_uint64le(mdp, NULL);   /* change time */
3912	md_get_uint32le(mdp, NULL);    /* attributes */
3913	md_get_uint64le(mdp, NULL);     /* allocation size */
3914	md_get_uint64le(mdp, &eof);   /* EOF */
3915	if (sizep)
3916		*sizep = (size_t)eof;		/* The calling routines can only handle size_t */
3917	md_get_uint16le(mdp, NULL);     /* file type */
3918	md_get_uint16le(mdp, NULL);     /* device state */
3919	md_get_uint8(mdp, NULL);	/* directory (boolean) */
3920	md_get_uint16(mdp, NULL);	/* byte count */
3921
3922	if (cmd != SMB_COM_READ_ANDX) {
3923		if ((rights & SMB2_FILE_WRITE_DATA) && fid)	/* We created the file */
3924			error = 0;
3925		else
3926			error = ENOENT;
3927		goto exit;
3928	}
3929
3930	off = nextOffset;
3931	/* Is the offset pass the end of our buffer? */
3932    m_fixhdr(mdp->md_top);
3933	if (nextOffset > mbuf_pkthdr_len(mdp->md_top)) {
3934		error = EINVAL;
3935		goto exit;
3936	}
3937	/* Take off what we have already consumed. */
3938	nextOffset -= (SMB_HDRLEN + SMB_CREATEXRLEN + SMB_BCOUNT_LEN);
3939	if (nextOffset != 0) /* Anything left dump it */
3940		md_get_mem(mdp, NULL, nextOffset, MB_MSYSTEM);
3941
3942		/* We are at the read message make sure the word count matches. */
3943	if (md_get_uint8(mdp, &wc) != 0 || (wc != 12)) {
3944		error = EINVAL;
3945		goto exit;
3946	}
3947	/* Now handle the read response */
3948	off++;
3949	md_get_uint8(mdp, NULL);
3950	off++;
3951	md_get_uint8(mdp, NULL);
3952	off++;
3953	md_get_uint16le(mdp, NULL);
3954	off += 2;
3955	md_get_uint16le(mdp, NULL);
3956	off += 2;
3957	md_get_uint16le(mdp, NULL);	/* data compaction mode */
3958	off += 2;
3959	md_get_uint16le(mdp, NULL);
3960	off += 2;
3961	md_get_uint16le(mdp, &residlo);
3962	off += 2;
3963	md_get_uint16le(mdp, &doff);	/* data offset */
3964	off += 2;
3965	md_get_uint16le(mdp, &residhi);
3966	off += 2;
3967	resid = (residhi << 16) | residlo;
3968	md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
3969	off += 4*2;
3970	md_get_uint16le(mdp, NULL);	/* ByteCount */
3971	off += 2;
3972	if (doff > off)	/* pad byte(s)? */
3973		md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
3974	if (resid)
3975		error = md_get_uio(mdp, uio, resid);
3976
3977exit:
3978	smb_rq_done(rqp);
3979	return (error);
3980}
3981
3982int
3983smb1fs_smb_open_maxaccess(struct smb_share *share, struct smbnode *dnp,
3984                          const char *namep, size_t name_len,
3985                          SMBFID *fidp, uint32_t *max_accessp,
3986                          vfs_context_t context)
3987{
3988#pragma unused(name_len)
3989	struct smb_rq rq, *rqp = &rq;
3990	struct mbchain *mbp;
3991	struct mdchain *mdp;
3992	uint8_t wc;
3993	int error = 0;
3994	uint16_t *namelenp, nextOffset;
3995	size_t nmlen = strnlen(namep, share->ss_maxfilenamelen+1);
3996    uint16_t smb1_fid;
3997
3998    /* Non zero fid means the open worked and a close is needed */
3999    *fidp = 0;
4000
4001	/* encode the CreateAndX request */
4002	error = smb_rq_init(rqp, SSTOCP(share), SMB_COM_NT_CREATE_ANDX, 0, context);
4003	if (error) {
4004		return error;
4005    }
4006
4007	smb_rq_getrequest(rqp, &mbp);
4008
4009	smb_rq_wstart(rqp);
4010	mb_put_uint8(mbp, 0xff);                /* secondary command */
4011	mb_put_uint8(mbp, 0);                   /* MBZ */
4012	mb_put_uint16le(mbp, 0);                /* offset to next command (none) */
4013	mb_put_uint8(mbp, 0);                   /* MBZ */
4014	/* Save off the name length field so we can fill it in later */
4015	namelenp = (uint16_t *)mb_reserve(mbp, sizeof(uint16_t));
4016	mb_put_uint32le(mbp, NTCREATEX_FLAGS_EXTENDED);	/* NTCREATEX_FLAGS_* */
4017	mb_put_uint32le(mbp, 0);                /* Root fid not used */
4018	mb_put_uint32le(mbp, SMB2_FILE_READ_DATA);
4019	mb_put_uint64le(mbp, 0);                /* "initial allocation size" */
4020	mb_put_uint32le(mbp, SMB_EFA_NORMAL);
4021    mb_put_uint32le(mbp, NTCREATEX_SHARE_ACCESS_ALL);
4022    mb_put_uint32le(mbp, FILE_OPEN);
4023	mb_put_uint32le(mbp, 0);
4024	mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION);
4025	mb_put_uint8(mbp, 0);                   /* security flags */
4026	smb_rq_wend(rqp);
4027
4028	smb_rq_bstart(rqp);
4029    	/* Put in the path name with stream name here */
4030	error = smbfs_fullpath_stream(mbp, dnp,
4031                                  namep, NULL,
4032                                  &nmlen, 0, UTF_SFM_CONVERSIONS,
4033                                  SMB_UNICODE_STRINGS(SSTOVC(share)), '\\');
4034	if (error)
4035		goto exit;
4036
4037	*namelenp = htoles(nmlen);              /* doesn't include the null bytes */
4038	smb_rq_bend(rqp);
4039
4040	/* Send the message */
4041	error = smb_rq_simple(rqp);
4042	if (error)
4043		goto exit;
4044
4045	smb_rq_getreply(rqp, &mdp);
4046
4047	/*
4048	 * I know there are some servers that return word counts of 42, but I don't
4049	 * remember exactly why (Not Windows Systems). Shouldn't matter to us because
4050	 * the offset to the read message will eat any extra bytes.
4051     */
4052	if (md_get_uint8(mdp, &wc) != 0 ||
4053        (wc != NTCREATEX_NORMAL_WDCNT && wc != NTCREATEX_EXTENDED_WDCNT)) {
4054		error = EINVAL;
4055		goto exit;
4056	}
4057
4058	md_get_uint8(mdp, NULL);            /* secondary cmd */
4059
4060	md_get_uint8(mdp, NULL);            /* mbz */
4061	/* Contains the offset from the start of the message to the read message. */
4062	md_get_uint16le(mdp, &nextOffset);  /* andxoffset */
4063	md_get_uint8(mdp, NULL);            /* oplock lvl granted */
4064	md_get_uint16(mdp, &smb1_fid);      /* Get the fid */
4065    *fidp = smb1_fid;                   /* save SMB 1 fid */
4066	md_get_uint32le(mdp, NULL);         /* create_action */
4067	md_get_uint64le(mdp, NULL);         /* creation time */
4068	md_get_uint64le(mdp, NULL);         /* access time */
4069    md_get_uint64le(mdp, NULL);         /* write time */
4070
4071	md_get_uint64le(mdp, NULL);         /* change time */
4072	md_get_uint32le(mdp, NULL);         /* attributes */
4073	md_get_uint64le(mdp, NULL);         /* allocation size */
4074	md_get_uint64le(mdp, NULL);         /* EOF */
4075	md_get_uint16le(mdp, NULL);         /* file type */
4076	md_get_uint16le(mdp, NULL);         /* device state */
4077	md_get_uint8(mdp, NULL);            /* directory (boolean) */
4078
4079    /* Supports the maximal access rights, so lets get them */
4080    if (wc == NTCREATEX_EXTENDED_WDCNT) {
4081        int maxAccessRightsError;
4082        uint8_t VolumeGID[16];
4083        uint64_t fileID = 0;
4084        uint32_t guestMaxAccessRights = 0;
4085        uint32_t max_access_rights = 0;
4086
4087        md_get_mem(mdp, (caddr_t)VolumeGID, sizeof(VolumeGID), MB_MSYSTEM);
4088        md_get_uint64le(mdp, &fileID);   /* File ID */
4089
4090        /*
4091         * We only care about maximal access rights currently,
4092         * so check for any errors
4093         */
4094        maxAccessRightsError = md_get_uint32le(mdp, &max_access_rights);
4095        if (!maxAccessRightsError) {
4096            maxAccessRightsError = md_get_uint32le(mdp, &guestMaxAccessRights);
4097        }
4098
4099        if (maxAccessRightsError) {
4100            *max_accessp = SA_RIGHT_FILE_ALL_ACCESS | STD_RIGHT_ALL_ACCESS;
4101        }
4102        else {
4103            /*
4104             * We weren't granted delete access, but the parent allows delete child
4105             * so say we have delete access on the item. If no parent then just
4106             * say we have delete access (let the server control it).
4107             */
4108            if (((max_access_rights & SMB2_DELETE) != SMB2_DELETE) &&
4109                (!dnp || (dnp->maxAccessRights & SMB2_FILE_DELETE_CHILD))) {
4110                max_access_rights |= SMB2_DELETE;
4111            }
4112
4113            *max_accessp = max_access_rights;
4114        }
4115    }
4116    else {
4117        /* Must not support max access rights, so grant full access */
4118        SMBDEBUG("Server does not support max access, returning full access\n");
4119        *max_accessp = SA_RIGHT_FILE_ALL_ACCESS | STD_RIGHT_ALL_ACCESS;
4120    }
4121
4122exit:
4123	smb_rq_done(rqp);
4124	return (error);
4125}
4126
4127int
4128smb1fs_smb_open_read(struct smb_share *share, struct smbnode *dnp,
4129                     const char *namep, size_t name_len,
4130                     const char *strm_namep, size_t strm_name_len,
4131                     SMBFID *fidp, uio_t uio, size_t *sizep,
4132                     uint32_t *max_accessp,
4133                     vfs_context_t context)
4134{
4135#pragma unused(name_len)
4136#pragma unused(strm_name_len)
4137	struct smb_rq rq, *rqp = &rq;
4138	struct mbchain *mbp;
4139	struct mdchain *mdp;
4140	uint8_t wc, cmd;
4141	int error = 0;
4142    int error2 = 0;
4143	uint16_t *namelenp, *nextWdCntOffset, nextOffset;
4144	uint64_t eof;
4145	uint16_t residhi, residlo, off, doff;
4146	uint32_t resid;
4147	uint32_t len = (uint32_t)uio_resid(uio);
4148	size_t nmlen = strnlen(namep, share->ss_maxfilenamelen+1);
4149	size_t snmlen = strnlen(strm_namep, share->ss_maxfilenamelen+1);
4150    uint16_t smb1_fid;
4151    uint32_t rights = SMB2_FILE_READ_DATA;
4152
4153	/*
4154	 * Make sure the whole response message will fit in our max buffer size. Since
4155	 * we use the CreateAndX open call make sure the server supports that call.
4156	 * The calling routine must handle this routine returning ENOTSUP.
4157	 */
4158	if ((SSTOVC(share)->vc_txmax - SMB_MAX_CHAIN_READ) < len)
4159		return(ENOTSUP);
4160
4161	/* encode the CreateAndX request */
4162	error = smb_rq_init(rqp, SSTOCP(share), SMB_COM_NT_CREATE_ANDX, 0, context);
4163	if (error)
4164		return error;
4165	smb_rq_getrequest(rqp, &mbp);
4166	smb_rq_wstart(rqp);
4167	mb_put_uint8(mbp, SMB_COM_READ_ANDX);	/* next chain command will be a read */
4168	mb_put_uint8(mbp, 0);					/* MBZ */
4169	/*
4170	 * The next command offset is the numbers of bytes from the smb header to
4171	 * the location ofthe next commands word count field. Save that location so
4172	 * we can fill it in later.
4173	 */
4174	nextWdCntOffset = (uint16_t *)mb_reserve(mbp, sizeof(uint16_t)); /* offset to next command */
4175	mb_put_uint8(mbp, 0);		/* MBZ */
4176	/* Save off the name length field so we can fill it in later */
4177	namelenp = (uint16_t *)mb_reserve(mbp, sizeof(uint16_t));
4178
4179    if (max_accessp) {
4180        /* Ask for max access */
4181        mb_put_uint32le(mbp, NTCREATEX_FLAGS_EXTENDED);	/* NTCREATEX_FLAGS_* */
4182    }
4183    else {
4184        mb_put_uint32le(mbp, 0);                        /* NTCREATEX_FLAGS_* */
4185    }
4186
4187	mb_put_uint32le(mbp, 0);	/* Root fid not used */
4188	mb_put_uint32le(mbp, rights);
4189	mb_put_uint64le(mbp, 0);	/* "initial allocation size" */
4190	mb_put_uint32le(mbp, SMB_EFA_NORMAL);
4191	/* Deny write access if they want write access */
4192	if (rights & SMB2_FILE_WRITE_DATA) {
4193		mb_put_uint32le(mbp, (NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE));
4194		mb_put_uint32le(mbp, FILE_OPEN_IF);
4195	} else {
4196		mb_put_uint32le(mbp, NTCREATEX_SHARE_ACCESS_ALL);
4197		mb_put_uint32le(mbp, FILE_OPEN);
4198	}
4199	mb_put_uint32le(mbp, 0);
4200	mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION);
4201	mb_put_uint8(mbp, 0);   /* security flags */
4202	smb_rq_wend(rqp);
4203	smb_rq_bstart(rqp);
4204	/* Put in the path name with stream name here */
4205	error = smbfs_fullpath_stream(mbp, dnp,
4206                                  namep, strm_namep,
4207                                  &nmlen, snmlen, UTF_SFM_CONVERSIONS,
4208                                  SMB_UNICODE_STRINGS(SSTOVC(share)), '\\');
4209	if (error)
4210		goto exit;
4211
4212	*namelenp = htoles(nmlen); /* doesn't include the null bytes */
4213	smb_rq_bend(rqp);
4214
4215	mb_put_padbyte(mbp); /* make sure the next message is on an even boundry */
4216	*nextWdCntOffset = htoles(mb_fixhdr(mbp));
4217
4218	/* now add the read request */
4219	smb_rq_wstart(rqp);
4220	mb_put_uint8(mbp, 0xff); /* no secondary command */
4221	mb_put_uint8(mbp, 0);
4222	mb_put_uint16le(mbp, 0); /* offset to secondary, no more chain items */
4223	mb_put_uint16le(mbp, 0); /* set fid field to zero the server fills this in */
4224
4225	mb_put_uint32le(mbp, (uint32_t)uio_offset(uio)); /* Lower offset */
4226	mb_put_uint16le(mbp, (uint16_t)len); /* MaxCount */
4227	mb_put_uint16le(mbp, (uint16_t)len); /* MinCount (only indicates blocking) */
4228	mb_put_uint32le(mbp, len >> 16); /* MaxCountHigh */
4229	mb_put_uint16le(mbp, (uint16_t)len); /* Remaining ("obsolete") */
4230	mb_put_uint32le(mbp, (uint32_t)(uio_offset(uio) >> 32)); /* high offset */
4231
4232	smb_rq_wend(rqp);
4233	smb_rq_bstart(rqp);
4234	smb_rq_bend(rqp);
4235	/* Send the message */
4236	error = smb_rq_simple(rqp);
4237	if (error) {
4238		/*
4239         * Dont exit yet, may still be able to parse the Create part out and
4240         * get the fid so we can do a close
4241         */
4242    }
4243	smb_rq_getreply(rqp, &mdp);
4244
4245	/*
4246	 * I know there are some servers that return word counts of 42, but I don't
4247	 * remember exactly why (Not Windows Systems). Shouldn't matter to us because
4248	 * the offset to the read message will eat any extra bytes.
4249     */
4250	if (md_get_uint8(mdp, &wc) != 0 ||
4251        (wc != NTCREATEX_NORMAL_WDCNT && wc != NTCREATEX_EXTENDED_WDCNT)) {
4252        /* Dont overwrite earlier error */
4253        if (error == 0) {
4254            error = EINVAL;
4255        }
4256		goto exit;
4257	}
4258
4259	error2 = md_get_uint8(mdp, &cmd);       /* AndX Command */
4260    if (error2) {
4261        /* Dont overwrite earlier error */
4262        if (error == 0) {
4263            error = error2;
4264        }
4265		goto exit;
4266    }
4267
4268	error2 = md_get_uint8(mdp, NULL);       /* AndX Reserved */
4269    if (error2) {
4270        /* Dont overwrite earlier error */
4271        if (error == 0) {
4272            error = error2;
4273        }
4274		goto exit;
4275    }
4276
4277	error2 = md_get_uint16le(mdp, &nextOffset); /* AndX Offset */
4278    if (error2) {
4279        /* Dont overwrite earlier error */
4280        if (error == 0) {
4281            error = error2;
4282        }
4283		goto exit;
4284    }
4285
4286	error2 = md_get_uint8(mdp, NULL);       /* OpLock Level */
4287    if (error2) {
4288        /* Dont overwrite earlier error */
4289        if (error == 0) {
4290            error = error2;
4291        }
4292		goto exit;
4293    }
4294
4295	error2 = md_get_uint16(mdp, &smb1_fid); /* FID */
4296    if (error2) {
4297        /* Dont overwrite earlier error */
4298        if (error == 0) {
4299            error = error2;
4300        }
4301		goto exit;
4302    }
4303    *fidp = smb1_fid;       /* save SMB 1 fid */
4304
4305	if (error) {
4306        /* Now have FID so can do a close, now we can return with error */
4307		goto exit;
4308    }
4309
4310    md_get_uint32le(mdp, NULL);     /* create_action */
4311	md_get_uint64le(mdp, NULL);     /* creation time */
4312	md_get_uint64le(mdp, NULL);     /* access time */
4313    md_get_uint64le(mdp, NULL);     /* write time */
4314
4315	md_get_uint64le(mdp, NULL);     /* change time */
4316	md_get_uint32le(mdp, NULL);     /* attributes */
4317	md_get_uint64le(mdp, NULL);     /* allocation size */
4318	md_get_uint64le(mdp, &eof);     /* EOF */
4319	if (sizep)
4320		*sizep = (size_t)eof;		/* The calling routines can only handle size_t */
4321	md_get_uint16le(mdp, NULL);     /* file type */
4322	md_get_uint16le(mdp, NULL);     /* device state */
4323	md_get_uint8(mdp, NULL);        /* directory (boolean) */
4324
4325    /* Supports the maximal access rights, so lets get them */
4326    if (wc == NTCREATEX_EXTENDED_WDCNT) {
4327        int maxAccessRightsError;
4328        uint8_t VolumeGID[16];
4329        uint64_t fileID = 0;
4330        uint32_t guestMaxAccessRights = 0;
4331        uint32_t max_access_rights = 0;
4332
4333        md_get_mem(mdp, (caddr_t)VolumeGID, sizeof(VolumeGID), MB_MSYSTEM);
4334        md_get_uint64le(mdp, &fileID);   /* File ID */
4335
4336        /* We only care about maximal access rights currently, so check for any errors */
4337        maxAccessRightsError = md_get_uint32le(mdp, &max_access_rights);
4338        if (!maxAccessRightsError) {
4339            maxAccessRightsError = md_get_uint32le(mdp, &guestMaxAccessRights);
4340        }
4341
4342        if (maxAccessRightsError) {
4343            if (max_accessp) {
4344                *max_accessp = SA_RIGHT_FILE_ALL_ACCESS | STD_RIGHT_ALL_ACCESS;
4345            }
4346        }
4347        else {
4348            /*
4349             * We weren't granted delete access, but the parent allows delete child
4350             * so say we have delete access on the item. If no parent then just
4351             * say we have delete access (let the server control it).
4352             */
4353            if (((max_access_rights & SMB2_DELETE) != SMB2_DELETE) &&
4354                (!dnp || (dnp->maxAccessRights & SMB2_FILE_DELETE_CHILD))) {
4355                max_access_rights |= SMB2_DELETE;
4356            }
4357
4358            if (max_accessp) {
4359                *max_accessp = max_access_rights;
4360            }
4361        }
4362    }
4363    else {
4364        /* Must not support max access rights, so grant full access */
4365        if (max_accessp) {
4366            SMBDEBUG("Server does not support max access, returning full access\n");
4367            *max_accessp = SA_RIGHT_FILE_ALL_ACCESS | STD_RIGHT_ALL_ACCESS;
4368        }
4369    }
4370
4371    if (cmd != SMB_COM_READ_ANDX) {
4372		if ((rights & SMB2_FILE_WRITE_DATA) && fidp)	/* We created the file */
4373			error = 0;
4374		else
4375			error = ENOENT;
4376		goto exit;
4377	}
4378
4379	off = nextOffset;
4380	/* Is the offset pass the end of our buffer? */
4381    m_fixhdr(mdp->md_top);
4382	if (nextOffset > mbuf_pkthdr_len(mdp->md_top)) {
4383		error = EINVAL;
4384		goto exit;
4385	}
4386
4387	/* Take off what we have already consumed. */
4388    if (wc == NTCREATEX_EXTENDED_WDCNT) {
4389        /* Extended Create response */
4390        nextOffset -= SMB_HDRLEN;
4391        nextOffset -= 69;       /* Ext Create Response length */
4392        nextOffset -= 32;       /* Max Access Rights len */
4393    }
4394    else {
4395        /* Non Extended Create response */
4396        md_get_uint16(mdp, NULL);        /* Byte Count */
4397
4398        nextOffset -= (SMB_HDRLEN + SMB_CREATEXRLEN + SMB_BCOUNT_LEN);
4399    }
4400
4401	if (nextOffset != 0) {
4402        /* Anything left dump it */
4403		md_get_mem(mdp, NULL, nextOffset, MB_MSYSTEM);
4404    }
4405
4406    /* We are at the read message make sure the word count matches. */
4407	if (md_get_uint8(mdp, &wc) != 0 || (wc != 12)) {
4408		error = EINVAL;
4409		goto exit;
4410	}
4411
4412	/* Now handle the read response */
4413	off++;
4414	md_get_uint8(mdp, NULL);
4415	off++;
4416	md_get_uint8(mdp, NULL);
4417	off++;
4418	md_get_uint16le(mdp, NULL);
4419	off += 2;
4420	md_get_uint16le(mdp, NULL);
4421	off += 2;
4422	md_get_uint16le(mdp, NULL);	/* data compaction mode */
4423	off += 2;
4424	md_get_uint16le(mdp, NULL);
4425	off += 2;
4426	md_get_uint16le(mdp, &residlo);
4427	off += 2;
4428	md_get_uint16le(mdp, &doff);	/* data offset */
4429	off += 2;
4430	md_get_uint16le(mdp, &residhi);
4431	off += 2;
4432	resid = (residhi << 16) | residlo;
4433	md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
4434	off += 4*2;
4435	md_get_uint16le(mdp, NULL);	/* ByteCount */
4436	off += 2;
4437	if (doff > off)	/* pad byte(s)? */
4438		md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
4439	if (resid)
4440		error = md_get_uio(mdp, uio, resid);
4441
4442exit:
4443	smb_rq_done(rqp);
4444	return (error);
4445}
4446
4447/*
4448 * The calling routine must hold a reference on the share
4449 */
4450int
4451smbfs_smb_open_file(struct smb_share *share, struct smbnode *np,
4452                    uint32_t rights, uint32_t shareMode, SMBFID *fidp,
4453                    const char *name, size_t nmlen, int xattr,
4454                    struct smbfattr *fap, vfs_context_t context)
4455{
4456	int error;
4457	int do_create;
4458    uint32_t disp;
4459
4460    /*
4461     * We are opening the resource fork from a normal open, so it should
4462     * always exist. Tell the server to create it if it doesn't exist otherwise
4463     * just open it. We never create it if coming from an xattr call.
4464     */
4465    if ((np->n_flag & N_ISRSRCFRK) && !xattr) {
4466        disp = FILE_OPEN_IF;
4467        do_create = TRUE;
4468    } else {
4469        disp = FILE_OPEN;
4470        do_create = FALSE;
4471    }
4472    error = smbfs_smb_ntcreatex(share, np,
4473                                rights, shareMode, VREG,
4474                                fidp, name, nmlen,
4475                                disp, xattr, fap,
4476                                do_create, NULL, context);
4477	return (error);
4478}
4479
4480/*
4481 * The calling routine must hold a reference on the share
4482 */
4483int
4484smbfs_smb_open_xattr(struct smb_share *share, struct smbnode *np, uint32_t rights,
4485                     uint32_t shareMode, SMBFID *fidp, const char *name,
4486                     size_t *sizep, vfs_context_t context)
4487{
4488	size_t nmlen = strnlen(name, share->ss_maxfilenamelen+1);
4489	int error;
4490	struct smbfattr fattr;
4491
4492	error = smbfs_smb_open_file(share, np, rights, shareMode, fidp,
4493								name, nmlen, TRUE, &fattr, context);
4494	if (!error && sizep)
4495		*sizep = (size_t)fattr.fa_size;
4496	return(error);
4497}
4498
4499/*
4500 * The calling routine must hold a reference on the share
4501 * Attempts to reopen the shared fid only.
4502 */
4503int
4504smbfs_smb_reopen_file(struct smb_share *share, struct smbnode *np,
4505                      vfs_context_t context)
4506{
4507    int error = 0;
4508    struct timespec n_mtime = np->n_mtime; /* open can change this value save it */
4509    u_quad_t n_size = np->n_size; /* open can change this value save it */
4510    struct smbfattr fattr;
4511
4512    /*
4513    * We are in the middle of a reconnect, wait for it to complete
4514    * Although if its the iod_context, allow this reopen to proceed
4515    */
4516    if (context != SSTOVC(share)->vc_iod->iod_context) {
4517        while (share->ss_flags & SMBS_RECONNECTING) {
4518            SMBDEBUG("SMBS_RECONNECTING Going to sleep! \n");
4519            msleep(&share->ss_flags, 0, PWAIT, "smbfs_smb_reopen_file", NULL);
4520        }
4521    }
4522
4523    lck_mtx_lock(&np->f_openStateLock);
4524
4525    /* File was already revoked, just return the correct error */
4526    if (np->f_openState & kNeedRevoke) {
4527        lck_mtx_unlock(&np->f_openStateLock);
4528        return EIO;
4529    } else if (!(np->f_openState & kNeedReopen) &&
4530               !(np->f_openState & kInReopen)) {
4531        /*
4532         * Note smb2fs_reconnect() resets kNeedReopen before making this call
4533         * so it can detect if another reconnect happened while trying to reopen
4534         * the file. But this inadvertently prevents the file from being opened,
4535         * since we would simply return here.
4536         *
4537         * Luckily smb2fs_reconnect() sets kInReopen at the same time,
4538         * so now we check both kNeedReopen and kInReopen to decide
4539         * whether to just return here or try to open the file below.
4540         * Fixes <rdar://problem/17510490>.
4541         */
4542        lck_mtx_unlock(&np->f_openStateLock);
4543        return 0;	/* Nothing wrong so just return */
4544    }
4545
4546	/*
4547     * Clear the kNeedReopen flag, this way we know if a
4548     * reconnect happens during reopen
4549     */
4550	np->f_openState &= ~kNeedReopen;
4551    np->f_openState |= kInReopen;
4552    lck_mtx_unlock(&np->f_openStateLock);
4553
4554    DBG_ASSERT(np->f_refcnt);	/* Better have an open at this point */
4555
4556	/*
4557     * For SMB 1, if there was anything on f_openDenyList, then the file got
4558     * revoked and thus no need for reopen.
4559     *
4560     * For SMB 2/3, only uses this to reopen shared fid
4561     */
4562    /* POSIX Open: Reopen with the same modes we had it open with before the reconnect */
4563    error = smbfs_smb_open_file(share, np, np->f_rights,
4564                                NTCREATEX_SHARE_ACCESS_ALL,
4565                                &np->f_fid, NULL, 0, FALSE, &fattr,
4566                                context);
4567    if (error) {
4568        SMBERROR_LOCK(np, "Reopen %s failed because the open call failed!\n", np->n_name);
4569    }
4570
4571    /* If an error or no lock then we are done, nothing else to do */
4572    if (error || (np->f_smbflock == NULL)) {
4573        goto exit;
4574    }
4575
4576    if ((!(timespeccmp(&n_mtime, &fattr.fa_mtime, ==))) ||
4577        (n_size != fattr.fa_size)) {
4578        if (n_size != np->n_size) {
4579            SMBERROR_LOCK(np, "Reopen %s failed because the size has changed was 0x%lld now 0x%lld!\n",
4580                          np->n_name, n_size, fattr.fa_size);
4581        }
4582        else {
4583            SMBERROR_LOCK(np, "Reopen %s failed because the modify time has changed was %lds %ldns now %lds %ldns!\n",
4584                          np->n_name, n_mtime.tv_sec, n_mtime.tv_nsec,
4585                          fattr.fa_mtime.tv_sec, fattr.fa_mtime.tv_nsec);
4586        }
4587        error = EIO;
4588    }
4589    else {
4590        struct smbfs_flock *flk = np->f_smbflock;
4591        error = smbfs_smb_lock(share, SMB_LOCK_EXCL, np->f_fid,
4592                               flk->lck_pid, flk->start, flk->len,
4593                               0, context);
4594        if (error) {
4595            SMBERROR_LOCK(np, "Reopen %s failed because we could not reestablish the lock! \n", np->n_name);
4596        }
4597    }
4598
4599    /* Something is different or we failed on the lock request, close it */
4600    if (error) {
4601        (void)smbfs_smb_close(share, np->f_fid, context);
4602    }
4603
4604exit:
4605    lck_mtx_lock(&np->f_openStateLock);
4606    np->f_openState &= ~kInReopen;
4607
4608    /* Error or we reconnect after the open, not much we can do here */
4609    if (context && (error || (np->f_openState & kNeedReopen))) {
4610        char errbuf[32];
4611        int pid = proc_pid(vfs_context_proc(context));
4612
4613        proc_name(pid, &errbuf[0], 32);
4614
4615        SMBERROR_LOCK(np, "Warning: pid %d(%.*s) reopening of %s failed with error %d\n",
4616                      pid, 32, &errbuf[0], np->n_name, error);
4617
4618        np->f_openState |= kNeedRevoke;
4619        error = EIO;
4620    }
4621    lck_mtx_unlock(&np->f_openStateLock);
4622
4623    return(error);
4624}
4625
4626/*
4627 * The calling routine must hold a reference on the share
4628 */
4629int
4630smb1fs_smb_close(struct smb_share *share, SMBFID fid, vfs_context_t context)
4631{
4632	struct smb_rq rq, *rqp = &rq;
4633	struct mbchain *mbp;
4634	uint32_t time;
4635	int error;
4636    uint16_t smb1_fid = (uint16_t) fid;
4637
4638	DBG_ASSERT(smb1_fid);
4639	error = smb_rq_init(rqp, SSTOCP(share), SMB_COM_CLOSE, 0, context);
4640	if (error)
4641		return error;
4642	smb_rq_getrequest(rqp, &mbp);
4643	smb_rq_wstart(rqp);
4644	mb_put_mem(mbp, (caddr_t)&smb1_fid, sizeof(smb1_fid), MB_MSYSTEM);
4645	/*
4646	 * Never set the modify time on close. Just a really bad idea!
4647	 *
4648	 * Leach and SNIA docs say to send zero here.  X/Open says
4649	 * 0 and -1 both are leaving timestamp up to the server.
4650	 * Win9x treats zero as a real time-to-be-set!  We send -1,
4651	 * same as observed with smbclient.
4652	 */
4653	time = -1;
4654	mb_put_uint32le(mbp, time);
4655	smb_rq_wend(rqp);
4656	smb_rq_bstart(rqp);
4657	smb_rq_bend(rqp);
4658	error = smb_rq_simple(rqp);
4659	smb_rq_done(rqp);
4660	/*
4661	 * ENOTCONN isn't interesting - if the connection is closed,
4662	 * so are all our FIDs - and ENXIO is also not interesting,
4663	 * as it means a forced unmount was done.
4664	 *
4665	 * EBADF means the fid is no longer good. Reconnect will make this happen.
4666	 * Should we check to see if the open was broken on the reconnect or does it
4667	 * really matter?
4668	 *
4669	 * Don't clog up the system log with warnings about those failures
4670	 * on closes.
4671	 */
4672	if ((error == ENOTCONN) || (error == ENXIO) || (error == EBADF))
4673		error = 0;
4674	return error;
4675}
4676
4677/*
4678 * The calling routine must hold a reference on the share
4679 */
4680int
4681smbfs_smb_create(struct smb_share *share, struct smbnode *dnp,
4682                 const char *in_name, size_t in_nmlen, uint32_t rights,
4683                 SMBFID *fidp, uint32_t disp, int xattr, struct smbfattr *fap,
4684                 vfs_context_t context)
4685{
4686	const char *name = in_name;
4687	size_t nmlen = in_nmlen;
4688    SMBFID fid = 0;
4689	int error;
4690    uint32_t desired_access = rights;
4691    uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL;
4692    uint64_t create_flags = SMB2_CREATE_DO_CREATE | SMB2_CREATE_GET_MAX_ACCESS;
4693    uint32_t ntstatus = 0;
4694    char *file_namep = NULL, *stream_namep = NULL;
4695    size_t file_name_len = 0, stream_name_len = 0;
4696
4697    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
4698        /*
4699         * SMB 2/3 - do compound create/close, or create
4700         * If fidp == NULL, then it will do a create/close.
4701         */
4702        if (!xattr) {
4703            file_namep = (char *) in_name;
4704            file_name_len = in_nmlen;
4705        }
4706        else {
4707            /* name is actually the stream name */
4708            create_flags |= SMB2_CREATE_IS_NAMED_STREAM;
4709
4710            stream_namep = (char *) in_name;
4711            stream_name_len = in_nmlen;
4712        }
4713
4714        error = smb2fs_smb_cmpd_create(share, dnp,
4715                                       file_namep, file_name_len,
4716                                       stream_namep, stream_name_len,
4717                                       desired_access, VREG,
4718                                       share_access, disp,
4719                                       create_flags, &ntstatus,
4720                                       fidp, fap,
4721                                       NULL, context);
4722    }
4723    else {
4724        /* SMB 1 */
4725        error = smbfs_smb_ntcreatex(share, dnp,
4726                                    desired_access, share_access, VREG,
4727                                    &fid, name, nmlen,
4728                                    disp, xattr, fap,
4729                                    TRUE, NULL, context);
4730        if (fidp) {
4731            /* Caller wants the FID, return it to them */
4732            *fidp = fid;
4733        }
4734        else {
4735            if (!error) {
4736                /* Caller doesn't want the FID, close it if we have it opened */
4737                (void)smbfs_smb_close(share, fid, context);
4738            }
4739        }
4740    }
4741
4742	return error;
4743}
4744
4745/*
4746 * This is the only way to remove symlinks with a samba server.
4747 *
4748 * The calling routine must hold a reference on the share
4749 *
4750 */
4751static int
4752smbfs_posix_unlink(struct smb_share *share, struct smbnode *np,
4753				   vfs_context_t context, const char *name, size_t nmlen)
4754{
4755	struct smb_t2rq *t2p;
4756	struct mbchain *mbp;
4757	int error;
4758	uint32_t isDir = (vnode_isdir(np->n_vnode)) ? 1 : 0;
4759
4760	error = smb_t2_alloc(SSTOCP(share), SMB_TRANS2_SET_PATH_INFORMATION, 1, context, &t2p);
4761	if (error)
4762		return error;
4763	mbp = &t2p->t2_tparam;
4764	mb_init(mbp);
4765	mb_put_uint16le(mbp, SMB_SFILEINFO_POSIX_UNLINK);
4766	mb_put_uint32le(mbp, 0);
4767	error = smbfs_fullpath(mbp, np, name, &nmlen, UTF_SFM_CONVERSIONS,
4768						   SMB_UNICODE_STRINGS(SSTOVC(share)), '\\');
4769	if (error) {
4770		smb_t2_done(t2p);
4771		return error;
4772	}
4773
4774	mbp = &t2p->t2_tdata;
4775	mb_init(mbp);
4776	mb_put_uint32le(mbp, isDir);
4777
4778	t2p->t2_maxpcount = 2;
4779	t2p->t2_maxdcount = SSTOVC(share)->vc_txmax;
4780	error = smb_t2_request(t2p);
4781	smb_t2_done(t2p);
4782	return error;
4783}
4784
4785/*
4786 * The calling routine must hold a reference on the share
4787 */
4788int
4789smb1fs_smb_delete(struct smb_share *share, struct smbnode *np, const char *name,
4790                  size_t nmlen, int xattr, vfs_context_t context)
4791{
4792	struct smb_rq rq, *rqp = &rq;
4793	struct mbchain *mbp;
4794	int error;
4795
4796	/* Not doing extended attribute and they support the posix unlink call */
4797	if (!xattr && (UNIX_CAPS(share) & UNIX_SFILEINFO_POSIX_UNLINK_CAP)) {
4798		error = smbfs_posix_unlink(share, np, context, name, nmlen);
4799		/*
4800		 * If the file doesn't have write posix modes then Samba returns
4801		 * STATUS_CANNOT_DELETE, which we convert to EPERM. This seems
4802		 * wrong we are expecting posix symantics from the call. So for now
4803		 * try to change the mode and attempt the delete again.
4804		 */
4805		if (error == EPERM) {
4806			int chmod_error;
4807			uint64_t vamode = np->n_mode | S_IWUSR;
4808
4809			/* See if we can chmod on the file */
4810			chmod_error = smbfs_set_unix_info2(share, np, NULL, NULL, NULL, SMB_SIZE_NO_CHANGE,
4811										 vamode, SMB_FLAGS_NO_CHANGE, SMB_FLAGS_NO_CHANGE, context);
4812			if (chmod_error == 0) {
4813				error = smbfs_posix_unlink(share, np, context, name, nmlen);
4814			}
4815		}
4816		if (error != ENOTSUP) {
4817			return error;
4818		} else {
4819			/* They don't really support this call, don't call them again */
4820			UNIX_CAPS(share) &= ~UNIX_SFILEINFO_POSIX_UNLINK_CAP;
4821		}
4822	}
4823
4824	error = smb_rq_init(rqp, SSTOCP(share), SMB_COM_DELETE, 0, context);
4825	if (error)
4826		return error;
4827	smb_rq_getrequest(rqp, &mbp);
4828	smb_rq_wstart(rqp);
4829	mb_put_uint16le(mbp, SMB_EFA_SYSTEM | SMB_EFA_HIDDEN);
4830	smb_rq_wend(rqp);
4831	smb_rq_bstart(rqp);
4832	mb_put_uint8(mbp, SMB_DT_ASCII);
4833	error = smbfs_fullpath(mbp, np, name, &nmlen, UTF_SFM_CONVERSIONS,
4834						   SMB_UNICODE_STRINGS(SSTOVC(share)), xattr ? ':' : '\\');
4835	if (!error) {
4836		smb_rq_bend(rqp);
4837		error = smb_rq_simple(rqp);
4838	}
4839	/*
4840	 * We could have sent the delete before the connection went down, but we lost the
4841	 * response. We resent the delete, but since it already succeeded we got an ENOENT
4842	 * error. We are deleting something that does not exist, since it happen during
4843	 * a reconnect take a guess that we succeeded.
4844	 */
4845	if ((error == ENOENT) && (rqp->sr_flags & SMBR_REXMIT))
4846		error = 0;
4847	smb_rq_done(rqp);
4848	return error;
4849}
4850
4851/*
4852 * The calling routine must hold a reference on the share
4853 */
4854int
4855smb1fs_smb_rename(struct smb_share *share, struct smbnode *src,
4856                  struct smbnode *tdnp, const char *tname, size_t tnmlen,
4857                  vfs_context_t context)
4858{
4859	struct smb_rq rq, *rqp = &rq;
4860	struct mbchain *mbp;
4861	int error, retest = 0;
4862
4863	error = smb_rq_init(rqp, SSTOCP(share), SMB_COM_RENAME, 0, context);
4864	if (error)
4865		return error;
4866	smb_rq_getrequest(rqp, &mbp);
4867	smb_rq_wstart(rqp);
4868	/* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
4869	mb_put_uint16le(mbp, (vnode_isdir(SMBTOV(src)) ? SMB_EFA_DIRECTORY : 0) |
4870			     SMB_EFA_SYSTEM | SMB_EFA_HIDDEN);
4871	smb_rq_wend(rqp);
4872	smb_rq_bstart(rqp);
4873	mb_put_uint8(mbp, SMB_DT_ASCII);
4874	do {
4875		error = smbfs_fullpath(mbp, src, NULL, NULL, UTF_SFM_CONVERSIONS,
4876							   SMB_UNICODE_STRINGS(SSTOVC(share)), '\\');
4877		if (error)
4878			break;
4879		mb_put_uint8(mbp, SMB_DT_ASCII);
4880		error = smbfs_fullpath(mbp, tdnp, tname, &tnmlen, UTF_SFM_CONVERSIONS,
4881							   SMB_UNICODE_STRINGS(SSTOVC(share)), '\\');
4882		if (error)
4883			break;
4884		smb_rq_bend(rqp);
4885		error = smb_rq_simple(rqp);
4886	} while(0);
4887	if ((error == ENOENT) && (rqp->sr_flags & SMBR_REXMIT))
4888		retest = 1;
4889	smb_rq_done(rqp);
4890	/*
4891	 * We could have sent the rename before the connection went down, but we lost
4892	 * the response. We resent the rename message, but since it already succeeded
4893	 * we got an ENOENTerror. So lets test to see if the rename worked or not.
4894	 *
4895	 *	1. Check to make sure the source doesn't exist.
4896	 *	2. Check to make sure the dest does exist.
4897	 *
4898	 * If either fails then we leave the error alone, we could still be wrong here.
4899	 * Someone could have played with the file between the time we lost the
4900	 * connection and the time we do our test. Not trying to be prefect here just
4901	 * to the best we can.
4902	 */
4903	if (error && retest) {
4904		if ((smbfs_smb_query_info(share, src, VREG, NULL, 0, NULL, context) == ENOENT) &&
4905			(smbfs_smb_query_info(share, tdnp, VREG, tname, tnmlen, NULL, context) == 0))
4906			error = 0;
4907	}
4908	return error;
4909}
4910
4911/*
4912 * The calling routine must hold a reference on the share
4913 */
4914int
4915smbfs_smb_mkdir(struct smb_share *share, struct smbnode *dnp, const char *name,
4916				size_t len, struct smbfattr *fap, vfs_context_t context)
4917{
4918    SMBFID fid = 0;
4919	int error = 0;
4920    uint32_t desired_access = SMB2_FILE_READ_DATA;
4921    uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL;
4922    uint64_t create_flags = SMB2_CREATE_DO_CREATE | SMB2_CREATE_GET_MAX_ACCESS;
4923    uint32_t ntstatus = 0;
4924
4925	/*
4926	 * We ask for SMB2_FILE_READ_DATA not because we need it, but
4927	 * just to be asking for something.  The rights == 0 case could
4928	 * easily be broken on some old or unusual servers.
4929	 */
4930    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
4931        /* SMB 2 - do compound create/close */
4932        error = smb2fs_smb_cmpd_create(share, dnp,
4933                                       name, len,
4934                                       NULL, 0,
4935                                       desired_access, VDIR,
4936                                       share_access, FILE_CREATE,
4937                                       create_flags, &ntstatus,
4938                                       NULL, fap,
4939                                       NULL, context);
4940    }
4941    else {
4942        /* SMB 1 */
4943        error = smbfs_smb_ntcreatex(share, dnp,
4944                                    desired_access, share_access, VDIR,
4945                                    &fid, name, len,
4946                                    FILE_CREATE, 0, fap,
4947                                    TRUE, NULL, context);
4948        if (!error) {
4949            (void)smbfs_smb_close(share, fid, context);
4950        }
4951    }
4952
4953	return error;
4954}
4955
4956/*
4957 * The calling routine must hold a reference on the share
4958 */
4959int
4960smb1fs_smb_rmdir(struct smb_share *share, struct smbnode *np, vfs_context_t context)
4961{
4962	struct smb_rq rq, *rqp = &rq;
4963	struct mbchain *mbp;
4964	int error;
4965
4966	error = smb_rq_init(rqp, SSTOCP(share), SMB_COM_DELETE_DIRECTORY, 0, context);
4967	if (error)
4968		return error;
4969	smb_rq_getrequest(rqp, &mbp);
4970	smb_rq_wstart(rqp);
4971	smb_rq_wend(rqp);
4972	smb_rq_bstart(rqp);
4973	mb_put_uint8(mbp, SMB_DT_ASCII);
4974	error = smbfs_fullpath(mbp, np, NULL, NULL, UTF_SFM_CONVERSIONS,
4975						   SMB_UNICODE_STRINGS(SSTOVC(share)), '\\');
4976	if (!error) {
4977		smb_rq_bend(rqp);
4978		error = smb_rq_simple(rqp);
4979	}
4980	/*
4981	 * We could have sent the delete before the connection went down, but we lost the
4982	 * response. We resent the delete, but since it already succeeded we got an ENOENT
4983	 * error. We are deleting something that does not exist, since it happen during
4984	 * a reconnect take a guess that we succeeded.
4985	 */
4986	if ((error == ENOENT) && (rqp->sr_flags & SMBR_REXMIT))
4987		error = 0;
4988	smb_rq_done(rqp);
4989	return error;
4990}
4991
4992/*
4993 * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
4994 */
4995static int
4996smbfs_smb_trans2find2(struct smbfs_fctx *ctx, vfs_context_t context)
4997{
4998	struct smb_t2rq *t2p;
4999	struct mbchain *mbp;
5000	struct mdchain *mdp;
5001	uint16_t tw, flags;
5002	size_t len;
5003	int error;
5004
5005	if (ctx->f_t2) {
5006		smb_t2_done(ctx->f_t2);
5007		ctx->f_t2 = NULL;
5008	}
5009	ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
5010	flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
5011	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
5012		flags |= FIND2_CLOSE_AFTER_REQUEST;
5013		ctx->f_flags |= SMBFS_RDD_NOCLOSE;
5014	}
5015	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
5016		error = smb_t2_alloc(SSTOCP(ctx->f_share), SMB_TRANS2_FIND_FIRST2, 1, context, &t2p);
5017		if (error)
5018			return error;
5019		ctx->f_t2 = t2p;
5020		mbp = &t2p->t2_tparam;
5021		mb_init(mbp);
5022		mb_put_uint16le(mbp, ctx->f_attrmask);
5023		mb_put_uint16le(mbp, ctx->f_searchCount);
5024		mb_put_uint16le(mbp, flags);
5025		mb_put_uint16le(mbp, ctx->f_infolevel);
5026		mb_put_uint32le(mbp, 0);
5027		len = ctx->f_lookupNameLen;
5028		error = smbfs_fullpath(mbp, ctx->f_dnp, ctx->f_lookupName, &len,
5029							   ctx->f_sfm_conversion,
5030							   SMB_UNICODE_STRINGS(SSTOVC(ctx->f_share)), '\\');
5031		if (error)
5032			return error;
5033	} else	{
5034		error = smb_t2_alloc(SSTOCP(ctx->f_share), SMB_TRANS2_FIND_NEXT2, 1, context, &t2p);
5035		if (error)
5036			return error;
5037		ctx->f_t2 = t2p;
5038		mbp = &t2p->t2_tparam;
5039		mb_init(mbp);
5040		mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
5041		mb_put_uint16le(mbp, ctx->f_searchCount);
5042		mb_put_uint16le(mbp, ctx->f_infolevel);
5043		/* If they give us a resume key return it */
5044		mb_put_uint32le(mbp, ctx->f_rkey);
5045		mb_put_uint16le(mbp, flags);
5046		if (ctx->f_rname) {
5047			/* resume file name */
5048			mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen, MB_MSYSTEM);
5049		}
5050		/* Add trailing null - 1 byte if ASCII, 2 if Unicode */
5051		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_share)))
5052			mb_put_uint8(mbp, 0);	/* 1st byte of NULL Unicode char */
5053		mb_put_uint8(mbp, 0);
5054	}
5055	t2p->t2_maxpcount = 5 * 2;
5056	t2p->t2_maxdcount = SSTOVC(ctx->f_share)->vc_txmax;
5057	error = smb_t2_request(t2p);
5058	if (error) {
5059		/*
5060		 * We told them to close search when end of search is reached. So if we
5061		 * get an ENOENT, no reason to send a close. From testing this
5062		 * is correct. Not sure about other errors, so for now only do it on
5063		 * ENOENT.
5064		 */
5065		if (error == ENOENT) {
5066			ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
5067		}
5068		return error;
5069	}
5070	mdp = &t2p->t2_rparam;
5071	/*
5072	 * At this point md_cur and md_top have the same value. Now all the md_get
5073	 * routines will will check for null, but just to be safe we check here
5074	 */
5075	if (mdp->md_cur == NULL) {
5076		SMBWARNING("Parsing error reading the message\n");
5077		return EBADRPC;
5078	}
5079	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
5080		if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
5081			return error;
5082		/* Turn on the SFM Conversion flag. Next call is a FindNext */
5083		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
5084		ctx->f_sfm_conversion = UTF_SFM_CONVERSIONS;
5085	}
5086	if ((error = md_get_uint16le(mdp, &tw)) != 0)
5087		return error;
5088	ctx->f_ecnt = tw; /* search count - # entries returned */
5089	if ((error = md_get_uint16le(mdp, &tw)) != 0)
5090		return error;
5091	/*
5092	 * tw now is the "end of search" flag. against an XP server tw
5093	 * comes back zero when the prior find_next returned exactly
5094	 * the number of entries requested.  in which case we'd try again
5095	 * but the search has in fact been closed so an EBADF results.  our
5096	 * circumvention is to check here for a zero search count.
5097	 */
5098	if (tw || ctx->f_ecnt == 0)
5099		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
5100	if ((error = md_get_uint16le(mdp, &tw)) != 0)
5101		return error;
5102	if ((error = md_get_uint16le(mdp, &tw)) != 0)
5103		return error;
5104	if (ctx->f_ecnt == 0)
5105		return ENOENT;
5106	ctx->f_rnameofs = tw;
5107	mdp = &t2p->t2_rdata;
5108	if (mdp->md_top == NULL) {
5109		SMBERROR("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt);
5110		/*
5111		 * Something bad has happened we did not get all the data. We
5112		 * need to close the directory listing, otherwise we may cause
5113		 * the calling process to hang in an infinite loop.
5114		 */
5115		ctx->f_ecnt = 0; /* Force the directory listing to close. */
5116		ctx->f_flags |= SMBFS_RDD_EOF;
5117		return ENOENT;
5118	}
5119	/*
5120	 * Changed the code to check to see if there is any data on the whole
5121	 * mbuf chain, not just the first mbuf. Remember in a mbuf chain there
5122	 * can be mbufs with nothing in them. Need to make sure we have data in
5123	 * the mbuf chain, if not we received a bad message.
5124	 */
5125     m_fixhdr(mdp->md_top);
5126	 if (mbuf_pkthdr_len(mdp->md_top) == 0) {
5127		SMBERROR("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n",
5128				 ctx->f_ecnt, mbuf_next(mbp->mb_top));
5129		/*
5130		 * Something bad has happened we did not get all the data. We
5131		 * need to close the directory listing, otherwise we may cause
5132		 * the calling process to hang in an infinite loop.
5133		 */
5134		ctx->f_ecnt = 0; /* Force the directory listing to close. */
5135		ctx->f_flags |= SMBFS_RDD_EOF;
5136		return ENOENT;
5137	}
5138	ctx->f_eofs = 0;
5139	return 0;
5140}
5141
5142static int
5143smbfs_ntwrk_findclose(struct smbfs_fctx *ctx, vfs_context_t context)
5144{
5145	struct smb_rq rq, *rqp = &rq;
5146	struct mbchain *mbp;
5147	int error;
5148
5149	error = smb_rq_init(rqp, SSTOCP(ctx->f_share), SMB_COM_FIND_CLOSE2, 0, context);
5150	if (error)
5151		return error;
5152	smb_rq_getrequest(rqp, &mbp);
5153	smb_rq_wstart(rqp);
5154	mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
5155	smb_rq_wend(rqp);
5156	smb_rq_bstart(rqp);
5157	smb_rq_bend(rqp);
5158	error = smb_rq_simple(rqp);
5159	smb_rq_done(rqp);
5160	return error;
5161}
5162
5163int
5164smb1fs_smb_findclose(struct smbfs_fctx *ctx, vfs_context_t context)
5165{
5166	if (ctx->f_t2)
5167		smb_t2_done(ctx->f_t2);
5168	if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
5169		smbfs_ntwrk_findclose(ctx, context);
5170	/* We are done with the share release our reference */
5171    smb_share_rele(ctx->f_share, context);
5172
5173    if (ctx->f_LocalName) {
5174        SMB_FREE(ctx->f_LocalName, M_SMBFSDATA);
5175    }
5176
5177    if (ctx->f_NetworkNameBuffer) {
5178        SMB_FREE(ctx->f_NetworkNameBuffer, M_SMBFSDATA);
5179    }
5180
5181    if (ctx->f_rname) {
5182        SMB_FREE(ctx->f_rname, M_SMBFSDATA);
5183    }
5184
5185    SMB_FREE(ctx, M_SMBFSDATA);
5186	return 0;
5187}
5188
5189int
5190smb1fs_smb_findnext(struct smbfs_fctx *ctx, vfs_context_t context)
5191{
5192	struct mdchain *mdp;
5193	struct smb_t2rq *t2p;
5194	uint32_t next, dattr, resumekey = 0;
5195	uint64_t llint;
5196	int error, cnt;
5197	uint32_t fxsz, recsz;
5198	struct timespec ts;
5199	uint32_t eaSize;
5200
5201	if (ctx->f_ecnt == 0) {
5202		if (ctx->f_flags & SMBFS_RDD_EOF)
5203			return ENOENT;
5204		nanouptime(&ts);
5205		error = smbfs_smb_trans2find2(ctx, context);
5206		if (error)
5207			return error;
5208		ctx->f_attr.fa_reqtime = ts;
5209	}
5210	t2p = ctx->f_t2;
5211	mdp = &t2p->t2_rdata;
5212
5213	ctx->f_NetworkNameLen = 0;
5214
5215    /* Set default uid/gid values */
5216    ctx->f_attr.fa_uid = KAUTH_UID_NONE;
5217    ctx->f_attr.fa_gid = KAUTH_GID_NONE;
5218
5219	switch (ctx->f_infolevel) {
5220	case SMB_FIND_BOTH_DIRECTORY_INFO:
5221		md_get_uint32le(mdp, &next);
5222		md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
5223		md_get_uint64le(mdp, &llint);	/* creation time */
5224		if (llint) {
5225			smb_time_NT2local(llint, &ctx->f_attr.fa_crtime);
5226		}
5227		md_get_uint64le(mdp, &llint);
5228		if (llint) {
5229			smb_time_NT2local(llint, &ctx->f_attr.fa_atime);
5230		}
5231		md_get_uint64le(mdp, &llint);
5232		if (llint) {
5233			smb_time_NT2local(llint, &ctx->f_attr.fa_mtime);
5234		}
5235		md_get_uint64le(mdp, &llint);
5236		if (llint) {
5237			smb_time_NT2local(llint, &ctx->f_attr.fa_chtime);
5238		}
5239		md_get_uint64le(mdp, &llint);	/* data size */
5240		ctx->f_attr.fa_size = llint;
5241		md_get_uint64le(mdp, &llint);	/* data allocation size */
5242		ctx->f_attr.fa_data_alloc = llint;
5243		/* freebsd bug: fa_attr endian bug */
5244		md_get_uint32le(mdp, &dattr);	/* extended file attributes */
5245		ctx->f_attr.fa_attr = dattr;
5246		/*
5247		 * Because of the Steve/Conrad Symlinks we can never be completely
5248		 * sure that we have the correct vnode type if its a file. Since we
5249		 * don't support Steve/Conrad Symlinks with Darwin we can always count
5250		 * on the vtype being correct. For directories we always know the
5251		 * correct information.
5252		 */
5253		if ((SSTOVC(ctx->f_share)->vc_flags & SMBV_DARWIN) ||
5254			(ctx->f_attr.fa_attr & SMB_EFA_DIRECTORY)) {
5255			ctx->f_attr.fa_valid_mask |= FA_VTYPE_VALID;
5256		}
5257		ctx->f_attr.fa_vtype = (ctx->f_attr.fa_attr & SMB_EFA_DIRECTORY) ? VDIR : VREG;
5258		md_get_uint32le(mdp, &ctx->f_NetworkNameLen);
5259		fxsz = 64; /* size of info up to filename */
5260		/*
5261		 * Confirmed from MS:
5262		 * When the attribute has the Reparse Point bit set then the EASize
5263		 * contains the reparse tag info. This behavior is consistent for
5264		 * Full, Both, FullId, or BothId query dir calls.  It will pack the
5265		 * reparse tag into the EaSize value if ATTRIBUTE_REPARSE_POINT is set.
5266		 * I verified with local MS Engineers, and they also checking to make
5267		 * sure the behavior is covered in MS-FSA.
5268		 *
5269		 * EAs and reparse points cannot both be in a file at the same
5270		 * time. We return different information for each case.
5271		 */
5272		ctx->f_attr.fa_valid_mask |= FA_REPARSE_TAG_VALID;
5273		md_get_uint32le(mdp, &eaSize);	/* extended attributes size */
5274		if (ctx->f_attr.fa_attr & SMB_EFA_REPARSE_POINT) {
5275			ctx->f_attr.fa_reparse_tag = eaSize;
5276			if (ctx->f_attr.fa_reparse_tag == IO_REPARSE_TAG_SYMLINK) {
5277				ctx->f_attr.fa_valid_mask |= FA_VTYPE_VALID;
5278				ctx->f_attr.fa_vtype = VLNK;
5279			}
5280		} else {
5281			ctx->f_attr.fa_reparse_tag = IO_REPARSE_TAG_RESERVED_ZERO;
5282		}
5283		md_get_uint8(mdp, NULL);		/* Skip short name Length */
5284		md_get_uint8(mdp, NULL);		/* Skip reserved byte */
5285		/* Skip 8.3 short name, defined to be 12 WCHAR or 24 bytes. */
5286		md_get_mem(mdp, NULL, 24, MB_MSYSTEM);
5287		fxsz += 30;
5288		recsz = next ? next : fxsz + ctx->f_NetworkNameLen;
5289		break;
5290	case SMB_FIND_FILE_UNIX_INFO2:
5291		md_get_uint32le(mdp, &next);
5292		md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
5293
5294
5295		md_get_uint64le(mdp, &llint);	/* file size */
5296		ctx->f_attr.fa_size = llint;
5297
5298		md_get_uint64le(mdp, &llint); /* allocation size */
5299		ctx->f_attr.fa_data_alloc = llint;
5300
5301		md_get_uint64le(mdp, &llint);	/* change time */
5302		if (llint)
5303			smb_time_NT2local(llint, &ctx->f_attr.fa_chtime);
5304
5305		md_get_uint64le(mdp, &llint);	/* access time */
5306		if (llint)
5307			smb_time_NT2local(llint, &ctx->f_attr.fa_atime);
5308
5309		md_get_uint64le(mdp, &llint);	/* write time */
5310		if (llint)
5311			smb_time_NT2local(llint, &ctx->f_attr.fa_mtime);
5312
5313		md_get_uint64le(mdp, &llint);	/* Numeric user id for the owner */
5314		ctx->f_attr.fa_uid = llint;
5315
5316		md_get_uint64le(mdp, &llint);	/* Numeric group id for the owner */
5317		ctx->f_attr.fa_gid = llint;
5318
5319		md_get_uint32le(mdp, &dattr);	/* Enumeration specifying the file type, st_mode */
5320		/* Make sure the dos attributes are correct */
5321		if (dattr & EXT_UNIX_DIR) {
5322			ctx->f_attr.fa_attr |= SMB_EFA_DIRECTORY;
5323			ctx->f_attr.fa_vtype = VDIR;
5324		} else {
5325			ctx->f_attr.fa_attr &= ~SMB_EFA_DIRECTORY;
5326			if (dattr & EXT_UNIX_SYMLINK)
5327				ctx->f_attr.fa_vtype = VLNK;
5328			else	/* Do we ever what to handle the others? */
5329				ctx->f_attr.fa_vtype = VREG;
5330		}
5331
5332		md_get_uint64le(mdp, &llint);	/* Major device number if type is device */
5333		md_get_uint64le(mdp, &llint);	/* Minor device number if type is device */
5334		md_get_uint64le(mdp, &llint);	/* This is a server-assigned unique id */
5335		md_get_uint64le(mdp, &llint);	/* Standard UNIX permissions */
5336		ctx->f_attr.fa_permissions = llint;
5337		ctx->f_attr.fa_valid_mask |= FA_UNIX_MODES_VALID;
5338		md_get_uint64le(mdp, &llint);	/* Number of hard link */
5339		ctx->f_attr.fa_nlinks = llint;
5340
5341		md_get_uint64le(mdp, &llint);	/* creation time */
5342		if (llint)
5343			smb_time_NT2local(llint, &ctx->f_attr.fa_crtime);
5344
5345		md_get_uint32le(mdp, &dattr);	/* File flags enumeration */
5346		md_get_uint32le(mdp, &ctx->f_attr.fa_flags_mask);	/* Mask of valid flags */
5347		if (ctx->f_attr.fa_flags_mask & EXT_HIDDEN) {
5348			if (dattr & EXT_HIDDEN)
5349				ctx->f_attr.fa_attr |= SMB_EFA_HIDDEN;
5350			else
5351				ctx->f_attr.fa_attr &= ~SMB_EFA_HIDDEN;
5352		}
5353		if (ctx->f_attr.fa_flags_mask & EXT_IMMUTABLE) {
5354			if (dattr & EXT_IMMUTABLE)
5355				ctx->f_attr.fa_attr |= SMB_EFA_RDONLY;
5356			else
5357				ctx->f_attr.fa_attr &= ~SMB_EFA_RDONLY;
5358		}
5359		if (ctx->f_attr.fa_flags_mask & EXT_DO_NOT_BACKUP) {
5360			if (dattr & EXT_DO_NOT_BACKUP)
5361				ctx->f_attr.fa_attr &= ~SMB_EFA_ARCHIVE;
5362			else
5363				ctx->f_attr.fa_attr |= SMB_EFA_ARCHIVE;
5364		}
5365
5366		ctx->f_attr.fa_unix = TRUE;
5367
5368		md_get_uint32le(mdp, &ctx->f_NetworkNameLen);
5369		fxsz = 128; /* size ofinfo up to filename */
5370		recsz = next ? next : fxsz + ctx->f_NetworkNameLen;
5371		break;
5372	default:
5373		SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
5374		return EINVAL;
5375	}
5376	if ((size_t)ctx->f_NetworkNameLen > ctx->f_MaxNetworkNameBufferSize)
5377		ctx->f_NetworkNameLen = (uint32_t)ctx->f_MaxNetworkNameBufferSize;
5378	error = md_get_mem(mdp, ctx->f_NetworkNameBuffer, ctx->f_NetworkNameLen, MB_MSYSTEM);
5379	if (error)
5380		return error;
5381	if (next) {
5382		cnt = next - ctx->f_NetworkNameLen - fxsz;
5383		if (cnt > 0)
5384			md_get_mem(mdp, NULL, cnt, MB_MSYSTEM);
5385		else if (cnt < 0) {
5386			SMBERROR("out of sync\n");
5387			return EBADRPC;
5388		}
5389	}
5390	/* Don't count any trailing null in the name. */
5391	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_share))) {
5392		if ((ctx->f_NetworkNameLen > 1) && (ctx->f_NetworkNameBuffer[ctx->f_NetworkNameLen - 1] == 0) &&
5393			(ctx->f_NetworkNameBuffer[ctx->f_NetworkNameLen - 2] == 0))
5394			ctx->f_NetworkNameLen -= 2;
5395	} else {
5396		if (ctx->f_NetworkNameLen && ctx->f_NetworkNameBuffer[ctx->f_NetworkNameLen - 1] == 0)
5397			ctx->f_NetworkNameLen--;
5398	}
5399	if (ctx->f_NetworkNameLen == 0)
5400		return EBADRPC;
5401
5402	/*
5403	 * Ref radar 3983209.  On a find-next we expect a server will
5404	 * 1) if the continue bit is set, use the server's idea of current loc,
5405	 * 2) else if the resume key is non-zero, use that location,
5406	 * 3) else if the resume name is set, use that location,
5407	 * 4) else use the server's idea of current location.
5408	 *
5409	 * There was some crazy code here to work around a NetApp bug, but it
5410	 * was wrong. We always set the resume key flag. If the server returns a
5411	 * resume key then we should send it back to them. This would have solve
5412	 * the NetApp bug.
5413	 */
5414	ctx->f_rkey = resumekey;
5415
5416	next = ctx->f_eofs + recsz;
5417	if (ctx->f_rnameofs && ((ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0) &&
5418	    ((ctx->f_rnameofs >= ctx->f_eofs) && (ctx->f_rnameofs < next))) {
5419		/* Server needs a resume filename. */
5420		if (ctx->f_rnamelen < ctx->f_NetworkNameLen) {
5421            if (ctx->f_rname) {
5422                SMB_FREE(ctx->f_rname, M_SMBFSDATA);
5423            }
5424			SMB_MALLOC(ctx->f_rname, char *, ctx->f_NetworkNameLen, M_SMBFSDATA, M_WAITOK);
5425		}
5426		ctx->f_rnamelen = ctx->f_NetworkNameLen;
5427		bcopy(ctx->f_NetworkNameBuffer, ctx->f_rname, ctx->f_NetworkNameLen);
5428		ctx->f_flags |= SMBFS_RDD_GOTRNAME;
5429	}
5430	ctx->f_eofs = next;
5431	ctx->f_ecnt--;
5432	return 0;
5433}
5434
5435/*
5436 * The calling routine must hold a reference on the share
5437 */
5438int
5439smbfs_smb_findopen(struct smb_share *share, struct smbnode *dnp,
5440                   const char *lookupName, size_t lookupNameLen,
5441                   struct smbfs_fctx **ctxpp, int wildCardLookup,
5442                   vfs_context_t context)
5443{
5444	struct smbfs_fctx *ctx;
5445	int error = 0;
5446
5447    SMB_MALLOC(ctx, struct smbfs_fctx *, sizeof(*ctx), M_SMBFSDATA,
5448               M_WAITOK | M_ZERO);
5449	if (ctx == NULL) {
5450		return ENOMEM;
5451    }
5452
5453	/* We need to hold a reference on the share for the life of the directory listing. */
5454	ctx->f_share = share;
5455	smb_share_ref(ctx->f_share);
5456	ctx->f_dnp = dnp;
5457	ctx->f_flags |= SMBFS_RDD_FINDFIRST;
5458	/*
5459	 * If this is a wildcard lookup then make sure we are not setting the
5460	 * UTF_SFM_CONVERSIONS flag. We are either doing a lookup by name or we are
5461	 * doing a wildcard lookup using the asterisk. When doing a wildcard lookup
5462	 * the asterisk is legit, so we don't have to convert it. Now once we send
5463	 * the FindFirst we need to turn the UTF_SFM_CONVERSIONS flag back on, this
5464	 * is done in smbfs_smb_trans2find2. Also by definition non wildcard lookups
5465	 * need to be single lookups, so if we are not doing a wildcard lookup then
5466	 * set the SMBFS_RDD_FINDSINGLE flag.
5467	 */
5468	if (!wildCardLookup) {
5469		ctx->f_sfm_conversion = UTF_SFM_CONVERSIONS;
5470		ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
5471		ctx->f_searchCount = 1;
5472	}
5473
5474	if (UNIX_CAPS(share) & UNIX_FIND_FILE_UNIX_INFO2_CAP) {
5475		/*
5476		 * Search count is the clients request for the max number of items to
5477		 * be return. We could always request some large number, but lets just
5478		 * request the max number of entries that will fit in a buffer.
5479		 *
5480		 * NOTE: We always make sure vc_txmax is 1k or larger.
5481		 */
5482		if (wildCardLookup) {
5483			ctx->f_searchCount = SSTOVC(share)->vc_txmax / SMB_FIND_FILE_UNIX_INFO2_MIN_LEN;
5484		}
5485		ctx->f_infolevel = SMB_FIND_FILE_UNIX_INFO2;
5486	} else {
5487		/*
5488		 * Search count is the clients request for the max number of items to
5489		 * be return. We could always request some large number, but lets just
5490		 * request the max number of entries that will fit in a buffer.
5491		 *
5492		 * NOTE: We always make sure vc_txmax is 1k or larger.
5493		 */
5494		if (wildCardLookup) {
5495			ctx->f_searchCount = SSTOVC(share)->vc_txmax / SMB_FIND_BOTH_DIRECTORY_INFO_MIN_LEN;
5496		}
5497
5498        if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
5499            /* Short Name info may contain special info if its a Mac OS Server */
5500            ctx->f_infolevel = SMB_FIND_BOTH_DIRECTORY_INFO;
5501        }
5502        else {
5503            ctx->f_infolevel = SMB_FIND_BOTH_DIRECTORY_INFO;
5504        }
5505	}
5506	/* We always default to using the same attribute mask */
5507	ctx->f_attrmask = SMB_EFA_SYSTEM | SMB_EFA_HIDDEN | SMB_EFA_DIRECTORY;
5508	ctx->f_lookupName = lookupName;
5509	ctx->f_lookupNameLen = lookupNameLen;
5510	/*
5511	 * Unicode requires 4 * max file name len, codepage requires 3 * max file
5512	 * name, so lets just always use the unicode size.
5513	 */
5514	ctx->f_MaxNetworkNameBufferSize = share->ss_maxfilenamelen * 4;
5515	SMB_MALLOC(ctx->f_NetworkNameBuffer, char *, ctx->f_MaxNetworkNameBufferSize, M_TEMP, M_WAITOK);
5516	if (ctx->f_NetworkNameBuffer == NULL) {
5517        SMBERROR("f_NetworkNameBuffer failed\n");
5518		error = ENOMEM;
5519    }
5520
5521	if (error) {
5522		smbfs_smb_findclose(ctx, context);
5523    }
5524	else {
5525		*ctxpp = ctx;
5526    }
5527
5528	return error;
5529}
5530
5531int
5532smbfs_findnext(struct smbfs_fctx *ctx, vfs_context_t context)
5533{
5534	int error;
5535	struct timespec save_reqtime;
5536
5537	for (;;) {
5538        /* save time that enumerate was done at */
5539        save_reqtime = ctx->f_attr.fa_reqtime;
5540        bzero(&ctx->f_attr, sizeof(ctx->f_attr));
5541        ctx->f_attr.fa_reqtime = save_reqtime;
5542
5543		error = smbfs_smb_findnext(ctx, context);
5544        if (error == EAGAIN) {
5545            /*
5546             * Try one more time, server may have a tempsmbfs_smb_qpathinfo
5547             * resource issue
5548             */
5549            /* save time that enumerate was done at */
5550            save_reqtime = ctx->f_attr.fa_reqtime;
5551            bzero(&ctx->f_attr, sizeof(ctx->f_attr));
5552            ctx->f_attr.fa_reqtime = save_reqtime;
5553
5554            error = smbfs_smb_findnext(ctx, context);
5555        }
5556		if (error) {
5557			return error;
5558        }
5559
5560		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_share))) {
5561            /* ignore the Unicode '.' and '..' dirs */
5562			if ((ctx->f_NetworkNameLen == 2 &&
5563			     letohs(*(uint16_t *)ctx->f_NetworkNameBuffer) == 0x002e) ||
5564			    (ctx->f_NetworkNameLen == 4 &&
5565			     letohl(*(uint32_t *)ctx->f_NetworkNameBuffer) == 0x002e002e))
5566				continue;
5567		}
5568        else {
5569            /* ignore the '.' and '..' dirs */
5570			if ((ctx->f_NetworkNameLen == 1 && ctx->f_NetworkNameBuffer[0] == '.') ||
5571			    (ctx->f_NetworkNameLen == 2 && ctx->f_NetworkNameBuffer[0] == '.' &&
5572			     ctx->f_NetworkNameBuffer[1] == '.'))
5573				continue;
5574		}
5575		break;
5576	}
5577
5578    /*
5579     * Successfully parsed out one entry from the search buffer
5580     * so return that one entry.
5581     */
5582    if (ctx->f_LocalName) {
5583        SMB_FREE(ctx->f_LocalName, M_TEMP);	/* Free any old name we may have */
5584    }
5585	ctx->f_LocalNameLen = ctx->f_NetworkNameLen;
5586	ctx->f_LocalName = smbfs_ntwrkname_tolocal(ctx->f_NetworkNameBuffer,
5587                                               &ctx->f_LocalNameLen,
5588                                               SMB_UNICODE_STRINGS(SSTOVC(ctx->f_share)));
5589
5590    if (!(SSTOVC(ctx->f_share)->vc_misc_flags & SMBV_HAS_FILEIDS)) {
5591        /* Server does not support File IDs */
5592        ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp,
5593                                          ctx->f_LocalName,
5594                                          ctx->f_LocalNameLen);
5595    }
5596
5597	return 0;
5598}
5599
5600/*
5601 * The calling routine must hold a reference on the share
5602 */
5603int
5604smbfs_lookup(struct smb_share *share, struct smbnode *dnp, const char **namep,
5605				 size_t *nmlenp, struct smbfattr *fap, vfs_context_t context)
5606{
5607	struct smbfs_fctx *ctx;
5608	int error = EINVAL;
5609	const char *name = (namep ? *namep : NULL);
5610	size_t nmlen = (nmlenp ? *nmlenp : 0);
5611	struct smbmount *smp;
5612    struct smb_vc *vcp = SSTOVC(share);
5613    enum vtype vnode_type = VREG;
5614
5615	DBG_ASSERT(dnp);
5616
5617    SMB_LOG_KTRACE(SMB_DBG_SMBFS_LOOKUP | DBG_FUNC_START, 0, 0, 0, 0, 0);
5618
5619	/* This should no longer happen, but just in case (should remove someday). */
5620	if (dnp == NULL) {
5621		SMBERROR("The parent node is NULL, shouldn't happen\n");
5622		error = EINVAL;
5623        goto done;
5624	}
5625
5626    smp = dnp->n_mount;
5627	if ((dnp->n_ino == smp->sm_root_ino) && (name == NULL)) {
5628		uint64_t DIFF1980TO1601 = 11960035200ULL*10000000ULL;
5629
5630		bzero(fap, sizeof(*fap));
5631
5632		/* We keep track of the time the lookup call was requested */
5633		nanouptime(&fap->fa_reqtime);
5634
5635		fap->fa_attr = SMB_EFA_DIRECTORY;
5636		fap->fa_vtype = VDIR;
5637        fap->fa_valid_mask |= FA_VTYPE_VALID;
5638
5639        if (smp->sm_root_ino == 0) {
5640            /*
5641             * Must be at mount time and we dont know what the root File ID is.
5642             * Assume its 2 to start with
5643             */
5644            smp->sm_root_ino = SMBFS_ROOT_INO;
5645            fap->fa_ino = SMBFS_ROOT_INO;
5646        }
5647        else {
5648            /* Recreating root vnode and we know what its ID was */
5649            fap->fa_ino = smp->sm_root_ino;
5650        }
5651
5652        /* Its the root,thus its a dir */
5653        vnode_type = VDIR;
5654
5655        if (!(vcp->vc_misc_flags & SMBV_NO_QUERYINFO)) {
5656            /* Try the normal Query Info */
5657            if (UNIX_CAPS(share) & UNIX_QFILEINFO_UNIX_INFO2_CAP) {
5658                error = smbfs_smb_qpathinfo(share, dnp, vnode_type,
5659                                            fap, SMB_QFILEINFO_UNIX_INFO2,
5660                                            NULL, NULL,
5661                                            context);
5662            }
5663            else {
5664                error = smbfs_smb_qpathinfo(share, dnp, vnode_type,
5665                                            fap, SMB_QFILEINFO_ALL_INFO,
5666                                            NULL, NULL,
5667                                            context);
5668            }
5669
5670            SMB_LOG_KTRACE(SMB_DBG_SMBFS_LOOKUP | DBG_FUNC_NONE,
5671                           0xabc001, error, 0, 0, 0);
5672
5673            if (error) {
5674                /* This server does not support Query Info? */
5675                SMBERROR("Server failed Query Info %d\n", error);
5676                vcp->vc_misc_flags |= SMBV_NO_QUERYINFO;
5677            }
5678        }
5679
5680        if ((vcp->vc_flags & SMBV_SMB2) &&
5681            (vcp->vc_misc_flags & SMBV_NO_QUERYINFO)) {
5682            /* Use Query Dir instead of Query Info, but only if SMB 2/3 */
5683            error = smb2fs_smb_cmpd_query_dir_one(share, dnp,
5684                                                  NULL, 0,
5685                                                  fap, NULL, NULL,
5686                                                  context);
5687
5688            SMB_LOG_KTRACE(SMB_DBG_SMBFS_LOOKUP | DBG_FUNC_NONE,
5689                           0xabc002, error, 0, 0, 0);
5690        }
5691
5692		/*
5693		 * NTFS handles dates correctly, but FAT file systems have some
5694		 * problems. If an entire FAT drive is shared, then the root of the
5695         * share may have either no dates (ie 0) or bad dates. This seems to
5696         * only happen with the root of the share, so we have to check for bad
5697         * dates and fix them up. Windows XP/2000/2003 will return Jan. 1, 1980
5698         * for the create, modif and access dates. NT4 will return no dates
5699         * at all.
5700		 *
5701		 * So we follow the Windows 2000 model. If any of the time
5702		 * fields are zero we fill them in with Jan 1, 1980.
5703         *
5704         * Note: in setattr, we also do not allow any dates before 1980 for a
5705         * FAT file system.
5706		 */
5707		if (fap->fa_mtime.tv_sec == 0)
5708			smb_time_NT2local(DIFF1980TO1601, &fap->fa_mtime);
5709		if (fap->fa_crtime.tv_sec == 0)
5710			smb_time_NT2local(DIFF1980TO1601, &fap->fa_crtime);
5711		if (fap->fa_atime.tv_sec == 0)
5712			fap->fa_atime = fap->fa_mtime;
5713		if (fap->fa_chtime.tv_sec == 0)
5714			fap->fa_chtime = fap->fa_mtime;
5715
5716		goto done;
5717	}
5718
5719	if (nmlen == 1 && name && name[0] == '.') {
5720		error = smbfs_lookup(share, dnp, NULL, NULL, fap, context);
5721        SMB_LOG_KTRACE(SMB_DBG_SMBFS_LOOKUP | DBG_FUNC_NONE,
5722                       0xabc003, error, 0, 0, 0);
5723		goto done;
5724	} else if (nmlen == 2 && name && name[0] == '.' && name[1] == '.') {
5725		/*
5726		 * Remember that error is set to EINVAL. This should never happen, but
5727		 * just in case make sure we have a parent, if not return EINVAL
5728		 */
5729        lck_rw_lock_shared(&dnp->n_parent_rwlock);
5730		if (dnp->n_parent) {
5731			error = smbfs_lookup(share, dnp->n_parent, NULL, NULL, fap, context);
5732            SMB_LOG_KTRACE(SMB_DBG_SMBFS_LOOKUP | DBG_FUNC_NONE,
5733                           0xabc004, error, 0, 0, 0);
5734        }
5735        lck_rw_unlock_shared(&dnp->n_parent_rwlock);
5736
5737		goto done;
5738	}
5739
5740	bzero(fap, sizeof(*fap));
5741	/* We keep track of the time the lookup call was requested */
5742	nanouptime(&fap->fa_reqtime);
5743
5744	/*
5745	 * So we now default to using FindFirst, because of Dfs. Only FindFirst
5746	 * support getting the reparse point tag. If this is a stream node then
5747	 * use the query info call to do the lookup. The FindFirst code doesn't
5748	 * handle stream nodes yet, may want to change that in the future.
5749	 */
5750	if ((dnp->n_vnode) && vnode_isnamedstream(dnp->n_vnode)) {
5751		goto doQueryInfo;
5752	}
5753
5754    if (vcp->vc_flags & SMBV_SMB2) {
5755        /* SMB 2/3 can do this in in one compound req */
5756        error = smb2fs_smb_cmpd_query_dir_one(share, dnp,
5757                                              name, nmlen,
5758                                              fap, (char **) namep, nmlenp,
5759                                              context);
5760        SMB_LOG_KTRACE(SMB_DBG_SMBFS_LOOKUP | DBG_FUNC_NONE,
5761                       0xabc005, error, 0, 0, 0);
5762    }
5763    else {
5764		Boolean unix_symlink = ((UNIX_CAPS(share) & UNIX_SFILEINFO_UNIX_LINK_CAP)) ? TRUE : FALSE;
5765		Boolean darwin = (SSTOVC(share)->vc_flags & SMBV_DARWIN) ? TRUE : FALSE;
5766
5767		/*
5768		 * We need to workaround a Samba Server bug. In some lookup paths, Samba
5769		 * will follow the symlink to see if it exists before returning the info
5770		 * requested. In the case were the symlink is broken Samba will return
5771		 * that the symlink doesn't exist when its what the symlink points to that
5772		 * doesn't exist.  This can cause symlinks to appear not to exist in some case
5773		 * and not others. Samba servers will follow the symlink if we make a
5774		 * non wildcard FindFirst/Next call, but they will not follow it if we do a
5775		 * Trans2Query. The problem we have here is the Trans2Query call does not
5776		 * return the name of the file, which means we could have the wrong case.
5777		 *
5778		 * If they support unix symlinks and its not darwin then we know its one
5779		 * of these Samba servers, this includes Snow Leopard Servers.
5780		 *
5781		 * So if we already have the vnode then we know its a symlink and have its
5782		 * name so just make the Trans2Query call and we are done.
5783		 *
5784		 * In the case were we don't have the vnode we need to do the FindFirst/Next
5785		 * call first, if that call returns ENOENT then we need to retry with a
5786		 * Trans2Query call. This can cause a performance issue, but only when
5787		 * the item doesn't exist and we should have this in our negative name
5788		 * cache after this double lookup.
5789		*/
5790		if (unix_symlink && !darwin && (namep == NULL) && dnp->n_vnode &&
5791			(vnode_vtype(dnp->n_vnode) == VLNK)) {
5792			return smbfs_smb_qpathinfo(share, dnp, VREG,
5793                                       fap, SMB_QFILEINFO_UNIX_INFO2,
5794									   namep, nmlenp,
5795                                       context);
5796		}
5797
5798		/* SMB 1 using old, slower way */
5799		error = smbfs_smb_findopen(share, dnp, name, nmlen, &ctx, FALSE, context);
5800		if (error) {
5801			/* Can't happen we do wait ok */
5802			goto done;
5803		}
5804		error = smbfs_findnext(ctx, context);
5805		if (error == 0) {
5806			*fap = ctx->f_attr;
5807			if (name == NULL) {
5808				fap->fa_ino = dnp->n_ino;
5809			}
5810			if (namep) {
5811				*namep = ctx->f_LocalName;
5812				ctx->f_LocalName = NULL;
5813			}
5814			if (nmlenp) {
5815				*nmlenp = ctx->f_LocalNameLen;
5816			}
5817		}
5818		smbfs_smb_findclose(ctx, context);
5819
5820		/*
5821		 * We need to workaround a Samba Server bug. See the comment above for
5822		 * complete details.
5823		 */
5824		if ((error == ENOENT) && unix_symlink && !darwin && (namep)) {
5825			SMBWARNING("Working around Samba bug doing second lookup\n");
5826            vnode_type = (ctx->f_attr.fa_attr & SMB_EFA_DIRECTORY) ? VDIR : VREG;
5827            error = smbfs_smb_qpathinfo(share, dnp, vnode_type,
5828                                        fap, SMB_QFILEINFO_UNIX_INFO2,
5829                                        namep, nmlenp,
5830                                        context);
5831            goto done;
5832		}
5833    }
5834
5835	/*
5836	 * So if the FindFirst fails with an access error of some kind. If they support
5837	 * the UNIX extensions we can try SMB_QFILEINFO_UNIX_INFO2. If they support
5838	 * the NT CAPS option we can try SMB_QFILEINFO_ALL_INFO. Both Trans2 Query
5839	 * Info levels return the same information as FindFirst and will work
5840	 * with Drop boxes.
5841	 *
5842	 * Setting up a Drop Box for Windows 2000 and 2003
5843	 *
5844	 * 1. In Windows Explorer, right-click on the folder and choose
5845	 *    "Properties"
5846	 * 2. Switch to the Security tab in the Properties dialog
5847	 * 3. Confirm "Allow inheritable permissions from parent to propagate
5848	 *    to this object" is not checked.
5849	 * 4. Confirm that CREATOR OWNER exist and has full access to
5850	 *    sub-folders and files.
5851	 * 5. Select/Add the user, group or everyone who will only have drop box
5852	 *    permissions.
5853	 * 6. Under the "Permissions" section at the bottom of the dialog, click
5854	 *    "Write" under the "Allow" column.
5855	 * 7. Click on the Advanced Tab
5856	 * 8. Select the user or group who will only have drop box permissions.
5857	 * 9. Click "View/Edit"
5858	 * 10. There are several different settings that will work, but here are
5859	 *     the ones required.
5860	 *
5861	 *    In the Apply onto menu select "This Folder, subfolders and files".
5862	 *
5863	 * 	Select the following under the "Allow" column:
5864	 * 		- Traverse Folders / Execute File
5865	 *		- Create Files / Write Data
5866	 *		- Create Folders / Append Data
5867	 *		- Write Attributes
5868	 *		- Write Extended Attributes
5869	 *
5870	 * 11. Click OK.
5871	 * 12. Click Apply to apply your changes.
5872	 * 13. Click OK
5873	 *
5874	 * Setting up a Drop Box for Windows NT
5875	 *
5876	 * 1. In Windows Explorer, right-click on the folder and choose
5877	 *    "Properties"
5878	 * 2. Switch to the Security tab in the Properties dialog
5879	 * 3. Click on the "Permissions" button.
5880	 * 4. Confirm that CREATOR OWNER exist and has full control.
5881	 * 5. Select/Add the user, group or everyone who will only have drop box
5882	 *    permissions.
5883	 * 6. Double click on the user, group or everyone who will only have
5884	 *    drop box permissions.
5885	 * 7. Check the Write checkbox.
5886	 * 8. Un-check all the other checkboxes.
5887	 * 9. Click Apply to apply your changes.
5888	 * 10. Click OK
5889	 *
5890	 * Setting up a Drop Box for SAMBA on a Mac OS X system
5891	 *
5892	 * 1. Bring up a terminal.
5893	 * 2. Create a folder and make the owner the administrator of the
5894	 *    system.
5895	 * 3. Now run the chmod command give everyone write and execute
5896	 *    privileges.
5897	 * 	e.g. chmod 733 ./DropBox
5898	 *
5899	 * If they support UNIX_QFILEINFO_UNIX_INFO2_CAP then they must support UNIX_INFO2.
5900	 * Hopefully everyone does this correctly. Remember the SMB_QFILEINFO_UNIX_INFO2 call does
5901	 * not return the name. So if they are asking for the name then just fail.
5902     *
5903     * NOTE: If we failed because of a low resources (EAGAIN) then try again.
5904	 */
5905	if ((error != EACCES) && (error != EPERM) && (error != EAGAIN)) {
5906		goto done;
5907	}
5908
5909doQueryInfo:
5910	/*
5911     * Either its a named stream vnode, or the Query Dir failed so try
5912     * doing a Query Info instead
5913     */
5914
5915     /*
5916      * Since we dont know what the item is, try VREG as that is least likely
5917      * to return an error
5918      */
5919    vnode_type = VREG;
5920    if (UNIX_CAPS(share) & UNIX_QFILEINFO_UNIX_INFO2_CAP) {
5921		if (namep == NULL) {
5922			error = smbfs_smb_qpathinfo(share, dnp, vnode_type,
5923                                        fap, SMB_QFILEINFO_UNIX_INFO2,
5924                                        namep, nmlenp,
5925                                        context);
5926		} else {
5927			/* If they are requesting the name, return error nothing else we can do here. */
5928			error = EACCES;
5929		}
5930	}
5931    else  {
5932        error = smbfs_smb_qpathinfo(share, dnp, vnode_type,
5933                                    fap, SMB_QFILEINFO_ALL_INFO,
5934                                    namep, nmlenp,
5935                                    context);
5936	}
5937    SMB_LOG_KTRACE(SMB_DBG_SMBFS_LOOKUP | DBG_FUNC_NONE,
5938                   0xabc006, error, 0, 0, 0);
5939
5940done:
5941    SMB_LOG_KTRACE(SMB_DBG_SMBFS_LOOKUP | DBG_FUNC_END, error, 0, 0, 0, 0);
5942	return error;
5943}
5944
5945/*
5946 * Close the network search, reset the offset count and if there is
5947 * a next entry remove it.
5948 */
5949void smbfs_closedirlookup(struct smbnode *np, vfs_context_t context)
5950{
5951	if (np->d_fctx)
5952		smbfs_smb_findclose(np->d_fctx, context);
5953	np->d_fctx = NULL;
5954	np->d_offset = 0;
5955	if (np->d_nextEntry)
5956		SMB_FREE(np->d_nextEntry, M_TEMP);
5957	np->d_nextEntry = NULL;
5958	np->d_nextEntryLen = 0;
5959}
5960
5961/*
5962 * The calling routine must hold a reference on the share
5963 */
5964static int
5965smbfs_smb_getsec_int(struct smb_share *share, SMBFID fid, uint32_t selector,
5966                     struct ntsecdesc **res, uint32_t *reslen,
5967                     vfs_context_t context)
5968{
5969	struct smb_ntrq *ntp;
5970	struct mbchain *mbp;
5971	struct mdchain *mdp;
5972	int error;
5973	size_t len;
5974    uint16_t smb1_fid = (uint16_t) fid;
5975
5976	error = smb_nt_alloc(SSTOCP(share), NT_TRANSACT_QUERY_SECURITY_DESC, context, &ntp);
5977	if (error)
5978		return error;
5979	mbp = &ntp->nt_tparam;
5980	mb_init(mbp);
5981	mb_put_mem(mbp, (caddr_t)&smb1_fid, sizeof(smb1_fid), MB_MSYSTEM);
5982	mb_put_uint16le(mbp, 0); /* reserved */
5983	mb_put_uint32le(mbp, selector);
5984	ntp->nt_maxpcount = 4;
5985	ntp->nt_maxdcount = *reslen;
5986	error = smb_nt_request(ntp);
5987	*res = NULL;
5988	mdp = &ntp->nt_rparam;
5989	if (error) {
5990	    	/*
5991		 * The error is that the buffer wasn't big enough; get
5992		 * the required buffer size, so our caller can try again
5993		 * with a bigger buffer.
5994		 */
5995		if (ntp->nt_flags & SMBT2_MOREDATA)
5996		    md_get_uint32le(mdp, reslen);
5997		goto done;
5998	} else {
5999		md_get_uint32le(mdp, reslen);
6000	}
6001	mdp = &ntp->nt_rdata;
6002	if (mdp->md_top) {
6003		len = m_fixhdr(mdp->md_top);
6004		if (len != (size_t)*reslen)
6005			SMBWARNING("Sent us %ld but said they sent us %d for fid = 0x%x\n",
6006					   len, *reslen, letohs(smb1_fid));
6007		/*
6008		 * The following "if (len < *reslen)" handles a Windows bug
6009		 * observed when the underlying filesystem is FAT32.  In that
6010		 * case a 32 byte security descriptor comes back (S-1-1-0, ie
6011		 * "Everyone") but the Parameter Block claims 44 is the length
6012		 * of the security descriptor.  (The Data Block length
6013		 * claimed is 32.  This server bug was reported against NT
6014		 * first and I've personally observed it with W2K.
6015		 */
6016
6017		if (len < (size_t)*reslen) {
6018			 /* Believe what we got instead of what they told us */
6019			*reslen = (uint32_t)len;
6020		} else if (len > (size_t)*reslen) {
6021			len = *reslen;	 /* ignore any extra data */
6022		}
6023		/*
6024		 * All the calling routines expect to have sizeof(struct ntsecdesc). The
6025		 * len is the amount of data we have received and *reslen is what they
6026		 * claim they sent. Up above we make sure that *reslen and len are the
6027		 * same. So all we need to do here is make sure that len is not less than
6028		 * the size of our ntsecdesc structure.
6029		 */
6030		if (len >= sizeof(struct ntsecdesc)) {
6031			SMB_MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
6032			md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
6033		} else {
6034			SMBERROR("len %ld < ntsecdesc %ld fid 0x%x\n", len,
6035					 sizeof(struct ntsecdesc), letohs(smb1_fid));
6036			error = EBADRPC;
6037		}
6038	} else {
6039		SMBERROR("null md_top? fid 0x%x\n", letohs(smb1_fid));
6040		error = EBADRPC;
6041	}
6042done:
6043	smb_nt_done(ntp);
6044	return (error);
6045}
6046
6047/*
6048 * The calling routine must hold a reference on the share
6049 */
6050int
6051smbfs_smb_getsec(struct smb_share *share, struct smbnode *np,
6052                 uint32_t desired_access, SMBFID fid, uint32_t selector,
6053                 struct ntsecdesc **res, size_t *rt_len, vfs_context_t context)
6054{
6055	int error;
6056	uint32_t seclen;
6057
6058    seclen = SSTOVC(share)->vc_txmax;
6059
6060    if (SSTOVC(share)->vc_flags & SMBV_SMB2) {
6061        error = smb2fs_smb_security_get(share, np,
6062                                        desired_access, selector,
6063                                        res, &seclen,
6064                                        context);
6065    }
6066    else {
6067        /*
6068         * If the buffer size is to small we could end up making two request. Using
6069         * the max transmit buffer should limit this from happening to often.
6070         */
6071        error = smbfs_smb_getsec_int(share, fid, selector, res, &seclen, context);
6072        if (error && (seclen > SSTOVC(share)->vc_txmax)) {
6073            error = smbfs_smb_getsec_int(share, fid, selector, res, &seclen,
6074                                         context);
6075        }
6076    }
6077
6078    /* Return the the size we ended up getting */
6079    if (error == 0)
6080        *rt_len = seclen;
6081
6082	return (error);
6083}
6084
6085/*
6086 * The calling routine must hold a reference on the share
6087 */
6088int
6089smb1fs_setsec(struct smb_share *share, SMBFID fid, uint32_t selector,
6090              uint16_t ControlFlags, struct ntsid *owner, struct ntsid *group,
6091              struct ntacl *sacl, struct ntacl *dacl, vfs_context_t context)
6092{
6093	struct smb_ntrq *ntp;
6094	struct mbchain *mbp;
6095	int error;
6096	uint32_t off;
6097	struct ntsecdesc ntsd;
6098    uint16_t smb1_fid = (uint16_t) fid;
6099
6100	error = smb_nt_alloc(SSTOCP(share), NT_TRANSACT_SET_SECURITY_DESC,
6101						 context, &ntp);
6102	if (error)
6103		return error;
6104	mbp = &ntp->nt_tparam;
6105	mb_init(mbp);
6106	mb_put_mem(mbp, (caddr_t)&smb1_fid, sizeof(smb1_fid), MB_MSYSTEM);
6107	mb_put_uint16le(mbp, 0); /* reserved */
6108	mb_put_uint32le(mbp, selector);
6109	mbp = &ntp->nt_tdata;
6110	mb_init(mbp);
6111	bzero(&ntsd, sizeof ntsd);
6112	ntsd.Revision = 0x01;	/* Should we make this a define? */
6113	/*
6114	 * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN)
6115	 * We set here only those bits we can be sure must be set.  The rest
6116	 * are up to the caller.  In particular, the caller may intentionally
6117	 * set an acl PRESENT bit while giving us a null pointer for the
6118	 * acl - that sets a null acl, denying access to everyone.
6119	 */
6120	ControlFlags |= SE_SELF_RELATIVE;
6121	off = (uint32_t)sizeof(ntsd);
6122	if (owner) {
6123		ntsd.OffsetOwner = htolel(off);
6124		off += (uint32_t)sidlen(owner);
6125	}
6126	if (group) {
6127		ntsd.OffsetGroup = htolel(off);
6128		off += (uint32_t)sidlen(group);
6129	}
6130	if (sacl) {
6131		ControlFlags |= SE_SACL_PRESENT | SE_SACL_AUTO_INHERITED | SE_SACL_AUTO_INHERIT_REQ;
6132		ntsd.OffsetSacl = htolel(off);
6133		off += acllen(sacl);
6134	}
6135	if (dacl) {
6136		ControlFlags |= SE_DACL_PRESENT | SE_DACL_AUTO_INHERITED | SE_DACL_AUTO_INHERIT_REQ;
6137		ntsd.OffsetDacl = htolel(off);
6138	}
6139
6140	ntsd.ControlFlags = htoles(ControlFlags);
6141	mb_put_mem(mbp, (caddr_t)&ntsd, sizeof ntsd, MB_MSYSTEM);
6142	if (owner)
6143		mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM);
6144	if (group)
6145		mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM);
6146	if (sacl)
6147		mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM);
6148	if (dacl)
6149		mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM);
6150	ntp->nt_maxpcount = 0;
6151	ntp->nt_maxdcount = 0;
6152	error = smb_nt_request(ntp);
6153
6154	if ((error != 0) && (ntp->nt_status == STATUS_INVALID_SID)) {
6155		/*
6156		 * If the server returns STATUS_INVALID_SID, then just pretend that
6157		 * we set the security info even though it "failed".
6158		 * See <rdar://problem/10852453>.
6159		 */
6160		error = 0;
6161    }
6162
6163	smb_nt_done(ntp);
6164	return (error);
6165}
6166