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