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 *
1475374Sbp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1575374Sbp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1675374Sbp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1775374Sbp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1875374Sbp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1975374Sbp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2075374Sbp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2175374Sbp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2275374Sbp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2375374Sbp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2475374Sbp * SUCH DAMAGE.
2575374Sbp *
2675374Sbp * $FreeBSD$
2775374Sbp */
2875374Sbp#include <sys/param.h>
2975374Sbp#include <sys/systm.h>
3075374Sbp#include <sys/kernel.h>
3175374Sbp#include <sys/malloc.h>
3275374Sbp#include <sys/proc.h>
3375374Sbp#include <sys/lock.h>
3475374Sbp#include <sys/vnode.h>
3575374Sbp#include <sys/mbuf.h>
3675374Sbp#include <sys/mount.h>
37227650Skevlo#include <sys/endian.h>
3875374Sbp
3975374Sbp#ifdef USE_MD5_HASH
4075374Sbp#include <sys/md5.h>
4175374Sbp#endif
4275374Sbp
4375374Sbp#include <netsmb/smb.h>
4475374Sbp#include <netsmb/smb_subr.h>
4575374Sbp#include <netsmb/smb_rq.h>
4675374Sbp#include <netsmb/smb_conn.h>
4775374Sbp
4875374Sbp#include <fs/smbfs/smbfs.h>
4975374Sbp#include <fs/smbfs/smbfs_node.h>
5075374Sbp#include <fs/smbfs/smbfs_subr.h>
5175374Sbp
5275374Sbp/*
5375374Sbp * Lack of inode numbers leads us to the problem of generating them.
5475374Sbp * Partially this problem can be solved by having a dir/file cache
5575374Sbp * with inode numbers generated from the incremented by one counter.
5675374Sbp * However this way will require too much kernel memory, gives all
5775374Sbp * sorts of locking and consistency problems, not to mentinon counter overflows.
5875374Sbp * So, I'm decided to use a hash function to generate pseudo random (and unique)
5975374Sbp * inode numbers.
6075374Sbp */
6175374Sbpstatic long
6275374Sbpsmbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
6375374Sbp{
6475374Sbp#ifdef USE_MD5_HASH
6575374Sbp	MD5_CTX md5;
6675374Sbp	u_int32_t state[4];
6775374Sbp	long ino;
6875374Sbp	int i;
6975374Sbp
7075374Sbp	MD5Init(&md5);
7175374Sbp	MD5Update(&md5, name, nmlen);
7275374Sbp	MD5Final((u_char *)state, &md5);
7375374Sbp	for (i = 0, ino = 0; i < 4; i++)
7475374Sbp		ino += state[i];
7575374Sbp	return dnp->n_ino + ino;
7675374Sbp#endif
7775374Sbp	u_int32_t ino;
7875374Sbp
7975374Sbp	ino = dnp->n_ino + smbfs_hash(name, nmlen);
8075374Sbp	if (ino <= 2)
8175374Sbp		ino += 3;
8275374Sbp	return ino;
8375374Sbp}
8475374Sbp
8575374Sbpstatic int
8675374Sbpsmbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end,
8775374Sbp	struct smb_cred *scred)
8875374Sbp{
8975374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
90242386Sdavide	struct smb_rq *rqp;
9175374Sbp	struct mbchain *mbp;
9275374Sbp	u_char ltype = 0;
9375374Sbp	int error;
9475374Sbp
9575374Sbp	if (op == SMB_LOCK_SHARED)
9675374Sbp		ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
97252558Sdavide
98252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred, &rqp);
99252558Sdavide	if (error)
100252558Sdavide		return (error);
10175374Sbp	smb_rq_getrequest(rqp, &mbp);
10275374Sbp	smb_rq_wstart(rqp);
103103533Sbp	mb_put_uint8(mbp, 0xff);	/* secondary command */
10475374Sbp	mb_put_uint8(mbp, 0);		/* MBZ */
10575374Sbp	mb_put_uint16le(mbp, 0);
10675374Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
10775374Sbp	mb_put_uint8(mbp, ltype);	/* locktype */
10875374Sbp	mb_put_uint8(mbp, 0);		/* oplocklevel - 0 seems is NO_OPLOCK */
109103533Sbp	mb_put_uint32le(mbp, 0);	/* timeout - break immediately */
11075374Sbp	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
11175374Sbp	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
11275374Sbp	smb_rq_wend(rqp);
11375374Sbp	smb_rq_bstart(rqp);
11475374Sbp	mb_put_uint16le(mbp, pid);
11575374Sbp	mb_put_uint32le(mbp, start);
11675374Sbp	mb_put_uint32le(mbp, end - start);
11775374Sbp	smb_rq_bend(rqp);
11875374Sbp	error = smb_rq_simple(rqp);
11975374Sbp	smb_rq_done(rqp);
12075374Sbp	return error;
12175374Sbp}
12275374Sbp
12375374Sbpint
12475374Sbpsmbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
12575374Sbp	off_t start, off_t end,	struct smb_cred *scred)
12675374Sbp{
12775374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
12875374Sbp
12975374Sbp	if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
13075374Sbp		/*
13175374Sbp		 * TODO: use LOCK_BYTE_RANGE here.
13275374Sbp		 */
13375374Sbp		return EINVAL;
13475374Sbp	else
135106595Sjhb		return smbfs_smb_lockandx(np, op, (uintptr_t)id, start, end, scred);
13675374Sbp}
13775374Sbp
138265243Saestatic int
139265243Saesmbfs_query_info_fs(struct smb_share *ssp, struct statfs *sbp,
14075374Sbp	struct smb_cred *scred)
14175374Sbp{
14275374Sbp	struct smb_t2rq *t2p;
14375374Sbp	struct mbchain *mbp;
14475374Sbp	struct mdchain *mdp;
145265243Sae	uint32_t bsize, bpu;
146265243Sae	int64_t units, funits;
147265243Sae	int error;
148265243Sae
149265243Sae	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
150265243Sae	    scred, &t2p);
151265243Sae	if (error)
152265243Sae		return (error);
153265243Sae	mbp = &t2p->t2_tparam;
154265243Sae	mb_init(mbp);
155265243Sae	mb_put_uint16le(mbp, SMB_QUERY_FS_SIZE_INFO);
156265243Sae	t2p->t2_maxpcount = 2;
157265243Sae	t2p->t2_maxdcount = sizeof(int64_t) * 2 + sizeof(uint32_t) * 2;
158265243Sae	error = smb_t2_request(t2p);
159265243Sae	if (error) {
160265243Sae		smb_t2_done(t2p);
161265243Sae		return (error);
162265243Sae	}
163265243Sae	mdp = &t2p->t2_rdata;
164265243Sae	md_get_int64le(mdp, &units);
165265243Sae	md_get_int64le(mdp, &funits);
166265243Sae	md_get_uint32le(mdp, &bpu);
167265243Sae	md_get_uint32le(mdp, &bsize);
168265243Sae	sbp->f_bsize = bpu * bsize;	/* fundamental filesystem block size */
169265243Sae	sbp->f_blocks= (uint64_t)units;	/* total data blocks in filesystem */
170265243Sae	sbp->f_bfree = (uint64_t)funits;/* free blocks in fs */
171265243Sae	sbp->f_bavail= (uint64_t)funits;/* free blocks avail to non-superuser */
172265243Sae	sbp->f_files = 0xffff;		/* total file nodes in filesystem */
173265243Sae	sbp->f_ffree = 0xffff;		/* free file nodes in fs */
174265243Sae	smb_t2_done(t2p);
175265243Sae	return (0);
176265243Sae}
177265243Sae
178265243Sae
179265243Saestatic int
180265243Saesmbfs_query_info_alloc(struct smb_share *ssp, struct statfs *sbp,
181265243Sae	struct smb_cred *scred)
182265243Sae{
183265243Sae	struct smb_t2rq *t2p;
184265243Sae	struct mbchain *mbp;
185265243Sae	struct mdchain *mdp;
18675374Sbp	u_int16_t bsize;
18775374Sbp	u_int32_t units, bpu, funits;
18875374Sbp	int error;
18975374Sbp
19075374Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
19175374Sbp	    scred, &t2p);
19275374Sbp	if (error)
19375374Sbp		return error;
19475374Sbp	mbp = &t2p->t2_tparam;
19575374Sbp	mb_init(mbp);
19675374Sbp	mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
19775374Sbp	t2p->t2_maxpcount = 4;
19875374Sbp	t2p->t2_maxdcount = 4 * 4 + 2;
19975374Sbp	error = smb_t2_request(t2p);
20075374Sbp	if (error) {
20175374Sbp		smb_t2_done(t2p);
20275374Sbp		return error;
20375374Sbp	}
20475374Sbp	mdp = &t2p->t2_rdata;
20575374Sbp	md_get_uint32(mdp, NULL);	/* fs id */
20675374Sbp	md_get_uint32le(mdp, &bpu);
20775374Sbp	md_get_uint32le(mdp, &units);
20875374Sbp	md_get_uint32le(mdp, &funits);
20975374Sbp	md_get_uint16le(mdp, &bsize);
21096755Strhodes	sbp->f_bsize = bpu * bsize;	/* fundamental filesystem block size */
21196755Strhodes	sbp->f_blocks= units;		/* total data blocks in filesystem */
21275374Sbp	sbp->f_bfree = funits;		/* free blocks in fs */
21375374Sbp	sbp->f_bavail= funits;		/* free blocks avail to non-superuser */
21496755Strhodes	sbp->f_files = 0xffff;		/* total file nodes in filesystem */
21575374Sbp	sbp->f_ffree = 0xffff;		/* free file nodes in fs */
21675374Sbp	smb_t2_done(t2p);
21775374Sbp	return 0;
21875374Sbp}
21975374Sbp
220265243Saestatic int
221265243Saesmbfs_query_info_disk(struct smb_share *ssp, struct statfs *sbp,
22275374Sbp	struct smb_cred *scred)
22375374Sbp{
224242386Sdavide	struct smb_rq *rqp;
22575374Sbp	struct mdchain *mdp;
22675374Sbp	u_int16_t units, bpu, bsize, funits;
22775374Sbp	int error;
22875374Sbp
229252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
230252558Sdavide	    scred, &rqp);
231252558Sdavide	if (error)
232252558Sdavide		return (error);
23375374Sbp	smb_rq_wstart(rqp);
23475374Sbp	smb_rq_wend(rqp);
23575374Sbp	smb_rq_bstart(rqp);
23675374Sbp	smb_rq_bend(rqp);
23775374Sbp	error = smb_rq_simple(rqp);
23875374Sbp	if (error) {
23975374Sbp		smb_rq_done(rqp);
24075374Sbp		return error;
24175374Sbp	}
24275374Sbp	smb_rq_getreply(rqp, &mdp);
24375374Sbp	md_get_uint16le(mdp, &units);
24475374Sbp	md_get_uint16le(mdp, &bpu);
24575374Sbp	md_get_uint16le(mdp, &bsize);
24675374Sbp	md_get_uint16le(mdp, &funits);
24796755Strhodes	sbp->f_bsize = bpu * bsize;	/* fundamental filesystem block size */
24896755Strhodes	sbp->f_blocks= units;		/* total data blocks in filesystem */
24975374Sbp	sbp->f_bfree = funits;		/* free blocks in fs */
25075374Sbp	sbp->f_bavail= funits;		/* free blocks avail to non-superuser */
25196755Strhodes	sbp->f_files = 0xffff;		/* total file nodes in filesystem */
25275374Sbp	sbp->f_ffree = 0xffff;		/* free file nodes in fs */
25375374Sbp	smb_rq_done(rqp);
25475374Sbp	return 0;
25575374Sbp}
25675374Sbp
257265243Saeint
258265243Saesmbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
259265243Sae	struct smb_cred *scred)
260265243Sae{
261265243Sae
262265243Sae	if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) {
263265243Sae		if (smbfs_query_info_fs(ssp, sbp, scred) == 0)
264265243Sae			return (0);
265265243Sae		if (smbfs_query_info_alloc(ssp, sbp, scred) == 0)
266265243Sae			return (0);
267265243Sae	}
268265243Sae	return (smbfs_query_info_disk(ssp, sbp, scred));
269265243Sae}
270265243Sae
271103533Sbpstatic int
272103533Sbpsmbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
273103533Sbp{
274103533Sbp	struct smb_t2rq *t2p;
275103533Sbp	struct smb_share *ssp = np->n_mount->sm_share;
276103533Sbp	struct mbchain *mbp;
277103533Sbp	int error;
278103533Sbp
279103533Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
280103533Sbp	    scred, &t2p);
281103533Sbp	if (error)
282103533Sbp		return error;
283103533Sbp	mbp = &t2p->t2_tparam;
284103533Sbp	mb_init(mbp);
285103533Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
286103533Sbp	mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO);
287103533Sbp	mb_put_uint32le(mbp, 0);
288103533Sbp	mbp = &t2p->t2_tdata;
289103533Sbp	mb_init(mbp);
290103533Sbp	mb_put_int64le(mbp, newsize);
291103533Sbp	mb_put_uint32le(mbp, 0);			/* padding */
292103533Sbp	mb_put_uint16le(mbp, 0);
293103533Sbp	t2p->t2_maxpcount = 2;
294103533Sbp	t2p->t2_maxdcount = 0;
295103533Sbp	error = smb_t2_request(t2p);
296103533Sbp	smb_t2_done(t2p);
297103533Sbp	return error;
298103533Sbp}
299103533Sbp
300103533Sbpstatic int
301103533Sbpsmb_smb_flush(struct smbnode *np, struct smb_cred *scred)
302103533Sbp{
303103533Sbp	struct smb_share *ssp = np->n_mount->sm_share;
304242386Sdavide	struct smb_rq *rqp;
305103533Sbp	struct mbchain *mbp;
306103533Sbp	int error;
307103533Sbp
308124434Stjr	if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) ||
309116486Stjr	    SMBTOV(np)->v_type != VREG)
310108470Sschweikh		return 0; /* not a regular open file */
311252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_FLUSH, scred, &rqp);
312252558Sdavide	if (error)
313103533Sbp		return (error);
314103533Sbp	smb_rq_getrequest(rqp, &mbp);
315103533Sbp	smb_rq_wstart(rqp);
316103533Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
317103533Sbp	smb_rq_wend(rqp);
318103533Sbp	smb_rq_bstart(rqp);
319103533Sbp	smb_rq_bend(rqp);
320103533Sbp	error = smb_rq_simple(rqp);
321103533Sbp	smb_rq_done(rqp);
322103533Sbp	if (!error)
323103533Sbp		np->n_flag &= ~NFLUSHWIRE;
324103533Sbp	return (error);
325103533Sbp}
326103533Sbp
32775374Sbpint
328103533Sbpsmbfs_smb_flush(struct smbnode *np, struct smb_cred *scred)
329103533Sbp{
330103533Sbp	if (np->n_flag & NFLUSHWIRE)
331103533Sbp		return (smb_smb_flush(np, scred));
332103533Sbp	return (0);
333103533Sbp}
334103533Sbp
335103533Sbpint
33675374Sbpsmbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred)
33775374Sbp{
33875374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
339242386Sdavide	struct smb_rq *rqp;
34075374Sbp	struct mbchain *mbp;
34175374Sbp	int error;
34275374Sbp
343103533Sbp	if (!smbfs_smb_seteof(np, (int64_t) newsize, scred)) {
344103533Sbp		np->n_flag |= NFLUSHWIRE;
345103533Sbp		return (0);
346103533Sbp	}
347103533Sbp
348252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
349252558Sdavide	if (error)
350252558Sdavide		return (error);
35175374Sbp	smb_rq_getrequest(rqp, &mbp);
35275374Sbp	smb_rq_wstart(rqp);
35375374Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
35475374Sbp	mb_put_uint16le(mbp, 0);
35575374Sbp	mb_put_uint32le(mbp, newsize);
35675374Sbp	mb_put_uint16le(mbp, 0);
35775374Sbp	smb_rq_wend(rqp);
35875374Sbp	smb_rq_bstart(rqp);
35975374Sbp	mb_put_uint8(mbp, SMB_DT_DATA);
36075374Sbp	mb_put_uint16le(mbp, 0);
36175374Sbp	smb_rq_bend(rqp);
36275374Sbp	error = smb_rq_simple(rqp);
36375374Sbp	smb_rq_done(rqp);
36475374Sbp	return error;
36575374Sbp}
36675374Sbp
367103533Sbpint
368103533Sbpsmbfs_smb_query_info(struct smbnode *np, const char *name, int len,
369103533Sbp		     struct smbfattr *fap, struct smb_cred *scred)
370103533Sbp{
371242386Sdavide	struct smb_rq *rqp;
372103533Sbp	struct smb_share *ssp = np->n_mount->sm_share;
373103533Sbp	struct mbchain *mbp;
374103533Sbp	struct mdchain *mdp;
375103533Sbp	u_int8_t wc;
376103533Sbp	int error;
377103533Sbp	u_int16_t wattr;
378103533Sbp	u_int32_t lint;
37975374Sbp
380252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred,
381252558Sdavide	    &rqp);
382252558Sdavide	if (error)
383252558Sdavide		return (error);
384103533Sbp	smb_rq_getrequest(rqp, &mbp);
385103533Sbp	smb_rq_wstart(rqp);
386103533Sbp	smb_rq_wend(rqp);
387103533Sbp	smb_rq_bstart(rqp);
388103533Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
389103533Sbp	do {
390103533Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len);
391103533Sbp		if (error)
392103533Sbp			break;
393103533Sbp		smb_rq_bend(rqp);
394103533Sbp		error = smb_rq_simple(rqp);
395103533Sbp		if (error)
396103533Sbp			break;
397103533Sbp		smb_rq_getreply(rqp, &mdp);
398103533Sbp		if (md_get_uint8(mdp, &wc) != 0 || wc != 10) {
399103533Sbp			error = EBADRPC;
400103533Sbp			break;
401103533Sbp		}
402103533Sbp		md_get_uint16le(mdp, &wattr);
403103533Sbp		fap->fa_attr = wattr;
404103533Sbp		/*
405103533Sbp		 * Be careful using the time returned here, as
406103533Sbp		 * with FAT on NT4SP6, at least, the time returned is low
407103533Sbp		 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
408103533Sbp		 * over about every seven minutes!
409103533Sbp		 */
410103533Sbp		md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */
411103533Sbp		if (lint)	/* avoid bogus zero returns */
412103533Sbp			smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz,
413103533Sbp					      &fap->fa_mtime);
414103533Sbp		md_get_uint32le(mdp, &lint);
415103533Sbp		fap->fa_size = lint;
416103533Sbp	} while(0);
417103533Sbp	smb_rq_done(rqp);
418103533Sbp	return error;
419103533Sbp}
420103533Sbp
42175374Sbp/*
42275374Sbp * Set DOS file attributes. mtime should be NULL for dialects above lm10
42375374Sbp */
42475374Sbpint
42575374Sbpsmbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
42675374Sbp	struct smb_cred *scred)
42775374Sbp{
428242386Sdavide	struct smb_rq *rqp;
42975374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
43075374Sbp	struct mbchain *mbp;
43175374Sbp	u_long time;
43275374Sbp	int error, svtz;
43375374Sbp
434252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred,
435252558Sdavide	    &rqp);
436252558Sdavide	if (error)
437252558Sdavide		return (error);
43875374Sbp	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
43975374Sbp	smb_rq_getrequest(rqp, &mbp);
44075374Sbp	smb_rq_wstart(rqp);
44175374Sbp	mb_put_uint16le(mbp, attr);
44275374Sbp	if (mtime) {
44375374Sbp		smb_time_local2server(mtime, svtz, &time);
44475374Sbp	} else
44575374Sbp		time = 0;
44675374Sbp	mb_put_uint32le(mbp, time);		/* mtime */
44775374Sbp	mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
44875374Sbp	smb_rq_wend(rqp);
44975374Sbp	smb_rq_bstart(rqp);
45075374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
45175374Sbp	do {
45275374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
45375374Sbp		if (error)
45475374Sbp			break;
45575374Sbp		mb_put_uint8(mbp, SMB_DT_ASCII);
456227650Skevlo		if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
457227650Skevlo			mb_put_padbyte(mbp);
458227650Skevlo			mb_put_uint8(mbp, 0);	/* 1st byte of NULL Unicode char */
459227650Skevlo		}
46075374Sbp		mb_put_uint8(mbp, 0);
46175374Sbp		smb_rq_bend(rqp);
46275374Sbp		error = smb_rq_simple(rqp);
463163993Sbp		if (error) {
464163993Sbp			SMBERROR("smb_rq_simple(rqp) => error %d\n", error);
46575374Sbp			break;
466163993Sbp		}
46775374Sbp	} while(0);
46875374Sbp	smb_rq_done(rqp);
46975374Sbp	return error;
47075374Sbp}
47175374Sbp
47275374Sbp/*
47375374Sbp * Note, win95 doesn't support this call.
47475374Sbp */
47575374Sbpint
47675374Sbpsmbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
47775374Sbp	struct timespec *atime, int attr, struct smb_cred *scred)
47875374Sbp{
47975374Sbp	struct smb_t2rq *t2p;
48075374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
48175374Sbp	struct smb_vc *vcp = SSTOVC(ssp);
48275374Sbp	struct mbchain *mbp;
48375374Sbp	u_int16_t date, time;
48475374Sbp	int error, tzoff;
48575374Sbp
48675374Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
48775374Sbp	    scred, &t2p);
48875374Sbp	if (error)
48975374Sbp		return error;
49075374Sbp	mbp = &t2p->t2_tparam;
49175374Sbp	mb_init(mbp);
49275374Sbp	mb_put_uint16le(mbp, SMB_INFO_STANDARD);
49375374Sbp	mb_put_uint32le(mbp, 0);		/* MBZ */
494103533Sbp	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
49575374Sbp	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
49675374Sbp	if (error) {
49775374Sbp		smb_t2_done(t2p);
49875374Sbp		return error;
49975374Sbp	}
50075374Sbp	tzoff = vcp->vc_sopt.sv_tz;
50175374Sbp	mbp = &t2p->t2_tdata;
50275374Sbp	mb_init(mbp);
50375374Sbp	mb_put_uint32le(mbp, 0);		/* creation time */
50475374Sbp	if (atime)
50575374Sbp		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
50675374Sbp	else
50775374Sbp		time = date = 0;
50875374Sbp	mb_put_uint16le(mbp, date);
50975374Sbp	mb_put_uint16le(mbp, time);
51075374Sbp	if (mtime)
51175374Sbp		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
51275374Sbp	else
51375374Sbp		time = date = 0;
51475374Sbp	mb_put_uint16le(mbp, date);
51575374Sbp	mb_put_uint16le(mbp, time);
51675374Sbp	mb_put_uint32le(mbp, 0);		/* file size */
51775374Sbp	mb_put_uint32le(mbp, 0);		/* allocation unit size */
51875374Sbp	mb_put_uint16le(mbp, attr);	/* DOS attr */
51975374Sbp	mb_put_uint32le(mbp, 0);		/* EA size */
52075374Sbp	t2p->t2_maxpcount = 5 * 2;
52175374Sbp	t2p->t2_maxdcount = vcp->vc_txmax;
52275374Sbp	error = smb_t2_request(t2p);
52375374Sbp	smb_t2_done(t2p);
52475374Sbp	return error;
52575374Sbp}
52675374Sbp
52775374Sbp/*
52875374Sbp * NT level. Specially for win9x
52975374Sbp */
53075374Sbpint
53175374Sbpsmbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
53275374Sbp	struct timespec *atime, struct smb_cred *scred)
53375374Sbp{
53475374Sbp	struct smb_t2rq *t2p;
53575374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
53675374Sbp	struct smb_vc *vcp = SSTOVC(ssp);
53775374Sbp	struct mbchain *mbp;
53875374Sbp	int64_t tm;
53975374Sbp	int error, tzoff;
54075374Sbp
54175374Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
54275374Sbp	    scred, &t2p);
54375374Sbp	if (error)
54475374Sbp		return error;
54575374Sbp	mbp = &t2p->t2_tparam;
54675374Sbp	mb_init(mbp);
54775374Sbp	mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
54875374Sbp	mb_put_uint32le(mbp, 0);		/* MBZ */
549103533Sbp	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
55075374Sbp	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
55175374Sbp	if (error) {
55275374Sbp		smb_t2_done(t2p);
55375374Sbp		return error;
55475374Sbp	}
55575374Sbp	tzoff = vcp->vc_sopt.sv_tz;
55675374Sbp	mbp = &t2p->t2_tdata;
55775374Sbp	mb_init(mbp);
55875374Sbp	mb_put_int64le(mbp, 0);		/* creation time */
55975374Sbp	if (atime) {
56075374Sbp		smb_time_local2NT(atime, tzoff, &tm);
56175374Sbp	} else
56275374Sbp		tm = 0;
56375374Sbp	mb_put_int64le(mbp, tm);
56475374Sbp	if (mtime) {
56575374Sbp		smb_time_local2NT(mtime, tzoff, &tm);
56675374Sbp	} else
56775374Sbp		tm = 0;
56875374Sbp	mb_put_int64le(mbp, tm);
56975374Sbp	mb_put_int64le(mbp, tm);		/* change time */
57075374Sbp	mb_put_uint32le(mbp, attr);		/* attr */
57175374Sbp	t2p->t2_maxpcount = 24;
57275374Sbp	t2p->t2_maxdcount = 56;
57375374Sbp	error = smb_t2_request(t2p);
57475374Sbp	smb_t2_done(t2p);
57575374Sbp	return error;
57675374Sbp}
57775374Sbp
57875374Sbp/*
57975374Sbp * Set file atime and mtime. Doesn't supported by core dialect.
58075374Sbp */
58175374Sbpint
58275374Sbpsmbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
58375374Sbp	struct timespec *atime, struct smb_cred *scred)
58475374Sbp{
585242386Sdavide	struct smb_rq *rqp;
58675374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
58775374Sbp	struct mbchain *mbp;
58875374Sbp	u_int16_t date, time;
58975374Sbp	int error, tzoff;
59075374Sbp
591252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred,
592252558Sdavide	    &rqp);
593252558Sdavide	if (error)
594252558Sdavide		return (error);
59575374Sbp	tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
59675374Sbp	smb_rq_getrequest(rqp, &mbp);
59775374Sbp	smb_rq_wstart(rqp);
59875374Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
59975374Sbp	mb_put_uint32le(mbp, 0);		/* creation time */
60075374Sbp
60175374Sbp	if (atime)
60275374Sbp		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
60375374Sbp	else
60475374Sbp		time = date = 0;
60575374Sbp	mb_put_uint16le(mbp, date);
60675374Sbp	mb_put_uint16le(mbp, time);
60775374Sbp	if (mtime)
60875374Sbp		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
60975374Sbp	else
61075374Sbp		time = date = 0;
61175374Sbp	mb_put_uint16le(mbp, date);
61275374Sbp	mb_put_uint16le(mbp, time);
61375374Sbp	smb_rq_wend(rqp);
61475374Sbp	smb_rq_bstart(rqp);
61575374Sbp	smb_rq_bend(rqp);
61675374Sbp	error = smb_rq_simple(rqp);
61775374Sbp	SMBSDEBUG("%d\n", error);
61875374Sbp	smb_rq_done(rqp);
61975374Sbp	return error;
62075374Sbp}
62175374Sbp
62275374Sbp/*
62375374Sbp * Set DOS file attributes.
624223843Sjonathan * Looks like this call can be used only if SMB_CAP_NT_SMBS bit is on.
62575374Sbp */
62675374Sbpint
62775374Sbpsmbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
62875374Sbp	struct timespec *atime, struct smb_cred *scred)
62975374Sbp{
63075374Sbp	struct smb_t2rq *t2p;
63175374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
63275374Sbp	struct mbchain *mbp;
63375374Sbp	int64_t tm;
63475374Sbp	int error, svtz;
63575374Sbp
63675374Sbp	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
63775374Sbp	    scred, &t2p);
63875374Sbp	if (error)
63975374Sbp		return error;
64075374Sbp	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
64175374Sbp	mbp = &t2p->t2_tparam;
64275374Sbp	mb_init(mbp);
64375374Sbp	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
64475374Sbp	mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
64575374Sbp	mb_put_uint32le(mbp, 0);
64675374Sbp	mbp = &t2p->t2_tdata;
64775374Sbp	mb_init(mbp);
64875374Sbp	mb_put_int64le(mbp, 0);		/* creation time */
64975374Sbp	if (atime) {
65075374Sbp		smb_time_local2NT(atime, svtz, &tm);
65175374Sbp	} else
65275374Sbp		tm = 0;
65375374Sbp	mb_put_int64le(mbp, tm);
65475374Sbp	if (mtime) {
65575374Sbp		smb_time_local2NT(mtime, svtz, &tm);
65675374Sbp	} else
65775374Sbp		tm = 0;
65875374Sbp	mb_put_int64le(mbp, tm);
65975374Sbp	mb_put_int64le(mbp, tm);		/* change time */
66075374Sbp	mb_put_uint16le(mbp, attr);
66175374Sbp	mb_put_uint32le(mbp, 0);			/* padding */
66275374Sbp	mb_put_uint16le(mbp, 0);
66375374Sbp	t2p->t2_maxpcount = 2;
66475374Sbp	t2p->t2_maxdcount = 0;
66575374Sbp	error = smb_t2_request(t2p);
66675374Sbp	smb_t2_done(t2p);
66775374Sbp	return error;
66875374Sbp}
66975374Sbp
67075374Sbp
67175374Sbpint
67275374Sbpsmbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
67375374Sbp{
674242386Sdavide	struct smb_rq *rqp;
67575374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
67675374Sbp	struct mbchain *mbp;
67775374Sbp	struct mdchain *mdp;
67875374Sbp	u_int8_t wc;
67975374Sbp	u_int16_t fid, wattr, grantedmode;
68075374Sbp	int error;
68175374Sbp
682252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_OPEN, scred, &rqp);
683252558Sdavide	if (error)
684252558Sdavide		return (error);
68575374Sbp	smb_rq_getrequest(rqp, &mbp);
68675374Sbp	smb_rq_wstart(rqp);
68775374Sbp	mb_put_uint16le(mbp, accmode);
68875374Sbp	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
68975374Sbp	smb_rq_wend(rqp);
69075374Sbp	smb_rq_bstart(rqp);
69175374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
69275374Sbp	do {
69375374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
69475374Sbp		if (error)
69575374Sbp			break;
69675374Sbp		smb_rq_bend(rqp);
69775374Sbp		error = smb_rq_simple(rqp);
69875374Sbp		if (error)
69975374Sbp			break;
70075374Sbp		smb_rq_getreply(rqp, &mdp);
70175374Sbp		if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
70275374Sbp			error = EBADRPC;
70375374Sbp			break;
70475374Sbp		}
70575374Sbp		md_get_uint16(mdp, &fid);
70675374Sbp		md_get_uint16le(mdp, &wattr);
70775374Sbp		md_get_uint32(mdp, NULL);	/* mtime */
70875374Sbp		md_get_uint32(mdp, NULL);	/* fsize */
70975374Sbp		md_get_uint16le(mdp, &grantedmode);
71075374Sbp		/*
71175374Sbp		 * TODO: refresh attributes from this reply
71275374Sbp		 */
71375374Sbp	} while(0);
71475374Sbp	smb_rq_done(rqp);
71575374Sbp	if (error)
71675374Sbp		return error;
71775374Sbp	np->n_fid = fid;
71875374Sbp	np->n_rwstate = grantedmode;
71975374Sbp	return 0;
72075374Sbp}
72175374Sbp
72275374Sbp
72375374Sbpint
72475374Sbpsmbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
72575374Sbp	struct smb_cred *scred)
72675374Sbp{
727242386Sdavide	struct smb_rq *rqp;
72875374Sbp	struct mbchain *mbp;
72975374Sbp	u_long time;
73075374Sbp	int error;
73175374Sbp
732252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CLOSE, scred, &rqp);
733252558Sdavide	if (error)
734252558Sdavide		return (error);
73575374Sbp	smb_rq_getrequest(rqp, &mbp);
73675374Sbp	smb_rq_wstart(rqp);
73775374Sbp	mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
73875374Sbp	if (mtime) {
73975374Sbp		smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
74075374Sbp	} else
74175374Sbp		time = 0;
74275374Sbp	mb_put_uint32le(mbp, time);
74375374Sbp	smb_rq_wend(rqp);
74475374Sbp	smb_rq_bstart(rqp);
74575374Sbp	smb_rq_bend(rqp);
74675374Sbp	error = smb_rq_simple(rqp);
74775374Sbp	smb_rq_done(rqp);
74875374Sbp	return error;
74975374Sbp}
75075374Sbp
75175374Sbpint
75275374Sbpsmbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
75375374Sbp	struct smb_cred *scred)
75475374Sbp{
755242386Sdavide	struct smb_rq *rqp;
75675374Sbp	struct smb_share *ssp = dnp->n_mount->sm_share;
75775374Sbp	struct mbchain *mbp;
75875374Sbp	struct mdchain *mdp;
75975374Sbp	struct timespec ctime;
76075374Sbp	u_int8_t wc;
76175374Sbp	u_int16_t fid;
76275374Sbp	u_long tm;
76375374Sbp	int error;
76475374Sbp
765252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE, scred, &rqp);
766252558Sdavide	if (error)
767252558Sdavide		return (error);
76875374Sbp	smb_rq_getrequest(rqp, &mbp);
76975374Sbp	smb_rq_wstart(rqp);
77075374Sbp	mb_put_uint16le(mbp, SMB_FA_ARCHIVE);		/* attributes  */
77175374Sbp	nanotime(&ctime);
77275374Sbp	smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
77375374Sbp	mb_put_uint32le(mbp, tm);
77475374Sbp	smb_rq_wend(rqp);
77575374Sbp	smb_rq_bstart(rqp);
77675374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
77775374Sbp	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen);
77875374Sbp	if (!error) {
77975374Sbp		smb_rq_bend(rqp);
78075374Sbp		error = smb_rq_simple(rqp);
78175374Sbp		if (!error) {
78275374Sbp			smb_rq_getreply(rqp, &mdp);
78375374Sbp			md_get_uint8(mdp, &wc);
78475374Sbp			if (wc == 1)
78575374Sbp				md_get_uint16(mdp, &fid);
78675374Sbp			else
78775374Sbp				error = EBADRPC;
78875374Sbp		}
78975374Sbp	}
79075374Sbp	smb_rq_done(rqp);
79175374Sbp	if (error)
79275374Sbp		return error;
79375374Sbp	smbfs_smb_close(ssp, fid, &ctime, scred);
79475374Sbp	return error;
79575374Sbp}
79675374Sbp
79775374Sbpint
79875374Sbpsmbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
79975374Sbp{
800242386Sdavide	struct smb_rq *rqp;
80175374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
80275374Sbp	struct mbchain *mbp;
80375374Sbp	int error;
80475374Sbp
805252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE, scred, &rqp);
806252558Sdavide	if (error)
807252558Sdavide		return (error);
80875374Sbp	smb_rq_getrequest(rqp, &mbp);
80975374Sbp	smb_rq_wstart(rqp);
81075374Sbp	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
81175374Sbp	smb_rq_wend(rqp);
81275374Sbp	smb_rq_bstart(rqp);
81375374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
81475374Sbp	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
81575374Sbp	if (!error) {
81675374Sbp		smb_rq_bend(rqp);
81775374Sbp		error = smb_rq_simple(rqp);
81875374Sbp	}
81975374Sbp	smb_rq_done(rqp);
82075374Sbp	return error;
82175374Sbp}
82275374Sbp
82375374Sbpint
82475374Sbpsmbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
82575374Sbp	const char *tname, int tnmlen, struct smb_cred *scred)
82675374Sbp{
827242386Sdavide	struct smb_rq *rqp;
82875374Sbp	struct smb_share *ssp = src->n_mount->sm_share;
82975374Sbp	struct mbchain *mbp;
83075374Sbp	int error;
83175374Sbp
832252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_RENAME, scred, &rqp);
833252558Sdavide	if (error)
834252558Sdavide		return (error);
83575374Sbp	smb_rq_getrequest(rqp, &mbp);
83675374Sbp	smb_rq_wstart(rqp);
83775374Sbp	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
83875374Sbp	smb_rq_wend(rqp);
83975374Sbp	smb_rq_bstart(rqp);
84075374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
84175374Sbp	do {
84275374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
84375374Sbp		if (error)
84475374Sbp			break;
84575374Sbp		mb_put_uint8(mbp, SMB_DT_ASCII);
84675374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
84775374Sbp		if (error)
84875374Sbp			break;
84975374Sbp		smb_rq_bend(rqp);
85075374Sbp		error = smb_rq_simple(rqp);
85175374Sbp	} while(0);
85275374Sbp	smb_rq_done(rqp);
85375374Sbp	return error;
85475374Sbp}
85575374Sbp
85675374Sbpint
85775374Sbpsmbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
85875374Sbp	const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
85975374Sbp{
860242386Sdavide	struct smb_rq *rqp;
86175374Sbp	struct smb_share *ssp = src->n_mount->sm_share;
86275374Sbp	struct mbchain *mbp;
86375374Sbp	int error;
86475374Sbp
865252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_MOVE, scred, &rqp);
866252558Sdavide	if (error)
867252558Sdavide		return (error);
86875374Sbp	smb_rq_getrequest(rqp, &mbp);
86975374Sbp	smb_rq_wstart(rqp);
87075374Sbp	mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
87175374Sbp	mb_put_uint16le(mbp, 0x20);	/* delete target file */
87275374Sbp	mb_put_uint16le(mbp, flags);
87375374Sbp	smb_rq_wend(rqp);
87475374Sbp	smb_rq_bstart(rqp);
87575374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
87675374Sbp	do {
87775374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
87875374Sbp		if (error)
87975374Sbp			break;
88075374Sbp		mb_put_uint8(mbp, SMB_DT_ASCII);
88175374Sbp		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
88275374Sbp		if (error)
88375374Sbp			break;
88475374Sbp		smb_rq_bend(rqp);
88575374Sbp		error = smb_rq_simple(rqp);
88675374Sbp	} while(0);
88775374Sbp	smb_rq_done(rqp);
88875374Sbp	return error;
88975374Sbp}
89075374Sbp
89175374Sbpint
89275374Sbpsmbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
89375374Sbp	struct smb_cred *scred)
89475374Sbp{
895242386Sdavide	struct smb_rq *rqp;
89675374Sbp	struct smb_share *ssp = dnp->n_mount->sm_share;
89775374Sbp	struct mbchain *mbp;
89875374Sbp	int error;
89975374Sbp
900252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred,
901252558Sdavide	    &rqp);
902252558Sdavide	if (error)
903252558Sdavide		return (error);
90475374Sbp	smb_rq_getrequest(rqp, &mbp);
90575374Sbp	smb_rq_wstart(rqp);
90675374Sbp	smb_rq_wend(rqp);
90775374Sbp	smb_rq_bstart(rqp);
90875374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
90975374Sbp	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len);
91075374Sbp	if (!error) {
91175374Sbp		smb_rq_bend(rqp);
91275374Sbp		error = smb_rq_simple(rqp);
91375374Sbp	}
91475374Sbp	smb_rq_done(rqp);
91575374Sbp	return error;
91675374Sbp}
91775374Sbp
91875374Sbpint
91975374Sbpsmbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred)
92075374Sbp{
921242386Sdavide	struct smb_rq *rqp;
92275374Sbp	struct smb_share *ssp = np->n_mount->sm_share;
92375374Sbp	struct mbchain *mbp;
92475374Sbp	int error;
92575374Sbp
926252558Sdavide	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred,
927252558Sdavide	    &rqp);
928252558Sdavide	if (error)
929252558Sdavide		return (error);
93075374Sbp	smb_rq_getrequest(rqp, &mbp);
93175374Sbp	smb_rq_wstart(rqp);
93275374Sbp	smb_rq_wend(rqp);
93375374Sbp	smb_rq_bstart(rqp);
93475374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);
93575374Sbp	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
93675374Sbp	if (!error) {
93775374Sbp		smb_rq_bend(rqp);
93875374Sbp		error = smb_rq_simple(rqp);
93975374Sbp	}
94075374Sbp	smb_rq_done(rqp);
94175374Sbp	return error;
94275374Sbp}
94375374Sbp
94475374Sbpstatic int
94575374Sbpsmbfs_smb_search(struct smbfs_fctx *ctx)
94675374Sbp{
94775374Sbp	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
94875374Sbp	struct smb_rq *rqp;
94975374Sbp	struct mbchain *mbp;
95075374Sbp	struct mdchain *mdp;
95175374Sbp	u_int8_t wc, bt;
95275374Sbp	u_int16_t ec, dlen, bc;
95375374Sbp	int maxent, error, iseof = 0;
95475374Sbp
95575374Sbp	maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
95675374Sbp	if (ctx->f_rq) {
95775374Sbp		smb_rq_done(ctx->f_rq);
95875374Sbp		ctx->f_rq = NULL;
95975374Sbp	}
96075374Sbp	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
96175374Sbp	if (error)
962252558Sdavide		return (error);
96375374Sbp	ctx->f_rq = rqp;
96475374Sbp	smb_rq_getrequest(rqp, &mbp);
96575374Sbp	smb_rq_wstart(rqp);
96675374Sbp	mb_put_uint16le(mbp, maxent);	/* max entries to return */
96775374Sbp	mb_put_uint16le(mbp, ctx->f_attrmask);
96875374Sbp	smb_rq_wend(rqp);
96975374Sbp	smb_rq_bstart(rqp);
97075374Sbp	mb_put_uint8(mbp, SMB_DT_ASCII);	/* buffer format */
97175374Sbp	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
97275374Sbp		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
97375374Sbp		if (error)
97475374Sbp			return error;
97575374Sbp		mb_put_uint8(mbp, SMB_DT_VARIABLE);
97675374Sbp		mb_put_uint16le(mbp, 0);	/* context length */
97775374Sbp		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
97875374Sbp	} else {
979227650Skevlo		if (SMB_UNICODE_STRINGS(vcp)) {
980227650Skevlo			mb_put_padbyte(mbp);
981227650Skevlo			mb_put_uint8(mbp, 0);
982227650Skevlo		}
98375374Sbp		mb_put_uint8(mbp, 0);	/* file name length */
98475374Sbp		mb_put_uint8(mbp, SMB_DT_VARIABLE);
98575374Sbp		mb_put_uint16le(mbp, SMB_SKEYLEN);
98675374Sbp		mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
98775374Sbp	}
98875374Sbp	smb_rq_bend(rqp);
98975374Sbp	error = smb_rq_simple(rqp);
99075374Sbp	if (error) {
99175374Sbp		if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
99275374Sbp			error = 0;
99375374Sbp			iseof = 1;
99475374Sbp			ctx->f_flags |= SMBFS_RDD_EOF;
99575374Sbp		} else
99675374Sbp			return error;
99775374Sbp	}
99875374Sbp	smb_rq_getreply(rqp, &mdp);
99975374Sbp	md_get_uint8(mdp, &wc);
100075374Sbp	if (wc != 1)
100175374Sbp		return iseof ? ENOENT : EBADRPC;
100275374Sbp	md_get_uint16le(mdp, &ec);
100375374Sbp	if (ec == 0)
100475374Sbp		return ENOENT;
100575374Sbp	ctx->f_ecnt = ec;
100675374Sbp	md_get_uint16le(mdp, &bc);
100775374Sbp	if (bc < 3)
100875374Sbp		return EBADRPC;
100975374Sbp	bc -= 3;
101075374Sbp	md_get_uint8(mdp, &bt);
101175374Sbp	if (bt != SMB_DT_VARIABLE)
101275374Sbp		return EBADRPC;
101375374Sbp	md_get_uint16le(mdp, &dlen);
101475374Sbp	if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
101575374Sbp		return EBADRPC;
101675374Sbp	return 0;
101775374Sbp}
101875374Sbp
101975374Sbpstatic int
102075374Sbpsmbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
102175374Sbp	const char *wildcard, int wclen, int attr, struct smb_cred *scred)
102275374Sbp{
102375374Sbp	ctx->f_attrmask = attr;
102475374Sbp	if (wildcard) {
102575374Sbp		if (wclen == 1 && wildcard[0] == '*') {
102675374Sbp			ctx->f_wildcard = "*.*";
102775374Sbp			ctx->f_wclen = 3;
102875374Sbp		} else {
102975374Sbp			ctx->f_wildcard = wildcard;
103075374Sbp			ctx->f_wclen = wclen;
103175374Sbp		}
103275374Sbp	} else {
103375374Sbp		ctx->f_wildcard = NULL;
103475374Sbp		ctx->f_wclen = 0;
103575374Sbp	}
103675374Sbp	ctx->f_name = ctx->f_fname;
103775374Sbp	return 0;
103875374Sbp}
103975374Sbp
104075374Sbpstatic int
104175374Sbpsmbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
104275374Sbp{
104375374Sbp	struct mdchain *mbp;
104475374Sbp	struct smb_rq *rqp;
104575374Sbp	char *cp;
104675374Sbp	u_int8_t battr;
104775374Sbp	u_int16_t date, time;
104875374Sbp	u_int32_t size;
104975374Sbp	int error;
105075374Sbp
105175374Sbp	if (ctx->f_ecnt == 0) {
105275374Sbp		if (ctx->f_flags & SMBFS_RDD_EOF)
105375374Sbp			return ENOENT;
105475374Sbp		ctx->f_left = ctx->f_limit = limit;
105575374Sbp		error = smbfs_smb_search(ctx);
105675374Sbp		if (error)
105775374Sbp			return error;
105875374Sbp	}
105975374Sbp	rqp = ctx->f_rq;
106075374Sbp	smb_rq_getreply(rqp, &mbp);
106175374Sbp	md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
106275374Sbp	md_get_uint8(mbp, &battr);
106375374Sbp	md_get_uint16le(mbp, &time);
106475374Sbp	md_get_uint16le(mbp, &date);
106575374Sbp	md_get_uint32le(mbp, &size);
106675374Sbp	cp = ctx->f_name;
106775374Sbp	md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM);
106875374Sbp	cp[sizeof(ctx->f_fname) - 1] = 0;
106975374Sbp	cp += strlen(cp) - 1;
107075374Sbp	while (*cp == ' ' && cp >= ctx->f_name)
107175374Sbp		*cp-- = 0;
107275374Sbp	ctx->f_attr.fa_attr = battr;
107375374Sbp	smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
107475374Sbp	    &ctx->f_attr.fa_mtime);
107575374Sbp	ctx->f_attr.fa_size = size;
107675374Sbp	ctx->f_nmlen = strlen(ctx->f_name);
107775374Sbp	ctx->f_ecnt--;
107875374Sbp	ctx->f_left--;
107975374Sbp	return 0;
108075374Sbp}
108175374Sbp
108275374Sbpstatic int
108375374Sbpsmbfs_findcloseLM1(struct smbfs_fctx *ctx)
108475374Sbp{
108575374Sbp	if (ctx->f_rq)
108675374Sbp		smb_rq_done(ctx->f_rq);
108775374Sbp	return 0;
108875374Sbp}
108975374Sbp
109075374Sbp/*
109175374Sbp * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
109275374Sbp */
109375374Sbpstatic int
109475374Sbpsmbfs_smb_trans2find2(struct smbfs_fctx *ctx)
109575374Sbp{
109675374Sbp	struct smb_t2rq *t2p;
109775374Sbp	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
109875374Sbp	struct mbchain *mbp;
109975374Sbp	struct mdchain *mdp;
110075374Sbp	u_int16_t tw, flags;
110175374Sbp	int error;
110275374Sbp
110375374Sbp	if (ctx->f_t2) {
110475374Sbp		smb_t2_done(ctx->f_t2);
110575374Sbp		ctx->f_t2 = NULL;
110675374Sbp	}
110775374Sbp	ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
110875374Sbp	flags = 8 | 2;			/* <resume> | <close if EOS> */
110975374Sbp	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
111075374Sbp		flags |= 1;		/* close search after this request */
111175374Sbp		ctx->f_flags |= SMBFS_RDD_NOCLOSE;
111275374Sbp	}
111375374Sbp	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
111475374Sbp		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
111575374Sbp		    ctx->f_scred, &t2p);
111675374Sbp		if (error)
111775374Sbp			return error;
111875374Sbp		ctx->f_t2 = t2p;
111975374Sbp		mbp = &t2p->t2_tparam;
112075374Sbp		mb_init(mbp);
112175374Sbp		mb_put_uint16le(mbp, ctx->f_attrmask);
112275374Sbp		mb_put_uint16le(mbp, ctx->f_limit);
112375374Sbp		mb_put_uint16le(mbp, flags);
112475374Sbp		mb_put_uint16le(mbp, ctx->f_infolevel);
112575374Sbp		mb_put_uint32le(mbp, 0);
112675374Sbp		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
112775374Sbp		if (error)
112875374Sbp			return error;
112975374Sbp	} else	{
113075374Sbp		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
113175374Sbp		    ctx->f_scred, &t2p);
113275374Sbp		if (error)
113375374Sbp			return error;
113475374Sbp		ctx->f_t2 = t2p;
113575374Sbp		mbp = &t2p->t2_tparam;
113675374Sbp		mb_init(mbp);
113775374Sbp		mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
113875374Sbp		mb_put_uint16le(mbp, ctx->f_limit);
113975374Sbp		mb_put_uint16le(mbp, ctx->f_infolevel);
114075374Sbp		mb_put_uint32le(mbp, 0);		/* resume key */
114175374Sbp		mb_put_uint16le(mbp, flags);
114275374Sbp		if (ctx->f_rname)
1143227650Skevlo			mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen + 1, MB_MSYSTEM);
114475374Sbp		else
114575374Sbp			mb_put_uint8(mbp, 0);	/* resume file name */
114675374Sbp#if 0
114775374Sbp	struct timeval tv;
114875374Sbp	tv.tv_sec = 0;
114975374Sbp	tv.tv_usec = 200 * 1000;	/* 200ms */
115075374Sbp		if (vcp->vc_flags & SMBC_WIN95) {
115175374Sbp			/*
115275374Sbp			 * some implementations suggests to sleep here
115375374Sbp			 * for 200ms, due to the bug in the Win95.
115475374Sbp			 * I've didn't notice any problem, but put code
115575374Sbp			 * for it.
115675374Sbp			 */
1157167086Sjhb			 pause("fix95", tvtohz(&tv));
115875374Sbp		}
115975374Sbp#endif
116075374Sbp	}
116175374Sbp	t2p->t2_maxpcount = 5 * 2;
116275374Sbp	t2p->t2_maxdcount = vcp->vc_txmax;
116375374Sbp	error = smb_t2_request(t2p);
116475374Sbp	if (error)
116575374Sbp		return error;
116675374Sbp	mdp = &t2p->t2_rparam;
116775374Sbp	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
116875374Sbp		if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
116975374Sbp			return error;
117075374Sbp		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
117175374Sbp	}
117275374Sbp	if ((error = md_get_uint16le(mdp, &tw)) != 0)
117375374Sbp		return error;
117475374Sbp	ctx->f_ecnt = tw;
117575374Sbp	if ((error = md_get_uint16le(mdp, &tw)) != 0)
117675374Sbp		return error;
117775374Sbp	if (tw)
117875374Sbp		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
117975374Sbp	if ((error = md_get_uint16le(mdp, &tw)) != 0)
118075374Sbp		return error;
118175374Sbp	if ((error = md_get_uint16le(mdp, &tw)) != 0)
118275374Sbp		return error;
1183152678Sbp	if (ctx->f_ecnt == 0) {
1184152678Sbp		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
118575374Sbp		return ENOENT;
1186152678Sbp	}
118775374Sbp	ctx->f_rnameofs = tw;
118875374Sbp	mdp = &t2p->t2_rdata;
118975374Sbp	if (mdp->md_top == NULL) {
119075374Sbp		printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt);
119175374Sbp		return ENOENT;
119275374Sbp	}
119375374Sbp	if (mdp->md_top->m_len == 0) {
119475374Sbp		printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next);
119575374Sbp		return ENOENT;
119675374Sbp	}
119775374Sbp	ctx->f_eofs = 0;
119875374Sbp	return 0;
119975374Sbp}
120075374Sbp
120175374Sbpstatic int
120275374Sbpsmbfs_smb_findclose2(struct smbfs_fctx *ctx)
120375374Sbp{
1204242386Sdavide	struct smb_rq *rqp;
120575374Sbp	struct mbchain *mbp;
120675374Sbp	int error;
120775374Sbp
1208252558Sdavide	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
1209252558Sdavide	    ctx->f_scred, &rqp);
1210252558Sdavide	if (error)
1211252558Sdavide		return (error);
121275374Sbp	smb_rq_getrequest(rqp, &mbp);
121375374Sbp	smb_rq_wstart(rqp);
121475374Sbp	mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
121575374Sbp	smb_rq_wend(rqp);
121675374Sbp	smb_rq_bstart(rqp);
121775374Sbp	smb_rq_bend(rqp);
121875374Sbp	error = smb_rq_simple(rqp);
121975374Sbp	smb_rq_done(rqp);
122075374Sbp	return error;
122175374Sbp}
122275374Sbp
122375374Sbpstatic int
122475374Sbpsmbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
122575374Sbp	const char *wildcard, int wclen, int attr, struct smb_cred *scred)
122675374Sbp{
1227227650Skevlo	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1228227650Skevlo		ctx->f_name = malloc(SMB_MAXFNAMELEN * 2, M_SMBFSDATA, M_WAITOK);
1229227650Skevlo	} else
1230227650Skevlo		ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
123175374Sbp	ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
123275374Sbp	    SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
123375374Sbp	ctx->f_attrmask = attr;
123475374Sbp	ctx->f_wildcard = wildcard;
123575374Sbp	ctx->f_wclen = wclen;
123675374Sbp	return 0;
123775374Sbp}
123875374Sbp
123975374Sbpstatic int
124075374Sbpsmbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
124175374Sbp{
124275374Sbp	struct mdchain *mbp;
124375374Sbp	struct smb_t2rq *t2p;
124475374Sbp	char *cp;
124575374Sbp	u_int8_t tb;
124675374Sbp	u_int16_t date, time, wattr;
124775374Sbp	u_int32_t size, next, dattr;
124875374Sbp	int64_t lint;
124975374Sbp	int error, svtz, cnt, fxsz, nmlen, recsz;
125075374Sbp
125175374Sbp	if (ctx->f_ecnt == 0) {
125275374Sbp		if (ctx->f_flags & SMBFS_RDD_EOF)
125375374Sbp			return ENOENT;
125475374Sbp		ctx->f_left = ctx->f_limit = limit;
125575374Sbp		error = smbfs_smb_trans2find2(ctx);
125675374Sbp		if (error)
125775374Sbp			return error;
125875374Sbp	}
125975374Sbp	t2p = ctx->f_t2;
126075374Sbp	mbp = &t2p->t2_rdata;
126175374Sbp	svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
126275374Sbp	switch (ctx->f_infolevel) {
126375374Sbp	    case SMB_INFO_STANDARD:
126475374Sbp		next = 0;
126575374Sbp		fxsz = 0;
126675374Sbp		md_get_uint16le(mbp, &date);
126775374Sbp		md_get_uint16le(mbp, &time);	/* creation time */
126875374Sbp		md_get_uint16le(mbp, &date);
126975374Sbp		md_get_uint16le(mbp, &time);	/* access time */
127075374Sbp		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
127175374Sbp		md_get_uint16le(mbp, &date);
127275374Sbp		md_get_uint16le(mbp, &time);	/* access time */
127375374Sbp		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
127475374Sbp		md_get_uint32le(mbp, &size);
127575374Sbp		ctx->f_attr.fa_size = size;
127675374Sbp		md_get_uint32(mbp, NULL);	/* allocation size */
127775374Sbp		md_get_uint16le(mbp, &wattr);
127875374Sbp		ctx->f_attr.fa_attr = wattr;
127975374Sbp		md_get_uint8(mbp, &tb);
128075374Sbp		size = nmlen = tb;
128175374Sbp		fxsz = 23;
128275374Sbp		recsz = next = 24 + nmlen;	/* docs misses zero byte at end */
128375374Sbp		break;
128475374Sbp	    case SMB_FIND_FILE_DIRECTORY_INFO:
128575374Sbp		md_get_uint32le(mbp, &next);
128675374Sbp		md_get_uint32(mbp, NULL);	/* file index */
128775374Sbp		md_get_int64(mbp, NULL);	/* creation time */
128875374Sbp		md_get_int64le(mbp, &lint);
128975374Sbp		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime);
129075374Sbp		md_get_int64le(mbp, &lint);
129175374Sbp		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime);
129275374Sbp		md_get_int64le(mbp, &lint);
129375374Sbp		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime);
129475374Sbp		md_get_int64le(mbp, &lint);	/* file size */
129575374Sbp		ctx->f_attr.fa_size = lint;
129675374Sbp		md_get_int64(mbp, NULL);	/* real size (should use) */
129782039Sbp		md_get_uint32le(mbp, &dattr);	/* EA */
129875374Sbp		ctx->f_attr.fa_attr = dattr;
129975374Sbp		md_get_uint32le(mbp, &size);	/* name len */
130075374Sbp		fxsz = 64;
130175374Sbp		recsz = next ? next : fxsz + size;
130275374Sbp		break;
130375374Sbp	    default:
130475374Sbp		SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
130575374Sbp		return EINVAL;
130675374Sbp	}
1307227650Skevlo	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1308227650Skevlo		nmlen = min(size, SMB_MAXFNAMELEN * 2);
1309227650Skevlo	} else
1310227650Skevlo		nmlen = min(size, SMB_MAXFNAMELEN);
131175374Sbp	cp = ctx->f_name;
131275374Sbp	error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
131375374Sbp	if (error)
131475374Sbp		return error;
131575374Sbp	if (next) {
131675374Sbp		cnt = next - nmlen - fxsz;
131775374Sbp		if (cnt > 0)
131875374Sbp			md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
131975374Sbp		else if (cnt < 0) {
132075374Sbp			SMBERROR("out of sync\n");
132175374Sbp			return EBADRPC;
132275374Sbp		}
132375374Sbp	}
1324227650Skevlo	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1325227650Skevlo		if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
1326227650Skevlo			nmlen -= 2;
1327227650Skevlo	} else
1328227650Skevlo		if (nmlen && cp[nmlen - 1] == 0)
1329227650Skevlo			nmlen--;
133075374Sbp	if (nmlen == 0)
133175374Sbp		return EBADRPC;
133275374Sbp
133375374Sbp	next = ctx->f_eofs + recsz;
133475374Sbp	if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
133575374Sbp	    (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
133675374Sbp		/*
133775374Sbp		 * Server needs a resume filename.
133875374Sbp		 */
133975374Sbp		if (ctx->f_rnamelen <= nmlen) {
134075374Sbp			if (ctx->f_rname)
134175374Sbp				free(ctx->f_rname, M_SMBFSDATA);
1342111119Simp			ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
134375374Sbp			ctx->f_rnamelen = nmlen;
134475374Sbp		}
134575374Sbp		bcopy(ctx->f_name, ctx->f_rname, nmlen);
134675374Sbp		ctx->f_rname[nmlen] = 0;
134775374Sbp		ctx->f_flags |= SMBFS_RDD_GOTRNAME;
134875374Sbp	}
134975374Sbp	ctx->f_nmlen = nmlen;
135075374Sbp	ctx->f_eofs = next;
135175374Sbp	ctx->f_ecnt--;
135275374Sbp	ctx->f_left--;
135375374Sbp	return 0;
135475374Sbp}
135575374Sbp
135675374Sbpstatic int
135775374Sbpsmbfs_findcloseLM2(struct smbfs_fctx *ctx)
135875374Sbp{
135975374Sbp	if (ctx->f_name)
136075374Sbp		free(ctx->f_name, M_SMBFSDATA);
136175374Sbp	if (ctx->f_t2)
136275374Sbp		smb_t2_done(ctx->f_t2);
136375374Sbp	if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
136475374Sbp		smbfs_smb_findclose2(ctx);
136575374Sbp	return 0;
136675374Sbp}
136775374Sbp
136875374Sbpint
136975374Sbpsmbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
137075374Sbp	struct smb_cred *scred, struct smbfs_fctx **ctxpp)
137175374Sbp{
137275374Sbp	struct smbfs_fctx *ctx;
137375374Sbp	int error;
137475374Sbp
1375242092Sdavide	ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK | M_ZERO);
137675374Sbp	ctx->f_ssp = dnp->n_mount->sm_share;
137775374Sbp	ctx->f_dnp = dnp;
137875374Sbp	ctx->f_flags = SMBFS_RDD_FINDFIRST;
137975374Sbp	ctx->f_scred = scred;
138075374Sbp	if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
1381138490Sphk	    (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) {
138275374Sbp		ctx->f_flags |= SMBFS_RDD_USESEARCH;
138375374Sbp		error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
138475374Sbp	} else
138575374Sbp		error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
138675374Sbp	if (error)
138775374Sbp		smbfs_findclose(ctx, scred);
138875374Sbp	else
138975374Sbp		*ctxpp = ctx;
139075374Sbp	return error;
139175374Sbp}
139275374Sbp
139375374Sbpint
139475374Sbpsmbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
139575374Sbp{
139675374Sbp	int error;
139775374Sbp
139875374Sbp	if (limit == 0)
139975374Sbp		limit = 1000000;
140075374Sbp	else if (limit > 1)
140175374Sbp		limit *= 4;	/* imperical */
140275374Sbp	ctx->f_scred = scred;
140375374Sbp	for (;;) {
140475374Sbp		if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
140575374Sbp			error = smbfs_findnextLM1(ctx, limit);
140675374Sbp		} else
140775374Sbp			error = smbfs_findnextLM2(ctx, limit);
140875374Sbp		if (error)
140975374Sbp			return error;
1410227650Skevlo		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1411227650Skevlo			if ((ctx->f_nmlen == 2 &&
1412227650Skevlo			     *(u_int16_t *)ctx->f_name == htole16(0x002e)) ||
1413227650Skevlo			    (ctx->f_nmlen == 4 &&
1414227650Skevlo			     *(u_int32_t *)ctx->f_name == htole32(0x002e002e)))
1415227650Skevlo				continue;
1416227650Skevlo		} else
1417227650Skevlo			if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
1418227650Skevlo			    (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
1419227650Skevlo			     ctx->f_name[1] == '.'))
1420227650Skevlo				continue;
142175374Sbp		break;
142275374Sbp	}
1423145872Stakawata	smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen,
1424145872Stakawata			    ctx->f_dnp->n_mount->sm_caseopt);
142575374Sbp	ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
142675374Sbp	return 0;
142775374Sbp}
142875374Sbp
142975374Sbpint
143075374Sbpsmbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
143175374Sbp{
143275374Sbp	ctx->f_scred = scred;
143375374Sbp	if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
143475374Sbp		smbfs_findcloseLM1(ctx);
143575374Sbp	} else
143675374Sbp		smbfs_findcloseLM2(ctx);
143775374Sbp	if (ctx->f_rname)
143875374Sbp		free(ctx->f_rname, M_SMBFSDATA);
143975374Sbp	free(ctx, M_SMBFSDATA);
144075374Sbp	return 0;
144175374Sbp}
144275374Sbp
144375374Sbpint
144475374Sbpsmbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
144575374Sbp	struct smbfattr *fap, struct smb_cred *scred)
144675374Sbp{
144775374Sbp	struct smbfs_fctx *ctx;
144875374Sbp	int error;
144975374Sbp
145075374Sbp	if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
145175374Sbp		bzero(fap, sizeof(*fap));
145275374Sbp		fap->fa_attr = SMB_FA_DIR;
145375374Sbp		fap->fa_ino = 2;
145475374Sbp		return 0;
145575374Sbp	}
1456248101Sdavide	MPASS(!(nmlen == 2 && name[0] == '.' && name[1] == '.'));
1457248101Sdavide	MPASS(!(nmlen == 1 && name[0] == '.'));
1458248101Sdavide	ASSERT_VOP_ELOCKED(dnp->n_vnode, "smbfs_smb_lookup");
145975374Sbp	error = smbfs_findopen(dnp, name, nmlen,
146075374Sbp	    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
146175374Sbp	if (error)
146275374Sbp		return error;
146375374Sbp	ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
146475374Sbp	error = smbfs_findnext(ctx, 1, scred);
146575374Sbp	if (error == 0) {
146675374Sbp		*fap = ctx->f_attr;
146775374Sbp		if (name == NULL)
146875374Sbp			fap->fa_ino = dnp->n_ino;
146975374Sbp	}
147075374Sbp	smbfs_findclose(ctx, scred);
147175374Sbp	return error;
147275374Sbp}
1473