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