initial stab at smbfs (CIFS). originally for freebsd by boris popov,

first ported to 1.4 branch by Christian Limpach <chris@nice.ch>.
This commit is contained in:
deberg 2000-12-07 03:33:46 +00:00
parent a934922366
commit f825ec3136
11 changed files with 5043 additions and 0 deletions

8
sys/smbfs/Makefile Normal file
View File

@ -0,0 +1,8 @@
# $NetBSD: Makefile,v 1.1 2000/12/07 03:33:46 deberg Exp $
KDIR= /sys/smbfs
INCSDIR= /usr/include/smbfs
INCS= smbfs.h smbfs_node.h smbfs_subr.h
.include <bsd.kinc.mk>

105
sys/smbfs/smbfs.h Normal file
View File

@ -0,0 +1,105 @@
/* $NetBSD: smbfs.h,v 1.1 2000/12/07 03:33:46 deberg Exp $ */
/*
* Copyright (c) 2000, 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.
*/
#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
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;
};
#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_ */

677
sys/smbfs/smbfs_io.c Normal file
View File

@ -0,0 +1,677 @@
/* $NetBSD: smbfs_io.c,v 1.1 2000/12/07 03:33:46 deberg Exp $ */
/*
* Copyright (c) 2000, 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.
*
*/
#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/mount.h>
#include <sys/namei.h>
#include <sys/vnode.h>
#include <sys/dirent.h>
#include <sys/signalvar.h>
#include <uvm/uvm_extern.h>
#include <sys/sysctl.h>
#ifndef NetBSD
#if __FreeBSD_version < 400000
#include <vm/vm_prot.h>
#endif
#endif
#include <uvm/uvm_page.h>
#include <uvm/uvm_object.h>
#include <uvm/uvm_pager.h>
#ifndef NetBSD
#include <vm/vnode_pager.h>
#endif
/*
#include <sys/ioccom.h>
*/
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_lock.h>
#include <smbfs/smbfs.h>
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
#ifdef FB_CURRENT
#include <sys/bio.h>
#else
#define bufdone biodone
#endif
#include <sys/buf.h>
/*#define SMBFS_RWGENERIC*/
extern int smbfs_pbuf_freecnt;
static int smbfs_fastlookup = 1;
extern struct linker_set sysctl_vfs_smbfs;
#ifdef SYSCTL_DECL
SYSCTL_DECL(_vfs_smbfs);
#endif
#ifndef NetBSD
SYSCTL_INT(_vfs_smbfs, OID_AUTO, fastlookup, CTLFLAG_RW, &smbfs_fastlookup, 0, "");
#endif
#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;
const unsigned char *hcp;
int i;
np = VTOSMB(vp);
SMBVDEBUG("dirname='%s'\n", np->n_name);
if (uio->uio_resid < DE_SIZE || uio->uio_offset < 0)
return EINVAL;
smb_makescred(&scred, uio->uio_procp, cred);
offset = uio->uio_offset / DE_SIZE; /* offset in the directory */
limit = uio->uio_resid / DE_SIZE;
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++) {
bzero((caddr_t)&de, DE_SIZE);
de.d_reclen = DE_SIZE;
error = smbfs_findnext(ctx, limit, &scred);
if (error)
break;
np->n_dirofs++;
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 && de.d_namlen <= NCHNAMLEN) {
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;
cn.cn_hash = 0;
for (hcp = cn.cn_nameptr, i = 1;
i <= cn.cn_namelen;
i++, hcp++)
cn.cn_hash += *hcp * i;
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;
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;*/
if (vp->v_type == VDIR) {
error = simple_spinlock(&np->n_rdirlock, 0);
if (error)
return error;
error = smbfs_readvdir(vp, uiop, cred);
simple_spinunlock(&np->n_rdirlock);
return error;
}
p = uiop->uio_procp;
/* 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;
#ifndef NetBSD
vnode_pager_setsize(vp, np->n_size);
#else
uvm_vnp_setsize(vp, np->n_size);
#endif
}
}
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);
#ifdef FB_CURRENT
if (bp->b_iocmd == BIO_READ) {
#else
if (bp->b_flags & B_READ) {
#endif
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_BSHIFT;
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;
/* case VDIR:
nfsstats.readdir_bios++;
uiop->uio_offset = ((u_quad_t)bp->b_lblkno) * NFS_DIRBLKSIZ;
if (smp->nm_flag & NFSMNT_RDIRPLUS) {
error = nfs_readdirplusrpc(vp, uiop, cr);
if (error == NFSERR_NOTSUPP)
smp->nm_flag &= ~NFSMNT_RDIRPLUS;
}
if ((smp->nm_flag & NFSMNT_RDIRPLUS) == 0)
error = nfs_readdirrpc(vp, uiop, cr);
if (error == 0 && uiop->uio_resid == bp->b_bcount)
bp->b_ioflags |= BIO_INVAL;
break;
*/
default:
printf("smbfs_doio: type %x unexpected\n",vp->v_type);
break;
};
if (error) {
bp->b_error = error;
#ifdef FB_CURRENT
bp->b_ioflags |= BIO_ERROR;
#else
bp->b_flags |= B_ERROR;
#endif
}
} else { /* write */
io.iov_base = bp->b_data;
io.iov_len = uiop->uio_resid = bp->b_bcount;
uiop->uio_offset = (((off_t)bp->b_blkno) << DEV_BSHIFT);
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; */
}
bp->b_resid = uiop->uio_resid;
bufdone(bp);
return error;
}
#ifndef NetBSD
/*
* 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 */
}
#endif
#ifndef NetBSD
/*
* 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 */
}
#endif
/*
* 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;
{
register 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);
}

63
sys/smbfs/smbfs_ioctl.c Normal file
View File

@ -0,0 +1,63 @@
/* $NetBSD: smbfs_ioctl.c,v 1.1 2000/12/07 03:33:46 deberg Exp $ */
/*
* Copyright (c) 2000, 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.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/ioccom.h>
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_lock.h>
#include <smbfs/smbfs.h>
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
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;
}

352
sys/smbfs/smbfs_node.c Normal file
View File

@ -0,0 +1,352 @@
/* $NetBSD: smbfs_node.c,v 1.1 2000/12/07 03:33:47 deberg Exp $ */
/*
* Copyright (c) 2000, 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.
*/
#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 <uvm/uvm_extern.h>
#include <sys/sysctl.h>
#ifndef NetBSD
#include <vm/vm_extern.h>
#endif
/*#include <vm/vm_page.h>
#include <vm/vm_object.h>*/
#include <sys/queue.h>
#include <sys/namei.h>
#include <sys/tree.h>
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_lock.h>
#include <smbfs/smbfs.h>
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
#define SMBFS_NOHASH(hval) (&smbfs_hashtbl[(hval) & smbfs_hashlen])
#define SLOCK_UNLOCK(id) do { \
if ((id) < 0) wakeup(&(id)); \
(id) = 0; \
} while(0);
#ifndef NetBSD
extern vop_t **smbfs_vnodeop_p;
MALLOC_DEFINE(M_SMBNODE, "SMBFS node", "SMBFS vnode private part");
MALLOC_DEFINE(M_SMBFSHASH, "SMBFS hash", "SMBFS hash table");
#endif
static LIST_HEAD(smbnode_hashhead, smbnode) *smbfs_hashtbl;
static u_long smbfs_hashlen;
static int smbfs_hashlock = 0;
#ifndef NetBSD
#if __FreeBSD_version > 500000
static int smbfs_hashprint(SYSCTL_HANDLER_ARGS);
#else
static int smbfs_hashprint SYSCTL_HANDLER_ARGS;
#endif
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
void
smbfs_hash_init(void)
{
smbfs_hashtbl = hashinit(desiredvnodes, HASH_LIST, M_SMBFSHASH,
M_WAITOK, &smbfs_hashlen);
}
void
smbfs_hash_free(void)
{
free(smbfs_hashtbl, M_SMBFSHASH);
}
static u_long
smbfs_hash(const u_char *name, int nmlen)
{
u_long v;
for (v = 0; nmlen; name++, nmlen--)
v += *name;
return v;
}
#ifndef NetBSD
static int
#if __FreeBSD_version > 500000
smbfs_hashprint(SYSCTL_HANDLER_ARGS)
#else
smbfs_hashprint SYSCTL_HANDLER_ARGS
#endif
{
struct smbnode_hashhead *nhpp;
struct smbnode *np;
struct vnode *vp;
int i;
if (smbfs_debuglevel == 0)
return 0;
printf("Name:uc:hc:parent\n");
for(i = 0; i <= smbfs_hashlen; i++) {
nhpp = &smbfs_hashtbl[i];
for (np = nhpp->lh_first; np != 0; np = np->n_hash.le_next) {
vp = SMBTOV(np);
printf("%s:%d:%d\n", np->n_name, vp->v_usecount,
vp->v_holdcnt/*,
(np->n_parent != NULL) ? np->n_parent->n_name : "<noparent>"
*/);
}
}
return 0;
}
#endif
int
smbfs_node_alloc(struct mount *mp, struct vnode *dvp,
const char *name, int nmlen, struct vnode **vpp)
{
/* struct proc *p = curproc; */ /* XXX */
struct smbnode_hashhead *nhpp;
struct smbnode *np, *np2, *dnp;
extern int (**smbfs_vnodeop_p)__P((void *));
struct vnode *vp;
u_long hashval;
int error;
*vpp = NULL;
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;
}
hashval = smbfs_hash(name, nmlen);
dnp = dvp ? VTOSMB(dvp) : NULL;
retry:
nhpp = SMBFS_NOHASH(hashval);
loop:
for (np = nhpp->lh_first; np; np = np->n_hash.le_next) {
vp = SMBTOV(np);
if (mp != vp->v_mount || np->n_parent != dnp ||
np->n_nmlen != nmlen || strcmp(name, np->n_name) != 0)
continue;
if (vget(vp, LK_EXCLUSIVE/* , p */))
goto loop;
*vpp = vp;
return(0);
}
if (smbfs_hashlock) {
while(smbfs_hashlock) {
smbfs_hashlock = -1;
tsleep((caddr_t)&smbfs_hashlock, PVFS, "smbhash", 0);
}
goto loop;
}
smbfs_hashlock = 1;
MALLOC(np, struct smbnode *, sizeof *np, M_SMBNODE, M_WAITOK);
error = getnewvnode(VT_SMBFS, mp, smbfs_vnodeop_p, &vp);
if (error) {
SLOCK_UNLOCK(smbfs_hashlock);
FREE(np, M_SMBNODE);
return error;
}
bzero(np, sizeof(*np));
vp->v_data = np;
np->n_vnode = vp;
np->n_mount = VFSTOSMBFS(mp);
np->n_nmlen = nmlen;
np->n_name = smb_memdup(name, nmlen + 1);
np->n_name[nmlen] = 0;
simple_spinlock_init(&np->n_rdirlock, "dirlck", PVFS);
for (np2 = nhpp->lh_first; np2 != 0; np2 = np->n_hash.le_next) {
if (mp != SMBTOV(np2)->v_mount || np->n_parent != dnp ||
np2->n_nmlen != nmlen || strcmp(name, np2->n_name) != 0)
continue;
vrele(vp);
smb_memfree(np->n_name);
FREE(np, M_SMBNODE);
SLOCK_UNLOCK(smbfs_hashlock);
goto retry;
}
LIST_INSERT_HEAD(nhpp, np, n_hash);
SLOCK_UNLOCK(smbfs_hashlock);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY/* , p */);
np->n_flag |= NNEW;
*vpp = vp;
return error;
}
/*
* Free smbnode, and give vnode back to system
*/
int
smbfs_reclaim(ap)
struct vop_reclaim_args /* {
struct vnode *a_vp;
} */ *ap;
{
struct vnode *vp = ap->a_vp;
struct vnode *dvp = NULL;
struct smbnode *np = VTOSMB(vp);
struct smbmount *smp = VTOSMBFS(vp);
SMBVDEBUG("%s,%ld\n", np->n_name, vp->v_usecount);
if (np->n_parent && (np->n_flag & NREFPARENT))
dvp = np->n_parent->n_vnode;
LIST_REMOVE(np, n_hash);
cache_purge(vp);
if (smp->sm_root == np)
smp->sm_root = NULL;
vp->v_data = NULL;
if (np->n_name)
smb_memfree(np->n_name);
FREE(np, M_SMBNODE);
if (dvp)
vrele(dvp);
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: %ld\n", VTOSMB(vp)->n_name, vp->v_usecount);
if (np->opened) {
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->opened = 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;
#ifndef NetBSD
vnode_pager_setsize(vp, np->n_size);
#else
uvm_vnp_setsize(vp, np->n_size);
#endif
}
} 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 = mono_time.tv_sec;
return;
}
int
smbfs_attr_cachelookup(struct vnode *vp, struct vattr *va)
{
struct smbnode *np = VTOSMB(vp);
struct smbmount *smp = VTOSMBFS(vp);
int diff;
diff = mono_time.tv_sec - 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;
}

