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