14bff34e3Sthurlow /*
24bff34e3Sthurlow  * Copyright (c) 2000-2001, Boris Popov
34bff34e3Sthurlow  * All rights reserved.
44bff34e3Sthurlow  *
54bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
64bff34e3Sthurlow  * modification, are permitted provided that the following conditions
74bff34e3Sthurlow  * are met:
84bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
94bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
104bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
114bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
124bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
134bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
144bff34e3Sthurlow  *    must display the following acknowledgement:
154bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
164bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
174bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
184bff34e3Sthurlow  *    without specific prior written permission.
194bff34e3Sthurlow  *
204bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304bff34e3Sthurlow  * SUCH DAMAGE.
314bff34e3Sthurlow  *
324bff34e3Sthurlow  * $Id: smbfs_subr.c,v 1.18 2005/02/02 00:22:23 lindak Exp $
334bff34e3Sthurlow  */
344bff34e3Sthurlow 
354bff34e3Sthurlow /*
36613a2f6bSGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
374bff34e3Sthurlow  * Use is subject to license terms.
38adee6784SGordon Ross  *
39adee6784SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
404bff34e3Sthurlow  */
414bff34e3Sthurlow 
424bff34e3Sthurlow #include <sys/param.h>
434bff34e3Sthurlow #include <sys/systm.h>
444bff34e3Sthurlow #include <sys/time.h>
454bff34e3Sthurlow #include <sys/vnode.h>
464bff34e3Sthurlow #include <sys/sunddi.h>
474bff34e3Sthurlow 
484bff34e3Sthurlow #include <netsmb/smb_osdep.h>
494bff34e3Sthurlow 
504bff34e3Sthurlow #include <netsmb/smb.h>
51adee6784SGordon Ross #include <netsmb/smb2.h>
524bff34e3Sthurlow #include <netsmb/smb_conn.h>
534bff34e3Sthurlow #include <netsmb/smb_subr.h>
544bff34e3Sthurlow #include <netsmb/smb_rq.h>
554bff34e3Sthurlow 
564bff34e3Sthurlow #include <smbfs/smbfs.h>
574bff34e3Sthurlow #include <smbfs/smbfs_node.h>
584bff34e3Sthurlow #include <smbfs/smbfs_subr.h>
594bff34e3Sthurlow 
604bff34e3Sthurlow /*
614bff34e3Sthurlow  * In the Darwin code, this function used to compute the full path
624bff34e3Sthurlow  * by following the chain of n_parent pointers back to the root.
634bff34e3Sthurlow  * In the Solaris port we found the n_parent pointers inconvenient
644bff34e3Sthurlow  * because they hold parent nodes busy.  We now keep the full path
654bff34e3Sthurlow  * in every node, so this function need only marshall the directory
664bff34e3Sthurlow  * path, and (if provided) the separator and last component name.
674bff34e3Sthurlow  *
684bff34e3Sthurlow  * Note that this logic must match that in smbfs_getino
694bff34e3Sthurlow  */
704bff34e3Sthurlow int
smbfs_fullpath(struct mbchain * mbp,struct smb_vc * vcp,struct smbnode * dnp,const char * name,int nmlen,u_int8_t sep)714bff34e3Sthurlow smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
72430b4c46SGordon Ross 	const char *name, int nmlen, u_int8_t sep)
734bff34e3Sthurlow {
744bff34e3Sthurlow 	int caseopt = SMB_CS_NONE;
754bff34e3Sthurlow 	int unicode = (SMB_UNICODE_STRINGS(vcp)) ? 1 : 0;
76430b4c46SGordon Ross 	int error;
774bff34e3Sthurlow 
78adee6784SGordon Ross 	/*
79adee6784SGordon Ross 	 * SMB1 may need an alignment pad before (not SMB2)
80adee6784SGordon Ross 	 */
81adee6784SGordon Ross 	if (((vcp)->vc_flags & SMBV_SMB2) == 0 &&
82adee6784SGordon Ross 	    ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) != 0) {
834bff34e3Sthurlow 		error = mb_put_padbyte(mbp);
844bff34e3Sthurlow 		if (error)
854bff34e3Sthurlow 			return (error);
864bff34e3Sthurlow 	}
8791d632c8Sgwr 
884bff34e3Sthurlow 	error = smb_put_dmem(mbp, vcp,
894bff34e3Sthurlow 	    dnp->n_rpath, dnp->n_rplen,
90430b4c46SGordon Ross 	    caseopt, NULL);
914bff34e3Sthurlow 	if (name) {
9291d632c8Sgwr 		/*
9391d632c8Sgwr 		 * Special case at share root:
9491d632c8Sgwr 		 * Don't put another slash.
9591d632c8Sgwr 		 */
9691d632c8Sgwr 		if (dnp->n_rplen <= 1 && sep == '\\')
9791d632c8Sgwr 			sep = 0;
9891d632c8Sgwr 		/*
9991d632c8Sgwr 		 * More special cases, now for XATTR:
10091d632c8Sgwr 		 * Our "faked up" XATTR directories use a
10191d632c8Sgwr 		 * full path name ending with ":" so as to
10291d632c8Sgwr 		 * avoid conflicts with any real paths.
10391d632c8Sgwr 		 * (It is not a valid CIFS path name.)
10491d632c8Sgwr 		 * Therefore, when we're composing a full
10591d632c8Sgwr 		 * path name from an XATTR directory, we
10691d632c8Sgwr 		 * need to _ommit_ the ":" separator and
10791d632c8Sgwr 		 * instead copy the one from the "fake"
10891d632c8Sgwr 		 * parent node's path name.
10991d632c8Sgwr 		 */
11091d632c8Sgwr 		if (dnp->n_flag & N_XATTR)
11191d632c8Sgwr 			sep = 0;
11291d632c8Sgwr 
11391d632c8Sgwr 		if (sep) {
11491d632c8Sgwr 			/* Put the separator */
1154bff34e3Sthurlow 			if (unicode)
1164bff34e3Sthurlow 				error = mb_put_uint16le(mbp, sep);
1174bff34e3Sthurlow 			else
1184bff34e3Sthurlow 				error = mb_put_uint8(mbp, sep);
1194bff34e3Sthurlow 			if (error)
1204bff34e3Sthurlow 				return (error);
1214bff34e3Sthurlow 		}
1224bff34e3Sthurlow 		/* Put the name */
1234bff34e3Sthurlow 		error = smb_put_dmem(mbp, vcp,
124430b4c46SGordon Ross 		    name, nmlen, caseopt, NULL);
1254bff34e3Sthurlow 		if (error)
1264bff34e3Sthurlow 			return (error);
1274bff34e3Sthurlow 	}
128adee6784SGordon Ross 
129adee6784SGordon Ross 	/* SMB1 wants NULL termination. */
130adee6784SGordon Ross 	if (((vcp)->vc_flags & SMBV_SMB2) == 0) {
131adee6784SGordon Ross 		if (unicode)
132adee6784SGordon Ross 			error = mb_put_uint16le(mbp, 0);
133adee6784SGordon Ross 		else
134adee6784SGordon Ross 			error = mb_put_uint8(mbp, 0);
135adee6784SGordon Ross 	}
1364bff34e3Sthurlow 
1374bff34e3Sthurlow 	return (error);
1384bff34e3Sthurlow }
1394bff34e3Sthurlow 
140613a2f6bSGordon Ross /*
141613a2f6bSGordon Ross  * Convert a Unicode directory entry to UTF-8
142613a2f6bSGordon Ross  */
1434bff34e3Sthurlow void
smbfs_fname_tolocal(struct smbfs_fctx * ctx)1444bff34e3Sthurlow smbfs_fname_tolocal(struct smbfs_fctx *ctx)
1454bff34e3Sthurlow {
146613a2f6bSGordon Ross 	uchar_t tmpbuf[SMB_MAXFNAMELEN+1];
1474bff34e3Sthurlow 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1484bff34e3Sthurlow 	uchar_t *dst;
1494bff34e3Sthurlow 	const ushort_t *src;
1504bff34e3Sthurlow 	size_t inlen, outlen;
151613a2f6bSGordon Ross 	int flags;
1524bff34e3Sthurlow 
1534bff34e3Sthurlow 	if (ctx->f_nmlen == 0)
1544bff34e3Sthurlow 		return;
1554bff34e3Sthurlow 
1564bff34e3Sthurlow 	if (!SMB_UNICODE_STRINGS(vcp))
1574bff34e3Sthurlow 		return;
1584bff34e3Sthurlow 
159613a2f6bSGordon Ross 	if (ctx->f_namesz < sizeof (tmpbuf)) {
160613a2f6bSGordon Ross 		ASSERT(0);
161613a2f6bSGordon Ross 		goto errout;
162613a2f6bSGordon Ross 	}
163613a2f6bSGordon Ross 
1644bff34e3Sthurlow 	/*
165613a2f6bSGordon Ross 	 * In-place conversions are not supported,
166613a2f6bSGordon Ross 	 * so convert into tmpbuf and copy.
1674bff34e3Sthurlow 	 */
168613a2f6bSGordon Ross 	dst = tmpbuf;
169613a2f6bSGordon Ross 	outlen = SMB_MAXFNAMELEN;
1704bff34e3Sthurlow 	/*LINTED*/
1714bff34e3Sthurlow 	src = (const ushort_t *)ctx->f_name;
172613a2f6bSGordon Ross 	inlen = ctx->f_nmlen / 2;	/* number of UCS-2 characters */
173613a2f6bSGordon Ross 	flags = UCONV_IN_LITTLE_ENDIAN;
174613a2f6bSGordon Ross 
175613a2f6bSGordon Ross 	if (uconv_u16tou8(src, &inlen, dst, &outlen, flags) != 0)
176613a2f6bSGordon Ross 		goto errout;
177613a2f6bSGordon Ross 
178613a2f6bSGordon Ross 	ASSERT(outlen < sizeof (tmpbuf));
179613a2f6bSGordon Ross 	tmpbuf[outlen] = '\0';
180613a2f6bSGordon Ross 	bcopy(tmpbuf, ctx->f_name, outlen + 1);
181613a2f6bSGordon Ross 	ctx->f_nmlen = (int)outlen;
182613a2f6bSGordon Ross 	return;
183613a2f6bSGordon Ross 
184613a2f6bSGordon Ross errout:
185613a2f6bSGordon Ross 	/*
186613a2f6bSGordon Ross 	 * Conversion failed, but our caller does not
18702d09e03SGordon Ross 	 * deal with errors here, so just put a "?".
188613a2f6bSGordon Ross 	 * Don't expect to ever see this.
189613a2f6bSGordon Ross 	 */
190ab415d94SGordon Ross 	(void) strlcpy(ctx->f_name, "?", ctx->f_namesz);
1914bff34e3Sthurlow }
192adee6784SGordon Ross 
193adee6784SGordon Ross /*
194adee6784SGordon Ross  * Decode a directory entry from OtW form into ctx->f_attr
195adee6784SGordon Ross  *
196adee6784SGordon Ross  * Caller already put some (wire-format) directory entries
197adee6784SGordon Ross  * into ctx->f_mdchain and we expect to find one.
198adee6784SGordon Ross  *
199adee6784SGordon Ross  * Advancing correctly through the buffer can be tricky if one
200adee6784SGordon Ross  * tries to add up the size of an entry as you go (which is how
201adee6784SGordon Ross  * the darwin code this is derived from did it).  The easiest way
202adee6784SGordon Ross  * to correctly advance the position is to get a whole dirent
203adee6784SGordon Ross  * into another mdchain (entry_mdc) based on NextEntryOffset,
204adee6784SGordon Ross  * and then scan the data from that mdchain.  On the last entry,
205adee6784SGordon Ross  * we don't know the entire length, so just scan directly from
206adee6784SGordon Ross  * what remains of the multi-entry buffer instead of trying to
207adee6784SGordon Ross  * figure out the length to copy into a separate mdchain.
208adee6784SGordon Ross  */
209adee6784SGordon Ross int
smbfs_decode_dirent(struct smbfs_fctx * ctx)210adee6784SGordon Ross smbfs_decode_dirent(struct smbfs_fctx *ctx)
211adee6784SGordon Ross {
212adee6784SGordon Ross 	struct mdchain entry_mdc;
213adee6784SGordon Ross 	struct mdchain *mdp = &ctx->f_mdchain;
214adee6784SGordon Ross 	size_t nmlen;
215adee6784SGordon Ross 	uint64_t llongint;
216adee6784SGordon Ross 	uint32_t nmsize, dattr;
217adee6784SGordon Ross 	uint32_t nextoff = 0;
218adee6784SGordon Ross 	int error;
219adee6784SGordon Ross 
220adee6784SGordon Ross 	/* In case we error out... */
221adee6784SGordon Ross 	ctx->f_nmlen = 0;
222adee6784SGordon Ross 	ctx->f_rkey = (uint32_t)-1;
223adee6784SGordon Ross 	bzero(&entry_mdc, sizeof (entry_mdc));
224adee6784SGordon Ross 
225adee6784SGordon Ross 	/*
226adee6784SGordon Ross 	 * Setup mdp to point to an mbchain holding
227adee6784SGordon Ross 	 * what should be a single directory entry.
228adee6784SGordon Ross 	 */
229adee6784SGordon Ross 	error = md_get_uint32le(mdp, &nextoff);
230adee6784SGordon Ross 	if (error != 0)
231adee6784SGordon Ross 		goto errout;
232adee6784SGordon Ross 	if (nextoff >= 4) {
233adee6784SGordon Ross 		/*
234adee6784SGordon Ross 		 * More entries follow.  Make a new mbchain
235adee6784SGordon Ross 		 * holding just this one entry, then advance.
236adee6784SGordon Ross 		 */
237adee6784SGordon Ross 		mblk_t *m = NULL;
238adee6784SGordon Ross 		error = md_get_mbuf(mdp, nextoff - 4, &m);
239adee6784SGordon Ross 		if (error != 0)
240adee6784SGordon Ross 			goto errout;
241adee6784SGordon Ross 		md_initm(&entry_mdc, m);
242adee6784SGordon Ross 		mdp = &entry_mdc;
243adee6784SGordon Ross 		ctx->f_eofs += nextoff;
244adee6784SGordon Ross 	} else {
245adee6784SGordon Ross 		/* Scan directly from ctx->f_mdchain */
246adee6784SGordon Ross 		ctx->f_eofs = ctx->f_left;
247adee6784SGordon Ross 	}
248adee6784SGordon Ross 
249adee6784SGordon Ross 	/*
250adee6784SGordon Ross 	 * Decode the fixed-size parts
251adee6784SGordon Ross 	 */
252adee6784SGordon Ross 	switch (ctx->f_infolevel) {
253adee6784SGordon Ross 	case FileFullDirectoryInformation:
254adee6784SGordon Ross 	case SMB_FIND_FULL_DIRECTORY_INFO:
255adee6784SGordon Ross 		md_get_uint32le(mdp, &ctx->f_rkey);	/* resume key (idx) */
256adee6784SGordon Ross 		md_get_uint64le(mdp, &llongint);	/* creation time */
257adee6784SGordon Ross 		smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
258adee6784SGordon Ross 		md_get_uint64le(mdp, &llongint);
259adee6784SGordon Ross 		smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
260adee6784SGordon Ross 		md_get_uint64le(mdp, &llongint);
261adee6784SGordon Ross 		smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
262adee6784SGordon Ross 		md_get_uint64le(mdp, &llongint);
263adee6784SGordon Ross 		smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
264adee6784SGordon Ross 		md_get_uint64le(mdp, &llongint);	/* file size */
265adee6784SGordon Ross 		ctx->f_attr.fa_size = llongint;
266adee6784SGordon Ross 		md_get_uint64le(mdp, &llongint);	/* alloc. size */
267adee6784SGordon Ross 		ctx->f_attr.fa_allocsz = llongint;
268adee6784SGordon Ross 		md_get_uint32le(mdp, &dattr);	/* ext. file attributes */
269adee6784SGordon Ross 		ctx->f_attr.fa_attr = dattr;
270adee6784SGordon Ross 		error = md_get_uint32le(mdp, &nmsize);	/* name size (otw) */
271adee6784SGordon Ross 		if (error)
272adee6784SGordon Ross 			goto errout;
273adee6784SGordon Ross 		md_get_uint32le(mdp, NULL);	/* Ea size */
274adee6784SGordon Ross 		break;
275adee6784SGordon Ross 
276adee6784SGordon Ross 	case FileStreamInformation:
277adee6784SGordon Ross 		error = md_get_uint32le(mdp, &nmsize);	/* name size (otw) */
278adee6784SGordon Ross 		md_get_uint64le(mdp, &llongint);	/* file size */
279adee6784SGordon Ross 		ctx->f_attr.fa_size = llongint;
280adee6784SGordon Ross 		md_get_uint64le(mdp, &llongint);	/* alloc. size */
281adee6784SGordon Ross 		ctx->f_attr.fa_allocsz = llongint;
282adee6784SGordon Ross 		/*
283adee6784SGordon Ross 		 * Stream names start with a ':' that we want to skip.
284adee6784SGordon Ross 		 * This is the easiest place to take care of that.
285adee6784SGordon Ross 		 * Always unicode here.
286adee6784SGordon Ross 		 */
287adee6784SGordon Ross 		if (nmsize >= 2) {
288adee6784SGordon Ross 			struct mdchain save_mdc;
289adee6784SGordon Ross 			uint16_t wch;
290adee6784SGordon Ross 			save_mdc = *mdp;
291adee6784SGordon Ross 			md_get_uint16le(mdp, &wch);
292adee6784SGordon Ross 			if (wch == ':') {
293adee6784SGordon Ross 				/* OK, we skipped the ':' */
294adee6784SGordon Ross 				nmsize -= 2;
295adee6784SGordon Ross 			} else {
296adee6784SGordon Ross 				SMBVDEBUG("No leading : in stream?\n");
297adee6784SGordon Ross 				/* restore position */
298adee6784SGordon Ross 				*mdp = save_mdc;
299adee6784SGordon Ross 			}
300adee6784SGordon Ross 		}
301adee6784SGordon Ross 		break;
302adee6784SGordon Ross 
303adee6784SGordon Ross 	default:
304adee6784SGordon Ross 		SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
305adee6784SGordon Ross 		error = EINVAL;
306adee6784SGordon Ross 		goto errout;
307adee6784SGordon Ross 	}
308adee6784SGordon Ross 
309adee6784SGordon Ross 	/*
310adee6784SGordon Ross 	 * Get the filename, and convert to utf-8
311adee6784SGordon Ross 	 * Allocated f_name in findopen
312adee6784SGordon Ross 	 */
313adee6784SGordon Ross 	nmlen = ctx->f_namesz;
314adee6784SGordon Ross 	error = smb_get_dstring(mdp, SSTOVC(ctx->f_ssp),
315adee6784SGordon Ross 	    ctx->f_name, &nmlen, nmsize);
316adee6784SGordon Ross 	if (error != 0)
317adee6784SGordon Ross 		goto errout;
318adee6784SGordon Ross 	ctx->f_nmlen = (int)nmlen;
319adee6784SGordon Ross 	md_done(&entry_mdc);
320adee6784SGordon Ross 	return (0);
321adee6784SGordon Ross 
322adee6784SGordon Ross errout:
323adee6784SGordon Ross 	/*
324adee6784SGordon Ross 	 * Something bad has happened and we ran out of data
325adee6784SGordon Ross 	 * before we could parse all f_ecnt entries expected.
326adee6784SGordon Ross 	 * Give up on the current buffer.
327adee6784SGordon Ross 	 */
328adee6784SGordon Ross 	SMBVDEBUG("ran out of data\n");
329adee6784SGordon Ross 	ctx->f_eofs = ctx->f_left;
330adee6784SGordon Ross 	md_done(&entry_mdc);
331adee6784SGordon Ross 	return (error);
332adee6784SGordon Ross }
333adee6784SGordon Ross 
334adee6784SGordon Ross /*
335adee6784SGordon Ross  * Decode FileAllInformation
336adee6784SGordon Ross  *
337adee6784SGordon Ross  * The data is a concatenation of:
338adee6784SGordon Ross  *	FileBasicInformation
339adee6784SGordon Ross  *	FileStandardInformation
340adee6784SGordon Ross  *	FileInternalInformation
341adee6784SGordon Ross  *	FileEaInformation
342*bb936843SToomas Soome  *	FileAccessInformation
343adee6784SGordon Ross  *	FilePositionInformation
344adee6784SGordon Ross  *	FileModeInformation
345adee6784SGordon Ross  *	FileAlignmentInformation
346adee6784SGordon Ross  *	FileNameInformation
347adee6784SGordon Ross  */
348adee6784SGordon Ross /*ARGSUSED*/
349adee6784SGordon Ross int
smbfs_decode_file_all_info(struct smb_share * ssp,struct mdchain * mdp,struct smbfattr * fap)350adee6784SGordon Ross smbfs_decode_file_all_info(struct smb_share *ssp,
351adee6784SGordon Ross 	struct mdchain *mdp, struct smbfattr *fap)
352adee6784SGordon Ross {
353adee6784SGordon Ross 	uint64_t llongint, lsize;
354adee6784SGordon Ross 	uint32_t dattr;
355adee6784SGordon Ross 	int error;
356adee6784SGordon Ross 
357adee6784SGordon Ross 	/*
358adee6784SGordon Ross 	 * This part is: FileBasicInformation
359adee6784SGordon Ross 	 */
360adee6784SGordon Ross 
361adee6784SGordon Ross 	/* creation time */
362adee6784SGordon Ross 	md_get_uint64le(mdp, &llongint);
363adee6784SGordon Ross 	smb_time_NT2local(llongint, &fap->fa_createtime);
364adee6784SGordon Ross 
365adee6784SGordon Ross 	/* last access time */
366adee6784SGordon Ross 	md_get_uint64le(mdp, &llongint);
367adee6784SGordon Ross 	smb_time_NT2local(llongint, &fap->fa_atime);
368adee6784SGordon Ross 
369adee6784SGordon Ross 	/* last write time */
370adee6784SGordon Ross 	md_get_uint64le(mdp, &llongint);
371adee6784SGordon Ross 	smb_time_NT2local(llongint, &fap->fa_mtime);
372adee6784SGordon Ross 
373adee6784SGordon Ross 	/* last change time */
374adee6784SGordon Ross 	md_get_uint64le(mdp, &llongint);
375adee6784SGordon Ross 	smb_time_NT2local(llongint, &fap->fa_ctime);
376adee6784SGordon Ross 
377adee6784SGordon Ross 	/* attributes */
378adee6784SGordon Ross 	md_get_uint32le(mdp, &dattr);
379adee6784SGordon Ross 	fap->fa_attr = dattr;
380adee6784SGordon Ross 
381adee6784SGordon Ross 	/* reserved */
382adee6784SGordon Ross 	md_get_uint32le(mdp, NULL);
383adee6784SGordon Ross 
384adee6784SGordon Ross 	/*
385adee6784SGordon Ross 	 * This part is: FileStandardInformation
386adee6784SGordon Ross 	 */
387adee6784SGordon Ross 
388adee6784SGordon Ross 	/* allocation size */
389adee6784SGordon Ross 	md_get_uint64le(mdp, &lsize);
390adee6784SGordon Ross 	fap->fa_allocsz = lsize;
391adee6784SGordon Ross 
392adee6784SGordon Ross 	/* File size */
393adee6784SGordon Ross 	error = md_get_uint64le(mdp, &lsize);
394adee6784SGordon Ross 	fap->fa_size = lsize;
395adee6784SGordon Ross 
396adee6784SGordon Ross 	/*
397adee6784SGordon Ross 	 * There's more after this but we don't need it:
398adee6784SGordon Ross 	 * Remainder of FileStandardInformation
399adee6784SGordon Ross 	 *	NumLlinks, DeletOnClose, IsDir, reserved.
400adee6784SGordon Ross 	 * Then:
401adee6784SGordon Ross 	 *	FileInternalInformation
402adee6784SGordon Ross 	 *	FileEaInformation
403*bb936843SToomas Soome 	 *	FileAccessInformation
404adee6784SGordon Ross 	 *	FilePositionInformation
405adee6784SGordon Ross 	 *	FileModeInformation
406adee6784SGordon Ross 	 *	FileAlignmentInformation
407adee6784SGordon Ross 	 *	FileNameInformation
408adee6784SGordon Ross 	 */
409adee6784SGordon Ross 
410adee6784SGordon Ross 	return (error);
411adee6784SGordon Ross }
412adee6784SGordon Ross 
413adee6784SGordon Ross /*
414adee6784SGordon Ross  * Decode FileFsAttributeInformation
415adee6784SGordon Ross  *
416adee6784SGordon Ross  *    ULONG FileSystemAttributes;
417adee6784SGordon Ross  *    LONG MaximumComponentNameLength;
418adee6784SGordon Ross  *    ULONG FileSystemNameLength;
419adee6784SGordon Ross  *    WCHAR FileSystemName[1];
420adee6784SGordon Ross  */
421adee6784SGordon Ross int
smbfs_decode_fs_attr_info(struct smb_share * ssp,struct mdchain * mdp,struct smb_fs_attr_info * fsa)422adee6784SGordon Ross smbfs_decode_fs_attr_info(struct smb_share *ssp,
423adee6784SGordon Ross 	struct mdchain *mdp, struct smb_fs_attr_info *fsa)
424adee6784SGordon Ross {
425adee6784SGordon Ross 	struct smb_vc *vcp = SSTOVC(ssp);
426adee6784SGordon Ross 	uint32_t nlen;
427adee6784SGordon Ross 	int error;
428adee6784SGordon Ross 
429adee6784SGordon Ross 	md_get_uint32le(mdp, &fsa->fsa_aflags);
430adee6784SGordon Ross 	md_get_uint32le(mdp, &fsa->fsa_maxname);
431adee6784SGordon Ross 	error = md_get_uint32le(mdp, &nlen);	/* fs name length */
432adee6784SGordon Ross 	if (error)
433adee6784SGordon Ross 		goto out;
434adee6784SGordon Ross 
435adee6784SGordon Ross 	/*
436adee6784SGordon Ross 	 * Get the FS type name.
437adee6784SGordon Ross 	 */
438adee6784SGordon Ross 	bzero(fsa->fsa_tname, FSTYPSZ);
439adee6784SGordon Ross 	if (SMB_UNICODE_STRINGS(vcp)) {
440adee6784SGordon Ross 		uint16_t tmpbuf[FSTYPSZ];
441adee6784SGordon Ross 		size_t tmplen, outlen;
442adee6784SGordon Ross 
443adee6784SGordon Ross 		if (nlen > sizeof (tmpbuf))
444adee6784SGordon Ross 			nlen = sizeof (tmpbuf);
445adee6784SGordon Ross 		error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
446adee6784SGordon Ross 		if (error != 0)
447adee6784SGordon Ross 			goto out;
448adee6784SGordon Ross 		tmplen = nlen / 2;	/* UCS-2 chars */
449adee6784SGordon Ross 		outlen = FSTYPSZ - 1;
450adee6784SGordon Ross 		error = uconv_u16tou8(tmpbuf, &tmplen,
451adee6784SGordon Ross 		    (uchar_t *)fsa->fsa_tname, &outlen,
452adee6784SGordon Ross 		    UCONV_IN_LITTLE_ENDIAN);
453adee6784SGordon Ross 	} else {
454adee6784SGordon Ross 		if (nlen > (FSTYPSZ - 1))
455adee6784SGordon Ross 			nlen = FSTYPSZ - 1;
456adee6784SGordon Ross 		error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
457adee6784SGordon Ross 	}
458adee6784SGordon Ross 
459adee6784SGordon Ross out:
460adee6784SGordon Ross 	return (error);
461adee6784SGordon Ross }
462