xref: /freebsd/sys/fs/smbfs/smbfs_smb.c (revision 0957b409)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2000-2001 Boris Popov
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/malloc.h>
34 #include <sys/proc.h>
35 #include <sys/lock.h>
36 #include <sys/vnode.h>
37 #include <sys/mbuf.h>
38 #include <sys/mount.h>
39 #include <sys/endian.h>
40 
41 #ifdef USE_MD5_HASH
42 #include <sys/md5.h>
43 #endif
44 
45 #include <netsmb/smb.h>
46 #include <netsmb/smb_subr.h>
47 #include <netsmb/smb_rq.h>
48 #include <netsmb/smb_conn.h>
49 
50 #include <fs/smbfs/smbfs.h>
51 #include <fs/smbfs/smbfs_node.h>
52 #include <fs/smbfs/smbfs_subr.h>
53 
54 /*
55  * Lack of inode numbers leads us to the problem of generating them.
56  * Partially this problem can be solved by having a dir/file cache
57  * with inode numbers generated from the incremented by one counter.
58  * However this way will require too much kernel memory, gives all
59  * sorts of locking and consistency problems, not to mentinon counter overflows.
60  * So, I'm decided to use a hash function to generate pseudo random (and unique)
61  * inode numbers.
62  */
63 static long
64 smbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
65 {
66 #ifdef USE_MD5_HASH
67 	MD5_CTX md5;
68 	u_int32_t state[4];
69 	long ino;
70 	int i;
71 
72 	MD5Init(&md5);
73 	MD5Update(&md5, name, nmlen);
74 	MD5Final((u_char *)state, &md5);
75 	for (i = 0, ino = 0; i < 4; i++)
76 		ino += state[i];
77 	return dnp->n_ino + ino;
78 #endif
79 	u_int32_t ino;
80 
81 	ino = dnp->n_ino + smbfs_hash(name, nmlen);
82 	if (ino <= 2)
83 		ino += 3;
84 	return ino;
85 }
86 
87 static int
88 smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end,
89 	struct smb_cred *scred)
90 {
91 	struct smb_share *ssp = np->n_mount->sm_share;
92 	struct smb_rq *rqp;
93 	struct mbchain *mbp;
94 	u_char ltype = 0;
95 	int error;
96 
97 	if (op == SMB_LOCK_SHARED)
98 		ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
99 
100 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred, &rqp);
101 	if (error)
102 		return (error);
103 	smb_rq_getrequest(rqp, &mbp);
104 	smb_rq_wstart(rqp);
105 	mb_put_uint8(mbp, 0xff);	/* secondary command */
106 	mb_put_uint8(mbp, 0);		/* MBZ */
107 	mb_put_uint16le(mbp, 0);
108 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
109 	mb_put_uint8(mbp, ltype);	/* locktype */
110 	mb_put_uint8(mbp, 0);		/* oplocklevel - 0 seems is NO_OPLOCK */
111 	mb_put_uint32le(mbp, 0);	/* timeout - break immediately */
112 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
113 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
114 	smb_rq_wend(rqp);
115 	smb_rq_bstart(rqp);
116 	mb_put_uint16le(mbp, pid);
117 	mb_put_uint32le(mbp, start);
118 	mb_put_uint32le(mbp, end - start);
119 	smb_rq_bend(rqp);
120 	error = smb_rq_simple(rqp);
121 	smb_rq_done(rqp);
122 	return error;
123 }
124 
125 int
126 smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
127 	off_t start, off_t end,	struct smb_cred *scred)
128 {
129 	struct smb_share *ssp = np->n_mount->sm_share;
130 
131 	if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
132 		/*
133 		 * TODO: use LOCK_BYTE_RANGE here.
134 		 */
135 		return EINVAL;
136 	else
137 		return smbfs_smb_lockandx(np, op, (uintptr_t)id, start, end, scred);
138 }
139 
140 static int
141 smbfs_query_info_fs(struct smb_share *ssp, struct statfs *sbp,
142 	struct smb_cred *scred)
143 {
144 	struct smb_t2rq *t2p;
145 	struct mbchain *mbp;
146 	struct mdchain *mdp;
147 	uint32_t bsize, bpu;
148 	int64_t units, funits;
149 	int error;
150 
151 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
152 	    scred, &t2p);
153 	if (error)
154 		return (error);
155 	mbp = &t2p->t2_tparam;
156 	mb_init(mbp);
157 	mb_put_uint16le(mbp, SMB_QUERY_FS_SIZE_INFO);
158 	t2p->t2_maxpcount = 2;
159 	t2p->t2_maxdcount = sizeof(int64_t) * 2 + sizeof(uint32_t) * 2;
160 	error = smb_t2_request(t2p);
161 	if (error) {
162 		smb_t2_done(t2p);
163 		return (error);
164 	}
165 	mdp = &t2p->t2_rdata;
166 	md_get_int64le(mdp, &units);
167 	md_get_int64le(mdp, &funits);
168 	md_get_uint32le(mdp, &bpu);
169 	md_get_uint32le(mdp, &bsize);
170 	sbp->f_bsize = bpu * bsize;	/* fundamental filesystem block size */
171 	sbp->f_blocks= (uint64_t)units;	/* total data blocks in filesystem */
172 	sbp->f_bfree = (uint64_t)funits;/* free blocks in fs */
173 	sbp->f_bavail= (uint64_t)funits;/* free blocks avail to non-superuser */
174 	sbp->f_files = 0xffff;		/* total file nodes in filesystem */
175 	sbp->f_ffree = 0xffff;		/* free file nodes in fs */
176 	smb_t2_done(t2p);
177 	return (0);
178 }
179 
180 
181 static int
182 smbfs_query_info_alloc(struct smb_share *ssp, struct statfs *sbp,
183 	struct smb_cred *scred)
184 {
185 	struct smb_t2rq *t2p;
186 	struct mbchain *mbp;
187 	struct mdchain *mdp;
188 	u_int16_t bsize;
189 	u_int32_t units, bpu, funits;
190 	int error;
191 
192 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
193 	    scred, &t2p);
194 	if (error)
195 		return error;
196 	mbp = &t2p->t2_tparam;
197 	mb_init(mbp);
198 	mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
199 	t2p->t2_maxpcount = 4;
200 	t2p->t2_maxdcount = 4 * 4 + 2;
201 	error = smb_t2_request(t2p);
202 	if (error) {
203 		smb_t2_done(t2p);
204 		return error;
205 	}
206 	mdp = &t2p->t2_rdata;
207 	md_get_uint32(mdp, NULL);	/* fs id */
208 	md_get_uint32le(mdp, &bpu);
209 	md_get_uint32le(mdp, &units);
210 	md_get_uint32le(mdp, &funits);
211 	md_get_uint16le(mdp, &bsize);
212 	sbp->f_bsize = bpu * bsize;	/* fundamental filesystem block size */
213 	sbp->f_blocks= units;		/* total data blocks in filesystem */
214 	sbp->f_bfree = funits;		/* free blocks in fs */
215 	sbp->f_bavail= funits;		/* free blocks avail to non-superuser */
216 	sbp->f_files = 0xffff;		/* total file nodes in filesystem */
217 	sbp->f_ffree = 0xffff;		/* free file nodes in fs */
218 	smb_t2_done(t2p);
219 	return 0;
220 }
221 
222 static int
223 smbfs_query_info_disk(struct smb_share *ssp, struct statfs *sbp,
224 	struct smb_cred *scred)
225 {
226 	struct smb_rq *rqp;
227 	struct mdchain *mdp;
228 	u_int16_t units, bpu, bsize, funits;
229 	int error;
230 
231 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
232 	    scred, &rqp);
233 	if (error)
234 		return (error);
235 	smb_rq_wstart(rqp);
236 	smb_rq_wend(rqp);
237 	smb_rq_bstart(rqp);
238 	smb_rq_bend(rqp);
239 	error = smb_rq_simple(rqp);
240 	if (error) {
241 		smb_rq_done(rqp);
242 		return error;
243 	}
244 	smb_rq_getreply(rqp, &mdp);
245 	md_get_uint16le(mdp, &units);
246 	md_get_uint16le(mdp, &bpu);
247 	md_get_uint16le(mdp, &bsize);
248 	md_get_uint16le(mdp, &funits);
249 	sbp->f_bsize = bpu * bsize;	/* fundamental filesystem block size */
250 	sbp->f_blocks= units;		/* total data blocks in filesystem */
251 	sbp->f_bfree = funits;		/* free blocks in fs */
252 	sbp->f_bavail= funits;		/* free blocks avail to non-superuser */
253 	sbp->f_files = 0xffff;		/* total file nodes in filesystem */
254 	sbp->f_ffree = 0xffff;		/* free file nodes in fs */
255 	smb_rq_done(rqp);
256 	return 0;
257 }
258 
259 int
260 smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
261 	struct smb_cred *scred)
262 {
263 
264 	if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0) {
265 		if (smbfs_query_info_fs(ssp, sbp, scred) == 0)
266 			return (0);
267 		if (smbfs_query_info_alloc(ssp, sbp, scred) == 0)
268 			return (0);
269 	}
270 	return (smbfs_query_info_disk(ssp, sbp, scred));
271 }
272 
273 static int
274 smbfs_smb_seteof(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
275 {
276 	struct smb_t2rq *t2p;
277 	struct smb_share *ssp = np->n_mount->sm_share;
278 	struct mbchain *mbp;
279 	int error;
280 
281 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
282 	    scred, &t2p);
283 	if (error)
284 		return error;
285 	mbp = &t2p->t2_tparam;
286 	mb_init(mbp);
287 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
288 	mb_put_uint16le(mbp, SMB_SET_FILE_END_OF_FILE_INFO);
289 	mb_put_uint32le(mbp, 0);
290 	mbp = &t2p->t2_tdata;
291 	mb_init(mbp);
292 	mb_put_int64le(mbp, newsize);
293 	mb_put_uint32le(mbp, 0);			/* padding */
294 	mb_put_uint16le(mbp, 0);
295 	t2p->t2_maxpcount = 2;
296 	t2p->t2_maxdcount = 0;
297 	error = smb_t2_request(t2p);
298 	smb_t2_done(t2p);
299 	return error;
300 }
301 
302 static int
303 smb_smb_flush(struct smbnode *np, struct smb_cred *scred)
304 {
305 	struct smb_share *ssp = np->n_mount->sm_share;
306 	struct smb_rq *rqp;
307 	struct mbchain *mbp;
308 	int error;
309 
310 	if ((np->n_flag & NOPEN) == 0 || !SMBTOV(np) ||
311 	    SMBTOV(np)->v_type != VREG)
312 		return 0; /* not a regular open file */
313 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_FLUSH, scred, &rqp);
314 	if (error)
315 		return (error);
316 	smb_rq_getrequest(rqp, &mbp);
317 	smb_rq_wstart(rqp);
318 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
319 	smb_rq_wend(rqp);
320 	smb_rq_bstart(rqp);
321 	smb_rq_bend(rqp);
322 	error = smb_rq_simple(rqp);
323 	smb_rq_done(rqp);
324 	if (!error)
325 		np->n_flag &= ~NFLUSHWIRE;
326 	return (error);
327 }
328 
329 int
330 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scred)
331 {
332 	if (np->n_flag & NFLUSHWIRE)
333 		return (smb_smb_flush(np, scred));
334 	return (0);
335 }
336 
337 int
338 smbfs_smb_setfsize(struct smbnode *np, int64_t newsize, struct smb_cred *scred)
339 {
340 	struct smb_share *ssp = np->n_mount->sm_share;
341 	struct smb_rq *rqp;
342 	struct mbchain *mbp;
343 	int error;
344 
345 	if (!smbfs_smb_seteof(np, newsize, scred)) {
346 		np->n_flag |= NFLUSHWIRE;
347 		return (0);
348 	}
349 	/* XXX: We should use SMB_COM_WRITE_ANDX to support large offsets */
350 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
351 	if (error)
352 		return (error);
353 	smb_rq_getrequest(rqp, &mbp);
354 	smb_rq_wstart(rqp);
355 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
356 	mb_put_uint16le(mbp, 0);
357 	mb_put_uint32le(mbp, (uint32_t)newsize);
358 	mb_put_uint16le(mbp, 0);
359 	smb_rq_wend(rqp);
360 	smb_rq_bstart(rqp);
361 	mb_put_uint8(mbp, SMB_DT_DATA);
362 	mb_put_uint16le(mbp, 0);
363 	smb_rq_bend(rqp);
364 	error = smb_rq_simple(rqp);
365 	smb_rq_done(rqp);
366 	return error;
367 }
368 
369 int
370 smbfs_smb_query_info(struct smbnode *np, const char *name, int len,
371 		     struct smbfattr *fap, struct smb_cred *scred)
372 {
373 	struct smb_rq *rqp;
374 	struct smb_share *ssp = np->n_mount->sm_share;
375 	struct mbchain *mbp;
376 	struct mdchain *mdp;
377 	u_int8_t wc;
378 	int error;
379 	u_int16_t wattr;
380 	u_int32_t lint;
381 
382 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scred,
383 	    &rqp);
384 	if (error)
385 		return (error);
386 	smb_rq_getrequest(rqp, &mbp);
387 	smb_rq_wstart(rqp);
388 	smb_rq_wend(rqp);
389 	smb_rq_bstart(rqp);
390 	mb_put_uint8(mbp, SMB_DT_ASCII);
391 	do {
392 		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len);
393 		if (error)
394 			break;
395 		smb_rq_bend(rqp);
396 		error = smb_rq_simple(rqp);
397 		if (error)
398 			break;
399 		smb_rq_getreply(rqp, &mdp);
400 		if (md_get_uint8(mdp, &wc) != 0 || wc != 10) {
401 			error = EBADRPC;
402 			break;
403 		}
404 		md_get_uint16le(mdp, &wattr);
405 		fap->fa_attr = wattr;
406 		/*
407 		 * Be careful using the time returned here, as
408 		 * with FAT on NT4SP6, at least, the time returned is low
409 		 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
410 		 * over about every seven minutes!
411 		 */
412 		md_get_uint32le(mdp, &lint); /* specs: secs since 1970 */
413 		if (lint)	/* avoid bogus zero returns */
414 			smb_time_server2local(lint, SSTOVC(ssp)->vc_sopt.sv_tz,
415 					      &fap->fa_mtime);
416 		md_get_uint32le(mdp, &lint);
417 		fap->fa_size = lint;
418 	} while(0);
419 	smb_rq_done(rqp);
420 	return error;
421 }
422 
423 /*
424  * Set DOS file attributes. mtime should be NULL for dialects above lm10
425  */
426 int
427 smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
428 	struct smb_cred *scred)
429 {
430 	struct smb_rq *rqp;
431 	struct smb_share *ssp = np->n_mount->sm_share;
432 	struct mbchain *mbp;
433 	u_long time;
434 	int error, svtz;
435 
436 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred,
437 	    &rqp);
438 	if (error)
439 		return (error);
440 	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
441 	smb_rq_getrequest(rqp, &mbp);
442 	smb_rq_wstart(rqp);
443 	mb_put_uint16le(mbp, attr);
444 	if (mtime) {
445 		smb_time_local2server(mtime, svtz, &time);
446 	} else
447 		time = 0;
448 	mb_put_uint32le(mbp, time);		/* mtime */
449 	mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
450 	smb_rq_wend(rqp);
451 	smb_rq_bstart(rqp);
452 	mb_put_uint8(mbp, SMB_DT_ASCII);
453 	do {
454 		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
455 		if (error)
456 			break;
457 		mb_put_uint8(mbp, SMB_DT_ASCII);
458 		if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
459 			mb_put_padbyte(mbp);
460 			mb_put_uint8(mbp, 0);	/* 1st byte of NULL Unicode char */
461 		}
462 		mb_put_uint8(mbp, 0);
463 		smb_rq_bend(rqp);
464 		error = smb_rq_simple(rqp);
465 		if (error) {
466 			SMBERROR("smb_rq_simple(rqp) => error %d\n", error);
467 			break;
468 		}
469 	} while(0);
470 	smb_rq_done(rqp);
471 	return error;
472 }
473 
474 /*
475  * Note, win95 doesn't support this call.
476  */
477 int
478 smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
479 	struct timespec *atime, int attr, struct smb_cred *scred)
480 {
481 	struct smb_t2rq *t2p;
482 	struct smb_share *ssp = np->n_mount->sm_share;
483 	struct smb_vc *vcp = SSTOVC(ssp);
484 	struct mbchain *mbp;
485 	u_int16_t date, time;
486 	int error, tzoff;
487 
488 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
489 	    scred, &t2p);
490 	if (error)
491 		return error;
492 	mbp = &t2p->t2_tparam;
493 	mb_init(mbp);
494 	mb_put_uint16le(mbp, SMB_INFO_STANDARD);
495 	mb_put_uint32le(mbp, 0);		/* MBZ */
496 	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
497 	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
498 	if (error) {
499 		smb_t2_done(t2p);
500 		return error;
501 	}
502 	tzoff = vcp->vc_sopt.sv_tz;
503 	mbp = &t2p->t2_tdata;
504 	mb_init(mbp);
505 	mb_put_uint32le(mbp, 0);		/* creation time */
506 	if (atime)
507 		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
508 	else
509 		time = date = 0;
510 	mb_put_uint16le(mbp, date);
511 	mb_put_uint16le(mbp, time);
512 	if (mtime)
513 		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
514 	else
515 		time = date = 0;
516 	mb_put_uint16le(mbp, date);
517 	mb_put_uint16le(mbp, time);
518 	mb_put_uint32le(mbp, 0);		/* file size */
519 	mb_put_uint32le(mbp, 0);		/* allocation unit size */
520 	mb_put_uint16le(mbp, attr);	/* DOS attr */
521 	mb_put_uint32le(mbp, 0);		/* EA size */
522 	t2p->t2_maxpcount = 5 * 2;
523 	t2p->t2_maxdcount = vcp->vc_txmax;
524 	error = smb_t2_request(t2p);
525 	smb_t2_done(t2p);
526 	return error;
527 }
528 
529 /*
530  * NT level. Specially for win9x
531  */
532 int
533 smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
534 	struct timespec *atime, struct smb_cred *scred)
535 {
536 	struct smb_t2rq *t2p;
537 	struct smb_share *ssp = np->n_mount->sm_share;
538 	struct smb_vc *vcp = SSTOVC(ssp);
539 	struct mbchain *mbp;
540 	int64_t tm;
541 	int error, tzoff;
542 
543 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
544 	    scred, &t2p);
545 	if (error)
546 		return error;
547 	mbp = &t2p->t2_tparam;
548 	mb_init(mbp);
549 	mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
550 	mb_put_uint32le(mbp, 0);		/* MBZ */
551 	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
552 	error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
553 	if (error) {
554 		smb_t2_done(t2p);
555 		return error;
556 	}
557 	tzoff = vcp->vc_sopt.sv_tz;
558 	mbp = &t2p->t2_tdata;
559 	mb_init(mbp);
560 	mb_put_int64le(mbp, 0);		/* creation time */
561 	if (atime) {
562 		smb_time_local2NT(atime, tzoff, &tm);
563 	} else
564 		tm = 0;
565 	mb_put_int64le(mbp, tm);
566 	if (mtime) {
567 		smb_time_local2NT(mtime, tzoff, &tm);
568 	} else
569 		tm = 0;
570 	mb_put_int64le(mbp, tm);
571 	mb_put_int64le(mbp, tm);		/* change time */
572 	mb_put_uint32le(mbp, attr);		/* attr */
573 	t2p->t2_maxpcount = 24;
574 	t2p->t2_maxdcount = 56;
575 	error = smb_t2_request(t2p);
576 	smb_t2_done(t2p);
577 	return error;
578 }
579 
580 /*
581  * Set file atime and mtime. Doesn't supported by core dialect.
582  */
583 int
584 smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
585 	struct timespec *atime, struct smb_cred *scred)
586 {
587 	struct smb_rq *rqp;
588 	struct smb_share *ssp = np->n_mount->sm_share;
589 	struct mbchain *mbp;
590 	u_int16_t date, time;
591 	int error, tzoff;
592 
593 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred,
594 	    &rqp);
595 	if (error)
596 		return (error);
597 	tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
598 	smb_rq_getrequest(rqp, &mbp);
599 	smb_rq_wstart(rqp);
600 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
601 	mb_put_uint32le(mbp, 0);		/* creation time */
602 
603 	if (atime)
604 		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
605 	else
606 		time = date = 0;
607 	mb_put_uint16le(mbp, date);
608 	mb_put_uint16le(mbp, time);
609 	if (mtime)
610 		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
611 	else
612 		time = date = 0;
613 	mb_put_uint16le(mbp, date);
614 	mb_put_uint16le(mbp, time);
615 	smb_rq_wend(rqp);
616 	smb_rq_bstart(rqp);
617 	smb_rq_bend(rqp);
618 	error = smb_rq_simple(rqp);
619 	SMBSDEBUG("%d\n", error);
620 	smb_rq_done(rqp);
621 	return error;
622 }
623 
624 /*
625  * Set DOS file attributes.
626  * Looks like this call can be used only if SMB_CAP_NT_SMBS bit is on.
627  */
628 int
629 smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
630 	struct timespec *atime, struct smb_cred *scred)
631 {
632 	struct smb_t2rq *t2p;
633 	struct smb_share *ssp = np->n_mount->sm_share;
634 	struct mbchain *mbp;
635 	int64_t tm;
636 	int error, svtz;
637 
638 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
639 	    scred, &t2p);
640 	if (error)
641 		return error;
642 	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
643 	mbp = &t2p->t2_tparam;
644 	mb_init(mbp);
645 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
646 	mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
647 	mb_put_uint32le(mbp, 0);
648 	mbp = &t2p->t2_tdata;
649 	mb_init(mbp);
650 	mb_put_int64le(mbp, 0);		/* creation time */
651 	if (atime) {
652 		smb_time_local2NT(atime, svtz, &tm);
653 	} else
654 		tm = 0;
655 	mb_put_int64le(mbp, tm);
656 	if (mtime) {
657 		smb_time_local2NT(mtime, svtz, &tm);
658 	} else
659 		tm = 0;
660 	mb_put_int64le(mbp, tm);
661 	mb_put_int64le(mbp, tm);		/* change time */
662 	mb_put_uint16le(mbp, attr);
663 	mb_put_uint32le(mbp, 0);			/* padding */
664 	mb_put_uint16le(mbp, 0);
665 	t2p->t2_maxpcount = 2;
666 	t2p->t2_maxdcount = 0;
667 	error = smb_t2_request(t2p);
668 	smb_t2_done(t2p);
669 	return error;
670 }
671 
672 
673 int
674 smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
675 {
676 	struct smb_rq *rqp;
677 	struct smb_share *ssp = np->n_mount->sm_share;
678 	struct mbchain *mbp;
679 	struct mdchain *mdp;
680 	u_int8_t wc;
681 	u_int16_t fid, wattr, grantedmode;
682 	int error;
683 
684 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_OPEN, scred, &rqp);
685 	if (error)
686 		return (error);
687 	smb_rq_getrequest(rqp, &mbp);
688 	smb_rq_wstart(rqp);
689 	mb_put_uint16le(mbp, accmode);
690 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
691 	smb_rq_wend(rqp);
692 	smb_rq_bstart(rqp);
693 	mb_put_uint8(mbp, SMB_DT_ASCII);
694 	do {
695 		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
696 		if (error)
697 			break;
698 		smb_rq_bend(rqp);
699 		error = smb_rq_simple(rqp);
700 		if (error)
701 			break;
702 		smb_rq_getreply(rqp, &mdp);
703 		if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
704 			error = EBADRPC;
705 			break;
706 		}
707 		md_get_uint16(mdp, &fid);
708 		md_get_uint16le(mdp, &wattr);
709 		md_get_uint32(mdp, NULL);	/* mtime */
710 		md_get_uint32(mdp, NULL);	/* fsize */
711 		md_get_uint16le(mdp, &grantedmode);
712 		/*
713 		 * TODO: refresh attributes from this reply
714 		 */
715 	} while(0);
716 	smb_rq_done(rqp);
717 	if (error)
718 		return error;
719 	np->n_fid = fid;
720 	np->n_rwstate = grantedmode;
721 	return 0;
722 }
723 
724 
725 int
726 smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
727 	struct smb_cred *scred)
728 {
729 	struct smb_rq *rqp;
730 	struct mbchain *mbp;
731 	u_long time;
732 	int error;
733 
734 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CLOSE, scred, &rqp);
735 	if (error)
736 		return (error);
737 	smb_rq_getrequest(rqp, &mbp);
738 	smb_rq_wstart(rqp);
739 	mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
740 	if (mtime) {
741 		smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
742 	} else
743 		time = 0;
744 	mb_put_uint32le(mbp, time);
745 	smb_rq_wend(rqp);
746 	smb_rq_bstart(rqp);
747 	smb_rq_bend(rqp);
748 	error = smb_rq_simple(rqp);
749 	smb_rq_done(rqp);
750 	return error;
751 }
752 
753 int
754 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
755 	struct smb_cred *scred)
756 {
757 	struct smb_rq *rqp;
758 	struct smb_share *ssp = dnp->n_mount->sm_share;
759 	struct mbchain *mbp;
760 	struct mdchain *mdp;
761 	struct timespec ctime;
762 	u_int8_t wc;
763 	u_int16_t fid;
764 	u_long tm;
765 	int error;
766 
767 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE, scred, &rqp);
768 	if (error)
769 		return (error);
770 	smb_rq_getrequest(rqp, &mbp);
771 	smb_rq_wstart(rqp);
772 	mb_put_uint16le(mbp, SMB_FA_ARCHIVE);		/* attributes  */
773 	nanotime(&ctime);
774 	smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
775 	mb_put_uint32le(mbp, tm);
776 	smb_rq_wend(rqp);
777 	smb_rq_bstart(rqp);
778 	mb_put_uint8(mbp, SMB_DT_ASCII);
779 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen);
780 	if (!error) {
781 		smb_rq_bend(rqp);
782 		error = smb_rq_simple(rqp);
783 		if (!error) {
784 			smb_rq_getreply(rqp, &mdp);
785 			md_get_uint8(mdp, &wc);
786 			if (wc == 1)
787 				md_get_uint16(mdp, &fid);
788 			else
789 				error = EBADRPC;
790 		}
791 	}
792 	smb_rq_done(rqp);
793 	if (error)
794 		return error;
795 	smbfs_smb_close(ssp, fid, &ctime, scred);
796 	return error;
797 }
798 
799 int
800 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
801 {
802 	struct smb_rq *rqp;
803 	struct smb_share *ssp = np->n_mount->sm_share;
804 	struct mbchain *mbp;
805 	int error;
806 
807 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE, scred, &rqp);
808 	if (error)
809 		return (error);
810 	smb_rq_getrequest(rqp, &mbp);
811 	smb_rq_wstart(rqp);
812 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
813 	smb_rq_wend(rqp);
814 	smb_rq_bstart(rqp);
815 	mb_put_uint8(mbp, SMB_DT_ASCII);
816 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
817 	if (!error) {
818 		smb_rq_bend(rqp);
819 		error = smb_rq_simple(rqp);
820 	}
821 	smb_rq_done(rqp);
822 	return error;
823 }
824 
825 int
826 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
827 	const char *tname, int tnmlen, struct smb_cred *scred)
828 {
829 	struct smb_rq *rqp;
830 	struct smb_share *ssp = src->n_mount->sm_share;
831 	struct mbchain *mbp;
832 	int error;
833 
834 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_RENAME, scred, &rqp);
835 	if (error)
836 		return (error);
837 	smb_rq_getrequest(rqp, &mbp);
838 	smb_rq_wstart(rqp);
839 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
840 	smb_rq_wend(rqp);
841 	smb_rq_bstart(rqp);
842 	mb_put_uint8(mbp, SMB_DT_ASCII);
843 	do {
844 		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
845 		if (error)
846 			break;
847 		mb_put_uint8(mbp, SMB_DT_ASCII);
848 		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
849 		if (error)
850 			break;
851 		smb_rq_bend(rqp);
852 		error = smb_rq_simple(rqp);
853 	} while(0);
854 	smb_rq_done(rqp);
855 	return error;
856 }
857 
858 int
859 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
860 	const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
861 {
862 	struct smb_rq *rqp;
863 	struct smb_share *ssp = src->n_mount->sm_share;
864 	struct mbchain *mbp;
865 	int error;
866 
867 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_MOVE, scred, &rqp);
868 	if (error)
869 		return (error);
870 	smb_rq_getrequest(rqp, &mbp);
871 	smb_rq_wstart(rqp);
872 	mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
873 	mb_put_uint16le(mbp, 0x20);	/* delete target file */
874 	mb_put_uint16le(mbp, flags);
875 	smb_rq_wend(rqp);
876 	smb_rq_bstart(rqp);
877 	mb_put_uint8(mbp, SMB_DT_ASCII);
878 	do {
879 		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
880 		if (error)
881 			break;
882 		mb_put_uint8(mbp, SMB_DT_ASCII);
883 		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
884 		if (error)
885 			break;
886 		smb_rq_bend(rqp);
887 		error = smb_rq_simple(rqp);
888 	} while(0);
889 	smb_rq_done(rqp);
890 	return error;
891 }
892 
893 int
894 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
895 	struct smb_cred *scred)
896 {
897 	struct smb_rq *rqp;
898 	struct smb_share *ssp = dnp->n_mount->sm_share;
899 	struct mbchain *mbp;
900 	int error;
901 
902 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred,
903 	    &rqp);
904 	if (error)
905 		return (error);
906 	smb_rq_getrequest(rqp, &mbp);
907 	smb_rq_wstart(rqp);
908 	smb_rq_wend(rqp);
909 	smb_rq_bstart(rqp);
910 	mb_put_uint8(mbp, SMB_DT_ASCII);
911 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len);
912 	if (!error) {
913 		smb_rq_bend(rqp);
914 		error = smb_rq_simple(rqp);
915 	}
916 	smb_rq_done(rqp);
917 	return error;
918 }
919 
920 int
921 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred)
922 {
923 	struct smb_rq *rqp;
924 	struct smb_share *ssp = np->n_mount->sm_share;
925 	struct mbchain *mbp;
926 	int error;
927 
928 	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred,
929 	    &rqp);
930 	if (error)
931 		return (error);
932 	smb_rq_getrequest(rqp, &mbp);
933 	smb_rq_wstart(rqp);
934 	smb_rq_wend(rqp);
935 	smb_rq_bstart(rqp);
936 	mb_put_uint8(mbp, SMB_DT_ASCII);
937 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
938 	if (!error) {
939 		smb_rq_bend(rqp);
940 		error = smb_rq_simple(rqp);
941 	}
942 	smb_rq_done(rqp);
943 	return error;
944 }
945 
946 static int
947 smbfs_smb_search(struct smbfs_fctx *ctx)
948 {
949 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
950 	struct smb_rq *rqp;
951 	struct mbchain *mbp;
952 	struct mdchain *mdp;
953 	u_int8_t wc, bt;
954 	u_int16_t ec, dlen, bc;
955 	int maxent, error, iseof = 0;
956 
957 	maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / SMB_DENTRYLEN);
958 	if (ctx->f_rq) {
959 		smb_rq_done(ctx->f_rq);
960 		ctx->f_rq = NULL;
961 	}
962 	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH, ctx->f_scred, &rqp);
963 	if (error)
964 		return (error);
965 	ctx->f_rq = rqp;
966 	smb_rq_getrequest(rqp, &mbp);
967 	smb_rq_wstart(rqp);
968 	mb_put_uint16le(mbp, maxent);	/* max entries to return */
969 	mb_put_uint16le(mbp, ctx->f_attrmask);
970 	smb_rq_wend(rqp);
971 	smb_rq_bstart(rqp);
972 	mb_put_uint8(mbp, SMB_DT_ASCII);	/* buffer format */
973 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
974 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
975 		if (error)
976 			return error;
977 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
978 		mb_put_uint16le(mbp, 0);	/* context length */
979 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
980 	} else {
981 		if (SMB_UNICODE_STRINGS(vcp)) {
982 			mb_put_padbyte(mbp);
983 			mb_put_uint8(mbp, 0);
984 		}
985 		mb_put_uint8(mbp, 0);	/* file name length */
986 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
987 		mb_put_uint16le(mbp, SMB_SKEYLEN);
988 		mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
989 	}
990 	smb_rq_bend(rqp);
991 	error = smb_rq_simple(rqp);
992 	if (error) {
993 		if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
994 			error = 0;
995 			iseof = 1;
996 			ctx->f_flags |= SMBFS_RDD_EOF;
997 		} else
998 			return error;
999 	}
1000 	smb_rq_getreply(rqp, &mdp);
1001 	md_get_uint8(mdp, &wc);
1002 	if (wc != 1)
1003 		return iseof ? ENOENT : EBADRPC;
1004 	md_get_uint16le(mdp, &ec);
1005 	if (ec == 0)
1006 		return ENOENT;
1007 	ctx->f_ecnt = ec;
1008 	md_get_uint16le(mdp, &bc);
1009 	if (bc < 3)
1010 		return EBADRPC;
1011 	bc -= 3;
1012 	md_get_uint8(mdp, &bt);
1013 	if (bt != SMB_DT_VARIABLE)
1014 		return EBADRPC;
1015 	md_get_uint16le(mdp, &dlen);
1016 	if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
1017 		return EBADRPC;
1018 	return 0;
1019 }
1020 
1021 static int
1022 smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
1023 	const char *wildcard, int wclen, int attr, struct smb_cred *scred)
1024 {
1025 	ctx->f_attrmask = attr;
1026 	if (wildcard) {
1027 		if (wclen == 1 && wildcard[0] == '*') {
1028 			ctx->f_wildcard = "*.*";
1029 			ctx->f_wclen = 3;
1030 		} else {
1031 			ctx->f_wildcard = wildcard;
1032 			ctx->f_wclen = wclen;
1033 		}
1034 	} else {
1035 		ctx->f_wildcard = NULL;
1036 		ctx->f_wclen = 0;
1037 	}
1038 	ctx->f_name = ctx->f_fname;
1039 	return 0;
1040 }
1041 
1042 static int
1043 smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
1044 {
1045 	struct mdchain *mbp;
1046 	struct smb_rq *rqp;
1047 	char *cp;
1048 	u_int8_t battr;
1049 	u_int16_t date, time;
1050 	u_int32_t size;
1051 	int error;
1052 
1053 	if (ctx->f_ecnt == 0) {
1054 		if (ctx->f_flags & SMBFS_RDD_EOF)
1055 			return ENOENT;
1056 		ctx->f_left = ctx->f_limit = limit;
1057 		error = smbfs_smb_search(ctx);
1058 		if (error)
1059 			return error;
1060 	}
1061 	rqp = ctx->f_rq;
1062 	smb_rq_getreply(rqp, &mbp);
1063 	md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1064 	md_get_uint8(mbp, &battr);
1065 	md_get_uint16le(mbp, &time);
1066 	md_get_uint16le(mbp, &date);
1067 	md_get_uint32le(mbp, &size);
1068 	cp = ctx->f_name;
1069 	md_get_mem(mbp, cp, sizeof(ctx->f_fname), MB_MSYSTEM);
1070 	cp[sizeof(ctx->f_fname) - 1] = 0;
1071 	cp += strlen(cp) - 1;
1072 	while (*cp == ' ' && cp >= ctx->f_name)
1073 		*cp-- = 0;
1074 	ctx->f_attr.fa_attr = battr;
1075 	smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
1076 	    &ctx->f_attr.fa_mtime);
1077 	ctx->f_attr.fa_size = size;
1078 	ctx->f_nmlen = strlen(ctx->f_name);
1079 	ctx->f_ecnt--;
1080 	ctx->f_left--;
1081 	return 0;
1082 }
1083 
1084 static int
1085 smbfs_findcloseLM1(struct smbfs_fctx *ctx)
1086 {
1087 	if (ctx->f_rq)
1088 		smb_rq_done(ctx->f_rq);
1089 	return 0;
1090 }
1091 
1092 /*
1093  * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
1094  */
1095 static int
1096 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
1097 {
1098 	struct smb_t2rq *t2p;
1099 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1100 	struct mbchain *mbp;
1101 	struct mdchain *mdp;
1102 	u_int16_t tw, flags;
1103 	int error;
1104 
1105 	if (ctx->f_t2) {
1106 		smb_t2_done(ctx->f_t2);
1107 		ctx->f_t2 = NULL;
1108 	}
1109 	ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
1110 	flags = 8 | 2;			/* <resume> | <close if EOS> */
1111 	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
1112 		flags |= 1;		/* close search after this request */
1113 		ctx->f_flags |= SMBFS_RDD_NOCLOSE;
1114 	}
1115 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1116 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
1117 		    ctx->f_scred, &t2p);
1118 		if (error)
1119 			return error;
1120 		ctx->f_t2 = t2p;
1121 		mbp = &t2p->t2_tparam;
1122 		mb_init(mbp);
1123 		mb_put_uint16le(mbp, ctx->f_attrmask);
1124 		mb_put_uint16le(mbp, ctx->f_limit);
1125 		mb_put_uint16le(mbp, flags);
1126 		mb_put_uint16le(mbp, ctx->f_infolevel);
1127 		mb_put_uint32le(mbp, 0);
1128 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard, ctx->f_wclen);
1129 		if (error)
1130 			return error;
1131 	} else	{
1132 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
1133 		    ctx->f_scred, &t2p);
1134 		if (error)
1135 			return error;
1136 		ctx->f_t2 = t2p;
1137 		mbp = &t2p->t2_tparam;
1138 		mb_init(mbp);
1139 		mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
1140 		mb_put_uint16le(mbp, ctx->f_limit);
1141 		mb_put_uint16le(mbp, ctx->f_infolevel);
1142 		mb_put_uint32le(mbp, 0);		/* resume key */
1143 		mb_put_uint16le(mbp, flags);
1144 		if (ctx->f_rname)
1145 			mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen + 1, MB_MSYSTEM);
1146 		else
1147 			mb_put_uint8(mbp, 0);	/* resume file name */
1148 #if 0
1149 	struct timeval tv;
1150 	tv.tv_sec = 0;
1151 	tv.tv_usec = 200 * 1000;	/* 200ms */
1152 		if (vcp->vc_flags & SMBC_WIN95) {
1153 			/*
1154 			 * some implementations suggests to sleep here
1155 			 * for 200ms, due to the bug in the Win95.
1156 			 * I've didn't notice any problem, but put code
1157 			 * for it.
1158 			 */
1159 			 pause("fix95", tvtohz(&tv));
1160 		}
1161 #endif
1162 	}
1163 	t2p->t2_maxpcount = 5 * 2;
1164 	t2p->t2_maxdcount = vcp->vc_txmax;
1165 	error = smb_t2_request(t2p);
1166 	if (error)
1167 		return error;
1168 	mdp = &t2p->t2_rparam;
1169 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1170 		if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
1171 			return error;
1172 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1173 	}
1174 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
1175 		return error;
1176 	ctx->f_ecnt = tw;
1177 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
1178 		return error;
1179 	if (tw)
1180 		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1181 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
1182 		return error;
1183 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
1184 		return error;
1185 	if (ctx->f_ecnt == 0) {
1186 		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
1187 		return ENOENT;
1188 	}
1189 	ctx->f_rnameofs = tw;
1190 	mdp = &t2p->t2_rdata;
1191 	if (mdp->md_top == NULL) {
1192 		printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt);
1193 		return ENOENT;
1194 	}
1195 	if (mdp->md_top->m_len == 0) {
1196 		printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next);
1197 		return ENOENT;
1198 	}
1199 	ctx->f_eofs = 0;
1200 	return 0;
1201 }
1202 
1203 static int
1204 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
1205 {
1206 	struct smb_rq *rqp;
1207 	struct mbchain *mbp;
1208 	int error;
1209 
1210 	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
1211 	    ctx->f_scred, &rqp);
1212 	if (error)
1213 		return (error);
1214 	smb_rq_getrequest(rqp, &mbp);
1215 	smb_rq_wstart(rqp);
1216 	mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
1217 	smb_rq_wend(rqp);
1218 	smb_rq_bstart(rqp);
1219 	smb_rq_bend(rqp);
1220 	error = smb_rq_simple(rqp);
1221 	smb_rq_done(rqp);
1222 	return error;
1223 }
1224 
1225 static int
1226 smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
1227 	const char *wildcard, int wclen, int attr, struct smb_cred *scred)
1228 {
1229 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1230 		ctx->f_name = malloc(SMB_MAXFNAMELEN * 2, M_SMBFSDATA, M_WAITOK);
1231 	} else
1232 		ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
1233 	ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
1234 	    SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
1235 	ctx->f_attrmask = attr;
1236 	ctx->f_wildcard = wildcard;
1237 	ctx->f_wclen = wclen;
1238 	return 0;
1239 }
1240 
1241 static int
1242 smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
1243 {
1244 	struct mdchain *mbp;
1245 	struct smb_t2rq *t2p;
1246 	char *cp;
1247 	u_int8_t tb;
1248 	u_int16_t date, time, wattr;
1249 	u_int32_t size, next, dattr;
1250 	int64_t lint;
1251 	int error, svtz, cnt, fxsz, nmlen, recsz;
1252 
1253 	if (ctx->f_ecnt == 0) {
1254 		if (ctx->f_flags & SMBFS_RDD_EOF)
1255 			return ENOENT;
1256 		ctx->f_left = ctx->f_limit = limit;
1257 		error = smbfs_smb_trans2find2(ctx);
1258 		if (error)
1259 			return error;
1260 	}
1261 	t2p = ctx->f_t2;
1262 	mbp = &t2p->t2_rdata;
1263 	svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
1264 	switch (ctx->f_infolevel) {
1265 	    case SMB_INFO_STANDARD:
1266 		next = 0;
1267 		fxsz = 0;
1268 		md_get_uint16le(mbp, &date);
1269 		md_get_uint16le(mbp, &time);	/* creation time */
1270 		md_get_uint16le(mbp, &date);
1271 		md_get_uint16le(mbp, &time);	/* access time */
1272 		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
1273 		md_get_uint16le(mbp, &date);
1274 		md_get_uint16le(mbp, &time);	/* access time */
1275 		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
1276 		md_get_uint32le(mbp, &size);
1277 		ctx->f_attr.fa_size = size;
1278 		md_get_uint32(mbp, NULL);	/* allocation size */
1279 		md_get_uint16le(mbp, &wattr);
1280 		ctx->f_attr.fa_attr = wattr;
1281 		md_get_uint8(mbp, &tb);
1282 		size = nmlen = tb;
1283 		fxsz = 23;
1284 		recsz = next = 24 + nmlen;	/* docs misses zero byte at end */
1285 		break;
1286 	    case SMB_FIND_FILE_DIRECTORY_INFO:
1287 		md_get_uint32le(mbp, &next);
1288 		md_get_uint32(mbp, NULL);	/* file index */
1289 		md_get_int64(mbp, NULL);	/* creation time */
1290 		md_get_int64le(mbp, &lint);
1291 		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime);
1292 		md_get_int64le(mbp, &lint);
1293 		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime);
1294 		md_get_int64le(mbp, &lint);
1295 		smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime);
1296 		md_get_int64le(mbp, &lint);	/* file size */
1297 		ctx->f_attr.fa_size = lint;
1298 		md_get_int64(mbp, NULL);	/* real size (should use) */
1299 		md_get_uint32le(mbp, &dattr);	/* EA */
1300 		ctx->f_attr.fa_attr = dattr;
1301 		md_get_uint32le(mbp, &size);	/* name len */
1302 		fxsz = 64;
1303 		recsz = next ? next : fxsz + size;
1304 		break;
1305 	    default:
1306 		SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
1307 		return EINVAL;
1308 	}
1309 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1310 		nmlen = min(size, SMB_MAXFNAMELEN * 2);
1311 	} else
1312 		nmlen = min(size, SMB_MAXFNAMELEN);
1313 	cp = ctx->f_name;
1314 	error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
1315 	if (error)
1316 		return error;
1317 	if (next) {
1318 		cnt = next - nmlen - fxsz;
1319 		if (cnt > 0)
1320 			md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
1321 		else if (cnt < 0) {
1322 			SMBERROR("out of sync\n");
1323 			return EBADRPC;
1324 		}
1325 	}
1326 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1327 		if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
1328 			nmlen -= 2;
1329 	} else
1330 		if (nmlen && cp[nmlen - 1] == 0)
1331 			nmlen--;
1332 	if (nmlen == 0)
1333 		return EBADRPC;
1334 
1335 	next = ctx->f_eofs + recsz;
1336 	if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
1337 	    (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
1338 		/*
1339 		 * Server needs a resume filename.
1340 		 */
1341 		if (ctx->f_rnamelen <= nmlen) {
1342 			if (ctx->f_rname)
1343 				free(ctx->f_rname, M_SMBFSDATA);
1344 			ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
1345 			ctx->f_rnamelen = nmlen;
1346 		}
1347 		bcopy(ctx->f_name, ctx->f_rname, nmlen);
1348 		ctx->f_rname[nmlen] = 0;
1349 		ctx->f_flags |= SMBFS_RDD_GOTRNAME;
1350 	}
1351 	ctx->f_nmlen = nmlen;
1352 	ctx->f_eofs = next;
1353 	ctx->f_ecnt--;
1354 	ctx->f_left--;
1355 	return 0;
1356 }
1357 
1358 static int
1359 smbfs_findcloseLM2(struct smbfs_fctx *ctx)
1360 {
1361 	if (ctx->f_name)
1362 		free(ctx->f_name, M_SMBFSDATA);
1363 	if (ctx->f_t2)
1364 		smb_t2_done(ctx->f_t2);
1365 	if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
1366 		smbfs_smb_findclose2(ctx);
1367 	return 0;
1368 }
1369 
1370 int
1371 smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
1372 	struct smb_cred *scred, struct smbfs_fctx **ctxpp)
1373 {
1374 	struct smbfs_fctx *ctx;
1375 	int error;
1376 
1377 	ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK | M_ZERO);
1378 	ctx->f_ssp = dnp->n_mount->sm_share;
1379 	ctx->f_dnp = dnp;
1380 	ctx->f_flags = SMBFS_RDD_FINDFIRST;
1381 	ctx->f_scred = scred;
1382 	if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
1383 	    (dnp->n_mount->sm_flags & SMBFS_MOUNT_NO_LONG)) {
1384 		ctx->f_flags |= SMBFS_RDD_USESEARCH;
1385 		error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
1386 	} else
1387 		error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
1388 	if (error)
1389 		smbfs_findclose(ctx, scred);
1390 	else
1391 		*ctxpp = ctx;
1392 	return error;
1393 }
1394 
1395 int
1396 smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
1397 {
1398 	int error;
1399 
1400 	if (limit == 0)
1401 		limit = 1000000;
1402 	else if (limit > 1)
1403 		limit *= 4;	/* imperical */
1404 	ctx->f_scred = scred;
1405 	for (;;) {
1406 		if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1407 			error = smbfs_findnextLM1(ctx, limit);
1408 		} else
1409 			error = smbfs_findnextLM2(ctx, limit);
1410 		if (error)
1411 			return error;
1412 		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
1413 			if ((ctx->f_nmlen == 2 &&
1414 			     *(u_int16_t *)ctx->f_name == htole16(0x002e)) ||
1415 			    (ctx->f_nmlen == 4 &&
1416 			     *(u_int32_t *)ctx->f_name == htole32(0x002e002e)))
1417 				continue;
1418 		} else
1419 			if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
1420 			    (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
1421 			     ctx->f_name[1] == '.'))
1422 				continue;
1423 		break;
1424 	}
1425 	smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen,
1426 			    ctx->f_dnp->n_mount->sm_caseopt);
1427 	ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
1428 	return 0;
1429 }
1430 
1431 int
1432 smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
1433 {
1434 	ctx->f_scred = scred;
1435 	if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
1436 		smbfs_findcloseLM1(ctx);
1437 	} else
1438 		smbfs_findcloseLM2(ctx);
1439 	if (ctx->f_rname)
1440 		free(ctx->f_rname, M_SMBFSDATA);
1441 	free(ctx, M_SMBFSDATA);
1442 	return 0;
1443 }
1444 
1445 int
1446 smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
1447 	struct smbfattr *fap, struct smb_cred *scred)
1448 {
1449 	struct smbfs_fctx *ctx;
1450 	int error;
1451 
1452 	if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
1453 		bzero(fap, sizeof(*fap));
1454 		fap->fa_attr = SMB_FA_DIR;
1455 		fap->fa_ino = 2;
1456 		return 0;
1457 	}
1458 	MPASS(!(nmlen == 2 && name[0] == '.' && name[1] == '.'));
1459 	MPASS(!(nmlen == 1 && name[0] == '.'));
1460 	ASSERT_VOP_ELOCKED(dnp->n_vnode, "smbfs_smb_lookup");
1461 	error = smbfs_findopen(dnp, name, nmlen,
1462 	    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
1463 	if (error)
1464 		return error;
1465 	ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
1466 	error = smbfs_findnext(ctx, 1, scred);
1467 	if (error == 0) {
1468 		*fap = ctx->f_attr;
1469 		if (name == NULL)
1470 			fap->fa_ino = dnp->n_ino;
1471 	}
1472 	smbfs_findclose(ctx, scred);
1473 	return error;
1474 }
1475