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