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