xref: /freebsd/sys/fs/smbfs/smbfs_smb.c (revision d63027b668c055c83bad6191a9986616380c86e4)
1d167cf6fSWarner Losh /*-
2*d63027b6SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*d63027b6SPedro F. Giffuni  *
4681a5bbeSBoris Popov  * Copyright (c) 2000-2001 Boris Popov
5681a5bbeSBoris Popov  * All rights reserved.
6681a5bbeSBoris Popov  *
7681a5bbeSBoris Popov  * Redistribution and use in source and binary forms, with or without
8681a5bbeSBoris Popov  * modification, are permitted provided that the following conditions
9681a5bbeSBoris Popov  * are met:
10681a5bbeSBoris Popov  * 1. Redistributions of source code must retain the above copyright
11681a5bbeSBoris Popov  *    notice, this list of conditions and the following disclaimer.
12681a5bbeSBoris Popov  * 2. Redistributions in binary form must reproduce the above copyright
13681a5bbeSBoris Popov  *    notice, this list of conditions and the following disclaimer in the
14681a5bbeSBoris Popov  *    documentation and/or other materials provided with the distribution.
15681a5bbeSBoris Popov  *
16681a5bbeSBoris Popov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17681a5bbeSBoris Popov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18681a5bbeSBoris Popov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19681a5bbeSBoris Popov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20681a5bbeSBoris Popov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21681a5bbeSBoris Popov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22681a5bbeSBoris Popov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23681a5bbeSBoris Popov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24681a5bbeSBoris Popov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25681a5bbeSBoris Popov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26681a5bbeSBoris Popov  * SUCH DAMAGE.
27681a5bbeSBoris Popov  *
28681a5bbeSBoris Popov  * $FreeBSD$
29681a5bbeSBoris Popov  */
30681a5bbeSBoris Popov #include <sys/param.h>
31681a5bbeSBoris Popov #include <sys/systm.h>
32681a5bbeSBoris Popov #include <sys/kernel.h>
33681a5bbeSBoris Popov #include <sys/malloc.h>
34681a5bbeSBoris Popov #include <sys/proc.h>
35681a5bbeSBoris Popov #include <sys/lock.h>
36681a5bbeSBoris Popov #include <sys/vnode.h>
37681a5bbeSBoris Popov #include <sys/mbuf.h>
38681a5bbeSBoris Popov #include <sys/mount.h>
3941f1dcccSKevin Lo #include <sys/endian.h>
40681a5bbeSBoris Popov 
41681a5bbeSBoris Popov #ifdef USE_MD5_HASH
42681a5bbeSBoris Popov #include <sys/md5.h>
43681a5bbeSBoris Popov #endif
44681a5bbeSBoris Popov 
45681a5bbeSBoris Popov #include <netsmb/smb.h>
46681a5bbeSBoris Popov #include <netsmb/smb_subr.h>
47681a5bbeSBoris Popov #include <netsmb/smb_rq.h>
48681a5bbeSBoris Popov #include <netsmb/smb_conn.h>
49681a5bbeSBoris Popov 
50681a5bbeSBoris Popov #include <fs/smbfs/smbfs.h>
51681a5bbeSBoris Popov #include <fs/smbfs/smbfs_node.h>
52681a5bbeSBoris Popov #include <fs/smbfs/smbfs_subr.h>
53681a5bbeSBoris Popov 
54681a5bbeSBoris Popov /*
55681a5bbeSBoris Popov  * Lack of inode numbers leads us to the problem of generating them.
56681a5bbeSBoris Popov  * Partially this problem can be solved by having a dir/file cache
57681a5bbeSBoris Popov  * with inode numbers generated from the incremented by one counter.
58681a5bbeSBoris Popov  * However this way will require too much kernel memory, gives all
59681a5bbeSBoris Popov  * sorts of locking and consistency problems, not to mentinon counter overflows.
60681a5bbeSBoris Popov  * So, I'm decided to use a hash function to generate pseudo random (and unique)
61681a5bbeSBoris Popov  * inode numbers.
62681a5bbeSBoris Popov  */
63681a5bbeSBoris Popov static long
64681a5bbeSBoris Popov smbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
65681a5bbeSBoris Popov {
66681a5bbeSBoris Popov #ifdef USE_MD5_HASH
67681a5bbeSBoris Popov 	MD5_CTX md5;
68681a5bbeSBoris Popov 	u_int32_t state[4];
69681a5bbeSBoris Popov 	long ino;
70681a5bbeSBoris Popov 	int i;
71681a5bbeSBoris Popov 
72681a5bbeSBoris Popov 	MD5Init(&md5);
73681a5bbeSBoris Popov 	MD5Update(&md5, name, nmlen);
74681a5bbeSBoris Popov 	MD5Final((u_char *)state, &md5);
75681a5bbeSBoris Popov 	for (i = 0, ino = 0; i < 4; i++)
76681a5bbeSBoris Popov 		ino += state[i];
77681a5bbeSBoris Popov 	return dnp->n_ino + ino;
78681a5bbeSBoris Popov #endif
79681a5bbeSBoris Popov 	u_int32_t ino;
80681a5bbeSBoris Popov 
81681a5bbeSBoris Popov 	ino = dnp->n_ino + smbfs_hash(name, nmlen);
82681a5bbeSBoris Popov 	if (ino <= 2)
83681a5bbeSBoris Popov 		ino += 3;
84681a5bbeSBoris Popov 	return ino;
85681a5bbeSBoris Popov }
86681a5bbeSBoris Popov 
87681a5bbeSBoris Popov static int
88681a5bbeSBoris Popov smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end,
89681a5bbeSBoris Popov 	struct smb_cred *scred)
90681a5bbeSBoris Popov {
91681a5bbeSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
92afe09751SDavide Italiano 	struct smb_rq *rqp;
93681a5bbeSBoris Popov 	struct mbchain *mbp;
94681a5bbeSBoris Popov 	u_char ltype = 0;
95681a5bbeSBoris Popov 	int error;
96681a5bbeSBoris Popov 
97681a5bbeSBoris Popov 	if (op == SMB_LOCK_SHARED)
98681a5bbeSBoris Popov 		ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
999e9421bcSDavide Italiano 
1009e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred, &rqp);
1019e9421bcSDavide Italiano 	if (error)
1029e9421bcSDavide Italiano 		return (error);
103681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
104681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
105681a5bbeSBoris Popov 	mb_put_uint8(mbp, 0xff);	/* secondary command */
106681a5bbeSBoris Popov 	mb_put_uint8(mbp, 0);		/* MBZ */
107681a5bbeSBoris Popov 	mb_put_uint16le(mbp, 0);
108681a5bbeSBoris Popov 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
109681a5bbeSBoris Popov 	mb_put_uint8(mbp, ltype);	/* locktype */
110681a5bbeSBoris Popov 	mb_put_uint8(mbp, 0);		/* oplocklevel - 0 seems is NO_OPLOCK */
111681a5bbeSBoris Popov 	mb_put_uint32le(mbp, 0);	/* timeout - break immediately */
112681a5bbeSBoris Popov 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
113681a5bbeSBoris Popov 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
114681a5bbeSBoris Popov 	smb_rq_wend(rqp);
115681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
116681a5bbeSBoris Popov 	mb_put_uint16le(mbp, pid);
117681a5bbeSBoris Popov 	mb_put_uint32le(mbp, start);
118681a5bbeSBoris Popov 	mb_put_uint32le(mbp, end - start);
119681a5bbeSBoris Popov 	smb_rq_bend(rqp);
120681a5bbeSBoris Popov 	error = smb_rq_simple(rqp);
121681a5bbeSBoris Popov 	smb_rq_done(rqp);
122681a5bbeSBoris Popov 	return error;
123681a5bbeSBoris Popov }
124681a5bbeSBoris Popov 
125681a5bbeSBoris Popov int
126681a5bbeSBoris Popov smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
127681a5bbeSBoris Popov 	off_t start, off_t end,	struct smb_cred *scred)
128681a5bbeSBoris Popov {
129681a5bbeSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
130681a5bbeSBoris Popov 
131681a5bbeSBoris Popov 	if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
132681a5bbeSBoris Popov 		/*
133681a5bbeSBoris Popov 		 * TODO: use LOCK_BYTE_RANGE here.
134681a5bbeSBoris Popov 		 */
135681a5bbeSBoris Popov 		return EINVAL;
136681a5bbeSBoris Popov 	else
13795c2dc84SJohn Baldwin 		return smbfs_smb_lockandx(np, op, (uintptr_t)id, start, end, scred);
138681a5bbeSBoris Popov }
139681a5bbeSBoris Popov 
14014b2dc39SAndrey V. Elsukov static int
14114b2dc39SAndrey V. Elsukov smbfs_query_info_fs(struct smb_share *ssp, struct statfs *sbp,
14214b2dc39SAndrey V. Elsukov 	struct smb_cred *scred)
14314b2dc39SAndrey V. Elsukov {
14414b2dc39SAndrey V. Elsukov 	struct smb_t2rq *t2p;
14514b2dc39SAndrey V. Elsukov 	struct mbchain *mbp;
14614b2dc39SAndrey V. Elsukov 	struct mdchain *mdp;
14714b2dc39SAndrey V. Elsukov 	uint32_t bsize, bpu;
14814b2dc39SAndrey V. Elsukov 	int64_t units, funits;
14914b2dc39SAndrey V. Elsukov 	int error;
15014b2dc39SAndrey V. Elsukov 
15114b2dc39SAndrey V. Elsukov 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
15214b2dc39SAndrey V. Elsukov 	    scred, &t2p);
15314b2dc39SAndrey V. Elsukov 	if (error)
15414b2dc39SAndrey V. Elsukov 		return (error);
15514b2dc39SAndrey V. Elsukov 	mbp = &t2p->t2_tparam;
15614b2dc39SAndrey V. Elsukov 	mb_init(mbp);
15714b2dc39SAndrey V. Elsukov 	mb_put_uint16le(mbp, SMB_QUERY_FS_SIZE_INFO);
15814b2dc39SAndrey V. Elsukov 	t2p->t2_maxpcount = 2;
15914b2dc39SAndrey V. Elsukov 	t2p->t2_maxdcount = sizeof(int64_t) * 2 + sizeof(uint32_t) * 2;
16014b2dc39SAndrey V. Elsukov 	error = smb_t2_request(t2p);
16114b2dc39SAndrey V. Elsukov 	if (error) {
16214b2dc39SAndrey V. Elsukov 		smb_t2_done(t2p);
16314b2dc39SAndrey V. Elsukov 		return (error);
16414b2dc39SAndrey V. Elsukov 	}
16514b2dc39SAndrey V. Elsukov 	mdp = &t2p->t2_rdata;
16614b2dc39SAndrey V. Elsukov 	md_get_int64le(mdp, &units);
16714b2dc39SAndrey V. Elsukov 	md_get_int64le(mdp, &funits);
16814b2dc39SAndrey V. Elsukov 	md_get_uint32le(mdp, &bpu);
16914b2dc39SAndrey V. Elsukov 	md_get_uint32le(mdp, &bsize);
17014b2dc39SAndrey V. Elsukov 	sbp->f_bsize = bpu * bsize;	/* fundamental filesystem block size */
17114b2dc39SAndrey V. Elsukov 	sbp->f_blocks= (uint64_t)units;	/* total data blocks in filesystem */
17214b2dc39SAndrey V. Elsukov 	sbp->f_bfree = (uint64_t)funits;/* free blocks in fs */
17314b2dc39SAndrey V. Elsukov 	sbp->f_bavail= (uint64_t)funits;/* free blocks avail to non-superuser */
17414b2dc39SAndrey V. Elsukov 	sbp->f_files = 0xffff;		/* total file nodes in filesystem */
17514b2dc39SAndrey V. Elsukov 	sbp->f_ffree = 0xffff;		/* free file nodes in fs */
17614b2dc39SAndrey V. Elsukov 	smb_t2_done(t2p);
17714b2dc39SAndrey V. Elsukov 	return (0);
17814b2dc39SAndrey V. Elsukov }
17914b2dc39SAndrey V. Elsukov 
18014b2dc39SAndrey V. Elsukov 
18114b2dc39SAndrey V. Elsukov static int
18214b2dc39SAndrey V. Elsukov smbfs_query_info_alloc(struct smb_share *ssp, struct statfs *sbp,
183681a5bbeSBoris Popov 	struct smb_cred *scred)
184681a5bbeSBoris Popov {
185681a5bbeSBoris Popov 	struct smb_t2rq *t2p;
186681a5bbeSBoris Popov 	struct mbchain *mbp;
187681a5bbeSBoris Popov 	struct mdchain *mdp;
188681a5bbeSBoris Popov 	u_int16_t bsize;
189681a5bbeSBoris Popov 	u_int32_t units, bpu, funits;
190681a5bbeSBoris Popov 	int error;
191681a5bbeSBoris Popov 
192681a5bbeSBoris Popov 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
193681a5bbeSBoris Popov 	    scred, &t2p);
194681a5bbeSBoris Popov 	if (error)
195681a5bbeSBoris Popov 		return error;
196681a5bbeSBoris Popov 	mbp = &t2p->t2_tparam;
197681a5bbeSBoris Popov 	mb_init(mbp);
198681a5bbeSBoris Popov 	mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
199681a5bbeSBoris Popov 	t2p->t2_maxpcount = 4;
200681a5bbeSBoris Popov 	t2p->t2_maxdcount = 4 * 4 + 2;
201681a5bbeSBoris Popov 	error = smb_t2_request(t2p);
202681a5bbeSBoris Popov 	if (error) {
203681a5bbeSBoris Popov 		smb_t2_done(t2p);
204681a5bbeSBoris Popov 		return error;
205681a5bbeSBoris Popov 	}
206681a5bbeSBoris Popov 	mdp = &t2p->t2_rdata;
207681a5bbeSBoris Popov 	md_get_uint32(mdp, NULL);	/* fs id */
208681a5bbeSBoris Popov 	md_get_uint32le(mdp, &bpu);
209681a5bbeSBoris Popov 	md_get_uint32le(mdp, &units);
210681a5bbeSBoris Popov 	md_get_uint32le(mdp, &funits);
211681a5bbeSBoris Popov 	md_get_uint16le(mdp, &bsize);
212681a5bbeSBoris Popov 	sbp->f_bsize = bpu * bsize;	/* fundamental filesystem block size */
213681a5bbeSBoris Popov 	sbp->f_blocks= units;		/* total data blocks in filesystem */
214681a5bbeSBoris Popov 	sbp->f_bfree = funits;		/* free blocks in fs */
215681a5bbeSBoris Popov 	sbp->f_bavail= funits;		/* free blocks avail to non-superuser */
216681a5bbeSBoris Popov 	sbp->f_files = 0xffff;		/* total file nodes in filesystem */
217681a5bbeSBoris Popov 	sbp->f_ffree = 0xffff;		/* free file nodes in fs */
218681a5bbeSBoris Popov 	smb_t2_done(t2p);
219681a5bbeSBoris Popov 	return 0;
220681a5bbeSBoris Popov }
221681a5bbeSBoris Popov 
22214b2dc39SAndrey V. Elsukov static int
22314b2dc39SAndrey V. Elsukov smbfs_query_info_disk(struct smb_share *ssp, struct statfs *sbp,
224681a5bbeSBoris Popov 	struct smb_cred *scred)
225681a5bbeSBoris Popov {
226afe09751SDavide Italiano 	struct smb_rq *rqp;
227681a5bbeSBoris Popov 	struct mdchain *mdp;
228681a5bbeSBoris Popov 	u_int16_t units, bpu, bsize, funits;
229681a5bbeSBoris Popov 	int error;
230681a5bbeSBoris Popov 
2319e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
2329e9421bcSDavide Italiano 	    scred, &rqp);
2339e9421bcSDavide Italiano 	if (error)
2349e9421bcSDavide Italiano 		return (error);
235681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
236681a5bbeSBoris Popov 	smb_rq_wend(rqp);
237681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
238681a5bbeSBoris Popov 	smb_rq_bend(rqp);
239681a5bbeSBoris Popov 	error = smb_rq_simple(rqp);
240681a5bbeSBoris Popov 	if (error) {
241681a5bbeSBoris Popov 		smb_rq_done(rqp);
242681a5bbeSBoris Popov 		return error;
243681a5bbeSBoris Popov 	}
244681a5bbeSBoris Popov 	smb_rq_getreply(rqp, &mdp);
245681a5bbeSBoris Popov 	md_get_uint16le(mdp, &units);
246681a5bbeSBoris Popov 	md_get_uint16le(mdp, &bpu);
247681a5bbeSBoris Popov 	md_get_uint16le(mdp, &bsize);
248681a5bbeSBoris Popov 	md_get_uint16le(mdp, &funits);
249681a5bbeSBoris Popov 	sbp->f_bsize = bpu * bsize;	/* fundamental filesystem block size */
250681a5bbeSBoris Popov 	sbp->f_blocks= units;		/* total data blocks in filesystem */
251681a5bbeSBoris Popov 	sbp->f_bfree = funits;		/* free blocks in fs */
252681a5bbeSBoris Popov 	sbp->f_bavail= funits;		/* free blocks avail to non-superuser */
253681a5bbeSBoris Popov 	sbp->f_files = 0xffff;		/* total file nodes in filesystem */
254681a5bbeSBoris Popov 	sbp->f_ffree = 0xffff;		/* free file nodes in fs */
255681a5bbeSBoris Popov 	smb_rq_done(rqp);
256681a5bbeSBoris Popov 	return 0;
257681a5bbeSBoris Popov }
258681a5bbeSBoris Popov 
25914b2dc39SAndrey V. Elsukov int
26014b2dc39SAndrey V. Elsukov smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
26114b2dc39SAndrey V. Elsukov 	struct smb_cred *scred)
26214b2dc39SAndrey V. Elsukov {
26314b2dc39SAndrey V. Elsukov 
26414b2dc39SAndrey V. Elsukov 	if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) {
26514b2dc39SAndrey V. Elsukov 		if (smbfs_query_info_fs(ssp, sbp, scred) == 0)
26614b2dc39SAndrey V. Elsukov 			return (0);
26714b2dc39SAndrey V. Elsukov 		if (smbfs_query_info_alloc(ssp, sbp, scred) == 0)
26814b2dc39SAndrey V. Elsukov 			return (0);
26914b2dc39SAndrey V. Elsukov 	}
27014b2dc39SAndrey V. Elsukov 	return (smbfs_query_info_disk(ssp, sbp, scred));
27114b2dc39SAndrey V. Elsukov }
27214b2dc39SAndrey V. Elsukov 
2733c2f5c3cSBoris Popov static int
2743c2f5c3cSBoris Popov smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
2753c2f5c3cSBoris Popov {
2763c2f5c3cSBoris Popov 	struct smb_t2rq *t2p;
2773c2f5c3cSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
2783c2f5c3cSBoris Popov 	struct mbchain *mbp;
2793c2f5c3cSBoris Popov 	int error;
2803c2f5c3cSBoris Popov 
2813c2f5c3cSBoris Popov 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
2823c2f5c3cSBoris Popov 	    scred, &t2p);
2833c2f5c3cSBoris Popov 	if (error)
2843c2f5c3cSBoris Popov 		return error;
2853c2f5c3cSBoris Popov 	mbp = &t2p->t2_tparam;
2863c2f5c3cSBoris Popov 	mb_init(mbp);
2873c2f5c3cSBoris Popov 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
2883c2f5c3cSBoris Popov 	mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO);
2893c2f5c3cSBoris Popov 	mb_put_uint32le(mbp, 0);
2903c2f5c3cSBoris Popov 	mbp = &t2p->t2_tdata;
2913c2f5c3cSBoris Popov 	mb_init(mbp);
2923c2f5c3cSBoris Popov 	mb_put_int64le(mbp, newsize);
2933c2f5c3cSBoris Popov 	mb_put_uint32le(mbp, 0);			/* padding */
2943c2f5c3cSBoris Popov 	mb_put_uint16le(mbp, 0);
2953c2f5c3cSBoris Popov 	t2p->t2_maxpcount = 2;
2963c2f5c3cSBoris Popov 	t2p->t2_maxdcount = 0;
2973c2f5c3cSBoris Popov 	error = smb_t2_request(t2p);
2983c2f5c3cSBoris Popov 	smb_t2_done(t2p);
2993c2f5c3cSBoris Popov 	return error;
3003c2f5c3cSBoris Popov }
3013c2f5c3cSBoris Popov 
3023c2f5c3cSBoris Popov static int
3033c2f5c3cSBoris Popov smb_smb_flush(struct smbnode *np, struct smb_cred *scred)
3043c2f5c3cSBoris Popov {
3053c2f5c3cSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
306afe09751SDavide Italiano 	struct smb_rq *rqp;
3073c2f5c3cSBoris Popov 	struct mbchain *mbp;
3083c2f5c3cSBoris Popov 	int error;
3093c2f5c3cSBoris Popov 
31008fe4bfbSTim J. Robbins 	if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) ||
3112a4ad258STim J. Robbins 	    SMBTOV(np)->v_type != VREG)
312d64ada50SJens Schweikhardt 		return 0; /* not a regular open file */
3139e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_FLUSH, scred, &rqp);
3149e9421bcSDavide Italiano 	if (error)
3153c2f5c3cSBoris Popov 		return (error);
3163c2f5c3cSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
3173c2f5c3cSBoris Popov 	smb_rq_wstart(rqp);
3183c2f5c3cSBoris Popov 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
3193c2f5c3cSBoris Popov 	smb_rq_wend(rqp);
3203c2f5c3cSBoris Popov 	smb_rq_bstart(rqp);
3213c2f5c3cSBoris Popov 	smb_rq_bend(rqp);
3223c2f5c3cSBoris Popov 	error = smb_rq_simple(rqp);
3233c2f5c3cSBoris Popov 	smb_rq_done(rqp);
3243c2f5c3cSBoris Popov 	if (!error)
3253c2f5c3cSBoris Popov 		np->n_flag &= ~NFLUSHWIRE;
3263c2f5c3cSBoris Popov 	return (error);
3273c2f5c3cSBoris Popov }
3283c2f5c3cSBoris Popov 
3293c2f5c3cSBoris Popov int
3303c2f5c3cSBoris Popov smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred)
3313c2f5c3cSBoris Popov {
3323c2f5c3cSBoris Popov 	if (np->n_flag & NFLUSHWIRE)
3333c2f5c3cSBoris Popov 		return (smb_smb_flush(np, scred));
3343c2f5c3cSBoris Popov 	return (0);
3353c2f5c3cSBoris Popov }
3363c2f5c3cSBoris Popov 
337681a5bbeSBoris Popov int
338c829016eSAndrey V. Elsukov smbfs_smb_setfsize(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
339681a5bbeSBoris Popov {
340681a5bbeSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
341afe09751SDavide Italiano 	struct smb_rq *rqp;
342681a5bbeSBoris Popov 	struct mbchain *mbp;
343681a5bbeSBoris Popov 	int error;
344681a5bbeSBoris Popov 
345c829016eSAndrey V. Elsukov 	if (!smbfs_smb_seteof(np, newsize, scred)) {
3463c2f5c3cSBoris Popov 		np->n_flag |= NFLUSHWIRE;
3473c2f5c3cSBoris Popov 		return (0);
3483c2f5c3cSBoris Popov 	}
349c829016eSAndrey V. Elsukov 	/* XXX: We should use SMB_COM_WRITE_ANDX to support large offsets */
3509e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
3519e9421bcSDavide Italiano 	if (error)
3529e9421bcSDavide Italiano 		return (error);
353681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
354681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
355681a5bbeSBoris Popov 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
356681a5bbeSBoris Popov 	mb_put_uint16le(mbp, 0);
357c829016eSAndrey V. Elsukov 	mb_put_uint32le(mbp, (uint32_t)newsize);
358681a5bbeSBoris Popov 	mb_put_uint16le(mbp, 0);
359681a5bbeSBoris Popov 	smb_rq_wend(rqp);
360681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
361681a5bbeSBoris Popov 	mb_put_uint8(mbp, SMB_DT_DATA);
362681a5bbeSBoris Popov 	mb_put_uint16le(mbp, 0);
363681a5bbeSBoris Popov 	smb_rq_bend(rqp);
364681a5bbeSBoris Popov 	error = smb_rq_simple(rqp);
365681a5bbeSBoris Popov 	smb_rq_done(rqp);
366681a5bbeSBoris Popov 	return error;
367681a5bbeSBoris Popov }
368681a5bbeSBoris Popov 
3693c2f5c3cSBoris Popov int
3703c2f5c3cSBoris Popov smbfs_smb_query_info(struct smbnode *np, const char *name, int len,
3713c2f5c3cSBoris Popov 		     struct smbfattr *fap, struct smb_cred *scred)
3723c2f5c3cSBoris Popov {
373afe09751SDavide Italiano 	struct smb_rq *rqp;
3743c2f5c3cSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
3753c2f5c3cSBoris Popov 	struct mbchain *mbp;
3763c2f5c3cSBoris Popov 	struct mdchain *mdp;
3773c2f5c3cSBoris Popov 	u_int8_t wc;
3783c2f5c3cSBoris Popov 	int error;
3793c2f5c3cSBoris Popov 	u_int16_t wattr;
3803c2f5c3cSBoris Popov 	u_int32_t lint;
3813c2f5c3cSBoris Popov 
3829e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred,
3839e9421bcSDavide Italiano 	    &rqp);
3849e9421bcSDavide Italiano 	if (error)
3859e9421bcSDavide Italiano 		return (error);
3863c2f5c3cSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
3873c2f5c3cSBoris Popov 	smb_rq_wstart(rqp);
3883c2f5c3cSBoris Popov 	smb_rq_wend(rqp);
3893c2f5c3cSBoris Popov 	smb_rq_bstart(rqp);
3903c2f5c3cSBoris Popov 	mb_put_uint8(mbp, SMB_DT_ASCII);
3913c2f5c3cSBoris Popov 	do {
3923c2f5c3cSBoris Popov 		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len);
3933c2f5c3cSBoris Popov 		if (error)
3943c2f5c3cSBoris Popov 			break;
3953c2f5c3cSBoris Popov 		smb_rq_bend(rqp);
3963c2f5c3cSBoris Popov 		error = smb_rq_simple(rqp);
3973c2f5c3cSBoris Popov 		if (error)
3983c2f5c3cSBoris Popov 			break;
3993c2f5c3cSBoris Popov 		smb_rq_getreply(rqp, &mdp);
4003c2f5c3cSBoris Popov 		if (md_get_uint8(mdp, &wc) != 0 || wc != 10) {
4013c2f5c3cSBoris Popov 			error = EBADRPC;
4023c2f5c3cSBoris Popov 			break;
4033c2f5c3cSBoris Popov 		}
4043c2f5c3cSBoris Popov 		md_get_uint16le(mdp, &wattr);
4053c2f5c3cSBoris Popov 		fap->fa_attr = wattr;
4063c2f5c3cSBoris Popov 		/*
4073c2f5c3cSBoris Popov 		 * Be careful using the time returned here, as
4083c2f5c3cSBoris Popov 		 * with FAT on NT4SP6, at least, the time returned is low
4093c2f5c3cSBoris Popov 		 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
4103c2f5c3cSBoris Popov 		 * over about every seven minutes!
4113c2f5c3cSBoris Popov 		 */
4123c2f5c3cSBoris Popov 		md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */
4133c2f5c3cSBoris Popov 		if (lint)	/* avoid bogus zero returns */
4143c2f5c3cSBoris Popov 			smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz,
4153c2f5c3cSBoris Popov 					      &fap->fa_mtime);
4163c2f5c3cSBoris Popov 		md_get_uint32le(mdp, &lint);
4173c2f5c3cSBoris Popov 		fap->fa_size = lint;
4183c2f5c3cSBoris Popov 	} while(0);
4193c2f5c3cSBoris Popov 	smb_rq_done(rqp);
4203c2f5c3cSBoris Popov 	return error;
4213c2f5c3cSBoris Popov }
422681a5bbeSBoris Popov 
423681a5bbeSBoris Popov /*
424681a5bbeSBoris Popov  * Set DOS file attributes. mtime should be NULL for dialects above lm10
425681a5bbeSBoris Popov  */
426681a5bbeSBoris Popov int
427681a5bbeSBoris Popov smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
428681a5bbeSBoris Popov 	struct smb_cred *scred)
429681a5bbeSBoris Popov {
430afe09751SDavide Italiano 	struct smb_rq *rqp;
431681a5bbeSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
432681a5bbeSBoris Popov 	struct mbchain *mbp;
433681a5bbeSBoris Popov 	u_long time;
434681a5bbeSBoris Popov 	int error, svtz;
435681a5bbeSBoris Popov 
4369e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred,
4379e9421bcSDavide Italiano 	    &rqp);
4389e9421bcSDavide Italiano 	if (error)
4399e9421bcSDavide Italiano 		return (error);
440681a5bbeSBoris Popov 	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
441681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
442681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
443681a5bbeSBoris Popov 	mb_put_uint16le(mbp, attr);
444681a5bbeSBoris Popov 	if (mtime) {
445681a5bbeSBoris Popov 		smb_time_local2server(mtime, svtz, &time);
446681a5bbeSBoris Popov 	} else
447681a5bbeSBoris Popov 		time = 0;
448681a5bbeSBoris Popov 	mb_put_uint32le(mbp, time);		/* mtime */
449681a5bbeSBoris Popov 	mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
450681a5bbeSBoris Popov 	smb_rq_wend(rqp);
451681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
452681a5bbeSBoris Popov 	mb_put_uint8(mbp, SMB_DT_ASCII);
453681a5bbeSBoris Popov 	do {
454681a5bbeSBoris Popov 		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
455681a5bbeSBoris Popov 		if (error)
456681a5bbeSBoris Popov 			break;
457681a5bbeSBoris Popov 		mb_put_uint8(mbp, SMB_DT_ASCII);
45841f1dcccSKevin Lo 		if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
45941f1dcccSKevin Lo 			mb_put_padbyte(mbp);
46041f1dcccSKevin Lo 			mb_put_uint8(mbp, 0);	/* 1st byte of NULL Unicode char */
46141f1dcccSKevin Lo 		}
462681a5bbeSBoris Popov 		mb_put_uint8(mbp, 0);
463681a5bbeSBoris Popov 		smb_rq_bend(rqp);
464681a5bbeSBoris Popov 		error = smb_rq_simple(rqp);
465fb8e9eadSBoris Popov 		if (error) {
466fb8e9eadSBoris Popov 			SMBERROR("smb_rq_simple(rqp) => error %d\n", error);
467681a5bbeSBoris Popov 			break;
468fb8e9eadSBoris Popov 		}
469681a5bbeSBoris Popov 	} while(0);
470681a5bbeSBoris Popov 	smb_rq_done(rqp);
471681a5bbeSBoris Popov 	return error;
472681a5bbeSBoris Popov }
473681a5bbeSBoris Popov 
474681a5bbeSBoris Popov /*
475681a5bbeSBoris Popov  * Note, win95 doesn't support this call.
476681a5bbeSBoris Popov  */
477681a5bbeSBoris Popov int
478681a5bbeSBoris Popov smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
479681a5bbeSBoris Popov 	struct timespec *atime, int attr, struct smb_cred *scred)
480681a5bbeSBoris Popov {
481681a5bbeSBoris Popov 	struct smb_t2rq *t2p;
482681a5bbeSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
483681a5bbeSBoris Popov 	struct smb_vc *vcp = SSTOVC(ssp);
484681a5bbeSBoris Popov 	struct mbchain *mbp;
485681a5bbeSBoris Popov 	u_int16_t date, time;
486681a5bbeSBoris Popov 	int error, tzoff;
487681a5bbeSBoris Popov 
488681a5bbeSBoris Popov 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
489681a5bbeSBoris Popov 	    scred, &t2p);
490681a5bbeSBoris Popov 	if (error)
491681a5bbeSBoris Popov 		return error;
492681a5bbeSBoris Popov 	mbp = &t2p->t2_tparam;
493681a5bbeSBoris Popov 	mb_init(mbp);
494681a5bbeSBoris Popov 	mb_put_uint16le(mbp, SMB_INFO_STANDARD);
495681a5bbeSBoris Popov 	mb_put_uint32le(mbp, 0);		/* MBZ */
4963c2f5c3cSBoris Popov 	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
497681a5bbeSBoris Popov 	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
498681a5bbeSBoris Popov 	if (error) {
499681a5bbeSBoris Popov 		smb_t2_done(t2p);
500681a5bbeSBoris Popov 		return error;
501681a5bbeSBoris Popov 	}
502681a5bbeSBoris Popov 	tzoff = vcp->vc_sopt.sv_tz;
503681a5bbeSBoris Popov 	mbp = &t2p->t2_tdata;
504681a5bbeSBoris Popov 	mb_init(mbp);
505681a5bbeSBoris Popov 	mb_put_uint32le(mbp, 0);		/* creation time */
506681a5bbeSBoris Popov 	if (atime)
507681a5bbeSBoris Popov 		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
508681a5bbeSBoris Popov 	else
509681a5bbeSBoris Popov 		time = date = 0;
510681a5bbeSBoris Popov 	mb_put_uint16le(mbp, date);
511681a5bbeSBoris Popov 	mb_put_uint16le(mbp, time);
512681a5bbeSBoris Popov 	if (mtime)
513681a5bbeSBoris Popov 		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
514681a5bbeSBoris Popov 	else
515681a5bbeSBoris Popov 		time = date = 0;
516681a5bbeSBoris Popov 	mb_put_uint16le(mbp, date);
517681a5bbeSBoris Popov 	mb_put_uint16le(mbp, time);
518681a5bbeSBoris Popov 	mb_put_uint32le(mbp, 0);		/* file size */
519681a5bbeSBoris Popov 	mb_put_uint32le(mbp, 0);		/* allocation unit size */
520681a5bbeSBoris Popov 	mb_put_uint16le(mbp, attr);	/* DOS attr */
521681a5bbeSBoris Popov 	mb_put_uint32le(mbp, 0);		/* EA size */
522681a5bbeSBoris Popov 	t2p->t2_maxpcount = 5 * 2;
523681a5bbeSBoris Popov 	t2p->t2_maxdcount = vcp->vc_txmax;
524681a5bbeSBoris Popov 	error = smb_t2_request(t2p);
525681a5bbeSBoris Popov 	smb_t2_done(t2p);
526681a5bbeSBoris Popov 	return error;
527681a5bbeSBoris Popov }
528681a5bbeSBoris Popov 
529681a5bbeSBoris Popov /*
530681a5bbeSBoris Popov  * NT level. Specially for win9x
531681a5bbeSBoris Popov  */
532681a5bbeSBoris Popov int
533681a5bbeSBoris Popov smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
534681a5bbeSBoris Popov 	struct timespec *atime, struct smb_cred *scred)
535681a5bbeSBoris Popov {
536681a5bbeSBoris Popov 	struct smb_t2rq *t2p;
537681a5bbeSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
538681a5bbeSBoris Popov 	struct smb_vc *vcp = SSTOVC(ssp);
539681a5bbeSBoris Popov 	struct mbchain *mbp;
540681a5bbeSBoris Popov 	int64_t tm;
541681a5bbeSBoris Popov 	int error, tzoff;
542681a5bbeSBoris Popov 
543681a5bbeSBoris Popov 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
544681a5bbeSBoris Popov 	    scred, &t2p);
545681a5bbeSBoris Popov 	if (error)
546681a5bbeSBoris Popov 		return error;
547681a5bbeSBoris Popov 	mbp = &t2p->t2_tparam;
548681a5bbeSBoris Popov 	mb_init(mbp);
549681a5bbeSBoris Popov 	mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
550681a5bbeSBoris Popov 	mb_put_uint32le(mbp, 0);		/* MBZ */
5513c2f5c3cSBoris Popov 	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
552681a5bbeSBoris Popov 	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
553681a5bbeSBoris Popov 	if (error) {
554681a5bbeSBoris Popov 		smb_t2_done(t2p);
555681a5bbeSBoris Popov 		return error;
556681a5bbeSBoris Popov 	}
557681a5bbeSBoris Popov 	tzoff = vcp->vc_sopt.sv_tz;
558681a5bbeSBoris Popov 	mbp = &t2p->t2_tdata;
559681a5bbeSBoris Popov 	mb_init(mbp);
560681a5bbeSBoris Popov 	mb_put_int64le(mbp, 0);		/* creation time */
561681a5bbeSBoris Popov 	if (atime) {
562681a5bbeSBoris Popov 		smb_time_local2NT(atime, tzoff, &tm);
563681a5bbeSBoris Popov 	} else
564681a5bbeSBoris Popov 		tm = 0;
565681a5bbeSBoris Popov 	mb_put_int64le(mbp, tm);
566681a5bbeSBoris Popov 	if (mtime) {
567681a5bbeSBoris Popov 		smb_time_local2NT(mtime, tzoff, &tm);
568681a5bbeSBoris Popov 	} else
569681a5bbeSBoris Popov 		tm = 0;
570681a5bbeSBoris Popov 	mb_put_int64le(mbp, tm);
571681a5bbeSBoris Popov 	mb_put_int64le(mbp, tm);		/* change time */
572681a5bbeSBoris Popov 	mb_put_uint32le(mbp, attr);		/* attr */
573681a5bbeSBoris Popov 	t2p->t2_maxpcount = 24;
574681a5bbeSBoris Popov 	t2p->t2_maxdcount = 56;
575681a5bbeSBoris Popov 	error = smb_t2_request(t2p);
576681a5bbeSBoris Popov 	smb_t2_done(t2p);
577681a5bbeSBoris Popov 	return error;
578681a5bbeSBoris Popov }
579681a5bbeSBoris Popov 
580681a5bbeSBoris Popov /*
581681a5bbeSBoris Popov  * Set file atime and mtime. Doesn't supported by core dialect.
582681a5bbeSBoris Popov  */
583681a5bbeSBoris Popov int
584681a5bbeSBoris Popov smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
585681a5bbeSBoris Popov 	struct timespec *atime, struct smb_cred *scred)
586681a5bbeSBoris Popov {
587afe09751SDavide Italiano 	struct smb_rq *rqp;
588681a5bbeSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
589681a5bbeSBoris Popov 	struct mbchain *mbp;
590681a5bbeSBoris Popov 	u_int16_t date, time;
591681a5bbeSBoris Popov 	int error, tzoff;
592681a5bbeSBoris Popov 
5939e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred,
5949e9421bcSDavide Italiano 	    &rqp);
5959e9421bcSDavide Italiano 	if (error)
5969e9421bcSDavide Italiano 		return (error);
597681a5bbeSBoris Popov 	tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
598681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
599681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
600681a5bbeSBoris Popov 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
601681a5bbeSBoris Popov 	mb_put_uint32le(mbp, 0);		/* creation time */
602681a5bbeSBoris Popov 
603681a5bbeSBoris Popov 	if (atime)
604681a5bbeSBoris Popov 		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
605681a5bbeSBoris Popov 	else
606681a5bbeSBoris Popov 		time = date = 0;
607681a5bbeSBoris Popov 	mb_put_uint16le(mbp, date);
608681a5bbeSBoris Popov 	mb_put_uint16le(mbp, time);
609681a5bbeSBoris Popov 	if (mtime)
610681a5bbeSBoris Popov 		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
611681a5bbeSBoris Popov 	else
612681a5bbeSBoris Popov 		time = date = 0;
613681a5bbeSBoris Popov 	mb_put_uint16le(mbp, date);
614681a5bbeSBoris Popov 	mb_put_uint16le(mbp, time);
615681a5bbeSBoris Popov 	smb_rq_wend(rqp);
616681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
617681a5bbeSBoris Popov 	smb_rq_bend(rqp);
618681a5bbeSBoris Popov 	error = smb_rq_simple(rqp);
619681a5bbeSBoris Popov 	SMBSDEBUG("%d\n", error);
620681a5bbeSBoris Popov 	smb_rq_done(rqp);
621681a5bbeSBoris Popov 	return error;
622681a5bbeSBoris Popov }
623681a5bbeSBoris Popov 
624681a5bbeSBoris Popov /*
625681a5bbeSBoris Popov  * Set DOS file attributes.
626cd6dac7dSJonathan Anderson  * Looks like this call can be used only if SMB_CAP_NT_SMBS bit is on.
627681a5bbeSBoris Popov  */
628681a5bbeSBoris Popov int
629681a5bbeSBoris Popov smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
630681a5bbeSBoris Popov 	struct timespec *atime, struct smb_cred *scred)
631681a5bbeSBoris Popov {
632681a5bbeSBoris Popov 	struct smb_t2rq *t2p;
633681a5bbeSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
634681a5bbeSBoris Popov 	struct mbchain *mbp;
635681a5bbeSBoris Popov 	int64_t tm;
636681a5bbeSBoris Popov 	int error, svtz;
637681a5bbeSBoris Popov 
638681a5bbeSBoris Popov 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
639681a5bbeSBoris Popov 	    scred, &t2p);
640681a5bbeSBoris Popov 	if (error)
641681a5bbeSBoris Popov 		return error;
642681a5bbeSBoris Popov 	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
643681a5bbeSBoris Popov 	mbp = &t2p->t2_tparam;
644681a5bbeSBoris Popov 	mb_init(mbp);
645681a5bbeSBoris Popov 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
646681a5bbeSBoris Popov 	mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
647681a5bbeSBoris Popov 	mb_put_uint32le(mbp, 0);
648681a5bbeSBoris Popov 	mbp = &t2p->t2_tdata;
649681a5bbeSBoris Popov 	mb_init(mbp);
650681a5bbeSBoris Popov 	mb_put_int64le(mbp, 0);		/* creation time */
651681a5bbeSBoris Popov 	if (atime) {
652681a5bbeSBoris Popov 		smb_time_local2NT(atime, svtz, &tm);
653681a5bbeSBoris Popov 	} else
654681a5bbeSBoris Popov 		tm = 0;
655681a5bbeSBoris Popov 	mb_put_int64le(mbp, tm);
656681a5bbeSBoris Popov 	if (mtime) {
657681a5bbeSBoris Popov 		smb_time_local2NT(mtime, svtz, &tm);
658681a5bbeSBoris Popov 	} else
659681a5bbeSBoris Popov 		tm = 0;
660681a5bbeSBoris Popov 	mb_put_int64le(mbp, tm);
661681a5bbeSBoris Popov 	mb_put_int64le(mbp, tm);		/* change time */
662681a5bbeSBoris Popov 	mb_put_uint16le(mbp, attr);
663681a5bbeSBoris Popov 	mb_put_uint32le(mbp, 0);			/* padding */
664681a5bbeSBoris Popov 	mb_put_uint16le(mbp, 0);
665681a5bbeSBoris Popov 	t2p->t2_maxpcount = 2;
666681a5bbeSBoris Popov 	t2p->t2_maxdcount = 0;
667681a5bbeSBoris Popov 	error = smb_t2_request(t2p);
668681a5bbeSBoris Popov 	smb_t2_done(t2p);
669681a5bbeSBoris Popov 	return error;
670681a5bbeSBoris Popov }
671681a5bbeSBoris Popov 
672681a5bbeSBoris Popov 
673681a5bbeSBoris Popov int
674681a5bbeSBoris Popov smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
675681a5bbeSBoris Popov {
676afe09751SDavide Italiano 	struct smb_rq *rqp;
677681a5bbeSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
678681a5bbeSBoris Popov 	struct mbchain *mbp;
679681a5bbeSBoris Popov 	struct mdchain *mdp;
680681a5bbeSBoris Popov 	u_int8_t wc;
681681a5bbeSBoris Popov 	u_int16_t fid, wattr, grantedmode;
682681a5bbeSBoris Popov 	int error;
683681a5bbeSBoris Popov 
6849e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_OPEN, scred, &rqp);
6859e9421bcSDavide Italiano 	if (error)
6869e9421bcSDavide Italiano 		return (error);
687681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
688681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
689681a5bbeSBoris Popov 	mb_put_uint16le(mbp, accmode);
690681a5bbeSBoris Popov 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
691681a5bbeSBoris Popov 	smb_rq_wend(rqp);
692681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
693681a5bbeSBoris Popov 	mb_put_uint8(mbp, SMB_DT_ASCII);
694681a5bbeSBoris Popov 	do {
695681a5bbeSBoris Popov 		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
696681a5bbeSBoris Popov 		if (error)
697681a5bbeSBoris Popov 			break;
698681a5bbeSBoris Popov 		smb_rq_bend(rqp);
699681a5bbeSBoris Popov 		error = smb_rq_simple(rqp);
700681a5bbeSBoris Popov 		if (error)
701681a5bbeSBoris Popov 			break;
702681a5bbeSBoris Popov 		smb_rq_getreply(rqp, &mdp);
703681a5bbeSBoris Popov 		if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
704681a5bbeSBoris Popov 			error = EBADRPC;
705681a5bbeSBoris Popov 			break;
706681a5bbeSBoris Popov 		}
707681a5bbeSBoris Popov 		md_get_uint16(mdp, &fid);
708681a5bbeSBoris Popov 		md_get_uint16le(mdp, &wattr);
709681a5bbeSBoris Popov 		md_get_uint32(mdp, NULL);	/* mtime */
710681a5bbeSBoris Popov 		md_get_uint32(mdp, NULL);	/* fsize */
711681a5bbeSBoris Popov 		md_get_uint16le(mdp, &grantedmode);
712681a5bbeSBoris Popov 		/*
713681a5bbeSBoris Popov 		 * TODO: refresh attributes from this reply
714681a5bbeSBoris Popov 		 */
715681a5bbeSBoris Popov 	} while(0);
716681a5bbeSBoris Popov 	smb_rq_done(rqp);
717681a5bbeSBoris Popov 	if (error)
718681a5bbeSBoris Popov 		return error;
719681a5bbeSBoris Popov 	np->n_fid = fid;
720681a5bbeSBoris Popov 	np->n_rwstate = grantedmode;
721681a5bbeSBoris Popov 	return 0;
722681a5bbeSBoris Popov }
723681a5bbeSBoris Popov 
724681a5bbeSBoris Popov 
725681a5bbeSBoris Popov int
726681a5bbeSBoris Popov smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
727681a5bbeSBoris Popov 	struct smb_cred *scred)
728681a5bbeSBoris Popov {
729afe09751SDavide Italiano 	struct smb_rq *rqp;
730681a5bbeSBoris Popov 	struct mbchain *mbp;
731681a5bbeSBoris Popov 	u_long time;
732681a5bbeSBoris Popov 	int error;
733681a5bbeSBoris Popov 
7349e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CLOSE, scred, &rqp);
7359e9421bcSDavide Italiano 	if (error)
7369e9421bcSDavide Italiano 		return (error);
737681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
738681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
739681a5bbeSBoris Popov 	mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
740681a5bbeSBoris Popov 	if (mtime) {
741681a5bbeSBoris Popov 		smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
742681a5bbeSBoris Popov 	} else
743681a5bbeSBoris Popov 		time = 0;
744681a5bbeSBoris Popov 	mb_put_uint32le(mbp, time);
745681a5bbeSBoris Popov 	smb_rq_wend(rqp);
746681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
747681a5bbeSBoris Popov 	smb_rq_bend(rqp);
748681a5bbeSBoris Popov 	error = smb_rq_simple(rqp);
749681a5bbeSBoris Popov 	smb_rq_done(rqp);
750681a5bbeSBoris Popov 	return error;
751681a5bbeSBoris Popov }
752681a5bbeSBoris Popov 
753681a5bbeSBoris Popov int
754681a5bbeSBoris Popov smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
755681a5bbeSBoris Popov 	struct smb_cred *scred)
756681a5bbeSBoris Popov {
757afe09751SDavide Italiano 	struct smb_rq *rqp;
758681a5bbeSBoris Popov 	struct smb_share *ssp = dnp->n_mount->sm_share;
759681a5bbeSBoris Popov 	struct mbchain *mbp;
760681a5bbeSBoris Popov 	struct mdchain *mdp;
761681a5bbeSBoris Popov 	struct timespec ctime;
762681a5bbeSBoris Popov 	u_int8_t wc;
763681a5bbeSBoris Popov 	u_int16_t fid;
764681a5bbeSBoris Popov 	u_long tm;
765681a5bbeSBoris Popov 	int error;
766681a5bbeSBoris Popov 
7679e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE, scred, &rqp);
7689e9421bcSDavide Italiano 	if (error)
7699e9421bcSDavide Italiano 		return (error);
770681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
771681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
772681a5bbeSBoris Popov 	mb_put_uint16le(mbp, SMB_FA_ARCHIVE);		/* attributes  */
773681a5bbeSBoris Popov 	nanotime(&ctime);
774681a5bbeSBoris Popov 	smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
775681a5bbeSBoris Popov 	mb_put_uint32le(mbp, tm);
776681a5bbeSBoris Popov 	smb_rq_wend(rqp);
777681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
778681a5bbeSBoris Popov 	mb_put_uint8(mbp, SMB_DT_ASCII);
779681a5bbeSBoris Popov 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen);
780681a5bbeSBoris Popov 	if (!error) {
781681a5bbeSBoris Popov 		smb_rq_bend(rqp);
782681a5bbeSBoris Popov 		error = smb_rq_simple(rqp);
783681a5bbeSBoris Popov 		if (!error) {
784681a5bbeSBoris Popov 			smb_rq_getreply(rqp, &mdp);
785681a5bbeSBoris Popov 			md_get_uint8(mdp, &wc);
786681a5bbeSBoris Popov 			if (wc == 1)
787681a5bbeSBoris Popov 				md_get_uint16(mdp, &fid);
788681a5bbeSBoris Popov 			else
789681a5bbeSBoris Popov 				error = EBADRPC;
790681a5bbeSBoris Popov 		}
791681a5bbeSBoris Popov 	}
792681a5bbeSBoris Popov 	smb_rq_done(rqp);
793681a5bbeSBoris Popov 	if (error)
794681a5bbeSBoris Popov 		return error;
795681a5bbeSBoris Popov 	smbfs_smb_close(ssp, fid, &ctime, scred);
796681a5bbeSBoris Popov 	return error;
797681a5bbeSBoris Popov }
798681a5bbeSBoris Popov 
799681a5bbeSBoris Popov int
800681a5bbeSBoris Popov smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
801681a5bbeSBoris Popov {
802afe09751SDavide Italiano 	struct smb_rq *rqp;
803681a5bbeSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
804681a5bbeSBoris Popov 	struct mbchain *mbp;
805681a5bbeSBoris Popov 	int error;
806681a5bbeSBoris Popov 
8079e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE, scred, &rqp);
8089e9421bcSDavide Italiano 	if (error)
8099e9421bcSDavide Italiano 		return (error);
810681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
811681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
812681a5bbeSBoris Popov 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
813681a5bbeSBoris Popov 	smb_rq_wend(rqp);
814681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
815681a5bbeSBoris Popov 	mb_put_uint8(mbp, SMB_DT_ASCII);
816681a5bbeSBoris Popov 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
817681a5bbeSBoris Popov 	if (!error) {
818681a5bbeSBoris Popov 		smb_rq_bend(rqp);
819681a5bbeSBoris Popov 		error = smb_rq_simple(rqp);
820681a5bbeSBoris Popov 	}
821681a5bbeSBoris Popov 	smb_rq_done(rqp);
822681a5bbeSBoris Popov 	return error;
823681a5bbeSBoris Popov }
824681a5bbeSBoris Popov 
825681a5bbeSBoris Popov int
826681a5bbeSBoris Popov smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
827681a5bbeSBoris Popov 	const char *tname, int tnmlen, struct smb_cred *scred)
828681a5bbeSBoris Popov {
829afe09751SDavide Italiano 	struct smb_rq *rqp;
830681a5bbeSBoris Popov 	struct smb_share *ssp = src->n_mount->sm_share;
831681a5bbeSBoris Popov 	struct mbchain *mbp;
832681a5bbeSBoris Popov 	int error;
833681a5bbeSBoris Popov 
8349e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_RENAME, scred, &rqp);
8359e9421bcSDavide Italiano 	if (error)
8369e9421bcSDavide Italiano 		return (error);
837681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
838681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
839681a5bbeSBoris Popov 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
840681a5bbeSBoris Popov 	smb_rq_wend(rqp);
841681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
842681a5bbeSBoris Popov 	mb_put_uint8(mbp, SMB_DT_ASCII);
843681a5bbeSBoris Popov 	do {
844681a5bbeSBoris Popov 		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
845681a5bbeSBoris Popov 		if (error)
846681a5bbeSBoris Popov 			break;
847681a5bbeSBoris Popov 		mb_put_uint8(mbp, SMB_DT_ASCII);
848681a5bbeSBoris Popov 		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
849681a5bbeSBoris Popov 		if (error)
850681a5bbeSBoris Popov 			break;
851681a5bbeSBoris Popov 		smb_rq_bend(rqp);
852681a5bbeSBoris Popov 		error = smb_rq_simple(rqp);
853681a5bbeSBoris Popov 	} while(0);
854681a5bbeSBoris Popov 	smb_rq_done(rqp);
855681a5bbeSBoris Popov 	return error;
856681a5bbeSBoris Popov }
857681a5bbeSBoris Popov 
858681a5bbeSBoris Popov int
859681a5bbeSBoris Popov smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
860681a5bbeSBoris Popov 	const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
861681a5bbeSBoris Popov {
862afe09751SDavide Italiano 	struct smb_rq *rqp;
863681a5bbeSBoris Popov 	struct smb_share *ssp = src->n_mount->sm_share;
864681a5bbeSBoris Popov 	struct mbchain *mbp;
865681a5bbeSBoris Popov 	int error;
866681a5bbeSBoris Popov 
8679e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_MOVE, scred, &rqp);
8689e9421bcSDavide Italiano 	if (error)
8699e9421bcSDavide Italiano 		return (error);
870681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
871681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
872681a5bbeSBoris Popov 	mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
873681a5bbeSBoris Popov 	mb_put_uint16le(mbp, 0x20);	/* delete target file */
874681a5bbeSBoris Popov 	mb_put_uint16le(mbp, flags);
875681a5bbeSBoris Popov 	smb_rq_wend(rqp);
876681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
877681a5bbeSBoris Popov 	mb_put_uint8(mbp, SMB_DT_ASCII);
878681a5bbeSBoris Popov 	do {
879681a5bbeSBoris Popov 		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
880681a5bbeSBoris Popov 		if (error)
881681a5bbeSBoris Popov 			break;
882681a5bbeSBoris Popov 		mb_put_uint8(mbp, SMB_DT_ASCII);
883681a5bbeSBoris Popov 		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
884681a5bbeSBoris Popov 		if (error)
885681a5bbeSBoris Popov 			break;
886681a5bbeSBoris Popov 		smb_rq_bend(rqp);
887681a5bbeSBoris Popov 		error = smb_rq_simple(rqp);
888681a5bbeSBoris Popov 	} while(0);
889681a5bbeSBoris Popov 	smb_rq_done(rqp);
890681a5bbeSBoris Popov 	return error;
891681a5bbeSBoris Popov }
892681a5bbeSBoris Popov 
893681a5bbeSBoris Popov int
894681a5bbeSBoris Popov smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
895681a5bbeSBoris Popov 	struct smb_cred *scred)
896681a5bbeSBoris Popov {
897afe09751SDavide Italiano 	struct smb_rq *rqp;
898681a5bbeSBoris Popov 	struct smb_share *ssp = dnp->n_mount->sm_share;
899681a5bbeSBoris Popov 	struct mbchain *mbp;
900681a5bbeSBoris Popov 	int error;
901681a5bbeSBoris Popov 
9029e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred,
9039e9421bcSDavide Italiano 	    &rqp);
9049e9421bcSDavide Italiano 	if (error)
9059e9421bcSDavide Italiano 		return (error);
906681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
907681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
908681a5bbeSBoris Popov 	smb_rq_wend(rqp);
909681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
910681a5bbeSBoris Popov 	mb_put_uint8(mbp, SMB_DT_ASCII);
911681a5bbeSBoris Popov 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len);
912681a5bbeSBoris Popov 	if (!error) {
913681a5bbeSBoris Popov 		smb_rq_bend(rqp);
914681a5bbeSBoris Popov 		error = smb_rq_simple(rqp);
915681a5bbeSBoris Popov 	}
916681a5bbeSBoris Popov 	smb_rq_done(rqp);
917681a5bbeSBoris Popov 	return error;
918681a5bbeSBoris Popov }
919681a5bbeSBoris Popov 
920681a5bbeSBoris Popov int
921681a5bbeSBoris Popov smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred)
922681a5bbeSBoris Popov {
923afe09751SDavide Italiano 	struct smb_rq *rqp;
924681a5bbeSBoris Popov 	struct smb_share *ssp = np->n_mount->sm_share;
925681a5bbeSBoris Popov 	struct mbchain *mbp;
926681a5bbeSBoris Popov 	int error;
927681a5bbeSBoris Popov 
9289e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred,
9299e9421bcSDavide Italiano 	    &rqp);
9309e9421bcSDavide Italiano 	if (error)
9319e9421bcSDavide Italiano 		return (error);
932681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
933681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
934681a5bbeSBoris Popov 	smb_rq_wend(rqp);
935681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
936681a5bbeSBoris Popov 	mb_put_uint8(mbp, SMB_DT_ASCII);
937681a5bbeSBoris Popov 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
938681a5bbeSBoris Popov 	if (!error) {
939681a5bbeSBoris Popov 		smb_rq_bend(rqp);
940681a5bbeSBoris Popov 		error = smb_rq_simple(rqp);
941681a5bbeSBoris Popov 	}
942681a5bbeSBoris Popov 	smb_rq_done(rqp);
943681a5bbeSBoris Popov 	return error;
944681a5bbeSBoris Popov }
945681a5bbeSBoris Popov 
946681a5bbeSBoris Popov static int
947681a5bbeSBoris Popov smbfs_smb_search(struct smbfs_fctx *ctx)
948681a5bbeSBoris Popov {
949681a5bbeSBoris Popov 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
950681a5bbeSBoris Popov 	struct smb_rq *rqp;
951681a5bbeSBoris Popov 	struct mbchain *mbp;
952681a5bbeSBoris Popov 	struct mdchain *mdp;
953681a5bbeSBoris Popov 	u_int8_t wc, bt;
954681a5bbeSBoris Popov 	u_int16_t ec, dlen, bc;
955681a5bbeSBoris Popov 	int maxent, error, iseof = 0;
956681a5bbeSBoris Popov 
957681a5bbeSBoris Popov 	maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
958681a5bbeSBoris Popov 	if (ctx->f_rq) {
959681a5bbeSBoris Popov 		smb_rq_done(ctx->f_rq);
960681a5bbeSBoris Popov 		ctx->f_rq = NULL;
961681a5bbeSBoris Popov 	}
962681a5bbeSBoris Popov 	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
963681a5bbeSBoris Popov 	if (error)
9649e9421bcSDavide Italiano 		return (error);
965681a5bbeSBoris Popov 	ctx->f_rq = rqp;
966681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
967681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
968681a5bbeSBoris Popov 	mb_put_uint16le(mbp, maxent);	/* max entries to return */
969681a5bbeSBoris Popov 	mb_put_uint16le(mbp, ctx->f_attrmask);
970681a5bbeSBoris Popov 	smb_rq_wend(rqp);
971681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
972681a5bbeSBoris Popov 	mb_put_uint8(mbp, SMB_DT_ASCII);	/* buffer format */
973681a5bbeSBoris Popov 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
974681a5bbeSBoris Popov 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
975681a5bbeSBoris Popov 		if (error)
976681a5bbeSBoris Popov 			return error;
977681a5bbeSBoris Popov 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
978681a5bbeSBoris Popov 		mb_put_uint16le(mbp, 0);	/* context length */
979681a5bbeSBoris Popov 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
980681a5bbeSBoris Popov 	} else {
98141f1dcccSKevin Lo 		if (SMB_UNICODE_STRINGS(vcp)) {
98241f1dcccSKevin Lo 			mb_put_padbyte(mbp);
98341f1dcccSKevin Lo 			mb_put_uint8(mbp, 0);
98441f1dcccSKevin Lo 		}
985681a5bbeSBoris Popov 		mb_put_uint8(mbp, 0);	/* file name length */
986681a5bbeSBoris Popov 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
987681a5bbeSBoris Popov 		mb_put_uint16le(mbp, SMB_SKEYLEN);
988681a5bbeSBoris Popov 		mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
989681a5bbeSBoris Popov 	}
990681a5bbeSBoris Popov 	smb_rq_bend(rqp);
991681a5bbeSBoris Popov 	error = smb_rq_simple(rqp);
992681a5bbeSBoris Popov 	if (error) {
993681a5bbeSBoris Popov 		if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
994681a5bbeSBoris Popov 			error = 0;
995681a5bbeSBoris Popov 			iseof = 1;
996681a5bbeSBoris Popov 			ctx->f_flags |= SMBFS_RDD_EOF;
997681a5bbeSBoris Popov 		} else
998681a5bbeSBoris Popov 			return error;
999681a5bbeSBoris Popov 	}
1000681a5bbeSBoris Popov 	smb_rq_getreply(rqp, &mdp);
1001681a5bbeSBoris Popov 	md_get_uint8(mdp, &wc);
1002681a5bbeSBoris Popov 	if (wc != 1)
1003681a5bbeSBoris Popov 		return iseof ? ENOENT : EBADRPC;
1004681a5bbeSBoris Popov 	md_get_uint16le(mdp, &ec);
1005681a5bbeSBoris Popov 	if (ec == 0)
1006681a5bbeSBoris Popov 		return ENOENT;
1007681a5bbeSBoris Popov 	ctx->f_ecnt = ec;
1008681a5bbeSBoris Popov 	md_get_uint16le(mdp, &bc);
1009681a5bbeSBoris Popov 	if (bc < 3)
1010681a5bbeSBoris Popov 		return EBADRPC;
1011681a5bbeSBoris Popov 	bc -= 3;
1012681a5bbeSBoris Popov 	md_get_uint8(mdp, &bt);
1013681a5bbeSBoris Popov 	if (bt != SMB_DT_VARIABLE)
1014681a5bbeSBoris Popov 		return EBADRPC;
1015681a5bbeSBoris Popov 	md_get_uint16le(mdp, &dlen);
1016681a5bbeSBoris Popov 	if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
1017681a5bbeSBoris Popov 		return EBADRPC;
1018681a5bbeSBoris Popov 	return 0;
1019681a5bbeSBoris Popov }
1020681a5bbeSBoris Popov 
1021681a5bbeSBoris Popov static int
1022681a5bbeSBoris Popov smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
1023681a5bbeSBoris Popov 	const char *wildcard, int wclen, int attr, struct smb_cred *scred)
1024681a5bbeSBoris Popov {
1025681a5bbeSBoris Popov 	ctx->f_attrmask = attr;
1026681a5bbeSBoris Popov 	if (wildcard) {
1027681a5bbeSBoris Popov 		if (wclen == 1 && wildcard[0] == '*') {
1028681a5bbeSBoris Popov 			ctx->f_wildcard = "*.*";
1029681a5bbeSBoris Popov 			ctx->f_wclen = 3;
1030681a5bbeSBoris Popov 		} else {
1031681a5bbeSBoris Popov 			ctx->f_wildcard = wildcard;
1032681a5bbeSBoris Popov 			ctx->f_wclen = wclen;
1033681a5bbeSBoris Popov 		}
1034681a5bbeSBoris Popov 	} else {
1035681a5bbeSBoris Popov 		ctx->f_wildcard = NULL;
1036681a5bbeSBoris Popov 		ctx->f_wclen = 0;
1037681a5bbeSBoris Popov 	}
1038681a5bbeSBoris Popov 	ctx->f_name = ctx->f_fname;
1039681a5bbeSBoris Popov 	return 0;
1040681a5bbeSBoris Popov }
1041681a5bbeSBoris Popov 
1042681a5bbeSBoris Popov static int
1043681a5bbeSBoris Popov smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
1044681a5bbeSBoris Popov {
1045681a5bbeSBoris Popov 	struct mdchain *mbp;
1046681a5bbeSBoris Popov 	struct smb_rq *rqp;
1047681a5bbeSBoris Popov 	char *cp;
1048681a5bbeSBoris Popov 	u_int8_t battr;
1049681a5bbeSBoris Popov 	u_int16_t date, time;
1050681a5bbeSBoris Popov 	u_int32_t size;
1051681a5bbeSBoris Popov 	int error;
1052681a5bbeSBoris Popov 
1053681a5bbeSBoris Popov 	if (ctx->f_ecnt == 0) {
1054681a5bbeSBoris Popov 		if (ctx->f_flags & SMBFS_RDD_EOF)
1055681a5bbeSBoris Popov 			return ENOENT;
1056681a5bbeSBoris Popov 		ctx->f_left = ctx->f_limit = limit;
1057681a5bbeSBoris Popov 		error = smbfs_smb_search(ctx);
1058681a5bbeSBoris Popov 		if (error)
1059681a5bbeSBoris Popov 			return error;
1060681a5bbeSBoris Popov 	}
1061681a5bbeSBoris Popov 	rqp = ctx->f_rq;
1062681a5bbeSBoris Popov 	smb_rq_getreply(rqp, &mbp);
1063681a5bbeSBoris Popov 	md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1064681a5bbeSBoris Popov 	md_get_uint8(mbp, &battr);
1065681a5bbeSBoris Popov 	md_get_uint16le(mbp, &time);
1066681a5bbeSBoris Popov 	md_get_uint16le(mbp, &date);
1067681a5bbeSBoris Popov 	md_get_uint32le(mbp, &size);
1068681a5bbeSBoris Popov 	cp = ctx->f_name;
1069681a5bbeSBoris Popov 	md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM);
1070681a5bbeSBoris Popov 	cp[sizeof(ctx->f_fname) - 1] = 0;
1071681a5bbeSBoris Popov 	cp += strlen(cp) - 1;
1072681a5bbeSBoris Popov 	while (*cp == ' ' && cp >= ctx->f_name)
1073681a5bbeSBoris Popov 		*cp-- = 0;
1074681a5bbeSBoris Popov 	ctx->f_attr.fa_attr = battr;
1075681a5bbeSBoris Popov 	smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
1076681a5bbeSBoris Popov 	    &ctx->f_attr.fa_mtime);
1077681a5bbeSBoris Popov 	ctx->f_attr.fa_size = size;
1078681a5bbeSBoris Popov 	ctx->f_nmlen = strlen(ctx->f_name);
1079681a5bbeSBoris Popov 	ctx->f_ecnt--;
1080681a5bbeSBoris Popov 	ctx->f_left--;
1081681a5bbeSBoris Popov 	return 0;
1082681a5bbeSBoris Popov }
1083681a5bbeSBoris Popov 
1084681a5bbeSBoris Popov static int
1085681a5bbeSBoris Popov smbfs_findcloseLM1(struct smbfs_fctx *ctx)
1086681a5bbeSBoris Popov {
1087681a5bbeSBoris Popov 	if (ctx->f_rq)
1088681a5bbeSBoris Popov 		smb_rq_done(ctx->f_rq);
1089681a5bbeSBoris Popov 	return 0;
1090681a5bbeSBoris Popov }
1091681a5bbeSBoris Popov 
1092681a5bbeSBoris Popov /*
1093681a5bbeSBoris Popov  * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
1094681a5bbeSBoris Popov  */
1095681a5bbeSBoris Popov static int
1096681a5bbeSBoris Popov smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
1097681a5bbeSBoris Popov {
1098681a5bbeSBoris Popov 	struct smb_t2rq *t2p;
1099681a5bbeSBoris Popov 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1100681a5bbeSBoris Popov 	struct mbchain *mbp;
1101681a5bbeSBoris Popov 	struct mdchain *mdp;
1102681a5bbeSBoris Popov 	u_int16_t tw, flags;
1103681a5bbeSBoris Popov 	int error;
1104681a5bbeSBoris Popov 
1105681a5bbeSBoris Popov 	if (ctx->f_t2) {
1106681a5bbeSBoris Popov 		smb_t2_done(ctx->f_t2);
1107681a5bbeSBoris Popov 		ctx->f_t2 = NULL;
1108681a5bbeSBoris Popov 	}
1109681a5bbeSBoris Popov 	ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
1110681a5bbeSBoris Popov 	flags = 8 | 2;			/* <resume> | <close if EOS> */
1111681a5bbeSBoris Popov 	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
1112681a5bbeSBoris Popov 		flags |= 1;		/* close search after this request */
1113681a5bbeSBoris Popov 		ctx->f_flags |= SMBFS_RDD_NOCLOSE;
1114681a5bbeSBoris Popov 	}
1115681a5bbeSBoris Popov 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1116681a5bbeSBoris Popov 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
1117681a5bbeSBoris Popov 		    ctx->f_scred, &t2p);
1118681a5bbeSBoris Popov 		if (error)
1119681a5bbeSBoris Popov 			return error;
1120681a5bbeSBoris Popov 		ctx->f_t2 = t2p;
1121681a5bbeSBoris Popov 		mbp = &t2p->t2_tparam;
1122681a5bbeSBoris Popov 		mb_init(mbp);
1123681a5bbeSBoris Popov 		mb_put_uint16le(mbp, ctx->f_attrmask);
1124681a5bbeSBoris Popov 		mb_put_uint16le(mbp, ctx->f_limit);
1125681a5bbeSBoris Popov 		mb_put_uint16le(mbp, flags);
1126681a5bbeSBoris Popov 		mb_put_uint16le(mbp, ctx->f_infolevel);
1127681a5bbeSBoris Popov 		mb_put_uint32le(mbp, 0);
1128681a5bbeSBoris Popov 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
1129681a5bbeSBoris Popov 		if (error)
1130681a5bbeSBoris Popov 			return error;
1131681a5bbeSBoris Popov 	} else	{
1132681a5bbeSBoris Popov 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
1133681a5bbeSBoris Popov 		    ctx->f_scred, &t2p);
1134681a5bbeSBoris Popov 		if (error)
1135681a5bbeSBoris Popov 			return error;
1136681a5bbeSBoris Popov 		ctx->f_t2 = t2p;
1137681a5bbeSBoris Popov 		mbp = &t2p->t2_tparam;
1138681a5bbeSBoris Popov 		mb_init(mbp);
1139681a5bbeSBoris Popov 		mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
1140681a5bbeSBoris Popov 		mb_put_uint16le(mbp, ctx->f_limit);
1141681a5bbeSBoris Popov 		mb_put_uint16le(mbp, ctx->f_infolevel);
1142681a5bbeSBoris Popov 		mb_put_uint32le(mbp, 0);		/* resume key */
1143681a5bbeSBoris Popov 		mb_put_uint16le(mbp, flags);
1144681a5bbeSBoris Popov 		if (ctx->f_rname)
114541f1dcccSKevin Lo 			mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen + 1, MB_MSYSTEM);
1146681a5bbeSBoris Popov 		else
1147681a5bbeSBoris Popov 			mb_put_uint8(mbp, 0);	/* resume file name */
1148681a5bbeSBoris Popov #if 0
1149681a5bbeSBoris Popov 	struct timeval tv;
1150681a5bbeSBoris Popov 	tv.tv_sec = 0;
1151681a5bbeSBoris Popov 	tv.tv_usec = 200 * 1000;	/* 200ms */
1152681a5bbeSBoris Popov 		if (vcp->vc_flags & SMBC_WIN95) {
1153681a5bbeSBoris Popov 			/*
1154681a5bbeSBoris Popov 			 * some implementations suggests to sleep here
1155681a5bbeSBoris Popov 			 * for 200ms, due to the bug in the Win95.
1156681a5bbeSBoris Popov 			 * I've didn't notice any problem, but put code
1157681a5bbeSBoris Popov 			 * for it.
1158681a5bbeSBoris Popov 			 */
11594d70511aSJohn Baldwin 			 pause("fix95", tvtohz(&tv));
1160681a5bbeSBoris Popov 		}
1161681a5bbeSBoris Popov #endif
1162681a5bbeSBoris Popov 	}
1163681a5bbeSBoris Popov 	t2p->t2_maxpcount = 5 * 2;
1164681a5bbeSBoris Popov 	t2p->t2_maxdcount = vcp->vc_txmax;
1165681a5bbeSBoris Popov 	error = smb_t2_request(t2p);
1166681a5bbeSBoris Popov 	if (error)
1167681a5bbeSBoris Popov 		return error;
1168681a5bbeSBoris Popov 	mdp = &t2p->t2_rparam;
1169681a5bbeSBoris Popov 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1170681a5bbeSBoris Popov 		if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
1171681a5bbeSBoris Popov 			return error;
1172681a5bbeSBoris Popov 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1173681a5bbeSBoris Popov 	}
1174681a5bbeSBoris Popov 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
1175681a5bbeSBoris Popov 		return error;
1176681a5bbeSBoris Popov 	ctx->f_ecnt = tw;
1177681a5bbeSBoris Popov 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
1178681a5bbeSBoris Popov 		return error;
1179681a5bbeSBoris Popov 	if (tw)
1180681a5bbeSBoris Popov 		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1181681a5bbeSBoris Popov 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
1182681a5bbeSBoris Popov 		return error;
1183681a5bbeSBoris Popov 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
1184681a5bbeSBoris Popov 		return error;
1185cc518d3bSBoris Popov 	if (ctx->f_ecnt == 0) {
1186cc518d3bSBoris Popov 		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1187681a5bbeSBoris Popov 		return ENOENT;
1188cc518d3bSBoris Popov 	}
1189681a5bbeSBoris Popov 	ctx->f_rnameofs = tw;
1190681a5bbeSBoris Popov 	mdp = &t2p->t2_rdata;
1191681a5bbeSBoris Popov 	if (mdp->md_top == NULL) {
1192681a5bbeSBoris Popov 		printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt);
1193681a5bbeSBoris Popov 		return ENOENT;
1194681a5bbeSBoris Popov 	}
1195681a5bbeSBoris Popov 	if (mdp->md_top->m_len == 0) {
1196681a5bbeSBoris Popov 		printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next);
1197681a5bbeSBoris Popov 		return ENOENT;
1198681a5bbeSBoris Popov 	}
1199681a5bbeSBoris Popov 	ctx->f_eofs = 0;
1200681a5bbeSBoris Popov 	return 0;
1201681a5bbeSBoris Popov }
1202681a5bbeSBoris Popov 
1203681a5bbeSBoris Popov static int
1204681a5bbeSBoris Popov smbfs_smb_findclose2(struct smbfs_fctx *ctx)
1205681a5bbeSBoris Popov {
1206afe09751SDavide Italiano 	struct smb_rq *rqp;
1207681a5bbeSBoris Popov 	struct mbchain *mbp;
1208681a5bbeSBoris Popov 	int error;
1209681a5bbeSBoris Popov 
12109e9421bcSDavide Italiano 	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
12119e9421bcSDavide Italiano 	    ctx->f_scred, &rqp);
12129e9421bcSDavide Italiano 	if (error)
12139e9421bcSDavide Italiano 		return (error);
1214681a5bbeSBoris Popov 	smb_rq_getrequest(rqp, &mbp);
1215681a5bbeSBoris Popov 	smb_rq_wstart(rqp);
1216681a5bbeSBoris Popov 	mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
1217681a5bbeSBoris Popov 	smb_rq_wend(rqp);
1218681a5bbeSBoris Popov 	smb_rq_bstart(rqp);
1219681a5bbeSBoris Popov 	smb_rq_bend(rqp);
1220681a5bbeSBoris Popov 	error = smb_rq_simple(rqp);
1221681a5bbeSBoris Popov 	smb_rq_done(rqp);
1222681a5bbeSBoris Popov 	return error;
1223681a5bbeSBoris Popov }
1224681a5bbeSBoris Popov 
1225681a5bbeSBoris Popov static int
1226681a5bbeSBoris Popov smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
1227681a5bbeSBoris Popov 	const char *wildcard, int wclen, int attr, struct smb_cred *scred)
1228681a5bbeSBoris Popov {
122941f1dcccSKevin Lo 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
123041f1dcccSKevin Lo 		ctx->f_name = malloc(SMB_MAXFNAMELEN * 2, M_SMBFSDATA, M_WAITOK);
123141f1dcccSKevin Lo 	} else
1232a163d034SWarner Losh 		ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
1233681a5bbeSBoris Popov 	ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
1234681a5bbeSBoris Popov 	    SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
1235681a5bbeSBoris Popov 	ctx->f_attrmask = attr;
1236681a5bbeSBoris Popov 	ctx->f_wildcard = wildcard;
1237681a5bbeSBoris Popov 	ctx->f_wclen = wclen;
1238681a5bbeSBoris Popov 	return 0;
1239681a5bbeSBoris Popov }
1240681a5bbeSBoris Popov 
1241681a5bbeSBoris Popov static int
1242681a5bbeSBoris Popov smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
1243681a5bbeSBoris Popov {
1244681a5bbeSBoris Popov 	struct mdchain *mbp;
1245681a5bbeSBoris Popov 	struct smb_t2rq *t2p;
1246681a5bbeSBoris Popov 	char *cp;
1247681a5bbeSBoris Popov 	u_int8_t tb;
1248681a5bbeSBoris Popov 	u_int16_t date, time, wattr;
1249681a5bbeSBoris Popov 	u_int32_t size, next, dattr;
1250681a5bbeSBoris Popov 	int64_t lint;
1251681a5bbeSBoris Popov 	int error, svtz, cnt, fxsz, nmlen, recsz;
1252681a5bbeSBoris Popov 
1253681a5bbeSBoris Popov 	if (ctx->f_ecnt == 0) {
1254681a5bbeSBoris Popov 		if (ctx->f_flags & SMBFS_RDD_EOF)
1255681a5bbeSBoris Popov 			return ENOENT;
1256681a5bbeSBoris Popov 		ctx->f_left = ctx->f_limit = limit;
1257681a5bbeSBoris Popov 		error = smbfs_smb_trans2find2(ctx);
1258681a5bbeSBoris Popov 		if (error)
1259681a5bbeSBoris Popov 			return error;
1260681a5bbeSBoris Popov 	}
1261681a5bbeSBoris Popov 	t2p = ctx->f_t2;
1262681a5bbeSBoris Popov 	mbp = &t2p->t2_rdata;
1263681a5bbeSBoris Popov 	svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
1264681a5bbeSBoris Popov 	switch (ctx->f_infolevel) {
1265681a5bbeSBoris Popov 	    case SMB_INFO_STANDARD:
1266681a5bbeSBoris Popov 		next = 0;
1267681a5bbeSBoris Popov 		fxsz = 0;
1268681a5bbeSBoris Popov 		md_get_uint16le(mbp, &date);
1269681a5bbeSBoris Popov 		md_get_uint16le(mbp, &time);	/* creation time */
1270681a5bbeSBoris Popov 		md_get_uint16le(mbp, &date);
1271681a5bbeSBoris Popov 		md_get_uint16le(mbp, &time);	/* access time */
1272681a5bbeSBoris Popov 		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
1273681a5bbeSBoris Popov 		md_get_uint16le(mbp, &date);
1274681a5bbeSBoris Popov 		md_get_uint16le(mbp, &time);	/* access time */
1275681a5bbeSBoris Popov 		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
1276681a5bbeSBoris Popov 		md_get_uint32le(mbp, &size);
1277681a5bbeSBoris Popov 		ctx->f_attr.fa_size = size;
1278681a5bbeSBoris Popov 		md_get_uint32(mbp, NULL);	/* allocation size */
1279681a5bbeSBoris Popov 		md_get_uint16le(mbp, &wattr);
1280681a5bbeSBoris Popov 		ctx->f_attr.fa_attr = wattr;
1281681a5bbeSBoris Popov 		md_get_uint8(mbp, &tb);
1282681a5bbeSBoris Popov 		size = nmlen = tb;
1283681a5bbeSBoris Popov 		fxsz = 23;
1284681a5bbeSBoris Popov 		recsz = next = 24 + nmlen;	/* docs misses zero byte at end */
1285681a5bbeSBoris Popov 		break;
1286681a5bbeSBoris Popov 	    case SMB_FIND_FILE_DIRECTORY_INFO:
1287681a5bbeSBoris Popov 		md_get_uint32le(mbp, &next);
1288681a5bbeSBoris Popov 		md_get_uint32(mbp, NULL);	/* file index */
1289681a5bbeSBoris Popov 		md_get_int64(mbp, NULL);	/* creation time */
1290681a5bbeSBoris Popov 		md_get_int64le(mbp, &lint);
1291681a5bbeSBoris Popov 		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime);
1292681a5bbeSBoris Popov 		md_get_int64le(mbp, &lint);
1293681a5bbeSBoris Popov 		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime);
1294681a5bbeSBoris Popov 		md_get_int64le(mbp, &lint);
1295681a5bbeSBoris Popov 		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime);
1296681a5bbeSBoris Popov 		md_get_int64le(mbp, &lint);	/* file size */
1297681a5bbeSBoris Popov 		ctx->f_attr.fa_size = lint;
1298681a5bbeSBoris Popov 		md_get_int64(mbp, NULL);	/* real size (should use) */
1299798bb23eSBoris Popov 		md_get_uint32le(mbp, &dattr);	/* EA */
1300681a5bbeSBoris Popov 		ctx->f_attr.fa_attr = dattr;
1301681a5bbeSBoris Popov 		md_get_uint32le(mbp, &size);	/* name len */
1302681a5bbeSBoris Popov 		fxsz = 64;
1303681a5bbeSBoris Popov 		recsz = next ? next : fxsz + size;
1304681a5bbeSBoris Popov 		break;
1305681a5bbeSBoris Popov 	    default:
1306681a5bbeSBoris Popov 		SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
1307681a5bbeSBoris Popov 		return EINVAL;
1308681a5bbeSBoris Popov 	}
130941f1dcccSKevin Lo 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
131041f1dcccSKevin Lo 		nmlen = min(size, SMB_MAXFNAMELEN * 2);
131141f1dcccSKevin Lo 	} else
1312681a5bbeSBoris Popov 		nmlen = min(size, SMB_MAXFNAMELEN);
1313681a5bbeSBoris Popov 	cp = ctx->f_name;
1314681a5bbeSBoris Popov 	error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
1315681a5bbeSBoris Popov 	if (error)
1316681a5bbeSBoris Popov 		return error;
1317681a5bbeSBoris Popov 	if (next) {
1318681a5bbeSBoris Popov 		cnt = next - nmlen - fxsz;
1319681a5bbeSBoris Popov 		if (cnt > 0)
1320681a5bbeSBoris Popov 			md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
1321681a5bbeSBoris Popov 		else if (cnt < 0) {
1322681a5bbeSBoris Popov 			SMBERROR("out of sync\n");
1323681a5bbeSBoris Popov 			return EBADRPC;
1324681a5bbeSBoris Popov 		}
1325681a5bbeSBoris Popov 	}
132641f1dcccSKevin Lo 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
132741f1dcccSKevin Lo 		if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
132841f1dcccSKevin Lo 			nmlen -= 2;
132941f1dcccSKevin Lo 	} else
1330681a5bbeSBoris Popov 		if (nmlen && cp[nmlen - 1] == 0)
1331681a5bbeSBoris Popov 			nmlen--;
1332681a5bbeSBoris Popov 	if (nmlen == 0)
1333681a5bbeSBoris Popov 		return EBADRPC;
1334681a5bbeSBoris Popov 
1335681a5bbeSBoris Popov 	next = ctx->f_eofs + recsz;
1336681a5bbeSBoris Popov 	if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
1337681a5bbeSBoris Popov 	    (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
1338681a5bbeSBoris Popov 		/*
1339681a5bbeSBoris Popov 		 * Server needs a resume filename.
1340681a5bbeSBoris Popov 		 */
1341681a5bbeSBoris Popov 		if (ctx->f_rnamelen <= nmlen) {
1342681a5bbeSBoris Popov 			if (ctx->f_rname)
1343681a5bbeSBoris Popov 				free(ctx->f_rname, M_SMBFSDATA);
1344a163d034SWarner Losh 			ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
1345681a5bbeSBoris Popov 			ctx->f_rnamelen = nmlen;
1346681a5bbeSBoris Popov 		}
1347681a5bbeSBoris Popov 		bcopy(ctx->f_name, ctx->f_rname, nmlen);
1348681a5bbeSBoris Popov 		ctx->f_rname[nmlen] = 0;
1349681a5bbeSBoris Popov 		ctx->f_flags |= SMBFS_RDD_GOTRNAME;
1350681a5bbeSBoris Popov 	}
1351681a5bbeSBoris Popov 	ctx->f_nmlen = nmlen;
1352681a5bbeSBoris Popov 	ctx->f_eofs = next;
1353681a5bbeSBoris Popov 	ctx->f_ecnt--;
1354681a5bbeSBoris Popov 	ctx->f_left--;
1355681a5bbeSBoris Popov 	return 0;
1356681a5bbeSBoris Popov }
1357681a5bbeSBoris Popov 
1358681a5bbeSBoris Popov static int
1359681a5bbeSBoris Popov smbfs_findcloseLM2(struct smbfs_fctx *ctx)
1360681a5bbeSBoris Popov {
1361681a5bbeSBoris Popov 	if (ctx->f_name)
1362681a5bbeSBoris Popov 		free(ctx->f_name, M_SMBFSDATA);
1363681a5bbeSBoris Popov 	if (ctx->f_t2)
1364681a5bbeSBoris Popov 		smb_t2_done(ctx->f_t2);
1365681a5bbeSBoris Popov 	if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
1366681a5bbeSBoris Popov 		smbfs_smb_findclose2(ctx);
1367681a5bbeSBoris Popov 	return 0;
1368681a5bbeSBoris Popov }
1369681a5bbeSBoris Popov 
1370681a5bbeSBoris Popov int
1371681a5bbeSBoris Popov smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
1372681a5bbeSBoris Popov 	struct smb_cred *scred, struct smbfs_fctx **ctxpp)
1373681a5bbeSBoris Popov {
1374681a5bbeSBoris Popov 	struct smbfs_fctx *ctx;
1375681a5bbeSBoris Popov 	int error;
1376681a5bbeSBoris Popov 
13778d9495bbSDavide Italiano 	ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK | M_ZERO);
1378681a5bbeSBoris Popov 	ctx->f_ssp = dnp->n_mount->sm_share;
1379681a5bbeSBoris Popov 	ctx->f_dnp = dnp;
1380681a5bbeSBoris Popov 	ctx->f_flags = SMBFS_RDD_FINDFIRST;
1381681a5bbeSBoris Popov 	ctx->f_scred = scred;
1382681a5bbeSBoris Popov 	if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
1383d14c8441SPoul-Henning Kamp 	    (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) {
1384681a5bbeSBoris Popov 		ctx->f_flags |= SMBFS_RDD_USESEARCH;
1385681a5bbeSBoris Popov 		error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
1386681a5bbeSBoris Popov 	} else
1387681a5bbeSBoris Popov 		error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
1388681a5bbeSBoris Popov 	if (error)
1389681a5bbeSBoris Popov 		smbfs_findclose(ctx, scred);
1390681a5bbeSBoris Popov 	else
1391681a5bbeSBoris Popov 		*ctxpp = ctx;
1392681a5bbeSBoris Popov 	return error;
1393681a5bbeSBoris Popov }
1394681a5bbeSBoris Popov 
1395681a5bbeSBoris Popov int
1396681a5bbeSBoris Popov smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
1397681a5bbeSBoris Popov {
1398681a5bbeSBoris Popov 	int error;
1399681a5bbeSBoris Popov 
1400681a5bbeSBoris Popov 	if (limit == 0)
1401681a5bbeSBoris Popov 		limit = 1000000;
1402681a5bbeSBoris Popov 	else if (limit > 1)
1403681a5bbeSBoris Popov 		limit *= 4;	/* imperical */
1404681a5bbeSBoris Popov 	ctx->f_scred = scred;
1405681a5bbeSBoris Popov 	for (;;) {
1406681a5bbeSBoris Popov 		if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1407681a5bbeSBoris Popov 			error = smbfs_findnextLM1(ctx, limit);
1408681a5bbeSBoris Popov 		} else
1409681a5bbeSBoris Popov 			error = smbfs_findnextLM2(ctx, limit);
1410681a5bbeSBoris Popov 		if (error)
1411681a5bbeSBoris Popov 			return error;
141241f1dcccSKevin Lo 		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
141341f1dcccSKevin Lo 			if ((ctx->f_nmlen == 2 &&
141441f1dcccSKevin Lo 			     *(u_int16_t *)ctx->f_name == htole16(0x002e)) ||
141541f1dcccSKevin Lo 			    (ctx->f_nmlen == 4 &&
141641f1dcccSKevin Lo 			     *(u_int32_t *)ctx->f_name == htole32(0x002e002e)))
141741f1dcccSKevin Lo 				continue;
141841f1dcccSKevin Lo 		} else
1419681a5bbeSBoris Popov 			if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
1420681a5bbeSBoris Popov 			    (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
1421681a5bbeSBoris Popov 			     ctx->f_name[1] == '.'))
1422681a5bbeSBoris Popov 				continue;
1423681a5bbeSBoris Popov 		break;
1424681a5bbeSBoris Popov 	}
14254ebd3ea1STakanori Watanabe 	smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen,
1426681a5bbeSBoris Popov 			    ctx->f_dnp->n_mount->sm_caseopt);
1427681a5bbeSBoris Popov 	ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
1428681a5bbeSBoris Popov 	return 0;
1429681a5bbeSBoris Popov }
1430681a5bbeSBoris Popov 
1431681a5bbeSBoris Popov int
1432681a5bbeSBoris Popov smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
1433681a5bbeSBoris Popov {
1434681a5bbeSBoris Popov 	ctx->f_scred = scred;
1435681a5bbeSBoris Popov 	if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1436681a5bbeSBoris Popov 		smbfs_findcloseLM1(ctx);
1437681a5bbeSBoris Popov 	} else
1438681a5bbeSBoris Popov 		smbfs_findcloseLM2(ctx);
1439681a5bbeSBoris Popov 	if (ctx->f_rname)
1440681a5bbeSBoris Popov 		free(ctx->f_rname, M_SMBFSDATA);
1441681a5bbeSBoris Popov 	free(ctx, M_SMBFSDATA);
1442681a5bbeSBoris Popov 	return 0;
1443681a5bbeSBoris Popov }
1444681a5bbeSBoris Popov 
1445681a5bbeSBoris Popov int
1446681a5bbeSBoris Popov smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
1447681a5bbeSBoris Popov 	struct smbfattr *fap, struct smb_cred *scred)
1448681a5bbeSBoris Popov {
1449681a5bbeSBoris Popov 	struct smbfs_fctx *ctx;
1450681a5bbeSBoris Popov 	int error;
1451681a5bbeSBoris Popov 
1452681a5bbeSBoris Popov 	if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
1453681a5bbeSBoris Popov 		bzero(fap, sizeof(*fap));
1454681a5bbeSBoris Popov 		fap->fa_attr = SMB_FA_DIR;
1455681a5bbeSBoris Popov 		fap->fa_ino = 2;
1456681a5bbeSBoris Popov 		return 0;
1457681a5bbeSBoris Popov 	}
1458ce589ae2SDavide Italiano 	MPASS(!(nmlen == 2 && name[0] == '.' && name[1] == '.'));
1459ce589ae2SDavide Italiano 	MPASS(!(nmlen == 1 && name[0] == '.'));
1460ce589ae2SDavide Italiano 	ASSERT_VOP_ELOCKED(dnp->n_vnode, "smbfs_smb_lookup");
1461681a5bbeSBoris Popov 	error = smbfs_findopen(dnp, name, nmlen,
1462681a5bbeSBoris Popov 	    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
1463681a5bbeSBoris Popov 	if (error)
1464681a5bbeSBoris Popov 		return error;
1465681a5bbeSBoris Popov 	ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
1466681a5bbeSBoris Popov 	error = smbfs_findnext(ctx, 1, scred);
1467681a5bbeSBoris Popov 	if (error == 0) {
1468681a5bbeSBoris Popov 		*fap = ctx->f_attr;
1469681a5bbeSBoris Popov 		if (name == NULL)
1470681a5bbeSBoris Popov 			fap->fa_ino = dnp->n_ino;
1471681a5bbeSBoris Popov 	}
1472681a5bbeSBoris Popov 	smbfs_findclose(ctx, scred);
1473681a5bbeSBoris Popov 	return error;
1474681a5bbeSBoris Popov }
1475