PageRenderTime 209ms CodeModel.GetById 105ms app.highlight 90ms RepoModel.GetById 1ms app.codeStats 1ms

/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c

https://bitbucket.org/osunix/osunix-gate
C | 2831 lines | 2119 code | 255 blank | 457 comment | 371 complexity | 3b8c9685fb05652d92bc904bc48edff4 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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#include <netsmb/smb_osdep.h>
  48
  49#include <netsmb/smb.h>
  50#include <netsmb/smb_conn.h>
  51#include <netsmb/smb_subr.h>
  52#include <netsmb/smb_rq.h>
  53
  54#include <smbfs/smbfs.h>
  55#include <smbfs/smbfs_node.h>
  56#include <smbfs/smbfs_subr.h>
  57
  58/*
  59 * Jan 1 1980 as 64 bit NT time.
  60 * (tenths of microseconds since 1601)
  61 */
  62const uint64_t NT1980 = 11960035200ULL*10000000ULL;
  63
  64/*
  65 * Local functions.
  66 * Not static, to aid debugging.
  67 */
  68
  69int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
  70	struct smbfattr *fap, struct smb_cred *scrp);
  71int smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
  72	struct smb_cred *scrp, uint16_t infolevel);
  73
  74int smbfs_smb_statfsLM1(struct smb_share *ssp,
  75	statvfs64_t *sbp, struct smb_cred *scrp);
  76int smbfs_smb_statfsLM2(struct smb_share *ssp,
  77	statvfs64_t *sbp, struct smb_cred *scrp);
  78
  79int  smbfs_smb_setfattrNT(struct smbnode *np, int fid,
  80	uint32_t attr, struct timespec *mtime,	struct timespec *atime,
  81	struct smb_cred *scrp);
  82
  83int  smbfs_smb_setftime1(struct smbnode *np, uint16_t fid,
  84	struct timespec *mtime,	struct timespec *atime,
  85	struct smb_cred *scrp);
  86
  87int  smbfs_smb_setpattr1(struct smbnode *np,
  88	const char *name, int len, uint32_t attr,
  89	struct timespec *mtime, struct smb_cred *scrp);
  90
  91
  92/*
  93 * Todo: locking over-the-wire
  94 */
  95#ifdef APPLE
  96
  97static int
  98smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid,
  99	offset_t start, uint64_t len, int largelock,
 100	struct smb_cred *scrp, uint32_t timeout)
 101{
 102	struct smb_share *ssp = np->n_mount->smi_share;
 103	struct smb_rq rq, *rqp = &rq;
 104	struct mbchain *mbp;
 105	uint8_t ltype = 0;
 106	int error;
 107
 108	/* Shared lock for n_fid use below. */
 109	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
 110
 111	/* After reconnect, n_fid is invalid */
 112	if (np->n_vcgenid != ssp->ss_vcgenid)
 113		return (ESTALE);
 114
 115	if (op == SMB_LOCK_SHARED)
 116		ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
 117	/* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */
 118	if (largelock)
 119		ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
 120	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
 121	if (error)
 122		return (error);
 123	smb_rq_getrequest(rqp, &mbp);
 124	smb_rq_wstart(rqp);
 125	mb_put_uint8(mbp, 0xff);	/* secondary command */
 126	mb_put_uint8(mbp, 0);		/* MBZ */
 127	mb_put_uint16le(mbp, 0);
 128	mb_put_uint16le(mbp, np->n_fid);
 129	mb_put_uint8(mbp, ltype);	/* locktype */
 130	mb_put_uint8(mbp, 0);		/* oplocklevel - 0 seems is NO_OPLOCK */
 131	mb_put_uint32le(mbp, timeout);	/* 0 nowait, -1 infinite wait */
 132	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
 133	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
 134	smb_rq_wend(rqp);
 135	smb_rq_bstart(rqp);
 136	mb_put_uint16le(mbp, pid);
 137	if (!largelock) {
 138		mb_put_uint32le(mbp, start);
 139		mb_put_uint32le(mbp, len);
 140	} else {
 141		mb_put_uint16le(mbp, 0); /* pad */
 142		mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
 143		mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
 144		mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
 145		mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
 146	}
 147	smb_rq_bend(rqp);
 148	/*
 149	 * Don't want to risk missing a successful
 150	 * unlock send or lock response, or we could
 151	 * lose track of an outstanding lock.
 152	 */
 153	if (op == SMB_LOCK_RELEASE)
 154		rqp->sr_flags |= SMBR_NOINTR_SEND;
 155	else
 156		rqp->sr_flags |= SMBR_NOINTR_RECV;
 157
 158	error = smb_rq_simple(rqp);
 159	smb_rq_done(rqp);
 160	return (error);
 161}
 162
 163int
 164smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
 165	offset_t start, uint64_t len,	int largelock,
 166	struct smb_cred *scrp, uint32_t timeout)
 167{
 168	struct smb_share *ssp = np->n_mount->smi_share;
 169
 170	if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
 171		/*
 172		 * TODO: use LOCK_BYTE_RANGE here.
 173		 */
 174		return (EINVAL);
 175
 176	/*
 177	 * XXX: compute largelock via:
 178	 * (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)?
 179	 */
 180	return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len,
 181	    largelock, scrp, timeout));
 182}
 183
 184#endif /* APPLE */
 185
 186/*
 187 * Helper for smbfs_getattr
 188 * Something like nfs_getattr_otw
 189 */
 190int
 191smbfs_smb_getfattr(
 192	struct smbnode *np,
 193	struct smbfattr *fap,
 194	struct smb_cred *scrp)
 195{
 196	int error;
 197
 198	/*
 199	 * This lock is necessary for FID-based calls.
 200	 * Lock may be writer (via open) or reader.
 201	 */
 202	ASSERT(np->r_lkserlock.count != 0);
 203
 204	/*
 205	 * Extended attribute directory or file.
 206	 */
 207	if (np->n_flag & N_XATTR) {
 208		error = smbfs_xa_getfattr(np, fap, scrp);
 209		return (error);
 210	}
 211
 212	error = smbfs_smb_trans2_query(np, fap, scrp, 0);
 213	if (error != EINVAL)
 214		return (error);
 215
 216	/* fallback */
 217	error = smbfs_smb_query_info(np, NULL, 0, fap, scrp);
 218
 219	return (error);
 220}
 221
 222/*
 223 * Common function for QueryFileInfo, QueryPathInfo.
 224 */
 225int
 226smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
 227	struct smb_cred *scrp, uint16_t infolevel)
 228{
 229	struct smb_share *ssp = np->n_mount->smi_share;
 230	struct smb_vc *vcp = SSTOVC(ssp);
 231	struct smb_t2rq *t2p;
 232	int error, svtz, timesok = 1;
 233	struct mbchain *mbp;
 234	struct mdchain *mdp;
 235	uint16_t cmd, date, time, wattr;
 236	uint64_t llongint, lsize;
 237	uint32_t size, dattr;
 238
 239	/*
 240	 * Shared lock for n_fid use below.
 241	 * See smbfs_smb_getfattr()
 242	 */
 243	ASSERT(np->r_lkserlock.count != 0);
 244
 245	/*
 246	 * If we have a valid open FID, use it.
 247	 */
 248	if ((np->n_fidrefs > 0) &&
 249	    (np->n_fid != SMB_FID_UNUSED) &&
 250	    (np->n_vcgenid == ssp->ss_vcgenid))
 251		cmd = SMB_TRANS2_QUERY_FILE_INFORMATION;
 252	else
 253		cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
 254
 255top:
 256	error = smb_t2_alloc(SSTOCP(ssp), cmd, 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
 268	if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION)
 269		mb_put_uint16le(mbp, np->n_fid);
 270
 271	mb_put_uint16le(mbp, infolevel);
 272
 273	if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) {
 274		mb_put_uint32le(mbp, 0);
 275		/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
 276		error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
 277		if (error) {
 278			smb_t2_done(t2p);
 279			return (error);
 280		}
 281	}
 282
 283	t2p->t2_maxpcount = 2;
 284	t2p->t2_maxdcount = vcp->vc_txmax;
 285	error = smb_t2_request(t2p);
 286	if (error) {
 287		smb_t2_done(t2p);
 288		/* Invalid info level?  Try fallback. */
 289		if (error == EINVAL &&
 290		    infolevel == SMB_QFILEINFO_ALL_INFO) {
 291			infolevel = SMB_QFILEINFO_STANDARD;
 292			goto top;
 293		}
 294		return (error);
 295	}
 296	mdp = &t2p->t2_rdata;
 297	svtz = vcp->vc_sopt.sv_tz;
 298	switch (infolevel) {
 299	case SMB_QFILEINFO_STANDARD:
 300		md_get_uint16le(mdp, &date);
 301		md_get_uint16le(mdp, &time);	/* creation time */
 302		smb_dos2unixtime(date, time, 0, svtz, &fap->fa_createtime);
 303		md_get_uint16le(mdp, &date);
 304		md_get_uint16le(mdp, &time);	/* access time */
 305		smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
 306		md_get_uint16le(mdp, &date);
 307		md_get_uint16le(mdp, &time);	/* modify time */
 308		smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
 309		md_get_uint32le(mdp, &size);	/* EOF position */
 310		fap->fa_size = size;
 311		md_get_uint32le(mdp, &size);	/* allocation size */
 312		fap->fa_allocsz = size;
 313		error = md_get_uint16le(mdp, &wattr);
 314		fap->fa_attr = wattr;
 315		timesok = 1;
 316		break;
 317	case SMB_QFILEINFO_ALL_INFO:
 318		timesok = 0;
 319		/* creation time */
 320		md_get_uint64le(mdp, &llongint);
 321		if (llongint)
 322			timesok++;
 323		smb_time_NT2local(llongint, &fap->fa_createtime);
 324
 325		/* last access time */
 326		md_get_uint64le(mdp, &llongint);
 327		if (llongint)
 328			timesok++;
 329		smb_time_NT2local(llongint, &fap->fa_atime);
 330
 331		/* last write time */
 332		md_get_uint64le(mdp, &llongint);
 333		if (llongint)
 334			timesok++;
 335		smb_time_NT2local(llongint, &fap->fa_mtime);
 336
 337		/* last change time */
 338		md_get_uint64le(mdp, &llongint);
 339		if (llongint)
 340			timesok++;
 341		smb_time_NT2local(llongint, &fap->fa_ctime);
 342
 343		/* attributes */
 344		md_get_uint32le(mdp, &dattr);
 345		fap->fa_attr = dattr;
 346
 347		/*
 348		 * 4-Byte alignment - discard
 349		 * Specs don't talk about this.
 350		 */
 351		md_get_uint32le(mdp, NULL);
 352		/* allocation size */
 353		md_get_uint64le(mdp, &lsize);
 354		fap->fa_allocsz = lsize;
 355		/* File size */
 356		error = md_get_uint64le(mdp, &lsize);
 357		fap->fa_size = lsize;
 358		break;
 359	default:
 360		SMBVDEBUG("unexpected info level %d\n", infolevel);
 361		error = EINVAL;
 362	}
 363	smb_t2_done(t2p);
 364	/*
 365	 * if all times are zero (observed with FAT on NT4SP6)
 366	 * then fall back to older info level
 367	 */
 368	if (!timesok) {
 369		if (infolevel == SMB_QFILEINFO_ALL_INFO) {
 370			infolevel = SMB_QFILEINFO_STANDARD;
 371			goto top;
 372		}
 373		error = EINVAL;
 374	}
 375	return (error);
 376}
 377
 378/*
 379 * Support functions for _qstreaminfo
 380 * Moved to smbfs_xattr.c
 381 */
 382
 383int
 384smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
 385	struct smb_cred *scrp)
 386{
 387	struct smb_t2rq *t2p;
 388	struct mbchain *mbp;
 389	struct mdchain *mdp;
 390	int error;
 391	uint32_t nlen;
 392
 393	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
 394	    scrp, &t2p);
 395	if (error)
 396		return (error);
 397	mbp = &t2p->t2_tparam;
 398	mb_init(mbp);
 399	mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO);
 400	t2p->t2_maxpcount = 4;
 401	t2p->t2_maxdcount = 4 * 3 + 512;
 402	error = smb_t2_request(t2p);
 403	if (error)
 404		goto out;
 405
 406	mdp = &t2p->t2_rdata;
 407	md_get_uint32le(mdp, &fsa->fsa_aflags);
 408	md_get_uint32le(mdp, &fsa->fsa_maxname);
 409	error = md_get_uint32le(mdp, &nlen);	/* fs name length */
 410	if (error)
 411		goto out;
 412
 413	/*
 414	 * Get the FS type name.
 415	 */
 416	bzero(fsa->fsa_tname, FSTYPSZ);
 417	if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
 418		uint16_t tmpbuf[FSTYPSZ];
 419		size_t tmplen, outlen;
 420
 421		if (nlen > sizeof (tmpbuf))
 422			nlen = sizeof (tmpbuf);
 423		error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
 424		tmplen = nlen / 2;	/* UCS-2 chars */
 425		outlen = FSTYPSZ - 1;
 426		(void) uconv_u16tou8(tmpbuf, &tmplen,
 427		    (uchar_t *)fsa->fsa_tname, &outlen,
 428		    UCONV_IN_LITTLE_ENDIAN);
 429	} else {
 430		if (nlen > (FSTYPSZ - 1))
 431			nlen = FSTYPSZ - 1;
 432		error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
 433	}
 434
 435	/*
 436	 * If fs_name starts with FAT, we can't set dates before 1980
 437	 */
 438	if (0 == strncmp(fsa->fsa_tname, "FAT", 3)) {
 439		SMB_SS_LOCK(ssp);
 440		ssp->ss_flags |= SMBS_FST_FAT;
 441		SMB_SS_UNLOCK(ssp);
 442	}
 443
 444out:
 445	smb_t2_done(t2p);
 446	return (0);
 447}
 448
 449int
 450smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
 451	struct smb_cred *scp)
 452{
 453	int error;
 454
 455	if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
 456		error = smbfs_smb_statfsLM2(ssp, sbp, scp);
 457	else
 458		error = smbfs_smb_statfsLM1(ssp, sbp, scp);
 459
 460	return (error);
 461}
 462
 463int
 464smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp,
 465	struct smb_cred *scrp)
 466{
 467	struct smb_t2rq *t2p;
 468	struct mbchain *mbp;
 469	struct mdchain *mdp;
 470	uint16_t bsize;
 471	uint32_t units, bpu, funits;
 472	uint64_t s, t, f;
 473	int error;
 474
 475	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
 476	    scrp, &t2p);
 477	if (error)
 478		return (error);
 479	mbp = &t2p->t2_tparam;
 480	mb_init(mbp);
 481	mb_put_uint16le(mbp, SMB_QFS_ALLOCATION);
 482	t2p->t2_maxpcount = 4;
 483	t2p->t2_maxdcount = 4 * 4 + 2;
 484	error = smb_t2_request(t2p);
 485	if (error)
 486		goto out;
 487
 488	mdp = &t2p->t2_rdata;
 489	md_get_uint32le(mdp, NULL);	/* fs id */
 490	md_get_uint32le(mdp, &bpu);
 491	md_get_uint32le(mdp, &units);
 492	md_get_uint32le(mdp, &funits);
 493	error = md_get_uint16le(mdp, &bsize);
 494	if (error)
 495		goto out;
 496	s = bsize;
 497	s *= bpu;
 498	t = units;
 499	f = funits;
 500	/*
 501	 * Don't allow over-large blocksizes as they determine
 502	 * Finder List-view size granularities.  On the other
 503	 * hand, we mustn't let the block count overflow the
 504	 * 31 bits available.
 505	 */
 506	while (s > 16 * 1024) {
 507		if (t > LONG_MAX)
 508			break;
 509		s /= 2;
 510		t *= 2;
 511		f *= 2;
 512	}
 513	while (t > LONG_MAX) {
 514		t /= 2;
 515		f /= 2;
 516		s *= 2;
 517	}
 518	sbp->f_bsize  = (ulong_t)s;	/* file system block size */
 519	sbp->f_blocks = t;	/* total data blocks in file system */
 520	sbp->f_bfree  = f;	/* free blocks in fs */
 521	sbp->f_bavail = f;	/* free blocks avail to non-superuser */
 522	sbp->f_files  = (-1);	/* total file nodes in file system */
 523	sbp->f_ffree  = (-1);	/* free file nodes in fs */
 524
 525out:
 526	smb_t2_done(t2p);
 527	return (0);
 528}
 529
 530int
 531smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp,
 532	struct smb_cred *scrp)
 533{
 534	struct smb_rq rq, *rqp = &rq;
 535	struct mdchain *mdp;
 536	uint16_t units, bpu, bsize, funits;
 537	uint64_t s, t, f;
 538	int error;
 539
 540	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
 541	    scrp);
 542	if (error)
 543		return (error);
 544	smb_rq_wstart(rqp);
 545	smb_rq_wend(rqp);
 546	smb_rq_bstart(rqp);
 547	smb_rq_bend(rqp);
 548	error = smb_rq_simple(rqp);
 549	if (error)
 550		goto out;
 551
 552	smb_rq_getreply(rqp, &mdp);
 553	md_get_uint16le(mdp, &units);
 554	md_get_uint16le(mdp, &bpu);
 555	md_get_uint16le(mdp, &bsize);
 556	error = md_get_uint16le(mdp, &funits);
 557	if (error)
 558		goto out;
 559	s = bsize;
 560	s *= bpu;
 561	t = units;
 562	f = funits;
 563	/*
 564	 * Don't allow over-large blocksizes as they determine
 565	 * Finder List-view size granularities.  On the other
 566	 * hand, we mustn't let the block count overflow the
 567	 * 31 bits available.
 568	 */
 569	while (s > 16 * 1024) {
 570		if (t > LONG_MAX)
 571			break;
 572		s /= 2;
 573		t *= 2;
 574		f *= 2;
 575	}
 576	while (t > LONG_MAX) {
 577		t /= 2;
 578		f /= 2;
 579		s *= 2;
 580	}
 581	sbp->f_bsize = (ulong_t)s;	/* file system block size */
 582	sbp->f_blocks = t;	/* total data blocks in file system */
 583	sbp->f_bfree = f;	/* free blocks in fs */
 584	sbp->f_bavail = f;	/* free blocks avail to non-superuser */
 585	sbp->f_files = (-1);		/* total file nodes in file system */
 586	sbp->f_ffree = (-1);		/* free file nodes in fs */
 587
 588out:
 589	smb_rq_done(rqp);
 590	return (0);
 591}
 592
 593int
 594smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
 595			struct smb_cred *scrp)
 596{
 597	struct smb_t2rq *t2p;
 598	struct smb_vc *vcp = SSTOVC(ssp);
 599	struct mbchain *mbp;
 600	int error;
 601
 602	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
 603	    scrp, &t2p);
 604	if (error)
 605		return (error);
 606	mbp = &t2p->t2_tparam;
 607	mb_init(mbp);
 608	mb_put_uint16le(mbp, fid);
 609	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
 610		mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
 611	else
 612		mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO);
 613	mb_put_uint16le(mbp, 0); /* pad */
 614	mbp = &t2p->t2_tdata;
 615	mb_init(mbp);
 616	mb_put_uint64le(mbp, newsize);
 617	t2p->t2_maxpcount = 2;
 618	t2p->t2_maxdcount = 0;
 619	error = smb_t2_request(t2p);
 620	smb_t2_done(t2p);
 621	return (error);
 622}
 623
 624/*ARGSUSED*/
 625int
 626smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp,
 627	const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite)
 628{
 629	struct smb_t2rq *t2p;
 630	struct smb_share *ssp = np->n_mount->smi_share;
 631	struct smb_vc *vcp = SSTOVC(ssp);
 632	struct mbchain *mbp;
 633	int32_t *ucslenp;
 634	int error, cerror;
 635	uint16_t fid = 0;
 636
 637	/* Shared lock for n_fid use below. */
 638	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
 639
 640	/* After reconnect, n_fid is invalid */
 641	if (np->n_vcgenid != ssp->ss_vcgenid)
 642		return (ESTALE);
 643
 644	if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
 645		return (ENOTSUP);
 646	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
 647	    scrp, &t2p);
 648	if (error)
 649		return (error);
 650	if (tdnp) {
 651		error = smbfs_smb_tmpopen(tdnp, SA_RIGHT_FILE_READ_DATA, scrp,
 652		    &fid);
 653		if (error)
 654			goto exit;
 655	}
 656	mbp = &t2p->t2_tparam;
 657	mb_init(mbp);
 658	mb_put_uint16le(mbp, np->n_fid);
 659	mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
 660	mb_put_uint16le(mbp, 0); /* reserved, nowadays */
 661	mbp = &t2p->t2_tdata;
 662	mb_init(mbp);
 663	mb_put_uint32le(mbp, overwrite);
 664	mb_put_uint16le(mbp, fid); /* base for tname */
 665	mb_put_uint16le(mbp, 0); /* part of a 32bit fid? */
 666	ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
 667	mbp->mb_count = 0;
 668	error = smb_put_dstring(mbp, vcp, tname, SMB_CS_NONE);
 669	if (error)
 670		goto exit;
 671	mbp->mb_count--;	/* don't count the null */
 672	*ucslenp = htolel(mbp->mb_count);
 673	t2p->t2_maxpcount = 2;
 674	t2p->t2_maxdcount = 0;
 675	error = smb_t2_request(t2p);
 676exit:
 677	if (fid) {
 678		cerror = smbfs_smb_tmpclose(tdnp, fid, scrp);
 679		if (cerror)
 680			SMBVDEBUG("error %d closing %s\n",
 681			    cerror, tdnp->n_rpath);
 682	}
 683	smb_t2_done(t2p);
 684	return (error);
 685}
 686
 687int
 688smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
 689{
 690	struct smb_share *ssp = np->n_mount->smi_share;
 691	struct smb_rq rq, *rqp = &rq;
 692	struct mbchain *mbp;
 693	int error;
 694
 695	/* Shared lock for n_fid use below. */
 696	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
 697
 698	if (!(np->n_flag & NFLUSHWIRE))
 699		return (0);
 700	if (np->n_fidrefs == 0)
 701		return (0); /* not open */
 702
 703	/* After reconnect, n_fid is invalid */
 704	if (np->n_vcgenid != ssp->ss_vcgenid)
 705		return (ESTALE);
 706
 707	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
 708	if (error)
 709		return (error);
 710	smb_rq_getrequest(rqp, &mbp);
 711	smb_rq_wstart(rqp);
 712	mb_put_uint16le(mbp, np->n_fid);
 713	smb_rq_wend(rqp);
 714	smb_rq_bstart(rqp);
 715	smb_rq_bend(rqp);
 716	error = smb_rq_simple(rqp);
 717	smb_rq_done(rqp);
 718	if (!error) {
 719		mutex_enter(&np->r_statelock);
 720		np->n_flag &= ~NFLUSHWIRE;
 721		mutex_exit(&np->r_statelock);
 722	}
 723	return (error);
 724}
 725
 726int
 727smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
 728			struct smb_cred *scrp)
 729{
 730	struct smb_share *ssp = np->n_mount->smi_share;
 731	struct smb_rq rq, *rqp = &rq;
 732	struct mbchain *mbp;
 733	int error;
 734
 735	if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
 736		/*
 737		 * This call knows about 64-bit offsets.
 738		 */
 739		error = smbfs_smb_seteof(ssp, fid, newsize, scrp);
 740		if (!error) {
 741			mutex_enter(&np->r_statelock);
 742			np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
 743			mutex_exit(&np->r_statelock);
 744			return (0);
 745		}
 746	}
 747
 748	/*
 749	 * OK, so fallback to SMB_COM_WRITE, but note:
 750	 * it only supports 32-bit file offsets.
 751	 */
 752	if (newsize > UINT32_MAX)
 753		return (EFBIG);
 754
 755	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp);
 756	if (error)
 757		return (error);
 758	smb_rq_getrequest(rqp, &mbp);
 759	smb_rq_wstart(rqp);
 760	mb_put_uint16le(mbp, fid);
 761	mb_put_uint16le(mbp, 0);
 762	mb_put_uint32le(mbp, newsize);
 763	mb_put_uint16le(mbp, 0);
 764	smb_rq_wend(rqp);
 765	smb_rq_bstart(rqp);
 766	mb_put_uint8(mbp, SMB_DT_DATA);
 767	mb_put_uint16le(mbp, 0);
 768	smb_rq_bend(rqp);
 769	error = smb_rq_simple(rqp);
 770	smb_rq_done(rqp);
 771	mutex_enter(&np->r_statelock);
 772	np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
 773	mutex_exit(&np->r_statelock);
 774	return (error);
 775}
 776
 777/*
 778 * Old method for getting file attributes.
 779 */
 780int
 781smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
 782	struct smbfattr *fap, struct smb_cred *scrp)
 783{
 784	struct smb_rq rq, *rqp = &rq;
 785	struct smb_share *ssp = np->n_mount->smi_share;
 786	struct mbchain *mbp;
 787	struct mdchain *mdp;
 788	uint8_t wc;
 789	int error;
 790	uint16_t wattr;
 791	uint32_t longint;
 792
 793	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp);
 794	if (error)
 795		return (error);
 796	smb_rq_getrequest(rqp, &mbp);
 797	smb_rq_wstart(rqp);
 798	smb_rq_wend(rqp);
 799	smb_rq_bstart(rqp);
 800	mb_put_uint8(mbp, SMB_DT_ASCII);
 801
 802	error = smbfs_fullpath(mbp, SSTOVC(ssp), np,
 803	    name, &nmlen, '\\');
 804	if (error)
 805		goto out;
 806	smb_rq_bend(rqp);
 807	error = smb_rq_simple(rqp);
 808	if (error)
 809		goto out;
 810	smb_rq_getreply(rqp, &mdp);
 811	error = md_get_uint8(mdp, &wc);
 812	if (error)
 813		goto out;
 814	if (wc != 10) {
 815		error = EBADRPC;
 816		goto out;
 817	}
 818	md_get_uint16le(mdp, &wattr);
 819	fap->fa_attr = wattr;
 820	/*
 821	 * Be careful using the time returned here, as
 822	 * with FAT on NT4SP6, at least, the time returned is low
 823	 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
 824	 * over about every seven minutes!
 825	 */
 826	md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
 827	smb_time_server2local(longint,
 828	    SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime);
 829	error = md_get_uint32le(mdp, &longint);
 830	fap->fa_size = longint;
 831
 832out:
 833	smb_rq_done(rqp);
 834	return (error);
 835}
 836
 837/*
 838 * Set DOS file attributes. mtime should be NULL for dialects above lm10
 839 */
 840int
 841smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len,
 842	uint32_t attr, struct timespec *mtime,
 843	struct smb_cred *scrp)
 844{
 845	struct smb_rq rq, *rqp = &rq;
 846	struct smb_share *ssp = np->n_mount->smi_share;
 847	struct mbchain *mbp;
 848	long time;
 849	int error, svtz;
 850
 851	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp);
 852	if (error)
 853		return (error);
 854	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
 855	smb_rq_getrequest(rqp, &mbp);
 856	smb_rq_wstart(rqp);
 857	mb_put_uint16le(mbp, (uint16_t)attr);
 858	if (mtime) {
 859		smb_time_local2server(mtime, svtz, &time);
 860	} else
 861		time = 0;
 862	mb_put_uint32le(mbp, time);		/* mtime */
 863	mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
 864	smb_rq_wend(rqp);
 865	smb_rq_bstart(rqp);
 866	mb_put_uint8(mbp, SMB_DT_ASCII);
 867
 868	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &len, '\\');
 869	if (error)
 870		goto out;
 871	mb_put_uint8(mbp, SMB_DT_ASCII);
 872	if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
 873		mb_put_padbyte(mbp);
 874		mb_put_uint8(mbp, 0);	/* 1st byte NULL Unicode char */
 875	}
 876	mb_put_uint8(mbp, 0);
 877	smb_rq_bend(rqp);
 878	error = smb_rq_simple(rqp);
 879
 880out:
 881	smb_rq_done(rqp);
 882	return (error);
 883}
 884
 885int
 886smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
 887			struct smb_cred *scrp)
 888{
 889	struct smbfattr fa;
 890	int error;
 891	uint32_t attr;
 892
 893	error = smbfs_smb_query_info(np, name, len, &fa, scrp);
 894	attr = fa.fa_attr;
 895	if (!error && !(attr & SMB_FA_HIDDEN)) {
 896		attr |= SMB_FA_HIDDEN;
 897		error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
 898	}
 899	return (error);
 900}
 901
 902
 903int
 904smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
 905			struct smb_cred *scrp)
 906{
 907	struct smbfattr fa;
 908	uint32_t attr;
 909	int error;
 910
 911	error = smbfs_smb_query_info(np, name, len, &fa, scrp);
 912	attr = fa.fa_attr;
 913	if (!error && (attr & SMB_FA_HIDDEN)) {
 914		attr &= ~SMB_FA_HIDDEN;
 915		error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
 916	}
 917	return (error);
 918}
 919
 920/*
 921 * Set file attributes (optionally: DOS attr, atime, mtime)
 922 * either by open FID or by path name (FID == -1).
 923 */
 924int
 925smbfs_smb_setfattr(
 926	struct smbnode *np,
 927	int fid,
 928	uint32_t attr,
 929	struct timespec *mtime,
 930	struct timespec *atime,
 931	struct smb_cred *scrp)
 932{
 933	struct smb_share *ssp = np->n_mount->smi_share;
 934	struct smb_vc *vcp = SSTOVC(ssp);
 935	int error;
 936
 937	/*
 938	 * Normally can use the trans2 call.
 939	 */
 940	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
 941		error = smbfs_smb_setfattrNT(np, fid,
 942		    attr, mtime, atime, scrp);
 943		return (error);
 944	}
 945
 946	/*
 947	 * Fall-back for older protocols.
 948	 */
 949	if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) {
 950		error = smbfs_smb_setftime1(np, fid,
 951		    mtime, atime, scrp);
 952		return (error);
 953	}
 954	error = smbfs_smb_setpattr1(np, NULL, 0,
 955	    attr, mtime, scrp);
 956	return (error);
 957}
 958
 959/*
 960 * Set file atime and mtime. Isn't supported by core dialect.
 961 */
 962int
 963smbfs_smb_setftime1(
 964	struct smbnode *np,
 965	uint16_t fid,
 966	struct timespec *mtime,
 967	struct timespec *atime,
 968	struct smb_cred *scrp)
 969{
 970	struct smb_rq rq, *rqp = &rq;
 971	struct smb_share *ssp = np->n_mount->smi_share;
 972	struct mbchain *mbp;
 973	uint16_t date, time;
 974	int error, tzoff;
 975
 976	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp);
 977	if (error)
 978		return (error);
 979
 980	tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
 981	smb_rq_getrequest(rqp, &mbp);
 982	smb_rq_wstart(rqp);
 983	mb_put_uint16le(mbp, fid);
 984	mb_put_uint32le(mbp, 0);		/* creation time */
 985
 986	if (atime)
 987		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
 988	else
 989		time = date = 0;
 990	mb_put_uint16le(mbp, date);
 991	mb_put_uint16le(mbp, time);
 992	if (mtime)
 993		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
 994	else
 995		time = date = 0;
 996	mb_put_uint16le(mbp, date);
 997	mb_put_uint16le(mbp, time);
 998	smb_rq_wend(rqp);
 999	smb_rq_bstart(rqp);