102
sys/smbfs/smbfs_node.h Normal file
View File

@ -0,0 +1,102 @@
/* $NetBSD: smbfs_node.h,v 1.1 2000/12/07 03:33:47 deberg Exp $ */
/*
* Copyright (c) 2000, 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.
*/
#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 */
#define NNEW 0x0008 /* smb/vnode has been allocated */
#define NREFPARENT 0x0010 /* node holds parent from recycling */
struct smbfs_fctx;
struct smbnode {
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_long n_size;
long n_ino;
int n_dosattr;
int opened;
u_int16_t n_fid; /* file handle */
int n_rwstate; /* granted access mode */
u_char n_nmlen;
u_char * n_name;
struct simplespinlock n_rdirlock;
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;
void smbfs_hash_init(void);
void smbfs_hash_free(void);
int smbfs_node_alloc(struct mount *mp, struct vnode *dvp, const char *name,
int nmlen, struct vnode **vpp);
int smbfs_inactive __P((struct vop_inactive_args *));
int smbfs_reclaim __P((struct vop_reclaim_args *));
int smbfs_nget(struct mount *mp, struct vnode *dvp, const char *name, int nmlen,
struct smbfattr *fap, struct vnode **vpp);
int smbfs_getpages __P((struct vop_getpages_args *));
int smbfs_putpages __P((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_ */

1235
sys/smbfs/smbfs_smb.c Normal file

File diff suppressed because it is too large Load Diff

337
sys/smbfs/smbfs_subr.c Normal file
View File

@ -0,0 +1,337 @@
/* $NetBSD: smbfs_subr.c,v 1.1 2000/12/07 03:33:47 deberg Exp $ */
/*
* Copyright (c) 2000, 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.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#ifndef NetBSD
#include <machine/clock.h>
#endif
#include <sys/time.h>
#include <sys/tree.h>
#include <sys/vnode.h>
#include <sys/subr_mbuf.h>
#ifndef NetBSD
#include <sys/iconv.h>
#endif
#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 <netsmb/smb_lock.h>
#include <smbfs/smbfs.h>
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
#ifndef NetBSD
MALLOC_DEFINE(M_SMBFSDATA, "SMBFS data", "SMBFS private data");
#endif
/*
* 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 mbdata *mbp, struct smb_conn *scp, 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, scp, "\\", 2, caseopt);*/
while (i--) {
np = *--npp;
error = mb_put_byte(mbp, '\\');
if (error)
break;
error = smb_put_dmem(mbp, scp, np->n_name, np->n_nmlen, caseopt);
if (error)
break;
}
simple_unlock(&smp->sm_npslock);
return error;
}
int
smbfs_fullpath(struct mbdata *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, VCTOCN(vcp), dnp, caseopt);
if (error)
return error;
}
if (name) {
error = mb_put_byte(mbp, '\\');
if (error)
return error;
error = smb_put_dmem(mbp, VCTOCN(vcp), name, nmlen, caseopt);
if (error)
return error;
}
error = mb_put_byte(mbp, 0);
return error;
}
int
smbfs_fname_tolocal(struct smb_conn *scp, char *name, int nmlen, int caseopt)
{
/* if (caseopt & SMB_CS_UPPER)
iconv_convmem(scp->sc_toupper, name, name, nmlen);
else if (caseopt & SMB_CS_LOWER)
iconv_convmem(scp->sc_tolower, name, name, nmlen);*/
#ifndef NetBSD
if (scp->sc_tolocal)
iconv_convmem(scp->sc_tolocal, name, name, nmlen);
#endif
return 0;
}

