smbfs_smb.c revision 163993
1139776Simp/*-
275374Sbp * Copyright (c) 2000-2001 Boris Popov
375374Sbp * All rights reserved.
475374Sbp *
575374Sbp * Redistribution and use in source and binary forms, with or without
675374Sbp * modification, are permitted provided that the following conditions
775374Sbp * are met:
875374Sbp * 1. Redistributions of source code must retain the above copyright
975374Sbp *    notice, this list of conditions and the following disclaimer.
1075374Sbp * 2. Redistributions in binary form must reproduce the above copyright
1175374Sbp *    notice, this list of conditions and the following disclaimer in the
1275374Sbp *    documentation and/or other materials provided with the distribution.
1375374Sbp * 3. All advertising materials mentioning features or use of this software
1475374Sbp *    must display the following acknowledgement:
1575374Sbp *    This product includes software developed by Boris Popov.
1675374Sbp * 4. Neither the name of the author nor the names of any co-contributors
1775374Sbp *    may be used to endorse or promote products derived from this software
1875374Sbp *    without specific prior written permission.
1975374Sbp *
2075374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2175374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2275374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2375374Sbp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2475374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2575374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2675374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2775374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2875374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2975374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3075374Sbp * SUCH DAMAGE.
3175374Sbp *
3275374Sbp * $FreeBSD: head/sys/fs/smbfs/smbfs_smb.c 163993 2006-11-05 06:38:42Z bp $
3375374Sbp */
3475374Sbp#include <sys/param.h>
3575374Sbp#include <sys/systm.h>
3675374Sbp#include <sys/kernel.h>
3775374Sbp#include <sys/malloc.h>
3875374Sbp#include <sys/proc.h>
3975374Sbp#include <sys/lock.h>
4075374Sbp#include <sys/vnode.h>
4175374Sbp#include <sys/mbuf.h>
4275374Sbp#include <sys/mount.h>
4375374Sbp
4475374Sbp#ifdef USE_MD5_HASH
4575374Sbp#include <sys/md5.h>
4675374Sbp#endif
4775374Sbp
4875374Sbp#include <netsmb/smb.h>
4975374Sbp#include <netsmb/smb_subr.h>
5075374Sbp#include <netsmb/smb_rq.h>
5175374Sbp#include <netsmb/smb_conn.h>
5275374Sbp
5375374Sbp#include <fs/smbfs/smbfs.h>
5475374Sbp#include <fs/smbfs/smbfs_node.h>
5575374Sbp#include <fs/smbfs/smbfs_subr.h>
5675374Sbp
5775374Sbp/*
5875374Sbp * Lack of inode numbers leads us to the problem of generating them.
5975374Sbp * Partially this problem can be solved by having a dir/file cache
6075374Sbp * with inode numbers generated from the incremented by one counter.
6175374Sbp * However this way will require too much kernel memory, gives all
6275374Sbp * sorts of locking and consistency problems, not to mentinon counter overflows.
6375374Sbp * So, I'm decided to use a hash function to generate pseudo random (and unique)
6475374Sbp * inode numbers.
6575374Sbp */
6675374Sbpstatic long
6775374Sbpsmbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
6875374Sbp{
6975374Sbp#ifdef USE_MD5_HASH
7075374Sbp	MD5_CTX md5;
7175374Sbp	u_int32_t state[4];
7275374Sbp	long ino;
7375374Sbp	int i;
7475374Sbp
7575374Sbp	MD5Init(&md5);
7675374Sbp	MD5Update(&md5, name, nmlen);
7775374Sbp	MD5Final((u_char *)state, &md5);
7875374Sbp	for (i = 0, ino = 0; i < 4; i++)
7975374Sbp		ino += state[i];
8075374Sbp	return dnp->n_ino + ino;
8175374Sbp#endif
8275374Sbp	u_int32_t ino;
8375374Sbp
8475374Sbp	ino = dnp->n_ino + smbfs_hash(name, nmlen);
8575374Sbp	if (ino <= 2)
8675374Sbp		ino += 3;
8775374Sbp	return ino;
8875374Sbp}
8975374Sbp
9075374Sbpstatic int
9175374Sbpsmbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end,
9275374Sbp	struct smb_cred *scred)
9375374Sbp{
9475374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
9575374Sbp	struct smb_rq rq, *rqp = &rq;
9675374Sbp	struct mbchain *mbp;
9775374Sbp	u_char ltype = 0;
9875374Sbp	int error;
9975374Sbp
10075374Sbp	if (op == SMB_LOCK_SHARED)
10175374Sbp		ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
10275374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred);
10375374Sbp	if (error)
10475374Sbp		return error;
10575374Sbp	smb_rq_getrequest(rqp, &mbp);
10675374Sbp	smb_rq_wstart(rqp);
107103533Sbp	mb_put_uint8(mbp, 0xff);	/* secondary command */
10875374Sbp	mb_put_uint8(mbp, 0);		/* MBZ */
10975374Sbp	mb_put_uint16le(mbp, 0);
11075374Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
11175374Sbp	mb_put_uint8(mbp, ltype);	/* locktype */
11275374Sbp	mb_put_uint8(mbp, 0);		/* oplocklevel - 0 seems is NO_OPLOCK */
113103533Sbp	mb_put_uint32le(mbp, 0);	/* timeout - break immediately */
11475374Sbp	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
11575374Sbp	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
11675374Sbp	smb_rq_wend(rqp);
11775374Sbp	smb_rq_bstart(rqp);
11875374Sbp	mb_put_uint16le(mbp, pid);
11975374Sbp	mb_put_uint32le(mbp, start);
12075374Sbp	mb_put_uint32le(mbp, end - start);
12175374Sbp	smb_rq_bend(rqp);
12275374Sbp	error = smb_rq_simple(rqp);
12375374Sbp	smb_rq_done(rqp);
12475374Sbp	return error;
12575374Sbp}
12675374Sbp
12775374Sbpint
12875374Sbpsmbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
12975374Sbp	off_t start, off_t end,	struct smb_cred *scred)
13075374Sbp{
13175374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
13275374Sbp
13375374Sbp	if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
13475374Sbp		/*
13575374Sbp		 * TODO: use LOCK_BYTE_RANGE here.
13675374Sbp		 */
13775374Sbp		return EINVAL;
13875374Sbp	else
139106595Sjhb		return smbfs_smb_lockandx(np, op, (uintptr_t)id, start, end, scred);
14075374Sbp}
14175374Sbp
142103533Sbpstatic int
143103533Sbpsmbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap,
144103533Sbp		    struct smb_cred *scred, short infolevel)
145103533Sbp{
146103533Sbp	struct smb_share *ssp = np->n_mount->sm_share;
147103533Sbp	struct smb_vc *vcp = SSTOVC(ssp);
148103533Sbp	struct smb_t2rq *t2p;
149103533Sbp	int error, svtz, timesok = 1;
150103533Sbp	struct mbchain *mbp;
151103533Sbp	struct mdchain *mdp;
152103533Sbp	u_int16_t date, time, wattr;
153103533Sbp	int64_t lint;
154103533Sbp	u_int32_t size, dattr;
155103533Sbp
156103533Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION,
157103533Sbp			     scred, &t2p);
158103533Sbp	if (error)
159103533Sbp		return error;
160103533Sbp	mbp = &t2p->t2_tparam;
161103533Sbp	mb_init(mbp);
162103533Sbp	if (!infolevel) {
163103533Sbp		if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
164103533Sbp			infolevel = SMB_QUERY_FILE_STANDARD;
165103533Sbp		else
166103533Sbp			infolevel = SMB_QUERY_FILE_BASIC_INFO;
167103533Sbp	}
168103533Sbp	mb_put_uint16le(mbp, infolevel);
169103533Sbp	mb_put_uint32le(mbp, 0);
170103533Sbp	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
171103533Sbp	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
172103533Sbp	if (error) {
173103533Sbp		smb_t2_done(t2p);
174103533Sbp		return error;
175103533Sbp	}
176103533Sbp	t2p->t2_maxpcount = 2;
177103533Sbp	t2p->t2_maxdcount = vcp->vc_txmax;
178103533Sbp	error = smb_t2_request(t2p);
179103533Sbp	if (error) {
180103533Sbp		smb_t2_done(t2p);
181103533Sbp		if (infolevel == SMB_QUERY_FILE_STANDARD || error != EINVAL)
182103533Sbp			return error;
183103533Sbp		return smbfs_smb_qpathinfo(np, fap, scred,
184103533Sbp					   SMB_QUERY_FILE_STANDARD);
185103533Sbp	}
186103533Sbp	mdp = &t2p->t2_rdata;
187103533Sbp	svtz = vcp->vc_sopt.sv_tz;
188103533Sbp	switch (infolevel) {
189103533Sbp	    case SMB_QUERY_FILE_STANDARD:
190103533Sbp		timesok = 0;
191103533Sbp		md_get_uint16le(mdp, NULL);
192103533Sbp		md_get_uint16le(mdp, NULL);	/* creation time */
193103533Sbp		md_get_uint16le(mdp, &date);
194103533Sbp		md_get_uint16le(mdp, &time);	/* access time */
195103533Sbp		if (date || time) {
196103533Sbp			timesok++;
197103533Sbp			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
198103533Sbp		}
199103533Sbp		md_get_uint16le(mdp, &date);
200103533Sbp		md_get_uint16le(mdp, &time);	/* modify time */
201103533Sbp		if (date || time) {
202103533Sbp			timesok++;
203103533Sbp			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
204103533Sbp		}
205103533Sbp		md_get_uint32le(mdp, &size);
206103533Sbp		fap->fa_size = size;
207103533Sbp		md_get_uint32(mdp, NULL);	/* allocation size */
208103533Sbp		md_get_uint16le(mdp, &wattr);
209103533Sbp		fap->fa_attr = wattr;
210103533Sbp		break;
211103533Sbp	    case SMB_QUERY_FILE_BASIC_INFO:
212103533Sbp		timesok = 0;
213103533Sbp		md_get_int64(mdp, NULL);	/* creation time */
214103533Sbp		md_get_int64le(mdp, &lint);
215103533Sbp		if (lint) {
216103533Sbp			timesok++;
217103533Sbp			smb_time_NT2local(lint, svtz, &fap->fa_atime);
218103533Sbp		}
219103533Sbp		md_get_int64le(mdp, &lint);
220103533Sbp		if (lint) {
221103533Sbp			timesok++;
222103533Sbp			smb_time_NT2local(lint, svtz, &fap->fa_mtime);
223103533Sbp		}
224103533Sbp		md_get_int64le(mdp, &lint);
225103533Sbp		if (lint) {
226103533Sbp			timesok++;
227103533Sbp			smb_time_NT2local(lint, svtz, &fap->fa_ctime);
228103533Sbp		}
229103533Sbp		md_get_uint32le(mdp, &dattr);
230103533Sbp		fap->fa_attr = dattr;
231103533Sbp		md_get_uint32(mdp, NULL);
232103533Sbp		/* XXX could use ALL_INFO to get size */
233103533Sbp		break;
234103533Sbp	    default:
235103533Sbp		SMBERROR("unexpected info level %d\n", infolevel);
236103533Sbp		error = EINVAL;
237103533Sbp	}
238103533Sbp	smb_t2_done(t2p);
239103533Sbp	/*
240103533Sbp	 * if all times are zero (observed with FAT on NT4SP6)
241103533Sbp	 * then fall back to older info level
242103533Sbp	 */
243103533Sbp	if (!timesok) {
244103533Sbp		if (infolevel != SMB_QUERY_FILE_STANDARD)
245103533Sbp			return smbfs_smb_qpathinfo(np, fap, scred,
246103533Sbp						   SMB_QUERY_FILE_STANDARD);
247103533Sbp		error = EINVAL;
248103533Sbp	}
249103533Sbp	return error;
250103533Sbp}
251103533Sbp
25275374Sbpint
25375374Sbpsmbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp,
25475374Sbp	struct smb_cred *scred)
25575374Sbp{
25675374Sbp	struct smb_t2rq *t2p;
25775374Sbp	struct mbchain *mbp;
25875374Sbp	struct mdchain *mdp;
25975374Sbp	u_int16_t bsize;
26075374Sbp	u_int32_t units, bpu, funits;
26175374Sbp	int error;
26275374Sbp
26375374Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
26475374Sbp	    scred, &t2p);
26575374Sbp	if (error)
26675374Sbp		return error;
26775374Sbp	mbp = &t2p->t2_tparam;
26875374Sbp	mb_init(mbp);
26975374Sbp	mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
27075374Sbp	t2p->t2_maxpcount = 4;
27175374Sbp	t2p->t2_maxdcount = 4 * 4 + 2;
27275374Sbp	error = smb_t2_request(t2p);
27375374Sbp	if (error) {
27475374Sbp		smb_t2_done(t2p);
27575374Sbp		return error;
27675374Sbp	}
27775374Sbp	mdp = &t2p->t2_rdata;
27875374Sbp	md_get_uint32(mdp, NULL);	/* fs id */
27975374Sbp	md_get_uint32le(mdp, &bpu);
28075374Sbp	md_get_uint32le(mdp, &units);
28175374Sbp	md_get_uint32le(mdp, &funits);
28275374Sbp	md_get_uint16le(mdp, &bsize);
28396755Strhodes	sbp->f_bsize = bpu * bsize;	/* fundamental filesystem block size */
28496755Strhodes	sbp->f_blocks= units;		/* total data blocks in filesystem */
28575374Sbp	sbp->f_bfree = funits;		/* free blocks in fs */
28675374Sbp	sbp->f_bavail= funits;		/* free blocks avail to non-superuser */
28796755Strhodes	sbp->f_files = 0xffff;		/* total file nodes in filesystem */
28875374Sbp	sbp->f_ffree = 0xffff;		/* free file nodes in fs */
28975374Sbp	smb_t2_done(t2p);
29075374Sbp	return 0;
29175374Sbp}
29275374Sbp
29375374Sbpint
29475374Sbpsmbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
29575374Sbp	struct smb_cred *scred)
29675374Sbp{
29775374Sbp	struct smb_rq rq, *rqp = &rq;
29875374Sbp	struct mdchain *mdp;
29975374Sbp	u_int16_t units, bpu, bsize, funits;
30075374Sbp	int error;
30175374Sbp
30275374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, scred);
30375374Sbp	if (error)
30475374Sbp		return error;
30575374Sbp	smb_rq_wstart(rqp);
30675374Sbp	smb_rq_wend(rqp);
30775374Sbp	smb_rq_bstart(rqp);
30875374Sbp	smb_rq_bend(rqp);
30975374Sbp	error = smb_rq_simple(rqp);
31075374Sbp	if (error) {
31175374Sbp		smb_rq_done(rqp);
31275374Sbp		return error;
31375374Sbp	}
31475374Sbp	smb_rq_getreply(rqp, &mdp);
31575374Sbp	md_get_uint16le(mdp, &units);
31675374Sbp	md_get_uint16le(mdp, &bpu);
31775374Sbp	md_get_uint16le(mdp, &bsize);
31875374Sbp	md_get_uint16le(mdp, &funits);
31996755Strhodes	sbp->f_bsize = bpu * bsize;	/* fundamental filesystem block size */
32096755Strhodes	sbp->f_blocks= units;		/* total data blocks in filesystem */
32175374Sbp	sbp->f_bfree = funits;		/* free blocks in fs */
32275374Sbp	sbp->f_bavail= funits;		/* free blocks avail to non-superuser */
32396755Strhodes	sbp->f_files = 0xffff;		/* total file nodes in filesystem */
32475374Sbp	sbp->f_ffree = 0xffff;		/* free file nodes in fs */
32575374Sbp	smb_rq_done(rqp);
32675374Sbp	return 0;
32775374Sbp}
32875374Sbp
329103533Sbpstatic int
330103533Sbpsmbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
331103533Sbp{
332103533Sbp	struct smb_t2rq *t2p;
333103533Sbp	struct smb_share *ssp = np->n_mount->sm_share;
334103533Sbp	struct mbchain *mbp;
335103533Sbp	int error;
336103533Sbp
337103533Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
338103533Sbp	    scred, &t2p);
339103533Sbp	if (error)
340103533Sbp		return error;
341103533Sbp	mbp = &t2p->t2_tparam;
342103533Sbp	mb_init(mbp);
343103533Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
344103533Sbp	mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO);
345103533Sbp	mb_put_uint32le(mbp, 0);
346103533Sbp	mbp = &t2p->t2_tdata;
347103533Sbp	mb_init(mbp);
348103533Sbp	mb_put_int64le(mbp, newsize);
349103533Sbp	mb_put_uint32le(mbp, 0);			/* padding */
350103533Sbp	mb_put_uint16le(mbp, 0);
351103533Sbp	t2p->t2_maxpcount = 2;
352103533Sbp	t2p->t2_maxdcount = 0;
353103533Sbp	error = smb_t2_request(t2p);
354103533Sbp	smb_t2_done(t2p);
355103533Sbp	return error;
356103533Sbp}
357103533Sbp
358103533Sbpstatic int
359103533Sbpsmb_smb_flush(struct smbnode *np, struct smb_cred *scred)
360103533Sbp{
361103533Sbp	struct smb_share *ssp = np->n_mount->sm_share;
362103533Sbp	struct smb_rq rq, *rqp = &rq;
363103533Sbp	struct mbchain *mbp;
364103533Sbp	int error;
365103533Sbp
366124434Stjr	if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) ||
367116486Stjr	    SMBTOV(np)->v_type != VREG)
368108470Sschweikh		return 0; /* not a regular open file */
369103533Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scred);
370103533Sbp	if (error)
371103533Sbp		return (error);
372103533Sbp	smb_rq_getrequest(rqp, &mbp);
373103533Sbp	smb_rq_wstart(rqp);
374103533Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
375103533Sbp	smb_rq_wend(rqp);
376103533Sbp	smb_rq_bstart(rqp);
377103533Sbp	smb_rq_bend(rqp);
378103533Sbp	error = smb_rq_simple(rqp);
379103533Sbp	smb_rq_done(rqp);
380103533Sbp	if (!error)
381103533Sbp		np->n_flag &= ~NFLUSHWIRE;
382103533Sbp	return (error);
383103533Sbp}
384103533Sbp
38575374Sbpint
386103533Sbpsmbfs_smb_flush(struct smbnode *np, struct smb_cred *scred)
387103533Sbp{
388103533Sbp	if (np->n_flag & NFLUSHWIRE)
389103533Sbp		return (smb_smb_flush(np, scred));
390103533Sbp	return (0);
391103533Sbp}
392103533Sbp
393103533Sbpint
39475374Sbpsmbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred)
39575374Sbp{
39675374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
39775374Sbp	struct smb_rq rq, *rqp = &rq;
39875374Sbp	struct mbchain *mbp;
39975374Sbp	int error;
40075374Sbp
401103533Sbp	if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) {
402103533Sbp		np->n_flag |= NFLUSHWIRE;
403103533Sbp		return (0);
404103533Sbp	}
405103533Sbp
40675374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred);
40775374Sbp	if (error)
40875374Sbp		return error;
40975374Sbp	smb_rq_getrequest(rqp, &mbp);
41075374Sbp	smb_rq_wstart(rqp);
41175374Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
41275374Sbp	mb_put_uint16le(mbp, 0);
41375374Sbp	mb_put_uint32le(mbp, newsize);
41475374Sbp	mb_put_uint16le(mbp, 0);
41575374Sbp	smb_rq_wend(rqp);
41675374Sbp	smb_rq_bstart(rqp);
41775374Sbp	mb_put_uint8(mbp, SMB_DT_DATA);
41875374Sbp	mb_put_uint16le(mbp, 0);
41975374Sbp	smb_rq_bend(rqp);
42075374Sbp	error = smb_rq_simple(rqp);
42175374Sbp	smb_rq_done(rqp);
42275374Sbp	return error;
42375374Sbp}
42475374Sbp
425103533Sbpint
426103533Sbpsmbfs_smb_query_info(struct smbnode *np, const char *name, int len,
427103533Sbp		     struct smbfattr *fap, struct smb_cred *scred)
428103533Sbp{
429103533Sbp	struct smb_rq rq, *rqp = &rq;
430103533Sbp	struct smb_share *ssp = np->n_mount->sm_share;
431103533Sbp	struct mbchain *mbp;
432103533Sbp	struct mdchain *mdp;
433103533Sbp	u_int8_t wc;
434103533Sbp	int error;
435103533Sbp	u_int16_t wattr;
436103533Sbp	u_int32_t lint;
43775374Sbp
438103533Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred);
439103533Sbp	if (error)
440103533Sbp		return error;
441103533Sbp	smb_rq_getrequest(rqp, &mbp);
442103533Sbp	smb_rq_wstart(rqp);
443103533Sbp	smb_rq_wend(rqp);
444103533Sbp	smb_rq_bstart(rqp);
445103533Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
446103533Sbp	do {
447103533Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len);
448103533Sbp		if (error)
449103533Sbp			break;
450103533Sbp		smb_rq_bend(rqp);
451103533Sbp		error = smb_rq_simple(rqp);
452103533Sbp		if (error)
453103533Sbp			break;
454103533Sbp		smb_rq_getreply(rqp, &mdp);
455103533Sbp		if (md_get_uint8(mdp, &wc) != 0 || wc != 10) {
456103533Sbp			error = EBADRPC;
457103533Sbp			break;
458103533Sbp		}
459103533Sbp		md_get_uint16le(mdp, &wattr);
460103533Sbp		fap->fa_attr = wattr;
461103533Sbp		/*
462103533Sbp		 * Be careful using the time returned here, as
463103533Sbp		 * with FAT on NT4SP6, at least, the time returned is low
464103533Sbp		 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
465103533Sbp		 * over about every seven minutes!
466103533Sbp		 */
467103533Sbp		md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */
468103533Sbp		if (lint)	/* avoid bogus zero returns */
469103533Sbp			smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz,
470103533Sbp					      &fap->fa_mtime);
471103533Sbp		md_get_uint32le(mdp, &lint);
472103533Sbp		fap->fa_size = lint;
473103533Sbp	} while(0);
474103533Sbp	smb_rq_done(rqp);
475103533Sbp	return error;
476103533Sbp}
477103533Sbp
47875374Sbp/*
47975374Sbp * Set DOS file attributes. mtime should be NULL for dialects above lm10
48075374Sbp */
48175374Sbpint
48275374Sbpsmbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
48375374Sbp	struct smb_cred *scred)
48475374Sbp{
48575374Sbp	struct smb_rq rq, *rqp = &rq;
48675374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
48775374Sbp	struct mbchain *mbp;
48875374Sbp	u_long time;
48975374Sbp	int error, svtz;
49075374Sbp
49175374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred);
49275374Sbp	if (error)
49375374Sbp		return error;
49475374Sbp	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
49575374Sbp	smb_rq_getrequest(rqp, &mbp);
49675374Sbp	smb_rq_wstart(rqp);
49775374Sbp	mb_put_uint16le(mbp, attr);
49875374Sbp	if (mtime) {
49975374Sbp		smb_time_local2server(mtime, svtz, &time);
50075374Sbp	} else
50175374Sbp		time = 0;
50275374Sbp	mb_put_uint32le(mbp, time);		/* mtime */
50375374Sbp	mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
50475374Sbp	smb_rq_wend(rqp);
50575374Sbp	smb_rq_bstart(rqp);
50675374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
50775374Sbp	do {
50875374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
50975374Sbp		if (error)
51075374Sbp			break;
51175374Sbp		mb_put_uint8(mbp, SMB_DT_ASCII);
51275374Sbp		mb_put_uint8(mbp, 0);
51375374Sbp		smb_rq_bend(rqp);
51475374Sbp		error = smb_rq_simple(rqp);
515163993Sbp		if (error) {
516163993Sbp			SMBERROR("smb_rq_simple(rqp) => error %d\n", error);
51775374Sbp			break;
518163993Sbp		}
51975374Sbp	} while(0);
52075374Sbp	smb_rq_done(rqp);
52175374Sbp	return error;
52275374Sbp}
52375374Sbp
52475374Sbp/*
52575374Sbp * Note, win95 doesn't support this call.
52675374Sbp */
52775374Sbpint
52875374Sbpsmbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
52975374Sbp	struct timespec *atime, int attr, struct smb_cred *scred)
53075374Sbp{
53175374Sbp	struct smb_t2rq *t2p;
53275374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
53375374Sbp	struct smb_vc *vcp = SSTOVC(ssp);
53475374Sbp	struct mbchain *mbp;
53575374Sbp	u_int16_t date, time;
53675374Sbp	int error, tzoff;
53775374Sbp
53875374Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
53975374Sbp	    scred, &t2p);
54075374Sbp	if (error)
54175374Sbp		return error;
54275374Sbp	mbp = &t2p->t2_tparam;
54375374Sbp	mb_init(mbp);
54475374Sbp	mb_put_uint16le(mbp, SMB_INFO_STANDARD);
54575374Sbp	mb_put_uint32le(mbp, 0);		/* MBZ */
546103533Sbp	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
54775374Sbp	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
54875374Sbp	if (error) {
54975374Sbp		smb_t2_done(t2p);
55075374Sbp		return error;
55175374Sbp	}
55275374Sbp	tzoff = vcp->vc_sopt.sv_tz;
55375374Sbp	mbp = &t2p->t2_tdata;
55475374Sbp	mb_init(mbp);
55575374Sbp	mb_put_uint32le(mbp, 0);		/* creation time */
55675374Sbp	if (atime)
55775374Sbp		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
55875374Sbp	else
55975374Sbp		time = date = 0;
56075374Sbp	mb_put_uint16le(mbp, date);
56175374Sbp	mb_put_uint16le(mbp, time);
56275374Sbp	if (mtime)
56375374Sbp		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
56475374Sbp	else
56575374Sbp		time = date = 0;
56675374Sbp	mb_put_uint16le(mbp, date);
56775374Sbp	mb_put_uint16le(mbp, time);
56875374Sbp	mb_put_uint32le(mbp, 0);		/* file size */
56975374Sbp	mb_put_uint32le(mbp, 0);		/* allocation unit size */
57075374Sbp	mb_put_uint16le(mbp, attr);	/* DOS attr */
57175374Sbp	mb_put_uint32le(mbp, 0);		/* EA size */
57275374Sbp	t2p->t2_maxpcount = 5 * 2;
57375374Sbp	t2p->t2_maxdcount = vcp->vc_txmax;
57475374Sbp	error = smb_t2_request(t2p);
57575374Sbp	smb_t2_done(t2p);
57675374Sbp	return error;
57775374Sbp}
57875374Sbp
57975374Sbp/*
58075374Sbp * NT level. Specially for win9x
58175374Sbp */
58275374Sbpint
58375374Sbpsmbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
58475374Sbp	struct timespec *atime, struct smb_cred *scred)
58575374Sbp{
58675374Sbp	struct smb_t2rq *t2p;
58775374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
58875374Sbp	struct smb_vc *vcp = SSTOVC(ssp);
58975374Sbp	struct mbchain *mbp;
59075374Sbp	int64_t tm;
59175374Sbp	int error, tzoff;
59275374Sbp
59375374Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
59475374Sbp	    scred, &t2p);
59575374Sbp	if (error)
59675374Sbp		return error;
59775374Sbp	mbp = &t2p->t2_tparam;
59875374Sbp	mb_init(mbp);
59975374Sbp	mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
60075374Sbp	mb_put_uint32le(mbp, 0);		/* MBZ */
601103533Sbp	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
60275374Sbp	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
60375374Sbp	if (error) {
60475374Sbp		smb_t2_done(t2p);
60575374Sbp		return error;
60675374Sbp	}
60775374Sbp	tzoff = vcp->vc_sopt.sv_tz;
60875374Sbp	mbp = &t2p->t2_tdata;
60975374Sbp	mb_init(mbp);
61075374Sbp	mb_put_int64le(mbp, 0);		/* creation time */
61175374Sbp	if (atime) {
61275374Sbp		smb_time_local2NT(atime, tzoff, &tm);
61375374Sbp	} else
61475374Sbp		tm = 0;
61575374Sbp	mb_put_int64le(mbp, tm);
61675374Sbp	if (mtime) {
61775374Sbp		smb_time_local2NT(mtime, tzoff, &tm);
61875374Sbp	} else
61975374Sbp		tm = 0;
62075374Sbp	mb_put_int64le(mbp, tm);
62175374Sbp	mb_put_int64le(mbp, tm);		/* change time */
62275374Sbp	mb_put_uint32le(mbp, attr);		/* attr */
62375374Sbp	t2p->t2_maxpcount = 24;
62475374Sbp	t2p->t2_maxdcount = 56;
62575374Sbp	error = smb_t2_request(t2p);
62675374Sbp	smb_t2_done(t2p);
62775374Sbp	return error;
62875374Sbp}
62975374Sbp
63075374Sbp/*
63175374Sbp * Set file atime and mtime. Doesn't supported by core dialect.
63275374Sbp */
63375374Sbpint
63475374Sbpsmbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
63575374Sbp	struct timespec *atime, struct smb_cred *scred)
63675374Sbp{
63775374Sbp	struct smb_rq rq, *rqp = &rq;
63875374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
63975374Sbp	struct mbchain *mbp;
64075374Sbp	u_int16_t date, time;
64175374Sbp	int error, tzoff;
64275374Sbp
64375374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred);
64475374Sbp	if (error)
64575374Sbp		return error;
64675374Sbp	tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
64775374Sbp	smb_rq_getrequest(rqp, &mbp);
64875374Sbp	smb_rq_wstart(rqp);
64975374Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
65075374Sbp	mb_put_uint32le(mbp, 0);		/* creation time */
65175374Sbp
65275374Sbp	if (atime)
65375374Sbp		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
65475374Sbp	else
65575374Sbp		time = date = 0;
65675374Sbp	mb_put_uint16le(mbp, date);
65775374Sbp	mb_put_uint16le(mbp, time);
65875374Sbp	if (mtime)
65975374Sbp		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
66075374Sbp	else
66175374Sbp		time = date = 0;
66275374Sbp	mb_put_uint16le(mbp, date);
66375374Sbp	mb_put_uint16le(mbp, time);
66475374Sbp	smb_rq_wend(rqp);
66575374Sbp	smb_rq_bstart(rqp);
66675374Sbp	smb_rq_bend(rqp);
66775374Sbp	error = smb_rq_simple(rqp);
66875374Sbp	SMBSDEBUG("%d\n", error);
66975374Sbp	smb_rq_done(rqp);
67075374Sbp	return error;
67175374Sbp}
67275374Sbp
67375374Sbp/*
67475374Sbp * Set DOS file attributes.
67575374Sbp * Looks like this call can be used only if CAP_NT_SMBS bit is on.
67675374Sbp */
67775374Sbpint
67875374Sbpsmbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
67975374Sbp	struct timespec *atime, struct smb_cred *scred)
68075374Sbp{
68175374Sbp	struct smb_t2rq *t2p;
68275374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
68375374Sbp	struct mbchain *mbp;
68475374Sbp	int64_t tm;
68575374Sbp	int error, svtz;
68675374Sbp
68775374Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
68875374Sbp	    scred, &t2p);
68975374Sbp	if (error)
69075374Sbp		return error;
69175374Sbp	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
69275374Sbp	mbp = &t2p->t2_tparam;
69375374Sbp	mb_init(mbp);
69475374Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
69575374Sbp	mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
69675374Sbp	mb_put_uint32le(mbp, 0);
69775374Sbp	mbp = &t2p->t2_tdata;
69875374Sbp	mb_init(mbp);
69975374Sbp	mb_put_int64le(mbp, 0);		/* creation time */
70075374Sbp	if (atime) {
70175374Sbp		smb_time_local2NT(atime, svtz, &tm);
70275374Sbp	} else
70375374Sbp		tm = 0;
70475374Sbp	mb_put_int64le(mbp, tm);
70575374Sbp	if (mtime) {
70675374Sbp		smb_time_local2NT(mtime, svtz, &tm);
70775374Sbp	} else
70875374Sbp		tm = 0;
70975374Sbp	mb_put_int64le(mbp, tm);
71075374Sbp	mb_put_int64le(mbp, tm);		/* change time */
71175374Sbp	mb_put_uint16le(mbp, attr);
71275374Sbp	mb_put_uint32le(mbp, 0);			/* padding */
71375374Sbp	mb_put_uint16le(mbp, 0);
71475374Sbp	t2p->t2_maxpcount = 2;
71575374Sbp	t2p->t2_maxdcount = 0;
71675374Sbp	error = smb_t2_request(t2p);
71775374Sbp	smb_t2_done(t2p);
71875374Sbp	return error;
71975374Sbp}
72075374Sbp
72175374Sbp
72275374Sbpint
72375374Sbpsmbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
72475374Sbp{
72575374Sbp	struct smb_rq rq, *rqp = &rq;
72675374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
72775374Sbp	struct mbchain *mbp;
72875374Sbp	struct mdchain *mdp;
72975374Sbp	u_int8_t wc;
73075374Sbp	u_int16_t fid, wattr, grantedmode;
73175374Sbp	int error;
73275374Sbp
73375374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred);
73475374Sbp	if (error)
73575374Sbp		return error;
73675374Sbp	smb_rq_getrequest(rqp, &mbp);
73775374Sbp	smb_rq_wstart(rqp);
73875374Sbp	mb_put_uint16le(mbp, accmode);
73975374Sbp	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
74075374Sbp	smb_rq_wend(rqp);
74175374Sbp	smb_rq_bstart(rqp);
74275374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
74375374Sbp	do {
74475374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
74575374Sbp		if (error)
74675374Sbp			break;
74775374Sbp		smb_rq_bend(rqp);
74875374Sbp		error = smb_rq_simple(rqp);
74975374Sbp		if (error)
75075374Sbp			break;
75175374Sbp		smb_rq_getreply(rqp, &mdp);
75275374Sbp		if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
75375374Sbp			error = EBADRPC;
75475374Sbp			break;
75575374Sbp		}
75675374Sbp		md_get_uint16(mdp, &fid);
75775374Sbp		md_get_uint16le(mdp, &wattr);
75875374Sbp		md_get_uint32(mdp, NULL);	/* mtime */
75975374Sbp		md_get_uint32(mdp, NULL);	/* fsize */
76075374Sbp		md_get_uint16le(mdp, &grantedmode);
76175374Sbp		/*
76275374Sbp		 * TODO: refresh attributes from this reply
76375374Sbp		 */
76475374Sbp	} while(0);
76575374Sbp	smb_rq_done(rqp);
76675374Sbp	if (error)
76775374Sbp		return error;
76875374Sbp	np->n_fid = fid;
76975374Sbp	np->n_rwstate = grantedmode;
77075374Sbp	return 0;
77175374Sbp}
77275374Sbp
77375374Sbp
77475374Sbpint
77575374Sbpsmbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
77675374Sbp	struct smb_cred *scred)
77775374Sbp{
77875374Sbp	struct smb_rq rq, *rqp = &rq;
77975374Sbp	struct mbchain *mbp;
78075374Sbp	u_long time;
78175374Sbp	int error;
78275374Sbp
78375374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred);
78475374Sbp	if (error)
78575374Sbp		return error;
78675374Sbp	smb_rq_getrequest(rqp, &mbp);
78775374Sbp	smb_rq_wstart(rqp);
78875374Sbp	mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
78975374Sbp	if (mtime) {
79075374Sbp		smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
79175374Sbp	} else
79275374Sbp		time = 0;
79375374Sbp	mb_put_uint32le(mbp, time);
79475374Sbp	smb_rq_wend(rqp);
79575374Sbp	smb_rq_bstart(rqp);
79675374Sbp	smb_rq_bend(rqp);
79775374Sbp	error = smb_rq_simple(rqp);
79875374Sbp	smb_rq_done(rqp);
79975374Sbp	return error;
80075374Sbp}
80175374Sbp
80275374Sbpint
80375374Sbpsmbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
80475374Sbp	struct smb_cred *scred)
80575374Sbp{
80675374Sbp	struct smb_rq rq, *rqp = &rq;
80775374Sbp	struct smb_share *ssp = dnp->n_mount->sm_share;
80875374Sbp	struct mbchain *mbp;
80975374Sbp	struct mdchain *mdp;
81075374Sbp	struct timespec ctime;
81175374Sbp	u_int8_t wc;
81275374Sbp	u_int16_t fid;
81375374Sbp	u_long tm;
81475374Sbp	int error;
81575374Sbp
81675374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred);
81775374Sbp	if (error)
81875374Sbp		return error;
81975374Sbp	smb_rq_getrequest(rqp, &mbp);
82075374Sbp	smb_rq_wstart(rqp);
82175374Sbp	mb_put_uint16le(mbp, SMB_FA_ARCHIVE);		/* attributes  */
82275374Sbp	nanotime(&ctime);
82375374Sbp	smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
82475374Sbp	mb_put_uint32le(mbp, tm);
82575374Sbp	smb_rq_wend(rqp);
82675374Sbp	smb_rq_bstart(rqp);
82775374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
82875374Sbp	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen);
82975374Sbp	if (!error) {
83075374Sbp		smb_rq_bend(rqp);
83175374Sbp		error = smb_rq_simple(rqp);
83275374Sbp		if (!error) {
83375374Sbp			smb_rq_getreply(rqp, &mdp);
83475374Sbp			md_get_uint8(mdp, &wc);
83575374Sbp			if (wc == 1)
83675374Sbp				md_get_uint16(mdp, &fid);
83775374Sbp			else
83875374Sbp				error = EBADRPC;
83975374Sbp		}
84075374Sbp	}
84175374Sbp	smb_rq_done(rqp);
84275374Sbp	if (error)
84375374Sbp		return error;
84475374Sbp	smbfs_smb_close(ssp, fid, &ctime, scred);
84575374Sbp	return error;
84675374Sbp}
84775374Sbp
84875374Sbpint
84975374Sbpsmbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
85075374Sbp{
85175374Sbp	struct smb_rq rq, *rqp = &rq;
85275374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
85375374Sbp	struct mbchain *mbp;
85475374Sbp	int error;
85575374Sbp
85675374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred);
85775374Sbp	if (error)
85875374Sbp		return error;
85975374Sbp	smb_rq_getrequest(rqp, &mbp);
86075374Sbp	smb_rq_wstart(rqp);
86175374Sbp	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
86275374Sbp	smb_rq_wend(rqp);
86375374Sbp	smb_rq_bstart(rqp);
86475374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
86575374Sbp	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
86675374Sbp	if (!error) {
86775374Sbp		smb_rq_bend(rqp);
86875374Sbp		error = smb_rq_simple(rqp);
86975374Sbp	}
87075374Sbp	smb_rq_done(rqp);
87175374Sbp	return error;
87275374Sbp}
87375374Sbp
87475374Sbpint
87575374Sbpsmbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
87675374Sbp	const char *tname, int tnmlen, struct smb_cred *scred)
87775374Sbp{
87875374Sbp	struct smb_rq rq, *rqp = &rq;
87975374Sbp	struct smb_share *ssp = src->n_mount->sm_share;
88075374Sbp	struct mbchain *mbp;
88175374Sbp	int error;
88275374Sbp
88375374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred);
88475374Sbp	if (error)
88575374Sbp		return error;
88675374Sbp	smb_rq_getrequest(rqp, &mbp);
88775374Sbp	smb_rq_wstart(rqp);
88875374Sbp	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
88975374Sbp	smb_rq_wend(rqp);
89075374Sbp	smb_rq_bstart(rqp);
89175374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
89275374Sbp	do {
89375374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
89475374Sbp		if (error)
89575374Sbp			break;
89675374Sbp		mb_put_uint8(mbp, SMB_DT_ASCII);
89775374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
89875374Sbp		if (error)
89975374Sbp			break;
90075374Sbp		smb_rq_bend(rqp);
90175374Sbp		error = smb_rq_simple(rqp);
90275374Sbp	} while(0);
90375374Sbp	smb_rq_done(rqp);
90475374Sbp	return error;
90575374Sbp}
90675374Sbp
90775374Sbpint
90875374Sbpsmbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
90975374Sbp	const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
91075374Sbp{
91175374Sbp	struct smb_rq rq, *rqp = &rq;
91275374Sbp	struct smb_share *ssp = src->n_mount->sm_share;
91375374Sbp	struct mbchain *mbp;
91475374Sbp	int error;
91575374Sbp
91675374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred);
91775374Sbp	if (error)
91875374Sbp		return error;
91975374Sbp	smb_rq_getrequest(rqp, &mbp);
92075374Sbp	smb_rq_wstart(rqp);
92175374Sbp	mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
92275374Sbp	mb_put_uint16le(mbp, 0x20);	/* delete target file */
92375374Sbp	mb_put_uint16le(mbp, flags);
92475374Sbp	smb_rq_wend(rqp);
92575374Sbp	smb_rq_bstart(rqp);
92675374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
92775374Sbp	do {
92875374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
92975374Sbp		if (error)
93075374Sbp			break;
93175374Sbp		mb_put_uint8(mbp, SMB_DT_ASCII);
93275374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
93375374Sbp		if (error)
93475374Sbp			break;
93575374Sbp		smb_rq_bend(rqp);
93675374Sbp		error = smb_rq_simple(rqp);
93775374Sbp	} while(0);
93875374Sbp	smb_rq_done(rqp);
93975374Sbp	return error;
94075374Sbp}
94175374Sbp
94275374Sbpint
94375374Sbpsmbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
94475374Sbp	struct smb_cred *scred)
94575374Sbp{
94675374Sbp	struct smb_rq rq, *rqp = &rq;
94775374Sbp	struct smb_share *ssp = dnp->n_mount->sm_share;
94875374Sbp	struct mbchain *mbp;
94975374Sbp	int error;
95075374Sbp
95175374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred);
95275374Sbp	if (error)
95375374Sbp		return error;
95475374Sbp	smb_rq_getrequest(rqp, &mbp);
95575374Sbp	smb_rq_wstart(rqp);
95675374Sbp	smb_rq_wend(rqp);
95775374Sbp	smb_rq_bstart(rqp);
95875374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
95975374Sbp	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len);
96075374Sbp	if (!error) {
96175374Sbp		smb_rq_bend(rqp);
96275374Sbp		error = smb_rq_simple(rqp);
96375374Sbp	}
96475374Sbp	smb_rq_done(rqp);
96575374Sbp	return error;
96675374Sbp}
96775374Sbp
96875374Sbpint
96975374Sbpsmbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred)
97075374Sbp{
97175374Sbp	struct smb_rq rq, *rqp = &rq;
97275374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
97375374Sbp	struct mbchain *mbp;
97475374Sbp	int error;
97575374Sbp
97675374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred);
97775374Sbp	if (error)
97875374Sbp		return error;
97975374Sbp	smb_rq_getrequest(rqp, &mbp);
98075374Sbp	smb_rq_wstart(rqp);
98175374Sbp	smb_rq_wend(rqp);
98275374Sbp	smb_rq_bstart(rqp);
98375374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
98475374Sbp	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
98575374Sbp	if (!error) {
98675374Sbp		smb_rq_bend(rqp);
98775374Sbp		error = smb_rq_simple(rqp);
98875374Sbp	}
98975374Sbp	smb_rq_done(rqp);
99075374Sbp	return error;
99175374Sbp}
99275374Sbp
99375374Sbpstatic int
99475374Sbpsmbfs_smb_search(struct smbfs_fctx *ctx)
99575374Sbp{
99675374Sbp	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
99775374Sbp	struct smb_rq *rqp;
99875374Sbp	struct mbchain *mbp;
99975374Sbp	struct mdchain *mdp;
100075374Sbp	u_int8_t wc, bt;
100175374Sbp	u_int16_t ec, dlen, bc;
100275374Sbp	int maxent, error, iseof = 0;
100375374Sbp
100475374Sbp	maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
100575374Sbp	if (ctx->f_rq) {
100675374Sbp		smb_rq_done(ctx->f_rq);
100775374Sbp		ctx->f_rq = NULL;
100875374Sbp	}
100975374Sbp	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
101075374Sbp	if (error)
101175374Sbp		return error;
101275374Sbp	ctx->f_rq = rqp;
101375374Sbp	smb_rq_getrequest(rqp, &mbp);
101475374Sbp	smb_rq_wstart(rqp);
101575374Sbp	mb_put_uint16le(mbp, maxent);	/* max entries to return */
101675374Sbp	mb_put_uint16le(mbp, ctx->f_attrmask);
101775374Sbp	smb_rq_wend(rqp);
101875374Sbp	smb_rq_bstart(rqp);
101975374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);	/* buffer format */
102075374Sbp	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
102175374Sbp		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
102275374Sbp		if (error)
102375374Sbp			return error;
102475374Sbp		mb_put_uint8(mbp, SMB_DT_VARIABLE);
102575374Sbp		mb_put_uint16le(mbp, 0);	/* context length */
102675374Sbp		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
102775374Sbp	} else {
102875374Sbp		mb_put_uint8(mbp, 0);	/* file name length */
102975374Sbp		mb_put_uint8(mbp, SMB_DT_VARIABLE);
103075374Sbp		mb_put_uint16le(mbp, SMB_SKEYLEN);
103175374Sbp		mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
103275374Sbp	}
103375374Sbp	smb_rq_bend(rqp);
103475374Sbp	error = smb_rq_simple(rqp);
103575374Sbp	if (error) {
103675374Sbp		if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
103775374Sbp			error = 0;
103875374Sbp			iseof = 1;
103975374Sbp			ctx->f_flags |= SMBFS_RDD_EOF;
104075374Sbp		} else
104175374Sbp			return error;
104275374Sbp	}
104375374Sbp	smb_rq_getreply(rqp, &mdp);
104475374Sbp	md_get_uint8(mdp, &wc);
104575374Sbp	if (wc != 1)
104675374Sbp		return iseof ? ENOENT : EBADRPC;
104775374Sbp	md_get_uint16le(mdp, &ec);
104875374Sbp	if (ec == 0)
104975374Sbp		return ENOENT;
105075374Sbp	ctx->f_ecnt = ec;
105175374Sbp	md_get_uint16le(mdp, &bc);
105275374Sbp	if (bc < 3)
105375374Sbp		return EBADRPC;
105475374Sbp	bc -= 3;
105575374Sbp	md_get_uint8(mdp, &bt);
105675374Sbp	if (bt != SMB_DT_VARIABLE)
105775374Sbp		return EBADRPC;
105875374Sbp	md_get_uint16le(mdp, &dlen);
105975374Sbp	if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
106075374Sbp		return EBADRPC;
106175374Sbp	return 0;
106275374Sbp}
106375374Sbp
106475374Sbpstatic int
106575374Sbpsmbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
106675374Sbp	const char *wildcard, int wclen, int attr, struct smb_cred *scred)
106775374Sbp{
106875374Sbp	ctx->f_attrmask = attr;
106975374Sbp	if (wildcard) {
107075374Sbp		if (wclen == 1 && wildcard[0] == '*') {
107175374Sbp			ctx->f_wildcard = "*.*";
107275374Sbp			ctx->f_wclen = 3;
107375374Sbp		} else {
107475374Sbp			ctx->f_wildcard = wildcard;
107575374Sbp			ctx->f_wclen = wclen;
107675374Sbp		}
107775374Sbp	} else {
107875374Sbp		ctx->f_wildcard = NULL;
107975374Sbp		ctx->f_wclen = 0;
108075374Sbp	}
108175374Sbp	ctx->f_name = ctx->f_fname;
108275374Sbp	return 0;
108375374Sbp}
108475374Sbp
108575374Sbpstatic int
108675374Sbpsmbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
108775374Sbp{
108875374Sbp	struct mdchain *mbp;
108975374Sbp	struct smb_rq *rqp;
109075374Sbp	char *cp;
109175374Sbp	u_int8_t battr;
109275374Sbp	u_int16_t date, time;
109375374Sbp	u_int32_t size;
109475374Sbp	int error;
109575374Sbp
109675374Sbp	if (ctx->f_ecnt == 0) {
109775374Sbp		if (ctx->f_flags & SMBFS_RDD_EOF)
109875374Sbp			return ENOENT;
109975374Sbp		ctx->f_left = ctx->f_limit = limit;
110075374Sbp		error = smbfs_smb_search(ctx);
110175374Sbp		if (error)
110275374Sbp			return error;
110375374Sbp	}
110475374Sbp	rqp = ctx->f_rq;
110575374Sbp	smb_rq_getreply(rqp, &mbp);
110675374Sbp	md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
110775374Sbp	md_get_uint8(mbp, &battr);
110875374Sbp	md_get_uint16le(mbp, &time);
110975374Sbp	md_get_uint16le(mbp, &date);
111075374Sbp	md_get_uint32le(mbp, &size);
111175374Sbp	cp = ctx->f_name;
111275374Sbp	md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM);
111375374Sbp	cp[sizeof(ctx->f_fname) - 1] = 0;
111475374Sbp	cp += strlen(cp) - 1;
111575374Sbp	while (*cp == ' ' && cp >= ctx->f_name)
111675374Sbp		*cp-- = 0;
111775374Sbp	ctx->f_attr.fa_attr = battr;
111875374Sbp	smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
111975374Sbp	    &ctx->f_attr.fa_mtime);
112075374Sbp	ctx->f_attr.fa_size = size;
112175374Sbp	ctx->f_nmlen = strlen(ctx->f_name);
112275374Sbp	ctx->f_ecnt--;
112375374Sbp	ctx->f_left--;
112475374Sbp	return 0;
112575374Sbp}
112675374Sbp
112775374Sbpstatic int
112875374Sbpsmbfs_findcloseLM1(struct smbfs_fctx *ctx)
112975374Sbp{
113075374Sbp	if (ctx->f_rq)
113175374Sbp		smb_rq_done(ctx->f_rq);
113275374Sbp	return 0;
113375374Sbp}
113475374Sbp
113575374Sbp/*
113675374Sbp * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
113775374Sbp */
113875374Sbpstatic int
113975374Sbpsmbfs_smb_trans2find2(struct smbfs_fctx *ctx)
114075374Sbp{
114175374Sbp	struct smb_t2rq *t2p;
114275374Sbp	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
114375374Sbp	struct mbchain *mbp;
114475374Sbp	struct mdchain *mdp;
114575374Sbp	u_int16_t tw, flags;
114675374Sbp	int error;
114775374Sbp
114875374Sbp	if (ctx->f_t2) {
114975374Sbp		smb_t2_done(ctx->f_t2);
115075374Sbp		ctx->f_t2 = NULL;
115175374Sbp	}
115275374Sbp	ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
115375374Sbp	flags = 8 | 2;			/* <resume> | <close if EOS> */
115475374Sbp	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
115575374Sbp		flags |= 1;		/* close search after this request */
115675374Sbp		ctx->f_flags |= SMBFS_RDD_NOCLOSE;
115775374Sbp	}
115875374Sbp	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
115975374Sbp		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
116075374Sbp		    ctx->f_scred, &t2p);
116175374Sbp		if (error)
116275374Sbp			return error;
116375374Sbp		ctx->f_t2 = t2p;
116475374Sbp		mbp = &t2p->t2_tparam;
116575374Sbp		mb_init(mbp);
116675374Sbp		mb_put_uint16le(mbp, ctx->f_attrmask);
116775374Sbp		mb_put_uint16le(mbp, ctx->f_limit);
116875374Sbp		mb_put_uint16le(mbp, flags);
116975374Sbp		mb_put_uint16le(mbp, ctx->f_infolevel);
117075374Sbp		mb_put_uint32le(mbp, 0);
117175374Sbp		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
117275374Sbp		if (error)
117375374Sbp			return error;
117475374Sbp	} else	{
117575374Sbp		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
117675374Sbp		    ctx->f_scred, &t2p);
117775374Sbp		if (error)
117875374Sbp			return error;
117975374Sbp		ctx->f_t2 = t2p;
118075374Sbp		mbp = &t2p->t2_tparam;
118175374Sbp		mb_init(mbp);
118275374Sbp		mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
118375374Sbp		mb_put_uint16le(mbp, ctx->f_limit);
118475374Sbp		mb_put_uint16le(mbp, ctx->f_infolevel);
118575374Sbp		mb_put_uint32le(mbp, 0);		/* resume key */
118675374Sbp		mb_put_uint16le(mbp, flags);
118775374Sbp		if (ctx->f_rname)
118875374Sbp			mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM);
118975374Sbp		else
119075374Sbp			mb_put_uint8(mbp, 0);	/* resume file name */
119175374Sbp#if 0
119275374Sbp	struct timeval tv;
119375374Sbp	tv.tv_sec = 0;
119475374Sbp	tv.tv_usec = 200 * 1000;	/* 200ms */
119575374Sbp		if (vcp->vc_flags & SMBC_WIN95) {
119675374Sbp			/*
119775374Sbp			 * some implementations suggests to sleep here
119875374Sbp			 * for 200ms, due to the bug in the Win95.
119975374Sbp			 * I've didn't notice any problem, but put code
120075374Sbp			 * for it.
120175374Sbp			 */
120275374Sbp			 tsleep(&flags, PVFS, "fix95", tvtohz(&tv));
120375374Sbp		}
120475374Sbp#endif
120575374Sbp	}
120675374Sbp	t2p->t2_maxpcount = 5 * 2;
120775374Sbp	t2p->t2_maxdcount = vcp->vc_txmax;
120875374Sbp	error = smb_t2_request(t2p);
120975374Sbp	if (error)
121075374Sbp		return error;
121175374Sbp	mdp = &t2p->t2_rparam;
121275374Sbp	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
121375374Sbp		if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
121475374Sbp			return error;
121575374Sbp		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
121675374Sbp	}
121775374Sbp	if ((error = md_get_uint16le(mdp, &tw)) != 0)
121875374Sbp		return error;
121975374Sbp	ctx->f_ecnt = tw;
122075374Sbp	if ((error = md_get_uint16le(mdp, &tw)) != 0)
122175374Sbp		return error;
122275374Sbp	if (tw)
122375374Sbp		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
122475374Sbp	if ((error = md_get_uint16le(mdp, &tw)) != 0)
122575374Sbp		return error;
122675374Sbp	if ((error = md_get_uint16le(mdp, &tw)) != 0)
122775374Sbp		return error;
1228152678Sbp	if (ctx->f_ecnt == 0) {
1229152678Sbp		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
123075374Sbp		return ENOENT;
1231152678Sbp	}
123275374Sbp	ctx->f_rnameofs = tw;
123375374Sbp	mdp = &t2p->t2_rdata;
123475374Sbp	if (mdp->md_top == NULL) {
123575374Sbp		printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt);
123675374Sbp		return ENOENT;
123775374Sbp	}
123875374Sbp	if (mdp->md_top->m_len == 0) {
123975374Sbp		printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next);
124075374Sbp		return ENOENT;
124175374Sbp	}
124275374Sbp	ctx->f_eofs = 0;
124375374Sbp	return 0;
124475374Sbp}
124575374Sbp
124675374Sbpstatic int
124775374Sbpsmbfs_smb_findclose2(struct smbfs_fctx *ctx)
124875374Sbp{
124975374Sbp	struct smb_rq rq, *rqp = &rq;
125075374Sbp	struct mbchain *mbp;
125175374Sbp	int error;
125275374Sbp
125375374Sbp	error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred);
125475374Sbp	if (error)
125575374Sbp		return error;
125675374Sbp	smb_rq_getrequest(rqp, &mbp);
125775374Sbp	smb_rq_wstart(rqp);
125875374Sbp	mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
125975374Sbp	smb_rq_wend(rqp);
126075374Sbp	smb_rq_bstart(rqp);
126175374Sbp	smb_rq_bend(rqp);
126275374Sbp	error = smb_rq_simple(rqp);
126375374Sbp	smb_rq_done(rqp);
126475374Sbp	return error;
126575374Sbp}
126675374Sbp
126775374Sbpstatic int
126875374Sbpsmbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
126975374Sbp	const char *wildcard, int wclen, int attr, struct smb_cred *scred)
127075374Sbp{
1271111119Simp	ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
127275374Sbp	if (ctx->f_name == NULL)
127375374Sbp		return ENOMEM;
127475374Sbp	ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
127575374Sbp	    SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
127675374Sbp	ctx->f_attrmask = attr;
127775374Sbp	ctx->f_wildcard = wildcard;
127875374Sbp	ctx->f_wclen = wclen;
127975374Sbp	return 0;
128075374Sbp}
128175374Sbp
128275374Sbpstatic int
128375374Sbpsmbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
128475374Sbp{
128575374Sbp	struct mdchain *mbp;
128675374Sbp	struct smb_t2rq *t2p;
128775374Sbp	char *cp;
128875374Sbp	u_int8_t tb;
128975374Sbp	u_int16_t date, time, wattr;
129075374Sbp	u_int32_t size, next, dattr;
129175374Sbp	int64_t lint;
129275374Sbp	int error, svtz, cnt, fxsz, nmlen, recsz;
129375374Sbp
129475374Sbp	if (ctx->f_ecnt == 0) {
129575374Sbp		if (ctx->f_flags & SMBFS_RDD_EOF)
129675374Sbp			return ENOENT;
129775374Sbp		ctx->f_left = ctx->f_limit = limit;
129875374Sbp		error = smbfs_smb_trans2find2(ctx);
129975374Sbp		if (error)
130075374Sbp			return error;
130175374Sbp	}
130275374Sbp	t2p = ctx->f_t2;
130375374Sbp	mbp = &t2p->t2_rdata;
130475374Sbp	svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
130575374Sbp	switch (ctx->f_infolevel) {
130675374Sbp	    case SMB_INFO_STANDARD:
130775374Sbp		next = 0;
130875374Sbp		fxsz = 0;
130975374Sbp		md_get_uint16le(mbp, &date);
131075374Sbp		md_get_uint16le(mbp, &time);	/* creation time */
131175374Sbp		md_get_uint16le(mbp, &date);
131275374Sbp		md_get_uint16le(mbp, &time);	/* access time */
131375374Sbp		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
131475374Sbp		md_get_uint16le(mbp, &date);
131575374Sbp		md_get_uint16le(mbp, &time);	/* access time */
131675374Sbp		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
131775374Sbp		md_get_uint32le(mbp, &size);
131875374Sbp		ctx->f_attr.fa_size = size;
131975374Sbp		md_get_uint32(mbp, NULL);	/* allocation size */
132075374Sbp		md_get_uint16le(mbp, &wattr);
132175374Sbp		ctx->f_attr.fa_attr = wattr;
132275374Sbp		md_get_uint8(mbp, &tb);
132375374Sbp		size = nmlen = tb;
132475374Sbp		fxsz = 23;
132575374Sbp		recsz = next = 24 + nmlen;	/* docs misses zero byte at end */
132675374Sbp		break;
132775374Sbp	    case SMB_FIND_FILE_DIRECTORY_INFO:
132875374Sbp		md_get_uint32le(mbp, &next);
132975374Sbp		md_get_uint32(mbp, NULL);	/* file index */
133075374Sbp		md_get_int64(mbp, NULL);	/* creation time */
133175374Sbp		md_get_int64le(mbp, &lint);
133275374Sbp		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime);
133375374Sbp		md_get_int64le(mbp, &lint);
133475374Sbp		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime);
133575374Sbp		md_get_int64le(mbp, &lint);
133675374Sbp		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime);
133775374Sbp		md_get_int64le(mbp, &lint);	/* file size */
133875374Sbp		ctx->f_attr.fa_size = lint;
133975374Sbp		md_get_int64(mbp, NULL);	/* real size (should use) */
134082039Sbp		md_get_uint32le(mbp, &dattr);	/* EA */
134175374Sbp		ctx->f_attr.fa_attr = dattr;
134275374Sbp		md_get_uint32le(mbp, &size);	/* name len */
134375374Sbp		fxsz = 64;
134475374Sbp		recsz = next ? next : fxsz + size;
134575374Sbp		break;
134675374Sbp	    default:
134775374Sbp		SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
134875374Sbp		return EINVAL;
134975374Sbp	}
135075374Sbp	nmlen = min(size, SMB_MAXFNAMELEN);
135175374Sbp	cp = ctx->f_name;
135275374Sbp	error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
135375374Sbp	if (error)
135475374Sbp		return error;
135575374Sbp	if (next) {
135675374Sbp		cnt = next - nmlen - fxsz;
135775374Sbp		if (cnt > 0)
135875374Sbp			md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
135975374Sbp		else if (cnt < 0) {
136075374Sbp			SMBERROR("out of sync\n");
136175374Sbp			return EBADRPC;
136275374Sbp		}
136375374Sbp	}
136475374Sbp	if (nmlen && cp[nmlen - 1] == 0)
136575374Sbp		nmlen--;
136675374Sbp	if (nmlen == 0)
136775374Sbp		return EBADRPC;
136875374Sbp
136975374Sbp	next = ctx->f_eofs + recsz;
137075374Sbp	if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
137175374Sbp	    (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
137275374Sbp		/*
137375374Sbp		 * Server needs a resume filename.
137475374Sbp		 */
137575374Sbp		if (ctx->f_rnamelen <= nmlen) {
137675374Sbp			if (ctx->f_rname)
137775374Sbp				free(ctx->f_rname, M_SMBFSDATA);
1378111119Simp			ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
137975374Sbp			ctx->f_rnamelen = nmlen;
138075374Sbp		}
138175374Sbp		bcopy(ctx->f_name, ctx->f_rname, nmlen);
138275374Sbp		ctx->f_rname[nmlen] = 0;
138375374Sbp		ctx->f_flags |= SMBFS_RDD_GOTRNAME;
138475374Sbp	}
138575374Sbp	ctx->f_nmlen = nmlen;
138675374Sbp	ctx->f_eofs = next;
138775374Sbp	ctx->f_ecnt--;
138875374Sbp	ctx->f_left--;
138975374Sbp	return 0;
139075374Sbp}
139175374Sbp
139275374Sbpstatic int
139375374Sbpsmbfs_findcloseLM2(struct smbfs_fctx *ctx)
139475374Sbp{
139575374Sbp	if (ctx->f_name)
139675374Sbp		free(ctx->f_name, M_SMBFSDATA);
139775374Sbp	if (ctx->f_t2)
139875374Sbp		smb_t2_done(ctx->f_t2);
139975374Sbp	if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
140075374Sbp		smbfs_smb_findclose2(ctx);
140175374Sbp	return 0;
140275374Sbp}
140375374Sbp
140475374Sbpint
140575374Sbpsmbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
140675374Sbp	struct smb_cred *scred, struct smbfs_fctx **ctxpp)
140775374Sbp{
140875374Sbp	struct smbfs_fctx *ctx;
140975374Sbp	int error;
141075374Sbp
1411111119Simp	ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK);
141275374Sbp	if (ctx == NULL)
141375374Sbp		return ENOMEM;
141475374Sbp	bzero(ctx, sizeof(*ctx));
141575374Sbp	ctx->f_ssp = dnp->n_mount->sm_share;
141675374Sbp	ctx->f_dnp = dnp;
141775374Sbp	ctx->f_flags = SMBFS_RDD_FINDFIRST;
141875374Sbp	ctx->f_scred = scred;
141975374Sbp	if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
1420138490Sphk	    (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) {
142175374Sbp		ctx->f_flags |= SMBFS_RDD_USESEARCH;
142275374Sbp		error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
142375374Sbp	} else
142475374Sbp		error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
142575374Sbp	if (error)
142675374Sbp		smbfs_findclose(ctx, scred);
142775374Sbp	else
142875374Sbp		*ctxpp = ctx;
142975374Sbp	return error;
143075374Sbp}
143175374Sbp
143275374Sbpint
143375374Sbpsmbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
143475374Sbp{
143575374Sbp	int error;
143675374Sbp
143775374Sbp	if (limit == 0)
143875374Sbp		limit = 1000000;
143975374Sbp	else if (limit > 1)
144075374Sbp		limit *= 4;	/* imperical */
144175374Sbp	ctx->f_scred = scred;
144275374Sbp	for (;;) {
144375374Sbp		if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
144475374Sbp			error = smbfs_findnextLM1(ctx, limit);
144575374Sbp		} else
144675374Sbp			error = smbfs_findnextLM2(ctx, limit);
144775374Sbp		if (error)
144875374Sbp			return error;
144975374Sbp		if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
145075374Sbp		    (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
145175374Sbp		     ctx->f_name[1] == '.'))
145275374Sbp			continue;
145375374Sbp		break;
145475374Sbp	}
1455145872Stakawata	smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen,
1456145872Stakawata			    ctx->f_dnp->n_mount->sm_caseopt);
145775374Sbp	ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
145875374Sbp	return 0;
145975374Sbp}
146075374Sbp
146175374Sbpint
146275374Sbpsmbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
146375374Sbp{
146475374Sbp	ctx->f_scred = scred;
146575374Sbp	if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
146675374Sbp		smbfs_findcloseLM1(ctx);
146775374Sbp	} else
146875374Sbp		smbfs_findcloseLM2(ctx);
146975374Sbp	if (ctx->f_rname)
147075374Sbp		free(ctx->f_rname, M_SMBFSDATA);
147175374Sbp	free(ctx, M_SMBFSDATA);
147275374Sbp	return 0;
147375374Sbp}
147475374Sbp
147575374Sbpint
147675374Sbpsmbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
147775374Sbp	struct smbfattr *fap, struct smb_cred *scred)
147875374Sbp{
147975374Sbp	struct smbfs_fctx *ctx;
148075374Sbp	int error;
148175374Sbp
148275374Sbp	if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
148375374Sbp		bzero(fap, sizeof(*fap));
148475374Sbp		fap->fa_attr = SMB_FA_DIR;
148575374Sbp		fap->fa_ino = 2;
148675374Sbp		return 0;
148775374Sbp	}
148875374Sbp	if (nmlen == 1 && name[0] == '.') {
148975374Sbp		error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred);
149075374Sbp		return error;
149175374Sbp	} else if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1492107821Stjr		error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap,
1493107821Stjr		    scred);
149487599Sobrien		printf("%s: knows NOTHING about '..'\n", __func__);
149575374Sbp		return error;
149675374Sbp	}
149775374Sbp	error = smbfs_findopen(dnp, name, nmlen,
149875374Sbp	    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
149975374Sbp	if (error)
150075374Sbp		return error;
150175374Sbp	ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
150275374Sbp	error = smbfs_findnext(ctx, 1, scred);
150375374Sbp	if (error == 0) {
150475374Sbp		*fap = ctx->f_attr;
150575374Sbp		if (name == NULL)
150675374Sbp			fap->fa_ino = dnp->n_ino;
150775374Sbp	}
150875374Sbp	smbfs_findclose(ctx, scred);
150975374Sbp	return error;
151075374Sbp}
1511