smbfs_smb.c revision 138490
175374Sbp/*
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 138490 2004-12-06 20:31:08Z phk $
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);
51575374Sbp		SMBERROR("%d\n", error);
51675374Sbp		if (error)
51775374Sbp			break;
51875374Sbp	} while(0);
51975374Sbp	smb_rq_done(rqp);
52075374Sbp	return error;
52175374Sbp}
52275374Sbp
52375374Sbp/*
52475374Sbp * Note, win95 doesn't support this call.
52575374Sbp */
52675374Sbpint
52775374Sbpsmbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
52875374Sbp	struct timespec *atime, int attr, struct smb_cred *scred)
52975374Sbp{
53075374Sbp	struct smb_t2rq *t2p;
53175374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
53275374Sbp	struct smb_vc *vcp = SSTOVC(ssp);
53375374Sbp	struct mbchain *mbp;
53475374Sbp	u_int16_t date, time;
53575374Sbp	int error, tzoff;
53675374Sbp
53775374Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
53875374Sbp	    scred, &t2p);
53975374Sbp	if (error)
54075374Sbp		return error;
54175374Sbp	mbp = &t2p->t2_tparam;
54275374Sbp	mb_init(mbp);
54375374Sbp	mb_put_uint16le(mbp, SMB_INFO_STANDARD);
54475374Sbp	mb_put_uint32le(mbp, 0);		/* MBZ */
545103533Sbp	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
54675374Sbp	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
54775374Sbp	if (error) {
54875374Sbp		smb_t2_done(t2p);
54975374Sbp		return error;
55075374Sbp	}
55175374Sbp	tzoff = vcp->vc_sopt.sv_tz;
55275374Sbp	mbp = &t2p->t2_tdata;
55375374Sbp	mb_init(mbp);
55475374Sbp	mb_put_uint32le(mbp, 0);		/* creation time */
55575374Sbp	if (atime)
55675374Sbp		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
55775374Sbp	else
55875374Sbp		time = date = 0;
55975374Sbp	mb_put_uint16le(mbp, date);
56075374Sbp	mb_put_uint16le(mbp, time);
56175374Sbp	if (mtime)
56275374Sbp		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
56375374Sbp	else
56475374Sbp		time = date = 0;
56575374Sbp	mb_put_uint16le(mbp, date);
56675374Sbp	mb_put_uint16le(mbp, time);
56775374Sbp	mb_put_uint32le(mbp, 0);		/* file size */
56875374Sbp	mb_put_uint32le(mbp, 0);		/* allocation unit size */
56975374Sbp	mb_put_uint16le(mbp, attr);	/* DOS attr */
57075374Sbp	mb_put_uint32le(mbp, 0);		/* EA size */
57175374Sbp	t2p->t2_maxpcount = 5 * 2;
57275374Sbp	t2p->t2_maxdcount = vcp->vc_txmax;
57375374Sbp	error = smb_t2_request(t2p);
57475374Sbp	smb_t2_done(t2p);
57575374Sbp	return error;
57675374Sbp}
57775374Sbp
57875374Sbp/*
57975374Sbp * NT level. Specially for win9x
58075374Sbp */
58175374Sbpint
58275374Sbpsmbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
58375374Sbp	struct timespec *atime, struct smb_cred *scred)
58475374Sbp{
58575374Sbp	struct smb_t2rq *t2p;
58675374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
58775374Sbp	struct smb_vc *vcp = SSTOVC(ssp);
58875374Sbp	struct mbchain *mbp;
58975374Sbp	int64_t tm;
59075374Sbp	int error, tzoff;
59175374Sbp
59275374Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
59375374Sbp	    scred, &t2p);
59475374Sbp	if (error)
59575374Sbp		return error;
59675374Sbp	mbp = &t2p->t2_tparam;
59775374Sbp	mb_init(mbp);
59875374Sbp	mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
59975374Sbp	mb_put_uint32le(mbp, 0);		/* MBZ */
600103533Sbp	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
60175374Sbp	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
60275374Sbp	if (error) {
60375374Sbp		smb_t2_done(t2p);
60475374Sbp		return error;
60575374Sbp	}
60675374Sbp	tzoff = vcp->vc_sopt.sv_tz;
60775374Sbp	mbp = &t2p->t2_tdata;
60875374Sbp	mb_init(mbp);
60975374Sbp	mb_put_int64le(mbp, 0);		/* creation time */
61075374Sbp	if (atime) {
61175374Sbp		smb_time_local2NT(atime, tzoff, &tm);
61275374Sbp	} else
61375374Sbp		tm = 0;
61475374Sbp	mb_put_int64le(mbp, tm);
61575374Sbp	if (mtime) {
61675374Sbp		smb_time_local2NT(mtime, tzoff, &tm);
61775374Sbp	} else
61875374Sbp		tm = 0;
61975374Sbp	mb_put_int64le(mbp, tm);
62075374Sbp	mb_put_int64le(mbp, tm);		/* change time */
62175374Sbp	mb_put_uint32le(mbp, attr);		/* attr */
62275374Sbp	t2p->t2_maxpcount = 24;
62375374Sbp	t2p->t2_maxdcount = 56;
62475374Sbp	error = smb_t2_request(t2p);
62575374Sbp	smb_t2_done(t2p);
62675374Sbp	return error;
62775374Sbp}
62875374Sbp
62975374Sbp/*
63075374Sbp * Set file atime and mtime. Doesn't supported by core dialect.
63175374Sbp */
63275374Sbpint
63375374Sbpsmbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
63475374Sbp	struct timespec *atime, struct smb_cred *scred)
63575374Sbp{
63675374Sbp	struct smb_rq rq, *rqp = &rq;
63775374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
63875374Sbp	struct mbchain *mbp;
63975374Sbp	u_int16_t date, time;
64075374Sbp	int error, tzoff;
64175374Sbp
64275374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred);
64375374Sbp	if (error)
64475374Sbp		return error;
64575374Sbp	tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
64675374Sbp	smb_rq_getrequest(rqp, &mbp);
64775374Sbp	smb_rq_wstart(rqp);
64875374Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
64975374Sbp	mb_put_uint32le(mbp, 0);		/* creation time */
65075374Sbp
65175374Sbp	if (atime)
65275374Sbp		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
65375374Sbp	else
65475374Sbp		time = date = 0;
65575374Sbp	mb_put_uint16le(mbp, date);
65675374Sbp	mb_put_uint16le(mbp, time);
65775374Sbp	if (mtime)
65875374Sbp		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
65975374Sbp	else
66075374Sbp		time = date = 0;
66175374Sbp	mb_put_uint16le(mbp, date);
66275374Sbp	mb_put_uint16le(mbp, time);
66375374Sbp	smb_rq_wend(rqp);
66475374Sbp	smb_rq_bstart(rqp);
66575374Sbp	smb_rq_bend(rqp);
66675374Sbp	error = smb_rq_simple(rqp);
66775374Sbp	SMBSDEBUG("%d\n", error);
66875374Sbp	smb_rq_done(rqp);
66975374Sbp	return error;
67075374Sbp}
67175374Sbp
67275374Sbp/*
67375374Sbp * Set DOS file attributes.
67475374Sbp * Looks like this call can be used only if CAP_NT_SMBS bit is on.
67575374Sbp */
67675374Sbpint
67775374Sbpsmbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
67875374Sbp	struct timespec *atime, struct smb_cred *scred)
67975374Sbp{
68075374Sbp	struct smb_t2rq *t2p;
68175374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
68275374Sbp	struct mbchain *mbp;
68375374Sbp	int64_t tm;
68475374Sbp	int error, svtz;
68575374Sbp
68675374Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
68775374Sbp	    scred, &t2p);
68875374Sbp	if (error)
68975374Sbp		return error;
69075374Sbp	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
69175374Sbp	mbp = &t2p->t2_tparam;
69275374Sbp	mb_init(mbp);
69375374Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
69475374Sbp	mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
69575374Sbp	mb_put_uint32le(mbp, 0);
69675374Sbp	mbp = &t2p->t2_tdata;
69775374Sbp	mb_init(mbp);
69875374Sbp	mb_put_int64le(mbp, 0);		/* creation time */
69975374Sbp	if (atime) {
70075374Sbp		smb_time_local2NT(atime, svtz, &tm);
70175374Sbp	} else
70275374Sbp		tm = 0;
70375374Sbp	mb_put_int64le(mbp, tm);
70475374Sbp	if (mtime) {
70575374Sbp		smb_time_local2NT(mtime, svtz, &tm);
70675374Sbp	} else
70775374Sbp		tm = 0;
70875374Sbp	mb_put_int64le(mbp, tm);
70975374Sbp	mb_put_int64le(mbp, tm);		/* change time */
71075374Sbp	mb_put_uint16le(mbp, attr);
71175374Sbp	mb_put_uint32le(mbp, 0);			/* padding */
71275374Sbp	mb_put_uint16le(mbp, 0);
71375374Sbp	t2p->t2_maxpcount = 2;
71475374Sbp	t2p->t2_maxdcount = 0;
71575374Sbp	error = smb_t2_request(t2p);
71675374Sbp	smb_t2_done(t2p);
71775374Sbp	return error;
71875374Sbp}
71975374Sbp
72075374Sbp
72175374Sbpint
72275374Sbpsmbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
72375374Sbp{
72475374Sbp	struct smb_rq rq, *rqp = &rq;
72575374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
72675374Sbp	struct mbchain *mbp;
72775374Sbp	struct mdchain *mdp;
72875374Sbp	u_int8_t wc;
72975374Sbp	u_int16_t fid, wattr, grantedmode;
73075374Sbp	int error;
73175374Sbp
73275374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred);
73375374Sbp	if (error)
73475374Sbp		return error;
73575374Sbp	smb_rq_getrequest(rqp, &mbp);
73675374Sbp	smb_rq_wstart(rqp);
73775374Sbp	mb_put_uint16le(mbp, accmode);
73875374Sbp	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
73975374Sbp	smb_rq_wend(rqp);
74075374Sbp	smb_rq_bstart(rqp);
74175374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
74275374Sbp	do {
74375374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
74475374Sbp		if (error)
74575374Sbp			break;
74675374Sbp		smb_rq_bend(rqp);
74775374Sbp		error = smb_rq_simple(rqp);
74875374Sbp		if (error)
74975374Sbp			break;
75075374Sbp		smb_rq_getreply(rqp, &mdp);
75175374Sbp		if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
75275374Sbp			error = EBADRPC;
75375374Sbp			break;
75475374Sbp		}
75575374Sbp		md_get_uint16(mdp, &fid);
75675374Sbp		md_get_uint16le(mdp, &wattr);
75775374Sbp		md_get_uint32(mdp, NULL);	/* mtime */
75875374Sbp		md_get_uint32(mdp, NULL);	/* fsize */
75975374Sbp		md_get_uint16le(mdp, &grantedmode);
76075374Sbp		/*
76175374Sbp		 * TODO: refresh attributes from this reply
76275374Sbp		 */
76375374Sbp	} while(0);
76475374Sbp	smb_rq_done(rqp);
76575374Sbp	if (error)
76675374Sbp		return error;
76775374Sbp	np->n_fid = fid;
76875374Sbp	np->n_rwstate = grantedmode;
76975374Sbp	return 0;
77075374Sbp}
77175374Sbp
77275374Sbp
77375374Sbpint
77475374Sbpsmbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
77575374Sbp	struct smb_cred *scred)
77675374Sbp{
77775374Sbp	struct smb_rq rq, *rqp = &rq;
77875374Sbp	struct mbchain *mbp;
77975374Sbp	u_long time;
78075374Sbp	int error;
78175374Sbp
78275374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred);
78375374Sbp	if (error)
78475374Sbp		return error;
78575374Sbp	smb_rq_getrequest(rqp, &mbp);
78675374Sbp	smb_rq_wstart(rqp);
78775374Sbp	mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
78875374Sbp	if (mtime) {
78975374Sbp		smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
79075374Sbp	} else
79175374Sbp		time = 0;
79275374Sbp	mb_put_uint32le(mbp, time);
79375374Sbp	smb_rq_wend(rqp);
79475374Sbp	smb_rq_bstart(rqp);
79575374Sbp	smb_rq_bend(rqp);
79675374Sbp	error = smb_rq_simple(rqp);
79775374Sbp	smb_rq_done(rqp);
79875374Sbp	return error;
79975374Sbp}
80075374Sbp
80175374Sbpint
80275374Sbpsmbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
80375374Sbp	struct smb_cred *scred)
80475374Sbp{
80575374Sbp	struct smb_rq rq, *rqp = &rq;
80675374Sbp	struct smb_share *ssp = dnp->n_mount->sm_share;
80775374Sbp	struct mbchain *mbp;
80875374Sbp	struct mdchain *mdp;
80975374Sbp	struct timespec ctime;
81075374Sbp	u_int8_t wc;
81175374Sbp	u_int16_t fid;
81275374Sbp	u_long tm;
81375374Sbp	int error;
81475374Sbp
81575374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred);
81675374Sbp	if (error)
81775374Sbp		return error;
81875374Sbp	smb_rq_getrequest(rqp, &mbp);
81975374Sbp	smb_rq_wstart(rqp);
82075374Sbp	mb_put_uint16le(mbp, SMB_FA_ARCHIVE);		/* attributes  */
82175374Sbp	nanotime(&ctime);
82275374Sbp	smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
82375374Sbp	mb_put_uint32le(mbp, tm);
82475374Sbp	smb_rq_wend(rqp);
82575374Sbp	smb_rq_bstart(rqp);
82675374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
82775374Sbp	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen);
82875374Sbp	if (!error) {
82975374Sbp		smb_rq_bend(rqp);
83075374Sbp		error = smb_rq_simple(rqp);
83175374Sbp		if (!error) {
83275374Sbp			smb_rq_getreply(rqp, &mdp);
83375374Sbp			md_get_uint8(mdp, &wc);
83475374Sbp			if (wc == 1)
83575374Sbp				md_get_uint16(mdp, &fid);
83675374Sbp			else
83775374Sbp				error = EBADRPC;
83875374Sbp		}
83975374Sbp	}
84075374Sbp	smb_rq_done(rqp);
84175374Sbp	if (error)
84275374Sbp		return error;
84375374Sbp	smbfs_smb_close(ssp, fid, &ctime, scred);
84475374Sbp	return error;
84575374Sbp}
84675374Sbp
84775374Sbpint
84875374Sbpsmbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
84975374Sbp{
85075374Sbp	struct smb_rq rq, *rqp = &rq;
85175374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
85275374Sbp	struct mbchain *mbp;
85375374Sbp	int error;
85475374Sbp
85575374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred);
85675374Sbp	if (error)
85775374Sbp		return error;
85875374Sbp	smb_rq_getrequest(rqp, &mbp);
85975374Sbp	smb_rq_wstart(rqp);
86075374Sbp	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
86175374Sbp	smb_rq_wend(rqp);
86275374Sbp	smb_rq_bstart(rqp);
86375374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
86475374Sbp	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
86575374Sbp	if (!error) {
86675374Sbp		smb_rq_bend(rqp);
86775374Sbp		error = smb_rq_simple(rqp);
86875374Sbp	}
86975374Sbp	smb_rq_done(rqp);
87075374Sbp	return error;
87175374Sbp}
87275374Sbp
87375374Sbpint
87475374Sbpsmbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
87575374Sbp	const char *tname, int tnmlen, struct smb_cred *scred)
87675374Sbp{
87775374Sbp	struct smb_rq rq, *rqp = &rq;
87875374Sbp	struct smb_share *ssp = src->n_mount->sm_share;
87975374Sbp	struct mbchain *mbp;
88075374Sbp	int error;
88175374Sbp
88275374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred);
88375374Sbp	if (error)
88475374Sbp		return error;
88575374Sbp	smb_rq_getrequest(rqp, &mbp);
88675374Sbp	smb_rq_wstart(rqp);
88775374Sbp	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
88875374Sbp	smb_rq_wend(rqp);
88975374Sbp	smb_rq_bstart(rqp);
89075374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
89175374Sbp	do {
89275374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
89375374Sbp		if (error)
89475374Sbp			break;
89575374Sbp		mb_put_uint8(mbp, SMB_DT_ASCII);
89675374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
89775374Sbp		if (error)
89875374Sbp			break;
89975374Sbp		smb_rq_bend(rqp);
90075374Sbp		error = smb_rq_simple(rqp);
90175374Sbp	} while(0);
90275374Sbp	smb_rq_done(rqp);
90375374Sbp	return error;
90475374Sbp}
90575374Sbp
90675374Sbpint
90775374Sbpsmbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
90875374Sbp	const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
90975374Sbp{
91075374Sbp	struct smb_rq rq, *rqp = &rq;
91175374Sbp	struct smb_share *ssp = src->n_mount->sm_share;
91275374Sbp	struct mbchain *mbp;
91375374Sbp	int error;
91475374Sbp
91575374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred);
91675374Sbp	if (error)
91775374Sbp		return error;
91875374Sbp	smb_rq_getrequest(rqp, &mbp);
91975374Sbp	smb_rq_wstart(rqp);
92075374Sbp	mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
92175374Sbp	mb_put_uint16le(mbp, 0x20);	/* delete target file */
92275374Sbp	mb_put_uint16le(mbp, flags);
92375374Sbp	smb_rq_wend(rqp);
92475374Sbp	smb_rq_bstart(rqp);
92575374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
92675374Sbp	do {
92775374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
92875374Sbp		if (error)
92975374Sbp			break;
93075374Sbp		mb_put_uint8(mbp, SMB_DT_ASCII);
93175374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
93275374Sbp		if (error)
93375374Sbp			break;
93475374Sbp		smb_rq_bend(rqp);
93575374Sbp		error = smb_rq_simple(rqp);
93675374Sbp	} while(0);
93775374Sbp	smb_rq_done(rqp);
93875374Sbp	return error;
93975374Sbp}
94075374Sbp
94175374Sbpint
94275374Sbpsmbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
94375374Sbp	struct smb_cred *scred)
94475374Sbp{
94575374Sbp	struct smb_rq rq, *rqp = &rq;
94675374Sbp	struct smb_share *ssp = dnp->n_mount->sm_share;
94775374Sbp	struct mbchain *mbp;
94875374Sbp	int error;
94975374Sbp
95075374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred);
95175374Sbp	if (error)
95275374Sbp		return error;
95375374Sbp	smb_rq_getrequest(rqp, &mbp);
95475374Sbp	smb_rq_wstart(rqp);
95575374Sbp	smb_rq_wend(rqp);
95675374Sbp	smb_rq_bstart(rqp);
95775374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
95875374Sbp	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len);
95975374Sbp	if (!error) {
96075374Sbp		smb_rq_bend(rqp);
96175374Sbp		error = smb_rq_simple(rqp);
96275374Sbp	}
96375374Sbp	smb_rq_done(rqp);
96475374Sbp	return error;
96575374Sbp}
96675374Sbp
96775374Sbpint
96875374Sbpsmbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred)
96975374Sbp{
97075374Sbp	struct smb_rq rq, *rqp = &rq;
97175374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
97275374Sbp	struct mbchain *mbp;
97375374Sbp	int error;
97475374Sbp
97575374Sbp	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred);
97675374Sbp	if (error)
97775374Sbp		return error;
97875374Sbp	smb_rq_getrequest(rqp, &mbp);
97975374Sbp	smb_rq_wstart(rqp);
98075374Sbp	smb_rq_wend(rqp);
98175374Sbp	smb_rq_bstart(rqp);
98275374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
98375374Sbp	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
98475374Sbp	if (!error) {
98575374Sbp		smb_rq_bend(rqp);
98675374Sbp		error = smb_rq_simple(rqp);
98775374Sbp	}
98875374Sbp	smb_rq_done(rqp);
98975374Sbp	return error;
99075374Sbp}
99175374Sbp
99275374Sbpstatic int
99375374Sbpsmbfs_smb_search(struct smbfs_fctx *ctx)
99475374Sbp{
99575374Sbp	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
99675374Sbp	struct smb_rq *rqp;
99775374Sbp	struct mbchain *mbp;
99875374Sbp	struct mdchain *mdp;
99975374Sbp	u_int8_t wc, bt;
100075374Sbp	u_int16_t ec, dlen, bc;
100175374Sbp	int maxent, error, iseof = 0;
100275374Sbp
100375374Sbp	maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
100475374Sbp	if (ctx->f_rq) {
100575374Sbp		smb_rq_done(ctx->f_rq);
100675374Sbp		ctx->f_rq = NULL;
100775374Sbp	}
100875374Sbp	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
100975374Sbp	if (error)
101075374Sbp		return error;
101175374Sbp	ctx->f_rq = rqp;
101275374Sbp	smb_rq_getrequest(rqp, &mbp);
101375374Sbp	smb_rq_wstart(rqp);
101475374Sbp	mb_put_uint16le(mbp, maxent);	/* max entries to return */
101575374Sbp	mb_put_uint16le(mbp, ctx->f_attrmask);
101675374Sbp	smb_rq_wend(rqp);
101775374Sbp	smb_rq_bstart(rqp);
101875374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);	/* buffer format */
101975374Sbp	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
102075374Sbp		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
102175374Sbp		if (error)
102275374Sbp			return error;
102375374Sbp		mb_put_uint8(mbp, SMB_DT_VARIABLE);
102475374Sbp		mb_put_uint16le(mbp, 0);	/* context length */
102575374Sbp		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
102675374Sbp	} else {
102775374Sbp		mb_put_uint8(mbp, 0);	/* file name length */
102875374Sbp		mb_put_uint8(mbp, SMB_DT_VARIABLE);
102975374Sbp		mb_put_uint16le(mbp, SMB_SKEYLEN);
103075374Sbp		mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
103175374Sbp	}
103275374Sbp	smb_rq_bend(rqp);
103375374Sbp	error = smb_rq_simple(rqp);
103475374Sbp	if (error) {
103575374Sbp		if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
103675374Sbp			error = 0;
103775374Sbp			iseof = 1;
103875374Sbp			ctx->f_flags |= SMBFS_RDD_EOF;
103975374Sbp		} else
104075374Sbp			return error;
104175374Sbp	}
104275374Sbp	smb_rq_getreply(rqp, &mdp);
104375374Sbp	md_get_uint8(mdp, &wc);
104475374Sbp	if (wc != 1)
104575374Sbp		return iseof ? ENOENT : EBADRPC;
104675374Sbp	md_get_uint16le(mdp, &ec);
104775374Sbp	if (ec == 0)
104875374Sbp		return ENOENT;
104975374Sbp	ctx->f_ecnt = ec;
105075374Sbp	md_get_uint16le(mdp, &bc);
105175374Sbp	if (bc < 3)
105275374Sbp		return EBADRPC;
105375374Sbp	bc -= 3;
105475374Sbp	md_get_uint8(mdp, &bt);
105575374Sbp	if (bt != SMB_DT_VARIABLE)
105675374Sbp		return EBADRPC;
105775374Sbp	md_get_uint16le(mdp, &dlen);
105875374Sbp	if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
105975374Sbp		return EBADRPC;
106075374Sbp	return 0;
106175374Sbp}
106275374Sbp
106375374Sbpstatic int
106475374Sbpsmbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
106575374Sbp	const char *wildcard, int wclen, int attr, struct smb_cred *scred)
106675374Sbp{
106775374Sbp	ctx->f_attrmask = attr;
106875374Sbp	if (wildcard) {
106975374Sbp		if (wclen == 1 && wildcard[0] == '*') {
107075374Sbp			ctx->f_wildcard = "*.*";
107175374Sbp			ctx->f_wclen = 3;
107275374Sbp		} else {
107375374Sbp			ctx->f_wildcard = wildcard;
107475374Sbp			ctx->f_wclen = wclen;
107575374Sbp		}
107675374Sbp	} else {
107775374Sbp		ctx->f_wildcard = NULL;
107875374Sbp		ctx->f_wclen = 0;
107975374Sbp	}
108075374Sbp	ctx->f_name = ctx->f_fname;
108175374Sbp	return 0;
108275374Sbp}
108375374Sbp
108475374Sbpstatic int
108575374Sbpsmbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
108675374Sbp{
108775374Sbp	struct mdchain *mbp;
108875374Sbp	struct smb_rq *rqp;
108975374Sbp	char *cp;
109075374Sbp	u_int8_t battr;
109175374Sbp	u_int16_t date, time;
109275374Sbp	u_int32_t size;
109375374Sbp	int error;
109475374Sbp
109575374Sbp	if (ctx->f_ecnt == 0) {
109675374Sbp		if (ctx->f_flags & SMBFS_RDD_EOF)
109775374Sbp			return ENOENT;
109875374Sbp		ctx->f_left = ctx->f_limit = limit;
109975374Sbp		error = smbfs_smb_search(ctx);
110075374Sbp		if (error)
110175374Sbp			return error;
110275374Sbp	}
110375374Sbp	rqp = ctx->f_rq;
110475374Sbp	smb_rq_getreply(rqp, &mbp);
110575374Sbp	md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
110675374Sbp	md_get_uint8(mbp, &battr);
110775374Sbp	md_get_uint16le(mbp, &time);
110875374Sbp	md_get_uint16le(mbp, &date);
110975374Sbp	md_get_uint32le(mbp, &size);
111075374Sbp	cp = ctx->f_name;
111175374Sbp	md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM);
111275374Sbp	cp[sizeof(ctx->f_fname) - 1] = 0;
111375374Sbp	cp += strlen(cp) - 1;
111475374Sbp	while (*cp == ' ' && cp >= ctx->f_name)
111575374Sbp		*cp-- = 0;
111675374Sbp	ctx->f_attr.fa_attr = battr;
111775374Sbp	smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
111875374Sbp	    &ctx->f_attr.fa_mtime);
111975374Sbp	ctx->f_attr.fa_size = size;
112075374Sbp	ctx->f_nmlen = strlen(ctx->f_name);
112175374Sbp	ctx->f_ecnt--;
112275374Sbp	ctx->f_left--;
112375374Sbp	return 0;
112475374Sbp}
112575374Sbp
112675374Sbpstatic int
112775374Sbpsmbfs_findcloseLM1(struct smbfs_fctx *ctx)
112875374Sbp{
112975374Sbp	if (ctx->f_rq)
113075374Sbp		smb_rq_done(ctx->f_rq);
113175374Sbp	return 0;
113275374Sbp}
113375374Sbp
113475374Sbp/*
113575374Sbp * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
113675374Sbp */
113775374Sbpstatic int
113875374Sbpsmbfs_smb_trans2find2(struct smbfs_fctx *ctx)
113975374Sbp{
114075374Sbp	struct smb_t2rq *t2p;
114175374Sbp	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
114275374Sbp	struct mbchain *mbp;
114375374Sbp	struct mdchain *mdp;
114475374Sbp	u_int16_t tw, flags;
114575374Sbp	int error;
114675374Sbp
114775374Sbp	if (ctx->f_t2) {
114875374Sbp		smb_t2_done(ctx->f_t2);
114975374Sbp		ctx->f_t2 = NULL;
115075374Sbp	}
115175374Sbp	ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
115275374Sbp	flags = 8 | 2;			/* <resume> | <close if EOS> */
115375374Sbp	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
115475374Sbp		flags |= 1;		/* close search after this request */
115575374Sbp		ctx->f_flags |= SMBFS_RDD_NOCLOSE;
115675374Sbp	}
115775374Sbp	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
115875374Sbp		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
115975374Sbp		    ctx->f_scred, &t2p);
116075374Sbp		if (error)
116175374Sbp			return error;
116275374Sbp		ctx->f_t2 = t2p;
116375374Sbp		mbp = &t2p->t2_tparam;
116475374Sbp		mb_init(mbp);
116575374Sbp		mb_put_uint16le(mbp, ctx->f_attrmask);
116675374Sbp		mb_put_uint16le(mbp, ctx->f_limit);
116775374Sbp		mb_put_uint16le(mbp, flags);
116875374Sbp		mb_put_uint16le(mbp, ctx->f_infolevel);
116975374Sbp		mb_put_uint32le(mbp, 0);
117075374Sbp		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
117175374Sbp		if (error)
117275374Sbp			return error;
117375374Sbp	} else	{
117475374Sbp		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
117575374Sbp		    ctx->f_scred, &t2p);
117675374Sbp		if (error)
117775374Sbp			return error;
117875374Sbp		ctx->f_t2 = t2p;
117975374Sbp		mbp = &t2p->t2_tparam;
118075374Sbp		mb_init(mbp);
118175374Sbp		mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
118275374Sbp		mb_put_uint16le(mbp, ctx->f_limit);
118375374Sbp		mb_put_uint16le(mbp, ctx->f_infolevel);
118475374Sbp		mb_put_uint32le(mbp, 0);		/* resume key */
118575374Sbp		mb_put_uint16le(mbp, flags);
118675374Sbp		if (ctx->f_rname)
118775374Sbp			mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM);
118875374Sbp		else
118975374Sbp			mb_put_uint8(mbp, 0);	/* resume file name */
119075374Sbp#if 0
119175374Sbp	struct timeval tv;
119275374Sbp	tv.tv_sec = 0;
119375374Sbp	tv.tv_usec = 200 * 1000;	/* 200ms */
119475374Sbp		if (vcp->vc_flags & SMBC_WIN95) {
119575374Sbp			/*
119675374Sbp			 * some implementations suggests to sleep here
119775374Sbp			 * for 200ms, due to the bug in the Win95.
119875374Sbp			 * I've didn't notice any problem, but put code
119975374Sbp			 * for it.
120075374Sbp			 */
120175374Sbp			 tsleep(&flags, PVFS, "fix95", tvtohz(&tv));
120275374Sbp		}
120375374Sbp#endif
120475374Sbp	}
120575374Sbp	t2p->t2_maxpcount = 5 * 2;
120675374Sbp	t2p->t2_maxdcount = vcp->vc_txmax;
120775374Sbp	error = smb_t2_request(t2p);
120875374Sbp	if (error)
120975374Sbp		return error;
121075374Sbp	mdp = &t2p->t2_rparam;
121175374Sbp	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
121275374Sbp		if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
121375374Sbp			return error;
121475374Sbp		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
121575374Sbp	}
121675374Sbp	if ((error = md_get_uint16le(mdp, &tw)) != 0)
121775374Sbp		return error;
121875374Sbp	ctx->f_ecnt = tw;
121975374Sbp	if ((error = md_get_uint16le(mdp, &tw)) != 0)
122075374Sbp		return error;
122175374Sbp	if (tw)
122275374Sbp		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
122375374Sbp	if ((error = md_get_uint16le(mdp, &tw)) != 0)
122475374Sbp		return error;
122575374Sbp	if ((error = md_get_uint16le(mdp, &tw)) != 0)
122675374Sbp		return error;
122775374Sbp	if (ctx->f_ecnt == 0)
122875374Sbp		return ENOENT;
122975374Sbp	ctx->f_rnameofs = tw;
123075374Sbp	mdp = &t2p->t2_rdata;
123175374Sbp	if (mdp->md_top == NULL) {
123275374Sbp		printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt);
123375374Sbp		return ENOENT;
123475374Sbp	}
123575374Sbp	if (mdp->md_top->m_len == 0) {
123675374Sbp		printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next);
123775374Sbp		return ENOENT;
123875374Sbp	}
123975374Sbp	ctx->f_eofs = 0;
124075374Sbp	return 0;
124175374Sbp}
124275374Sbp
124375374Sbpstatic int
124475374Sbpsmbfs_smb_findclose2(struct smbfs_fctx *ctx)
124575374Sbp{
124675374Sbp	struct smb_rq rq, *rqp = &rq;
124775374Sbp	struct mbchain *mbp;
124875374Sbp	int error;
124975374Sbp
125075374Sbp	error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2, ctx->f_scred);
125175374Sbp	if (error)
125275374Sbp		return error;
125375374Sbp	smb_rq_getrequest(rqp, &mbp);
125475374Sbp	smb_rq_wstart(rqp);
125575374Sbp	mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
125675374Sbp	smb_rq_wend(rqp);
125775374Sbp	smb_rq_bstart(rqp);
125875374Sbp	smb_rq_bend(rqp);
125975374Sbp	error = smb_rq_simple(rqp);
126075374Sbp	smb_rq_done(rqp);
126175374Sbp	return error;
126275374Sbp}
126375374Sbp
126475374Sbpstatic int
126575374Sbpsmbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
126675374Sbp	const char *wildcard, int wclen, int attr, struct smb_cred *scred)
126775374Sbp{
1268111119Simp	ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
126975374Sbp	if (ctx->f_name == NULL)
127075374Sbp		return ENOMEM;
127175374Sbp	ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
127275374Sbp	    SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
127375374Sbp	ctx->f_attrmask = attr;
127475374Sbp	ctx->f_wildcard = wildcard;
127575374Sbp	ctx->f_wclen = wclen;
127675374Sbp	return 0;
127775374Sbp}
127875374Sbp
127975374Sbpstatic int
128075374Sbpsmbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
128175374Sbp{
128275374Sbp	struct mdchain *mbp;
128375374Sbp	struct smb_t2rq *t2p;
128475374Sbp	char *cp;
128575374Sbp	u_int8_t tb;
128675374Sbp	u_int16_t date, time, wattr;
128775374Sbp	u_int32_t size, next, dattr;
128875374Sbp	int64_t lint;
128975374Sbp	int error, svtz, cnt, fxsz, nmlen, recsz;
129075374Sbp
129175374Sbp	if (ctx->f_ecnt == 0) {
129275374Sbp		if (ctx->f_flags & SMBFS_RDD_EOF)
129375374Sbp			return ENOENT;
129475374Sbp		ctx->f_left = ctx->f_limit = limit;
129575374Sbp		error = smbfs_smb_trans2find2(ctx);
129675374Sbp		if (error)
129775374Sbp			return error;
129875374Sbp	}
129975374Sbp	t2p = ctx->f_t2;
130075374Sbp	mbp = &t2p->t2_rdata;
130175374Sbp	svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
130275374Sbp	switch (ctx->f_infolevel) {
130375374Sbp	    case SMB_INFO_STANDARD:
130475374Sbp		next = 0;
130575374Sbp		fxsz = 0;
130675374Sbp		md_get_uint16le(mbp, &date);
130775374Sbp		md_get_uint16le(mbp, &time);	/* creation time */
130875374Sbp		md_get_uint16le(mbp, &date);
130975374Sbp		md_get_uint16le(mbp, &time);	/* access time */
131075374Sbp		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
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_mtime);
131475374Sbp		md_get_uint32le(mbp, &size);
131575374Sbp		ctx->f_attr.fa_size = size;
131675374Sbp		md_get_uint32(mbp, NULL);	/* allocation size */
131775374Sbp		md_get_uint16le(mbp, &wattr);
131875374Sbp		ctx->f_attr.fa_attr = wattr;
131975374Sbp		md_get_uint8(mbp, &tb);
132075374Sbp		size = nmlen = tb;
132175374Sbp		fxsz = 23;
132275374Sbp		recsz = next = 24 + nmlen;	/* docs misses zero byte at end */
132375374Sbp		break;
132475374Sbp	    case SMB_FIND_FILE_DIRECTORY_INFO:
132575374Sbp		md_get_uint32le(mbp, &next);
132675374Sbp		md_get_uint32(mbp, NULL);	/* file index */
132775374Sbp		md_get_int64(mbp, NULL);	/* creation time */
132875374Sbp		md_get_int64le(mbp, &lint);
132975374Sbp		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime);
133075374Sbp		md_get_int64le(mbp, &lint);
133175374Sbp		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime);
133275374Sbp		md_get_int64le(mbp, &lint);
133375374Sbp		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime);
133475374Sbp		md_get_int64le(mbp, &lint);	/* file size */
133575374Sbp		ctx->f_attr.fa_size = lint;
133675374Sbp		md_get_int64(mbp, NULL);	/* real size (should use) */
133782039Sbp		md_get_uint32le(mbp, &dattr);	/* EA */
133875374Sbp		ctx->f_attr.fa_attr = dattr;
133975374Sbp		md_get_uint32le(mbp, &size);	/* name len */
134075374Sbp		fxsz = 64;
134175374Sbp		recsz = next ? next : fxsz + size;
134275374Sbp		break;
134375374Sbp	    default:
134475374Sbp		SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
134575374Sbp		return EINVAL;
134675374Sbp	}
134775374Sbp	nmlen = min(size, SMB_MAXFNAMELEN);
134875374Sbp	cp = ctx->f_name;
134975374Sbp	error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
135075374Sbp	if (error)
135175374Sbp		return error;
135275374Sbp	if (next) {
135375374Sbp		cnt = next - nmlen - fxsz;
135475374Sbp		if (cnt > 0)
135575374Sbp			md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
135675374Sbp		else if (cnt < 0) {
135775374Sbp			SMBERROR("out of sync\n");
135875374Sbp			return EBADRPC;
135975374Sbp		}
136075374Sbp	}
136175374Sbp	if (nmlen && cp[nmlen - 1] == 0)
136275374Sbp		nmlen--;
136375374Sbp	if (nmlen == 0)
136475374Sbp		return EBADRPC;
136575374Sbp
136675374Sbp	next = ctx->f_eofs + recsz;
136775374Sbp	if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
136875374Sbp	    (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
136975374Sbp		/*
137075374Sbp		 * Server needs a resume filename.
137175374Sbp		 */
137275374Sbp		if (ctx->f_rnamelen <= nmlen) {
137375374Sbp			if (ctx->f_rname)
137475374Sbp				free(ctx->f_rname, M_SMBFSDATA);
1375111119Simp			ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
137675374Sbp			ctx->f_rnamelen = nmlen;
137775374Sbp		}
137875374Sbp		bcopy(ctx->f_name, ctx->f_rname, nmlen);
137975374Sbp		ctx->f_rname[nmlen] = 0;
138075374Sbp		ctx->f_flags |= SMBFS_RDD_GOTRNAME;
138175374Sbp	}
138275374Sbp	ctx->f_nmlen = nmlen;
138375374Sbp	ctx->f_eofs = next;
138475374Sbp	ctx->f_ecnt--;
138575374Sbp	ctx->f_left--;
138675374Sbp	return 0;
138775374Sbp}
138875374Sbp
138975374Sbpstatic int
139075374Sbpsmbfs_findcloseLM2(struct smbfs_fctx *ctx)
139175374Sbp{
139275374Sbp	if (ctx->f_name)
139375374Sbp		free(ctx->f_name, M_SMBFSDATA);
139475374Sbp	if (ctx->f_t2)
139575374Sbp		smb_t2_done(ctx->f_t2);
139675374Sbp	if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
139775374Sbp		smbfs_smb_findclose2(ctx);
139875374Sbp	return 0;
139975374Sbp}
140075374Sbp
140175374Sbpint
140275374Sbpsmbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
140375374Sbp	struct smb_cred *scred, struct smbfs_fctx **ctxpp)
140475374Sbp{
140575374Sbp	struct smbfs_fctx *ctx;
140675374Sbp	int error;
140775374Sbp
1408111119Simp	ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK);
140975374Sbp	if (ctx == NULL)
141075374Sbp		return ENOMEM;
141175374Sbp	bzero(ctx, sizeof(*ctx));
141275374Sbp	ctx->f_ssp = dnp->n_mount->sm_share;
141375374Sbp	ctx->f_dnp = dnp;
141475374Sbp	ctx->f_flags = SMBFS_RDD_FINDFIRST;
141575374Sbp	ctx->f_scred = scred;
141675374Sbp	if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
1417138490Sphk	    (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) {
141875374Sbp		ctx->f_flags |= SMBFS_RDD_USESEARCH;
141975374Sbp		error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
142075374Sbp	} else
142175374Sbp		error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
142275374Sbp	if (error)
142375374Sbp		smbfs_findclose(ctx, scred);
142475374Sbp	else
142575374Sbp		*ctxpp = ctx;
142675374Sbp	return error;
142775374Sbp}
142875374Sbp
142975374Sbpint
143075374Sbpsmbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
143175374Sbp{
143275374Sbp	int error;
143375374Sbp
143475374Sbp	if (limit == 0)
143575374Sbp		limit = 1000000;
143675374Sbp	else if (limit > 1)
143775374Sbp		limit *= 4;	/* imperical */
143875374Sbp	ctx->f_scred = scred;
143975374Sbp	for (;;) {
144075374Sbp		if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
144175374Sbp			error = smbfs_findnextLM1(ctx, limit);
144275374Sbp		} else
144375374Sbp			error = smbfs_findnextLM2(ctx, limit);
144475374Sbp		if (error)
144575374Sbp			return error;
144675374Sbp		if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
144775374Sbp		    (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
144875374Sbp		     ctx->f_name[1] == '.'))
144975374Sbp			continue;
145075374Sbp		break;
145175374Sbp	}
145275374Sbp	smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, ctx->f_nmlen,
145375374Sbp	    ctx->f_dnp->n_mount->sm_caseopt);
145475374Sbp	ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
145575374Sbp	return 0;
145675374Sbp}
145775374Sbp
145875374Sbpint
145975374Sbpsmbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
146075374Sbp{
146175374Sbp	ctx->f_scred = scred;
146275374Sbp	if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
146375374Sbp		smbfs_findcloseLM1(ctx);
146475374Sbp	} else
146575374Sbp		smbfs_findcloseLM2(ctx);
146675374Sbp	if (ctx->f_rname)
146775374Sbp		free(ctx->f_rname, M_SMBFSDATA);
146875374Sbp	free(ctx, M_SMBFSDATA);
146975374Sbp	return 0;
147075374Sbp}
147175374Sbp
147275374Sbpint
147375374Sbpsmbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
147475374Sbp	struct smbfattr *fap, struct smb_cred *scred)
147575374Sbp{
147675374Sbp	struct smbfs_fctx *ctx;
147775374Sbp	int error;
147875374Sbp
147975374Sbp	if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
148075374Sbp		bzero(fap, sizeof(*fap));
148175374Sbp		fap->fa_attr = SMB_FA_DIR;
148275374Sbp		fap->fa_ino = 2;
148375374Sbp		return 0;
148475374Sbp	}
148575374Sbp	if (nmlen == 1 && name[0] == '.') {
148675374Sbp		error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred);
148775374Sbp		return error;
148875374Sbp	} else if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1489107821Stjr		error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap,
1490107821Stjr		    scred);
149187599Sobrien		printf("%s: knows NOTHING about '..'\n", __func__);
149275374Sbp		return error;
149375374Sbp	}
149475374Sbp	error = smbfs_findopen(dnp, name, nmlen,
149575374Sbp	    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
149675374Sbp	if (error)
149775374Sbp		return error;
149875374Sbp	ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
149975374Sbp	error = smbfs_findnext(ctx, 1, scred);
150075374Sbp	if (error == 0) {
150175374Sbp		*fap = ctx->f_attr;
150275374Sbp		if (name == NULL)
150375374Sbp			fap->fa_ino = dnp->n_ino;
150475374Sbp	}
150575374Sbp	smbfs_findclose(ctx, scred);
150675374Sbp	return error;
150775374Sbp}
1508