xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c (revision 3d393ee6c37fa10ac512ed6d36109ad616dc7c1a)
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  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: smbfs_smb.c,v 1.73.38.1 2005/05/27 02:35:28 lindak Exp $
33  */
34 
35 /*
36  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37  * Use is subject to license terms.
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/time.h>
43 #include <sys/vnode.h>
44 #include <sys/cmn_err.h>
45 
46 #ifdef APPLE
47 #include <sys/smb_apple.h>
48 #include <sys/utfconv.h>
49 #else
50 #include <netsmb/smb_osdep.h>
51 #endif
52 
53 #include <netsmb/smb.h>
54 #include <netsmb/smb_conn.h>
55 #include <netsmb/smb_subr.h>
56 #include <netsmb/smb_rq.h>
57 
58 #include <smbfs/smbfs.h>
59 #include <smbfs/smbfs_node.h>
60 #include <smbfs/smbfs_subr.h>
61 
62 /*
63  * Local functions.
64  * Not static, to aid debugging.
65  */
66 
67 int smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap,
68 	struct smb_cred *scrp, short infolevel);
69 int smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap,
70 	struct smb_cred *scrp, short infolevel);
71 int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
72 	struct smbfattr *fap, struct smb_cred *scrp);
73 
74 int smbfs_smb_statfsLM1(struct smb_share *ssp,
75 	statvfs64_t *sbp, struct smb_cred *scrp);
76 int smbfs_smb_statfsLM2(struct smb_share *ssp,
77 	statvfs64_t *sbp, struct smb_cred *scrp);
78 
79 int  smbfs_smb_setftime1(struct smbnode *np, uint16_t fid,
80 	struct timespec *mtime,	struct timespec *atime,
81 	struct smb_cred *scrp);
82 int  smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid,
83 	uint32_t attr, struct timespec *mtime,	struct timespec *atime,
84 	struct smb_cred *scrp);
85 
86 int  smbfs_smb_setpattr1(struct smbnode *np,
87 	const char *name, int len, uint32_t attr,
88 	struct timespec *mtime, struct smb_cred *scrp);
89 int  smbfs_smb_setpattr2(struct smbnode *np, uint32_t attr,
90 	struct timespec *mtime,	struct timespec *atime,
91 	struct smb_cred *scrp);
92 int  smbfs_smb_setpattrNT(struct smbnode *np, uint32_t attr,
93 	struct timespec *mtime, struct timespec *atime,
94 	struct smb_cred *scrp);
95 
96 
97 /*
98  * Todo: locking over-the-wire
99  */
100 #ifdef APPLE
101 
102 static int
103 smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid,
104 	offset_t start, uint64_t len, int largelock,
105 	struct smb_cred *scrp, uint32_t timeout)
106 {
107 	struct smb_share *ssp = np->n_mount->smi_share;
108 	struct smb_rq rq, *rqp = &rq;
109 	struct mbchain *mbp;
110 	uint8_t ltype = 0;
111 	int error;
112 
113 	/* Shared lock for n_fid use below. */
114 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
115 
116 	if (op == SMB_LOCK_SHARED)
117 		ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
118 	if (largelock)
119 		ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
120 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
121 	if (error)
122 		return (error);
123 	smb_rq_getrequest(rqp, &mbp);
124 	smb_rq_wstart(rqp);
125 	mb_put_uint8(mbp, 0xff);	/* secondary command */
126 	mb_put_uint8(mbp, 0);		/* MBZ */
127 	mb_put_uint16le(mbp, 0);
128 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
129 	mb_put_uint8(mbp, ltype);	/* locktype */
130 	mb_put_uint8(mbp, 0);		/* oplocklevel - 0 seems is NO_OPLOCK */
131 	mb_put_uint32le(mbp, timeout);	/* 0 nowait, -1 infinite wait */
132 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
133 	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
134 	smb_rq_wend(rqp);
135 	smb_rq_bstart(rqp);
136 	mb_put_uint16le(mbp, pid);
137 	if (!largelock) {
138 		mb_put_uint32le(mbp, start);
139 		mb_put_uint32le(mbp, len);
140 	} else {
141 		mb_put_uint16le(mbp, 0); /* pad */
142 		mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
143 		mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
144 		mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
145 		mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
146 	}
147 	smb_rq_bend(rqp);
148 	/*
149 	 * Don't want to risk missing a successful
150 	 * unlock send or lock response, or we could
151 	 * lose track of an outstanding lock.
152 	 */
153 	if (op == SMB_LOCK_RELEASE)
154 		rqp->sr_flags |= SMBR_NOINTR_SEND;
155 	else
156 		rqp->sr_flags |= SMBR_NOINTR_RECV;
157 
158 	error = smb_rq_simple(rqp);
159 	smb_rq_done(rqp);
160 	return (error);
161 }
162 
163 int
164 smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
165 	offset_t start, uint64_t len,	int largelock,
166 	struct smb_cred *scrp, uint32_t timeout)
167 {
168 	struct smb_share *ssp = np->n_mount->smi_share;
169 
170 	if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
171 		/*
172 		 * TODO: use LOCK_BYTE_RANGE here.
173 		 */
174 		return (EINVAL);
175 	else
176 		return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len,
177 		    largelock, scrp, timeout));
178 }
179 
180 #endif /* APPLE */
181 
182 /*
183  * Helper for smbfs_getattr
184  * Something like nfs_getattr_otw
185  */
186 int
187 smbfs_smb_getfattr(
188 	struct smbnode *np,
189 	struct smbfattr *fap,
190 	struct smb_cred *scrp)
191 {
192 	int error;
193 
194 	/*
195 	 * This lock is really only necessary for qfileinfo,
196 	 * but hopefully we use that most of the time.
197 	 * Lock may be writer (via open) or reader.
198 	 */
199 	ASSERT(np->r_lkserlock.count != 0);
200 
201 	/*
202 	 * Extended attribute directory or file.
203 	 */
204 	if (np->n_flag & N_XATTR) {
205 		error = smbfs_xa_getfattr(np, fap, scrp);
206 		return (error);
207 	}
208 
209 	if (np->n_fidrefs)
210 		error = smbfs_smb_qfileinfo(np, fap, scrp, 0);
211 	else
212 		error = smbfs_smb_qpathinfo(np, fap, scrp, 0);
213 
214 	if (error == EINVAL) {
215 		/* fallback */
216 		error = smbfs_smb_query_info(np, NULL, 0, fap, scrp);
217 	}
218 
219 	/*
220 	 * Note directory size is not provided by
221 	 * windows servers (they leave it as zero)
222 	 */
223 	if ((fap->fa_attr & SMB_FA_DIR) &&
224 	    (fap->fa_size < DEV_BSIZE))
225 		fap->fa_size = DEV_BSIZE;
226 
227 	return (error);
228 }
229 
230 
231 /*
232  * Nearly identical to smbfs_smb_qfileinfo (below).
233  * Please keep them in sync.
234  */
235 int
236 smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap,
237 		    struct smb_cred *scrp, short infolevel)
238 {
239 	struct smb_share *ssp = np->n_mount->smi_share;
240 	struct smb_vc *vcp = SSTOVC(ssp);
241 	struct smb_t2rq *t2p;
242 	int error, svtz, timesok = 1;
243 	struct mbchain *mbp;
244 	struct mdchain *mdp;
245 	uint16_t date, time, wattr;
246 	uint64_t llongint, lsize;
247 	uint32_t size, dattr;
248 
249 top:
250 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION,
251 	    scrp, &t2p);
252 	if (error)
253 		return (error);
254 	mbp = &t2p->t2_tparam;
255 	mb_init(mbp);
256 	if (!infolevel) {
257 		if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
258 			infolevel = SMB_QFILEINFO_STANDARD;
259 		else
260 			infolevel = SMB_QFILEINFO_ALL_INFO;
261 	}
262 	mb_put_uint16le(mbp, infolevel);
263 	mb_put_uint32le(mbp, 0);
264 	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
265 	error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
266 	if (error) {
267 		smb_t2_done(t2p);
268 		return (error);
269 	}
270 	t2p->t2_maxpcount = 2;
271 	t2p->t2_maxdcount = vcp->vc_txmax;
272 	error = smb_t2_request(t2p);
273 	if (error) {
274 		smb_t2_done(t2p);
275 		/* Invalid info level?  Try fallback. */
276 		if (error == EINVAL &&
277 		    infolevel == SMB_QFILEINFO_ALL_INFO) {
278 			infolevel = SMB_QFILEINFO_STANDARD;
279 			goto top;
280 		}
281 		return (error);
282 	}
283 	mdp = &t2p->t2_rdata;
284 	svtz = vcp->vc_sopt.sv_tz;
285 	switch (infolevel) {
286 	case SMB_QFILEINFO_STANDARD:
287 		timesok = 0;
288 		md_get_uint16le(mdp, NULL);
289 		md_get_uint16le(mdp, NULL);	/* creation time */
290 		md_get_uint16le(mdp, &date);
291 		md_get_uint16le(mdp, &time);	/* access time */
292 		if (date || time) {
293 			timesok++;
294 			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
295 		}
296 		md_get_uint16le(mdp, &date);
297 		md_get_uint16le(mdp, &time);	/* modify time */
298 		if (date || time) {
299 			timesok++;
300 			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
301 		}
302 		md_get_uint32le(mdp, &size);
303 		fap->fa_size = size;
304 		md_get_uint32(mdp, NULL);	/* allocation size */
305 		md_get_uint16le(mdp, &wattr);
306 		fap->fa_attr = wattr;
307 		break;
308 	case SMB_QFILEINFO_ALL_INFO:
309 		timesok = 0;
310 		/* creation time (discard) */
311 		md_get_uint64(mdp, NULL);
312 		/* last access time */
313 		md_get_uint64le(mdp, &llongint);
314 		if (llongint) {
315 			timesok++;
316 			smb_time_NT2local(llongint, svtz, &fap->fa_atime);
317 		}
318 		/* last write time */
319 		md_get_uint64le(mdp, &llongint);
320 		if (llongint) {
321 			timesok++;
322 			smb_time_NT2local(llongint, svtz, &fap->fa_mtime);
323 		}
324 		/* last change time */
325 		md_get_uint64le(mdp, &llongint);
326 		if (llongint) {
327 			timesok++;
328 			smb_time_NT2local(llongint, svtz, &fap->fa_ctime);
329 		}
330 		/* attributes */
331 		md_get_uint32le(mdp, &dattr);
332 		fap->fa_attr = dattr;
333 		/*
334 		 * 4-Byte alignment - discard
335 		 * Specs doesn't talk about this.
336 		 */
337 		md_get_uint32le(mdp, NULL);
338 		/* allocation size (discard) */
339 		md_get_uint64le(mdp, NULL);
340 		/* File size */
341 		md_get_uint64le(mdp, &lsize);
342 		fap->fa_size = lsize;
343 		break;
344 	default:
345 		SMBVDEBUG("unexpected info level %d\n", infolevel);
346 		error = EINVAL;
347 	}
348 	smb_t2_done(t2p);
349 	/*
350 	 * if all times are zero (observed with FAT on NT4SP6)
351 	 * then fall back to older info level
352 	 */
353 	if (!timesok) {
354 		if (infolevel == SMB_QFILEINFO_ALL_INFO) {
355 			infolevel = SMB_QFILEINFO_STANDARD;
356 			goto top;
357 		}
358 		error = EINVAL;
359 	}
360 	return (error);
361 }
362 
363 /*
364  * Nearly identical to smbfs_smb_qpathinfo (above).
365  * Please keep them in sync.
366  */
367 int
368 smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap,
369 		    struct smb_cred *scrp, short infolevel)
370 {
371 	struct smb_share *ssp = np->n_mount->smi_share;
372 	struct smb_vc *vcp = SSTOVC(ssp);
373 	struct smb_t2rq *t2p;
374 	int error, svtz, timesok = 1;
375 	struct mbchain *mbp;
376 	struct mdchain *mdp;
377 	uint16_t date, time, wattr;
378 	uint64_t llongint, lsize;
379 	uint32_t size, dattr;
380 
381 	/*
382 	 * Shared lock for n_fid use below.
383 	 * See smbfs_smb_getfattr()
384 	 */
385 	ASSERT(np->r_lkserlock.count != 0);
386 
387 	if (np->n_fid == SMB_FID_UNUSED)
388 		return (EBADF);
389 
390 top:
391 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FILE_INFORMATION,
392 	    scrp, &t2p);
393 	if (error)
394 		return (error);
395 	mbp = &t2p->t2_tparam;
396 	mb_init(mbp);
397 	if (!infolevel) {
398 		if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
399 			infolevel = SMB_QFILEINFO_STANDARD;
400 		else
401 			infolevel = SMB_QFILEINFO_ALL_INFO;
402 	}
403 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
404 	mb_put_uint16le(mbp, infolevel);
405 	t2p->t2_maxpcount = 2;
406 	t2p->t2_maxdcount = vcp->vc_txmax;
407 	error = smb_t2_request(t2p);
408 	if (error) {
409 		smb_t2_done(t2p);
410 		/* Invalid info level?  Try fallback. */
411 		if (error == EINVAL &&
412 		    infolevel == SMB_QFILEINFO_ALL_INFO) {
413 			infolevel = SMB_QFILEINFO_STANDARD;
414 			goto top;
415 		}
416 		return (error);
417 	}
418 	mdp = &t2p->t2_rdata;
419 	svtz = vcp->vc_sopt.sv_tz;
420 	switch (infolevel) {
421 	case SMB_QFILEINFO_STANDARD:
422 		timesok = 0;
423 		md_get_uint16le(mdp, NULL);
424 		md_get_uint16le(mdp, NULL);	/* creation time */
425 		md_get_uint16le(mdp, &date);
426 		md_get_uint16le(mdp, &time);	/* access time */
427 		if (date || time) {
428 			timesok++;
429 			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
430 		}
431 		md_get_uint16le(mdp, &date);
432 		md_get_uint16le(mdp, &time);	/* modify time */
433 		if (date || time) {
434 			timesok++;
435 			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
436 		}
437 		md_get_uint32le(mdp, &size);
438 		fap->fa_size = size;
439 		md_get_uint32(mdp, NULL);	/* allocation size */
440 		md_get_uint16le(mdp, &wattr);
441 		fap->fa_attr = wattr;
442 		break;
443 	case SMB_QFILEINFO_ALL_INFO:
444 		timesok = 0;
445 		/* creation time (discard) */
446 		md_get_uint64(mdp, NULL);
447 		/* last access time */
448 		md_get_uint64le(mdp, &llongint);
449 		if (llongint) {
450 			timesok++;
451 			smb_time_NT2local(llongint, svtz, &fap->fa_atime);
452 		}
453 		/* last write time */
454 		md_get_uint64le(mdp, &llongint);
455 		if (llongint) {
456 			timesok++;
457 			smb_time_NT2local(llongint, svtz, &fap->fa_mtime);
458 		}
459 		/* last change time */
460 		md_get_uint64le(mdp, &llongint);
461 		if (llongint) {
462 			timesok++;
463 			smb_time_NT2local(llongint, svtz, &fap->fa_ctime);
464 		}
465 		/* attributes */
466 		md_get_uint32le(mdp, &dattr);
467 		fap->fa_attr = dattr;
468 		/*
469 		 * 4-Byte alignment - discard
470 		 * Specs doesn't talk about this.
471 		 */
472 		md_get_uint32le(mdp, NULL);
473 		/* allocation size (discard) */
474 		md_get_uint64le(mdp, NULL);
475 		/* File size */
476 		md_get_uint64le(mdp, &lsize);
477 		fap->fa_size = lsize;
478 		break;
479 	default:
480 		SMBVDEBUG("unexpected info level %d\n", infolevel);
481 		error = EINVAL;
482 	}
483 	smb_t2_done(t2p);
484 	/*
485 	 * if all times are zero (observed with FAT on NT4SP6)
486 	 * then fall back to older info level
487 	 */
488 	if (!timesok) {
489 		if (infolevel == SMB_QFILEINFO_ALL_INFO) {
490 			infolevel = SMB_QFILEINFO_STANDARD;
491 			goto top;
492 		}
493 		error = EINVAL;
494 	}
495 	return (error);
496 }
497 
498 /*
499  * Support functions for _qstreaminfo
500  * See smbfs_xattr.c
501  */
502 
503 int
504 smbfs_smb_qfsattr(struct smb_share *ssp, uint32_t *attrp,
505 			struct smb_cred *scrp)
506 {
507 	struct smb_t2rq *t2p;
508 	struct mbchain *mbp;
509 	struct mdchain *mdp;
510 	uint32_t nlen;
511 	int error;
512 	char *fs_name;	/* will malloc whatever the size is */
513 	struct smbfs_fctx	ctx;
514 
515 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
516 	    scrp, &t2p);
517 	if (error)
518 		return (error);
519 	mbp = &t2p->t2_tparam;
520 	mb_init(mbp);
521 	mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO);
522 	t2p->t2_maxpcount = 4;
523 	t2p->t2_maxdcount = 4 * 3 + 512;
524 	error = smb_t2_request(t2p);
525 	if (error) {
526 		smb_t2_done(t2p);
527 		return (error);
528 	}
529 	mdp = &t2p->t2_rdata;
530 	md_get_uint32le(mdp, attrp);
531 	md_get_uint32le(mdp, &ssp->ss_maxfilenamelen);
532 	md_get_uint32le(mdp, &nlen);	/* fs name length */
533 	if (ssp->ss_fsname == NULL && nlen) {
534 		ctx.f_ssp = ssp;
535 		ctx.f_name = kmem_alloc(nlen, KM_SLEEP);
536 		ctx.f_namesz = nlen;
537 		md_get_mem(mdp, ctx.f_name, nlen, MB_MSYSTEM);
538 		ctx.f_nmlen = nlen;
539 		smbfs_fname_tolocal(&ctx);
540 		fs_name = kmem_alloc(ctx.f_nmlen+1, KM_SLEEP);
541 		bcopy(ctx.f_name, fs_name, ctx.f_nmlen);
542 		fs_name[ctx.f_nmlen] = '\0';
543 		ssp->ss_fsname = fs_name;
544 		kmem_free(ctx.f_name, ctx.f_namesz);
545 		/*
546 		 * If fs_name isn't NTFS they probably require resume keys.
547 		 * This is another example of the client trying to fix a server
548 		 * bug. This code uses the logic created by PR-3983209. See
549 		 * long block comment in smbfs_smb_findnextLM2.
550 		 */
551 		if (strcmp(fs_name, "NTFS")) {
552 			SMB_SS_LOCK(ssp);
553 			ssp->ss_flags |= SMBS_RESUMEKEYS;
554 			SMB_SS_UNLOCK(ssp);
555 		}
556 		SMBVDEBUG("(fyi) share '%s', attr 0x%x, maxfilename %d\n",
557 		    ssp->ss_fsname, *attrp, ssp->ss_maxfilenamelen);
558 	}
559 	smb_t2_done(t2p);
560 	return (0);
561 }
562 
563 int
564 smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
565 	struct smb_cred *scp)
566 {
567 	int error;
568 
569 	if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
570 		error = smbfs_smb_statfsLM2(ssp, sbp, scp);
571 	else
572 		error = smbfs_smb_statfsLM1(ssp, sbp, scp);
573 
574 	return (error);
575 }
576 
577 int
578 smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp,
579 	struct smb_cred *scrp)
580 {
581 	struct smb_t2rq *t2p;
582 	struct mbchain *mbp;
583 	struct mdchain *mdp;
584 	uint16_t bsize;
585 	uint32_t units, bpu, funits;
586 	uint64_t s, t, f;
587 	int error;
588 
589 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
590 	    scrp, &t2p);
591 	if (error)
592 		return (error);
593 	mbp = &t2p->t2_tparam;
594 	mb_init(mbp);
595 	mb_put_uint16le(mbp, SMB_QFS_ALLOCATION);
596 	t2p->t2_maxpcount = 4;
597 	t2p->t2_maxdcount = 4 * 4 + 2;
598 	error = smb_t2_request(t2p);
599 	if (error) {
600 		smb_t2_done(t2p);
601 		return (error);
602 	}
603 	mdp = &t2p->t2_rdata;
604 	md_get_uint32(mdp, NULL);	/* fs id */
605 	md_get_uint32le(mdp, &bpu);
606 	md_get_uint32le(mdp, &units);
607 	md_get_uint32le(mdp, &funits);
608 	md_get_uint16le(mdp, &bsize);
609 	s = bsize;
610 	s *= bpu;
611 	t = units;
612 	f = funits;
613 	/*
614 	 * Don't allow over-large blocksizes as they determine
615 	 * Finder List-view size granularities.  On the other
616 	 * hand, we mustn't let the block count overflow the
617 	 * 31 bits available.
618 	 */
619 	while (s > 16 * 1024) {
620 		if (t > LONG_MAX)
621 			break;
622 		s /= 2;
623 		t *= 2;
624 		f *= 2;
625 	}
626 	while (t > LONG_MAX) {
627 		t /= 2;
628 		f /= 2;
629 		s *= 2;
630 	}
631 	sbp->f_bsize  = (ulong_t)s;	/* file system block size */
632 	sbp->f_blocks = t;	/* total data blocks in file system */
633 	sbp->f_bfree  = f;	/* free blocks in fs */
634 	sbp->f_bavail = f;	/* free blocks avail to non-superuser */
635 	sbp->f_files  = (-1);	/* total file nodes in file system */
636 	sbp->f_ffree  = (-1);	/* free file nodes in fs */
637 	smb_t2_done(t2p);
638 	return (0);
639 }
640 
641 int
642 smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp,
643 	struct smb_cred *scrp)
644 {
645 	struct smb_rq rq, *rqp = &rq;
646 	struct mdchain *mdp;
647 	uint16_t units, bpu, bsize, funits;
648 	uint64_t s, t, f;
649 	int error;
650 
651 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
652 	    scrp);
653 	if (error)
654 		return (error);
655 	smb_rq_wstart(rqp);
656 	smb_rq_wend(rqp);
657 	smb_rq_bstart(rqp);
658 	smb_rq_bend(rqp);
659 	error = smb_rq_simple(rqp);
660 	if (error) {
661 		smb_rq_done(rqp);
662 		return (error);
663 	}
664 	smb_rq_getreply(rqp, &mdp);
665 	md_get_uint16le(mdp, &units);
666 	md_get_uint16le(mdp, &bpu);
667 	md_get_uint16le(mdp, &bsize);
668 	md_get_uint16le(mdp, &funits);
669 	s = bsize;
670 	s *= bpu;
671 	t = units;
672 	f = funits;
673 	/*
674 	 * Don't allow over-large blocksizes as they determine
675 	 * Finder List-view size granularities.  On the other
676 	 * hand, we mustn't let the block count overflow the
677 	 * 31 bits available.
678 	 */
679 	while (s > 16 * 1024) {
680 		if (t > LONG_MAX)
681 			break;
682 		s /= 2;
683 		t *= 2;
684 		f *= 2;
685 	}
686 	while (t > LONG_MAX) {
687 		t /= 2;
688 		f /= 2;
689 		s *= 2;
690 	}
691 	sbp->f_bsize = (ulong_t)s;	/* file system block size */
692 	sbp->f_blocks = t;	/* total data blocks in file system */
693 	sbp->f_bfree = f;	/* free blocks in fs */
694 	sbp->f_bavail = f;	/* free blocks avail to non-superuser */
695 	sbp->f_files = (-1);		/* total file nodes in file system */
696 	sbp->f_ffree = (-1);		/* free file nodes in fs */
697 	smb_rq_done(rqp);
698 	return (0);
699 }
700 
701 int
702 smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
703 			struct smb_cred *scrp)
704 {
705 	struct smb_t2rq *t2p;
706 	struct smb_vc *vcp = SSTOVC(ssp);
707 	struct mbchain *mbp;
708 	int error;
709 
710 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
711 	    scrp, &t2p);
712 	if (error)
713 		return (error);
714 	mbp = &t2p->t2_tparam;
715 	mb_init(mbp);
716 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
717 	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
718 		mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
719 	else
720 		mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO);
721 	mb_put_uint32le(mbp, 0); /* XXX should be 16 not 32(?) */
722 	mbp = &t2p->t2_tdata;
723 	mb_init(mbp);
724 	mb_put_uint64le(mbp, newsize);
725 	mb_put_uint32le(mbp, 0);			/* padding */
726 	mb_put_uint16le(mbp, 0);
727 	t2p->t2_maxpcount = 2;
728 	t2p->t2_maxdcount = 0;
729 	error = smb_t2_request(t2p);
730 	smb_t2_done(t2p);
731 	return (error);
732 }
733 
734 /*ARGSUSED*/
735 int
736 smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp,
737 	const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite)
738 {
739 	struct smb_t2rq *t2p;
740 	struct smb_share *ssp = np->n_mount->smi_share;
741 	struct smb_vc *vcp = SSTOVC(ssp);
742 	struct mbchain *mbp;
743 	int32_t *ucslenp;
744 	int error, cerror;
745 	uint16_t fid = 0;
746 
747 	/* Shared lock for n_fid use below. */
748 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
749 
750 	if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
751 		return (ENOTSUP);
752 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
753 	    scrp, &t2p);
754 	if (error)
755 		return (error);
756 	if (tdnp) {
757 		error = smbfs_smb_tmpopen(tdnp, SA_RIGHT_FILE_READ_DATA, scrp,
758 		    &fid);
759 		if (error)
760 			goto exit;
761 	}
762 	mbp = &t2p->t2_tparam;
763 	mb_init(mbp);
764 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
765 	mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
766 	mb_put_uint16le(mbp, 0); /* reserved, nowadays */
767 	mbp = &t2p->t2_tdata;
768 	mb_init(mbp);
769 	mb_put_uint32le(mbp, overwrite);
770 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); /* base for tname */
771 	mb_put_uint16le(mbp, 0); /* part of a 32bit fid? */
772 	ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
773 	mbp->mb_count = 0;
774 	error = smb_put_dstring(mbp, vcp, tname, SMB_CS_NONE);
775 	if (error)
776 		goto exit;
777 	mbp->mb_count--;	/* don't count the null */
778 	*ucslenp = htolel(mbp->mb_count);
779 	t2p->t2_maxpcount = 2;
780 	t2p->t2_maxdcount = 0;
781 	error = smb_t2_request(t2p);
782 exit:
783 	if (fid) {
784 		cerror = smbfs_smb_tmpclose(tdnp, fid, scrp);
785 		if (cerror)
786 			SMBERROR("error %d closing fid %d\n", cerror, fid);
787 	}
788 	smb_t2_done(t2p);
789 	return (error);
790 }
791 
792 int
793 smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
794 {
795 	struct smb_share *ssp = np->n_mount->smi_share;
796 	struct smb_rq rq, *rqp = &rq;
797 	struct mbchain *mbp;
798 	int error;
799 
800 	/* Shared lock for n_fid use below. */
801 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
802 
803 	if (!(np->n_flag & NFLUSHWIRE))
804 		return (0);
805 	if (np->n_fidrefs == 0)
806 		return (0); /* not open */
807 
808 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
809 	if (error)
810 		return (error);
811 	smb_rq_getrequest(rqp, &mbp);
812 	smb_rq_wstart(rqp);
813 	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
814 	smb_rq_wend(rqp);
815 	smb_rq_bstart(rqp);
816 	smb_rq_bend(rqp);
817 	error = smb_rq_simple(rqp);
818 	smb_rq_done(rqp);
819 	if (!error) {
820 		mutex_enter(&np->r_statelock);
821 		np->n_flag &= ~NFLUSHWIRE;
822 		mutex_exit(&np->r_statelock);
823 	}
824 	return (error);
825 }
826 
827 int
828 smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
829 			struct smb_cred *scrp)
830 {
831 	struct smb_share *ssp = np->n_mount->smi_share;
832 	struct smb_rq rq, *rqp = &rq;
833 	struct mbchain *mbp;
834 	int error;
835 
836 	/*
837 	 * This call knows about 64-bit offsets.
838 	 */
839 	error = smbfs_smb_seteof(ssp, fid, newsize, scrp);
840 	if (!error) {
841 		mutex_enter(&np->r_statelock);
842 		np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
843 		mutex_exit(&np->r_statelock);
844 		return (0);
845 	}
846 
847 	/*
848 	 * If we have SMB_CAP_LARGE_FILES, the above
849 	 * should have worked.  XXX: Don't fallback?
850 	 * XXX: Or fallback on specific errors?
851 	 */
852 	if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) {
853 		SMBVDEBUG("Have CAP_LARGE but _seteof error=%d\n", error);
854 	}
855 
856 	/*
857 	 * OK, so fallback to SMB_COM_WRITE, but note:
858 	 * it only supports 32-bit file offsets.
859 	 */
860 	if (newsize > UINT32_MAX)
861 		return (EFBIG);
862 
863 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp);
864 	if (error)
865 		return (error);
866 	smb_rq_getrequest(rqp, &mbp);
867 	smb_rq_wstart(rqp);
868 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
869 	mb_put_uint16le(mbp, 0);
870 	mb_put_uint32le(mbp, newsize);
871 	mb_put_uint16le(mbp, 0);
872 	smb_rq_wend(rqp);
873 	smb_rq_bstart(rqp);
874 	mb_put_uint8(mbp, SMB_DT_DATA);
875 	mb_put_uint16le(mbp, 0);
876 	smb_rq_bend(rqp);
877 	error = smb_rq_simple(rqp);
878 	smb_rq_done(rqp);
879 	mutex_enter(&np->r_statelock);
880 	np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
881 	mutex_exit(&np->r_statelock);
882 	return (error);
883 }
884 
885 int
886 smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
887 	struct smbfattr *fap, struct smb_cred *scrp)
888 {
889 	struct smb_rq rq, *rqp = &rq;
890 	struct smb_share *ssp = np->n_mount->smi_share;
891 	struct mbchain *mbp;
892 	struct mdchain *mdp;
893 	uint8_t wc;
894 	int error;
895 	uint16_t wattr;
896 	uint32_t longint;
897 
898 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp);
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 	do {
907 		error = smbfs_fullpath(mbp, SSTOVC(ssp), np,
908 		    name, &nmlen, '\\');
909 		if (error)
910 			break;
911 		smb_rq_bend(rqp);
912 		error = smb_rq_simple(rqp);
913 		if (error)
914 			break;
915 		smb_rq_getreply(rqp, &mdp);
916 		if (md_get_uint8(mdp, &wc) != 0 || wc != 10) {
917 			error = EBADRPC;
918 			break;
919 		}
920 		md_get_uint16le(mdp, &wattr);
921 		fap->fa_attr = wattr;
922 		/*
923 		 * Be careful using the time returned here, as
924 		 * with FAT on NT4SP6, at least, the time returned is low
925 		 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
926 		 * over about every seven minutes!
927 		 */
928 		md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
929 		if (longint)	/* avoid bogus zero returns */
930 			smb_time_server2local(longint,
931 			    SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime);
932 		md_get_uint32le(mdp, &longint);
933 		fap->fa_size = longint;
934 		/*LINTED*/
935 	} while (0);
936 	smb_rq_done(rqp);
937 	return (error);
938 }
939 
940 int
941 smbfs_smb_setpattr(struct smbnode *np, uint32_t attr,
942 	struct timespec *mtime,	struct timespec *atime,
943 	struct smb_cred *scrp)
944 {
945 	struct smb_share *ssp = np->n_mount->smi_share;
946 	struct smb_vc *vcp = SSTOVC(ssp);
947 	int error;
948 
949 	/*
950 	 * This is the logic that was in smbfs_vnops.c
951 	 */
952 	if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) &&
953 	    (vcp->vc_flags & SMBV_NT4) == 0) {
954 		/*
955 		 * NT4 doesn't understand "NT" style SMBs;
956 		 * for NT4 we use the old SET_PATH_INFO
957 		 * XXX Actually, I think the issue is that
958 		 * NT requires an open handle for this.
959 		 */
960 		error = smbfs_smb_setpattrNT(np,
961 		    attr, mtime, atime, scrp);
962 		if (error != EBADRPC)
963 			return (error);
964 
965 		/* NT4 response, remember */
966 		SMB_VC_LOCK(vcp);
967 		vcp->vc_flags |= SMBV_NT4;
968 		SMB_VC_UNLOCK(vcp);
969 	}
970 
971 	if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) {
972 		error = smbfs_smb_setpattr2(np,
973 		    attr, mtime, atime, scrp);
974 	} else {
975 		error = smbfs_smb_setpattr1(np, NULL, 0,
976 		    attr, mtime, scrp);
977 	}
978 
979 	return (error);
980 }
981 
982 /*
983  * Set DOS file attributes. mtime should be NULL for dialects above lm10
984  */
985 int
986 smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len,
987 	uint32_t attr, struct timespec *mtime,
988 	struct smb_cred *scrp)
989 {
990 	struct smb_rq rq, *rqp = &rq;
991 	struct smb_share *ssp = np->n_mount->smi_share;
992 	struct mbchain *mbp;
993 	long time;
994 	int error, svtz;
995 
996 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp);
997 	if (error)
998 		return (error);
999 	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
1000 	smb_rq_getrequest(rqp, &mbp);
1001 	smb_rq_wstart(rqp);
1002 	mb_put_uint16le(mbp, (uint16_t)attr);
1003 	if (mtime) {
1004 		smb_time_local2server(mtime, svtz, &time);
1005 	} else
1006 		time = 0;
1007 	mb_put_uint32le(mbp, time);		/* mtime */
1008 	mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
1009 	smb_rq_wend(rqp);
1010 	smb_rq_bstart(rqp);
1011 	mb_put_uint8(mbp, SMB_DT_ASCII);
1012 	do {
1013 		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &len, '\\');
1014 		if (error)
1015 			break;
1016 		mb_put_uint8(mbp, SMB_DT_ASCII);
1017 		if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
1018 			mb_put_padbyte(mbp);
1019 			mb_put_uint8(mbp, 0);	/* 1st byte NULL Unicode char */
1020 		}
1021 		mb_put_uint8(mbp, 0);
1022 		smb_rq_bend(rqp);
1023 		error = smb_rq_simple(rqp);
1024 		if (error)
1025 			break;
1026 		/*LINTED*/
1027 	} while (0);
1028 	smb_rq_done(rqp);
1029 	return (error);
1030 }
1031 
1032 int
1033 smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
1034 			struct smb_cred *scrp)
1035 {
1036 	struct smbfattr fa;
1037 	int error;
1038 	uint32_t attr;
1039 
1040 	error = smbfs_smb_query_info(np, name, len, &fa, scrp);
1041 	attr = fa.fa_attr;
1042 	if (!error && !(attr & SMB_FA_HIDDEN)) {
1043 		attr |= SMB_FA_HIDDEN;
1044 		error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
1045 	}
1046 	return (error);
1047 }
1048 
1049 
1050 int
1051 smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
1052 			struct smb_cred *scrp)
1053 {
1054 	struct smbfattr fa;
1055 	uint32_t attr;
1056 	int error;
1057 
1058 	error = smbfs_smb_query_info(np, name, len, &fa, scrp);
1059 	attr = fa.fa_attr;
1060 	if (!error && (attr & SMB_FA_HIDDEN)) {
1061 		attr &= ~SMB_FA_HIDDEN;
1062 		error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
1063 	}
1064 	return (error);
1065 }
1066 
1067 /*
1068  * Note, win95 doesn't support this call.
1069  */
1070 int
1071 smbfs_smb_setpattr2(struct smbnode *np, uint32_t attr,
1072 	struct timespec *mtime,	struct timespec *atime,
1073 	struct smb_cred *scrp)
1074 {
1075 	struct smb_t2rq *t2p;
1076 	struct smb_share *ssp = np->n_mount->smi_share;
1077 	struct smb_vc *vcp = SSTOVC(ssp);
1078 	struct mbchain *mbp;
1079 	uint16_t date, time;
1080 	int error, tzoff;
1081 
1082 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
1083 	    scrp, &t2p);
1084 	if (error)
1085 		return (error);
1086 	mbp = &t2p->t2_tparam;
1087 	mb_init(mbp);
1088 	mb_put_uint16le(mbp, SMB_SFILEINFO_STANDARD);
1089 	mb_put_uint32le(mbp, 0);		/* MBZ */
1090 	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
1091 	error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
1092 	if (error) {
1093 		smb_t2_done(t2p);
1094 		return (error);
1095 	}
1096 	tzoff = vcp->vc_sopt.sv_tz;
1097 	mbp = &t2p->t2_tdata;
1098 	mb_init(mbp);
1099 	mb_put_uint32le(mbp, 0);		/* creation time */
1100 	if (atime)
1101 		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
1102 	else
1103 		time = date = 0;
1104 	mb_put_uint16le(mbp, date);
1105 	mb_put_uint16le(mbp, time);
1106 	if (mtime)
1107 		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
1108 	else
1109 		time = date = 0;
1110 	mb_put_uint16le(mbp, date);
1111 	mb_put_uint16le(mbp, time);
1112 	mb_put_uint32le(mbp, 0);		/* file size */
1113 	mb_put_uint32le(mbp, 0);		/* allocation unit size */
1114 	mb_put_uint16le(mbp, attr);	/* DOS attr */
1115 	mb_put_uint32le(mbp, 0);		/* EA size */
1116 	t2p->t2_maxpcount = 5 * 2;
1117 	t2p->t2_maxdcount = vcp->vc_txmax;
1118 	error = smb_t2_request(t2p);
1119 	smb_t2_done(t2p);
1120 	return (error);
1121 }
1122 
1123 /*
1124  * *BASIC_INFO works with Samba, but Win2K servers say it is an
1125  * invalid information level on a SET_PATH_INFO.  Note Win2K does
1126  * support *BASIC_INFO on a SET_FILE_INFO, and they support the
1127  * equivalent *BASIC_INFORMATION on SET_PATH_INFO.  Go figure.
1128  */
1129 int
1130 smbfs_smb_setpattrNT(struct smbnode *np, uint32_t attr,
1131 	struct timespec *mtime, struct timespec *atime,
1132 	struct smb_cred *scrp)
1133 {
1134 	struct smb_t2rq *t2p;
1135 	struct smb_share *ssp = np->n_mount->smi_share;
1136 	struct smb_vc *vcp = SSTOVC(ssp);
1137 	struct mbchain *mbp;
1138 	uint64_t tm;
1139 	int error, tzoff;
1140 	/* 64 bit value for Jan 1 1980 */
1141 	PRIVSYM uint64_t DIFF1980TO1601 = 11960035200ULL*10000000ULL;
1142 
1143 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
1144 	    scrp, &t2p);
1145 	if (error)
1146 		return (error);
1147 	mbp = &t2p->t2_tparam;
1148 	mb_init(mbp);
1149 	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
1150 		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION);
1151 	else
1152 		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO);
1153 	mb_put_uint32le(mbp, 0);		/* MBZ */
1154 	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
1155 	error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
1156 	if (error) {
1157 		smb_t2_done(t2p);
1158 		return (error);
1159 	}
1160 	tzoff = vcp->vc_sopt.sv_tz;
1161 
1162 	/* do we know it won't support dates < 1980? */
1163 	if (!(ssp->ss_flags & SMBS_1980)) {
1164 		mbp = &t2p->t2_tdata;
1165 		mb_init(mbp);
1166 		mb_put_uint64le(mbp, 0);		/* creation time */
1167 		if (atime) {
1168 			smb_time_local2NT(atime, tzoff, &tm);
1169 		} else
1170 			tm = 0;
1171 		mb_put_uint64le(mbp, tm);		/* access time */
1172 		if (mtime) {
1173 			smb_time_local2NT(mtime, tzoff, &tm);
1174 		} else
1175 			tm = 0;
1176 		mb_put_uint64le(mbp, tm);		/* last write time */
1177 		mb_put_uint64le(mbp, tm);		/* change time */
1178 		mb_put_uint32le(mbp, attr);		/* attr */
1179 		mb_put_uint32le(mbp, 0);	/* undocumented padding */
1180 		t2p->t2_maxpcount = 24;
1181 		t2p->t2_maxdcount = 56;
1182 		error = smb_t2_request(t2p);
1183 	}
1184 	/*
1185 	 * "invalid argument" error probably means it's a
1186 	 * FAT drive that doesn't accept dates earlier
1187 	 * than 1980, so adjust dates and retry. If the
1188 	 * 1980 flag is on we fell thru the if {} above
1189 	 */
1190 	if ((ssp->ss_flags & SMBS_1980) || (error == EINVAL)) {
1191 		mbp = &t2p->t2_tdata;
1192 		mb_init(mbp);
1193 		mb_put_uint64le(mbp, 0);		/* creation time */
1194 		if (atime) {
1195 			smb_time_local2NT(atime, tzoff, &tm);
1196 			if (tm < DIFF1980TO1601)
1197 				tm = DIFF1980TO1601;
1198 		} else
1199 			tm = 0;
1200 		mb_put_uint64le(mbp, tm);		/* access time */
1201 		if (mtime) {
1202 			smb_time_local2NT(mtime, tzoff, &tm);
1203 			if (tm < DIFF1980TO1601)
1204 				tm = DIFF1980TO1601;
1205 		} else
1206 			tm = 0;
1207 		mb_put_uint64le(mbp, tm);		/* last write time */
1208 		mb_put_uint64le(mbp, tm);		/* change time */
1209 		mb_put_uint32le(mbp, attr);		/* attr */
1210 		mb_put_uint32le(mbp, 0);	/* undocumented padding */
1211 		t2p->t2_maxpcount = 24;
1212 		t2p->t2_maxdcount = 56;
1213 		error = smb_t2_request(t2p);
1214 
1215 		/* if this worked set flag to do the right thing next time */
1216 		if (!(error)) {
1217 			SMB_SS_LOCK(ssp);
1218 			ssp->ss_flags |= SMBS_1980;
1219 			SMB_SS_UNLOCK(ssp);
1220 		}
1221 	}
1222 	smb_t2_done(t2p);
1223 	return (error);
1224 }
1225 
1226 int
1227 smbfs_smb_setfattr(struct smbnode *np, uint16_t fid,
1228 	uint32_t attr, struct timespec *mtime,
1229 	struct timespec *atime, struct smb_cred *scrp)
1230 {
1231 	struct smb_share *ssp = np->n_mount->smi_share;
1232 	struct smb_vc *vcp = SSTOVC(ssp);
1233 	int error;
1234 
1235 	/*
1236 	 * This is the logic that was in smbfs_vnops.c
1237 	 * Might not be quite right for older dialects.
1238 	 * (XXX: What about the DOS attributes?)
1239 	 */
1240 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)
1241 		error = smbfs_smb_setfattrNT(np, fid,
1242 		    np->n_dosattr, mtime, atime, scrp);
1243 	else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0)
1244 		error = smbfs_smb_setftime1(np, fid,
1245 		    mtime, atime, scrp);
1246 	else
1247 		error = smbfs_smb_setpattr1(np, NULL, 0,
1248 		    attr, mtime, scrp);
1249 
1250 	return (error);
1251 }
1252 
1253 /*
1254  * Set file atime and mtime. Isn't supported by core dialect.
1255  */
1256 int
1257 smbfs_smb_setftime1(
1258 	struct smbnode *np,
1259 	uint16_t fid,
1260 	struct timespec *mtime,
1261 	struct timespec *atime,
1262 	struct smb_cred *scrp)
1263 {
1264 	struct smb_rq rq, *rqp = &rq;
1265 	struct smb_share *ssp = np->n_mount->smi_share;
1266 	struct mbchain *mbp;
1267 	uint16_t date, time;
1268 	int error, tzoff;
1269 
1270 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp);
1271 	if (error)
1272 		return (error);
1273 	tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
1274 	smb_rq_getrequest(rqp, &mbp);
1275 	smb_rq_wstart(rqp);
1276 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
1277 	mb_put_uint32le(mbp, 0);		/* creation time */
1278 
1279 	if (atime)
1280 		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
1281 	else
1282 		time = date = 0;
1283 	mb_put_uint16le(mbp, date);
1284 	mb_put_uint16le(mbp, time);
1285 	if (mtime)
1286 		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
1287 	else
1288 		time = date = 0;
1289 	mb_put_uint16le(mbp, date);
1290 	mb_put_uint16le(mbp, time);
1291 	smb_rq_wend(rqp);
1292 	smb_rq_bstart(rqp);
1293 	smb_rq_bend(rqp);
1294 	error = smb_rq_simple(rqp);
1295 	SMBVDEBUG("%d\n", error);
1296 	smb_rq_done(rqp);
1297 	return (error);
1298 }
1299 
1300 /*
1301  * Set DOS file attributes.
1302  * Looks like this call can be used only if CAP_NT_SMBS bit is on.
1303  */
1304 int
1305 smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid,
1306 	uint32_t attr, struct timespec *mtime,
1307 	struct timespec *atime, struct smb_cred *scrp)
1308 {
1309 	struct smb_t2rq *t2p;
1310 	struct smb_share *ssp = np->n_mount->smi_share;
1311 	struct smb_vc *vcp = SSTOVC(ssp);
1312 	struct mbchain *mbp;
1313 	uint64_t tm;
1314 	int error, svtz;
1315 
1316 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
1317 	    scrp, &t2p);
1318 	if (error)
1319 		return (error);
1320 	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
1321 	mbp = &t2p->t2_tparam;
1322 	mb_init(mbp);
1323 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
1324 	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
1325 		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION);
1326 	else
1327 		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO);
1328 	mb_put_uint32le(mbp, 0); /* XXX should be 16 not 32(?) */
1329 	mbp = &t2p->t2_tdata;
1330 	mb_init(mbp);
1331 	mb_put_uint64le(mbp, 0);		/* creation time */
1332 	if (atime) {
1333 		smb_time_local2NT(atime, svtz, &tm);
1334 	} else
1335 		tm = 0;
1336 	mb_put_uint64le(mbp, tm);		/* access time */
1337 	if (mtime) {
1338 		smb_time_local2NT(mtime, svtz, &tm);
1339 	} else
1340 		tm = 0;
1341 	mb_put_uint64le(mbp, tm);		/* last write time */
1342 	mb_put_uint64le(mbp, tm);		/* change time */
1343 	mb_put_uint32le(mbp, attr);
1344 	mb_put_uint32le(mbp, 0);			/* padding */
1345 	t2p->t2_maxpcount = 2;
1346 	t2p->t2_maxdcount = 0;
1347 	error = smb_t2_request(t2p);
1348 	smb_t2_done(t2p);
1349 	return (error);
1350 }
1351 
1352 /*
1353  * Modern create/open of file or directory.
1354  *
1355  * If disp is ..._DISP_OPEN, or ...DISP_OPEN_IF, or...
1356  * then this is an open attempt, and:
1357  *   If xattr then name is the stream to be opened at np,
1358  *   Else np should be opened.
1359  *   ...we won't touch *fidp,
1360  *   ...we will set or clear *attrcacheupdated.
1361  * Else this is a creation attempt, and:
1362  *   If xattr then name is the stream to create at np,
1363  *   Else name is the thing to create under directory np.
1364  *   ...we will return *fidp,
1365  *   ...we won't touch *attrcacheupdated.
1366  *
1367  * Note, We use: disp = ...OPEN_IF, ...OVERWRITE_IF, etc.
1368  * now too, which may or may not create a new object.
1369  */
1370 int
1371 smbfs_smb_ntcreatex(struct smbnode *np, uint32_t rights,
1372 		    struct smb_cred *scrp, enum vtype vt,
1373 		    int *attrcacheupdated, uint16_t *fidp,
1374 		    const char *name, int nmlen, uint32_t disp, int xattr,
1375 		    len_t *sizep, uint32_t *rightsp)
1376 {
1377 	struct smb_rq rq, *rqp = &rq;
1378 	struct smb_share *ssp = np->n_mount->smi_share;
1379 	struct smb_vc *vcp = SSTOVC(ssp);
1380 	struct mbchain *mbp;
1381 	struct mdchain *mdp;
1382 	struct smbfattr fap;
1383 	uint8_t wc;
1384 	uint32_t longint, createact, createopt, efa;
1385 	uint64_t llongint;
1386 	int error;
1387 	uint16_t fid, *namelenp;
1388 
1389 	/*
1390 	 * Set the File attributes and Create options.
1391 	 * WinXP uses EFA_NORMAL in all of these cases.
1392 	 */
1393 	createopt = (vt == VDIR) ?
1394 	    NTCREATEX_OPTIONS_DIRECTORY :
1395 	    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
1396 	efa = SMB_EFA_NORMAL;
1397 	if (disp != NTCREATEX_DISP_OPEN && !xattr) {
1398 		if (name && *name == '.')
1399 			efa = SMB_EFA_HIDDEN;
1400 	}
1401 
1402 	gethrestime(&fap.fa_reqtime);
1403 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp);
1404 	if (error)
1405 		return (error);
1406 	smb_rq_getrequest(rqp, &mbp);
1407 	smb_rq_wstart(rqp);
1408 	mb_put_uint8(mbp, 0xff);	/* secondary command */
1409 	mb_put_uint8(mbp, 0);		/* MBZ */
1410 	mb_put_uint16le(mbp, 0);	/* offset to next command (none) */
1411 	mb_put_uint8(mbp, 0);		/* MBZ */
1412 	namelenp = (uint16_t *)mb_reserve(mbp, sizeof (uint16_t));
1413 	/*
1414 	 * XP to a W2K Server does not use NTCREATEX_FLAGS_OPEN_DIRECTORY
1415 	 * for creating nor for opening a directory.  Samba ignores the bit.
1416 	 */
1417 #if 0 /* causes sharing violation when making dir on W2K! */
1418 	mb_put_uint32le(mbp, vt == VDIR ?  NTCREATEX_FLAGS_OPEN_DIRECTORY : 0);
1419 #else
1420 	mb_put_uint32le(mbp, 0);	/* NTCREATEX_FLAGS_* */
1421 #endif
1422 	mb_put_uint32le(mbp, 0);	/* FID - basis for path if not root */
1423 	mb_put_uint32le(mbp, rights);
1424 	mb_put_uint64le(mbp, 0);	/* "initial allocation size" */
1425 	mb_put_uint32le(mbp, efa);
1426 	mb_put_uint32le(mbp, NTCREATEX_SHARE_ACCESS_ALL);
1427 	mb_put_uint32le(mbp, disp);
1428 	mb_put_uint32le(mbp, createopt);
1429 	mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */
1430 	mb_put_uint8(mbp, 0);   /* security flags (?) */
1431 	smb_rq_wend(rqp);
1432 	smb_rq_bstart(rqp);
1433 	do {
1434 		if (name == NULL)
1435 			nmlen = 0;
1436 		error = smbfs_fullpath(mbp, vcp, np, name, &nmlen,
1437 		    xattr ? ':' : '\\');
1438 		if (error)
1439 			break;
1440 		*namelenp = htoles(nmlen); /* includes null */
1441 		smb_rq_bend(rqp);
1442 		/*
1443 		 * Don't want to risk missing a successful
1444 		 * open response, or we could "leak" FIDs.
1445 		 */
1446 		rqp->sr_flags |= SMBR_NOINTR_RECV;
1447 		error = smb_rq_simple_timed(rqp, smb_timo_open);
1448 		if (error)
1449 			break;
1450 		smb_rq_getreply(rqp, &mdp);
1451 		/*
1452 		 * spec says 26 for word count, but 34 words are defined
1453 		 * and observed from win2000
1454 		 */
1455 		if (md_get_uint8(mdp, &wc) != 0 ||
1456 		    (wc != 26 && wc != 34 && wc != 42)) {
1457 			error = EBADRPC;
1458 			break;
1459 		}
1460 		md_get_uint8(mdp, NULL);	/* secondary cmd */
1461 		md_get_uint8(mdp, NULL);	/* mbz */
1462 		md_get_uint16le(mdp, NULL);	/* andxoffset */
1463 		md_get_uint8(mdp, NULL);	/* oplock lvl granted */
1464 		md_get_uint16(mdp, &fid);	/* yes, leaving it LE */
1465 		md_get_uint32le(mdp, &createact);	/* create_action */
1466 		md_get_uint64le(mdp, &llongint);	/* creation time */
1467 		md_get_uint64le(mdp, &llongint);	/* access time */
1468 		if (llongint)	/* avoid bogus 0 time (on FAT roots) */
1469 			smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz,
1470 			    &fap.fa_atime);
1471 		md_get_uint64le(mdp, &llongint);	/* write time */
1472 		if (llongint)	/* avoid bogus 0 time (on FAT roots) */
1473 			smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz,
1474 			    &fap.fa_mtime);
1475 		md_get_uint64le(mdp, &llongint);	/* change time */
1476 		if (llongint)	/* avoid bogus 0 time (on FAT roots) */
1477 			smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz,
1478 			    &fap.fa_ctime);
1479 		md_get_uint32le(mdp, &longint);	/* attributes */
1480 		fap.fa_attr = longint;
1481 		md_get_uint64le(mdp, NULL);	/* allocation size */
1482 		md_get_uint64le(mdp, &llongint);   /* EOF */
1483 		fap.fa_size = llongint;
1484 		if (sizep)
1485 			*sizep = fap.fa_size;
1486 		md_get_uint16le(mdp, NULL);	/* file type */
1487 		md_get_uint16le(mdp, NULL);	/* device state */
1488 		md_get_uint8(mdp, NULL);	/* directory (boolean) */
1489 		/*LINTED*/
1490 	} while (0);
1491 	smb_rq_done(rqp);
1492 	if (error)
1493 		return (error);
1494 	if (fidp)
1495 		*fidp = fid;
1496 	if (rightsp)
1497 		*rightsp = rights;
1498 	/*
1499 	 * Is it possible that we have cached attributes?
1500 	 * Assume "not cached" if we created the object.
1501 	 */
1502 	if (createact == NTCREATEX_ACTION_CREATED || xattr)
1503 		goto uncached;
1504 	if (attrcacheupdated)
1505 		*attrcacheupdated = 0;
1506 	/*
1507 	 * Update the cached attributes if they are still valid
1508 	 * in the cache and if nothing has changed.
1509 	 */
1510 	if (np->r_vnode == NULL)
1511 		goto uncached;
1512 	if (smbfs_attr_cachelookup(np->r_vnode, NULL) != 0)
1513 		goto uncached;  /* the cached attributes are not valid */
1514 	if (fap.fa_size != np->n_size)
1515 		goto uncached;  /* the size is different */
1516 	if (fap.fa_attr != np->n_dosattr)
1517 		goto uncached;  /* the attrs are different */
1518 	/*
1519 	 * fap.fa_mtime is in two second increments while np->n_mtime
1520 	 * may be in one second increments, so comparing the times is
1521 	 * somewhat sloppy.
1522 	 *
1523 	 * XXX: true fap.fa_mtime resolution must depend upon server's
1524 	 * local filesystem and is thus indeterminate... XXX ...TBD how that
1525 	 * affects this code... note wire resolution here is 100ns versus
1526 	 * 1sec down in smbfs_smb_oldopen(SMB_COM_OPEN)
1527 	 */
1528 	if (fap.fa_mtime.tv_sec != np->n_mtime.tv_sec &&
1529 	    fap.fa_mtime.tv_sec != np->n_mtime.tv_sec - 1 &&
1530 	    fap.fa_mtime.tv_sec != np->n_mtime.tv_sec + 1)
1531 		goto uncached;  /* the mod time is different */
1532 
1533 	fap.fa_mtime.tv_sec = np->n_mtime.tv_sec; /* keep higher res time */
1534 	smbfs_attr_cacheenter(np->r_vnode, &fap);
1535 	if (attrcacheupdated)
1536 		*attrcacheupdated = 1;
1537 uncached:
1538 	return (0);
1539 }
1540 
1541 static uint32_t
1542 smb_mode2rights(int mode)
1543 {
1544 	mode = mode & SMB_AM_OPENMODE;
1545 
1546 	switch (mode) {
1547 	case SMB_AM_OPENREAD:
1548 		return (GENERIC_RIGHT_READ_ACCESS);
1549 	case SMB_AM_OPENWRITE:
1550 		return (GENERIC_RIGHT_WRITE_ACCESS);
1551 	case SMB_AM_OPENRW:
1552 		return (GENERIC_RIGHT_ALL_ACCESS);
1553 	case SMB_AM_OPENEXEC:
1554 		return (GENERIC_RIGHT_EXECUTE_ACCESS);
1555 	}
1556 	return (0);
1557 }
1558 
1559 static int
1560 smb_rights2mode(uint32_t rights)
1561 {
1562 	int accmode = SMB_AM_OPENEXEC; /* our fallback */
1563 
1564 	if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD |
1565 	    SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES |
1566 	    SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS |
1567 	    STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS |
1568 	    GENERIC_RIGHT_ALL_ACCESS | GENERIC_RIGHT_WRITE_ACCESS))
1569 		accmode = SMB_AM_OPENWRITE;
1570 	if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES |
1571 	    SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS |
1572 	    GENERIC_RIGHT_ALL_ACCESS | GENERIC_RIGHT_READ_ACCESS))
1573 		accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD
1574 		    : SMB_AM_OPENRW;
1575 	return (accmode);
1576 }
1577 
1578 static int
1579 smbfs_smb_oldopen(struct smbnode *np, int accmode, struct smb_cred *scrp,
1580 		int *attrcacheupdated, uint16_t *fidp, const char *name,
1581 		int nmlen, int xattr, len_t *sizep, uint32_t *rightsp)
1582 {
1583 	struct smb_rq rq, *rqp = &rq;
1584 	struct smb_share *ssp = np->n_mount->smi_share;
1585 	struct smb_vc *vcp = SSTOVC(ssp);
1586 	struct mbchain *mbp;
1587 	struct mdchain *mdp;
1588 	struct smbfattr fap;
1589 	uint8_t wc;
1590 	uint16_t fid, wattr, grantedmode;
1591 	uint32_t longint;
1592 	int error;
1593 
1594 	/*
1595 	 * Use DENYNONE to give unixy semantics of permitting
1596 	 * everything not forbidden by permissions.  Ie denial
1597 	 * is up to server with clients/openers needing to use
1598 	 * advisory locks for further control.
1599 	 */
1600 	accmode |= SMB_SM_DENYNONE;
1601 
1602 	gethrestime(&fap.fa_reqtime);
1603 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp);
1604 	if (error)
1605 		return (error);
1606 	smb_rq_getrequest(rqp, &mbp);
1607 	smb_rq_wstart(rqp);
1608 	mb_put_uint16le(mbp, accmode);
1609 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY |
1610 	    SMB_FA_DIR);
1611 	smb_rq_wend(rqp);
1612 	smb_rq_bstart(rqp);
1613 	mb_put_uint8(mbp, SMB_DT_ASCII);
1614 	do {
1615 		error = smbfs_fullpath(mbp, vcp, np, name, &nmlen,
1616 		    xattr ? ':' : '\\');
1617 		if (error)
1618 			break;
1619 		smb_rq_bend(rqp);
1620 		/*
1621 		 * Don't want to risk missing a successful
1622 		 * open response, or we could "leak" FIDs.
1623 		 */
1624 		rqp->sr_flags |= SMBR_NOINTR_RECV;
1625 		error = smb_rq_simple_timed(rqp, smb_timo_open);
1626 		if (error)
1627 			break;
1628 		smb_rq_getreply(rqp, &mdp);
1629 		/*
1630 		 * 8/2002 a DAVE server returned wc of 15 so we ignore that.
1631 		 * (the actual packet length and data was correct)
1632 		 */
1633 		if (md_get_uint8(mdp, &wc) != 0 || (wc != 7 && wc != 15)) {
1634 			error = EBADRPC;
1635 			break;
1636 		}
1637 		md_get_uint16(mdp, &fid); /* yes, we leave it LE */
1638 		md_get_uint16le(mdp, &wattr);
1639 		fap.fa_attr = wattr;
1640 		/*
1641 		 * Be careful using the time returned here, as
1642 		 * with FAT on NT4SP6, at least, the time returned is low
1643 		 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
1644 		 * over about every seven minutes!
1645 		 */
1646 		md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
1647 		if (longint)	/* avoid bogus zero returns */
1648 			smb_time_server2local(longint, vcp->vc_sopt.sv_tz,
1649 			    &fap.fa_mtime);
1650 		md_get_uint32le(mdp, &longint);
1651 		fap.fa_size = longint;
1652 		if (sizep)
1653 			*sizep = fap.fa_size;
1654 		md_get_uint16le(mdp, &grantedmode);
1655 		/*LINTED*/
1656 	} while (0);
1657 	smb_rq_done(rqp);
1658 	if (error)
1659 		return (error);
1660 	if (fidp)
1661 		*fidp = fid;
1662 	if (xattr)
1663 		goto uncached;
1664 	if (rightsp)
1665 		*rightsp = smb_mode2rights(grantedmode);
1666 	if (attrcacheupdated)
1667 		*attrcacheupdated = 0;
1668 	/*
1669 	 * Update the cached attributes if they are still valid
1670 	 * in the cache and if nothing has changed.
1671 	 * Note that this won't ever update if the file size is
1672 	 * greater than the 32-bits returned by SMB_COM_OPEN.
1673 	 * For 64-bit file sizes, SMB_COM_NT_CREATE_ANDX must
1674 	 * be used instead of SMB_COM_OPEN.
1675 	 */
1676 	if (np->r_vnode == NULL)
1677 		goto uncached;
1678 	if (smbfs_attr_cachelookup(np->r_vnode, NULL) != 0)
1679 		goto uncached;	/* the cached attributes are not valid */
1680 	if (fap.fa_size != np->n_size)
1681 		goto uncached;	/* the size is different */
1682 	if (fap.fa_attr != np->n_dosattr)
1683 		goto uncached;	/* the attrs are different */
1684 	/*
1685 	 * fap.fa_mtime is in two second increments while np->n_mtime
1686 	 * may be in one second increments, so comparing the times is
1687 	 * somewhat sloppy.
1688 	 */
1689 	if (fap.fa_mtime.tv_sec != np->n_mtime.tv_sec &&
1690 	    fap.fa_mtime.tv_sec != np->n_mtime.tv_sec - 1 &&
1691 	    fap.fa_mtime.tv_sec != np->n_mtime.tv_sec + 1)
1692 		goto uncached;	/* the mod time is different */
1693 
1694 	fap.fa_mtime.tv_sec = np->n_mtime.tv_sec; /* keep higher res time */
1695 	smbfs_attr_cacheenter(np->r_vnode, &fap);
1696 	if (attrcacheupdated)
1697 		*attrcacheupdated = 1;
1698 uncached:
1699 	return (0);
1700 }
1701 
1702 int
1703 smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
1704 			uint16_t *fidp)
1705 {
1706 	struct smb_vc *vcp = SSTOVC(np->n_mount->smi_share);
1707 	enum vtype vt = VREG;
1708 	int error;
1709 
1710 	/* Shared lock for n_fid use below. */
1711 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1712 
1713 	mutex_enter(&np->r_statelock);
1714 	if (np->n_fidrefs && (rights & np->n_rights) == rights) {
1715 		np->n_fidrefs++;
1716 		*fidp = np->n_fid;
1717 		mutex_exit(&np->r_statelock);
1718 		return (0);
1719 	}
1720 	mutex_exit(&np->r_statelock);
1721 
1722 	if (!(vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) {
1723 		int mode = smb_rights2mode(rights);
1724 		error = smbfs_smb_oldopen(np, mode, scrp,
1725 		    NULL, fidp, NULL, 0, 0, NULL, NULL);
1726 	} else {
1727 		if (SMBTOV(np))
1728 			vt = SMBTOV(np)->v_type;
1729 		error = smbfs_smb_ntcreatex(np, rights, scrp, vt,
1730 		    NULL, fidp, NULL, 0, NTCREATEX_DISP_OPEN, 0,
1731 		    NULL, NULL);
1732 	}
1733 
1734 	if (*fidp == np->n_fid) {
1735 		/*
1736 		 * Oh no, the server gave us the same FID again?
1737 		 * This will cause us to close np->n_fid early!
1738 		 */
1739 		SMBVDEBUG("duplicate fid: 0x%x\n", *fidp);
1740 	}
1741 
1742 	return (error);
1743 }
1744 
1745 int
1746 smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp)
1747 {
1748 	struct smb_share *ssp = np->n_mount->smi_share;
1749 	int error = 0;
1750 	uint16_t oldfid = SMB_FID_UNUSED;
1751 
1752 	/* Shared lock for n_fid use below. */
1753 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1754 
1755 	mutex_enter(&np->r_statelock);
1756 	if (fid == np->n_fid) {
1757 		ASSERT(np->n_fidrefs > 0);
1758 		if (--np->n_fidrefs == 0) {
1759 			/*
1760 			 * Don't expect to find the last reference
1761 			 * here in tmpclose.  Hard to deal with as
1762 			 * we don't have r_lkserlock exclusive.
1763 			 * Will close oldfid below.
1764 			 */
1765 			oldfid = np->n_fid;
1766 			np->n_fid = SMB_FID_UNUSED;
1767 		}
1768 	} else {
1769 		/* Will close the passed fid. */
1770 		oldfid = fid;
1771 	}
1772 	mutex_exit(&np->r_statelock);
1773 
1774 	if (oldfid != SMB_FID_UNUSED)
1775 		error = smbfs_smb_close(ssp, oldfid, NULL, scrp);
1776 
1777 	return (error);
1778 }
1779 
1780 int
1781 smbfs_smb_open(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
1782 	int *attrcacheupdated, uint16_t *fidp, const char *name,
1783 	int nmlen, int xattr, len_t *sizep, uint32_t *rightsp)
1784 {
1785 	int error;
1786 	struct smb_share *ssp = np->n_mount->smi_share;
1787 	struct smb_vc *vcp = SSTOVC(ssp);
1788 	enum vtype vt = VREG;
1789 
1790 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1791 		if (SMBTOV(np))
1792 			vt = SMBTOV(np)->v_type;
1793 		error = smbfs_smb_ntcreatex(np, rights, scrp, vt,
1794 		    attrcacheupdated, fidp, name, nmlen,
1795 		    NTCREATEX_DISP_OPEN, xattr, sizep, rightsp);
1796 	} else {
1797 		error = smbfs_smb_oldopen(np, smb_rights2mode(rights), scrp,
1798 		    attrcacheupdated, fidp, name, nmlen, xattr, sizep, rightsp);
1799 	}
1800 #if 0 /* let caller do this */
1801 	if (!error && !name)
1802 		np->n_fidrefs++;
1803 #endif
1804 	return (error);
1805 }
1806 
1807 int
1808 smbfs_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
1809 	struct smb_cred *scrp)
1810 {
1811 	struct smb_rq rq, *rqp = &rq;
1812 	struct mbchain *mbp;
1813 	long time;
1814 	int error;
1815 
1816 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp);
1817 	if (error)
1818 		return (error);
1819 	smb_rq_getrequest(rqp, &mbp);
1820 	smb_rq_wstart(rqp);
1821 	mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
1822 	if (mtime) {
1823 		smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
1824 	} else
1825 		time = 0;
1826 	mb_put_uint32le(mbp, time);
1827 	smb_rq_wend(rqp);
1828 	smb_rq_bstart(rqp);
1829 	smb_rq_bend(rqp);
1830 
1831 	/*
1832 	 * We don't really care about the result here, but we
1833 	 * do need to make sure we send this out, or we could
1834 	 * "leak" open file handles on interrupt or timeout.
1835 	 * The NOINTR_SEND flag makes this request immune to
1836 	 * interrupt or timeout until the send is done.
1837 	 */
1838 	rqp->sr_flags |= SMBR_NOINTR_SEND;
1839 	error = smb_rq_simple(rqp);
1840 	smb_rq_done(rqp);
1841 	/*
1842 	 * ENOTCONN isn't interesting - if the connection is closed,
1843 	 * so are all our FIDs - and EIO is also not interesting,
1844 	 * as it means a forced unmount was done. (was ENXIO)
1845 	 * Also ETIME, which means we sent the request but gave up
1846 	 * waiting before the response came back.
1847 	 *
1848 	 * Don't clog up the system log with warnings about these
1849 	 * uninteresting failures on closes.
1850 	 */
1851 	switch (error) {
1852 	case ENOTCONN:
1853 	case ENXIO:
1854 	case EIO:
1855 	case ETIME:
1856 		error = 0;
1857 	}
1858 	return (error);
1859 }
1860 
1861 static int
1862 smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen,
1863 	struct smb_cred *scrp, uint16_t *fidp, int xattr)
1864 {
1865 	struct smb_rq rq, *rqp = &rq;
1866 	struct smb_share *ssp = dnp->n_mount->smi_share;
1867 	struct mbchain *mbp;
1868 	struct mdchain *mdp;
1869 	struct timespec ctime;
1870 	uint8_t wc;
1871 	long tm;
1872 	int error;
1873 	uint16_t attr = SMB_FA_ARCHIVE;
1874 
1875 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp);
1876 	if (error)
1877 		return (error);
1878 	smb_rq_getrequest(rqp, &mbp);
1879 	smb_rq_wstart(rqp);
1880 	if (name && *name == '.')
1881 		attr |= SMB_FA_HIDDEN;
1882 	mb_put_uint16le(mbp, attr);		/* attributes  */
1883 	gethrestime(&ctime);
1884 	smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
1885 	mb_put_uint32le(mbp, tm);
1886 	smb_rq_wend(rqp);
1887 	smb_rq_bstart(rqp);
1888 	mb_put_uint8(mbp, SMB_DT_ASCII);
1889 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &nmlen,
1890 	    xattr ? ':' : '\\');
1891 	if (!error) {
1892 		smb_rq_bend(rqp);
1893 		/*
1894 		 * Don't want to risk missing a successful
1895 		 * open response, or we could "leak" FIDs.
1896 		 */
1897 		rqp->sr_flags |= SMBR_NOINTR_RECV;
1898 		error = smb_rq_simple_timed(rqp, smb_timo_open);
1899 		if (!error) {
1900 			smb_rq_getreply(rqp, &mdp);
1901 			md_get_uint8(mdp, &wc);
1902 			if (wc == 1)
1903 				md_get_uint16(mdp, fidp);
1904 			else
1905 				error = EBADRPC;
1906 		}
1907 	}
1908 	smb_rq_done(rqp);
1909 	return (error);
1910 }
1911 
1912 int
1913 smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
1914 	struct smb_cred *scrp, uint16_t *fidp, uint32_t disp, int xattr)
1915 {
1916 	struct smb_vc *vcp = SSTOVC(dnp->n_mount->smi_share);
1917 
1918 	/*
1919 	 * At present the only access we might need is to WRITE data,
1920 	 * and that only if we are creating a "symlink".  When/if the
1921 	 * access needed gets more complex it should made a parameter
1922 	 * and be set upstream.
1923 	 */
1924 	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1925 		return (smbfs_smb_ntcreatex(dnp, SA_RIGHT_FILE_WRITE_DATA,
1926 		    scrp, VREG, NULL, fidp, name, nmlen, disp, xattr,
1927 		    NULL, NULL));
1928 	} else
1929 		return (smbfs_smb_oldcreate(dnp, name, nmlen, scrp, fidp,
1930 		    xattr));
1931 }
1932 
1933 int
1934 smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name,
1935 			int nmlen, int xattr)
1936 {
1937 	struct smb_rq rq, *rqp = &rq;
1938 	struct smb_share *ssp = np->n_mount->smi_share;
1939 	struct mbchain *mbp;
1940 	int error;
1941 
1942 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp);
1943 	if (error)
1944 		return (error);
1945 	smb_rq_getrequest(rqp, &mbp);
1946 	smb_rq_wstart(rqp);
1947 	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
1948 	smb_rq_wend(rqp);
1949 	smb_rq_bstart(rqp);
1950 	mb_put_uint8(mbp, SMB_DT_ASCII);
1951 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &nmlen,
1952 	    xattr ? ':' : '\\');
1953 	if (!error) {
1954 		smb_rq_bend(rqp);
1955 		error = smb_rq_simple(rqp);
1956 	}
1957 	smb_rq_done(rqp);
1958 	return (error);
1959 }
1960 
1961 int
1962 smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
1963 	const char *tname, int tnmlen, struct smb_cred *scrp)
1964 {
1965 	struct smb_rq rq, *rqp = &rq;
1966 	struct smb_share *ssp = src->n_mount->smi_share;
1967 	struct mbchain *mbp;
1968 	int error;
1969 	uint16_t fa;
1970 	char sep;
1971 
1972 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
1973 	if (error)
1974 		return (error);
1975 	smb_rq_getrequest(rqp, &mbp);
1976 	smb_rq_wstart(rqp);
1977 	/* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
1978 	fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
1979 	fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
1980 	mb_put_uint16le(mbp, fa);
1981 	smb_rq_wend(rqp);
1982 	smb_rq_bstart(rqp);
1983 
1984 	/*
1985 	 * When we're not adding any component name, the
1986 	 * passed sep is ignored, so just pass sep=0.
1987 	 */
1988 	mb_put_uint8(mbp, SMB_DT_ASCII);
1989 	error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, 0);
1990 	if (error)
1991 		goto out;
1992 
1993 	/*
1994 	 * After XATTR directories, separator is ":"
1995 	 */
1996 	sep = (src->n_flag & N_XATTR) ? ':' : '\\';
1997 	mb_put_uint8(mbp, SMB_DT_ASCII);
1998 	error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen, sep);
1999 	if (error)
2000 		goto out;
2001 
2002 	smb_rq_bend(rqp);
2003 	error = smb_rq_simple(rqp);
2004 out:
2005 	smb_rq_done(rqp);
2006 	return (error);
2007 }
2008 
2009 int
2010 smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
2011 	const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp)
2012 {
2013 	struct smb_rq rq, *rqp = &rq;
2014 	struct smb_share *ssp = src->n_mount->smi_share;
2015 	struct mbchain *mbp;
2016 	int error;
2017 
2018 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp);
2019 	if (error)
2020 		return (error);
2021 	smb_rq_getrequest(rqp, &mbp);
2022 	smb_rq_wstart(rqp);
2023 	mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
2024 	mb_put_uint16le(mbp, 0x20);	/* delete target file */
2025 	mb_put_uint16le(mbp, flags);
2026 	smb_rq_wend(rqp);
2027 	smb_rq_bstart(rqp);
2028 	mb_put_uint8(mbp, SMB_DT_ASCII);
2029 	do {
2030 		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, '\\');
2031 		if (error)
2032 			break;
2033 		mb_put_uint8(mbp, SMB_DT_ASCII);
2034 		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen,
2035 		    '\\');
2036 		if (error)
2037 			break;
2038 		smb_rq_bend(rqp);
2039 		error = smb_rq_simple(rqp);
2040 		/*LINTED*/
2041 	} while (0);
2042 	smb_rq_done(rqp);
2043 	return (error);
2044 }
2045 
2046 static int
2047 smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len,
2048 			struct smb_cred *scrp)
2049 {
2050 	struct smb_rq rq, *rqp = &rq;
2051 	struct smb_share *ssp = dnp->n_mount->smi_share;
2052 	struct mbchain *mbp;
2053 	int error;
2054 
2055 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp);
2056 	if (error)
2057 		return (error);
2058 	smb_rq_getrequest(rqp, &mbp);
2059 	smb_rq_wstart(rqp);
2060 	smb_rq_wend(rqp);
2061 	smb_rq_bstart(rqp);
2062 	mb_put_uint8(mbp, SMB_DT_ASCII);
2063 	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &len, '\\');
2064 	if (!error) {
2065 		smb_rq_bend(rqp);
2066 		error = smb_rq_simple(rqp);
2067 	}
2068 	smb_rq_done(rqp);
2069 	return (error);
2070 }
2071 
2072 int
2073 smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
2074 		struct smb_cred *scrp)
2075 {
2076 	struct smb_share *ssp = dnp->n_mount->smi_share;
2077 	uint16_t fid;
2078 	int error;
2079 
2080 	/*
2081 	 * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
2082 	 * just to be asking for something.  The rights==0 case could
2083 	 * easily be broken on some old or unusual servers.
2084 	 */
2085 	if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
2086 		error = smbfs_smb_ntcreatex(dnp, SA_RIGHT_FILE_READ_DATA,
2087 		    scrp, VDIR, NULL, &fid, name, len,
2088 		    NTCREATEX_DISP_CREATE, 0, NULL, NULL);
2089 		if (error)
2090 			return (error);
2091 		error = smbfs_smb_close(ssp, fid, NULL, scrp);
2092 		if (error)
2093 			SMBERROR("error %d closing fid %d\n", error, fid);
2094 		return (0);
2095 	} else
2096 		return (smbfs_smb_oldmkdir(dnp, name, len, scrp));
2097 }
2098 
2099 int
2100 smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp)
2101 {
2102 	struct smb_rq rq, *rqp = &rq;
2103 	struct smb_share *ssp = np->n_mount->smi_share;
2104 	struct mbchain *mbp;
2105 	int error;
2106 
2107 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp);
2108 	if (error)
2109 		return (error);
2110 	smb_rq_getrequest(rqp, &mbp);
2111 	smb_rq_wstart(rqp);
2112 	smb_rq_wend(rqp);
2113 	smb_rq_bstart(rqp);
2114 	mb_put_uint8(mbp, SMB_DT_ASCII);
2115 	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, NULL, '\\');
2116 	if (!error) {
2117 		smb_rq_bend(rqp);
2118 		error = smb_rq_simple(rqp);
2119 	}
2120 	smb_rq_done(rqp);
2121 	return (error);
2122 }
2123 
2124 static int
2125 smbfs_smb_search(struct smbfs_fctx *ctx)
2126 {
2127 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
2128 	struct smb_rq *rqp;
2129 	struct mbchain *mbp;
2130 	struct mdchain *mdp;
2131 	uint8_t wc, bt;
2132 	uint16_t ec, dlen, bc;
2133 	int len, maxent, error, iseof = 0;
2134 
2135 	maxent = min(ctx->f_left,
2136 	    (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN);
2137 	if (ctx->f_rq) {
2138 		smb_rq_done(ctx->f_rq);
2139 		ctx->f_rq = NULL;
2140 	}
2141 	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH,
2142 	    ctx->f_scred, &rqp);
2143 	if (error)
2144 		return (error);
2145 	ctx->f_rq = rqp;
2146 	smb_rq_getrequest(rqp, &mbp);
2147 	smb_rq_wstart(rqp);
2148 	mb_put_uint16le(mbp, maxent);	/* max entries to return */
2149 	mb_put_uint16le(mbp, ctx->f_attrmask);
2150 	smb_rq_wend(rqp);
2151 	smb_rq_bstart(rqp);
2152 	mb_put_uint8(mbp, SMB_DT_ASCII);	/* buffer format */
2153 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
2154 		len = ctx->f_wclen;
2155 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard,
2156 		    &len, '\\');
2157 		if (error)
2158 			return (error);
2159 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
2160 		mb_put_uint16le(mbp, 0);	/* context length */
2161 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
2162 	} else {
2163 		if (SMB_UNICODE_STRINGS(vcp)) {
2164 			mb_put_padbyte(mbp);
2165 			mb_put_uint8(mbp, 0);
2166 		}
2167 		mb_put_uint8(mbp, 0);
2168 		mb_put_uint8(mbp, SMB_DT_VARIABLE);
2169 		mb_put_uint16le(mbp, SMB_SKEYLEN);
2170 		mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
2171 	}
2172 	smb_rq_bend(rqp);
2173 	error = smb_rq_simple(rqp);
2174 	if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
2175 		error = 0;
2176 		iseof = 1;
2177 		ctx->f_flags |= SMBFS_RDD_EOF;
2178 	} else if (error)
2179 		return (error);
2180 	smb_rq_getreply(rqp, &mdp);
2181 	md_get_uint8(mdp, &wc);
2182 	if (wc != 1)
2183 		return (iseof ? ENOENT : EBADRPC);
2184 	md_get_uint16le(mdp, &ec);
2185 	if (ec == 0)
2186 		return (ENOENT);
2187 	ctx->f_ecnt = ec;
2188 	md_get_uint16le(mdp, &bc);
2189 	if (bc < 3)
2190 		return (EBADRPC);
2191 	bc -= 3;
2192 	md_get_uint8(mdp, &bt);
2193 	if (bt != SMB_DT_VARIABLE)
2194 		return (EBADRPC);
2195 	md_get_uint16le(mdp, &dlen);
2196 	if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
2197 		return (EBADRPC);
2198 	return (0);
2199 }
2200 
2201 
2202 /*ARGSUSED*/
2203 static int
2204 smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
2205     const char *wildcard, int wclen, uint16_t attr)
2206 {
2207 
2208 	ctx->f_type = ft_LM1;
2209 	ctx->f_attrmask = attr;
2210 	if (wildcard) {
2211 		if (wclen == 1 && wildcard[0] == '*') {
2212 			ctx->f_wildcard = "*.*";
2213 			ctx->f_wclen = 3;
2214 		} else {
2215 			ctx->f_wildcard = wildcard;
2216 			ctx->f_wclen = wclen;
2217 		}
2218 	} else {
2219 		ctx->f_wildcard = NULL;
2220 		ctx->f_wclen = 0;
2221 	}
2222 	ctx->f_name = (char *)ctx->f_fname;
2223 	ctx->f_namesz = 0;
2224 	return (0);
2225 }
2226 
2227 static int
2228 smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit)
2229 {
2230 	struct mdchain *mdp;
2231 	struct smb_rq *rqp;
2232 	char *cp;
2233 	uint8_t battr;
2234 	uint16_t date, time;
2235 	uint32_t size;
2236 	int error;
2237 	struct timespec ts;
2238 
2239 	if (ctx->f_ecnt == 0) {
2240 		if (ctx->f_flags & SMBFS_RDD_EOF)
2241 			return (ENOENT);
2242 		ctx->f_left = ctx->f_limit = limit;
2243 		gethrestime(&ts);
2244 		error = smbfs_smb_search(ctx);
2245 		if (error)
2246 			return (error);
2247 		ctx->f_attr.fa_reqtime = ts;
2248 	}
2249 	rqp = ctx->f_rq;
2250 	smb_rq_getreply(rqp, &mdp);
2251 	md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
2252 	md_get_uint8(mdp, &battr);
2253 	md_get_uint16le(mdp, &time);
2254 	md_get_uint16le(mdp, &date);
2255 	md_get_uint32le(mdp, &size);
2256 	cp = ctx->f_name;
2257 	md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM);
2258 	cp[sizeof (ctx->f_fname) - 1] = 0;
2259 	cp += strlen(cp) - 1;
2260 	while (*cp == ' ' && cp >= ctx->f_name)
2261 		*cp-- = 0;
2262 	ctx->f_attr.fa_attr = battr;
2263 	smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
2264 	    &ctx->f_attr.fa_mtime);
2265 	ctx->f_attr.fa_size = size;
2266 	ctx->f_nmlen = strlen(ctx->f_name);
2267 	ctx->f_ecnt--;
2268 	ctx->f_left--;
2269 	return (0);
2270 }
2271 
2272 static int
2273 smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx)
2274 {
2275 	if (ctx->f_rq)
2276 		smb_rq_done(ctx->f_rq);
2277 	return (0);
2278 }
2279 
2280 /*
2281  * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
2282  */
2283 static int
2284 smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
2285 {
2286 	struct smb_t2rq *t2p;
2287 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
2288 	struct mbchain *mbp;
2289 	struct mdchain *mdp;
2290 	uint16_t tw, flags;
2291 	int len, error;
2292 
2293 	if (ctx->f_t2) {
2294 		smb_t2_done(ctx->f_t2);
2295 		ctx->f_t2 = NULL;
2296 	}
2297 	ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
2298 	flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
2299 	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
2300 		flags |= FIND2_CLOSE_AFTER_REQUEST;
2301 		ctx->f_flags |= SMBFS_RDD_NOCLOSE;
2302 	}
2303 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
2304 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
2305 		    ctx->f_scred, &t2p);
2306 		if (error)
2307 			return (error);
2308 		ctx->f_t2 = t2p;
2309 		mbp = &t2p->t2_tparam;
2310 		mb_init(mbp);
2311 		mb_put_uint16le(mbp, ctx->f_attrmask);
2312 		mb_put_uint16le(mbp, ctx->f_limit);
2313 		mb_put_uint16le(mbp, flags);
2314 		mb_put_uint16le(mbp, ctx->f_infolevel);
2315 		mb_put_uint32le(mbp, 0);
2316 		/* mb_put_uint8(mbp, SMB_DT_ASCII); specs? hah! */
2317 		len = ctx->f_wclen;
2318 		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard,
2319 		    &len, '\\');
2320 		if (error)
2321 			return (error);
2322 	} else	{
2323 		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
2324 		    ctx->f_scred, &t2p);
2325 		if (error)
2326 			return (error);
2327 		ctx->f_t2 = t2p;
2328 		mbp = &t2p->t2_tparam;
2329 		mb_init(mbp);
2330 		mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
2331 		mb_put_uint16le(mbp, ctx->f_limit);
2332 		mb_put_uint16le(mbp, ctx->f_infolevel);
2333 		if (ctx->f_ssp->ss_flags & SMBS_RESUMEKEYS) {
2334 			mb_put_uint32le(mbp, ctx->f_rkey);
2335 		} else
2336 			mb_put_uint32le(mbp, 0);
2337 		mb_put_uint16le(mbp, flags);
2338 		if (ctx->f_rname) {
2339 			/* resume file name */
2340 			mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
2341 			    MB_MSYSTEM);
2342 		}
2343 		/* Add trailing null - 1 byte if ASCII, 2 if Unicode */
2344 		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2345 			mb_put_uint8(mbp, 0);	/* 1st byte NULL Unicode char */
2346 		mb_put_uint8(mbp, 0);
2347 #if 0
2348 		struct timespec ts;
2349 		ts.tv_sec = 0;
2350 		ts.tv_nsec = 200 * 1000 * 1000;	/* 200ms */
2351 		if (vcp->vc_flags & SMBC_WIN95) {
2352 			/*
2353 			 * some implementations suggests to sleep here
2354 			 * for 200ms, due to the bug in the Win95.
2355 			 * I've didn't notice any problem, but put code
2356 			 * for it.
2357 			 */
2358 			msleep(&flags, 0, PVFS, "fix95", &ts);
2359 		}
2360 #endif
2361 	}
2362 	t2p->t2_maxpcount = 5 * 2;
2363 	t2p->t2_maxdcount = vcp->vc_txmax;
2364 	error = smb_t2_request(t2p);
2365 	if (error)
2366 		return (error);
2367 	mdp = &t2p->t2_rparam;
2368 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
2369 		if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
2370 			return (error);
2371 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
2372 	}
2373 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
2374 		return (error);
2375 	ctx->f_ecnt = tw; /* search count - # entries returned */
2376 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
2377 		return (error);
2378 	/*
2379 	 * tw now is the "end of search" flag. against an XP server tw
2380 	 * comes back zero when the prior find_next returned exactly
2381 	 * the number of entries requested.  in which case we'd try again
2382 	 * but the search has in fact been closed so an EBADF results.  our
2383 	 * circumvention is to check here for a zero search count.
2384 	 */
2385 	if (tw || ctx->f_ecnt == 0)
2386 		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
2387 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
2388 		return (error);
2389 	if ((error = md_get_uint16le(mdp, &tw)) != 0)
2390 		return (error);
2391 	if (ctx->f_ecnt == 0)
2392 		return (ENOENT);
2393 	ctx->f_rnameofs = tw;
2394 	mdp = &t2p->t2_rdata;
2395 	if (mdp->md_top == NULL) {
2396 		SMBVDEBUG("ecnt = %d, but data is NULL\n", ctx->f_ecnt);
2397 		return (ENOENT);
2398 	}
2399 #ifdef APPLE
2400 	if (mdp->md_top->m_len == 0) {
2401 		printf("bug: ecnt = %d, but m_len = 0 and m_next = %p "
2402 		    "(please report)\n", ctx->f_ecnt, mbp->mb_top->m_next);
2403 		return (ENOENT);
2404 	}
2405 #endif
2406 	ctx->f_eofs = 0;
2407 	return (0);
2408 }
2409 
2410 static int
2411 smbfs_smb_findclose2(struct smbfs_fctx *ctx)
2412 {
2413 	struct smb_rq rq, *rqp = &rq;
2414 	struct mbchain *mbp;
2415 	int error;
2416 
2417 	error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
2418 	    ctx->f_scred);
2419 	if (error)
2420 		return (error);
2421 	smb_rq_getrequest(rqp, &mbp);
2422 	smb_rq_wstart(rqp);
2423 	mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
2424 	smb_rq_wend(rqp);
2425 	smb_rq_bstart(rqp);
2426 	smb_rq_bend(rqp);
2427 	/* Ditto comments at _smb_close */
2428 	rqp->sr_flags |= SMBR_NOINTR_SEND;
2429 	error = smb_rq_simple(rqp);
2430 	smb_rq_done(rqp);
2431 	return (error);
2432 }
2433 
2434 /*ARGSUSED*/
2435 static int
2436 smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
2437     const char *wildcard, int wclen, uint16_t attr)
2438 {
2439 
2440 	ctx->f_type = ft_LM2;
2441 	ctx->f_namesz = SMB_MAXFNAMELEN;
2442 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2443 		ctx->f_namesz *= 2;
2444 	ctx->f_name = kmem_zalloc(ctx->f_namesz, KM_SLEEP);
2445 	ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp))
2446 	    < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD :
2447 	    SMB_FIND_BOTH_DIRECTORY_INFO;
2448 	ctx->f_attrmask = attr;
2449 	ctx->f_wildcard = wildcard;
2450 	ctx->f_wclen = wclen;
2451 	return (0);
2452 }
2453 
2454 static int
2455 smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
2456 {
2457 	struct mdchain *mdp;
2458 	struct smb_t2rq *t2p;
2459 	char *cp;
2460 	uint8_t tb;
2461 	uint16_t date, time, wattr;
2462 	uint32_t size, next, dattr, resumekey = 0;
2463 	uint64_t llongint;
2464 	int error, svtz, cnt, fxsz, nmlen, recsz, otw;
2465 	struct timespec ts;
2466 
2467 again:
2468 	otw = 0;	/* nothing sent Over The Wire (yet) */
2469 	if (ctx->f_ecnt == 0) {
2470 		if (ctx->f_flags & SMBFS_RDD_EOF)
2471 			return (ENOENT);
2472 		ctx->f_left = ctx->f_limit = limit;
2473 		gethrestime(&ts);
2474 		error = smbfs_smb_trans2find2(ctx);
2475 		if (error)
2476 			return (error);
2477 		ctx->f_attr.fa_reqtime = ts;
2478 		ctx->f_otws++;
2479 		otw = 1;
2480 	}
2481 	t2p = ctx->f_t2;
2482 	mdp = &t2p->t2_rdata;
2483 	svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
2484 	switch (ctx->f_infolevel) {
2485 	case SMB_FIND_STANDARD:
2486 		next = 0;
2487 		fxsz = 0;
2488 		md_get_uint16le(mdp, &date);
2489 		md_get_uint16le(mdp, &time);	/* creation time */
2490 		md_get_uint16le(mdp, &date);
2491 		md_get_uint16le(mdp, &time);	/* access time */
2492 		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
2493 		md_get_uint16le(mdp, &date);
2494 		md_get_uint16le(mdp, &time);	/* modify time */
2495 		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
2496 		md_get_uint32le(mdp, &size);
2497 		ctx->f_attr.fa_size = size;
2498 		md_get_uint32(mdp, NULL);	/* allocation size */
2499 		md_get_uint16le(mdp, &wattr);
2500 		ctx->f_attr.fa_attr = wattr;
2501 		md_get_uint8(mdp, &tb);
2502 		size = nmlen = tb;
2503 		fxsz = 23;
2504 		recsz = next = 24 + nmlen;	/* docs misses zero byte @end */
2505 		break;
2506 	case SMB_FIND_DIRECTORY_INFO:
2507 	case SMB_FIND_BOTH_DIRECTORY_INFO:
2508 		md_get_uint32le(mdp, &next);
2509 		md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
2510 		md_get_uint64(mdp, NULL);	/* creation time */
2511 		md_get_uint64le(mdp, &llongint);
2512 		smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_atime);
2513 		md_get_uint64le(mdp, &llongint);
2514 		smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_mtime);
2515 		md_get_uint64le(mdp, &llongint);
2516 		smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_ctime);
2517 		md_get_uint64le(mdp, &llongint);	/* file size */
2518 		ctx->f_attr.fa_size = llongint;
2519 		md_get_uint64(mdp, NULL);	/* real size (should use) */
2520 		/* freebsd bug: fa_attr endian bug */
2521 		md_get_uint32le(mdp, &dattr);	/* extended file attributes */
2522 		ctx->f_attr.fa_attr = dattr;
2523 		md_get_uint32le(mdp, &size);	/* name len */
2524 		fxsz = 64; /* size ofinfo up to filename */
2525 		if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) {
2526 			/*
2527 			 * Skip EaSize(4 bytes), a byte of ShortNameLength,
2528 			 * a reserved byte, and ShortName(8.3 means 24 bytes,
2529 			 * as Leach defined it to always be Unicode)
2530 			 */
2531 			md_get_mem(mdp, NULL, 30, MB_MSYSTEM);
2532 			fxsz += 30;
2533 		}
2534 		recsz = next ? next : fxsz + size;
2535 		break;
2536 	default:
2537 		SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
2538 		return (EINVAL);
2539 	}
2540 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
2541 		nmlen = min(size, SMB_MAXFNAMELEN * 2);
2542 	else
2543 		nmlen = min(size, SMB_MAXFNAMELEN);
2544 	if (ctx->f_name)
2545 		kmem_free(ctx->f_name, ctx->f_namesz);
2546 	cp = ctx->f_name = kmem_alloc(nmlen, KM_SLEEP);
2547 	ctx->f_namesz = nmlen;
2548 	error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM);
2549 	if (error)
2550 		return (error);
2551 	if (next) {
2552 		cnt = next - nmlen - fxsz;
2553 		if (cnt > 0)
2554 			md_get_mem(mdp, NULL, cnt, MB_MSYSTEM);
2555 		else if (cnt < 0) {
2556 			SMBVDEBUG("out of sync\n");
2557 			return (EBADRPC);
2558 		}
2559 	}
2560 	/* Don't count any trailing null in the name. */
2561 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
2562 		if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
2563 			nmlen -= 2;
2564 	} else {
2565 		if (nmlen && cp[nmlen - 1] == 0)
2566 			nmlen--;
2567 	}
2568 	if (nmlen == 0)
2569 		return (EBADRPC);
2570 
2571 	/*
2572 	 * Ref radar 3983209.  On a find-next we expect a server will
2573 	 * 1) if the continue bit is set, use the server's idea of current loc,
2574 	 * 2) else if the resume key is non-zero, use that location,
2575 	 * 3) else if the resume name is set, use that location,
2576 	 * 4) else use the server's idea of current location.
2577 	 *
2578 	 * Current NetApps don't do that.  If we send no continue bit, a zero
2579 	 * resume key, and a resume name, the NetApp ignores the resume name
2580 	 * and acts on the (zero) resume key, sending back the start of the
2581 	 * directory again.  Panther doesn't expose the netapp bug; Panther used
2582 	 * the continue bit, but that was changed for 2866172. Win2000 as a
2583 	 * client also relies upon the resume name, but they request a very
2584 	 * large number of files, so the bug would be seen only with very
2585 	 * large directories.
2586 	 *
2587 	 * Our fix is to notice if the second OTW op (the first find-next)
2588 	 * returns, in the first filename, the same filename we got back
2589 	 * at the start of the first OTW (the find-first).  In that case
2590 	 * we've detected the server bug and set SMBS_RESUMEKEYS, causing us
2591 	 * to send non-zero resume keys henceforth.
2592 	 *
2593 	 * Caveat: if there's a netapp so old it doesn't negotiate NTLM 0.12
2594 	 * then we get no resume keys so f_rkey stays zero and this "fix"
2595 	 * changes nothing.
2596 	 *
2597 	 * Note due to a similar problem (4051871) we also set SMBS_RESUMEKEYS
2598 	 * for FAT volumes, at mount time.
2599 	 */
2600 	if (otw && !(ctx->f_ssp->ss_flags & SMBS_RESUMEKEYS)) {
2601 		if (ctx->f_otws == 1) {
2602 			ctx->f_firstnmlen = nmlen;
2603 			ctx->f_firstnm = kmem_alloc(nmlen, KM_SLEEP);
2604 			bcopy(ctx->f_name, ctx->f_firstnm, nmlen);
2605 		} else if (ctx->f_otws == 2 && nmlen == ctx->f_firstnmlen &&
2606 		    !(bcmp(ctx->f_name, ctx->f_firstnm, nmlen) == 0)) {
2607 			struct smb_share *ssp = ctx->f_ssp;
2608 			SMBERROR(
2609 			    "server resume_name bug seen; using resume keys\n");
2610 			SMB_SS_LOCK(ssp);
2611 			ssp->ss_flags |= SMBS_RESUMEKEYS;
2612 			SMB_SS_UNLOCK(ssp);
2613 			ctx->f_ecnt = 0;
2614 			goto again; /* must redo last otw op! */
2615 		}
2616 	}
2617 	ctx->f_rkey = resumekey;
2618 
2619 	next = ctx->f_eofs + recsz;
2620 	if (ctx->f_rnameofs &&
2621 	    (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
2622 	    (ctx->f_rnameofs >= ctx->f_eofs &&
2623 	    ctx->f_rnameofs < (int)next)) {
2624 		/*
2625 		 * Server needs a resume filename.
2626 		 */
2627 		if (ctx->f_rnamelen != nmlen) {
2628 			if (ctx->f_rname)
2629 				kmem_free(ctx->f_rname, ctx->f_rnamelen);
2630 			ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP);
2631 			ctx->f_rnamelen = nmlen;
2632 		}
2633 		bcopy(ctx->f_name, ctx->f_rname, nmlen);
2634 		ctx->f_flags |= SMBFS_RDD_GOTRNAME;
2635 	}
2636 	ctx->f_nmlen = nmlen;
2637 	ctx->f_eofs = next;
2638 	ctx->f_ecnt--;
2639 	ctx->f_left--;
2640 
2641 	smbfs_fname_tolocal(ctx);
2642 	return (0);
2643 }
2644 
2645 static int
2646 smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
2647 {
2648 	int error = 0;
2649 	if (ctx->f_name)
2650 		kmem_free(ctx->f_name, ctx->f_namesz);
2651 	if (ctx->f_t2)
2652 		smb_t2_done(ctx->f_t2);
2653 	if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
2654 		error = smbfs_smb_findclose2(ctx);
2655 	return (error);
2656 }
2657 
2658 int
2659 smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
2660 			int attr, struct smb_cred *scrp,
2661 			struct smbfs_fctx **ctxpp)
2662 {
2663 	struct smbfs_fctx *ctx;
2664 	int error;
2665 
2666 	ctx = kmem_alloc(sizeof (*ctx), KM_SLEEP);
2667 	if (ctx == NULL)
2668 		return (ENOMEM);
2669 	bzero(ctx, sizeof (*ctx));
2670 
2671 	ctx->f_flags = SMBFS_RDD_FINDFIRST;
2672 	ctx->f_dnp = dnp;
2673 	ctx->f_scred = scrp;
2674 	ctx->f_ssp = dnp->n_mount->smi_share;
2675 
2676 	if (dnp->n_flag & N_XATTR) {
2677 		error = smbfs_xa_findopen(ctx, dnp, wild, wlen);
2678 		goto out;
2679 	}
2680 
2681 	if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
2682 	    (dnp->n_mount->smi_args.flags & SMBFS_MOUNT_NO_LONG)) {
2683 		error = smbfs_smb_findopenLM1(ctx, dnp, wild, wlen, attr);
2684 	} else {
2685 		error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr);
2686 	}
2687 
2688 out:
2689 	if (error)
2690 		(void) smbfs_smb_findclose(ctx, scrp);
2691 	else
2692 		*ctxpp = ctx;
2693 	return (error);
2694 }
2695 
2696 int
2697 smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
2698 {
2699 	int error;
2700 
2701 	/*
2702 	 * Note: "limit" (maxcount) needs to fit in a short!
2703 	 *
2704 	 * smb_lookup always uses 1, which is OK (no wildcards).
2705 	 * Otherwise, this is smbfs_readdir, and we want to force
2706 	 * limit to be in the range 3 to 1000.  The low limit (3)
2707 	 * is so we can always give the caller one "real" entry
2708 	 * (something other than "." or "..") The high limit is
2709 	 * just tuning. WinNT used 512, Win2k 1366.  We use 1000.
2710 	 *
2711 	 * XXX: Move the [skip . ..] gunk to our caller (readdir).
2712 	 */
2713 	if ((ctx->f_flags & SMBFS_RDD_FINDSINGLE) == 0) {
2714 		if (limit < 3)
2715 			limit = 3;
2716 		if (limit > 1000)
2717 			limit = 1000;
2718 	}
2719 
2720 	ctx->f_scred = scrp;
2721 	for (;;) {
2722 		bzero(&ctx->f_attr, sizeof (ctx->f_attr));
2723 		switch (ctx->f_type) {
2724 		case ft_LM1:
2725 			error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit);
2726 			break;
2727 		case ft_LM2:
2728 			error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit);
2729 			break;
2730 		case ft_XA:
2731 			error = smbfs_xa_findnext(ctx, (uint16_t)limit);
2732 			break;
2733 		default:
2734 			ASSERT(0);
2735 			error = EINVAL;
2736 			break;
2737 		}
2738 		if (error)
2739 			return (error);
2740 		/*
2741 		 * Skip "." or ".." - easy now that ctx->f_name
2742 		 * has already been converted to utf-8 format.
2743 		 */
2744 		if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
2745 		    (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
2746 		    ctx->f_name[1] == '.'))
2747 			continue;
2748 		break;
2749 	}
2750 
2751 	/*
2752 	 * Moved the smbfs_fname_tolocal(ctx) call into
2753 	 * the ..._findnext functions above.
2754 	 */
2755 
2756 	ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name,
2757 	    ctx->f_nmlen);
2758 	return (0);
2759 }
2760 
2761 
2762 int
2763 smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
2764 {
2765 	int error;
2766 
2767 	ctx->f_scred = scrp;
2768 	switch (ctx->f_type) {
2769 	case ft_LM1:
2770 		error = smbfs_smb_findcloseLM1(ctx);
2771 		break;
2772 	case ft_LM2:
2773 		error = smbfs_smb_findcloseLM2(ctx);
2774 		break;
2775 	case ft_XA:
2776 		error = smbfs_xa_findclose(ctx);
2777 		break;
2778 	}
2779 	if (ctx->f_rname)
2780 		kmem_free(ctx->f_rname, ctx->f_rnamelen);
2781 	if (ctx->f_firstnm)
2782 		kmem_free(ctx->f_firstnm, ctx->f_firstnmlen);
2783 	kmem_free(ctx, sizeof (*ctx));
2784 	return (error);
2785 }
2786 
2787 
2788 int
2789 smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
2790 	struct smbfattr *fap, struct smb_cred *scrp)
2791 {
2792 	struct smbfs_fctx *ctx;
2793 	int error, intr;
2794 	const char *name = (namep ? *namep : NULL);
2795 	int nmlen = (nmlenp ? *nmlenp : 0);
2796 
2797 	/* This is no longer called with a null dnp */
2798 	ASSERT(dnp);
2799 
2800 	/*
2801 	 * Should not get here with "" anymore.
2802 	 */
2803 	if (!name || !nmlen) {
2804 		DEBUG_ENTER("smbfs_smb_lookup: name is NULL");
2805 		return (EINVAL);
2806 	}
2807 
2808 	/*
2809 	 * Should not get here with "." or ".." anymore.
2810 	 */
2811 	if ((nmlen == 1 && name[0] == '.') ||
2812 	    (nmlen == 2 && name[0] == '.' && name[1] == '.')) {
2813 		DEBUG_ENTER("smbfs_smb_lookup: name is '.' or '..'");
2814 		return (EINVAL);
2815 	}
2816 
2817 	/*
2818 	 * Shared lock for n_fid use (smb_flush).
2819 	 */
2820 	intr = dnp->n_mount->smi_flags & SMI_INT;
2821 	if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr))
2822 		return (EINTR);
2823 
2824 	/*
2825 	 * This hides a server bug observable in Win98:
2826 	 * size changes may not show until a CLOSE or a FLUSH op
2827 	 * XXX: Make this conditional on !NTSMBs
2828 	 */
2829 	error = smbfs_smb_flush(dnp, scrp);
2830 	if (error)
2831 		goto out;
2832 	error = smbfs_smb_findopen(dnp, name, nmlen,
2833 	    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx);
2834 	if (error)
2835 		goto out;
2836 	ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
2837 	error = smbfs_smb_findnext(ctx, 1, scrp);
2838 	if (error == 0) {
2839 		*fap = ctx->f_attr;
2840 		if (name == NULL)
2841 			fap->fa_ino = dnp->n_ino;
2842 		if (namep)
2843 			*namep = (const char *)smbfs_name_alloc(
2844 			    ctx->f_name, ctx->f_nmlen);
2845 		if (nmlenp)
2846 			*nmlenp = ctx->f_nmlen;
2847 	}
2848 	(void) smbfs_smb_findclose(ctx, scrp);
2849 
2850 out:
2851 	smbfs_rw_exit(&dnp->r_lkserlock);
2852 	return (error);
2853 }
2854 
2855 /*
2856  * OTW function to Get a security descriptor (SD).
2857  *
2858  * Note: On success, this fills in mdp->md_top,
2859  * which the caller should free.
2860  */
2861 int
2862 smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
2863 		struct smb_cred *scrp, uint32_t selector,
2864 		mblk_t **res, uint32_t *reslen)
2865 {
2866 	struct smb_ntrq *ntp;
2867 	struct mbchain *mbp;
2868 	struct mdchain *mdp;
2869 	int error, len;
2870 
2871 	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
2872 	    scrp, &ntp);
2873 	if (error)
2874 		return (error);
2875 
2876 	/* Parameters part */
2877 	mbp = &ntp->nt_tparam;
2878 	mb_init(mbp);
2879 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
2880 	mb_put_uint16le(mbp, 0); /* reserved */
2881 	mb_put_uint32le(mbp, selector);
2882 	/* Data part (none) */
2883 
2884 	/* Max. returned parameters and data. */
2885 	ntp->nt_maxpcount = 4;
2886 	ntp->nt_maxdcount = *reslen;
2887 
2888 	error = smb_nt_request(ntp);
2889 	if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
2890 		goto done;
2891 	*res = NULL;
2892 
2893 	/*
2894 	 * if there's more data than we said we could receive, here
2895 	 * is where we pick up the length of it
2896 	 */
2897 	mdp = &ntp->nt_rparam;
2898 	md_get_uint32le(mdp, reslen);
2899 	if (error)
2900 		goto done;
2901 
2902 	/*
2903 	 * get the data part.
2904 	 */
2905 	mdp = &ntp->nt_rdata;
2906 	if (mdp->md_top == NULL) {
2907 		SMBVDEBUG("null md_top? fid 0x%x\n", letohs(fid));
2908 		error = EBADRPC;
2909 		goto done;
2910 	}
2911 
2912 	/*
2913 	 * The returned parameter SD_length should match
2914 	 * the length of the returned data.  Unfortunately,
2915 	 * we have to work around server bugs here.
2916 	 */
2917 	len = m_fixhdr(mdp->md_top);
2918 	if (len != *reslen) {
2919 		SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
2920 		    len, *reslen, letohs(fid));
2921 	}
2922 
2923 	/*
2924 	 * Actual data provided is < returned SD_length.
2925 	 *
2926 	 * The following "if (len < *reslen)" handles a Windows bug
2927 	 * observed when the underlying filesystem is FAT32.  In that
2928 	 * case a 32 byte security descriptor comes back (S-1-1-0, ie
2929 	 * "Everyone") but the Parameter Block claims 44 is the length
2930 	 * of the security descriptor.  (The Data Block length
2931 	 * claimed is 32.  This server bug was reported against NT
2932 	 * first and I've personally observed it with W2K.
2933 	 */
2934 	if (len < *reslen)
2935 		*reslen = len;
2936 
2937 	/*
2938 	 * Actual data provided is > returned SD_length.
2939 	 * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0)
2940 	 * Narrow work-around for returned SD_length==0.
2941 	 */
2942 	if (len > *reslen) {
2943 		/*
2944 		 * Increase *reslen, but carefully.
2945 		 */
2946 		if (*reslen == 0 && len <= ntp->nt_maxdcount)
2947 			*reslen = len;
2948 	}
2949 	error = md_get_mbuf(mdp, len, res);
2950 
2951 done:
2952 	if (error == 0 && *res == NULL) {
2953 		ASSERT(*res);
2954 		error = EBADRPC;
2955 	}
2956 
2957 	smb_nt_done(ntp);
2958 	return (error);
2959 }
2960 
2961 #ifdef	APPLE
2962 /*
2963  * Wrapper for _getsd() compatible with darwin code.
2964  */
2965 int
2966 smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
2967 	uint32_t selector, struct ntsecdesc **res)
2968 {
2969 	int error;
2970 	uint32_t len, olen;
2971 	struct mdchain *mdp, md_store;
2972 	struct mbuf *m;
2973 
2974 	bzero(mdp, sizeof (*mdp));
2975 	len = 500; /* "overlarge" values => server errors */
2976 again:
2977 	olen = len;
2978 	error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len);
2979 	/*
2980 	 * Server may give us an error indicating that we
2981 	 * need a larger data buffer to receive the SD,
2982 	 * and the size we'll need.  Use the given size,
2983 	 * but only after a sanity check.
2984 	 *
2985 	 * XXX: Check for specific error values here?
2986 	 * XXX: also ... && len <= MAX_RAW_SD_SIZE
2987 	 */
2988 	if (error && len > olen)
2989 		goto again;
2990 
2991 	if (error)
2992 		return (error);
2993 
2994 	mdp = &md_store;
2995 	md_initm(mdp, m);
2996 	MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
2997 	error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
2998 	md_done(mdp);
2999 
3000 	return (error);
3001 }
3002 #endif /* APPLE */
3003 
3004 /*
3005  * OTW function to Set a security descriptor (SD).
3006  * Caller data are carried in an mbchain_t.
3007  *
3008  * Note: This normally consumes mbp->mb_top, and clears
3009  * that pointer when it does.
3010  */
3011 int  smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
3012 	struct smb_cred *scrp, uint32_t selector, mblk_t **mp)
3013 {
3014 	struct smb_ntrq *ntp;
3015 	struct mbchain *mbp;
3016 	int error;
3017 
3018 	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
3019 	    scrp, &ntp);
3020 	if (error)
3021 		return (error);
3022 
3023 	/* Parameters part */
3024 	mbp = &ntp->nt_tparam;
3025 	mb_init(mbp);
3026 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
3027 	mb_put_uint16le(mbp, 0); /* reserved */
3028 	mb_put_uint32le(mbp, selector);
3029 
3030 	/* Data part */
3031 	mbp = &ntp->nt_tdata;
3032 	mb_initm(mbp, *mp);
3033 	*mp = NULL; /* consumed */
3034 
3035 	/* No returned parameters or data. */
3036 	ntp->nt_maxpcount = 0;
3037 	ntp->nt_maxdcount = 0;
3038 
3039 	error = smb_nt_request(ntp);
3040 	smb_nt_done(ntp);
3041 
3042 	return (error);
3043 }
3044 
3045 #ifdef	APPLE
3046 /*
3047  * This function builds the SD given the various parts.
3048  */
3049 int
3050 smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
3051 	uint32_t selector, uint16_t flags, struct ntsid *owner,
3052 	struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl)
3053 {
3054 	struct mbchain *mbp, mb_store;
3055 	struct ntsecdesc ntsd;
3056 	int error, off;
3057 
3058 	/*
3059 	 * Build the SD as its own mbuf chain and pass it to
3060 	 * smbfs_smb_setsec_m()
3061 	 */
3062 	mbp = &mb_store;
3063 	mb_init(mbp);
3064 	bzero(&ntsd, sizeof (ntsd));
3065 	wset_sdrevision(&ntsd);
3066 	/*
3067 	 * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN)
3068 	 * We set here only those bits we can be sure must be set.  The rest
3069 	 * are up to the caller.  In particular, the caller may intentionally
3070 	 * set an acl PRESENT bit while giving us a null pointer for the
3071 	 * acl - that sets a null acl, giving access to everyone.  Note also
3072 	 * that the AUTO_INHERITED bits should probably always be set unless
3073 	 * the server is NT.
3074 	 */
3075 	flags |= SD_SELF_RELATIVE;
3076 	off = sizeof (ntsd);
3077 	if (owner) {
3078 		wset_sdowneroff(&ntsd, off);
3079 		off += sidlen(owner);
3080 	}
3081 	if (group) {
3082 		wset_sdgroupoff(&ntsd, off);
3083 		off += sidlen(group);
3084 	}
3085 	if (sacl) {
3086 		flags |= SD_SACL_PRESENT;
3087 		wset_sdsacloff(&ntsd, off);
3088 		off += acllen(sacl);
3089 	}
3090 	if (dacl) {
3091 		flags |= SD_DACL_PRESENT;
3092 		wset_sddacloff(&ntsd, off);
3093 	}
3094 	wset_sdflags(&ntsd, flags);
3095 	mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM);
3096 	if (owner)
3097 		mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM);
3098 	if (group)
3099 		mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM);
3100 	if (sacl)
3101 		mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM);
3102 	if (dacl)
3103 		mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM);
3104 
3105 	/*
3106 	 * Just pass the mbuf to _setsec_m
3107 	 * It will clear mb_top if consumed.
3108 	 */
3109 	error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top);
3110 	mb_done(mbp);
3111 
3112 	return (error);
3113 }
3114 
3115 #endif /* APPLE */
3116