summaryrefslogtreecommitdiffstats
path: root/sys/fs
diff options
context:
space:
mode:
authorbp <bp@FreeBSD.org>2001-04-10 07:59:06 +0000
committerbp <bp@FreeBSD.org>2001-04-10 07:59:06 +0000
commita414f03f5d87ade219aa2e4bcd0830eceaee6bd3 (patch)
treee02d13218bf41d783a93777341cba62b2921dc10 /sys/fs
parent88436d21df771b1b6d764b003c5daecf40dd767f (diff)
downloadFreeBSD-src-a414f03f5d87ade219aa2e4bcd0830eceaee6bd3.zip
FreeBSD-src-a414f03f5d87ade219aa2e4bcd0830eceaee6bd3.tar.gz
Import kernel part of SMB/CIFS requester.
Add smbfs(CIFS) filesystem. Userland part will be in the ports tree for a while. Obtained from: smbfs-1.3.7-dev package.
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/smbfs/smbfs.h112
-rw-r--r--sys/fs/smbfs/smbfs_io.c672
-rw-r--r--sys/fs/smbfs/smbfs_node.c415
-rw-r--r--sys/fs/smbfs/smbfs_node.h100
-rw-r--r--sys/fs/smbfs/smbfs_smb.c1273
-rw-r--r--sys/fs/smbfs/smbfs_subr.c326
-rw-r--r--sys/fs/smbfs/smbfs_subr.h187
-rw-r--r--sys/fs/smbfs/smbfs_vfsops.c513
-rw-r--r--sys/fs/smbfs/smbfs_vnops.c1340
9 files changed, 4938 insertions, 0 deletions
diff --git a/sys/fs/smbfs/smbfs.h b/sys/fs/smbfs/smbfs.h
new file mode 100644
index 0000000..0b9d88b
--- /dev/null
+++ b/sys/fs/smbfs/smbfs.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2000-2001, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _SMBFS_SMBFS_H_
+#define _SMBFS_SMBFS_H_
+
+#define VT_SMBFS 24
+
+#define SMBFS_VERMAJ 1
+#define SMBFS_VERMIN 1012
+#define SMBFS_VERSION (SMBFS_VERMAJ*100000 + SMBFS_VERMIN)
+#define SMBFS_VFSNAME "smbfs"
+
+/* Values for flags */
+#define SMBFS_MOUNT_SOFT 0x0001
+#define SMBFS_MOUNT_INTR 0x0002
+#define SMBFS_MOUNT_STRONG 0x0004
+#define SMBFS_MOUNT_HAVE_NLS 0x0008
+#define SMBFS_MOUNT_NO_LONG 0x0010
+
+#define SMBFS_MAXPATHCOMP 256 /* maximum number of path components */
+
+
+/* Layout of the mount control block for a netware file system. */
+struct smbfs_args {
+ int version;
+ int dev;
+ u_int flags;
+ char mount_point[MAXPATHLEN];
+ u_char root_path[512+1];
+ uid_t uid;
+ gid_t gid;
+ mode_t file_mode;
+ mode_t dir_mode;
+ int caseopt;
+};
+
+#ifdef _KERNEL
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_SMBFSMNT);
+#endif
+
+#ifndef VI_LOCK
+#define VI_LOCK(vp) smb_sl_lock(&(vp)->v_interlock)
+#define VI_UNLOCK(vp) smb_sl_unlock(&(vp)->v_interlock)
+#endif
+
+struct smbnode;
+struct smb_share;
+struct u_cred;
+struct vop_ioctl_args;
+struct buf;
+
+struct smbmount {
+ struct smbfs_args sm_args;
+ struct mount * sm_mp;
+ struct smbnode * sm_root;
+ struct ucred * sm_owner;
+ int sm_flags;
+ long sm_nextino;
+ struct smb_share * sm_share;
+/* struct simplelock sm_npslock;*/
+ struct smbnode * sm_npstack[SMBFS_MAXPATHCOMP];
+ int sm_caseopt;
+ struct lock sm_hashlock;
+ LIST_HEAD(smbnode_hashhead, smbnode) *sm_hash;
+ u_long sm_hashlen;
+};
+
+#define VFSTOSMBFS(mp) ((struct smbmount *)((mp)->mnt_data))
+#define SMBFSTOVFS(smp) ((struct mount *)((smp)->sm_mp))
+#define VTOVFS(vp) ((vp)->v_mount)
+#define VTOSMBFS(vp) (VFSTOSMBFS(VTOVFS(vp)))
+
+int smbfs_ioctl(struct vop_ioctl_args *ap);
+int smbfs_doio(struct buf *bp, struct ucred *cr, struct proc *p);
+int smbfs_vinvalbuf(struct vnode *vp, int flags, struct ucred *cred,
+ struct proc *p, int intrflg);
+#endif /* KERNEL */
+
+#endif /* _SMBFS_SMBFS_H_ */
diff --git a/sys/fs/smbfs/smbfs_io.c b/sys/fs/smbfs/smbfs_io.c
new file mode 100644
index 0000000..b275d74
--- /dev/null
+++ b/sys/fs/smbfs/smbfs_io.c
@@ -0,0 +1,672 @@
+/*
+ * Copyright (c) 2000-2001, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * 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.
+ *
+ * $FreeBSD$
+ *
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/resourcevar.h> /* defines plimit structure in proc struct */
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/mount.h>
+#include <sys/namei.h>
+#include <sys/vnode.h>
+#include <sys/dirent.h>
+#include <sys/signalvar.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+#if __FreeBSD_version < 400000
+#include <vm/vm_prot.h>
+#endif
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_pager.h>
+#include <vm/vnode_pager.h>
+/*
+#include <sys/ioccom.h>
+*/
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+
+#include <fs/smbfs/smbfs.h>
+#include <fs/smbfs/smbfs_node.h>
+#include <fs/smbfs/smbfs_subr.h>
+
+/*#define SMBFS_RWGENERIC*/
+
+extern int smbfs_pbuf_freecnt;
+
+static int smbfs_fastlookup = 1;
+
+extern struct linker_set sysctl_vfs_smbfs;
+
+SYSCTL_DECL(_vfs_smbfs);
+SYSCTL_INT(_vfs_smbfs, OID_AUTO, fastlookup, CTLFLAG_RW, &smbfs_fastlookup, 0, "");
+
+
+#define DE_SIZE (sizeof(struct dirent))
+
+static int
+smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
+{
+ struct dirent de;
+ struct componentname cn;
+ struct smb_cred scred;
+ struct smbfs_fctx *ctx;
+ struct vnode *newvp;
+ struct smbnode *np = VTOSMB(vp);
+ int error/*, *eofflag = ap->a_eofflag*/;
+ long offset, limit;
+
+ np = VTOSMB(vp);
+ SMBVDEBUG("dirname='%s'\n", np->n_name);
+ smb_makescred(&scred, uio->uio_procp, cred);
+ offset = uio->uio_offset / DE_SIZE; /* offset in the directory */
+ limit = uio->uio_resid / DE_SIZE;
+ if (uio->uio_resid < DE_SIZE || uio->uio_offset < 0)
+ return EINVAL;
+ while (limit && offset < 2) {
+ limit--;
+ bzero((caddr_t)&de, DE_SIZE);
+ de.d_reclen = DE_SIZE;
+ de.d_fileno = (offset == 0) ? np->n_ino :
+ (np->n_parent ? np->n_parent->n_ino : 2);
+ if (de.d_fileno == 0)
+ de.d_fileno = 0x7ffffffd + offset;
+ de.d_namlen = offset + 1;
+ de.d_name[0] = '.';
+ de.d_name[1] = '.';
+ de.d_name[offset + 1] = '\0';
+ de.d_type = DT_DIR;
+ error = uiomove((caddr_t)&de, DE_SIZE, uio);
+ if (error)
+ return error;
+ offset++;
+ uio->uio_offset += DE_SIZE;
+ }
+ if (limit == 0)
+ return 0;
+ if (offset != np->n_dirofs || np->n_dirseq == NULL) {
+ SMBVDEBUG("Reopening search %ld:%ld\n", offset, np->n_dirofs);
+ if (np->n_dirseq) {
+ smbfs_findclose(np->n_dirseq, &scred);
+ np->n_dirseq = NULL;
+ }
+ np->n_dirofs = 2;
+ error = smbfs_findopen(np, "*", 1,
+ SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
+ &scred, &ctx);
+ if (error) {
+ SMBVDEBUG("can not open search, error = %d", error);
+ return error;
+ }
+ np->n_dirseq = ctx;
+ } else
+ ctx = np->n_dirseq;
+ while (np->n_dirofs < offset) {
+ error = smbfs_findnext(ctx, offset - np->n_dirofs++, &scred);
+ if (error) {
+ smbfs_findclose(np->n_dirseq, &scred);
+ np->n_dirseq = NULL;
+ return error == ENOENT ? 0 : error;
+ }
+ }
+ error = 0;
+ for (; limit; limit--, offset++) {
+ error = smbfs_findnext(ctx, limit, &scred);
+ if (error)
+ break;
+ np->n_dirofs++;
+ bzero((caddr_t)&de, DE_SIZE);
+ de.d_reclen = DE_SIZE;
+ de.d_fileno = ctx->f_attr.fa_ino;
+ de.d_type = (ctx->f_attr.fa_attr & SMB_FA_DIR) ? DT_DIR : DT_REG;
+ de.d_namlen = ctx->f_nmlen;
+ bcopy(ctx->f_name, de.d_name, de.d_namlen);
+ de.d_name[de.d_namlen] = '\0';
+ if (smbfs_fastlookup) {
+ error = smbfs_nget(vp->v_mount, vp, ctx->f_name,
+ ctx->f_nmlen, &ctx->f_attr, &newvp);
+ if (!error) {
+ cn.cn_nameptr = de.d_name;
+ cn.cn_namelen = de.d_namlen;
+ cache_enter(vp, newvp, &cn);
+ vput(newvp);
+ }
+ }
+ error = uiomove((caddr_t)&de, DE_SIZE, uio);
+ if (error)
+ break;
+ }
+ if (error == ENOENT)
+ error = 0;
+ uio->uio_offset = offset * DE_SIZE;
+ return error;
+}
+
+int
+smbfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred)
+{
+ struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
+ struct smbnode *np = VTOSMB(vp);
+ struct proc *p;
+ struct vattr vattr;
+ struct smb_cred scred;
+ int error, lks;
+
+ if (vp->v_type != VREG && vp->v_type != VDIR) {
+ SMBFSERR("vn types other than VREG or VDIR are unsupported !\n");
+ return EIO;
+ }
+ if (uiop->uio_resid == 0)
+ return 0;
+ if (uiop->uio_offset < 0)
+ return EINVAL;
+/* if (uiop->uio_offset + uiop->uio_resid > smp->nm_maxfilesize)
+ return EFBIG;*/
+ p = uiop->uio_procp;
+ if (vp->v_type == VDIR) {
+ lks = LK_EXCLUSIVE;/*lockstatus(&vp->v_lock, p);*/
+ if (lks == LK_SHARED)
+ vn_lock(vp, LK_UPGRADE | LK_RETRY, p);
+ error = smbfs_readvdir(vp, uiop, cred);
+ if (lks == LK_SHARED)
+ vn_lock(vp, LK_DOWNGRADE | LK_RETRY, p);
+ return error;
+ }
+
+/* biosize = SSTOCN(smp->sm_share)->sc_txmax;*/
+ if (np->n_flag & NMODIFIED) {
+ smbfs_attr_cacheremove(vp);
+ error = VOP_GETATTR(vp, &vattr, cred, p);
+ if (error)
+ return error;
+ np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
+ } else {
+ error = VOP_GETATTR(vp, &vattr, cred, p);
+ if (error)
+ return error;
+ if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) {
+ error = smbfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
+ if (error)
+ return error;
+ np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
+ }
+ }
+ smb_makescred(&scred, p, cred);
+ return smb_read(smp->sm_share, np->n_fid, uiop, &scred);
+}
+
+int
+smbfs_writevnode(struct vnode *vp, struct uio *uiop,
+ struct ucred *cred, int ioflag)
+{
+ struct smbmount *smp = VTOSMBFS(vp);
+ struct smbnode *np = VTOSMB(vp);
+ struct smb_cred scred;
+ struct proc *p;
+ int error = 0;
+
+ if (vp->v_type != VREG) {
+ SMBERROR("vn types other than VREG unsupported !\n");
+ return EIO;
+ }
+ SMBVDEBUG("ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
+ if (uiop->uio_offset < 0)
+ return EINVAL;
+/* if (uiop->uio_offset + uiop->uio_resid > smp->nm_maxfilesize)
+ return (EFBIG);*/
+ p = uiop->uio_procp;
+ if (ioflag & (IO_APPEND | IO_SYNC)) {
+ if (np->n_flag & NMODIFIED) {
+ smbfs_attr_cacheremove(vp);
+ error = smbfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
+ if (error)
+ return error;
+ }
+ if (ioflag & IO_APPEND) {
+#if notyet
+ /*
+ * File size can be changed by another client
+ */
+ smbfs_attr_cacheremove(vp);
+ error = VOP_GETATTR(vp, &vattr, cred, p);
+ if (error) return (error);
+#endif
+ uiop->uio_offset = np->n_size;
+ }
+ }
+ if (uiop->uio_resid == 0)
+ return 0;
+ if (p && uiop->uio_offset + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
+ psignal(p, SIGXFSZ);
+ return EFBIG;
+ }
+ smb_makescred(&scred, p, cred);
+ error = smb_write(smp->sm_share, np->n_fid, uiop, &scred);
+ SMBVDEBUG("after: ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
+ if (!error) {
+ if (uiop->uio_offset > np->n_size) {
+ np->n_size = uiop->uio_offset;
+ vnode_pager_setsize(vp, np->n_size);
+ }
+ }
+ return error;
+}
+
+/*
+ * Do an I/O operation to/from a cache block.
+ */
+int
+smbfs_doio(struct buf *bp, struct ucred *cr, struct proc *p)
+{
+ struct vnode *vp = bp->b_vp;
+ struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
+ struct smbnode *np = VTOSMB(vp);
+ struct uio uio, *uiop = &uio;
+ struct iovec io;
+ struct smb_cred scred;
+ int error = 0;
+
+ uiop->uio_iov = &io;
+ uiop->uio_iovcnt = 1;
+ uiop->uio_segflg = UIO_SYSSPACE;
+ uiop->uio_procp = p;
+
+ smb_makescred(&scred, p, cr);
+
+ if (bp->b_iocmd == BIO_READ) {
+ io.iov_len = uiop->uio_resid = bp->b_bcount;
+ io.iov_base = bp->b_data;
+ uiop->uio_rw = UIO_READ;
+ switch (vp->v_type) {
+ case VREG:
+ uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
+ error = smb_read(smp->sm_share, np->n_fid, uiop, &scred);
+ if (error)
+ break;
+ if (uiop->uio_resid) {
+ int left = uiop->uio_resid;
+ int nread = bp->b_bcount - left;
+ if (left > 0)
+ bzero((char *)bp->b_data + nread, left);
+ }
+ break;
+ default:
+ printf("smbfs_doio: type %x unexpected\n",vp->v_type);
+ break;
+ };
+ if (error) {
+ bp->b_error = error;
+ bp->b_ioflags |= BIO_ERROR;
+ }
+ } else { /* write */
+ if (((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend) > np->n_size)
+ bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);
+
+ if (bp->b_dirtyend > bp->b_dirtyoff) {
+ io.iov_len = uiop->uio_resid = bp->b_dirtyend - bp->b_dirtyoff;
+ uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
+ io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
+ uiop->uio_rw = UIO_WRITE;
+ bp->b_flags |= B_WRITEINPROG;
+ error = smb_write(smp->sm_share, np->n_fid, uiop, &scred);
+ bp->b_flags &= ~B_WRITEINPROG;
+
+ /*
+ * For an interrupted write, the buffer is still valid
+ * and the write hasn't been pushed to the server yet,
+ * so we can't set BIO_ERROR and report the interruption
+ * by setting B_EINTR. For the B_ASYNC case, B_EINTR
+ * is not relevant, so the rpc attempt is essentially
+ * a noop. For the case of a V3 write rpc not being
+ * committed to stable storage, the block is still
+ * dirty and requires either a commit rpc or another
+ * write rpc with iomode == NFSV3WRITE_FILESYNC before
+ * the block is reused. This is indicated by setting
+ * the B_DELWRI and B_NEEDCOMMIT flags.
+ */
+ if (error == EINTR
+ || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
+ int s;
+
+ s = splbio();
+ bp->b_flags &= ~(B_INVAL|B_NOCACHE);
+ if ((bp->b_flags & B_ASYNC) == 0)
+ bp->b_flags |= B_EINTR;
+ if ((bp->b_flags & B_PAGING) == 0) {
+ bdirty(bp);
+ bp->b_flags &= ~B_DONE;
+ }
+ if ((bp->b_flags & B_ASYNC) == 0)
+ bp->b_flags |= B_EINTR;
+ splx(s);
+ } else {
+ if (error) {
+ bp->b_ioflags |= BIO_ERROR;
+ bp->b_error = error;
+ }
+ bp->b_dirtyoff = bp->b_dirtyend = 0;
+ }
+ } else {
+ bp->b_resid = 0;
+ bufdone(bp);
+ return 0;
+ }
+ }
+ bp->b_resid = uiop->uio_resid;
+ bufdone(bp);
+ return error;
+}
+
+/*
+ * Vnode op for VM getpages.
+ * Wish wish .... get rid from multiple IO routines
+ */
+int
+smbfs_getpages(ap)
+ struct vop_getpages_args /* {
+ struct vnode *a_vp;
+ vm_page_t *a_m;
+ int a_count;
+ int a_reqpage;
+ vm_ooffset_t a_offset;
+ } */ *ap;
+{
+#ifdef SMBFS_RWGENERIC
+ return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
+ ap->a_reqpage);
+#else
+ int i, error, nextoff, size, toff, npages, count;
+ struct uio uio;
+ struct iovec iov;
+ vm_offset_t kva;
+ struct buf *bp;
+ struct vnode *vp;
+ struct proc *p;
+ struct ucred *cred;
+ struct smbmount *smp;
+ struct smbnode *np;
+ struct smb_cred scred;
+ vm_page_t *pages;
+
+ vp = ap->a_vp;
+ p = curproc; /* XXX */
+ cred = curproc->p_ucred; /* XXX */
+ np = VTOSMB(vp);
+ smp = VFSTOSMBFS(vp->v_mount);
+ pages = ap->a_m;
+ count = ap->a_count;
+
+ if (vp->v_object == NULL) {
+ printf("smbfs_getpages: called with non-merged cache vnode??\n");
+ return VM_PAGER_ERROR;
+ }
+ smb_makescred(&scred, p, cred);
+
+#if __FreeBSD_version >= 400000
+ bp = getpbuf(&smbfs_pbuf_freecnt);
+#else
+ bp = getpbuf();
+#endif
+ npages = btoc(count);
+ kva = (vm_offset_t) bp->b_data;
+ pmap_qenter(kva, pages, npages);
+
+ iov.iov_base = (caddr_t) kva;
+ iov.iov_len = count;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
+ uio.uio_resid = count;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_READ;
+ uio.uio_procp = p;
+
+ error = smb_read(smp->sm_share, np->n_fid, &uio, &scred);
+ pmap_qremove(kva, npages);
+
+#if __FreeBSD_version >= 400000
+ relpbuf(bp, &smbfs_pbuf_freecnt);
+#else
+ relpbuf(bp);
+#endif
+
+ if (error && (uio.uio_resid == count)) {
+ printf("smbfs_getpages: error %d\n",error);
+ for (i = 0; i < npages; i++) {
+ if (ap->a_reqpage != i)
+ vnode_pager_freepage(pages[i]);
+ }
+ return VM_PAGER_ERROR;
+ }
+
+ size = count - uio.uio_resid;
+
+ for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
+ vm_page_t m;
+ nextoff = toff + PAGE_SIZE;
+ m = pages[i];
+
+ m->flags &= ~PG_ZERO;
+
+ if (nextoff <= size) {
+ m->valid = VM_PAGE_BITS_ALL;
+ m->dirty = 0;
+ } else {
+ int nvalid = ((size + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1);
+ vm_page_set_validclean(m, 0, nvalid);
+ }
+
+ if (i != ap->a_reqpage) {
+ /*
+ * Whether or not to leave the page activated is up in
+ * the air, but we should put the page on a page queue
+ * somewhere (it already is in the object). Result:
+ * It appears that emperical results show that
+ * deactivating pages is best.
+ */
+
+ /*
+ * Just in case someone was asking for this page we
+ * now tell them that it is ok to use.
+ */
+ if (!error) {
+ if (m->flags & PG_WANTED)
+ vm_page_activate(m);
+ else
+ vm_page_deactivate(m);
+ vm_page_wakeup(m);
+ } else {
+ vnode_pager_freepage(m);
+ }
+ }
+ }
+ return 0;
+#endif /* SMBFS_RWGENERIC */
+}
+
+/*
+ * Vnode op for VM putpages.
+ * possible bug: all IO done in sync mode
+ * Note that vop_close always invalidate pages before close, so it's
+ * not necessary to open vnode.
+ */
+int
+smbfs_putpages(ap)
+ struct vop_putpages_args /* {
+ struct vnode *a_vp;
+ vm_page_t *a_m;
+ int a_count;
+ int a_sync;
+ int *a_rtvals;
+ vm_ooffset_t a_offset;
+ } */ *ap;
+{
+ int error;
+ struct vnode *vp = ap->a_vp;
+ struct proc *p;
+ struct ucred *cred;
+
+#ifdef SMBFS_RWGENERIC
+ p = curproc; /* XXX */
+ cred = p->p_ucred; /* XXX */
+ VOP_OPEN(vp, FWRITE, cred, p);
+ error = vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
+ ap->a_sync, ap->a_rtvals);
+ VOP_CLOSE(vp, FWRITE, cred, p);
+ return error;
+#else
+ struct uio uio;
+ struct iovec iov;
+ vm_offset_t kva;
+ struct buf *bp;
+ int i, npages, count;
+ int *rtvals;
+ struct smbmount *smp;
+ struct smbnode *np;
+ struct smb_cred scred;
+ vm_page_t *pages;
+
+ p = curproc; /* XXX */
+ cred = p->p_ucred; /* XXX */
+/* VOP_OPEN(vp, FWRITE, cred, p);*/
+ np = VTOSMB(vp);
+ smp = VFSTOSMBFS(vp->v_mount);
+ pages = ap->a_m;
+ count = ap->a_count;
+ rtvals = ap->a_rtvals;
+ npages = btoc(count);
+
+ for (i = 0; i < npages; i++) {
+ rtvals[i] = VM_PAGER_AGAIN;
+ }
+
+#if __FreeBSD_version >= 400000
+ bp = getpbuf(&smbfs_pbuf_freecnt);
+#else
+ bp = getpbuf();
+#endif
+ kva = (vm_offset_t) bp->b_data;
+ pmap_qenter(kva, pages, npages);
+
+ iov.iov_base = (caddr_t) kva;
+ iov.iov_len = count;
+ uio.uio_iov = &iov;
+ uio.uio_iovcnt = 1;
+ uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
+ uio.uio_resid = count;
+ uio.uio_segflg = UIO_SYSSPACE;
+ uio.uio_rw = UIO_WRITE;
+ uio.uio_procp = p;
+ SMBVDEBUG("ofs=%d,resid=%d\n",(int)uio.uio_offset, uio.uio_resid);
+
+ smb_makescred(&scred, p, cred);
+ error = smb_write(smp->sm_share, np->n_fid, &uio, &scred);
+/* VOP_CLOSE(vp, FWRITE, cred, p);*/
+ SMBVDEBUG("paged write done: %d\n", error);
+
+ pmap_qremove(kva, npages);
+#if __FreeBSD_version >= 400000
+ relpbuf(bp, &smbfs_pbuf_freecnt);
+#else
+ relpbuf(bp);
+#endif
+
+ if (!error) {
+ int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
+ for (i = 0; i < nwritten; i++) {
+ rtvals[i] = VM_PAGER_OK;
+ pages[i]->dirty = 0;
+ }
+ }
+ return rtvals[0];
+#endif /* SMBFS_RWGENERIC */
+}
+
+/*
+ * Flush and invalidate all dirty buffers. If another process is already
+ * doing the flush, just wait for completion.
+ */
+int
+smbfs_vinvalbuf(vp, flags, cred, p, intrflg)
+ struct vnode *vp;
+ int flags;
+ struct ucred *cred;
+ struct proc *p;
+ int intrflg;
+{
+ struct smbnode *np = VTOSMB(vp);
+ int error = 0, slpflag, slptimeo;
+
+ if (vp->v_flag & VXLOCK)
+ return 0;
+ if (intrflg) {
+ slpflag = PCATCH;
+ slptimeo = 2 * hz;
+ } else {
+ slpflag = 0;
+ slptimeo = 0;
+ }
+ while (np->n_flag & NFLUSHINPROG) {
+ np->n_flag |= NFLUSHWANT;
+ error = tsleep((caddr_t)&np->n_flag, PRIBIO + 2, "smfsvinv", slptimeo);
+ error = smb_proc_intr(p);
+ if (error == EINTR && intrflg)
+ return EINTR;
+ }
+ np->n_flag |= NFLUSHINPROG;
+ error = vinvalbuf(vp, flags, cred, p, slpflag, 0);
+ while (error) {
+ if (intrflg && (error == ERESTART || error == EINTR)) {
+ np->n_flag &= ~NFLUSHINPROG;
+ if (np->n_flag & NFLUSHWANT) {
+ np->n_flag &= ~NFLUSHWANT;
+ wakeup((caddr_t)&np->n_flag);
+ }
+ return EINTR;
+ }
+ error = vinvalbuf(vp, flags, cred, p, slpflag, 0);
+ }
+ np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
+ if (np->n_flag & NFLUSHWANT) {
+ np->n_flag &= ~NFLUSHWANT;
+ wakeup((caddr_t)&np->n_flag);
+ }
+ return (error);
+}
diff --git a/sys/fs/smbfs/smbfs_node.c b/sys/fs/smbfs/smbfs_node.c
new file mode 100644
index 0000000..0d98605
--- /dev/null
+++ b/sys/fs/smbfs/smbfs_node.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+/*#include <vm/vm_page.h>
+#include <vm/vm_object.h>*/
+#include <sys/queue.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+
+#include <fs/smbfs/smbfs.h>
+#include <fs/smbfs/smbfs_node.h>
+#include <fs/smbfs/smbfs_subr.h>
+
+#define SMBFS_NOHASH(smp, hval) (&(smp)->sm_hash[(hval) & (smp)->sm_hashlen])
+#define smbfs_hash_lock(smp, p) lockmgr(&smp->sm_hashlock, LK_EXCLUSIVE, NULL, p)
+#define smbfs_hash_unlock(smp, p) lockmgr(&smp->sm_hashlock, LK_RELEASE, NULL, p)
+
+
+extern vop_t **smbfs_vnodeop_p;
+
+MALLOC_DEFINE(M_SMBNODE, "SMBFS node", "SMBFS vnode private part");
+static MALLOC_DEFINE(M_SMBNODENAME, "SMBFS nname", "SMBFS node name");
+
+int smbfs_hashprint(struct mount *mp);
+
+#if 0
+extern struct linker_set sysctl_vfs_smbfs;
+#ifdef SYSCTL_DECL
+SYSCTL_DECL(_vfs_smbfs);
+#endif
+SYSCTL_PROC(_vfs_smbfs, OID_AUTO, vnprint, CTLFLAG_WR|CTLTYPE_OPAQUE,
+ NULL, 0, smbfs_hashprint, "S,vnlist", "vnode hash");
+#endif
+
+#define FNV_32_PRIME ((u_int32_t) 0x01000193UL)
+#define FNV1_32_INIT ((u_int32_t) 33554467UL)
+
+u_int32_t
+smbfs_hash(const u_char *name, int nmlen)
+{
+ u_int32_t v;
+
+ for (v = FNV1_32_INIT; nmlen; name++, nmlen--) {
+ v *= FNV_32_PRIME;
+ v ^= (u_int32_t)*name;
+ }
+ return v;
+}
+
+int
+smbfs_hashprint(struct mount *mp)
+{
+ struct smbmount *smp = VFSTOSMBFS(mp);
+ struct smbnode_hashhead *nhpp;
+ struct smbnode *np;
+ int i;
+
+ for(i = 0; i <= smp->sm_hashlen; i++) {
+ nhpp = &smp->sm_hash[i];
+ LIST_FOREACH(np, nhpp, n_hash)
+ vprint(NULL, SMBTOV(np));
+ }
+ return 0;
+}
+
+static char *
+smbfs_name_alloc(const u_char *name, int nmlen)
+{
+ u_char *cp;
+
+ nmlen++;
+#ifdef SMBFS_NAME_DEBUG
+ cp = malloc(nmlen + 2 + sizeof(int), M_SMBNODENAME, M_WAITOK);
+ *(int*)cp = nmlen;
+ cp += sizeof(int);
+ cp[0] = 0xfc;
+ cp++;
+ bcopy(name, cp, nmlen - 1);
+ cp[nmlen] = 0xfe;
+#else
+ cp = malloc(nmlen, M_SMBNODENAME, M_WAITOK);
+ bcopy(name, cp, nmlen - 1);
+#endif
+ cp[nmlen - 1] = 0;
+ return cp;
+}
+
+static void
+smbfs_name_free(u_char *name)
+{
+#ifdef SMBFS_NAME_DEBUG
+ int nmlen, slen;
+ u_char *cp;
+
+ cp = name;
+ cp--;
+ if (*cp != 0xfc) {
+ printf("First byte of name entry '%s' corrupted\n", name);
+ Debugger("ditto");
+ }
+ cp -= sizeof(int);
+ nmlen = *(int*)cp;
+ slen = strlen(name) + 1;
+ if (nmlen != slen) {
+ printf("Name length mismatch: was %d, now %d name '%s'\n",
+ nmlen, slen, name);
+ Debugger("ditto");
+ }
+ if (name[nmlen] != 0xfe) {
+ printf("Last byte of name entry '%s' corrupted\n", name);
+ Debugger("ditto");
+ }
+ free(cp, M_SMBNODENAME);
+#else
+ free(name, M_SMBNODENAME);
+#endif
+}
+
+static int
+smbfs_node_alloc(struct mount *mp, struct vnode *dvp,
+ const char *name, int nmlen, struct smbfattr *fap, struct vnode **vpp)
+{
+ struct proc *p = curproc; /* XXX */
+ struct smbmount *smp = VFSTOSMBFS(mp);
+ struct smbnode_hashhead *nhpp;
+ struct smbnode *np, *np2, *dnp;
+ struct vnode *vp;
+ u_long hashval;
+ int error;
+
+ *vpp = NULL;
+ if (smp->sm_root != NULL && dvp == NULL) {
+ SMBERROR("do not allocate root vnode twice!\n");
+ return EINVAL;
+ }
+ if (nmlen == 2 && bcmp(name, "..", 2) == 0) {
+ if (dvp == NULL)
+ return EINVAL;
+ vp = VTOSMB(dvp)->n_parent->n_vnode;
+ error = vget(vp, LK_EXCLUSIVE, p);
+ if (error == 0)
+ *vpp = vp;
+ return error;
+ } else if (nmlen == 1 && name[0] == '.') {
+ SMBERROR("do not call me with dot!\n");
+ return EINVAL;
+ }
+ dnp = dvp ? VTOSMB(dvp) : NULL;
+ if (dnp == NULL && dvp != NULL) {
+ vprint("smbfs_node_alloc: dead parent vnode", dvp);
+ return EINVAL;
+ }
+ hashval = smbfs_hash(name, nmlen);
+retry:
+ smbfs_hash_lock(smp, p);
+loop:
+ nhpp = SMBFS_NOHASH(smp, hashval);
+ LIST_FOREACH(np, nhpp, n_hash) {
+ vp = SMBTOV(np);
+ if (np->n_parent != dnp ||
+ np->n_nmlen != nmlen || bcmp(name, np->n_name, nmlen) != 0)
+ continue;
+ VI_LOCK(vp);
+ smbfs_hash_unlock(smp, p);
+ if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p) != 0)
+ goto retry;
+ *vpp = vp;
+ return 0;
+ }
+ smbfs_hash_unlock(smp, p);
+ /*
+ * If we don't have node attributes, then it is an explicit lookup
+ * for an existing vnode.
+ */
+ if (fap == NULL)
+ return ENOENT;
+
+ MALLOC(np, struct smbnode *, sizeof *np, M_SMBNODE, M_WAITOK);
+ error = getnewvnode(VT_SMBFS, mp, smbfs_vnodeop_p, &vp);
+ if (error) {
+ FREE(np, M_SMBNODE);
+ return error;
+ }
+ vp->v_type = fap->fa_attr & SMB_FA_DIR ? VDIR : VREG;
+ bzero(np, sizeof(*np));
+ vp->v_data = np;
+ np->n_vnode = vp;
+ np->n_mount = VFSTOSMBFS(mp);
+ np->n_nmlen = nmlen;
+ np->n_name = smbfs_name_alloc(name, nmlen);
+ np->n_ino = fap->fa_ino;
+
+ if (dvp) {
+ np->n_parent = dnp;
+ if (/*vp->v_type == VDIR &&*/ (dvp->v_flag & VROOT) == 0) {
+ vref(dvp);
+ np->n_flag |= NREFPARENT;
+ }
+ } else if (vp->v_type == VREG)
+ SMBERROR("new vnode '%s' born without parent ?\n", np->n_name);
+
+ lockinit(&vp->v_lock, PINOD, "smbnode", 0, LK_CANRECURSE);
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+
+ smbfs_hash_lock(smp, p);
+ LIST_FOREACH(np2, nhpp, n_hash) {
+ if (np2->n_parent != dnp ||
+ np2->n_nmlen != nmlen || bcmp(name, np2->n_name, nmlen) != 0)
+ continue;
+ vput(vp);
+/* smb_name_free(np->n_name);
+ FREE(np, M_SMBNODE);*/
+ goto loop;
+ }
+ LIST_INSERT_HEAD(nhpp, np, n_hash);
+ smbfs_hash_unlock(smp, p);
+ *vpp = vp;
+ return 0;
+}
+
+int
+smbfs_nget(struct mount *mp, struct vnode *dvp, const char *name, int nmlen,
+ struct smbfattr *fap, struct vnode **vpp)
+{
+ struct smbnode *np;
+ struct vnode *vp;
+ int error;
+
+ *vpp = NULL;
+ error = smbfs_node_alloc(mp, dvp, name, nmlen, fap, &vp);
+ if (error)
+ return error;
+ np = VTOSMB(vp);
+ if (fap)
+ smbfs_attr_cacheenter(vp, fap);
+ *vpp = vp;
+ return 0;
+}
+
+/*
+ * Free smbnode, and give vnode back to system
+ */
+int
+smbfs_reclaim(ap)
+ struct vop_reclaim_args /* {
+ struct vnode *a_vp;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct proc *p = ap->a_p;
+ struct vnode *dvp;
+ struct smbnode *np = VTOSMB(vp);
+ struct smbmount *smp = VTOSMBFS(vp);
+
+ SMBVDEBUG("%s,%d\n", np->n_name, vp->v_usecount);
+
+ smbfs_hash_lock(smp, p);
+
+ dvp = (np->n_parent && (np->n_flag & NREFPARENT)) ?
+ np->n_parent->n_vnode : NULL;
+
+ if (np->n_hash.le_prev)
+ LIST_REMOVE(np, n_hash);
+ cache_purge(vp);
+ if (smp->sm_root == np) {
+ SMBVDEBUG("root vnode\n");
+ smp->sm_root = NULL;
+ }
+ vp->v_data = NULL;
+ smbfs_hash_unlock(smp, p);
+ if (np->n_name)
+ smbfs_name_free(np->n_name);
+ FREE(np, M_SMBNODE);
+ if (dvp) {
+ VI_LOCK(dvp);
+ if (dvp->v_usecount >= 1) {
+ VI_UNLOCK(dvp);
+ vrele(dvp);
+ } else {
+ VI_UNLOCK(dvp);
+ SMBERROR("BUG: negative use count for parent!\n");
+ }
+ }
+ return 0;
+}
+
+int
+smbfs_inactive(ap)
+ struct vop_inactive_args /* {
+ struct vnode *a_vp;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct proc *p = ap->a_p;
+ struct ucred *cred = p->p_ucred;
+ struct vnode *vp = ap->a_vp;
+ struct smbnode *np = VTOSMB(vp);
+ struct smb_cred scred;
+ int error;
+
+ SMBVDEBUG("%s: %d\n", VTOSMB(vp)->n_name, vp->v_usecount);
+ if (np->n_opencount) {
+ error = smbfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
+ smb_makescred(&scred, p, cred);
+ error = smbfs_smb_close(np->n_mount->sm_share, np->n_fid,
+ &np->n_mtime, &scred);
+ np->n_opencount = 0;
+ }
+ VOP_UNLOCK(vp, 0, p);
+ return (0);
+}
+/*
+ * routines to maintain vnode attributes cache
+ * smbfs_attr_cacheenter: unpack np.i to vattr structure
+ */
+void
+smbfs_attr_cacheenter(struct vnode *vp, struct smbfattr *fap)
+{
+ struct smbnode *np = VTOSMB(vp);
+
+ if (vp->v_type == VREG) {
+ if (np->n_size != fap->fa_size) {
+ np->n_size = fap->fa_size;
+ vnode_pager_setsize(vp, np->n_size);
+ }
+ } else if (vp->v_type == VDIR) {
+ np->n_size = 16384; /* should be a better way ... */
+ } else
+ return;
+ np->n_mtime = fap->fa_mtime;
+ np->n_dosattr = fap->fa_attr;
+ np->n_attrage = time_second;
+ return;
+}
+
+int
+smbfs_attr_cachelookup(struct vnode *vp, struct vattr *va)
+{
+ struct smbnode *np = VTOSMB(vp);
+ struct smbmount *smp = VTOSMBFS(vp);
+ int diff;
+
+ diff = time_second - np->n_attrage;
+ if (diff > 2) /* XXX should be configurable */
+ return ENOENT;
+ va->va_type = vp->v_type; /* vnode type (for create) */
+ if (vp->v_type == VREG) {
+ va->va_mode = smp->sm_args.file_mode; /* files access mode and type */
+ } else if (vp->v_type == VDIR) {
+ va->va_mode = smp->sm_args.dir_mode; /* files access mode and type */
+ } else
+ return EINVAL;
+ va->va_size = np->n_size;
+ va->va_nlink = 1; /* number of references to file */
+ va->va_uid = smp->sm_args.uid; /* owner user id */
+ va->va_gid = smp->sm_args.gid; /* owner group id */
+ va->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
+ va->va_fileid = np->n_ino; /* file id */
+ if (va->va_fileid == 0)
+ va->va_fileid = 2;
+ va->va_blocksize = SSTOVC(smp->sm_share)->vc_txmax;
+ va->va_mtime = np->n_mtime;
+ va->va_atime = va->va_ctime = va->va_mtime; /* time file changed */
+ va->va_gen = VNOVAL; /* generation number of file */
+ va->va_flags = 0; /* flags defined for file */
+ va->va_rdev = VNOVAL; /* device the special file represents */
+ va->va_bytes = va->va_size; /* bytes of disk space held by file */
+ va->va_filerev = 0; /* file modification number */
+ va->va_vaflags = 0; /* operations flags */
+ return 0;
+}
diff --git a/sys/fs/smbfs/smbfs_node.h b/sys/fs/smbfs/smbfs_node.h
new file mode 100644
index 0000000..1a5a643
--- /dev/null
+++ b/sys/fs/smbfs/smbfs_node.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2000-2001, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _FS_SMBFS_NODE_H_
+#define _FS_SMBFS_NODE_H_
+
+#define SMBFS_ROOT_INO 2 /* just like in UFS */
+
+/* Bits for smbnode.n_flag */
+#define NFLUSHINPROG 0x0001
+#define NFLUSHWANT 0x0002 /* they should gone ... */
+#define NMODIFIED 0x0004 /* bogus, until async IO implemented */
+/*efine NNEW 0x0008*//* smb/vnode has been allocated */
+#define NREFPARENT 0x0010 /* node holds parent from recycling */
+
+struct smbfs_fctx;
+
+struct smbnode {
+#ifndef FB_CURRENT
+ struct lock n_lock; /* smbnode lock. (mbf) */
+#endif
+ int n_flag;
+ struct smbnode * n_parent;
+ struct vnode * n_vnode;
+ struct smbmount * n_mount;
+ time_t n_attrage; /* attributes cache time */
+/* time_t n_ctime;*/
+ struct timespec n_mtime; /* modify time */
+ struct timespec n_atime; /* last access time */
+ u_quad_t n_size;
+ long n_ino;
+ int n_dosattr;
+ int n_opencount;
+ u_int16_t n_fid; /* file handle */
+ int n_rwstate; /* granted access mode */
+ u_char n_nmlen;
+ u_char * n_name;
+ struct smbfs_fctx * n_dirseq; /* ff context */
+ long n_dirofs; /* last ff offset */
+ struct lockf * n_lockf; /* Locking records of file */
+ LIST_ENTRY(smbnode) n_hash;
+};
+
+#define VTOSMB(vp) ((struct smbnode *)(vp)->v_data)
+#define SMBTOV(np) ((struct vnode *)(np)->n_vnode)
+
+struct vop_getpages_args;
+struct vop_inactive_args;
+struct vop_putpages_args;
+struct vop_reclaim_args;
+struct ucred;
+struct uio;
+struct smbfattr;
+
+int smbfs_inactive(struct vop_inactive_args *);
+int smbfs_reclaim(struct vop_reclaim_args *);
+int smbfs_nget(struct mount *mp, struct vnode *dvp, const char *name, int nmlen,
+ struct smbfattr *fap, struct vnode **vpp);
+u_int32_t smbfs_hash(const u_char *name, int nmlen);
+
+int smbfs_getpages(struct vop_getpages_args *);
+int smbfs_putpages(struct vop_putpages_args *);
+int smbfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred);
+int smbfs_writevnode(struct vnode *vp, struct uio *uiop, struct ucred *cred, int ioflag);
+void smbfs_attr_cacheenter(struct vnode *vp, struct smbfattr *fap);
+int smbfs_attr_cachelookup(struct vnode *vp ,struct vattr *va);
+
+#define smbfs_attr_cacheremove(vp) VTOSMB(vp)->n_attrage = 0
+
+#endif /* _FS_SMBFS_NODE_H_ */
diff --git a/sys/fs/smbfs/smbfs_smb.c b/sys/fs/smbfs/smbfs_smb.c
new file mode 100644
index 0000000..373d5c1
--- /dev/null
+++ b/sys/fs/smbfs/smbfs_smb.c
@@ -0,0 +1,1273 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/vnode.h>
+#include <sys/mbuf.h>
+#include <sys/mount.h>
+
+#ifdef USE_MD5_HASH
+#include <sys/md5.h>
+#endif
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb_conn.h>
+
+#include <fs/smbfs/smbfs.h>
+#include <fs/smbfs/smbfs_node.h>
+#include <fs/smbfs/smbfs_subr.h>
+
+/*
+ * Lack of inode numbers leads us to the problem of generating them.
+ * Partially this problem can be solved by having a dir/file cache
+ * with inode numbers generated from the incremented by one counter.
+ * However this way will require too much kernel memory, gives all
+ * sorts of locking and consistency problems, not to mentinon counter overflows.
+ * So, I'm decided to use a hash function to generate pseudo random (and unique)
+ * inode numbers.
+ */
+static long
+smbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
+{
+#ifdef USE_MD5_HASH
+ MD5_CTX md5;
+ u_int32_t state[4];
+ long ino;
+ int i;
+
+ MD5Init(&md5);
+ MD5Update(&md5, name, nmlen);
+ MD5Final((u_char *)state, &md5);
+ for (i = 0, ino = 0; i < 4; i++)
+ ino += state[i];
+ return dnp->n_ino + ino;
+#endif
+ u_int32_t ino;
+
+ ino = dnp->n_ino + smbfs_hash(name, nmlen);
+ if (ino <= 2)
+ ino += 3;
+ return ino;
+}
+
+static int
+smbfs_smb_lockandx(struct smbnode *np, int op, u_int32_t pid, off_t start, off_t end,
+ struct smb_cred *scred)
+{
+ struct smb_share *ssp = np->n_mount->sm_share;
+ struct smb_rq rq, *rqp = &rq;
+ struct mbchain *mbp;
+ u_char ltype = 0;
+ int error;
+
+ if (op == SMB_LOCK_SHARED)
+ ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scred);
+ 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_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+ mb_put_uint8(mbp, ltype); /* locktype */
+ mb_put_uint8(mbp, 0); /* oplocklevel - 0 seems is NO_OPLOCK */
+ mb_put_uint32le(mbp, 0); /* timeout - break immediately */
+ 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);
+ mb_put_uint32le(mbp, start);
+ mb_put_uint32le(mbp, end - start);
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return error;
+}
+
+int
+smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
+ off_t start, off_t end, struct smb_cred *scred)
+{
+ struct smb_share *ssp = np->n_mount->sm_share;
+
+ if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
+ /*
+ * TODO: use LOCK_BYTE_RANGE here.
+ */
+ return EINVAL;
+ else
+ return smbfs_smb_lockandx(np, op, (u_int32_t)id, start, end, scred);
+}
+
+int
+smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp,
+ struct smb_cred *scred)
+{
+ struct smb_t2rq *t2p;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ u_int16_t bsize;
+ u_int32_t units, bpu, funits;
+ int error;
+
+ error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
+ scred, &t2p);
+ if (error)
+ return error;
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, SMB_INFO_ALLOCATION);
+ t2p->t2_maxpcount = 4;
+ t2p->t2_maxdcount = 4 * 4 + 2;
+ error = smb_t2_request(t2p);
+ if (error) {
+ smb_t2_done(t2p);
+ return error;
+ }
+ mdp = &t2p->t2_rdata;
+ md_get_uint32(mdp, NULL); /* fs id */
+ md_get_uint32le(mdp, &bpu);
+ md_get_uint32le(mdp, &units);
+ md_get_uint32le(mdp, &funits);
+ md_get_uint16le(mdp, &bsize);
+ sbp->f_bsize = bpu * bsize; /* fundamental file system block size */
+ sbp->f_blocks= units; /* total data blocks in file system */
+ sbp->f_bfree = funits; /* free blocks in fs */
+ sbp->f_bavail= funits; /* free blocks avail to non-superuser */
+ sbp->f_files = 0xffff; /* total file nodes in file system */
+ sbp->f_ffree = 0xffff; /* free file nodes in fs */
+ smb_t2_done(t2p);
+ return 0;
+}
+
+int
+smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
+ struct smb_cred *scred)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct mdchain *mdp;
+ u_int16_t units, bpu, bsize, funits;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK, scred);
+ 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) {
+ smb_rq_done(rqp);
+ return error;
+ }
+ smb_rq_getreply(rqp, &mdp);
+ md_get_uint16le(mdp, &units);
+ md_get_uint16le(mdp, &bpu);
+ md_get_uint16le(mdp, &bsize);
+ md_get_uint16le(mdp, &funits);
+ sbp->f_bsize = bpu * bsize; /* fundamental file system block size */
+ sbp->f_blocks= units; /* total data blocks in file system */
+ sbp->f_bfree = funits; /* free blocks in fs */
+ sbp->f_bavail= funits; /* free blocks avail to non-superuser */
+ sbp->f_files = 0xffff; /* total file nodes in file system */
+ sbp->f_ffree = 0xffff; /* free file nodes in fs */
+ smb_rq_done(rqp);
+ return 0;
+}
+
+int
+smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred)
+{
+ struct smb_share *ssp = np->n_mount->sm_share;
+ struct smb_rq rq, *rqp = &rq;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scred);
+ if (error)
+ return error;
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+ 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);
+ return error;
+}
+
+
+/*
+ * Set DOS file attributes. mtime should be NULL for dialects above lm10
+ */
+int
+smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
+ struct smb_cred *scred)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct smb_share *ssp = np->n_mount->sm_share;
+ struct mbchain *mbp;
+ u_long time;
+ int error, svtz;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scred);
+ if (error)
+ return error;
+ svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, 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);
+ do {
+ error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
+ if (error)
+ break;
+ mb_put_uint8(mbp, SMB_DT_ASCII);
+ mb_put_uint8(mbp, 0);
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+ SMBERROR("%d\n", error);
+ if (error)
+ break;
+ } while(0);
+ smb_rq_done(rqp);
+ return error;
+}
+
+/*
+ * Note, win95 doesn't support this call.
+ */
+int
+smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
+ struct timespec *atime, int attr, struct smb_cred *scred)
+{
+ struct smb_t2rq *t2p;
+ struct smb_share *ssp = np->n_mount->sm_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ struct mbchain *mbp;
+ u_int16_t date, time;
+ int error, tzoff;
+
+ error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
+ scred, &t2p);
+ if (error)
+ return error;
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, SMB_INFO_STANDARD);
+ mb_put_uint32le(mbp, 0); /* MBZ */
+ error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
+ if (error) {
+ smb_t2_done(t2p);
+ return error;
+ }
+ tzoff = vcp->vc_sopt.sv_tz;
+ mbp = &t2p->t2_tdata;
+ mb_init(mbp);
+ 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);
+ mb_put_uint32le(mbp, 0); /* file size */
+ mb_put_uint32le(mbp, 0); /* allocation unit size */
+ mb_put_uint16le(mbp, attr); /* DOS attr */
+ mb_put_uint32le(mbp, 0); /* EA size */
+ t2p->t2_maxpcount = 5 * 2;
+ t2p->t2_maxdcount = vcp->vc_txmax;
+ error = smb_t2_request(t2p);
+ smb_t2_done(t2p);
+ return error;
+}
+
+/*
+ * NT level. Specially for win9x
+ */
+int
+smbfs_smb_setpattrNT(struct smbnode *np, u_short attr, struct timespec *mtime,
+ struct timespec *atime, struct smb_cred *scred)
+{
+ struct smb_t2rq *t2p;
+ struct smb_share *ssp = np->n_mount->sm_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ struct mbchain *mbp;
+ int64_t tm;
+ int error, tzoff;
+
+ error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
+ scred, &t2p);
+ if (error)
+ return error;
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
+ mb_put_uint32le(mbp, 0); /* MBZ */
+ error = smbfs_fullpath(mbp, vcp, np, NULL, 0);
+ if (error) {
+ smb_t2_done(t2p);
+ return error;
+ }
+ tzoff = vcp->vc_sopt.sv_tz;
+ mbp = &t2p->t2_tdata;
+ mb_init(mbp);
+ mb_put_int64le(mbp, 0); /* creation time */
+ if (atime) {
+ smb_time_local2NT(atime, tzoff, &tm);
+ } else
+ tm = 0;
+ mb_put_int64le(mbp, tm);
+ if (mtime) {
+ smb_time_local2NT(mtime, tzoff, &tm);
+ } else
+ tm = 0;
+ mb_put_int64le(mbp, tm);
+ mb_put_int64le(mbp, tm); /* change time */
+ mb_put_uint32le(mbp, attr); /* attr */
+ t2p->t2_maxpcount = 24;
+ t2p->t2_maxdcount = 56;
+ error = smb_t2_request(t2p);
+ smb_t2_done(t2p);
+ return error;
+}
+
+/*
+ * Set file atime and mtime. Doesn't supported by core dialect.
+ */
+int
+smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
+ struct timespec *atime, struct smb_cred *scred)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct smb_share *ssp = np->n_mount->sm_share;
+ struct mbchain *mbp;
+ u_int16_t date, time;
+ int error, tzoff;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scred);
+ if (error)
+ return error;
+ tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+ 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);
+ SMBSDEBUG("%d\n", error);
+ smb_rq_done(rqp);
+ return error;
+}
+
+/*
+ * Set DOS file attributes.
+ * Looks like this call can be used only if CAP_NT_SMBS bit is on.
+ */
+int
+smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr, struct timespec *mtime,
+ struct timespec *atime, struct smb_cred *scred)
+{
+ struct smb_t2rq *t2p;
+ struct smb_share *ssp = np->n_mount->sm_share;
+ struct mbchain *mbp;
+ int64_t tm;
+ int error, svtz;
+
+ error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
+ scred, &t2p);
+ if (error)
+ return error;
+ svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
+ mbp = &t2p->t2_tparam;
+ mb_init(mbp);
+ mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, SMB_SET_FILE_BASIC_INFO);
+ mb_put_uint32le(mbp, 0);
+ mbp = &t2p->t2_tdata;
+ mb_init(mbp);
+ mb_put_int64le(mbp, 0); /* creation time */
+ if (atime) {
+ smb_time_local2NT(atime, svtz, &tm);
+ } else
+ tm = 0;
+ mb_put_int64le(mbp, tm);
+ if (mtime) {
+ smb_time_local2NT(mtime, svtz, &tm);
+ } else
+ tm = 0;
+ mb_put_int64le(mbp, tm);
+ mb_put_int64le(mbp, tm); /* change time */
+ mb_put_uint16le(mbp, attr);
+ mb_put_uint32le(mbp, 0); /* padding */
+ mb_put_uint16le(mbp, 0);
+ t2p->t2_maxpcount = 2;
+ t2p->t2_maxdcount = 0;
+ error = smb_t2_request(t2p);
+ smb_t2_done(t2p);
+ return error;
+}
+
+
+int
+smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct smb_share *ssp = np->n_mount->sm_share;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ u_int8_t wc;
+ u_int16_t fid, wattr, grantedmode;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scred);
+ 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_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ mb_put_uint8(mbp, SMB_DT_ASCII);
+ do {
+ error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, 0);
+ if (error)
+ break;
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+ if (error)
+ break;
+ smb_rq_getreply(rqp, &mdp);
+ if (md_get_uint8(mdp, &wc) != 0 || wc != 7) {
+ error = EBADRPC;
+ break;
+ }
+ md_get_uint16(mdp, &fid);
+ md_get_uint16le(mdp, &wattr);
+ md_get_uint32(mdp, NULL); /* mtime */
+ md_get_uint32(mdp, NULL); /* fsize */
+ md_get_uint16le(mdp, &grantedmode);
+ /*
+ * TODO: refresh attributes from this reply
+ */
+ } while(0);
+ smb_rq_done(rqp);
+ if (error)
+ return error;
+ np->n_fid = fid;
+ np->n_rwstate = grantedmode;
+ return 0;
+}
+
+
+int
+smbfs_smb_close(struct smb_share *ssp, u_int16_t fid, struct timespec *mtime,
+ struct smb_cred *scred)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct mbchain *mbp;
+ u_long time;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scred);
+ if (error)
+ return error;
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_mem(mbp, (caddr_t)&fid, sizeof(fid), MB_MSYSTEM);
+ if (mtime) {
+ smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
+ } else
+ time = 0;
+ mb_put_uint32le(mbp, time);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return error;
+}
+
+int
+smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
+ struct smb_cred *scred)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct smb_share *ssp = dnp->n_mount->sm_share;
+ struct mbchain *mbp;
+ struct mdchain *mdp;
+ struct timespec ctime;
+ u_int8_t wc;
+ u_int16_t fid;
+ u_long tm;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scred);
+ if (error)
+ return error;
+ smb_rq_getrequest(rqp, &mbp);
+ smb_rq_wstart(rqp);
+ mb_put_uint16le(mbp, SMB_FA_ARCHIVE); /* attributes */
+ nanotime(&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);
+ if (!error) {
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+ if (!error) {
+ smb_rq_getreply(rqp, &mdp);
+ md_get_uint8(mdp, &wc);
+ if (wc == 1)
+ md_get_uint16(mdp, &fid);
+ else
+ error = EBADRPC;
+ }
+ }
+ smb_rq_done(rqp);
+ if (error)
+ return error;
+ smbfs_smb_close(ssp, fid, &ctime, scred);
+ return error;
+}
+
+int
+smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct smb_share *ssp = np->n_mount->sm_share;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scred);
+ 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, NULL, 0);
+ 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 *scred)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct smb_share *ssp = src->n_mount->sm_share;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scred);
+ 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);
+ do {
+ error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
+ if (error)
+ break;
+ mb_put_uint8(mbp, SMB_DT_ASCII);
+ error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
+ if (error)
+ break;
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+ } while(0);
+ smb_rq_done(rqp);
+ return error;
+}
+
+int
+smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
+ const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct smb_share *ssp = src->n_mount->sm_share;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scred);
+ 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);
+ do {
+ error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, 0);
+ if (error)
+ break;
+ mb_put_uint8(mbp, SMB_DT_ASCII);
+ error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, tnmlen);
+ if (error)
+ break;
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+ } while(0);
+ smb_rq_done(rqp);
+ return error;
+}
+
+int
+smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
+ struct smb_cred *scred)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct smb_share *ssp = dnp->n_mount->sm_share;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scred);
+ 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_rmdir(struct smbnode *np, struct smb_cred *scred)
+{
+ struct smb_rq rq, *rqp = &rq;
+ struct smb_share *ssp = np->n_mount->sm_share;
+ struct mbchain *mbp;
+ int error;
+
+ error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scred);
+ 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;
+ u_int8_t wc, bt;
+ u_int16_t ec, dlen, bc;
+ int maxent, error, iseof = 0;
+
+ maxent = min(ctx->f_left, (vcp->vc_txmax - SMB_HDRLEN - 3) / 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 {
+ mb_put_uint8(mbp, 0); /* file name length */
+ mb_put_uint8(mbp, SMB_DT_VARIABLE);
+ mb_put_uint16le(mbp, SMB_SKEYLEN);
+ mb_put_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
+ }
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+ if (error) {
+ if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
+ error = 0;
+ iseof = 1;
+ ctx->f_flags |= SMBFS_RDD_EOF;
+ } else
+ return error;
+ }
+ smb_rq_getreply(rqp, &mdp);
+ md_get_uint8(mdp, &wc);
+ if (wc != 1)
+ return iseof ? ENOENT : EBADRPC;
+ md_get_uint16le(mdp, &ec);
+ if (ec == 0)
+ return ENOENT;
+ ctx->f_ecnt = ec;
+ md_get_uint16le(mdp, &bc);
+ if (bc < 3)
+ return EBADRPC;
+ bc -= 3;
+ md_get_uint8(mdp, &bt);
+ if (bt != SMB_DT_VARIABLE)
+ return EBADRPC;
+ md_get_uint16le(mdp, &dlen);
+ if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
+ return EBADRPC;
+ return 0;
+}
+
+static int
+smbfs_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, int attr, struct smb_cred *scred)
+{
+ 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 = ctx->f_fname;
+ return 0;
+}
+
+static int
+smbfs_findnextLM1(struct smbfs_fctx *ctx, int limit)
+{
+ struct mdchain *mbp;
+ struct smb_rq *rqp;
+ char *cp;
+ u_int8_t battr;
+ u_int16_t date, time;
+ u_int32_t size;
+ int error;
+
+ if (ctx->f_ecnt == 0) {
+ if (ctx->f_flags & SMBFS_RDD_EOF)
+ return ENOENT;
+ ctx->f_left = ctx->f_limit = limit;
+ error = smbfs_smb_search(ctx);
+ if (error)
+ return error;
+ }
+ rqp = ctx->f_rq;
+ smb_rq_getreply(rqp, &mbp);
+ md_get_mem(mbp, ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
+ md_get_uint8(mbp, &battr);
+ md_get_uint16le(mbp, &time);
+ md_get_uint16le(mbp, &date);
+ md_get_uint32le(mbp, &size);
+ cp = ctx->f_name;
+ md_get_mem(mbp, 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_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;
+ u_int16_t tw, flags;
+ int error;
+
+ if (ctx->f_t2) {
+ smb_t2_done(ctx->f_t2);
+ ctx->f_t2 = NULL;
+ }
+ ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
+ flags = 8 | 2; /* <resume> | <close if EOS> */
+ if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
+ flags |= 1; /* close search after this 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_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
+ mb_put_uint16le(mbp, ctx->f_limit);
+ mb_put_uint16le(mbp, ctx->f_infolevel);
+ mb_put_uint32le(mbp, 0); /* resume key */
+ mb_put_uint16le(mbp, flags);
+ if (ctx->f_rname)
+ mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM);
+ else
+ mb_put_uint8(mbp, 0); /* resume file name */
+#if 0
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 200 * 1000; /* 200ms */
+ if (vcp->vc_flags & SMBC_WIN95) {
+ /*
+ * some implementations suggests to sleep here
+ * for 200ms, due to the bug in the Win95.
+ * I've didn't notice any problem, but put code
+ * for it.
+ */
+ tsleep(&flags, PVFS, "fix95", tvtohz(&tv));
+ }
+#endif
+ }
+ t2p->t2_maxpcount = 5 * 2;
+ t2p->t2_maxdcount = vcp->vc_txmax;
+ error = smb_t2_request(t2p);
+ if (error)
+ return error;
+ mdp = &t2p->t2_rparam;
+ if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
+ if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
+ return error;
+ ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
+ }
+ if ((error = md_get_uint16le(mdp, &tw)) != 0)
+ return error;
+ ctx->f_ecnt = tw;
+ if ((error = md_get_uint16le(mdp, &tw)) != 0)
+ return error;
+ if (tw)
+ ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
+ if ((error = md_get_uint16le(mdp, &tw)) != 0)
+ return error;
+ if ((error = md_get_uint16le(mdp, &tw)) != 0)
+ return error;
+ if (ctx->f_ecnt == 0)
+ return ENOENT;
+ ctx->f_rnameofs = tw;
+ mdp = &t2p->t2_rdata;
+ if (mdp->md_top == NULL) {
+ printf("bug: ecnt = %d, but data is NULL (please report)\n", ctx->f_ecnt);
+ return ENOENT;
+ }
+ if (mdp->md_top->m_len == 0) {
+ printf("bug: ecnt = %d, but m_len = 0 and m_next = %p (please report)\n", ctx->f_ecnt,mbp->mb_top->m_next);
+ return ENOENT;
+ }
+ ctx->f_eofs = 0;
+ return 0;
+}
+
+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_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
+ smb_rq_wend(rqp);
+ smb_rq_bstart(rqp);
+ smb_rq_bend(rqp);
+ error = smb_rq_simple(rqp);
+ smb_rq_done(rqp);
+ return error;
+}
+
+static int
+smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
+ const char *wildcard, int wclen, int attr, struct smb_cred *scred)
+{
+ ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK);
+ if (ctx->f_name == NULL)
+ return ENOMEM;
+ ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ?
+ SMB_INFO_STANDARD : SMB_FIND_FILE_DIRECTORY_INFO;
+ ctx->f_attrmask = attr;
+ ctx->f_wildcard = wildcard;
+ ctx->f_wclen = wclen;
+ return 0;
+}
+
+static int
+smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit)
+{
+ struct mdchain *mbp;
+ struct smb_t2rq *t2p;
+ char *cp;
+ u_int8_t tb;
+ u_int16_t date, time, wattr;
+ u_int32_t size, next, dattr;
+ int64_t lint;
+ int error, svtz, cnt, fxsz, nmlen, recsz;
+
+ if (ctx->f_ecnt == 0) {
+ if (ctx->f_flags & SMBFS_RDD_EOF)
+ return ENOENT;
+ ctx->f_left = ctx->f_limit = limit;
+ error = smbfs_smb_trans2find2(ctx);
+ if (error)
+ return error;
+ }
+ t2p = ctx->f_t2;
+ mbp = &t2p->t2_rdata;
+ svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
+ switch (ctx->f_infolevel) {
+ case SMB_INFO_STANDARD:
+ next = 0;
+ fxsz = 0;
+ md_get_uint16le(mbp, &date);
+ md_get_uint16le(mbp, &time); /* creation time */
+ md_get_uint16le(mbp, &date);
+ md_get_uint16le(mbp, &time); /* access time */
+ smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
+ md_get_uint16le(mbp, &date);
+ md_get_uint16le(mbp, &time); /* access time */
+ smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
+ md_get_uint32le(mbp, &size);
+ ctx->f_attr.fa_size = size;
+ md_get_uint32(mbp, NULL); /* allocation size */
+ md_get_uint16le(mbp, &wattr);
+ ctx->f_attr.fa_attr = wattr;
+ md_get_uint8(mbp, &tb);
+ size = nmlen = tb;
+ fxsz = 23;
+ recsz = next = 24 + nmlen; /* docs misses zero byte at end */
+ break;
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ md_get_uint32le(mbp, &next);
+ md_get_uint32(mbp, NULL); /* file index */
+ md_get_int64(mbp, NULL); /* creation time */
+ md_get_int64le(mbp, &lint);
+ smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_atime);
+ md_get_int64le(mbp, &lint);
+ smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_mtime);
+ md_get_int64le(mbp, &lint);
+ smb_time_NT2local(lint, svtz, &ctx->f_attr.fa_ctime);
+ md_get_int64le(mbp, &lint); /* file size */
+ ctx->f_attr.fa_size = lint;
+ md_get_int64(mbp, NULL); /* real size (should use) */
+ md_get_uint32(mbp, &dattr); /* EA */
+ ctx->f_attr.fa_attr = dattr;
+ md_get_uint32le(mbp, &size); /* name len */
+ fxsz = 64;
+ recsz = next ? next : fxsz + size;
+ break;
+ default:
+ SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
+ return EINVAL;
+ }
+ nmlen = min(size, SMB_MAXFNAMELEN);
+ cp = ctx->f_name;
+ error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM);
+ if (error)
+ return error;
+ if (next) {
+ cnt = next - nmlen - fxsz;
+ if (cnt > 0)
+ md_get_mem(mbp, NULL, cnt, MB_MSYSTEM);
+ else if (cnt < 0) {
+ SMBERROR("out of sync\n");
+ return EBADRPC;
+ }
+ }
+ if (nmlen && cp[nmlen - 1] == 0)
+ nmlen--;
+ if (nmlen == 0)
+ return EBADRPC;
+
+ next = ctx->f_eofs + recsz;
+ if (ctx->f_rnameofs && (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
+ (ctx->f_rnameofs >= ctx->f_eofs && ctx->f_rnameofs < next)) {
+ /*
+ * Server needs a resume filename.
+ */
+ if (ctx->f_rnamelen <= nmlen) {
+ if (ctx->f_rname)
+ free(ctx->f_rname, M_SMBFSDATA);
+ ctx->f_rname = malloc(nmlen + 1, M_SMBFSDATA, M_WAITOK);
+ ctx->f_rnamelen = nmlen;
+ }
+ bcopy(ctx->f_name, ctx->f_rname, nmlen);
+ ctx->f_rname[nmlen] = 0;
+ ctx->f_flags |= SMBFS_RDD_GOTRNAME;
+ }
+ ctx->f_nmlen = nmlen;
+ ctx->f_eofs = next;
+ ctx->f_ecnt--;
+ ctx->f_left--;
+ return 0;
+}
+
+static int
+smbfs_findcloseLM2(struct smbfs_fctx *ctx)
+{
+ if (ctx->f_name)
+ free(ctx->f_name, M_SMBFSDATA);
+ if (ctx->f_t2)
+ smb_t2_done(ctx->f_t2);
+ if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
+ smbfs_smb_findclose2(ctx);
+ return 0;
+}
+
+int
+smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen, int attr,
+ struct smb_cred *scred, struct smbfs_fctx **ctxpp)
+{
+ struct smbfs_fctx *ctx;
+ int error;
+
+ ctx = malloc(sizeof(*ctx), M_SMBFSDATA, M_WAITOK);
+ if (ctx == NULL)
+ return ENOMEM;
+ bzero(ctx, sizeof(*ctx));
+ ctx->f_ssp = dnp->n_mount->sm_share;
+ ctx->f_dnp = dnp;
+ ctx->f_flags = SMBFS_RDD_FINDFIRST;
+ ctx->f_scred = scred;
+ if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
+ (dnp->n_mount->sm_args.flags & SMBFS_MOUNT_NO_LONG)) {
+ ctx->f_flags |= SMBFS_RDD_USESEARCH;
+ error = smbfs_findopenLM1(ctx, dnp, wildcard, wclen, attr, scred);
+ } else
+ error = smbfs_findopenLM2(ctx, dnp, wildcard, wclen, attr, scred);
+ if (error)
+ smbfs_findclose(ctx, scred);
+ else
+ *ctxpp = ctx;
+ return error;
+}
+
+int
+smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred)
+{
+ int error;
+
+ if (limit == 0)
+ limit = 1000000;
+ else if (limit > 1)
+ limit *= 4; /* imperical */
+ ctx->f_scred = scred;
+ for (;;) {
+ if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
+ error = smbfs_findnextLM1(ctx, limit);
+ } else
+ error = smbfs_findnextLM2(ctx, limit);
+ if (error)
+ return error;
+ if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
+ (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
+ ctx->f_name[1] == '.'))
+ continue;
+ break;
+ }
+ smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, ctx->f_nmlen,
+ ctx->f_dnp->n_mount->sm_caseopt);
+ ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen);
+ return 0;
+}
+
+int
+smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred)
+{
+ ctx->f_scred = scred;
+ if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
+ smbfs_findcloseLM1(ctx);
+ } else
+ smbfs_findcloseLM2(ctx);
+ if (ctx->f_rname)
+ free(ctx->f_rname, M_SMBFSDATA);
+ free(ctx, M_SMBFSDATA);
+ return 0;
+}
+
+int
+smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
+ struct smbfattr *fap, struct smb_cred *scred)
+{
+ struct smbfs_fctx *ctx;
+ int error;
+
+ if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) {
+ bzero(fap, sizeof(*fap));
+ fap->fa_attr = SMB_FA_DIR;
+ fap->fa_ino = 2;
+ return 0;
+ }
+ if (nmlen == 1 && name[0] == '.') {
+ error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred);
+ return error;
+ } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
+ error = smbfs_smb_lookup(dnp->n_parent, NULL, 0, fap, scred);
+ printf("%s: knows NOTHING about '..'\n", __FUNCTION__);
+ return error;
+ }
+ error = smbfs_findopen(dnp, name, nmlen,
+ SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx);
+ if (error)
+ return error;
+ ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
+ error = smbfs_findnext(ctx, 1, scred);
+ if (error == 0) {
+ *fap = ctx->f_attr;
+ if (name == NULL)
+ fap->fa_ino = dnp->n_ino;
+ }
+ smbfs_findclose(ctx, scred);
+ return error;
+}
diff --git a/sys/fs/smbfs/smbfs_subr.c b/sys/fs/smbfs/smbfs_subr.c
new file mode 100644
index 0000000..8012c0b
--- /dev/null
+++ b/sys/fs/smbfs/smbfs_subr.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2000-2001, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <machine/clock.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#include <sys/sysctl.h>
+#include <sys/iconv.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb_dev.h>
+
+#include <fs/smbfs/smbfs.h>
+#include <fs/smbfs/smbfs_node.h>
+#include <fs/smbfs/smbfs_subr.h>
+
+MALLOC_DEFINE(M_SMBFSDATA, "SMBFS data", "SMBFS private data");
+
+/*
+ * Time & date conversion routines taken from msdosfs. Although leap
+ * year calculation is bogus, it's sufficient before 2100 :)
+ */
+/*
+ * This is the format of the contents of the deTime field in the direntry
+ * structure.
+ * We don't use bitfields because we don't know how compilers for
+ * arbitrary machines will lay them out.
+ */
+#define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */
+#define DT_2SECONDS_SHIFT 0
+#define DT_MINUTES_MASK 0x7E0 /* minutes */
+#define DT_MINUTES_SHIFT 5
+#define DT_HOURS_MASK 0xF800 /* hours */
+#define DT_HOURS_SHIFT 11
+
+/*
+ * This is the format of the contents of the deDate field in the direntry
+ * structure.
+ */
+#define DD_DAY_MASK 0x1F /* day of month */
+#define DD_DAY_SHIFT 0
+#define DD_MONTH_MASK 0x1E0 /* month */
+#define DD_MONTH_SHIFT 5
+#define DD_YEAR_MASK 0xFE00 /* year - 1980 */
+#define DD_YEAR_SHIFT 9
+/*
+ * Total number of days that have passed for each month in a regular year.
+ */
+static u_short regyear[] = {
+ 31, 59, 90, 120, 151, 181,
+ 212, 243, 273, 304, 334, 365
+};
+
+/*
+ * Total number of days that have passed for each month in a leap year.
+ */
+static u_short leapyear[] = {
+ 31, 60, 91, 121, 152, 182,
+ 213, 244, 274, 305, 335, 366
+};
+
+/*
+ * Variables used to remember parts of the last time conversion. Maybe we
+ * can avoid a full conversion.
+ */
+static u_long lasttime;
+static u_long lastday;
+static u_short lastddate;
+static u_short lastdtime;
+
+void
+smb_time_local2server(struct timespec *tsp, int tzoff, u_long *seconds)
+{
+ *seconds = tsp->tv_sec - tzoff * 60 /*- tz.tz_minuteswest * 60 -
+ (wall_cmos_clock ? adjkerntz : 0)*/;
+}
+
+void
+smb_time_server2local(u_long seconds, int tzoff, struct timespec *tsp)
+{
+ tsp->tv_sec = seconds + tzoff * 60;
+ /*+ tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0)*/;
+}
+
+/*
+ * Number of seconds between 1970 and 1601 year
+ */
+int64_t DIFF1970TO1601 = 11644473600ULL;
+
+/*
+ * Time from server comes as UTC, so no need to use tz
+ */
+void
+smb_time_NT2local(int64_t nsec, int tzoff, struct timespec *tsp)
+{
+ smb_time_server2local(nsec / 10000000 - DIFF1970TO1601, 0, tsp);
+}
+
+void
+smb_time_local2NT(struct timespec *tsp, int tzoff, int64_t *nsec)
+{
+ u_long seconds;
+
+ smb_time_local2server(tsp, 0, &seconds);
+ *nsec = (((int64_t)(seconds) & ~1) + DIFF1970TO1601) * (int64_t)10000000;
+}
+
+void
+smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp,
+ u_int16_t *dtp, u_int8_t *dhp)
+{
+ u_long t, days, year, month, inc;
+ u_short *months;
+
+ /*
+ * If the time from the last conversion is the same as now, then
+ * skip the computations and use the saved result.
+ */
+ smb_time_local2server(tsp, tzoff, &t);
+ t &= ~1;
+ if (lasttime != t) {
+ lasttime = t;
+ lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
+ + (((t / 60) % 60) << DT_MINUTES_SHIFT)
+ + (((t / 3600) % 24) << DT_HOURS_SHIFT);
+
+ /*
+ * If the number of days since 1970 is the same as the last
+ * time we did the computation then skip all this leap year
+ * and month stuff.
+ */
+ days = t / (24 * 60 * 60);
+ if (days != lastday) {
+ lastday = days;
+ for (year = 1970;; year++) {
+ inc = year & 0x03 ? 365 : 366;
+ if (days < inc)
+ break;
+ days -= inc;
+ }
+ months = year & 0x03 ? regyear : leapyear;
+ for (month = 0; days >= months[month]; month++)
+ ;
+ if (month > 0)
+ days -= months[month - 1];
+ lastddate = ((days + 1) << DD_DAY_SHIFT)
+ + ((month + 1) << DD_MONTH_SHIFT);
+ /*
+ * Remember dos's idea of time is relative to 1980.
+ * unix's is relative to 1970. If somehow we get a
+ * time before 1980 then don't give totally crazy
+ * results.
+ */
+ if (year > 1980)
+ lastddate += (year - 1980) << DD_YEAR_SHIFT;
+ }
+ }
+ if (dtp)
+ *dtp = lastdtime;
+ if (dhp)
+ *dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000;
+
+ *ddp = lastddate;
+}
+
+/*
+ * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
+ * interval there were 8 regular years and 2 leap years.
+ */
+#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
+
+static u_short lastdosdate;
+static u_long lastseconds;
+
+void
+smb_dos2unixtime(u_int dd, u_int dt, u_int dh, int tzoff,
+ struct timespec *tsp)
+{
+ u_long seconds;
+ u_long month;
+ u_long year;
+ u_long days;
+ u_short *months;
+
+ if (dd == 0) {
+ tsp->tv_sec = 0;
+ tsp->tv_nsec = 0;
+ return;
+ }
+ seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1)
+ + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
+ + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
+ + dh / 100;
+ /*
+ * If the year, month, and day from the last conversion are the
+ * same then use the saved value.
+ */
+ if (lastdosdate != dd) {
+ lastdosdate = dd;
+ days = 0;
+ year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
+ days = year * 365;
+ days += year / 4 + 1; /* add in leap days */
+ if ((year & 0x03) == 0)
+ days--; /* if year is a leap year */
+ months = year & 0x03 ? regyear : leapyear;
+ month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
+ if (month < 1 || month > 12) {
+ month = 1;
+ }
+ if (month > 1)
+ days += months[month - 2];
+ days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
+ lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
+ }
+ smb_time_server2local(seconds + lastseconds, tzoff, tsp);
+ tsp->tv_nsec = (dh % 100) * 10000000;
+}
+
+static int
+smb_fphelp(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *np,
+ int caseopt)
+{
+ struct smbmount *smp= np->n_mount;
+ struct smbnode **npp = smp->sm_npstack;
+ int i, error = 0;
+
+/* simple_lock(&smp->sm_npslock);*/
+ i = 0;
+ while (np->n_parent) {
+ if (i++ == SMBFS_MAXPATHCOMP) {
+/* simple_unlock(&smp->sm_npslock);*/
+ return ENAMETOOLONG;
+ }
+ *npp++ = np;
+ np = np->n_parent;
+ }
+/* if (i == 0)
+ return smb_put_dmem(mbp, vcp, "\\", 2, caseopt);*/
+ while (i--) {
+ np = *--npp;
+ error = mb_put_uint8(mbp, '\\');
+ if (error)
+ break;
+ error = smb_put_dmem(mbp, vcp, np->n_name, np->n_nmlen, caseopt);
+ if (error)
+ break;
+ }
+/* simple_unlock(&smp->sm_npslock);*/
+ return error;
+}
+
+int
+smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
+ const char *name, int nmlen)
+{
+ int caseopt = SMB_CS_NONE;
+ int error;
+
+ if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0)
+ caseopt |= SMB_CS_UPPER;
+ if (dnp != NULL) {
+ error = smb_fphelp(mbp, vcp, dnp, caseopt);
+ if (error)
+ return error;
+ }
+ if (name) {
+ error = mb_put_uint8(mbp, '\\');
+ if (error)
+ return error;
+ error = smb_put_dmem(mbp, vcp, name, nmlen, caseopt);
+ if (error)
+ return error;
+ }
+ error = mb_put_uint8(mbp, 0);
+ return error;
+}
+
+int
+smbfs_fname_tolocal(struct smb_vc *vcp, char *name, int nmlen, int caseopt)
+{
+/* if (caseopt & SMB_CS_UPPER)
+ iconv_convmem(vcp->vc_toupper, name, name, nmlen);
+ else if (caseopt & SMB_CS_LOWER)
+ iconv_convmem(vcp->vc_tolower, name, name, nmlen);*/
+ if (vcp->vc_tolocal)
+ iconv_convmem(vcp->vc_tolocal, name, name, nmlen);
+ return 0;
+}
diff --git a/sys/fs/smbfs/smbfs_subr.h b/sys/fs/smbfs/smbfs_subr.h
new file mode 100644
index 0000000..d41e9a8
--- /dev/null
+++ b/sys/fs/smbfs/smbfs_subr.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2000-2001, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef _FS_SMBFS_SMBFS_SUBR_H_
+#define _FS_SMBFS_SMBFS_SUBR_H_
+
+#ifdef MALLOC_DECLARE
+MALLOC_DECLARE(M_SMBFSDATA);
+#endif
+
+#define SMBFSERR(format, args...) printf("%s: "format, __FUNCTION__ ,## args)
+
+#ifdef SMB_VNODE_DEBUG
+#define SMBVDEBUG(format, args...) printf("%s: "format, __FUNCTION__ ,## args)
+#else
+#define SMBVDEBUG(format, args...)
+#endif
+
+/*
+ * Possible lock commands
+ */
+#define SMB_LOCK_EXCL 0
+#define SMB_LOCK_SHARED 1
+#define SMB_LOCK_RELEASE 2
+
+struct smbmount;
+struct proc;
+struct timespec;
+struct ucred;
+struct vattr;
+struct vnode;
+struct statfs;
+
+struct smbfattr {
+ int fa_attr;
+ int64_t fa_size;
+ struct timespec fa_atime;
+ struct timespec fa_ctime;
+ struct timespec fa_mtime;
+ long fa_ino;
+};
+
+/*
+ * Context to perform findfirst/findnext/findclose operations
+ */
+#define SMBFS_RDD_FINDFIRST 0x01
+#define SMBFS_RDD_EOF 0x02
+#define SMBFS_RDD_FINDSINGLE 0x04
+#define SMBFS_RDD_USESEARCH 0x08
+#define SMBFS_RDD_NOCLOSE 0x10
+#define SMBFS_RDD_GOTRNAME 0x1000
+
+/*
+ * Search context supplied by server
+ */
+#define SMB_SKEYLEN 21 /* search context */
+#define SMB_DENTRYLEN (SMB_SKEYLEN + 22) /* entire entry */
+
+struct smbfs_fctx {
+ /*
+ * Setable values
+ */
+ int f_flags; /* SMBFS_RDD_ */
+ /*
+ * Return values
+ */
+ struct smbfattr f_attr; /* current attributes */
+ char * f_name; /* current file name */
+ int f_nmlen; /* name len */
+ /*
+ * Internal variables
+ */
+ int f_limit; /* maximum number of entries */
+ int f_attrmask; /* SMB_FA_ */
+ int f_wclen;
+ const char * f_wildcard;
+ struct smbnode* f_dnp;
+ struct smb_cred*f_scred;
+ struct smb_share *f_ssp;
+ union {
+ struct smb_rq * uf_rq;
+ struct smb_t2rq * uf_t2;
+ } f_urq;
+ int f_left; /* entries left */
+ int f_ecnt; /* entries left in the current reponse */
+ int f_eofs; /* entry offset in the parameter block */
+ u_char f_skey[SMB_SKEYLEN]; /* server side search context */
+ u_char f_fname[8 + 1 + 3 + 1]; /* common case for 8.3 filenames */
+ u_int16_t f_Sid;
+ u_int16_t f_infolevel;
+ int f_rnamelen;
+ char * f_rname; /* resume name/key */
+ int f_rnameofs;
+};
+
+#define f_rq f_urq.uf_rq
+#define f_t2 f_urq.uf_t2
+
+extern int smbfs_debuglevel;
+
+
+/*
+ * smb level
+ */
+int smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
+ off_t start, off_t end, struct smb_cred *scred);
+int smbfs_smb_statfs2(struct smb_share *ssp, struct statfs *sbp,
+ struct smb_cred *scred);
+int smbfs_smb_statfs(struct smb_share *ssp, struct statfs *sbp,
+ struct smb_cred *scred);
+int smbfs_smb_setfsize(struct smbnode *np, int newsize, struct smb_cred *scred);
+
+int smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr,
+ struct timespec *mtime, struct smb_cred *scred);
+int smbfs_smb_setptime2(struct smbnode *np, struct timespec *mtime,
+ struct timespec *atime, int attr, struct smb_cred *scred);
+int smbfs_smb_setpattrNT(struct smbnode *np, u_int16_t attr,
+ struct timespec *mtime, struct timespec *atime, struct smb_cred *scred);
+
+int smbfs_smb_setftime(struct smbnode *np, struct timespec *mtime,
+ struct timespec *atime, struct smb_cred *scred);
+int smbfs_smb_setfattrNT(struct smbnode *np, u_int16_t attr,
+ struct timespec *mtime, struct timespec *atime, struct smb_cred *scred);
+
+int smbfs_smb_open(struct smbnode *np, int accmode, struct smb_cred *scred);
+int smbfs_smb_close(struct smb_share *ssp, u_int16_t fid,
+ struct timespec *mtime, struct smb_cred *scred);
+int smbfs_smb_create(struct smbnode *dnp, const char *name, int len,
+ struct smb_cred *scred);
+int smbfs_smb_delete(struct smbnode *np, struct smb_cred *scred);
+int smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
+ const char *tname, int tnmlen, struct smb_cred *scred);
+int smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
+ const char *tname, int tnmlen, u_int16_t flags, struct smb_cred *scred);
+int smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
+ struct smb_cred *scred);
+int smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scred);
+int smbfs_findopen(struct smbnode *dnp, const char *wildcard, int wclen,
+ int attr, struct smb_cred *scred, struct smbfs_fctx **ctxpp);
+int smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred);
+int smbfs_findclose(struct smbfs_fctx *ctx, struct smb_cred *scred);
+int smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp,
+ struct smbnode *dnp, const char *name, int nmlen);
+int smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen,
+ struct smbfattr *fap, struct smb_cred *scred);
+
+int smbfs_fname_tolocal(struct smb_vc *vcp, char *name, int nmlen, int caseopt);
+
+void smb_time_local2server(struct timespec *tsp, int tzoff, u_long *seconds);
+void smb_time_server2local(u_long seconds, int tzoff, struct timespec *tsp);
+void smb_time_NT2local(int64_t nsec, int tzoff, struct timespec *tsp);
+void smb_time_local2NT(struct timespec *tsp, int tzoff, int64_t *nsec);
+void smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp,
+ u_int16_t *dtp, u_int8_t *dhp);
+void smb_dos2unixtime (u_int dd, u_int dt, u_int dh, int tzoff, struct timespec *tsp);
+
+#endif /* !_FS_SMBFS_SMBFS_SUBR_H_ */
diff --git a/sys/fs/smbfs/smbfs_vfsops.c b/sys/fs/smbfs/smbfs_vfsops.c
new file mode 100644
index 0000000..c0f9ee1
--- /dev/null
+++ b/sys/fs/smbfs/smbfs_vfsops.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright (c) 2000-2001, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#include "opt_netsmb.h"
+#ifndef NETSMB
+#error "SMBFS requires option NETSMB"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/malloc.h>
+
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_dev.h>
+
+#include <fs/smbfs/smbfs.h>
+#include <fs/smbfs/smbfs_node.h>
+#include <fs/smbfs/smbfs_subr.h>
+
+int smbfs_debuglevel = 0;
+
+static int smbfs_version = SMBFS_VERSION;
+
+#ifdef SMBFS_USEZONE
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_zone.h>
+
+vm_zone_t smbfsmount_zone;
+#endif
+
+SYSCTL_NODE(_vfs, OID_AUTO, smbfs, CTLFLAG_RW, 0, "SMB/CIFS file system");
+SYSCTL_INT(_vfs_smbfs, OID_AUTO, version, CTLFLAG_RD, &smbfs_version, 0, "");
+SYSCTL_INT(_vfs_smbfs, OID_AUTO, debuglevel, CTLFLAG_RW, &smbfs_debuglevel, 0, "");
+
+static MALLOC_DEFINE(M_SMBFSHASH, "SMBFS hash", "SMBFS hash table");
+
+
+static int smbfs_mount(struct mount *, char *, caddr_t,
+ struct nameidata *, struct proc *);
+static int smbfs_quotactl(struct mount *, int, uid_t, caddr_t, struct proc *);
+static int smbfs_root(struct mount *, struct vnode **);
+static int smbfs_start(struct mount *, int, struct proc *);
+static int smbfs_statfs(struct mount *, struct statfs *, struct proc *);
+static int smbfs_sync(struct mount *, int, struct ucred *, struct proc *);
+static int smbfs_unmount(struct mount *, int, struct proc *);
+static int smbfs_init(struct vfsconf *vfsp);
+static int smbfs_uninit(struct vfsconf *vfsp);
+
+#if __FreeBSD_version < 400009
+static int smbfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp);
+static int smbfs_fhtovp(struct mount *, struct fid *,
+ struct sockaddr *, struct vnode **, int *,
+ struct ucred **);
+static int smbfs_vptofh(struct vnode *, struct fid *);
+#endif
+
+static struct vfsops smbfs_vfsops = {
+ smbfs_mount,
+ smbfs_start,
+ smbfs_unmount,
+ smbfs_root,
+ smbfs_quotactl,
+ smbfs_statfs,
+ smbfs_sync,
+#if __FreeBSD_version > 400008
+ vfs_stdvget,
+ vfs_stdfhtovp, /* shouldn't happen */
+ vfs_stdcheckexp,
+ vfs_stdvptofh, /* shouldn't happen */
+#else
+ smbfs_vget,
+ smbfs_fhtovp,
+ smbfs_vptofh,
+#endif
+ smbfs_init,
+ smbfs_uninit,
+#ifndef FB_RELENG3
+ vfs_stdextattrctl,
+#else
+#define M_USE_RESERVE M_KERNEL
+ &sysctl___vfs_smbfs
+#endif
+};
+
+
+VFS_SET(smbfs_vfsops, smbfs, VFCF_NETWORK);
+
+MODULE_DEPEND(smbfs, netsmb, NSMB_VERSION, NSMB_VERSION, NSMB_VERSION);
+MODULE_DEPEND(smbfs, libiconv, 1, 1, 1);
+
+int smbfs_pbuf_freecnt = -1; /* start out unlimited */
+
+static int
+smbfs_mount(struct mount *mp, char *path, caddr_t data,
+ struct nameidata *ndp, struct proc *p)
+{
+ struct smbfs_args args; /* will hold data from mount request */
+ struct smbmount *smp = NULL;
+ struct smb_vc *vcp;
+ struct smb_share *ssp = NULL;
+ struct vnode *vp;
+ struct smb_cred scred;
+#ifndef FB_CURRENT
+ size_t size;
+#endif
+ int error;
+ char *pc, *pe;
+
+ if (data == NULL) {
+ printf("missing data argument\n");
+ return EINVAL;
+ }
+ if (mp->mnt_flag & MNT_UPDATE) {
+ printf("MNT_UPDATE not implemented");
+ return EOPNOTSUPP;
+ }
+ error = copyin(data, (caddr_t)&args, sizeof(struct smbfs_args));
+ if (error)
+ return error;
+ if (args.version != SMBFS_VERSION) {
+ printf("mount version mismatch: kernel=%d, mount=%d\n",
+ SMBFS_VERSION, args.version);
+ return EINVAL;
+ }
+ smb_makescred(&scred, p, p->p_ucred);
+ error = smb_dev2share(args.dev, SMBM_EXEC, &scred, &ssp);
+ if (error) {
+ printf("invalid device handle %d (%d)\n", args.dev, error);
+ return error;
+ }
+ vcp = SSTOVC(ssp);
+ smb_share_unlock(ssp, 0, p);
+ mp->mnt_stat.f_iosize = SSTOVC(ssp)->vc_txmax;
+
+#ifdef SMBFS_USEZONE
+ smp = zalloc(smbfsmount_zone);
+#else
+ MALLOC(smp, struct smbmount*, sizeof(*smp), M_SMBFSDATA, M_USE_RESERVE);
+#endif
+ if (smp == NULL) {
+ printf("could not alloc smbmount\n");
+ error = ENOMEM;
+ goto bad;
+ }
+ bzero(smp, sizeof(*smp));
+ mp->mnt_data = (qaddr_t)smp;
+ smp->sm_hash = hashinit(desiredvnodes, M_SMBFSHASH, &smp->sm_hashlen);
+ if (smp->sm_hash == NULL)
+ goto bad;
+ lockinit(&smp->sm_hashlock, PVFS, "smbfsh", 0, 0);
+ smp->sm_share = ssp;
+ smp->sm_root = NULL;
+ smp->sm_args = args;
+ smp->sm_caseopt = args.caseopt;
+ smp->sm_args.file_mode = (smp->sm_args.file_mode &
+ (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
+ smp->sm_args.dir_mode = (smp->sm_args.dir_mode &
+ (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
+
+/* simple_lock_init(&smp->sm_npslock);*/
+#ifndef FB_CURRENT
+ error = copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
+ if (error)
+ goto bad;
+ bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
+#endif
+ pc = mp->mnt_stat.f_mntfromname;
+ pe = pc + sizeof(mp->mnt_stat.f_mntfromname);
+ bzero(pc, MNAMELEN);
+ *pc++ = '/';
+ *pc++ = '/';
+ pc=index(strncpy(pc, vcp->vc_username, pe - pc - 2), 0);
+ if (pc < pe-1) {
+ *(pc++) = '@';
+ pc = index(strncpy(pc, vcp->vc_srvname, pe - pc - 2), 0);
+ if (pc < pe - 1) {
+ *(pc++) = '/';
+ strncpy(pc, ssp->ss_name, pe - pc - 2);
+ }
+ }
+ /* protect against invalid mount points */
+ smp->sm_args.mount_point[sizeof(smp->sm_args.mount_point) - 1] = '\0';
+ vfs_getnewfsid(mp);
+ error = smbfs_root(mp, &vp);
+ if (error)
+ goto bad;
+ VOP_UNLOCK(vp, 0, p);
+ SMBVDEBUG("root.v_usecount = %d\n", vp->v_usecount);
+
+#ifdef DIAGNOSTICS
+ SMBERROR("mp=%p\n", mp);
+#endif
+ return error;
+bad:
+ if (smp) {
+ if (smp->sm_hash)
+ free(smp->sm_hash, M_SMBFSHASH);
+ lockdestroy(&smp->sm_hashlock);
+#ifdef SMBFS_USEZONE
+ zfree(smbfsmount_zone, smp);
+#else
+ free(smp, M_SMBFSDATA);
+#endif
+ }
+ if (ssp)
+ smb_share_put(ssp, &scred);
+ return error;
+}
+
+/* Unmount the filesystem described by mp. */
+static int
+smbfs_unmount(struct mount *mp, int mntflags, struct proc *p)
+{
+ struct smbmount *smp = VFSTOSMBFS(mp);
+ struct vnode *vp;
+ struct smb_cred scred;
+ int error, flags;
+
+ SMBVDEBUG("smbfs_unmount: flags=%04x\n", mntflags);
+ flags = 0;
+ if (mntflags & MNT_FORCE)
+ flags |= FORCECLOSE;
+ error = VFS_ROOT(mp, &vp);
+ if (error)
+ return (error);
+ if (vp->v_usecount > 2) {
+ printf("smbfs_unmount: usecnt=%d\n", vp->v_usecount);
+ vput(vp);
+ return EBUSY;
+ }
+ error = vflush(mp, vp, flags);
+ if (error) {
+ vput(vp);
+ return error;
+ }
+ vput(vp);
+ vrele(vp);
+ vgone(vp);
+ smb_makescred(&scred, p, p->p_ucred);
+ smb_share_put(smp->sm_share, &scred);
+ mp->mnt_data = (qaddr_t)0;
+
+ if (smp->sm_hash)
+ free(smp->sm_hash, M_SMBFSHASH);
+ lockdestroy(&smp->sm_hashlock);
+#ifdef SMBFS_USEZONE
+ zfree(smbfsmount_zone, smp);
+#else
+ free(smp, M_SMBFSDATA);
+#endif
+ mp->mnt_flag &= ~MNT_LOCAL;
+ return error;
+}
+
+/*
+ * Return locked root vnode of a filesystem
+ */
+static int
+smbfs_root(struct mount *mp, struct vnode **vpp)
+{
+ struct smbmount *smp = VFSTOSMBFS(mp);
+ struct vnode *vp;
+ struct smbnode *np;
+ struct smbfattr fattr;
+ struct proc *p = curproc;
+ struct ucred *cred = p->p_ucred;
+ struct smb_cred scred;
+ int error;
+
+ if (smp == NULL) {
+ SMBERROR("smp == NULL (bug in umount)\n");
+ return EINVAL;
+ }
+ if (smp->sm_root) {
+ *vpp = SMBTOV(smp->sm_root);
+ return vget(*vpp, LK_EXCLUSIVE | LK_RETRY, p);
+ }
+ smb_makescred(&scred, p, cred);
+ error = smbfs_smb_lookup(NULL, NULL, 0, &fattr, &scred);
+ if (error)
+ return error;
+ error = smbfs_nget(mp, NULL, "TheRooT", 7, &fattr, &vp);
+ if (error)
+ return error;
+ vp->v_flag |= VROOT;
+ np = VTOSMB(vp);
+ smp->sm_root = np;
+ *vpp = vp;
+ return 0;
+}
+
+/*
+ * Vfs start routine, a no-op.
+ */
+/* ARGSUSED */
+static int
+smbfs_start(mp, flags, p)
+ struct mount *mp;
+ int flags;
+ struct proc *p;
+{
+ SMBVDEBUG("flags=%04x\n", flags);
+ return 0;
+}
+
+/*
+ * Do operations associated with quotas, not supported
+ */
+/* ARGSUSED */
+static int
+smbfs_quotactl(mp, cmd, uid, arg, p)
+ struct mount *mp;
+ int cmd;
+ uid_t uid;
+ caddr_t arg;
+ struct proc *p;
+{
+ SMBVDEBUG("return EOPNOTSUPP\n");
+ return EOPNOTSUPP;
+}
+
+/*ARGSUSED*/
+int
+smbfs_init(struct vfsconf *vfsp)
+{
+#ifndef SMP
+ int name[2];
+ int olen, ncpu, plen, error;
+
+ name[0] = CTL_HW;
+ name[1] = HW_NCPU;
+ error = kernel_sysctl(curproc, name, 2, &ncpu, &olen, NULL, 0, &plen);
+ if (error == 0 && ncpu > 1)
+ printf("warning: smbfs module compiled without SMP support.");
+#endif
+
+#ifdef SMBFS_USEZONE
+ smbfsmount_zone = zinit("SMBFSMOUNT", sizeof(struct smbmount), 0, 0, 1);
+#endif
+ smbfs_pbuf_freecnt = nswbuf / 2 + 1;
+ SMBVDEBUG("done.\n");
+ return 0;
+}
+
+/*ARGSUSED*/
+int
+smbfs_uninit(struct vfsconf *vfsp)
+{
+
+ SMBVDEBUG("done.\n");
+ return 0;
+}
+
+/*
+ * smbfs_statfs call
+ */
+int
+smbfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
+{
+ struct smbmount *smp = VFSTOSMBFS(mp);
+ struct smbnode *np = smp->sm_root;
+ struct smb_share *ssp = smp->sm_share;
+ struct smb_cred scred;
+ int error = 0;
+
+ if (np == NULL)
+ return EINVAL;
+
+ sbp->f_iosize = SSTOVC(ssp)->vc_txmax; /* optimal transfer block size */
+ sbp->f_spare2 = 0; /* placeholder */
+ smb_makescred(&scred, p, p->p_ucred);
+
+ if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
+ error = smbfs_smb_statfs2(ssp, sbp, &scred);
+ else
+ error = smbfs_smb_statfs(ssp, sbp, &scred);
+ if (error)
+ return error;
+ sbp->f_flags = 0; /* copy of mount exported flags */
+ if (sbp != &mp->mnt_stat) {
+ sbp->f_fsid = mp->mnt_stat.f_fsid; /* file system id */
+ sbp->f_owner = mp->mnt_stat.f_owner; /* user that mounted the filesystem */
+ sbp->f_type = mp->mnt_vfc->vfc_typenum; /* type of filesystem */
+ bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
+ bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
+ }
+ strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
+ return 0;
+}
+
+/*
+ * Flush out the buffer cache
+ */
+/* ARGSUSED */
+static int
+smbfs_sync(mp, waitfor, cred, p)
+ struct mount *mp;
+ int waitfor;
+ struct ucred *cred;
+ struct proc *p;
+{
+ struct vnode *vp;
+ int error, allerror = 0;
+ /*
+ * Force stale buffer cache information to be flushed.
+ */
+loop:
+ for (vp = mp->mnt_vnodelist.lh_first;
+ vp != NULL;
+ vp = vp->v_mntvnodes.le_next) {
+ /*
+ * If the vnode that we are about to sync is no longer
+ * associated with this mount point, start over.
+ */
+ if (vp->v_mount != mp)
+ goto loop;
+#ifndef FB_RELENG3
+ if (VOP_ISLOCKED(vp, NULL) || TAILQ_EMPTY(&vp->v_dirtyblkhd) ||
+#else
+ if (VOP_ISLOCKED(vp) || TAILQ_EMPTY(&vp->v_dirtyblkhd) ||
+#endif
+ waitfor == MNT_LAZY)
+ continue;
+ if (vget(vp, LK_EXCLUSIVE, p))
+ goto loop;
+ error = VOP_FSYNC(vp, cred, waitfor, p);
+ if (error)
+ allerror = error;
+ vput(vp);
+ }
+ return (allerror);
+}
+
+#if __FreeBSD_version < 400009
+/*
+ * smbfs flat namespace lookup. Unsupported.
+ */
+/* ARGSUSED */
+static int smbfs_vget(mp, ino, vpp)
+ struct mount *mp;
+ ino_t ino;
+ struct vnode **vpp;
+{
+ return (EOPNOTSUPP);
+}
+
+/* ARGSUSED */
+static int smbfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
+ struct mount *mp;
+ struct fid *fhp;
+ struct sockaddr *nam;
+ struct vnode **vpp;
+ int *exflagsp;
+ struct ucred **credanonp;
+{
+ return (EINVAL);
+}
+
+/*
+ * Vnode pointer to File handle, should never happen either
+ */
+/* ARGSUSED */
+static int
+smbfs_vptofh(vp, fhp)
+ struct vnode *vp;
+ struct fid *fhp;
+{
+ return (EINVAL);
+}
+
+#endif /* __FreeBSD_version < 400009 */
diff --git a/sys/fs/smbfs/smbfs_vnops.c b/sys/fs/smbfs/smbfs_vnops.c
new file mode 100644
index 0000000..1d0637e
--- /dev/null
+++ b/sys/fs/smbfs/smbfs_vnops.c
@@ -0,0 +1,1340 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * 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.
+ *
+ * $FreeBSD$
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/fcntl.h>
+#include <sys/mount.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+#include <sys/lockf.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_zone.h>
+
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+
+#include <fs/smbfs/smbfs.h>
+#include <fs/smbfs/smbfs_node.h>
+#include <fs/smbfs/smbfs_subr.h>
+
+/*
+ * Prototypes for SMBFS vnode operations
+ */
+static int smbfs_create(struct vop_create_args *);
+static int smbfs_mknod(struct vop_mknod_args *);
+static int smbfs_open(struct vop_open_args *);
+static int smbfs_close(struct vop_close_args *);
+static int smbfs_access(struct vop_access_args *);
+static int smbfs_getattr(struct vop_getattr_args *);
+static int smbfs_setattr(struct vop_setattr_args *);
+static int smbfs_read(struct vop_read_args *);
+static int smbfs_write(struct vop_write_args *);
+static int smbfs_fsync(struct vop_fsync_args *);
+static int smbfs_remove(struct vop_remove_args *);
+static int smbfs_link(struct vop_link_args *);
+static int smbfs_lookup(struct vop_lookup_args *);
+static int smbfs_rename(struct vop_rename_args *);
+static int smbfs_mkdir(struct vop_mkdir_args *);
+static int smbfs_rmdir(struct vop_rmdir_args *);
+static int smbfs_symlink(struct vop_symlink_args *);
+static int smbfs_readdir(struct vop_readdir_args *);
+static int smbfs_bmap(struct vop_bmap_args *);
+static int smbfs_strategy(struct vop_strategy_args *);
+static int smbfs_print(struct vop_print_args *);
+static int smbfs_pathconf(struct vop_pathconf_args *ap);
+static int smbfs_advlock(struct vop_advlock_args *);
+#ifndef FB_RELENG3
+static int smbfs_getextattr(struct vop_getextattr_args *ap);
+#endif
+
+vop_t **smbfs_vnodeop_p;
+static struct vnodeopv_entry_desc smbfs_vnodeop_entries[] = {
+ { &vop_default_desc, (vop_t *) vop_defaultop },
+ { &vop_access_desc, (vop_t *) smbfs_access },
+ { &vop_advlock_desc, (vop_t *) smbfs_advlock },
+ { &vop_bmap_desc, (vop_t *) smbfs_bmap },
+ { &vop_close_desc, (vop_t *) smbfs_close },
+ { &vop_create_desc, (vop_t *) smbfs_create },
+ { &vop_fsync_desc, (vop_t *) smbfs_fsync },
+ { &vop_getattr_desc, (vop_t *) smbfs_getattr },
+ { &vop_getpages_desc, (vop_t *) smbfs_getpages },
+ { &vop_inactive_desc, (vop_t *) smbfs_inactive },
+ { &vop_ioctl_desc, (vop_t *) smbfs_ioctl },
+ { &vop_islocked_desc, (vop_t *) vop_stdislocked },
+ { &vop_link_desc, (vop_t *) smbfs_link },
+ { &vop_lock_desc, (vop_t *) vop_stdlock },
+ { &vop_lookup_desc, (vop_t *) smbfs_lookup },
+ { &vop_mkdir_desc, (vop_t *) smbfs_mkdir },
+ { &vop_mknod_desc, (vop_t *) smbfs_mknod },
+ { &vop_open_desc, (vop_t *) smbfs_open },
+ { &vop_pathconf_desc, (vop_t *) smbfs_pathconf },
+ { &vop_print_desc, (vop_t *) smbfs_print },
+ { &vop_putpages_desc, (vop_t *) smbfs_putpages },
+ { &vop_read_desc, (vop_t *) smbfs_read },
+ { &vop_readdir_desc, (vop_t *) smbfs_readdir },
+ { &vop_reclaim_desc, (vop_t *) smbfs_reclaim },
+ { &vop_remove_desc, (vop_t *) smbfs_remove },
+ { &vop_rename_desc, (vop_t *) smbfs_rename },
+ { &vop_rmdir_desc, (vop_t *) smbfs_rmdir },
+ { &vop_setattr_desc, (vop_t *) smbfs_setattr },
+ { &vop_strategy_desc, (vop_t *) smbfs_strategy },
+ { &vop_symlink_desc, (vop_t *) smbfs_symlink },
+ { &vop_unlock_desc, (vop_t *) vop_stdunlock },
+ { &vop_write_desc, (vop_t *) smbfs_write },
+#ifndef FB_RELENG3
+ { &vop_getextattr_desc, (vop_t *) smbfs_getextattr },
+/* { &vop_setextattr_desc, (vop_t *) smbfs_setextattr },*/
+#endif
+ { NULL, NULL }
+};
+
+static struct vnodeopv_desc smbfs_vnodeop_opv_desc =
+ { &smbfs_vnodeop_p, smbfs_vnodeop_entries };
+
+VNODEOP_SET(smbfs_vnodeop_opv_desc);
+
+static int
+smbfs_access(ap)
+ struct vop_access_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct ucred *cred = ap->a_cred;
+ u_int mode = ap->a_mode;
+ struct smbmount *smp = VTOSMBFS(vp);
+ int error = 0;
+
+ SMBVDEBUG("\n");
+ if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
+ switch (vp->v_type) {
+ case VREG: case VDIR: case VLNK:
+ return EROFS;
+ default:
+ break;
+ }
+ }
+ if (cred->cr_uid == 0)
+ return 0;
+ if (cred->cr_uid != smp->sm_args.uid) {
+ mode >>= 3;
+ if (!groupmember(smp->sm_args.gid, cred))
+ mode >>= 3;
+ }
+ error = (((vp->v_type == VREG) ? smp->sm_args.file_mode : smp->sm_args.dir_mode) & mode) == mode ? 0 : EACCES;
+ return error;
+}
+
+/* ARGSUSED */
+static int
+smbfs_open(ap)
+ struct vop_open_args /* {
+ struct vnode *a_vp;
+ int a_mode;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct smbnode *np = VTOSMB(vp);
+ struct smb_cred scred;
+ struct vattr vattr;
+ int mode = ap->a_mode;
+ int error, accmode;
+
+ SMBVDEBUG("%s,%d\n", np->n_name, np->n_opencount);
+ if (vp->v_type != VREG && vp->v_type != VDIR) {
+ SMBFSERR("open eacces vtype=%d\n", vp->v_type);
+ return EACCES;
+ }
+ if (vp->v_type == VDIR) {
+ np->n_opencount++;
+ return 0;
+ }
+ if (np->n_flag & NMODIFIED) {
+ if ((error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1)) == EINTR)
+ return error;
+ smbfs_attr_cacheremove(vp);
+ error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
+ if (error)
+ return error;
+ np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
+ } else {
+ error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
+ if (error)
+ return error;
+ if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) {
+ error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
+ if (error == EINTR)
+ return error;
+ np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
+ }
+ }
+ if (np->n_opencount) {
+ np->n_opencount++;
+ return 0;
+ }
+ accmode = SMB_AM_OPENREAD;
+ if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
+ accmode = SMB_AM_OPENRW;
+ smb_makescred(&scred, ap->a_p, ap->a_cred);
+ error = smbfs_smb_open(np, accmode, &scred);
+ if (error) {
+ if (mode & FWRITE)
+ return EACCES;
+ accmode = SMB_AM_OPENREAD;
+ error = smbfs_smb_open(np, accmode, &scred);
+ }
+ if (!error) {
+ np->n_opencount++;
+ }
+ smbfs_attr_cacheremove(vp);
+ return error;
+}
+
+static int
+smbfs_closel(struct vop_close_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct smbnode *np = VTOSMB(vp);
+ struct proc *p = ap->a_p;
+ struct smb_cred scred;
+ struct vattr vattr;
+ int error;
+
+ SMBVDEBUG("name=%s, pid=%d, c=%d\n",np->n_name, p->p_pid, np->n_opencount);
+
+ smb_makescred(&scred, p, ap->a_cred);
+
+ if (np->n_opencount == 0) {
+ SMBERROR("Negative opencount\n");
+ return 0;
+ }
+ np->n_opencount--;
+ if (vp->v_type == VDIR) {
+ if (np->n_opencount)
+ return 0;
+ if (np->n_dirseq) {
+ smbfs_findclose(np->n_dirseq, &scred);
+ np->n_dirseq = NULL;
+ }
+ error = 0;
+ } else {
+ error = smbfs_vinvalbuf(vp, V_SAVE, ap->a_cred, p, 1);
+ if (np->n_opencount)
+ return error;
+ VOP_GETATTR(vp, &vattr, ap->a_cred, p);
+ error = smbfs_smb_close(np->n_mount->sm_share, np->n_fid,
+ &np->n_mtime, &scred);
+ }
+ smbfs_attr_cacheremove(vp);
+ return error;
+}
+
+/*
+ * XXX: VOP_CLOSE() usually called without lock held which is suck. Here we
+ * do some heruistic to determine if vnode should be locked.
+ */
+static int
+smbfs_close(ap)
+ struct vop_close_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode *a_vp;
+ int a_fflag;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct proc *p = ap->a_p;
+ int error, dolock;
+
+ VI_LOCK(vp);
+ dolock = (vp->v_flag & VXLOCK) == 0;
+ if (dolock)
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_INTERLOCK, p);
+ else
+ VI_UNLOCK(vp);
+ error = smbfs_closel(ap);
+ if (dolock)
+ VOP_UNLOCK(vp, 0, p);
+ return error;
+}
+
+/*
+ * smbfs_getattr call from vfs.
+ */
+static int
+smbfs_getattr(ap)
+ struct vop_getattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct smbnode *np = VTOSMB(vp);
+ struct vattr *va=ap->a_vap;
+ struct smbfattr fattr;
+ struct smb_cred scred;
+ u_int32_t oldsize;
+ int error;
+
+ SMBVDEBUG("%lx: '%s' %d\n", (long)vp, np->n_name, (vp->v_flag & VROOT) != 0);
+ error = smbfs_attr_cachelookup(vp, va);
+ if (!error)
+ return 0;
+ SMBVDEBUG("not in the cache\n");
+ smb_makescred(&scred, ap->a_p, ap->a_cred);
+ oldsize = np->n_size;
+ error = smbfs_smb_lookup(np, NULL, 0, &fattr, &scred);
+ if (error) {
+ SMBVDEBUG("error %d\n", error);
+ return error;
+ }
+ smbfs_attr_cacheenter(vp, &fattr);
+ smbfs_attr_cachelookup(vp, va);
+ if (np->n_opencount)
+ np->n_size = oldsize;
+ return 0;
+}
+
+static int
+smbfs_setattr(ap)
+ struct vop_setattr_args /* {
+ struct vnode *a_vp;
+ struct vattr *a_vap;
+ struct ucred *a_cred;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct smbnode *np = VTOSMB(vp);
+ struct vattr *vap = ap->a_vap;
+ struct timespec *mtime, *atime;
+ struct smb_cred scred;
+ struct smb_share *ssp = np->n_mount->sm_share;
+ struct smb_vc *vcp = SSTOVC(ssp);
+ u_quad_t tsize = 0;
+ int isreadonly, doclose, error = 0;
+
+ SMBVDEBUG("\n");
+ if (vap->va_flags != VNOVAL)
+ return EOPNOTSUPP;
+ isreadonly = (vp->v_mount->mnt_flag & MNT_RDONLY);
+ /*
+ * Disallow write attempts if the filesystem is mounted read-only.
+ */
+ if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL ||
+ vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
+ vap->va_mode != (mode_t)VNOVAL) && isreadonly)
+ return EROFS;
+ smb_makescred(&scred, ap->a_p, ap->a_cred);
+ if (vap->va_size != VNOVAL) {
+ switch (vp->v_type) {
+ case VDIR:
+ return EISDIR;
+ case VREG:
+ break;
+ default:
+ return EINVAL;
+ };
+ if (isreadonly)
+ return EROFS;
+ doclose = 0;
+ vnode_pager_setsize(vp, (u_long)vap->va_size);
+ tsize = np->n_size;
+ np->n_size = vap->va_size;
+ if (np->n_opencount == 0) {
+ error = smbfs_smb_open(np, SMB_AM_OPENRW, &scred);
+ if (error == 0)
+ doclose = 1;
+ }
+ if (error == 0)
+ error = smbfs_smb_setfsize(np, vap->va_size, &scred);
+ if (doclose)
+ smbfs_smb_close(ssp, np->n_fid, NULL, &scred);
+ if (error) {
+ np->n_size = tsize;
+ vnode_pager_setsize(vp, (u_long)tsize);
+ return error;
+ }
+ }
+ mtime = atime = NULL;
+ if (vap->va_mtime.tv_sec != VNOVAL)
+ mtime = &vap->va_mtime;
+ if (vap->va_atime.tv_sec != VNOVAL)
+ atime = &vap->va_atime;
+ if (mtime != atime) {
+#if 0
+ if (mtime == NULL)
+ mtime = &np->n_mtime;
+ if (atime == NULL)
+ atime = &np->n_atime;
+#endif
+ /*
+ * If file is opened, then we can use handle based calls.
+ * If not, use path based ones.
+ */
+ if (np->n_opencount == 0) {
+ if (vcp->vc_flags & SMBV_WIN95) {
+ error = VOP_OPEN(vp, FWRITE, ap->a_cred, ap->a_p);
+ if (!error) {
+/* error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred);
+ VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);*/
+ if (mtime)
+ np->n_mtime = *mtime;
+ VOP_CLOSE(vp, FWRITE, ap->a_cred, ap->a_p);
+ }
+ } else if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) {
+ error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred);
+/* error = smbfs_smb_setpattrNT(np, 0, mtime, atime, &scred);*/
+ } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) {
+ error = smbfs_smb_setptime2(np, mtime, atime, 0, &scred);
+ } else {
+ error = smbfs_smb_setpattr(np, 0, mtime, &scred);
+ }
+ } else {
+ if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
+ error = smbfs_smb_setfattrNT(np, 0, mtime, atime, &scred);
+ } else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) {
+ error = smbfs_smb_setftime(np, mtime, atime, &scred);
+ } else {
+ /*
+ * I have no idea how to handle this for core
+ * level servers. The possible solution is to
+ * update mtime after file is closed.
+ */
+ SMBERROR("can't update times on an opened file\n");
+ }
+ }
+ }
+ /*
+ * Invalidate attribute cache in case if server doesn't set
+ * required attributes.
+ */
+ smbfs_attr_cacheremove(vp); /* invalidate cache */
+ VOP_GETATTR(vp, vap, ap->a_cred, ap->a_p);
+ np->n_mtime.tv_sec = vap->va_mtime.tv_sec;
+ return error;
+}
+/*
+ * smbfs_read call.
+ */
+static int
+smbfs_read(ap)
+ struct vop_read_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+
+ SMBVDEBUG("\n");
+ if (vp->v_type != VREG && vp->v_type != VDIR)
+ return EPERM;
+ return smbfs_readvnode(vp, uio, ap->a_cred);
+}
+
+static int
+smbfs_write(ap)
+ struct vop_write_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+
+ SMBVDEBUG("%d,ofs=%d,sz=%d\n",vp->v_type, (int)uio->uio_offset, uio->uio_resid);
+ if (vp->v_type != VREG)
+ return (EPERM);
+ return smbfs_writevnode(vp, uio, ap->a_cred,ap->a_ioflag);
+}
+/*
+ * smbfs_create call
+ * Create a regular file. On entry the directory to contain the file being
+ * created is locked. We must release before we return. We must also free
+ * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or
+ * only if the SAVESTART bit in cn_flags is clear on success.
+ */
+static int
+smbfs_create(ap)
+ struct vop_create_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ } */ *ap;
+{
+ struct vnode *dvp = ap->a_dvp;
+ struct vattr *vap = ap->a_vap;
+ struct vnode **vpp=ap->a_vpp;
+ struct componentname *cnp = ap->a_cnp;
+ struct smbnode *dnp = VTOSMB(dvp);
+ struct vnode *vp;
+ struct vattr vattr;
+ struct smbfattr fattr;
+ struct smb_cred scred;
+ char *name = cnp->cn_nameptr;
+ int nmlen = cnp->cn_namelen;
+ int error;
+
+
+ SMBVDEBUG("\n");
+ *vpp = NULL;
+ if (vap->va_type != VREG)
+ return EOPNOTSUPP;
+ if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)))
+ return error;
+ smb_makescred(&scred, cnp->cn_proc, cnp->cn_cred);
+
+ error = smbfs_smb_create(dnp, name, nmlen, &scred);
+ if (error)
+ return error;
+ error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, &scred);
+ if (error)
+ return error;
+ error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, &vp);
+ if (error)
+ return error;
+ *vpp = vp;
+ if (cnp->cn_flags & MAKEENTRY)
+ cache_enter(dvp, vp, cnp);
+ return error;
+}
+
+static int
+smbfs_remove(ap)
+ struct vop_remove_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode * a_dvp;
+ struct vnode * a_vp;
+ struct componentname * a_cnp;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+/* struct vnode *dvp = ap->a_dvp;*/
+ struct componentname *cnp = ap->a_cnp;
+ struct smbnode *np = VTOSMB(vp);
+ struct smb_cred scred;
+ int error;
+
+ if (vp->v_type == VDIR || np->n_opencount || vp->v_usecount != 1)
+ return EPERM;
+ smb_makescred(&scred, cnp->cn_proc, cnp->cn_cred);
+ error = smbfs_smb_delete(np, &scred);
+ cache_purge(vp);
+ return error;
+}
+
+/*
+ * smbfs_file rename call
+ */
+static int
+smbfs_rename(ap)
+ struct vop_rename_args /* {
+ struct vnode *a_fdvp;
+ struct vnode *a_fvp;
+ struct componentname *a_fcnp;
+ struct vnode *a_tdvp;
+ struct vnode *a_tvp;
+ struct componentname *a_tcnp;
+ } */ *ap;
+{
+ struct vnode *fvp = ap->a_fvp;
+ struct vnode *tvp = ap->a_tvp;
+ struct vnode *fdvp = ap->a_fdvp;
+ struct vnode *tdvp = ap->a_tdvp;
+ struct componentname *tcnp = ap->a_tcnp;
+/* struct componentname *fcnp = ap->a_fcnp;*/
+ struct smb_cred scred;
+ u_int16_t flags = 6;
+ int error=0;
+
+ /* Check for cross-device rename */
+ if ((fvp->v_mount != tdvp->v_mount) ||
+ (tvp && (fvp->v_mount != tvp->v_mount))) {
+ error = EXDEV;
+ goto out;
+ }
+
+ if (tvp && tvp->v_usecount > 1) {
+ error = EBUSY;
+ goto out;
+ }
+ flags = 0x10; /* verify all writes */
+ if (fvp->v_type == VDIR) {
+ flags |= 2;
+ } else if (fvp->v_type == VREG) {
+ flags |= 1;
+ } else
+ return EINVAL;
+ smb_makescred(&scred, tcnp->cn_proc, tcnp->cn_cred);
+ /*
+ * It seems that Samba doesn't implement SMB_COM_MOVE call...
+ */
+#ifdef notnow
+ if (SMB_DIALECT(SSTOCN(smp->sm_share)) >= SMB_DIALECT_LANMAN1_0) {
+ error = smbfs_smb_move(VTOSMB(fvp), VTOSMB(tdvp),
+ tcnp->cn_nameptr, tcnp->cn_namelen, flags, &scred);
+ } else
+#endif
+ {
+ /*
+ * We have to do the work atomicaly
+ */
+ if (tvp && tvp != fvp) {
+ error = smbfs_smb_delete(VTOSMB(tvp), &scred);
+ if (error)
+ goto out;
+ }
+ error = smbfs_smb_rename(VTOSMB(fvp), VTOSMB(tdvp),
+ tcnp->cn_nameptr, tcnp->cn_namelen, &scred);
+ }
+
+ if (fvp->v_type == VDIR) {
+ if (tvp != NULL && tvp->v_type == VDIR)
+ cache_purge(tdvp);
+ cache_purge(fdvp);
+ }
+out:
+ if (tdvp == tvp)
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ if (tvp)
+ vput(tvp);
+ vrele(fdvp);
+ vrele(fvp);
+ smbfs_attr_cacheremove(fdvp);
+ smbfs_attr_cacheremove(tdvp);
+#ifdef possible_mistake
+ vgone(fvp);
+ if (tvp)
+ vgone(tvp);
+#endif
+ return error;
+}
+
+/*
+ * somtime it will come true...
+ */
+static int
+smbfs_link(ap)
+ struct vop_link_args /* {
+ struct vnode *a_tdvp;
+ struct vnode *a_vp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+ return EOPNOTSUPP;
+}
+
+/*
+ * smbfs_symlink link create call.
+ * Sometime it will be functional...
+ */
+static int
+smbfs_symlink(ap)
+ struct vop_symlink_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ char *a_target;
+ } */ *ap;
+{
+ return EOPNOTSUPP;
+}
+
+static int
+smbfs_mknod(ap)
+ struct vop_mknod_args /* {
+ } */ *ap;
+{
+ return EOPNOTSUPP;
+}
+
+static int
+smbfs_mkdir(ap)
+ struct vop_mkdir_args /* {
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ struct vattr *a_vap;
+ } */ *ap;
+{
+ struct vnode *dvp = ap->a_dvp;
+/* struct vattr *vap = ap->a_vap;*/
+ struct vnode *vp;
+ struct componentname *cnp = ap->a_cnp;
+ struct smbnode *dnp = VTOSMB(dvp);
+ struct vattr vattr;
+ struct smb_cred scred;
+ struct smbfattr fattr;
+ char *name = cnp->cn_nameptr;
+ int len = cnp->cn_namelen;
+ int error;
+
+ if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
+ return error;
+ }
+ if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.'))))
+ return EEXIST;
+ smb_makescred(&scred, cnp->cn_proc, cnp->cn_cred);
+ error = smbfs_smb_mkdir(dnp, name, len, &scred);
+ if (error)
+ return error;
+ error = smbfs_smb_lookup(dnp, name, len, &fattr, &scred);
+ if (error)
+ return error;
+ error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp);
+ if (error)
+ return error;
+ *ap->a_vpp = vp;
+ return 0;
+}
+
+/*
+ * smbfs_remove directory call
+ */
+static int
+smbfs_rmdir(ap)
+ struct vop_rmdir_args /* {
+ struct vnode *a_dvp;
+ struct vnode *a_vp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct vnode *dvp = ap->a_dvp;
+ struct componentname *cnp = ap->a_cnp;
+/* struct smbmount *smp = VTOSMBFS(vp);*/
+ struct smbnode *dnp = VTOSMB(dvp);
+ struct smbnode *np = VTOSMB(vp);
+ struct smb_cred scred;
+ int error;
+
+ if (dvp == vp)
+ return EINVAL;
+
+ smb_makescred(&scred, cnp->cn_proc, cnp->cn_cred);
+ error = smbfs_smb_rmdir(np, &scred);
+ dnp->n_flag |= NMODIFIED;
+ smbfs_attr_cacheremove(dvp);
+/* cache_purge(dvp);*/
+ cache_purge(vp);
+ return error;
+}
+
+/*
+ * smbfs_readdir call
+ */
+static int
+smbfs_readdir(ap)
+ struct vop_readdir_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ struct ucred *a_cred;
+ int *a_eofflag;
+ u_long *a_cookies;
+ int a_ncookies;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct uio *uio = ap->a_uio;
+ int error;
+
+ if (vp->v_type != VDIR)
+ return (EPERM);
+#ifdef notnow
+ if (ap->a_ncookies) {
+ printf("smbfs_readdir: no support for cookies now...");
+ return (EOPNOTSUPP);
+ }
+#endif
+ error = smbfs_readvnode(vp, uio, ap->a_cred);
+ return error;
+}
+
+/* ARGSUSED */
+static int
+smbfs_fsync(ap)
+ struct vop_fsync_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode * a_vp;
+ struct ucred * a_cred;
+ int a_waitfor;
+ struct proc * a_p;
+ } */ *ap;
+{
+/* return (smb_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));*/
+ return (0);
+}
+
+static
+int smbfs_print (ap)
+ struct vop_print_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct smbnode *np = VTOSMB(vp);
+
+ if (np == NULL) {
+ printf("no smbnode data\n");
+ return (0);
+ }
+ printf("tag VT_SMBFS, name = %s, parent = %p, opencount = %d",
+ np->n_name, np->n_parent ? SMBTOV(np->n_parent) : NULL,
+ np->n_opencount);
+ lockmgr_printinfo(&vp->v_lock);
+ printf("\n");
+ return (0);
+}
+
+static int
+smbfs_pathconf (ap)
+ struct vop_pathconf_args /* {
+ struct vnode *vp;
+ int name;
+ register_t *retval;
+ } */ *ap;
+{
+ struct smbmount *smp = VFSTOSMBFS(VTOVFS(ap->a_vp));
+ struct smb_vc *vcp = SSTOVC(smp->sm_share);
+ register_t *retval = ap->a_retval;
+ int error = 0;
+
+ switch (ap->a_name) {
+ case _PC_LINK_MAX:
+ *retval = 0;
+ break;
+ case _PC_NAME_MAX:
+ *retval = (vcp->vc_flags & SMBV_LONGNAMES) ? 255 : 12;
+ break;
+ case _PC_PATH_MAX:
+ *retval = 800; /* XXX: a correct one ? */
+ break;
+ default:
+ error = EINVAL;
+ }
+ return error;
+}
+
+static int
+smbfs_strategy (ap)
+ struct vop_strategy_args /* {
+ struct buf *a_bp
+ } */ *ap;
+{
+ struct buf *bp=ap->a_bp;
+ struct ucred *cr;
+ struct proc *p;
+ int error = 0;
+
+ SMBVDEBUG("\n");
+ if (bp->b_flags & B_PHYS)
+ panic("smbfs physio");
+ if (bp->b_flags & B_ASYNC)
+ p = (struct proc *)0;
+ else
+ p = curproc; /* XXX */
+ if (bp->b_iocmd == BIO_READ)
+ cr = bp->b_rcred;
+ else
+ cr = bp->b_wcred;
+
+ if ((bp->b_flags & B_ASYNC) == 0 )
+ error = smbfs_doio(bp, cr, p);
+ return error;
+}
+
+static int
+smbfs_bmap(ap)
+ struct vop_bmap_args /* {
+ struct vnode *a_vp;
+ daddr_t a_bn;
+ struct vnode **a_vpp;
+ daddr_t *a_bnp;
+ int *a_runp;
+ int *a_runb;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+
+ if (ap->a_vpp != NULL)
+ *ap->a_vpp = vp;
+ if (ap->a_bnp != NULL)
+ *ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
+ if (ap->a_runp != NULL)
+ *ap->a_runp = 0;
+ if (ap->a_runb != NULL)
+ *ap->a_runb = 0;
+ return (0);
+}
+
+int
+smbfs_ioctl(ap)
+ struct vop_ioctl_args /* {
+ struct vnode *a_vp;
+ u_long a_command;
+ caddr_t a_data;
+ int fflag;
+ struct ucred *cred;
+ struct proc *p;
+ } */ *ap;
+{
+ return EINVAL;
+}
+
+static char smbfs_atl[] = "rhsvda";
+static int
+smbfs_getextattr(struct vop_getextattr_args *ap)
+/* {
+ IN struct vnode *a_vp;
+ IN char *a_name;
+ INOUT struct uio *a_uio;
+ IN struct ucred *a_cred;
+ IN struct proc *a_p;
+};
+*/
+{
+ struct vnode *vp = ap->a_vp;
+ struct proc *p = ap->a_p;
+ struct ucred *cred = ap->a_cred;
+ struct uio *uio = ap->a_uio;
+ const char *name = ap->a_name;
+ struct smbnode *np = VTOSMB(vp);
+ struct vattr vattr;
+ char buf[10];
+ int i, attr, error;
+
+ error = VOP_ACCESS(vp, VREAD, cred, p);
+ if (error)
+ return error;
+ error = VOP_GETATTR(vp, &vattr, cred, p);
+ if (error)
+ return error;
+ if (strcmp(name, "dosattr") == 0) {
+ attr = np->n_dosattr;
+ for (i = 0; i < 6; i++, attr >>= 1)
+ buf[i] = (attr & 1) ? smbfs_atl[i] : '-';
+ buf[i] = 0;
+ error = uiomove(buf, i, uio);
+
+ } else
+ error = EINVAL;
+ return error;
+}
+
+/*
+ * Since we expected to support F_GETLK (and SMB protocol has no such function),
+ * it is necessary to use lf_advlock(). It would be nice if this function had
+ * a callback mechanism because it will help to improve a level of consistency.
+ */
+int
+smbfs_advlock(ap)
+ struct vop_advlock_args /* {
+ struct vnode *a_vp;
+ caddr_t a_id;
+ int a_op;
+ struct flock *a_fl;
+ int a_flags;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct smbnode *np = VTOSMB(vp);
+ struct flock *fl = ap->a_fl;
+ caddr_t id = (caddr_t)1 /* ap->a_id */;
+/* int flags = ap->a_flags;*/
+ struct proc *p = curproc;
+ struct smb_cred scred;
+ off_t start, end, size;
+ int error, lkop;
+
+ if (vp->v_type == VDIR) {
+ /*
+ * SMB protocol have no support for directory locking.
+ * Although locks can be processed on local machine, I don't
+ * think that this is a good idea, because some programs
+ * can work wrong assuming directory is locked. So, we just
+ * return 'operation not supported
+ */
+ return EOPNOTSUPP;
+ }
+ size = np->n_size;
+ switch (fl->l_whence) {
+ case SEEK_SET:
+ case SEEK_CUR:
+ start = fl->l_start;
+ break;
+ case SEEK_END:
+ start = fl->l_start + size;
+ default:
+ return EINVAL;
+ }
+ if (start < 0)
+ return EINVAL;
+ if (fl->l_len == 0)
+ end = -1;
+ else {
+ end = start + fl->l_len - 1;
+ if (end < start)
+ return EINVAL;
+ }
+ smb_makescred(&scred, p, p ? p->p_ucred : NULL);
+ switch (ap->a_op) {
+ case F_SETLK:
+ switch (fl->l_type) {
+ case F_WRLCK:
+ lkop = SMB_LOCK_EXCL;
+ break;
+ case F_RDLCK:
+ lkop = SMB_LOCK_SHARED;
+ break;
+ case F_UNLCK:
+ lkop = SMB_LOCK_RELEASE;
+ break;
+ default:
+ return EINVAL;
+ }
+ error = lf_advlock(ap, &np->n_lockf, size);
+ if (error)
+ break;
+ lkop = SMB_LOCK_EXCL;
+ error = smbfs_smb_lock(np, lkop, id, start, end, &scred);
+ if (error) {
+ ap->a_op = F_UNLCK;
+ lf_advlock(ap, &np->n_lockf, size);
+ }
+ break;
+ case F_UNLCK:
+ lf_advlock(ap, &np->n_lockf, size);
+ error = smbfs_smb_lock(np, SMB_LOCK_RELEASE, id, start, end, &scred);
+ break;
+ case F_GETLK:
+ error = lf_advlock(ap, &np->n_lockf, size);
+ break;
+ default:
+ return EINVAL;
+ }
+ return error;
+}
+
+static int
+smbfs_pathcheck(struct smbmount *smp, const char *name, int nmlen, int nameiop)
+{
+ static const char *badchars = "*/\[]:<>=;?";
+ static const char *badchars83 = " +|,";
+ const char *cp;
+ int i, error;
+
+ if (nameiop == LOOKUP)
+ return 0;
+ error = ENOENT;
+ if (SMB_DIALECT(SSTOVC(smp->sm_share)) < SMB_DIALECT_LANMAN2_0) {
+ /*
+ * Name should conform 8.3 format
+ */
+ if (nmlen > 12)
+ return ENAMETOOLONG;
+ cp = index(name, '.');
+ if (cp == NULL)
+ return error;
+ if (cp == name || (cp - name) > 8)
+ return error;
+ cp = index(cp + 1, '.');
+ if (cp != NULL)
+ return error;
+ for (cp = name, i = 0; i < nmlen; i++, cp++)
+ if (index(badchars83, *cp) != NULL)
+ return error;
+ }
+ for (cp = name, i = 0; i < nmlen; i++, cp++)
+ if (index(badchars, *cp) != NULL)
+ return error;
+ return 0;
+}
+
+#ifndef PDIRUNLOCK
+#define PDIRUNLOCK 0
+#endif
+
+/*
+ * Things go even weird without fixed inode numbers...
+ */
+int
+smbfs_lookup(ap)
+ struct vop_lookup_args /* {
+ struct vnodeop_desc *a_desc;
+ struct vnode *a_dvp;
+ struct vnode **a_vpp;
+ struct componentname *a_cnp;
+ } */ *ap;
+{
+ struct componentname *cnp = ap->a_cnp;
+ struct proc *p = cnp->cn_proc;
+ struct vnode *dvp = ap->a_dvp;
+ struct vnode **vpp = ap->a_vpp;
+ struct vnode *vp;
+ struct smbmount *smp;
+ struct mount *mp = dvp->v_mount;
+ struct smbnode *dnp;
+ struct smbfattr fattr, *fap;
+ struct smb_cred scred;
+ char *name = cnp->cn_nameptr;
+ int flags = cnp->cn_flags;
+ int nameiop = cnp->cn_nameiop;
+ int nmlen = cnp->cn_namelen;
+ int lockparent, wantparent, error, islastcn, isdot;
+
+ SMBVDEBUG("\n");
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ if (dvp->v_type != VDIR)
+ return ENOTDIR;
+ if ((flags & ISDOTDOT) && (dvp->v_flag & VROOT)) {
+ SMBFSERR("invalid '..'\n");
+ return EIO;
+ }
+#ifdef SMB_VNODE_DEBUG
+ {
+ char *cp, c;
+
+ cp = name + nmlen;
+ c = *cp;
+ *cp = 0;
+ SMBVDEBUG("%d '%s' in '%s' id=d\n", nameiop, name,
+ VTOSMB(dvp)->n_name);
+ *cp = c;
+ }
+#endif
+ islastcn = flags & ISLASTCN;
+ if (islastcn && (mp->mnt_flag & MNT_RDONLY) && (nameiop != LOOKUP))
+ return EROFS;
+ if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p)) != 0)
+ return error;
+ lockparent = flags & LOCKPARENT;
+ wantparent = flags & (LOCKPARENT|WANTPARENT);
+ smp = VFSTOSMBFS(mp);
+ dnp = VTOSMB(dvp);
+ isdot = (nmlen == 1 && name[0] == '.');
+
+ error = smbfs_pathcheck(smp, cnp->cn_nameptr, cnp->cn_namelen, nameiop);
+
+ if (error)
+ return ENOENT;
+
+ error = cache_lookup(dvp, vpp, cnp);
+ SMBVDEBUG("cache_lookup returned %d\n", error);
+ if (error > 0)
+ return error;
+ if (error) { /* name was found */
+ struct vattr vattr;
+ int vpid;
+
+ vp = *vpp;
+ vpid = vp->v_id;
+ if (dvp == vp) { /* lookup on current */
+ vref(vp);
+ error = 0;
+ SMBVDEBUG("cached '.'\n");
+ } else if (flags & ISDOTDOT) {
+ VOP_UNLOCK(dvp, 0, p); /* unlock parent */
+ cnp->cn_flags |= PDIRUNLOCK;
+ error = vget(vp, LK_EXCLUSIVE, p);
+ if (!error && lockparent && islastcn) {
+ error = vn_lock(dvp, LK_EXCLUSIVE, p);
+ if (error == 0)
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ }
+ } else {
+ error = vget(vp, LK_EXCLUSIVE, p);
+ if (!lockparent || error || !islastcn) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+ }
+ if (!error) {
+ if (vpid == vp->v_id) {
+ if (!VOP_GETATTR(vp, &vattr, cnp->cn_cred, p)
+ /* && vattr.va_ctime.tv_sec == VTOSMB(vp)->n_ctime*/) {
+ if (nameiop != LOOKUP && islastcn)
+ cnp->cn_flags |= SAVENAME;
+ SMBVDEBUG("use cached vnode\n");
+ return (0);
+ }
+ cache_purge(vp);
+ }
+ vput(vp);
+ if (lockparent && dvp != vp && islastcn)
+ VOP_UNLOCK(dvp, 0, p);
+ }
+ error = vn_lock(dvp, LK_EXCLUSIVE, p);
+ *vpp = NULLVP;
+ if (error) {
+ cnp->cn_flags |= PDIRUNLOCK;
+ return (error);
+ }
+ cnp->cn_flags &= ~PDIRUNLOCK;
+ }
+ /*
+ * entry is not in the cache or has been expired
+ */
+ error = 0;
+ *vpp = NULLVP;
+ smb_makescred(&scred, p, cnp->cn_cred);
+ fap = &fattr;
+ if (flags & ISDOTDOT) {
+ error = smbfs_smb_lookup(dnp->n_parent, NULL, 0, fap, &scred);
+ SMBVDEBUG("result of dotdot lookup: %d\n", error);
+ } else {
+ fap = &fattr;
+ error = smbfs_smb_lookup(dnp, name, nmlen, fap, &scred);
+/* if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')*/
+ SMBVDEBUG("result of smbfs_smb_lookup: %d\n", error);
+ }
+ if (error && error != ENOENT)
+ return error;
+ if (error) { /* entry not found */
+ /*
+ * Handle RENAME or CREATE case...
+ */
+ if ((nameiop == CREATE || nameiop == RENAME) && wantparent && islastcn) {
+ cnp->cn_flags |= SAVENAME;
+ if (!lockparent) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+ return (EJUSTRETURN);
+ }
+ return ENOENT;
+ }/* else {
+ SMBVDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum);
+ }*/
+ /*
+ * handle DELETE case ...
+ */
+ if (nameiop == DELETE && islastcn) { /* delete last component */
+ error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, p);
+ if (error)
+ return error;
+ if (isdot) {
+ VREF(dvp);
+ *vpp = dvp;
+ return 0;
+ }
+ error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp);
+ if (error)
+ return error;
+ *vpp = vp;
+ cnp->cn_flags |= SAVENAME;
+ if (!lockparent) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+ return 0;
+ }
+ if (nameiop == RENAME && islastcn && wantparent) {
+ error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, p);
+ if (error)
+ return error;
+ if (isdot)
+ return EISDIR;
+ error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp);
+ if (error)
+ return error;
+ *vpp = vp;
+ cnp->cn_flags |= SAVENAME;
+ if (!lockparent) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+ return 0;
+ }
+ if (flags & ISDOTDOT) {
+ VOP_UNLOCK(dvp, 0, p);
+ error = smbfs_nget(mp, dvp, name, nmlen, NULL, &vp);
+ if (error) {
+ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
+ return error;
+ }
+ if (lockparent && islastcn) {
+ error = vn_lock(dvp, LK_EXCLUSIVE, p);
+ if (error) {
+ cnp->cn_flags |= PDIRUNLOCK;
+ vput(vp);
+ return error;
+ }
+ }
+ *vpp = vp;
+ } else if (isdot) {
+ vref(dvp);
+ *vpp = dvp;
+ } else {
+ error = smbfs_nget(mp, dvp, name, nmlen, fap, &vp);
+ if (error)
+ return error;
+ *vpp = vp;
+ SMBVDEBUG("lookup: getnewvp!\n");
+ if (!lockparent || !islastcn) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+ }
+ if ((cnp->cn_flags & MAKEENTRY)/* && !islastcn*/) {
+/* VTOSMB(*vpp)->n_ctime = VTOSMB(*vpp)->n_vattr.va_ctime.tv_sec;*/
+ cache_enter(dvp, *vpp, cnp);
+ }
+ return 0;
+}
OpenPOWER on IntegriCloud