184
sys/smbfs/smbfs_subr.h Normal file
View File

@ -0,0 +1,184 @@
/* $NetBSD: smbfs_subr.h,v 1.1 2000/12/07 03:33:47 deberg Exp $ */
/*
* Copyright (c) 2000, 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.
*/
#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)
/* #define SMB_VNODE_DEBUG */
#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
/*
* 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 */
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;
};
#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 mbdata *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_conn *scp, 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_ */

575
sys/smbfs/smbfs_vfsops.c Normal file
View File

@ -0,0 +1,575 @@
/* $NetBSD: smbfs_vfsops.c,v 1.1 2000/12/07 03:33:47 deberg Exp $ */
/*
* Copyright (c) 2000, 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.
*/
#include "netsmb.h"
#ifndef NNETSMB
#error "SMBFS requires NSMB device"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <uvm/uvm_extern.h>
#include <sys/sysctl.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/malloc.h>
#include <sys/tree.h>
#include <netsmb/smb.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_dev.h>
#include <netsmb/smb_lock.h>
#include <smbfs/smbfs.h>
#include <smbfs/smbfs_node.h>
#include <smbfs/smbfs_subr.h>
#ifdef FB_CURRENT
#include <sys/bio.h>
#endif
#include <sys/buf.h>
int smbfs_debuglevel = 0;
#ifndef NetBSD
static int smbfs_version = SMBFS_VERSION;
#endif
#ifdef SMBFS_USEZONE
#include <vm/vm_extern.h>
#include <vm/vm_zone.h>
vm_zone_t smbfsmount_zone;
#endif
#ifndef NetBSD
#ifdef SYSCTL_DECL
SYSCTL_DECL(_vfs_smbfs);
#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, "");
#endif
int smbfs_mount __P((struct mount *, const char *, void *,
struct nameidata *, struct proc *));
int smbfs_quotactl __P((struct mount *, int, uid_t, caddr_t,
struct proc *));
int smbfs_root __P((struct mount *, struct vnode **));
int smbfs_start __P((struct mount *, int, struct proc *));
int smbfs_statfs __P((struct mount *, struct statfs *,
struct proc *));
int smbfs_sync __P((struct mount *, int, struct ucred *,
struct proc *));
int smbfs_unmount __P((struct mount *, int, struct proc *));
void smbfs_init __P((void));
#ifndef __NetBSD__
static int smbfs_uninit __P((struct vfsconf *vfsp));
#else
static void smbfs_uninit __P((void));
#endif
int smbfs_vget __P((struct mount *mp, ino_t ino,
struct vnode **vpp));
int smbfs_fhtovp __P((struct mount *, struct fid *,
struct vnode **));
int smbfs_vptofh __P((struct vnode *, struct fid *));
#ifndef NetBSD
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);
#else
extern struct vnodeopv_desc smbfs_vnodeop_opv_desc;
struct vnodeopv_desc *smbfs_vnodeopv_descs[] = {
&smbfs_vnodeop_opv_desc,
NULL,
};
struct vfsops smbfs_vfsops = {
MOUNT_SMBFS,
smbfs_mount,
smbfs_start,
smbfs_unmount,
smbfs_root,
smbfs_quotactl,
smbfs_statfs,
smbfs_sync,
smbfs_vget,
smbfs_fhtovp,
smbfs_vptofh,
smbfs_init,
#ifdef __NetBSD__
smbfs_uninit,
#endif
(int (*) (int *, u_int, void *, size_t *, void *, size_t, struct proc *))
eopnotsupp, /* sysctl */
(int (*)(void)) eopnotsupp, /* mountroot */
(int (*)(struct mount *, struct mbuf *, int *, struct ucred **))
eopnotsupp, /* checkexp */
smbfs_vnodeopv_descs,
};
#define M_USE_RESERVE M_WAITOK
#ifndef index
#define index strchr
#endif
#endif
#ifdef MODULE_DEPEND
MODULE_DEPEND(smbfs, netsmb, 1, 1, 1);
MODULE_DEPEND(smbfs, libiconv, 1, 1, 1);
#endif
int smbfs_pbuf_freecnt = -1; /* start out unlimited */
int
smbfs_mount(struct mount *mp, const char *path, void *data,
struct nameidata *ndp, struct proc *p)
{
struct smbfs_args args; /* will hold data from mount request */
struct smbmount *smp = NULL;
struct smb_conn *scp;
struct smb_share *ssp = NULL;
struct vnode *vp;
struct smb_cred scred;
size_t size;
int error;
char *pc, *pe;
SMBVDEBUG("\n");
if (data == NULL) {
printf("missing data argument\n");
return EINVAL;
}
if (mp->mnt_flag & MNT_UPDATE) {
printf("MNT_UPDATE not implemented\n");
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\n", args.dev);
return error;
}
scp = SSTOCN(ssp);
smb_share_unlock(ssp, 0, &scred);
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_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);
error = copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
if (error)
goto bad;
bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
pc = mp->mnt_stat.f_mntfromname;
pe = pc + sizeof(mp->mnt_stat.f_mntfromname);
bzero(pc, MNAMELEN);
*pc++ = '/';
*pc++ = '/';
pc=index(strncpy(pc, SSTOVC(ssp)->vc_user, pe - pc - 2), 0);
if (pc < pe-1) {
*(pc++) = '@';
pc = index(strncpy(pc, scp->sc_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';
#ifdef __NetBSD__
vfs_getnewfsid(mp);
#else
vfs_getnewfsid(mp, MOUNT_SMBFS);
#endif
error = smbfs_root(mp, &vp);
if (error)
goto bad;
VOP_UNLOCK(vp, 0/* , curproc */);
SMBVDEBUG("root.v_usecount = %ld\n", vp->v_usecount);
return error;
bad:
if (smp)
#ifdef SMBFS_USEZONE
zfree(smbfsmount_zone, smp);
#else
free(smp, M_SMBFSDATA);
#endif
if (ssp)
smb_share_put(ssp, p);
return error;
}
/* Unmount the filesystem described by mp. */
int
smbfs_unmount(struct mount *mp, int mntflags, struct proc *p)
{
struct smbmount *smp = VFSTOSMBFS(mp);
struct vnode *vp;
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 ((mntflags & MNT_FORCE) == 0 && 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_share_put(smp->sm_share, p);
mp->mnt_data = (qaddr_t)0;
#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
*/
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;
SMBVDEBUG("\n");
if (smp->sm_root) {
*vpp = SMBTOV(smp->sm_root);
vget(*vpp, LK_EXCLUSIVE | LK_RETRY/* , p */);
return 0;
}
smb_makescred(&scred, p, cred);
error = smbfs_smb_lookup(NULL, NULL, 0, &fattr, &scred);
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 */
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 */
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*/
void
smbfs_init(/* struct vfsconf *vfsp */void)
{
#ifndef NetBSD
#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
#endif
SMBVDEBUG("\n");
#ifdef SMBFS_USEZONE
smbfsmount_zone = zinit("SMBFSMOUNT", sizeof(struct smbmount), 0, 0, 1);
#endif
smbfs_hash_init();
smbfs_pbuf_freecnt = nswbuf / 2 + 1;
SMBVDEBUG("done.\n");
/* return 0; */
}
/*ARGSUSED*/
#ifndef NetBSD
int
smbfs_uninit(struct vfsconf *vfsp)
{
smbfs_hash_free();
SMBVDEBUG("done.\n");
return 0;
}
#else
void
smbfs_uninit(void)
{
smbfs_hash_free();
SMBVDEBUG("done.\n");
}
#endif
/*
* 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;
SMBVDEBUG("\n");
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 = 0/* 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);
}
#ifndef NetBSD
strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
#else
strncpy(sbp->f_fstypename, MOUNT_SMBFS, MFSNAMELEN-1);
#endif
return 0;
}
/*
* Flush out the buffer cache
*/
/* ARGSUSED */
int
smbfs_sync(mp, waitfor, cred, p)
struct mount *mp;
int waitfor;
struct ucred *cred;
struct proc *p;
{
register struct vnode *vp;
int error, allerror = 0;
/*
* Force stale buffer cache information to be flushed.
*/
SMBVDEBUG("\n");
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 NetBSD
#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)
#else
if (VOP_ISLOCKED(vp) || vp->v_dirtyblkhd.lh_first == NULL)
#endif
continue;
if (vget(vp, LK_EXCLUSIVE/* , p */))
goto loop;
error = VOP_FSYNC(vp, cred,
waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0, p);
if (error)
allerror = error;
vput(vp);
}
return (allerror);
}
#if __FreeBSD_version < 400009
/*
* smbfs flat namespace lookup. Unsupported.
*/
/* ARGSUSED */
int smbfs_vget(mp, ino, vpp)
struct mount *mp;
ino_t ino;
struct vnode **vpp;
{
return (EOPNOTSUPP);
}
/* ARGSUSED */
int smbfs_fhtovp(mp, fhp, /* nam, */ vpp/* , exflagsp, credanonp */)
register 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 */
int
smbfs_vptofh(vp, fhp)
struct vnode *vp;
struct fid *fhp;
{
return (EINVAL);
}
#endif /* __FreeBSD_version < 400009 */

1405
sys/smbfs/smbfs_vnops.c Normal file

File diff suppressed because it is too large Load Diff