Print this page
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-16824 SMB client connection setup rework
NEX-17232 SMB client reconnect failures
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (improve debug)
NEX-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)
2552 smbfs: add support for NFS-like remove
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
Reviewed by: Jason King <jason.king@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
*** 26,55 ****
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * $Id: smbfs_smb.c,v 1.73.38.1 2005/05/27 02:35:28 lindak Exp $
*/
/*
- * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/vnode.h>
#include <sys/sunddi.h>
#include <sys/cmn_err.h>
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
#include <smbfs/smbfs.h>
--- 26,56 ----
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/param.h>
#include <sys/systm.h>
+ #include <sys/inttypes.h>
#include <sys/time.h>
#include <sys/vnode.h>
#include <sys/sunddi.h>
#include <sys/cmn_err.h>
#include <netsmb/smb_osdep.h>
#include <netsmb/smb.h>
+ #include <netsmb/smb2.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_rq.h>
#include <smbfs/smbfs.h>
*** 60,438 ****
* Jan 1 1980 as 64 bit NT time.
* (tenths of microseconds since 1601)
*/
const uint64_t NT1980 = 11960035200ULL*10000000ULL;
- /*
- * Local functions.
- * Not static, to aid debugging.
- */
- int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
- struct smbfattr *fap, struct smb_cred *scrp);
- int smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
- struct smb_cred *scrp, uint16_t infolevel);
-
- int smbfs_smb_statfsLM1(struct smb_share *ssp,
- statvfs64_t *sbp, struct smb_cred *scrp);
- int smbfs_smb_statfsLM2(struct smb_share *ssp,
- statvfs64_t *sbp, struct smb_cred *scrp);
-
- int smbfs_smb_setfattrNT(struct smbnode *np, int fid,
- uint32_t attr, struct timespec *mtime, struct timespec *atime,
- struct smb_cred *scrp);
-
- int smbfs_smb_setftime1(struct smbnode *np, uint16_t fid,
- struct timespec *mtime, struct timespec *atime,
- struct smb_cred *scrp);
-
- int smbfs_smb_setpattr1(struct smbnode *np,
- const char *name, int len, uint32_t attr,
- struct timespec *mtime, struct smb_cred *scrp);
-
-
/*
! * Todo: locking over-the-wire
*/
! #ifdef APPLE
!
! static int
! smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid,
! offset_t start, uint64_t len, int largelock,
! struct smb_cred *scrp, uint32_t timeout)
{
struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- uint8_t ltype = 0;
int error;
! /* Shared lock for n_fid use below. */
! ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
!
! /* After reconnect, n_fid is invalid */
! if (np->n_vcgenid != ssp->ss_vcgenid)
! return (ESTALE);
!
! if (op == SMB_LOCK_SHARED)
! ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
! /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */
! if (largelock)
! ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
! error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
! if (error)
! return (error);
! smb_rq_getrequest(rqp, &mbp);
! smb_rq_wstart(rqp);
! mb_put_uint8(mbp, 0xff); /* secondary command */
! mb_put_uint8(mbp, 0); /* MBZ */
! mb_put_uint16le(mbp, 0);
! mb_put_uint16le(mbp, np->n_fid);
! mb_put_uint8(mbp, ltype); /* locktype */
! mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
! mb_put_uint32le(mbp, timeout); /* 0 nowait, -1 infinite wait */
! mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
! mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
! smb_rq_wend(rqp);
! smb_rq_bstart(rqp);
! mb_put_uint16le(mbp, pid);
! if (!largelock) {
! mb_put_uint32le(mbp, start);
! mb_put_uint32le(mbp, len);
} else {
! mb_put_uint16le(mbp, 0); /* pad */
! mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
! mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
! mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
! mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
}
- smb_rq_bend(rqp);
- /*
- * Don't want to risk missing a successful
- * unlock send or lock response, or we could
- * lose track of an outstanding lock.
- */
- if (op == SMB_LOCK_RELEASE)
- rqp->sr_flags |= SMBR_NOINTR_SEND;
- else
- rqp->sr_flags |= SMBR_NOINTR_RECV;
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
return (error);
}
- int
- smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
- offset_t start, uint64_t len, int largelock,
- struct smb_cred *scrp, uint32_t timeout)
- {
- struct smb_share *ssp = np->n_mount->smi_share;
-
- if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
- /*
- * TODO: use LOCK_BYTE_RANGE here.
- */
- return (EINVAL);
-
- /*
- * XXX: compute largelock via:
- * (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)?
- */
- return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len,
- largelock, scrp, timeout));
- }
-
- #endif /* APPLE */
-
/*
! * Helper for smbfs_getattr
! * Something like nfs_getattr_otw
*/
int
! smbfs_smb_getfattr(
struct smbnode *np,
struct smbfattr *fap,
struct smb_cred *scrp)
{
int error;
! /*
! * This lock is necessary for FID-based calls.
! * Lock may be writer (via open) or reader.
! */
! ASSERT(np->r_lkserlock.count != 0);
!
! /*
! * Extended attribute directory or file.
! */
! if (np->n_flag & N_XATTR) {
! error = smbfs_xa_getfattr(np, fap, scrp);
! return (error);
}
- error = smbfs_smb_trans2_query(np, fap, scrp, 0);
- if (error != EINVAL)
return (error);
-
- /* fallback */
- error = smbfs_smb_query_info(np, NULL, 0, fap, scrp);
-
- return (error);
}
/*
! * Common function for QueryFileInfo, QueryPathInfo.
*/
int
- smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap,
- struct smb_cred *scrp, uint16_t infolevel)
- {
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct smb_t2rq *t2p;
- int error, svtz, timesok = 1;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint16_t cmd, date, time, wattr;
- uint64_t llongint, lsize;
- uint32_t size, dattr;
-
- /*
- * Shared lock for n_fid use below.
- * See smbfs_smb_getfattr()
- */
- ASSERT(np->r_lkserlock.count != 0);
-
- /*
- * If we have a valid open FID, use it.
- */
- if ((np->n_fidrefs > 0) &&
- (np->n_fid != SMB_FID_UNUSED) &&
- (np->n_vcgenid == ssp->ss_vcgenid))
- cmd = SMB_TRANS2_QUERY_FILE_INFORMATION;
- else
- cmd = SMB_TRANS2_QUERY_PATH_INFORMATION;
-
- top:
- error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
- if (error)
- return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- if (!infolevel) {
- if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
- infolevel = SMB_QFILEINFO_STANDARD;
- else
- infolevel = SMB_QFILEINFO_ALL_INFO;
- }
-
- if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION)
- mb_put_uint16le(mbp, np->n_fid);
-
- mb_put_uint16le(mbp, infolevel);
-
- if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) {
- mb_put_uint32le(mbp, 0);
- /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
- error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
- if (error) {
- smb_t2_done(t2p);
- return (error);
- }
- }
-
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = vcp->vc_txmax;
- error = smb_t2_request(t2p);
- if (error) {
- smb_t2_done(t2p);
- /* Invalid info level? Try fallback. */
- if (error == EINVAL &&
- infolevel == SMB_QFILEINFO_ALL_INFO) {
- infolevel = SMB_QFILEINFO_STANDARD;
- goto top;
- }
- return (error);
- }
- mdp = &t2p->t2_rdata;
- svtz = vcp->vc_sopt.sv_tz;
- switch (infolevel) {
- case SMB_QFILEINFO_STANDARD:
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* creation time */
- smb_dos2unixtime(date, time, 0, svtz, &fap->fa_createtime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* access time */
- smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* modify time */
- smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
- md_get_uint32le(mdp, &size); /* EOF position */
- fap->fa_size = size;
- md_get_uint32le(mdp, &size); /* allocation size */
- fap->fa_allocsz = size;
- error = md_get_uint16le(mdp, &wattr);
- fap->fa_attr = wattr;
- timesok = 1;
- break;
- case SMB_QFILEINFO_ALL_INFO:
- timesok = 0;
- /* creation time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_createtime);
-
- /* last access time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_atime);
-
- /* last write time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_mtime);
-
- /* last change time */
- md_get_uint64le(mdp, &llongint);
- if (llongint)
- timesok++;
- smb_time_NT2local(llongint, &fap->fa_ctime);
-
- /* attributes */
- md_get_uint32le(mdp, &dattr);
- fap->fa_attr = dattr;
-
- /*
- * 4-Byte alignment - discard
- * Specs don't talk about this.
- */
- md_get_uint32le(mdp, NULL);
- /* allocation size */
- md_get_uint64le(mdp, &lsize);
- fap->fa_allocsz = lsize;
- /* File size */
- error = md_get_uint64le(mdp, &lsize);
- fap->fa_size = lsize;
- break;
- default:
- SMBVDEBUG("unexpected info level %d\n", infolevel);
- error = EINVAL;
- }
- smb_t2_done(t2p);
- /*
- * if all times are zero (observed with FAT on NT4SP6)
- * then fall back to older info level
- */
- if (!timesok) {
- if (infolevel == SMB_QFILEINFO_ALL_INFO) {
- infolevel = SMB_QFILEINFO_STANDARD;
- goto top;
- }
- error = EINVAL;
- }
- return (error);
- }
-
- /*
- * Support functions for _qstreaminfo
- * Moved to smbfs_xattr.c
- */
-
- int
smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
struct smb_cred *scrp)
{
- struct smb_t2rq *t2p;
- struct mbchain *mbp;
- struct mdchain *mdp;
int error;
- uint32_t nlen;
! error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
! scrp, &t2p);
! if (error)
! return (error);
! mbp = &t2p->t2_tparam;
! mb_init(mbp);
! mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO);
! t2p->t2_maxpcount = 4;
! t2p->t2_maxdcount = 4 * 3 + 512;
! error = smb_t2_request(t2p);
! if (error)
! goto out;
!
! mdp = &t2p->t2_rdata;
! md_get_uint32le(mdp, &fsa->fsa_aflags);
! md_get_uint32le(mdp, &fsa->fsa_maxname);
! error = md_get_uint32le(mdp, &nlen); /* fs name length */
! if (error)
! goto out;
!
! /*
! * Get the FS type name.
! */
! bzero(fsa->fsa_tname, FSTYPSZ);
! if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
! uint16_t tmpbuf[FSTYPSZ];
! size_t tmplen, outlen;
!
! if (nlen > sizeof (tmpbuf))
! nlen = sizeof (tmpbuf);
! error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
! tmplen = nlen / 2; /* UCS-2 chars */
! outlen = FSTYPSZ - 1;
! (void) uconv_u16tou8(tmpbuf, &tmplen,
! (uchar_t *)fsa->fsa_tname, &outlen,
! UCONV_IN_LITTLE_ENDIAN);
} else {
! if (nlen > (FSTYPSZ - 1))
! nlen = FSTYPSZ - 1;
! error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
}
/*
* If fs_name starts with FAT, we can't set dates before 1980
*/
--- 61,134 ----
* Jan 1 1980 as 64 bit NT time.
* (tenths of microseconds since 1601)
*/
const uint64_t NT1980 = 11960035200ULL*10000000ULL;
/*
! * Helper for smbfs_getattr_otw
! * used when we have an open FID
*/
! int
! smbfs_smb_getfattr(
! struct smbnode *np,
! smb_fh_t *fhp,
! struct smbfattr *fap,
! struct smb_cred *scrp)
{
struct smb_share *ssp = np->n_mount->smi_share;
int error;
! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
! error = smbfs_smb2_qfileinfo(ssp, &fhp->fh_fid2, fap, scrp);
} else {
! error = smbfs_smb1_trans2_query(np, fhp->fh_fid1, fap, scrp);
}
return (error);
}
/*
! * Helper for smbfs_getattr_otw
! * used when we don't have an open FID
! *
! * For SMB1 we can just use the path form of trans2 query.
! * For SMB2 we need to do an attribute-only open.
! * See smbfs_smb2_getpattr()
*/
int
! smbfs_smb_getpattr(
struct smbnode *np,
struct smbfattr *fap,
struct smb_cred *scrp)
{
+ struct smb_share *ssp = np->n_mount->smi_share;
int error;
! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
! error = smbfs_smb2_getpattr(np, fap, scrp);
! } else {
! uint16_t fid = SMB_FID_UNUSED;
! error = smbfs_smb1_trans2_query(np, fid, fap, scrp);
}
return (error);
}
/*
! * Get and parse FileFsAttributeInformation
*/
int
smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
struct smb_cred *scrp)
{
int error;
! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
! error = smbfs_smb2_qfsattr(ssp, fsa, scrp);
} else {
! error = smbfs_smb1_qfsattr(ssp, fsa, scrp);
}
/*
* If fs_name starts with FAT, we can't set dates before 1980
*/
*** 440,1104 ****
SMB_SS_LOCK(ssp);
ssp->ss_flags |= SMBS_FST_FAT;
SMB_SS_UNLOCK(ssp);
}
! out:
! smb_t2_done(t2p);
! return (0);
}
int
smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
struct smb_cred *scp)
{
int error;
! if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
! error = smbfs_smb_statfsLM2(ssp, sbp, scp);
! else
! error = smbfs_smb_statfsLM1(ssp, sbp, scp);
!
return (error);
- }
! int
! smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp,
! struct smb_cred *scrp)
! {
! struct smb_t2rq *t2p;
! struct mbchain *mbp;
! struct mdchain *mdp;
! uint16_t bsize;
! uint32_t units, bpu, funits;
! uint64_t s, t, f;
! int error;
! error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
! scrp, &t2p);
! if (error)
! return (error);
! mbp = &t2p->t2_tparam;
! mb_init(mbp);
! mb_put_uint16le(mbp, SMB_QFS_ALLOCATION);
! t2p->t2_maxpcount = 4;
! t2p->t2_maxdcount = 4 * 4 + 2;
! error = smb_t2_request(t2p);
! if (error)
! goto out;
! mdp = &t2p->t2_rdata;
! md_get_uint32le(mdp, NULL); /* fs id */
! md_get_uint32le(mdp, &bpu);
! md_get_uint32le(mdp, &units);
! md_get_uint32le(mdp, &funits);
! error = md_get_uint16le(mdp, &bsize);
! if (error)
! goto out;
! s = bsize;
! s *= bpu;
! t = units;
! f = funits;
! /*
! * Don't allow over-large blocksizes as they determine
! * Finder List-view size granularities. On the other
! * hand, we mustn't let the block count overflow the
! * 31 bits available.
! */
! while (s > 16 * 1024) {
! if (t > LONG_MAX)
! break;
! s /= 2;
! t *= 2;
! f *= 2;
! }
! while (t > LONG_MAX) {
! t /= 2;
! f /= 2;
! s *= 2;
! }
! sbp->f_bsize = (ulong_t)s; /* file system block size */
! sbp->f_blocks = t; /* total data blocks in file system */
! sbp->f_bfree = f; /* free blocks in fs */
! sbp->f_bavail = f; /* free blocks avail to non-superuser */
! sbp->f_files = (-1); /* total file nodes in file system */
! sbp->f_ffree = (-1); /* free file nodes in fs */
! out:
! smb_t2_done(t2p);
! return (0);
! }
! int
! smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp,
! struct smb_cred *scrp)
! {
! struct smb_rq rq, *rqp = &rq;
! struct mdchain *mdp;
! uint16_t units, bpu, bsize, funits;
! uint64_t s, t, f;
! int error;
! error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
! scrp);
! if (error)
! return (error);
! smb_rq_wstart(rqp);
! smb_rq_wend(rqp);
! smb_rq_bstart(rqp);
! smb_rq_bend(rqp);
! error = smb_rq_simple(rqp);
! if (error)
! goto out;
- smb_rq_getreply(rqp, &mdp);
- md_get_uint16le(mdp, &units);
- md_get_uint16le(mdp, &bpu);
- md_get_uint16le(mdp, &bsize);
- error = md_get_uint16le(mdp, &funits);
- if (error)
- goto out;
- s = bsize;
- s *= bpu;
- t = units;
- f = funits;
- /*
- * Don't allow over-large blocksizes as they determine
- * Finder List-view size granularities. On the other
- * hand, we mustn't let the block count overflow the
- * 31 bits available.
- */
- while (s > 16 * 1024) {
- if (t > LONG_MAX)
- break;
- s /= 2;
- t *= 2;
- f *= 2;
- }
- while (t > LONG_MAX) {
- t /= 2;
- f /= 2;
- s *= 2;
- }
- sbp->f_bsize = (ulong_t)s; /* file system block size */
- sbp->f_blocks = t; /* total data blocks in file system */
- sbp->f_bfree = f; /* free blocks in fs */
- sbp->f_bavail = f; /* free blocks avail to non-superuser */
sbp->f_files = (-1); /* total file nodes in file system */
sbp->f_ffree = (-1); /* free file nodes in fs */
- out:
- smb_rq_done(rqp);
- return (0);
- }
-
- int
- smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
- struct smb_cred *scrp)
- {
- struct smb_t2rq *t2p;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- int error;
-
- error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
- scrp, &t2p);
- if (error)
return (error);
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
- mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
- else
- mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO);
- mb_put_uint16le(mbp, 0); /* pad */
- mbp = &t2p->t2_tdata;
- mb_init(mbp);
- mb_put_uint64le(mbp, newsize);
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
- smb_t2_done(t2p);
- return (error);
}
- /*ARGSUSED*/
int
! smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp,
! const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite)
{
! struct smb_t2rq *t2p;
! struct smb_share *ssp = np->n_mount->smi_share;
! struct smb_vc *vcp = SSTOVC(ssp);
! struct mbchain *mbp;
! int32_t *ucslenp;
! int error, cerror;
! uint16_t fid = 0;
! /* Shared lock for n_fid use below. */
! ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
!
! /* After reconnect, n_fid is invalid */
! if (np->n_vcgenid != ssp->ss_vcgenid)
! return (ESTALE);
!
! if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
! return (ENOTSUP);
! error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
! scrp, &t2p);
! if (error)
! return (error);
! if (tdnp) {
! error = smbfs_smb_tmpopen(tdnp, SA_RIGHT_FILE_READ_DATA, scrp,
! &fid);
! if (error)
! goto exit;
}
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, np->n_fid);
- mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
- mb_put_uint16le(mbp, 0); /* reserved, nowadays */
- mbp = &t2p->t2_tdata;
- mb_init(mbp);
- mb_put_uint32le(mbp, overwrite);
- mb_put_uint16le(mbp, fid); /* base for tname */
- mb_put_uint16le(mbp, 0); /* part of a 32bit fid? */
- ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
- mbp->mb_count = 0;
- error = smb_put_dstring(mbp, vcp, tname, SMB_CS_NONE);
- if (error)
- goto exit;
- mbp->mb_count--; /* don't count the null */
- *ucslenp = htolel(mbp->mb_count);
- t2p->t2_maxpcount = 2;
- t2p->t2_maxdcount = 0;
- error = smb_t2_request(t2p);
- exit:
- if (fid) {
- cerror = smbfs_smb_tmpclose(tdnp, fid, scrp);
- if (cerror)
- SMBVDEBUG("error %d closing %s\n",
- cerror, tdnp->n_rpath);
- }
- smb_t2_done(t2p);
- return (error);
- }
! int
! smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
! {
! struct smb_share *ssp = np->n_mount->smi_share;
! struct smb_rq rq, *rqp = &rq;
! struct mbchain *mbp;
! int error;
!
! /* Shared lock for n_fid use below. */
! ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
!
! if (!(np->n_flag & NFLUSHWIRE))
! return (0);
! if (np->n_fidrefs == 0)
! return (0); /* not open */
!
! /* After reconnect, n_fid is invalid */
! if (np->n_vcgenid != ssp->ss_vcgenid)
! return (ESTALE);
!
! error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
! if (error)
! return (error);
! smb_rq_getrequest(rqp, &mbp);
! smb_rq_wstart(rqp);
! mb_put_uint16le(mbp, np->n_fid);
! smb_rq_wend(rqp);
! smb_rq_bstart(rqp);
! smb_rq_bend(rqp);
! error = smb_rq_simple(rqp);
! smb_rq_done(rqp);
! if (!error) {
! mutex_enter(&np->r_statelock);
! np->n_flag &= ~NFLUSHWIRE;
! mutex_exit(&np->r_statelock);
! }
! return (error);
}
int
! smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
! struct smb_cred *scrp)
{
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
int error;
! if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
! /*
! * This call knows about 64-bit offsets.
! */
! error = smbfs_smb_seteof(ssp, fid, newsize, scrp);
! if (!error) {
! mutex_enter(&np->r_statelock);
! np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
! mutex_exit(&np->r_statelock);
! return (0);
}
- }
- /*
- * OK, so fallback to SMB_COM_WRITE, but note:
- * it only supports 32-bit file offsets.
- */
- if (newsize > UINT32_MAX)
- return (EFBIG);
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp);
- if (error)
return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, 0);
- mb_put_uint32le(mbp, newsize);
- mb_put_uint16le(mbp, 0);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_DATA);
- mb_put_uint16le(mbp, 0);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- mutex_enter(&np->r_statelock);
- np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
- mutex_exit(&np->r_statelock);
- return (error);
}
- /*
- * Old method for getting file attributes.
- */
- int
- smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
- struct smbfattr *fap, struct smb_cred *scrp)
- {
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint8_t wc;
- int error;
- uint16_t wattr;
- uint32_t longint;
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np,
- name, nmlen, '\\');
- if (error)
- goto out;
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- if (error)
- goto out;
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto out;
- if (wc != 10) {
- error = EBADRPC;
- goto out;
- }
- md_get_uint16le(mdp, &wattr);
- fap->fa_attr = wattr;
- /*
- * Be careful using the time returned here, as
- * with FAT on NT4SP6, at least, the time returned is low
- * 32 bits of 100s of nanoseconds (since 1601) so it rolls
- * over about every seven minutes!
- */
- md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
- smb_time_server2local(longint,
- SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime);
- error = md_get_uint32le(mdp, &longint);
- fap->fa_size = longint;
-
- out:
- smb_rq_done(rqp);
- return (error);
- }
-
/*
- * Set DOS file attributes. mtime should be NULL for dialects above lm10
- */
- int
- smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len,
- uint32_t attr, struct timespec *mtime,
- struct smb_cred *scrp)
- {
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- long time;
- int error, svtz;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp);
- if (error)
- return (error);
- svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, (uint16_t)attr);
- if (mtime) {
- smb_time_local2server(mtime, svtz, &time);
- } else
- time = 0;
- mb_put_uint32le(mbp, time); /* mtime */
- mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, len, '\\');
- if (error)
- goto out;
- mb_put_uint8(mbp, SMB_DT_ASCII);
- if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
- mb_put_padbyte(mbp);
- mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
- }
- mb_put_uint8(mbp, 0);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
-
- out:
- smb_rq_done(rqp);
- return (error);
- }
-
- int
- smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp)
- {
- struct smbfattr fa;
- int error;
- uint32_t attr;
-
- error = smbfs_smb_query_info(np, name, len, &fa, scrp);
- attr = fa.fa_attr;
- if (!error && !(attr & SMB_FA_HIDDEN)) {
- attr |= SMB_FA_HIDDEN;
- error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
- }
- return (error);
- }
-
-
- int
- smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
- struct smb_cred *scrp)
- {
- struct smbfattr fa;
- uint32_t attr;
- int error;
-
- error = smbfs_smb_query_info(np, name, len, &fa, scrp);
- attr = fa.fa_attr;
- if (!error && (attr & SMB_FA_HIDDEN)) {
- attr &= ~SMB_FA_HIDDEN;
- error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
- }
- return (error);
- }
-
- /*
* Set file attributes (optionally: DOS attr, atime, mtime)
! * either by open FID or by path name (FID == -1).
*/
int
smbfs_smb_setfattr(
! struct smbnode *np,
! int fid,
uint32_t attr,
struct timespec *mtime,
struct timespec *atime,
struct smb_cred *scrp)
{
! struct smb_share *ssp = np->n_mount->smi_share;
! struct smb_vc *vcp = SSTOVC(ssp);
int error;
/*
! * Normally can use the trans2 call.
*/
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
- error = smbfs_smb_setfattrNT(np, fid,
- attr, mtime, atime, scrp);
- return (error);
- }
-
- /*
- * Fall-back for older protocols.
- */
- if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) {
- error = smbfs_smb_setftime1(np, fid,
- mtime, atime, scrp);
- return (error);
- }
- error = smbfs_smb_setpattr1(np, NULL, 0,
- attr, mtime, scrp);
- return (error);
- }
-
- /*
- * Set file atime and mtime. Isn't supported by core dialect.
- */
- int
- smbfs_smb_setftime1(
- struct smbnode *np,
- uint16_t fid,
- struct timespec *mtime,
- struct timespec *atime,
- struct smb_cred *scrp)
- {
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- uint16_t date, time;
- int error, tzoff;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp);
- if (error)
- return (error);
-
- tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint32le(mbp, 0); /* creation time */
-
- if (atime)
- smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
- else
- time = date = 0;
- mb_put_uint16le(mbp, date);
- mb_put_uint16le(mbp, time);
- if (mtime)
- smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
- else
- time = date = 0;
- mb_put_uint16le(mbp, date);
- mb_put_uint16le(mbp, time);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- SMBVDEBUG("%d\n", error);
- smb_rq_done(rqp);
- return (error);
- }
-
- /*
- * Set DOS file attributes, either via open FID or by path name.
- * Looks like this call can be used only if CAP_NT_SMBS bit is on.
- *
- * When setting via path (fid == -1):
- * *BASIC_INFO works with Samba, but Win2K servers say it is an
- * invalid information level on a SET_PATH_INFO. Note Win2K does
- * support *BASIC_INFO on a SET_FILE_INFO, and they support the
- * equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure.
- */
- int
- smbfs_smb_setfattrNT(
- struct smbnode *np,
- int fid, /* if fid == -1, set by path */
- uint32_t attr,
- struct timespec *mtime,
- struct timespec *atime,
- struct smb_cred *scrp)
- {
- struct smb_t2rq *t2p;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct smb_vc *vcp = SSTOVC(ssp);
- struct mbchain *mbp;
- uint64_t tm;
- int error;
- uint16_t cmd, level;
-
- if (fid == -1) {
- cmd = SMB_TRANS2_SET_PATH_INFORMATION;
- } else {
- if (fid > UINT16_MAX)
- return (EINVAL);
- cmd = SMB_TRANS2_SET_FILE_INFORMATION;
- }
- if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
- level = SMB_SFILEINFO_BASIC_INFORMATION;
- else
- level = SMB_SFILEINFO_BASIC_INFO;
-
- error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p);
- if (error)
- return (error);
-
- mbp = &t2p->t2_tparam;
mb_init(mbp);
-
- if (cmd == SMB_TRANS2_SET_FILE_INFORMATION)
- mb_put_uint16le(mbp, fid);
-
- mb_put_uint16le(mbp, level);
- mb_put_uint32le(mbp, 0); /* MBZ */
-
- if (cmd == SMB_TRANS2_SET_PATH_INFORMATION) {
- error = smbfs_fullpath(mbp, vcp, np, NULL, 0, '\\');
- if (error != 0)
- goto out;
- }
-
- /* FAT file systems don't support dates earlier than 1980. */
-
- mbp = &t2p->t2_tdata;
- mb_init(mbp);
mb_put_uint64le(mbp, 0); /* creation time */
if (atime) {
smb_time_local2NT(atime, &tm);
if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
tm < NT1980)
tm = NT1980;
} else
tm = 0;
! mb_put_uint64le(mbp, tm); /* access time */
if (mtime) {
smb_time_local2NT(mtime, &tm);
if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
tm < NT1980)
tm = NT1980;
} else
tm = 0;
mb_put_uint64le(mbp, tm); /* last write time */
! mb_put_uint64le(mbp, 0); /* ctime (no change) */
mb_put_uint32le(mbp, attr);
! mb_put_uint32le(mbp, 0); /* padding */
! t2p->t2_maxpcount = 2;
! t2p->t2_maxdcount = 0;
! error = smb_t2_request(t2p);
! out:
! smb_t2_done(t2p);
return (error);
}
/*
* Modern create/open of file or directory.
*/
int
smbfs_smb_ntcreatex(
struct smbnode *np,
const char *name,
--- 136,299 ----
SMB_SS_LOCK(ssp);
ssp->ss_flags |= SMBS_FST_FAT;
SMB_SS_UNLOCK(ssp);
}
! return (error);
}
int
smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
struct smb_cred *scp)
{
+ struct smb_fs_size_info info;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ uint32_t bps, spu;
int error;
! if (vcp->vc_flags & SMBV_SMB2) {
! error = smbfs_smb2_statfs(ssp, &info, scp);
! } else {
! error = smbfs_smb1_statfs(ssp, &info, scp);
! }
! if (error)
return (error);
! /* A bit of paranoia. */
! bps = info.bytes_per_sect;
! if (bps < DEV_BSIZE)
! bps = DEV_BSIZE;
! spu = info.sect_per_unit;
! if (spu == 0)
! spu = 1;
! /* preferred file system block size */
! sbp->f_bsize = bps * spu;
! /* file system block size ("fragment size") */
! sbp->f_frsize = bps;
! /* total blocks of f_frsize */
! sbp->f_blocks = info.total_units * spu;
! /* free blocks of f_frsize */
! sbp->f_bfree = info.actual_avail * spu;
! /* free blocks avail to non-superuser */
! sbp->f_bavail = info.caller_avail * spu;
sbp->f_files = (-1); /* total file nodes in file system */
sbp->f_ffree = (-1); /* free file nodes in fs */
return (error);
}
int
! smbfs_smb_setdisp(struct smb_share *ssp, smb_fh_t *fhp,
! uint8_t disp, struct smb_cred *scrp)
{
! int err;
! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
! err = smbfs_smb2_setdisp(ssp, &fhp->fh_fid2, disp, scrp);
! } else {
! err = smbfs_smb1_setdisp(ssp, fhp->fh_fid1, disp, scrp);
}
! return (err);
}
int
! smbfs_smb_setfsize(struct smb_share *ssp, smb_fh_t *fhp,
! uint64_t size, struct smb_cred *scrp)
{
int error;
! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
! error = smbfs_smb2_seteof(ssp, &fhp->fh_fid2, size, scrp);
! } else {
! error = smbfs_smb1_seteof(ssp, fhp->fh_fid1, size, scrp);
}
return (error);
}
/*
* Set file attributes (optionally: DOS attr, atime, mtime)
! * Always have an open FID with set attr rights.
*/
int
smbfs_smb_setfattr(
! struct smb_share *ssp,
! smb_fh_t *fhp,
uint32_t attr,
struct timespec *mtime,
struct timespec *atime,
struct smb_cred *scrp)
{
! struct mbchain mb_info;
! struct mbchain *mbp = &mb_info;
! uint64_t tm;
int error;
/*
! * Build a struct FILE_BASIC_INFORMATION in mbp
! * LARGE_INTEGER CreationTime;
! * LARGE_INTEGER LastAccessTime;
! * LARGE_INTEGER LastWriteTime;
! * LARGE_INTEGER ChangeTime;
! * ULONG FileAttributes;
! * Zero in times means "no change".
*/
mb_init(mbp);
mb_put_uint64le(mbp, 0); /* creation time */
if (atime) {
smb_time_local2NT(atime, &tm);
if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
tm < NT1980)
tm = NT1980;
} else
tm = 0;
! mb_put_uint64le(mbp, tm); /* last access time */
if (mtime) {
smb_time_local2NT(mtime, &tm);
if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) &&
tm < NT1980)
tm = NT1980;
} else
tm = 0;
mb_put_uint64le(mbp, tm); /* last write time */
! mb_put_uint64le(mbp, 0); /* change time */
mb_put_uint32le(mbp, attr);
!
! if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
! error = smbfs_smb2_setfattr(ssp, &fhp->fh_fid2, mbp, scrp);
! } else {
! error = smbfs_smb1_setfattr(ssp, fhp->fh_fid1, mbp, scrp);
! }
!
return (error);
}
+ int
+ smbfs_smb_flush(struct smb_share *ssp, smb_fh_t *fhp,
+ struct smb_cred *scrp)
+ {
+ int error;
+
+ if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
+ error = smbfs_smb2_flush(ssp, &fhp->fh_fid2, scrp);
+ } else {
+ error = smbfs_smb1_flush(ssp, fhp->fh_fid1, scrp);
+ }
+ return (error);
+ }
+
/*
* Modern create/open of file or directory.
+ * On success, fills in fhp->fh_fid* and fhp->fh_rights
*/
int
smbfs_smb_ntcreatex(
struct smbnode *np,
const char *name,
*** 1108,1118 ****
uint32_t efa, /* ext. file attrs (DOS attr +) */
uint32_t share_acc,
uint32_t disp, /* open disposition */
uint32_t createopt, /* NTCREATEX_OPTIONS_ */
struct smb_cred *scrp,
! uint16_t *fidp, /* returned FID */
uint32_t *cr_act_p, /* optional returned create action */
struct smbfattr *fap) /* optional returned attributes */
{
struct mbchain name_mb;
struct smb_share *ssp = np->n_mount->smi_share;
--- 303,313 ----
uint32_t efa, /* ext. file attrs (DOS attr +) */
uint32_t share_acc,
uint32_t disp, /* open disposition */
uint32_t createopt, /* NTCREATEX_OPTIONS_ */
struct smb_cred *scrp,
! smb_fh_t *fhp, /* pre-made file handle to fill in */
uint32_t *cr_act_p, /* optional returned create action */
struct smbfattr *fap) /* optional returned attributes */
{
struct mbchain name_mb;
struct smb_share *ssp = np->n_mount->smi_share;
*** 1129,1373 ****
err = smb_smb_ntcreate(ssp, &name_mb,
0, /* NTCREATEX_FLAGS... */
req_acc, efa, share_acc, disp, createopt,
NTCREATEX_IMPERSONATION_IMPERSONATION,
! scrp, fidp, cr_act_p, fap);
out:
mb_done(&name_mb);
return (err);
}
! static uint32_t
! smb_mode2rights(int mode)
! {
! mode = mode & SMB_AM_OPENMODE;
! uint32_t rights =
! STD_RIGHT_SYNCHRONIZE_ACCESS |
! STD_RIGHT_READ_CONTROL_ACCESS;
!
! if ((mode == SMB_AM_OPENREAD) ||
! (mode == SMB_AM_OPENRW)) {
! rights |=
! SA_RIGHT_FILE_READ_ATTRIBUTES |
! SA_RIGHT_FILE_READ_DATA;
! }
!
! if ((mode == SMB_AM_OPENWRITE) ||
! (mode == SMB_AM_OPENRW)) {
! rights |=
! SA_RIGHT_FILE_WRITE_ATTRIBUTES |
! SA_RIGHT_FILE_APPEND_DATA |
! SA_RIGHT_FILE_WRITE_DATA;
! }
!
! if (mode == SMB_AM_OPENEXEC) {
! rights |=
! SA_RIGHT_FILE_READ_ATTRIBUTES |
! SA_RIGHT_FILE_EXECUTE;
! }
!
! return (rights);
! }
!
! static int
! smb_rights2mode(uint32_t rights)
! {
! int accmode = SMB_AM_OPENEXEC; /* our fallback */
!
! if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD |
! SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES |
! SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS |
! STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS))
! accmode = SMB_AM_OPENWRITE;
! if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES |
! SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS))
! accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD
! : SMB_AM_OPENRW;
! return (accmode);
! }
!
! static int
! smbfs_smb_oldopen(
! struct smbnode *np,
! const char *name,
! int nmlen,
! int xattr,
! int accmode,
! struct smb_cred *scrp,
! uint16_t *fidp,
! uint16_t *granted_mode_p,
! smbfattr_t *fap)
! {
! struct smb_rq rq, *rqp = &rq;
! struct smb_share *ssp = np->n_mount->smi_share;
! struct smb_vc *vcp = SSTOVC(ssp);
! struct mbchain *mbp;
! struct mdchain *mdp;
! struct smbfattr fa;
! uint8_t wc;
! uint16_t wattr;
! uint32_t longint;
! int error;
!
! bzero(&fa, sizeof (fa));
!
! /*
! * XXX: move to callers...
*
! * Use DENYNONE to give unixy semantics of permitting
! * everything not forbidden by permissions. Ie denial
! * is up to server with clients/openers needing to use
! * advisory locks for further control.
*/
- accmode |= SMB_SM_DENYNONE;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, accmode);
- mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY |
- SMB_FA_DIR);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, vcp, np, name, nmlen,
- xattr ? ':' : '\\');
- if (error)
- goto done;
- smb_rq_bend(rqp);
- /*
- * Don't want to risk missing a successful
- * open response, or we could "leak" FIDs.
- */
- rqp->sr_flags |= SMBR_NOINTR_RECV;
- error = smb_rq_simple_timed(rqp, smb_timo_open);
- if (error)
- goto done;
- smb_rq_getreply(rqp, &mdp);
- /*
- * 8/2002 a DAVE server returned wc of 15 so we ignore that.
- * (the actual packet length and data was correct)
- */
- error = md_get_uint8(mdp, &wc);
- if (error)
- goto done;
- if (wc != 7 && wc != 15) {
- error = EBADRPC;
- goto done;
- }
- md_get_uint16le(mdp, fidp);
- md_get_uint16le(mdp, &wattr);
- fa.fa_attr = wattr;
- /*
- * Be careful using the time returned here, as
- * with FAT on NT4SP6, at least, the time returned is low
- * 32 bits of 100s of nanoseconds (since 1601) so it rolls
- * over about every seven minutes!
- */
- md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
- smb_time_server2local(longint, vcp->vc_sopt.sv_tz, &fa.fa_mtime);
- md_get_uint32le(mdp, &longint);
- fa.fa_size = longint;
- error = md_get_uint16le(mdp, granted_mode_p);
-
- done:
- smb_rq_done(rqp);
- if (error)
- return (error);
-
- if (fap)
- *fap = fa; /* struct copy */
-
- return (0);
- }
-
int
smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
! uint16_t *fidp)
{
struct smb_share *ssp = np->n_mount->smi_share;
! struct smb_vc *vcp = SSTOVC(ssp);
! int accmode, error;
- /* Shared lock for n_fid use below. */
- ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
-
/* Can we re-use n_fid? or must we open anew? */
mutex_enter(&np->r_statelock);
if (np->n_fidrefs > 0 &&
! np->n_vcgenid == ssp->ss_vcgenid &&
! (rights & np->n_rights) == rights) {
! np->n_fidrefs++;
! *fidp = np->n_fid;
mutex_exit(&np->r_statelock);
return (0);
}
mutex_exit(&np->r_statelock);
/* re-open an existing file. */
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
error = smbfs_smb_ntcreatex(np,
NULL, 0, 0, /* name nmlen xattr */
rights, SMB_EFA_NORMAL,
NTCREATEX_SHARE_ACCESS_ALL,
NTCREATEX_DISP_OPEN,
0, /* create options */
! scrp, fidp,
NULL, NULL); /* cr_act_p fa_p */
! return (error);
! }
! accmode = smb_rights2mode(rights);
! error = smbfs_smb_oldopen(np,
! NULL, 0, 0, /* name nmlen xattr */
! accmode, scrp,
! fidp,
! NULL, /* granted mode p */
! NULL); /* fa p */
return (error);
}
! int
! smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp)
{
! struct smb_share *ssp = np->n_mount->smi_share;
! int error = 0;
! uint16_t oldfid = SMB_FID_UNUSED;
!
! /* Shared lock for n_fid use below. */
! ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
!
! mutex_enter(&np->r_statelock);
! if (fid == np->n_fid) {
! ASSERT(np->n_fidrefs > 0);
! if (--np->n_fidrefs == 0) {
! /*
! * Don't expect to find the last reference
! * here in tmpclose. Hard to deal with as
! * we don't have r_lkserlock exclusive.
! * Will close oldfid below.
! */
! oldfid = np->n_fid;
! np->n_fid = SMB_FID_UNUSED;
! }
! } else {
! /* Will close the passed fid. */
! oldfid = fid;
! }
! mutex_exit(&np->r_statelock);
!
! if (oldfid != SMB_FID_UNUSED)
! error = smbfs_smb_close(ssp, oldfid, NULL, scrp);
!
! return (error);
}
int
smbfs_smb_open(
struct smbnode *np,
--- 324,403 ----
err = smb_smb_ntcreate(ssp, &name_mb,
0, /* NTCREATEX_FLAGS... */
req_acc, efa, share_acc, disp, createopt,
NTCREATEX_IMPERSONATION_IMPERSONATION,
! scrp, fhp, cr_act_p, fap);
out:
mb_done(&name_mb);
return (err);
}
! /*
! * Get a file handle with (at least) the specified rights.
*
! * We'll try to borrow the node ->n_fid if we can. When we
! * borrow n_fid, just take a hold on the smb_fh_t, and don't
! * bump n_fidrefs as that tracks VFS-level opens. Similarly
! * in _tmpclose we just release the smb_fh_t, not n_fidrefs.
*/
int
smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
! smb_fh_t **fhpp)
{
struct smb_share *ssp = np->n_mount->smi_share;
! smb_fh_t *fhp = NULL;
! int error;
/* Can we re-use n_fid? or must we open anew? */
mutex_enter(&np->r_statelock);
if (np->n_fidrefs > 0 &&
! (fhp = np->n_fid) != NULL &&
! fhp->fh_vcgenid == ssp->ss_vcgenid &&
! (fhp->fh_rights & rights) == rights) {
! smb_fh_hold(fhp);
! *fhpp = fhp;
mutex_exit(&np->r_statelock);
return (0);
}
mutex_exit(&np->r_statelock);
+ error = smb_fh_create(ssp, &fhp);
+ if (error != 0)
+ goto out;
+
/* re-open an existing file. */
error = smbfs_smb_ntcreatex(np,
NULL, 0, 0, /* name nmlen xattr */
rights, SMB_EFA_NORMAL,
NTCREATEX_SHARE_ACCESS_ALL,
NTCREATEX_DISP_OPEN,
0, /* create options */
! scrp, fhp,
NULL, NULL); /* cr_act_p fa_p */
! if (error != 0)
! goto out;
! fhp->fh_rights = rights;
! smb_fh_opened(fhp);
! *fhpp = fhp;
! fhp = NULL;
+ out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
+
return (error);
}
! /* ARGSUSED */
! void
! smbfs_smb_tmpclose(struct smbnode *np, smb_fh_t *fhp)
{
! smb_fh_rele(fhp);
}
int
smbfs_smb_open(
struct smbnode *np,
*** 1374,2324 ****
const char *name,
int nmlen,
int xattr,
uint32_t rights,
struct smb_cred *scrp,
! uint16_t *fidp,
! uint32_t *rightsp,
smbfattr_t *fap)
{
struct smb_share *ssp = np->n_mount->smi_share;
! struct smb_vc *vcp = SSTOVC(ssp);
! int accmode, error;
! uint16_t grantedmode;
/* open an existing file */
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
error = smbfs_smb_ntcreatex(np,
name, nmlen, xattr,
rights, SMB_EFA_NORMAL,
NTCREATEX_SHARE_ACCESS_ALL,
NTCREATEX_DISP_OPEN,
0, /* create options */
! scrp, fidp,
! NULL, fap); /* cr_act_p fa_p */
if (error != 0)
! return (error);
! *rightsp = rights;
! return (0);
! }
! accmode = smb_rights2mode(rights);
! error = smbfs_smb_oldopen(np,
! name, nmlen, xattr, accmode, scrp,
! fidp, &grantedmode, fap);
! if (error != 0)
! return (error);
! *rightsp = smb_mode2rights(grantedmode);
! (void) smbfs_smb_getfattr(np, fap, scrp);
return (0);
}
! int
! smbfs_smb_close(struct smb_share *ssp, uint16_t fid,
! struct timespec *mtime, struct smb_cred *scrp)
{
- int error;
! error = smb_smb_close(ssp, fid, mtime, scrp);
!
! /*
! * ENOTCONN isn't interesting - if the connection is closed,
! * so are all our FIDs - and EIO is also not interesting,
! * as it means a forced unmount was done. (was ENXIO)
! * Also ETIME, which means we sent the request but gave up
! * waiting before the response came back.
! *
! * Don't clog up the system log with warnings about these
! * uninteresting failures on closes.
! */
! switch (error) {
! case ENOTCONN:
! case ENXIO:
! case EIO:
! case ETIME:
! error = 0;
! }
! return (error);
}
- static int
- smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen,
- int xattr, struct smb_cred *scrp, uint16_t *fidp)
- {
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = dnp->n_mount->smi_share;
- struct mbchain *mbp;
- struct mdchain *mdp;
- struct timespec ctime;
- uint8_t wc;
- long tm;
- int error;
- uint16_t attr = SMB_FA_ARCHIVE;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- if (name && *name == '.')
- attr |= SMB_FA_HIDDEN;
- mb_put_uint16le(mbp, attr); /* attributes */
- gethrestime(&ctime);
- smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
- mb_put_uint32le(mbp, tm);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, nmlen,
- xattr ? ':' : '\\');
- if (error)
- goto out;
- smb_rq_bend(rqp);
- /*
- * Don't want to risk missing a successful
- * open response, or we could "leak" FIDs.
- */
- rqp->sr_flags |= SMBR_NOINTR_RECV;
- error = smb_rq_simple_timed(rqp, smb_timo_open);
- if (error)
- goto out;
-
- smb_rq_getreply(rqp, &mdp);
- md_get_uint8(mdp, &wc);
- if (wc != 1) {
- error = EBADRPC;
- goto out;
- }
- error = md_get_uint16le(mdp, fidp);
-
- out:
- smb_rq_done(rqp);
- return (error);
- }
-
int
smbfs_smb_create(
struct smbnode *dnp,
const char *name,
int nmlen,
int xattr,
uint32_t disp,
struct smb_cred *scrp,
! uint16_t *fidp)
{
struct smb_share *ssp = dnp->n_mount->smi_share;
! struct smb_vc *vcp = SSTOVC(ssp);
uint32_t efa, rights;
int error;
/*
* At present the only access we might need is to WRITE data,
* and that only if we are creating a "symlink". When/if the
* access needed gets more complex it should made a parameter
* and be set upstream.
*/
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
rights = SA_RIGHT_FILE_WRITE_DATA;
efa = SMB_EFA_NORMAL;
if (!xattr && name && *name == '.')
efa = SMB_EFA_HIDDEN;
error = smbfs_smb_ntcreatex(dnp,
name, nmlen, xattr, rights, efa,
NTCREATEX_SHARE_ACCESS_ALL,
disp, /* != NTCREATEX_DISP_OPEN */
NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
! scrp, fidp, NULL, NULL); /* cr_act_p fa_p */
! return (error);
! }
! error = smbfs_smb_oldcreate(dnp, name, nmlen, xattr, scrp, fidp);
return (error);
}
int
! smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name,
! int nmlen, int xattr)
{
- struct smb_rq rq, *rqp = &rq;
struct smb_share *ssp = np->n_mount->smi_share;
! struct mbchain *mbp;
! int error;
! error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp);
! if (error)
! return (error);
! smb_rq_getrequest(rqp, &mbp);
! smb_rq_wstart(rqp);
! mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
! smb_rq_wend(rqp);
! smb_rq_bstart(rqp);
! mb_put_uint8(mbp, SMB_DT_ASCII);
! error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, nmlen,
! xattr ? ':' : '\\');
! if (!error) {
! smb_rq_bend(rqp);
! error = smb_rq_simple(rqp);
}
- smb_rq_done(rqp);
- return (error);
- }
- int
- smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, struct smb_cred *scrp)
- {
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = src->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
- uint16_t fa;
- char sep;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- /* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
- fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
- fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
- mb_put_uint16le(mbp, fa);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
-
/*
! * When we're not adding any component name, the
! * passed sep is ignored, so just pass sep=0.
*/
! mb_put_uint8(mbp, SMB_DT_ASCII);
! error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, 0);
! if (error)
! goto out;
! /*
! * After XATTR directories, separator is ":"
! */
! sep = (src->n_flag & N_XATTR) ? ':' : '\\';
! mb_put_uint8(mbp, SMB_DT_ASCII);
! error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, sep);
! if (error)
! goto out;
!
! smb_rq_bend(rqp);
! error = smb_rq_simple(rqp);
! out:
! smb_rq_done(rqp);
! return (error);
}
int
- smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
- const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp)
- {
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = src->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
- mb_put_uint16le(mbp, 0x20); /* delete target file */
- mb_put_uint16le(mbp, flags);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
-
- error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0, '\\');
- if (error)
- goto out;
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen, '\\');
- if (error)
- goto out;
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
-
- out:
- smb_rq_done(rqp);
- return (error);
- }
-
- static int
- smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len,
- struct smb_cred *scrp)
- {
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = dnp->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, len, '\\');
- if (!error) {
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- }
- smb_rq_done(rqp);
- return (error);
- }
-
- int
smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen,
struct smb_cred *scrp)
{
struct smb_share *ssp = dnp->n_mount->smi_share;
! struct smb_vc *vcp = SSTOVC(ssp);
! uint32_t rights;
! uint16_t fid;
int error;
/*
* We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
* just to be asking for something. The rights==0 case could
* easily be broken on some old or unusual servers.
*/
- if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
rights = SA_RIGHT_FILE_READ_DATA;
error = smbfs_smb_ntcreatex(dnp,
name, nmlen, 0, /* xattr */
rights, SMB_EFA_DIRECTORY,
NTCREATEX_SHARE_ACCESS_ALL,
NTCREATEX_DISP_CREATE,
NTCREATEX_OPTIONS_DIRECTORY,
! scrp, &fid, NULL, NULL); /* cr_act_p fa_p */
! if (error)
! return (error);
! (void) smbfs_smb_close(ssp, fid, NULL, scrp);
! return (0);
}
- error = smbfs_smb_oldmkdir(dnp, name, nmlen, scrp);
return (error);
}
- int
- smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp)
- {
- struct smb_rq rq, *rqp = &rq;
- struct smb_share *ssp = np->n_mount->smi_share;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII);
- error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0, '\\');
- if (!error) {
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- }
- smb_rq_done(rqp);
- return (error);
- }
-
- static int
- smbfs_smb_search(struct smbfs_fctx *ctx)
- {
- struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
- struct smb_rq *rqp;
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint8_t wc, bt;
- uint16_t ec, dlen, bc;
- int maxent, error, iseof = 0;
-
- maxent = min(ctx->f_left,
- (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN);
- if (ctx->f_rq) {
- smb_rq_done(ctx->f_rq);
- ctx->f_rq = NULL;
- }
- error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH,
- ctx->f_scred, &rqp);
- if (error)
- return (error);
- ctx->f_rq = rqp;
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, maxent); /* max entries to return */
- mb_put_uint16le(mbp, ctx->f_attrmask);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- mb_put_uint8(mbp, SMB_DT_ASCII); /* buffer format */
- if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
- error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
- ctx->f_wildcard, ctx->f_wclen, '\\');
- if (error)
- return (error);
- mb_put_uint8(mbp, SMB_DT_VARIABLE);
- mb_put_uint16le(mbp, 0); /* context length */
- ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
- } else {
- if (SMB_UNICODE_STRINGS(vcp)) {
- mb_put_padbyte(mbp);
- mb_put_uint8(mbp, 0);
- }
- mb_put_uint8(mbp, 0);
- mb_put_uint8(mbp, SMB_DT_VARIABLE);
- mb_put_uint16le(mbp, SMB_SKEYLEN);
- mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
- }
- smb_rq_bend(rqp);
- error = smb_rq_simple(rqp);
- if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
- error = 0;
- iseof = 1;
- ctx->f_flags |= SMBFS_RDD_EOF;
- } else if (error)
- return (error);
- smb_rq_getreply(rqp, &mdp);
- error = md_get_uint8(mdp, &wc);
- if (error)
- return (error);
- if (wc != 1)
- return (iseof ? ENOENT : EBADRPC);
- md_get_uint16le(mdp, &ec);
- md_get_uint16le(mdp, &bc);
- md_get_uint8(mdp, &bt);
- error = md_get_uint16le(mdp, &dlen);
- if (error)
- return (error);
- if (ec == 0)
- return (ENOENT);
- ctx->f_ecnt = ec;
- if (bc < 3)
- return (EBADRPC);
- bc -= 3;
- if (bt != SMB_DT_VARIABLE)
- return (EBADRPC);
- if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
- return (EBADRPC);
- return (0);
- }
-
-
- /*ARGSUSED*/
- static int
- smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
- const char *wildcard, int wclen, uint16_t attr)
- {
-
- ctx->f_type = ft_LM1;
- ctx->f_attrmask = attr;
- if (wildcard) {
- if (wclen == 1 && wildcard[0] == '*') {
- ctx->f_wildcard = "*.*";
- ctx->f_wclen = 3;
- } else {
- ctx->f_wildcard = wildcard;
- ctx->f_wclen = wclen;
- }
- } else {
- ctx->f_wildcard = NULL;
- ctx->f_wclen = 0;
- }
- ctx->f_name = (char *)ctx->f_fname;
- ctx->f_namesz = 0;
- return (0);
- }
-
- static int
- smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit)
- {
- struct mdchain *mdp;
- struct smb_rq *rqp;
- char *cp;
- uint8_t battr;
- uint16_t date, time;
- uint32_t size;
- int error;
- struct timespec ts;
-
- if (ctx->f_ecnt == 0) {
- if (ctx->f_flags & SMBFS_RDD_EOF)
- return (ENOENT);
- ctx->f_left = ctx->f_limit = limit;
- gethrestime(&ts);
- error = smbfs_smb_search(ctx);
- if (error)
- return (error);
- }
- rqp = ctx->f_rq;
- smb_rq_getreply(rqp, &mdp);
- md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
- md_get_uint8(mdp, &battr);
- md_get_uint16le(mdp, &time);
- md_get_uint16le(mdp, &date);
- md_get_uint32le(mdp, &size);
- cp = ctx->f_name;
- error = md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM);
- cp[sizeof (ctx->f_fname) - 1] = 0;
- cp += strlen(cp) - 1;
- while (*cp == ' ' && cp >= ctx->f_name)
- *cp-- = 0;
- ctx->f_attr.fa_attr = battr;
- smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
- &ctx->f_attr.fa_mtime);
- ctx->f_attr.fa_size = size;
- ctx->f_nmlen = strlen(ctx->f_name);
- ctx->f_ecnt--;
- ctx->f_left--;
- return (0);
- }
-
- static int
- smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx)
- {
- if (ctx->f_rq)
- smb_rq_done(ctx->f_rq);
- return (0);
- }
-
/*
! * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
*/
- static int
- smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
- {
- struct smb_t2rq *t2p;
- struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
- struct mbchain *mbp;
- struct mdchain *mdp;
- uint16_t ecnt, eos, lno, flags;
- int error;
-
- if (ctx->f_t2) {
- smb_t2_done(ctx->f_t2);
- ctx->f_t2 = NULL;
- }
- flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
- if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
- flags |= FIND2_CLOSE_AFTER_REQUEST;
- ctx->f_flags |= SMBFS_RDD_NOCLOSE;
- }
- if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
- error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
- ctx->f_scred, &t2p);
- if (error)
- return (error);
- ctx->f_t2 = t2p;
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, ctx->f_attrmask);
- mb_put_uint16le(mbp, ctx->f_limit);
- mb_put_uint16le(mbp, flags);
- mb_put_uint16le(mbp, ctx->f_infolevel);
- mb_put_uint32le(mbp, 0);
- error = smbfs_fullpath(mbp, vcp, ctx->f_dnp,
- ctx->f_wildcard, ctx->f_wclen, '\\');
- if (error)
- return (error);
- } else {
- error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
- ctx->f_scred, &t2p);
- if (error)
- return (error);
- ctx->f_t2 = t2p;
- mbp = &t2p->t2_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, ctx->f_Sid);
- mb_put_uint16le(mbp, ctx->f_limit);
- mb_put_uint16le(mbp, ctx->f_infolevel);
- /* Send whatever resume key we received... */
- mb_put_uint32le(mbp, ctx->f_rkey);
- mb_put_uint16le(mbp, flags);
- /* ... and the resume name if we have one. */
- if (ctx->f_rname) {
- /* resume file name */
- mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
- MB_MSYSTEM);
- }
- /* Add trailing null - 1 byte if ASCII, 2 if Unicode */
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */
- mb_put_uint8(mbp, 0);
- }
- t2p->t2_maxpcount = 5 * 2;
- t2p->t2_maxdcount = 0xF000; /* 64K less some overhead */
- error = smb_t2_request(t2p);
- if (error)
- return (error);
-
- /*
- * This is the "resume name" we just sent.
- * We want the new one (if any) that may be
- * found in the response we just received and
- * will now begin parsing. Free the old one
- * now so we'll know if we found a new one.
- */
- if (ctx->f_rname) {
- kmem_free(ctx->f_rname, ctx->f_rnamelen);
- ctx->f_rname = NULL;
- ctx->f_rnamelen = 0;
- }
-
- mdp = &t2p->t2_rparam;
- if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
- if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
- goto nodata;
- ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
- }
- md_get_uint16le(mdp, &ecnt); /* entry count */
- md_get_uint16le(mdp, &eos); /* end of search */
- md_get_uint16le(mdp, NULL); /* EA err. off. */
- error = md_get_uint16le(mdp, &lno); /* last name off. */
- if (error != 0)
- goto nodata;
-
- /*
- * The "end of search" flag from an XP server sometimes
- * comes back zero when the prior find_next returned exactly
- * the number of entries requested. in which case we'd try again
- * but the search has in fact been closed so an EBADF results.
- * our circumvention is to check here for a zero entry count.
- */
- ctx->f_ecnt = ecnt;
- if (eos || ctx->f_ecnt == 0)
- ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
- if (ctx->f_ecnt == 0)
- return (ENOENT);
-
- /* Last Name Off (LNO) is the entry with the resume name. */
- ctx->f_rnameofs = lno;
- ctx->f_eofs = 0;
- return (0);
-
- nodata:
- /*
- * Failed parsing the FindFirst or FindNext response.
- * Force this directory listing closed, otherwise the
- * calling process may hang in an infinite loop.
- */
- ctx->f_ecnt = 0; /* Force closed. */
- ctx->f_flags |= SMBFS_RDD_EOF;
- return (EIO);
- }
-
- static int
- smbfs_smb_findclose2(struct smbfs_fctx *ctx)
- {
- struct smb_rq rq, *rqp = &rq;
- struct mbchain *mbp;
- int error;
-
- error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
- ctx->f_scred);
- if (error)
- return (error);
- smb_rq_getrequest(rqp, &mbp);
- smb_rq_wstart(rqp);
- mb_put_uint16le(mbp, ctx->f_Sid);
- smb_rq_wend(rqp);
- smb_rq_bstart(rqp);
- smb_rq_bend(rqp);
- /* Ditto comments at _smb_close */
- rqp->sr_flags |= SMBR_NOINTR_SEND;
- error = smb_rq_simple(rqp);
- smb_rq_done(rqp);
- return (error);
- }
-
- /*ARGSUSED*/
- static int
- smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
- const char *wildcard, int wclen, uint16_t attr)
- {
-
- ctx->f_type = ft_LM2;
- ctx->f_namesz = SMB_MAXFNAMELEN + 1;
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- ctx->f_namesz *= 2;
- ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
- ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp))
- < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD :
- SMB_FIND_BOTH_DIRECTORY_INFO;
- ctx->f_attrmask = attr;
- ctx->f_wildcard = wildcard;
- ctx->f_wclen = wclen;
- return (0);
- }
-
- static int
- smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
- {
- struct mdchain *mdp;
- struct smb_t2rq *t2p;
- char *cp;
- uint8_t tb;
- uint16_t date, time, wattr;
- uint32_t size, next, dattr, resumekey = 0;
- uint64_t llongint;
- int error, svtz, cnt, fxsz, nmlen, recsz;
- struct timespec ts;
-
- if (ctx->f_ecnt == 0) {
- if (ctx->f_flags & SMBFS_RDD_EOF)
- return (ENOENT);
- ctx->f_left = ctx->f_limit = limit;
- gethrestime(&ts);
- error = smbfs_smb_trans2find2(ctx);
- if (error)
- return (error);
- ctx->f_otws++;
- }
- t2p = ctx->f_t2;
- mdp = &t2p->t2_rdata;
- svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
- switch (ctx->f_infolevel) {
- case SMB_FIND_STANDARD:
- next = 0;
- fxsz = 0;
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* creation time */
- smb_dos2unixtime(date, time, 0, svtz,
- &ctx->f_attr.fa_createtime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* access time */
- smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
- md_get_uint16le(mdp, &date);
- md_get_uint16le(mdp, &time); /* modify time */
- smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
- md_get_uint32le(mdp, &size);
- ctx->f_attr.fa_size = size;
- md_get_uint32le(mdp, &size); /* allocation size */
- ctx->f_attr.fa_allocsz = size;
- md_get_uint16le(mdp, &wattr);
- ctx->f_attr.fa_attr = wattr;
- error = md_get_uint8(mdp, &tb);
- if (error)
- goto nodata;
- size = nmlen = tb;
- fxsz = 23;
- recsz = next = 24 + nmlen; /* docs misses zero byte @end */
- break;
- case SMB_FIND_DIRECTORY_INFO:
- case SMB_FIND_BOTH_DIRECTORY_INFO:
- md_get_uint32le(mdp, &next);
- md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
- md_get_uint64le(mdp, &llongint); /* creation time */
- smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime);
- md_get_uint64le(mdp, &llongint);
- smb_time_NT2local(llongint, &ctx->f_attr.fa_atime);
- md_get_uint64le(mdp, &llongint);
- smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime);
- md_get_uint64le(mdp, &llongint);
- smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime);
- md_get_uint64le(mdp, &llongint); /* file size */
- ctx->f_attr.fa_size = llongint;
- md_get_uint64le(mdp, &llongint); /* alloc. size */
- ctx->f_attr.fa_allocsz = llongint;
- md_get_uint32le(mdp, &dattr); /* ext. file attributes */
- ctx->f_attr.fa_attr = dattr;
- error = md_get_uint32le(mdp, &size); /* name len */
- if (error)
- goto nodata;
- fxsz = 64; /* size ofinfo up to filename */
- if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) {
- /*
- * Skip EaSize(4 bytes), a byte of ShortNameLength,
- * a reserved byte, and ShortName(8.3 means 24 bytes,
- * as Leach defined it to always be Unicode)
- */
- error = md_get_mem(mdp, NULL, 30, MB_MSYSTEM);
- if (error)
- goto nodata;
- fxsz += 30;
- }
- recsz = next ? next : fxsz + size;
- break;
- default:
- SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
- return (EINVAL);
- }
-
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
- nmlen = min(size, SMB_MAXFNAMELEN * 2);
- else
- nmlen = min(size, SMB_MAXFNAMELEN);
-
- /* Allocated f_name in findopen */
- ASSERT(nmlen < ctx->f_namesz);
- cp = ctx->f_name;
-
- error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM);
- if (error)
- goto nodata;
- if (next) {
- /* How much data to skip? */
- cnt = next - nmlen - fxsz;
- if (cnt < 0) {
- SMBVDEBUG("out of sync\n");
- goto nodata;
- }
- if (cnt > 0)
- md_get_mem(mdp, NULL, cnt, MB_MSYSTEM);
- }
- /* Don't count any trailing null in the name. */
- if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
- if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
- nmlen -= 2;
- } else {
- if (nmlen && cp[nmlen - 1] == 0)
- nmlen--;
- }
- if (nmlen == 0)
- goto nodata;
-
- /*
- * On a find-next we expect that the server will:
- * 1) if the continue bit is set, use the server's offset,
- * 2) else if the resume key is non-zero, use that offset,
- * 3) else if the resume name is set, use that offset,
- * 4) else use the server's idea of current offset.
- *
- * We always set the resume key flag. If the server returns
- * a resume key then we should always send it back to them.
- */
- ctx->f_rkey = resumekey;
-
- next = ctx->f_eofs + recsz;
- if (ctx->f_rnameofs &&
- ctx->f_rnameofs >= ctx->f_eofs &&
- ctx->f_rnameofs < (int)next) {
- /*
- * This entry is the "resume name".
- * Save it for the next request.
- */
- if (ctx->f_rnamelen != nmlen) {
- if (ctx->f_rname)
- kmem_free(ctx->f_rname, ctx->f_rnamelen);
- ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP);
- ctx->f_rnamelen = nmlen;
- }
- bcopy(ctx->f_name, ctx->f_rname, nmlen);
- }
- ctx->f_nmlen = nmlen;
- ctx->f_eofs = next;
- ctx->f_ecnt--;
- ctx->f_left--;
-
- smbfs_fname_tolocal(ctx);
- return (0);
-
- nodata:
- /*
- * Something bad has happened and we ran out of data
- * before we could parse all f_ecnt entries expected.
- * Force this directory listing closed, otherwise the
- * calling process may hang in an infinite loop.
- */
- SMBVDEBUG("ran out of data\n");
- ctx->f_ecnt = 0; /* Force closed. */
- ctx->f_flags |= SMBFS_RDD_EOF;
- return (EIO);
- }
-
- static int
- smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
- {
- int error = 0;
- if (ctx->f_name)
- kmem_free(ctx->f_name, ctx->f_namesz);
- if (ctx->f_t2)
- smb_t2_done(ctx->f_t2);
- /*
- * If SMBFS_RDD_FINDFIRST is still set, we were opened
- * but never saw a findfirst, so we don't have any
- * search handle to close.
- */
- if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0)
- error = smbfs_smb_findclose2(ctx);
- return (error);
- }
-
int
smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
int attr, struct smb_cred *scrp,
struct smbfs_fctx **ctxpp)
{
struct smbfs_fctx *ctx;
int error;
ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
ctx->f_flags = SMBFS_RDD_FINDFIRST;
ctx->f_dnp = dnp;
ctx->f_scred = scrp;
! ctx->f_ssp = dnp->n_mount->smi_share;
if (dnp->n_flag & N_XATTR) {
error = smbfs_xa_findopen(ctx, dnp, wild, wlen);
goto out;
}
! if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0) {
! error = smbfs_smb_findopenLM1(ctx, dnp, wild, wlen, attr);
} else {
error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr);
}
out:
! if (error)
! (void) smbfs_smb_findclose(ctx, scrp);
! else
*ctxpp = ctx;
return (error);
}
int
smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
{
! int error;
/*
* Note: "limit" (maxcount) needs to fit in a short!
*/
if (limit > 0xffff)
limit = 0xffff;
ctx->f_scred = scrp;
for (;;) {
bzero(&ctx->f_attr, sizeof (ctx->f_attr));
switch (ctx->f_type) {
! case ft_LM1:
! error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit);
break;
case ft_LM2:
! error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit);
break;
case ft_XA:
! error = smbfs_xa_findnext(ctx, (uint16_t)limit);
break;
default:
ASSERT(0);
error = EINVAL;
break;
}
if (error)
! return (error);
/*
* Skip "." or ".." - easy now that ctx->f_name
* has already been converted to utf-8 format.
*/
if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
--- 404,651 ----
const char *name,
int nmlen,
int xattr,
uint32_t rights,
struct smb_cred *scrp,
! smb_fh_t **fhpp,
smbfattr_t *fap)
{
struct smb_share *ssp = np->n_mount->smi_share;
! // struct smb_vc *vcp = SSTOVC(ssp);
! smb_fh_t *fhp = NULL;
! int error;
+ error = smb_fh_create(ssp, &fhp);
+ if (error != 0)
+ goto out;
+
/* open an existing file */
error = smbfs_smb_ntcreatex(np,
name, nmlen, xattr,
rights, SMB_EFA_NORMAL,
NTCREATEX_SHARE_ACCESS_ALL,
NTCREATEX_DISP_OPEN,
0, /* create options */
! scrp, fhp, NULL, fap);
if (error != 0)
! goto out;
! fhp->fh_rights = rights;
! smb_fh_opened(fhp);
! *fhpp = fhp;
! fhp = NULL;
+ out:
+ if (fhp != NULL)
+ smb_fh_rele(fhp);
+
return (0);
}
! void
! smbfs_smb_close(smb_fh_t *fhp)
{
! smb_fh_close(fhp);
! smb_fh_rele(fhp);
}
int
smbfs_smb_create(
struct smbnode *dnp,
const char *name,
int nmlen,
int xattr,
uint32_t disp,
struct smb_cred *scrp,
! smb_fh_t **fhpp)
{
struct smb_share *ssp = dnp->n_mount->smi_share;
! // struct smb_vc *vcp = SSTOVC(ssp);
! smb_fh_t *fhp = NULL;
uint32_t efa, rights;
int error;
+ error = smb_fh_create(ssp, &fhp);
+ if (error != 0)
+ goto out;
+
/*
* At present the only access we might need is to WRITE data,
* and that only if we are creating a "symlink". When/if the
* access needed gets more complex it should made a parameter
* and be set upstream.
*/
rights = SA_RIGHT_FILE_WRITE_DATA;
efa = SMB_EFA_NORMAL;
if (!xattr && name && *name == '.')
efa = SMB_EFA_HIDDEN;
error = smbfs_smb_ntcreatex(dnp,
name, nmlen, xattr, rights, efa,
NTCREATEX_SHARE_ACCESS_ALL,
disp, /* != NTCREATEX_DISP_OPEN */
NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
! scrp, fhp, NULL, NULL);
! if (error != 0)
! goto out;
! fhp->fh_rights = rights;
! smb_fh_opened(fhp);
! *fhpp = fhp;
! fhp = NULL;
!
! out:
! if (fhp != NULL)
! smb_fh_rele(fhp);
!
return (error);
}
int
! smbfs_smb_rename(struct smbnode *sdnp, struct smbnode *np,
! struct smbnode *tdnp, const char *tname, int tnlen,
! smb_fh_t *fhp, struct smb_cred *scrp)
{
struct smb_share *ssp = np->n_mount->smi_share;
! struct smb_vc *vcp = SSTOVC(ssp);
! int err;
! if (vcp->vc_flags & SMBV_SMB2) {
! err = smbfs_smb2_rename(np, tdnp, tname, tnlen, 0,
! &fhp->fh_fid2, scrp);
! return (err);
}
/*
! * SMB1 -- Want to use _t2rename if we can
! * (rename in same dir and cap pass-through)
! * Most SMB1 servers have cap pass-through.
*/
! if (sdnp == tdnp &&
! (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) != 0) {
! err = smbfs_smb1_t2rename(np, tname, tnlen, fhp->fh_fid1, scrp);
! } else {
! err = smbfs_smb1_oldrename(np, tdnp, tname, tnlen, scrp);
! }
! return (err);
}
int
smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen,
struct smb_cred *scrp)
{
+ smb_fh_t tmp_fh;
struct smb_share *ssp = dnp->n_mount->smi_share;
! uint32_t efa, rights;
int error;
/*
+ * Using a faked-up handle here to avoid the work of
+ * creating and destroying a real "conn obj".
+ */
+ bzero(&tmp_fh, sizeof (tmp_fh));
+
+ /*
* We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
* just to be asking for something. The rights==0 case could
* easily be broken on some old or unusual servers.
*/
rights = SA_RIGHT_FILE_READ_DATA;
+ efa = SMB_EFA_NORMAL;
+ if (name && *name == '.')
+ efa |= SMB_EFA_HIDDEN;
error = smbfs_smb_ntcreatex(dnp,
name, nmlen, 0, /* xattr */
rights, SMB_EFA_DIRECTORY,
NTCREATEX_SHARE_ACCESS_ALL,
NTCREATEX_DISP_CREATE,
NTCREATEX_OPTIONS_DIRECTORY,
! scrp, &tmp_fh, NULL, NULL);
! if (error == 0) {
! (void) smb_smb_close(ssp, &tmp_fh, scrp);
}
return (error);
}
/*
! * Protocol-level directory open
*/
int
smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen,
int attr, struct smb_cred *scrp,
struct smbfs_fctx **ctxpp)
{
+ struct smb_share *ssp = dnp->n_mount->smi_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
struct smbfs_fctx *ctx;
int error;
ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
ctx->f_flags = SMBFS_RDD_FINDFIRST;
ctx->f_dnp = dnp;
ctx->f_scred = scrp;
! ctx->f_ssp = ssp;
if (dnp->n_flag & N_XATTR) {
error = smbfs_xa_findopen(ctx, dnp, wild, wlen);
goto out;
}
! if (vcp->vc_flags & SMBV_SMB2) {
! error = smbfs_smb2_findopen(ctx, dnp, wild, wlen, attr);
} else {
error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr);
}
out:
! ctx->f_scred = NULL;
! if (error) {
! kmem_free(ctx, sizeof (*ctx));
! } else {
*ctxpp = ctx;
+ }
+
return (error);
}
int
smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
{
! int error = 0;
! uint16_t lim;
/*
* Note: "limit" (maxcount) needs to fit in a short!
*/
if (limit > 0xffff)
limit = 0xffff;
+ lim = (uint16_t)limit;
ctx->f_scred = scrp;
for (;;) {
bzero(&ctx->f_attr, sizeof (ctx->f_attr));
switch (ctx->f_type) {
!
! case ft_SMB2:
! error = smbfs_smb2_findnext(ctx, lim);
break;
case ft_LM2:
! error = smbfs_smb_findnextLM2(ctx, lim);
break;
case ft_XA:
! error = smbfs_xa_findnext(ctx, lim);
break;
default:
ASSERT(0);
error = EINVAL;
break;
}
if (error)
! break;
/*
* Skip "." or ".." - easy now that ctx->f_name
* has already been converted to utf-8 format.
*/
if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
*** 2325,2342 ****
(ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
ctx->f_name[1] == '.'))
continue;
break;
}
! /*
! * Moved the smbfs_fname_tolocal(ctx) call into
! * the ..._findnext functions above.
! */
! ctx->f_inum = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
! return (0);
}
int
smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
--- 652,673 ----
(ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
ctx->f_name[1] == '.'))
continue;
break;
}
+ ctx->f_scred = NULL;
+ if (error != 0)
+ return (error);
! ctx->f_inum = smbfs_getino(ctx->f_dnp,
! ctx->f_name, ctx->f_nmlen);
! #ifdef DEBUG
! SMBVDEBUG("findnext: (%s)\n", ctx->f_name);
! #endif
!
! return (error);
}
int
smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
*** 2343,2362 ****
{
int error;
ctx->f_scred = scrp;
switch (ctx->f_type) {
! case ft_LM1:
! error = smbfs_smb_findcloseLM1(ctx);
break;
case ft_LM2:
error = smbfs_smb_findcloseLM2(ctx);
break;
case ft_XA:
error = smbfs_xa_findclose(ctx);
break;
}
if (ctx->f_rname)
kmem_free(ctx->f_rname, ctx->f_rnamelen);
if (ctx->f_firstnm)
kmem_free(ctx->f_firstnm, ctx->f_firstnmlen);
kmem_free(ctx, sizeof (*ctx));
--- 674,697 ----
{
int error;
ctx->f_scred = scrp;
switch (ctx->f_type) {
! case ft_SMB2:
! error = smbfs_smb2_findclose(ctx);
break;
case ft_LM2:
error = smbfs_smb_findcloseLM2(ctx);
break;
case ft_XA:
error = smbfs_xa_findclose(ctx);
break;
+ default:
+ error = ENOSYS;
+ break;
}
+ ctx->f_scred = NULL;
if (ctx->f_rname)
kmem_free(ctx->f_rname, ctx->f_rnamelen);
if (ctx->f_firstnm)
kmem_free(ctx->f_firstnm, ctx->f_firstnmlen);
kmem_free(ctx, sizeof (*ctx));
*** 2392,2420 ****
DEBUG_ENTER("smbfs_smb_lookup: name is '.' or '..'");
return (EINVAL);
}
/*
- * XXX: Should use _qpathinfo here instead.
- * (if SMB_CAP_NT_SMBS)
- */
-
- /*
* Shared lock for n_fid use (smb_flush).
*/
intr = dnp->n_mount->smi_flags & SMI_INT;
if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr))
return (EINTR);
- /*
- * This hides a server bug observable in Win98:
- * size changes may not show until a CLOSE or a FLUSH op
- * XXX: Make this conditional on !NTSMBs
- */
- error = smbfs_smb_flush(dnp, scrp);
- if (error)
- goto out;
error = smbfs_smb_findopen(dnp, name, nmlen,
SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx);
if (error)
goto out;
ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
--- 727,742 ----
*** 2444,2702 ****
*
* Note: On success, this fills in mdp->md_top,
* which the caller should free.
*/
int
! smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
! struct smb_cred *scrp, uint32_t selector,
! mblk_t **res, uint32_t *reslen)
{
! struct smb_ntrq *ntp;
! struct mbchain *mbp;
! struct mdchain *mdp;
int error, len;
- error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
- scrp, &ntp);
- if (error)
- return (error);
-
- /* Parameters part */
- mbp = &ntp->nt_tparam;
- mb_init(mbp);
- mb_put_uint16le(mbp, fid);
- mb_put_uint16le(mbp, 0); /* reserved */
- mb_put_uint32le(mbp, selector);
- /* Data part (none) */
-
- /* Max. returned parameters and data. */
- ntp->nt_maxpcount = 4;
- ntp->nt_maxdcount = *reslen;
-
- error = smb_nt_request(ntp);
- if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
- goto done;
*res = NULL;
! /*
! * if there's more data than we said we could receive, here
! * is where we pick up the length of it
! */
! mdp = &ntp->nt_rparam;
! md_get_uint32le(mdp, reslen);
! if (error)
! goto done;
/*
* get the data part.
*/
! mdp = &ntp->nt_rdata;
! if (mdp->md_top == NULL) {
! SMBVDEBUG("null md_top? fid 0x%x\n", fid);
error = EBADRPC;
goto done;
}
/*
! * The returned parameter SD_length should match
! * the length of the returned data. Unfortunately,
! * we have to work around server bugs here.
*/
! len = m_fixhdr(mdp->md_top);
! if (len != *reslen) {
! SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
! len, *reslen, fid);
! }
!
! /*
! * Actual data provided is < returned SD_length.
! *
! * The following "if (len < *reslen)" handles a Windows bug
! * observed when the underlying filesystem is FAT32. In that
! * case a 32 byte security descriptor comes back (S-1-1-0, ie
! * "Everyone") but the Parameter Block claims 44 is the length
! * of the security descriptor. (The Data Block length
! * claimed is 32. This server bug was reported against NT
! * first and I've personally observed it with W2K.
! */
if (len < *reslen)
*reslen = len;
- /*
- * Actual data provided is > returned SD_length.
- * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0)
- * Narrow work-around for returned SD_length==0.
- */
- if (len > *reslen) {
- /*
- * Increase *reslen, but carefully.
- */
- if (*reslen == 0 && len <= ntp->nt_maxdcount)
- *reslen = len;
- }
- error = md_get_mbuf(mdp, len, res);
-
done:
if (error == 0 && *res == NULL) {
ASSERT(*res);
error = EBADRPC;
}
- smb_nt_done(ntp);
return (error);
}
- #ifdef APPLE
/*
- * Wrapper for _getsd() compatible with darwin code.
- */
- int
- smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
- uint32_t selector, struct ntsecdesc **res)
- {
- int error;
- uint32_t len, olen;
- struct mdchain *mdp, md_store;
- struct mbuf *m;
-
- bzero(mdp, sizeof (*mdp));
- len = 500; /* "overlarge" values => server errors */
- again:
- olen = len;
- error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len);
- /*
- * Server may give us an error indicating that we
- * need a larger data buffer to receive the SD,
- * and the size we'll need. Use the given size,
- * but only after a sanity check.
- *
- * XXX: Check for specific error values here?
- * XXX: also ... && len <= MAX_RAW_SD_SIZE
- */
- if (error && len > olen)
- goto again;
-
- if (error)
- return (error);
-
- mdp = &md_store;
- md_initm(mdp, m);
- MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
- error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
- md_done(mdp);
-
- return (error);
- }
- #endif /* APPLE */
-
- /*
* OTW function to Set a security descriptor (SD).
* Caller data are carried in an mbchain_t.
*
* Note: This normally consumes mbp->mb_top, and clears
* that pointer when it does.
*/
! int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
! struct smb_cred *scrp, uint32_t selector, mblk_t **mp)
{
! struct smb_ntrq *ntp;
! struct mbchain *mbp;
int error;
! error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
! scrp, &ntp);
! if (error)
! return (error);
!
! /* Parameters part */
! mbp = &ntp->nt_tparam;
! mb_init(mbp);
! mb_put_uint16le(mbp, fid);
! mb_put_uint16le(mbp, 0); /* reserved */
! mb_put_uint32le(mbp, selector);
!
! /* Data part */
! mbp = &ntp->nt_tdata;
! mb_initm(mbp, *mp);
! *mp = NULL; /* consumed */
!
! /* No returned parameters or data. */
! ntp->nt_maxpcount = 0;
! ntp->nt_maxdcount = 0;
!
! error = smb_nt_request(ntp);
! smb_nt_done(ntp);
!
! return (error);
! }
!
! #ifdef APPLE
! /*
! * This function builds the SD given the various parts.
! */
! int
! smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
! uint32_t selector, uint16_t flags, struct ntsid *owner,
! struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl)
! {
! struct mbchain *mbp, mb_store;
! struct ntsecdesc ntsd;
! int error, off;
!
! /*
! * Build the SD as its own mbuf chain and pass it to
! * smbfs_smb_setsec_m()
! */
! mbp = &mb_store;
! mb_init(mbp);
! bzero(&ntsd, sizeof (ntsd));
! wset_sdrevision(&ntsd);
! /*
! * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN)
! * We set here only those bits we can be sure must be set. The rest
! * are up to the caller. In particular, the caller may intentionally
! * set an acl PRESENT bit while giving us a null pointer for the
! * acl - that sets a null acl, giving access to everyone. Note also
! * that the AUTO_INHERITED bits should probably always be set unless
! * the server is NT.
! */
! flags |= SD_SELF_RELATIVE;
! off = sizeof (ntsd);
! if (owner) {
! wset_sdowneroff(&ntsd, off);
! off += sidlen(owner);
}
- if (group) {
- wset_sdgroupoff(&ntsd, off);
- off += sidlen(group);
- }
- if (sacl) {
- flags |= SD_SACL_PRESENT;
- wset_sdsacloff(&ntsd, off);
- off += acllen(sacl);
- }
- if (dacl) {
- flags |= SD_DACL_PRESENT;
- wset_sddacloff(&ntsd, off);
- }
- wset_sdflags(&ntsd, flags);
- mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM);
- if (owner)
- mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM);
- if (group)
- mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM);
- if (sacl)
- mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM);
- if (dacl)
- mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM);
- /*
- * Just pass the mbuf to _setsec_m
- * It will clear mb_top if consumed.
- */
- error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top);
- mb_done(mbp);
-
return (error);
}
-
- #endif /* APPLE */
--- 766,838 ----
*
* Note: On success, this fills in mdp->md_top,
* which the caller should free.
*/
int
! smbfs_smb_getsec(struct smb_share *ssp, smb_fh_t *fhp,
! uint32_t selector, mblk_t **res, uint32_t *reslen,
! struct smb_cred *scrp)
{
! struct smb_vc *vcp = SSTOVC(ssp);
int error, len;
*res = NULL;
! if (vcp->vc_flags & SMBV_SMB2) {
! error = smbfs_smb2_getsec(ssp, &fhp->fh_fid2,
! selector, res, reslen, scrp);
! } else {
! error = smbfs_smb1_getsec(ssp, fhp->fh_fid1,
! selector, res, reslen, scrp);
! }
/*
* get the data part.
*/
! if (*res == NULL) {
error = EBADRPC;
goto done;
}
/*
! * If message length is < returned SD_length,
! * correct *reslen (reduce it). It greater,
! * just ignore the extra data.
*/
! len = m_fixhdr(*res);
if (len < *reslen)
*reslen = len;
done:
if (error == 0 && *res == NULL) {
ASSERT(*res);
error = EBADRPC;
}
return (error);
}
/*
* OTW function to Set a security descriptor (SD).
* Caller data are carried in an mbchain_t.
*
* Note: This normally consumes mbp->mb_top, and clears
* that pointer when it does.
*/
! int
! smbfs_smb_setsec(struct smb_share *ssp, smb_fh_t *fhp,
! uint32_t selector, mblk_t **mp,
! struct smb_cred *scrp)
{
! struct smb_vc *vcp = SSTOVC(ssp);
int error;
! if (vcp->vc_flags & SMBV_SMB2) {
! error = smbfs_smb2_setsec(ssp, &fhp->fh_fid2,
! selector, mp, scrp);
! } else {
! error = smbfs_smb1_setsec(ssp, fhp->fh_fid1,
! selector, mp, scrp);
}
return (error);
}