1000	smb_rq_bend(rqp);
1001	error = smb_rq_simple(rqp);
1002	SMBVDEBUG("%d\n", error);
1003	smb_rq_done(rqp);
1004	return (error);
1005}
1006
1007/*
1008 * Set DOS file attributes, either via open FID or by path name.
1009 * Looks like this call can be used only if CAP_NT_SMBS bit is on.
1010 *
1011 * When setting via path (fid == -1):
1012 * *BASIC_INFO works with Samba, but Win2K servers say it is an
1013 * invalid information level on a SET_PATH_INFO.  Note Win2K does
1014 * support *BASIC_INFO on a SET_FILE_INFO, and they support the
1015 * equivalent *BASIC_INFORMATION on SET_PATH_INFO.  Go figure.
1016 */
1017int
1018smbfs_smb_setfattrNT(
1019	struct smbnode *np,
1020	int fid,		/* if fid == -1, set by path */
1021	uint32_t attr,
1022	struct timespec *mtime,
1023	struct timespec *atime,
1024	struct smb_cred *scrp)
1025{
1026	struct smb_t2rq *t2p;
1027	struct smb_share *ssp = np->n_mount->smi_share;
1028	struct smb_vc *vcp = SSTOVC(ssp);
1029	struct mbchain *mbp;
1030	uint64_t tm;
1031	int error;
1032	uint16_t cmd, level;
1033
1034	if (fid == -1) {
1035		cmd = SMB_TRANS2_SET_PATH_INFORMATION;
1036	} else {
1037		if (fid > UINT16_MAX)
1038			return (EINVAL);
1039		cmd = SMB_TRANS2_SET_FILE_INFORMATION;
1040	}
1041	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
1042		level = SMB_SFILEINFO_BASIC_INFORMATION;
1043	else
1044		level = SMB_SFILEINFO_BASIC_INFO;
1045
1046	error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
1047	if (error)
1048		return (error);
1049
1050	mbp = &t2p->t2_tparam;
1051	mb_init(mbp);
1052
1053	if (cmd == SMB_TRANS2_SET_FILE_INFORMATION)
1054		mb_put_uint16le(mbp, fid);
1055
1056	mb_put_uint16le(mbp, level);
1057	mb_put_uint32le(mbp, 0);		/* MBZ */
1058
1059	if (cmd == SMB_TRANS2_SET_PATH_INFORMATION) {
1060		error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
1061		if (error != 0)
1062			goto out;
1063	}
1064
1065	/* FAT file systems don't support dates earlier than 1980. */
1066
1067	mbp = &t2p->t2_tdata;
1068	mb_init(mbp);
1069	mb_put_uint64le(mbp, 0);		/* creation time */
1070	if (atime) {
1071		smb_time_local2NT(atime, &tm);
1072		if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
1073		    tm < NT1980)
1074			tm = NT1980;
1075	} else
1076		tm = 0;
1077	mb_put_uint64le(mbp, tm);		/* access time */
1078	if (mtime) {
1079		smb_time_local2NT(mtime, &tm);
1080		if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
1081		    tm < NT1980)
1082			tm = NT1980;
1083	} else
1084		tm = 0;
1085	mb_put_uint64le(mbp, tm);		/* last write time */
1086	mb_put_uint64le(mbp, 0);		/* ctime (no change) */
1087	mb_put_uint32le(mbp, attr);
1088	mb_put_uint32le(mbp, 0);		/* padding */
1089	t2p->t2_maxpcount = 2;
1090	t2p->t2_maxdcount = 0;
1091	error = smb_t2_request(t2p);
1092out:
1093	smb_t2_done(t2p);
1094	return (error);
1095}
1096
1097/*
1098 * Modern create/open of file or directory.
1099 *
1100 * If disp is ..._DISP_OPEN, or ...DISP_OPEN_IF, or...
1101 * then this is an open attempt, and:
1102 *   If xattr then name is the stream to be opened at np,
1103 *   Else np should be opened.
1104 *   ...we won't touch *fidp,
1105 *   ...we will set or clear *attrcacheupdated.
1106 * Else this is a creation attempt, and:
1107 *   If xattr then name is the stream to create at np,
1108 *   Else name is the thing to create under directory np.
1109 *   ...we will return *fidp,
1110 *   ...we won't touch *attrcacheupdated.
1111 *
1112 * Note, We use: disp = ...OPEN_IF, ...OVERWRITE_IF, etc.
1113 * now too, which may or may not create a new object.
1114 */
1115int
1116smbfs_smb_ntcreatex(
1117	struct smbnode *np,
1118	const char *name,
1119	int nmlen,
1120	int xattr,		/* is named stream? */
1121	uint32_t req_acc,	/* requested access */
1122	uint32_t efa,		/* ext. file attrs (DOS attr +) */
1123	uint32_t share_acc,
1124	uint32_t disp,		/* open disposition */
1125	uint32_t createopt,	/* NTCREATEX_OPTIONS_ */
1126	struct smb_cred *scrp,
1127	uint16_t *fidp,
1128	uint32_t *cr_act_p,	/* create action */
1129	struct smbfattr *fap)	/* optional */
1130{
1131	struct smb_rq rq, *rqp = &rq;
1132	struct smb_share *ssp = np->n_mount->smi_share;
1133	struct smb_vc *vcp = SSTOVC(ssp);
1134	struct mbchain *mbp;
1135	struct mdchain *mdp;
1136	struct smbfattr fa;
1137	uint8_t wc;
1138	uint32_t longint, createact;
1139	uint64_t llongint;
1140	int error;
1141	uint16_t fid, *namelenp;
1142
1143	bzero(&fa, sizeof (fa));
1144	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp);
1145	if (error)
1146		return (error);
1147	smb_rq_getrequest(rqp, &mbp);
1148	smb_rq_wstart(rqp);
1149	mb_put_uint8(mbp, 0xff);	/* secondary command */
1150	mb_put_uint8(mbp, 0);		/* MBZ */
1151	mb_put_uint16le(mbp, 0);	/* offset to next command (none) */
1152	mb_put_uint8(mbp, 0);		/* MBZ */
1153	namelenp = (uint16_t *)mb_reserve(mbp, sizeof (uint16_t));
1154	/*
1155	 * XP to a W2K Server does not use NTCREATEX_FLAGS_OPEN_DIRECTORY
1156	 * for creating nor for opening a directory.  Samba ignores the bit.
1157	 */
1158	mb_put_uint32le(mbp, 0);	/* NTCREATEX_FLAGS_* */
1159	mb_put_uint32le(mbp, 0);	/* FID - basis for path if not root */
1160	mb_put_uint32le(mbp, req_acc);
1161	mb_put_uint64le(mbp, 0);	/* "initial allocation size" */
1162	mb_put_uint32le(mbp, efa);
1163	mb_put_uint32le(mbp, share_acc);
1164	mb_put_uint32le(mbp, disp);
1165	mb_put_uint32le(mbp, createopt);
1166	mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */
1167	mb_put_uint8(mbp, 0);   /* security flags (?) */
1168	smb_rq_wend(rqp);
1169	smb_rq_bstart(rqp);
1170
1171	if (name == NULL)
1172		nmlen = 0;
1173	error = smbfs_fullpath(mbp, vcp, np, name, &nmlen,
1174	    xattr ? ':' : '\\');
1175	if (error)
1176		goto done;
1177	*namelenp = htoles(nmlen); /* includes null */
1178	smb_rq_bend(rqp);
1179	/*
1180	 * Don't want to risk missing a successful
1181	 * open response, or we could "leak" FIDs.
1182	 */
1183	rqp->sr_flags |= SMBR_NOINTR_RECV;
1184	error = smb_rq_simple_timed(rqp, smb_timo_open);
1185	if (error)
1186		goto done;
1187	smb_rq_getreply(rqp, &mdp);
1188	/*
1189	 * spec says 26 for word count, but 34 words are defined
1190	 * and observed from win2000
1191	 */
1192	error = md_get_uint8(mdp, &wc);
1193	if (error)
1194		goto done;
1195	if (wc != 26 && wc != 34 && wc != 42) {
1196		error = EBADRPC;
1197		goto done;
1198	}
1199	md_get_uint8(mdp, NULL);		/* secondary cmd */
1200	md_get_uint8(mdp, NULL);		/* mbz */
1201	md_get_uint16le(mdp, NULL);		/* andxoffset */
1202	md_get_uint8(mdp, NULL);		/* oplock lvl granted */
1203	md_get_uint16le(mdp, &fid);		/* file ID */
1204	md_get_uint32le(mdp, &createact);	/* create_action */
1205
1206	md_get_uint64le(mdp, &llongint);	/* creation time */
1207	smb_time_NT2local(llongint, &fa.fa_createtime);
1208	md_get_uint64le(mdp, &llongint);	/* access time */
1209	smb_time_NT2local(llongint, &fa.fa_atime);
1210	md_get_uint64le(mdp, &llongint);	/* write time */
1211	smb_time_NT2local(llongint, &fa.fa_mtime);
1212	md_get_uint64le(mdp, &llongint);	/* change time */
1213	smb_time_NT2local(llongint, &fa.fa_ctime);
1214
1215	md_get_uint32le(mdp, &longint);		/* attributes */
1216	fa.fa_attr = longint;
1217
1218	md_get_uint64le(mdp, &llongint);	/* allocation size */
1219	fa.fa_allocsz = llongint;
1220
1221	md_get_uint64le(mdp, &llongint);	/* EOF position */
1222	fa.fa_size = llongint;
1223
1224	error = md_get_uint16le(mdp, NULL);	/* file type */
1225	/* other stuff we don't care about */
1226
1227done:
1228	smb_rq_done(rqp);
1229	if (error)
1230		return (error);
1231
1232	if (fidp)
1233		*fidp = fid;
1234	if (cr_act_p)
1235		*cr_act_p = createact;
1236	if (fap)
1237		*fap = fa; /* struct copy */
1238
1239	return (0);
1240}
1241
1242static uint32_t
1243smb_mode2rights(int mode)
1244{
1245	mode = mode & SMB_AM_OPENMODE;
1246	uint32_t rights =
1247	    STD_RIGHT_SYNCHRONIZE_ACCESS |
1248	    STD_RIGHT_READ_CONTROL_ACCESS;
1249
1250	if ((mode == SMB_AM_OPENREAD) ||
1251	    (mode == SMB_AM_OPENRW)) {
1252		rights |=
1253		    SA_RIGHT_FILE_READ_ATTRIBUTES |
1254		    SA_RIGHT_FILE_READ_DATA;
1255	}
1256
1257	if ((mode == SMB_AM_OPENWRITE) ||
1258	    (mode == SMB_AM_OPENRW)) {
1259		rights |=
1260		    SA_RIGHT_FILE_WRITE_ATTRIBUTES |
1261		    SA_RIGHT_FILE_APPEND_DATA |
1262		    SA_RIGHT_FILE_WRITE_DATA;
1263	}
1264
1265	if (mode == SMB_AM_OPENEXEC) {
1266		rights |=
1267		    SA_RIGHT_FILE_READ_ATTRIBUTES |
1268		    SA_RIGHT_FILE_EXECUTE;
1269	}
1270
1271	return (rights);
1272}
1273
1274static int
1275smb_rights2mode(uint32_t rights)
1276{
1277	int accmode = SMB_AM_OPENEXEC; /* our fallback */
1278
1279	if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD |
1280	    SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES |
1281	    SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS |
1282	    STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS))
1283		accmode = SMB_AM_OPENWRITE;
1284	if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES |
1285	    SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS))
1286		accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD
1287		    : SMB_AM_OPENRW;
1288	return (accmode);
1289}
1290
1291static int
1292smbfs_smb_oldopen(
1293	struct smbnode *np,
1294	const char *name,
1295	int nmlen,
1296	int xattr,
1297	int accmode,
1298	struct smb_cred *scrp,
1299	uint16_t *fidp,
1300	uint16_t *granted_mode_p,
1301	smbfattr_t *fap)
1302{
1303	struct smb_rq rq, *rqp = &rq;
1304	struct smb_share *ssp = np->n_mount->smi_share;
1305	struct smb_vc *vcp = SSTOVC(ssp);
1306	struct mbchain *mbp;
1307	struct mdchain *mdp;
1308	struct smbfattr fa;
1309	uint8_t wc;
1310	uint16_t wattr;
1311	uint32_t longint;
1312	int error;
1313
1314	bzero(&fa, sizeof (fa));
1315
1316	/*
1317	 * XXX: move to callers...
1318	 *
1319	 * Use DENYNONE to give unixy semantics of permitting
1320	 * everything not forbidden by permissions.  Ie denial
1321	 * is up to server with clients/openers needing to use
1322	 * advisory locks for further control.
1323	 */
1324	accmode |= SMB_SM_DENYNONE;
1325
1326	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp);
1327	if (error)
1328		return (error);
1329	smb_rq_getrequest(rqp, &mbp);
1330	smb_rq_wstart(rqp);
1331	mb_put_uint16le(mbp, accmode);
1332	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY |
1333	    SMB_FA_DIR);
1334	smb_rq_wend(rqp);
1335	smb_rq_bstart(rqp);
1336	mb_put_uint8(mbp, SMB_DT_ASCII);
1337
1338	error = smbfs_fullpath(mbp, vcp, np, name, &nmlen,
1339	    xattr ? ':' : '\\');
1340	if (error)
1341		goto done;
1342	smb_rq_bend(rqp);
1343	/*
1344	 * Don't want to risk missing a successful
1345	 * open response, or we could "leak" FIDs.
1346	 */
1347	rqp->sr_flags |= SMBR_NOINTR_RECV;
1348	error = smb_rq_simple_timed(rqp, smb_timo_open);
1349	if (error)
1350		goto done;
1351	smb_rq_getreply(rqp, &mdp);
1352	/*
1353	 * 8/2002 a DAVE server returned wc of 15 so we ignore that.
1354	 * (the actual packet length and data was correct)
1355	 */
1356	error = md_get_uint8(mdp, &wc);
1357	if (error)
1358		goto done;
1359	if (wc != 7 && wc != 15) {
1360		error = EBADRPC;
1361		goto done;
1362	}
1363	md_get_uint16le(mdp, fidp);
1364	md_get_uint16le(mdp, &wattr);
1365	fa.fa_attr = wattr;
1366	/*
1367	 * Be careful using the time returned here, as
1368	 * with FAT on NT4SP6, at least, the time returned is low
1369	 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
1370	 * over about every seven minutes!
1371	 */
1372	md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
1373	smb_time_server2local(longint, vcp->vc_sopt.sv_tz, &fa.fa_mtime);
1374	md_get_uint32le(mdp, &longint);
1375	fa.fa_size = longint;
1376	error = md_get_uint16le(mdp, granted_mode_p);
1377
1378done:
1379	smb_rq_done(rqp);
1380	if (error)
1381		return (error);
1382
1383	if (fap)
1384		*fap = fa; /* struct copy */
1385
1386	return (0);
1387}
1388
1389int
1390smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
1391			uint16_t *fidp)
1392{
1393	struct smb_share *ssp = np->n_mount->smi_share;
1394	struct smb_vc *vcp = SSTOVC(ssp);
1395	int accmode, error;
1396
1397	/* Shared lock for n_fid use below. */
1398	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1399
1400	/* Can we re-use n_fid? or must we open anew? */
1401	mutex_enter(&np->r_statelock);
1402	if (np->n_fidrefs > 0 &&
1403	    np->n_vcgenid == ssp->ss_vcgenid &&
1404	    (rights & np->n_rights) == rights) {
1405		np->n_fidrefs++;
1406		*fidp = np->n_fid;
1407		mutex_exit(&np->r_statelock);
1408		return (0);
1409	}
1410	mutex_exit(&np->r_statelock);
1411
1412	/* re-open an existing file. */
1413	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1414		error = smbfs_smb_ntcreatex(np,
1415		    NULL, 0, 0,	/* name nmlen xattr */
1416		    rights, SMB_EFA_NORMAL,
1417		    NTCREATEX_SHARE_ACCESS_ALL,
1418		    NTCREATEX_DISP_OPEN,
1419		    0, /* create options */
1420		    scrp, fidp,
1421		    NULL, NULL); /* cr_act_p fa_p */
1422		return (error);
1423	}
1424
1425	accmode = smb_rights2mode(rights);
1426	error = smbfs_smb_oldopen(np,
1427	    NULL, 0, 0, /* name nmlen xattr */
1428	    accmode, scrp,
1429	    fidp,
1430	    NULL, /* granted mode p */
1431	    NULL); /* fa p */
1432
1433	return (error);
1434}
1435
1436int
1437smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp)
1438{
1439	struct smb_share *ssp = np->n_mount->smi_share;
1440	int error = 0;
1441	uint16_t oldfid = SMB_FID_UNUSED;
1442
1443	/* Shared lock for n_fid use below. */
1444	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
1445
1446	mutex_enter(&np->r_statelock);
1447	if (fid == np->n_fid) {
1448		ASSERT(np->n_fidrefs > 0);
1449		if (--np->n_fidrefs == 0) {
1450			/*
1451			 * Don't expect to find the last reference
1452			 * here in tmpclose.  Hard to deal with as
1453			 * we don't have r_lkserlock exclusive.
1454			 * Will close oldfid below.
1455			 */
1456			oldfid = np->n_fid;
1457			np->n_fid = SMB_FID_UNUSED;
1458		}
1459	} else {
1460		/* Will close the passed fid. */
1461		oldfid = fid;
1462	}
1463	mutex_exit(&np->r_statelock);
1464
1465	if (oldfid != SMB_FID_UNUSED)
1466		error = smbfs_smb_close(ssp, oldfid, NULL, scrp);
1467
1468	return (error);
1469}
1470
1471int
1472smbfs_smb_open(
1473	struct smbnode *np,
1474	const char *name,
1475	int nmlen,
1476	int xattr,
1477	uint32_t rights,
1478	struct smb_cred *scrp,
1479	uint16_t *fidp,
1480	uint32_t *rightsp,
1481	smbfattr_t *fap)
1482{
1483	struct smb_share *ssp = np->n_mount->smi_share;
1484	struct smb_vc *vcp = SSTOVC(ssp);
1485	int accmode, error;
1486	uint16_t grantedmode;
1487
1488	/* open an existing file */
1489	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1490		error = smbfs_smb_ntcreatex(np,
1491		    name, nmlen, xattr,
1492		    rights, SMB_EFA_NORMAL,
1493		    NTCREATEX_SHARE_ACCESS_ALL,
1494		    NTCREATEX_DISP_OPEN,
1495		    0, /* create options */
1496		    scrp, fidp,
1497		    NULL, fap); /* cr_act_p fa_p */
1498		if (error != 0)
1499			return (error);
1500		*rightsp = rights;
1501		return (0);
1502	}
1503
1504	accmode = smb_rights2mode(rights);
1505	error = smbfs_smb_oldopen(np,
1506	    name, nmlen, xattr, accmode, scrp,
1507	    fidp, &grantedmode, fap);
1508	if (error != 0)
1509		return (error);
1510	*rightsp = smb_mode2rights(grantedmode);
1511	(void) smbfs_smb_getfattr(np, fap, scrp);
1512
1513	return (0);
1514}
1515
1516int
1517smbfs_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
1518	struct smb_cred *scrp)
1519{
1520	struct smb_rq rq, *rqp = &rq;
1521	struct mbchain *mbp;
1522	long time;
1523	int error;
1524
1525	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp);
1526	if (error)
1527		return (error);
1528	smb_rq_getrequest(rqp, &mbp);
1529	smb_rq_wstart(rqp);
1530	mb_put_uint16le(mbp, fid);
1531	if (mtime) {
1532		int sv_tz = SSTOVC(ssp)->vc_sopt.sv_tz;
1533		smb_time_local2server(mtime, sv_tz, &time);
1534	} else
1535		time = 0;
1536	mb_put_uint32le(mbp, time);
1537	smb_rq_wend(rqp);
1538	smb_rq_bstart(rqp);
1539	smb_rq_bend(rqp);
1540
1541	/*
1542	 * We don't really care about the result here, but we
1543	 * do need to make sure we send this out, or we could
1544	 * "leak" open file handles on interrupt or timeout.
1545	 * The NOINTR_SEND flag makes this request immune to
1546	 * interrupt or timeout until the send is done.
1547	 */
1548	rqp->sr_flags |= SMBR_NOINTR_SEND;
1549	error = smb_rq_simple(rqp);
1550	smb_rq_done(rqp);
1551	/*
1552	 * ENOTCONN isn't interesting - if the connection is closed,
1553	 * so are all our FIDs - and EIO is also not interesting,
1554	 * as it means a forced unmount was done. (was ENXIO)
1555	 * Also ETIME, which means we sent the request but gave up
1556	 * waiting before the response came back.
1557	 *
1558	 * Don't clog up the system log with warnings about these
1559	 * uninteresting failures on closes.
1560	 */
1561	switch (error) {
1562	case ENOTCONN:
1563	case ENXIO:
1564	case EIO:
1565	case ETIME:
1566		error = 0;
1567	}
1568	return (error);
1569}
1570
1571static int
1572smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen,
1573	int xattr, struct smb_cred *scrp, uint16_t *fidp)
1574{
1575	struct smb_rq rq, *rqp = &rq;
1576	struct smb_share *ssp = dnp->n_mount->smi_share;
1577	struct mbchain *mbp;
1578	struct mdchain *mdp;
1579	struct timespec ctime;
1580	uint8_t wc;
1581	long tm;
1582	int error;
1583	uint16_t attr = SMB_FA_ARCHIVE;
1584
1585	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp);
1586	if (error)
1587		return (error);
1588	smb_rq_getrequest(rqp, &mbp);
1589	smb_rq_wstart(rqp);
1590	if (name && *name == '.')
1591		attr |= SMB_FA_HIDDEN;
1592	mb_put_uint16le(mbp, attr);		/* attributes  */
1593	gethrestime(&ctime);
1594	smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
1595	mb_put_uint32le(mbp, tm);
1596	smb_rq_wend(rqp);
1597	smb_rq_bstart(rqp);
1598	mb_put_uint8(mbp, SMB_DT_ASCII);
1599	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &nmlen,
1600	    xattr ? ':' : '\\');
1601	if (error)
1602		goto out;
1603	smb_rq_bend(rqp);
1604	/*
1605	 * Don't want to risk missing a successful
1606	 * open response, or we could "leak" FIDs.
1607	 */
1608	rqp->sr_flags |= SMBR_NOINTR_RECV;
1609	error = smb_rq_simple_timed(rqp, smb_timo_open);
1610	if (error)
1611		goto out;
1612
1613	smb_rq_getreply(rqp, &mdp);
1614	md_get_uint8(mdp, &wc);
1615	if (wc != 1) {
1616		error = EBADRPC;
1617		goto out;
1618	}
1619	error = md_get_uint16le(mdp, fidp);
1620
1621out:
1622	smb_rq_done(rqp);
1623	return (error);
1624}
1625
1626int
1627smbfs_smb_create(
1628	struct smbnode *dnp,
1629	const char *name,
1630	int nmlen,
1631	int xattr,
1632	uint32_t disp,
1633	struct smb_cred *scrp,
1634	uint16_t *fidp)
1635{
1636	struct smb_share *ssp = dnp->n_mount->smi_share;
1637	struct smb_vc *vcp = SSTOVC(ssp);
1638	uint32_t efa, rights;
1639	int error;
1640
1641	/*
1642	 * At present the only access we might need is to WRITE data,
1643	 * and that only if we are creating a "symlink".  When/if the
1644	 * access needed gets more complex it should made a parameter
1645	 * and be set upstream.
1646	 */
1647	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1648		rights = SA_RIGHT_FILE_WRITE_DATA;
1649		efa = SMB_EFA_NORMAL;
1650		if (!xattr && name && *name == '.')
1651			efa = SMB_EFA_HIDDEN;
1652		error = smbfs_smb_ntcreatex(dnp,
1653		    name, nmlen, xattr, rights, efa,
1654		    NTCREATEX_SHARE_ACCESS_ALL,
1655		    disp, /* != NTCREATEX_DISP_OPEN */
1656		    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
1657		    scrp, fidp, NULL, NULL); /* cr_act_p fa_p */
1658		return (error);
1659	}
1660
1661	error = smbfs_smb_oldcreate(dnp, name, nmlen, xattr, scrp, fidp);
1662	return (error);
1663}
1664
1665int
1666smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name,
1667			int nmlen, int xattr)
1668{
1669	struct smb_rq rq, *rqp = &rq;
1670	struct smb_share *ssp = np->n_mount->smi_share;
1671	struct mbchain *mbp;
1672	int error;
1673
1674	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp);
1675	if (error)
1676		return (error);
1677	smb_rq_getrequest(rqp, &mbp);
1678	smb_rq_wstart(rqp);
1679	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
1680	smb_rq_wend(rqp);
1681	smb_rq_bstart(rqp);
1682	mb_put_uint8(mbp, SMB_DT_ASCII);
1683	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &nmlen,
1684	    xattr ? ':' : '\\');
1685	if (!error) {
1686		smb_rq_bend(rqp);
1687		error = smb_rq_simple(rqp);
1688	}
1689	smb_rq_done(rqp);
1690	return (error);
1691}
1692
1693int
1694smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
1695	const char *tname, int tnmlen, struct smb_cred *scrp)
1696{
1697	struct smb_rq rq, *rqp = &rq;
1698	struct smb_share *ssp = src->n_mount->smi_share;
1699	struct mbchain *mbp;
1700	int error;
1701	uint16_t fa;
1702	char sep;
1703
1704	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
1705	if (error)
1706		return (error);
1707	smb_rq_getrequest(rqp, &mbp);
1708	smb_rq_wstart(rqp);
1709	/* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
1710	fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
1711	fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
1712	mb_put_uint16le(mbp, fa);
1713	smb_rq_wend(rqp);
1714	smb_rq_bstart(rqp);
1715
1716	/*
1717	 * When we're not adding any component name, the
1718	 * passed sep is ignored, so just pass sep=0.
1719	 */
1720	mb_put_uint8(mbp, SMB_DT_ASCII);
1721	error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, 0);
1722	if (error)
1723		goto out;
1724
1725	/*
1726	 * After XATTR directories, separator is ":"
1727	 */
1728	sep = (src->n_flag & N_XATTR) ? ':' : '\\';
1729	mb_put_uint8(mbp, SMB_DT_ASCII);
1730	error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen, sep);
1731	if (error)
1732		goto out;
1733
1734	smb_rq_bend(rqp);
1735	error = smb_rq_simple(rqp);
1736out:
1737	smb_rq_done(rqp);
1738	return (error);
1739}
1740
1741int
1742smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
1743	const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp)
1744{
1745	struct smb_rq rq, *rqp = &rq;
1746	struct smb_share *ssp = src->n_mount->smi_share;
1747	struct mbchain *mbp;
1748	int error;
1749
1750	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp);
1751	if (error)
1752		return (error);
1753	smb_rq_getrequest(rqp, &mbp);
1754	smb_rq_wstart(rqp);
1755	mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
1756	mb_put_uint16le(mbp, 0x20);	/* delete target file */
1757	mb_put_uint16le(mbp, flags);
1758	smb_rq_wend(rqp);
1759	smb_rq_bstart(rqp);
1760	mb_put_uint8(mbp, SMB_DT_ASCII);
1761
1762	error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, '\\');
1763	if (error)
1764		goto out;
1765	mb_put_uint8(mbp, SMB_DT_ASCII);
1766	error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen, '\\');
1767	if (error)
1768		goto out;
1769	smb_rq_bend(rqp);
1770	error = smb_rq_simple(rqp);
1771
1772out:
1773	smb_rq_done(rqp);
1774	return (error);
1775}
1776
1777static int
1778smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len,
1779			struct smb_cred *scrp)
1780{
1781	struct smb_rq rq, *rqp = &rq;
1782	struct smb_share *ssp = dnp->n_mount->smi_share;
1783	struct mbchain *mbp;
1784	int error;
1785
1786	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp);
1787	if (error)
1788		return (error);
1789	smb_rq_getrequest(rqp, &mbp);
1790	smb_rq_wstart(rqp);
1791	smb_rq_wend(rqp);
1792	smb_rq_bstart(rqp);
1793	mb_put_uint8(mbp, SMB_DT_ASCII);
1794	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &len, '\\');
1795	if (!error) {
1796		smb_rq_bend(rqp);
1797		error = smb_rq_simple(rqp);
1798	}
1799	smb_rq_done(rqp);
1800	return (error);
1801}
1802
1803int
1804smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen,
1805		struct smb_cred *scrp)
1806{
1807	struct smb_share *ssp = dnp->n_mount->smi_share;
1808	struct smb_vc *vcp = SSTOVC(ssp);
1809	uint32_t rights;
1810	uint16_t fid;
1811	int error;
1812
1813	/*
1814	 * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
1815	 * just to be asking for something.  The rights==0 case could
1816	 * easily be broken on some old or unusual servers.
1817	 */
1818	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
1819		rights = SA_RIGHT_FILE_READ_DATA;
1820		error = smbfs_smb_ntcreatex(dnp,
1821		    name, nmlen, 0, /* xattr */
1822		    rights, SMB_EFA_DIRECTORY,
1823		    NTCREATEX_SHARE_ACCESS_ALL,
1824		    NTCREATEX_DISP_CREATE,
1825		    NTCREATEX_OPTIONS_DIRECTORY,
1826		    scrp, &fid, NULL, NULL); /* cr_act_p fa_p */
1827		if (error)
1828			return (error);
1829		(void) smbfs_smb_close(ssp, fid, NULL, scrp);
1830		return (0);
1831	}
1832
1833	error = smbfs_smb_oldmkdir(dnp, name, nmlen, scrp);
1834	return (error);
1835}
1836
1837int
1838smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp)
1839{
1840	struct smb_rq rq, *rqp = &rq;
1841	struct smb_share *ssp = np->n_mount->smi_share;
1842	struct mbchain *mbp;
1843	int error;
1844
1845	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp);
1846	if (error)
1847		return (error);
1848	smb_rq_getrequest(rqp, &mbp);
1849	smb_rq_wstart(rqp);
1850	smb_rq_wend(rqp);
1851	smb_rq_bstart(rqp);
1852	mb_put_uint8(mbp, SMB_DT_ASCII);
1853	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, NULL, '\\');
1854	if (!error) {
1855		smb_rq_bend(rqp);
1856		error = smb_rq_simple(rqp);
1857	}
1858	smb_rq_done(rqp);
1859	return (error);
1860}
1861
1862static int
1863smbfs_smb_search(struct smbfs_fctx *ctx)
1864{
1865	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
1866	struct smb_rq *rqp;
1867	struct mbchain *mbp;
1868	struct mdchain *mdp;
1869	uint8_t wc, bt;
1870	uint16_t ec, dlen, bc;
1871	int len, maxent, error, iseof = 0;
1872
1873	maxent = min(ctx->f_left,
1874	    (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN);
1875	if (ctx->f_rq) {
1876		smb_rq_done(ctx->f_rq);
1877		ctx->f_rq = NULL;
1878	}
1879	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH,
1880	    ctx->f_scred, &rqp);
1881	if (error)
1882		return (error);
1883	ctx->f_rq = rqp;
1884	smb_rq_getrequest(rqp, &mbp);
1885	smb_rq_wstart(rqp);
1886	mb_put_uint16le(mbp, maxent);	/* max entries to return */
1887	mb_put_uint16le(mbp, ctx->f_attrmask);
1888	smb_rq_wend(rqp);
1889	smb_rq_bstart(rqp);
1890	mb_put_uint8(mbp, SMB_DT_ASCII);	/* buffer format */
1891	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
1892		len = ctx->f_wclen;
1893		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard,
1894		    &len, '\\');
1895		if (error)
1896			return (error);
1897		mb_put_uint8(mbp, SMB_DT_VARIABLE);
1898		mb_put_uint16le(mbp, 0);	/* context length */
1899		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
1900	} else {
1901		if (SMB_UNICODE_STRINGS(vcp)) {
1902			mb_put_padbyte(mbp);
1903			mb_put_uint8(mbp, 0);
1904		}
1905		mb_put_uint8(mbp, 0);
1906		mb_put_uint8(mbp, SMB_DT_VARIABLE);
1907		mb_put_uint16le(mbp, SMB_SKEYLEN);
1908		mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
1909	}
1910	smb_rq_bend(rqp);
1911	error = smb_rq_simple(rqp);
1912	if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
1913		error = 0;
1914		iseof = 1;
1915		ctx->f_flags |= SMBFS_RDD_EOF;
1916	} else if (error)
1917		return (error);
1918	smb_rq_getreply(rqp, &mdp);
1919	error = md_get_uint8(mdp, &wc);
1920	if (error)
1921		return (error);
1922	if (wc != 1)
1923		return (iseof ? ENOENT : EBADRPC);
1924	md_get_uint16le(mdp, &ec);
1925	md_get_uint16le(mdp, &bc);
1926	md_get_uint8(mdp, &bt);
1927	error = md_get_uint16le(mdp, &dlen);
1928	if (error)
1929		return (error);
1930	if (ec == 0)
1931		return (ENOENT);
1932	ctx->f_ecnt = ec;
1933	if (bc < 3)
1934		return (EBADRPC);
1935	bc -= 3;
1936	if (bt != SMB_DT_VARIABLE)
1937		return (EBADRPC);
1938	if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
1939		return (EBADRPC);
1940	return (0);
1941}
1942
1943
1944/*ARGSUSED*/
1945static int
1946smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
1947    const char *wildcard, int wclen, uint16_t attr)
1948{
1949
1950	ctx->f_type = ft_LM1;
1951	ctx->f_attrmask = attr;
1952	if (wildcard) {
1953		if (wclen == 1 && wildcard[0] == '*') {
1954			ctx->f_wildcard = "*.*";
1955			ctx->f_wclen = 3;
1956		} else {
1957			ctx->f_wildcard = wildcard;
1958			ctx->f_wclen = wclen;
1959		}
1960	} else {
1961		ctx->f_wildcard = NULL;
1962		ctx->f_wclen = 0;
1963	}
1964	ctx->f_name = (char *)ctx->f_fname;
1965	ctx->f_namesz = 0;
1966	return (0);
1967}
1968
1969static int
1970smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit)
1971{
1972	struct mdchain *mdp;
1973	struct smb_rq *rqp;
1974	char *cp;
1975	uint8_t battr;
1976	uint16_t date, time;
1977	uint32_t size;
1978	int error;
1979	struct timespec ts;
1980
1981	if (ctx->f_ecnt == 0) {
1982		if (ctx->f_flags & SMBFS_RDD_EOF)
1983			return (ENOENT);
1984		ctx->f_left = ctx->f_limit = limit;
1985		gethrestime(&ts);
1986		error = smbfs_smb_search(ctx);
1987		if (error)
1988			return (error);
1989	}
1990	rqp = ctx->f_rq;
1991	smb_rq_getreply(rqp, &mdp);
1992	md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKE

Large files files are truncated, but you can click here to view the full file