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