import freebsd smbfs code
This commit is contained in:
parent
c184665926
commit
18ef438300
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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: src/sys/fs/smbfs/smbfs.h,v 1.3 2001/12/02 08:56:58 bp Exp $
|
||||
*/
|
||||
#ifndef _SMBFS_SMBFS_H_
|
||||
#define _SMBFS_SMBFS_H_
|
||||
|
||||
#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;
|
||||
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 thread *td);
|
||||
int smbfs_vinvalbuf(struct vnode *vp, int flags, struct ucred *cred,
|
||||
struct thread *td, int intrflg);
|
||||
#endif /* KERNEL */
|
||||
|
||||
#endif /* _SMBFS_SMBFS_H_ */
|
|
@ -0,0 +1,677 @@
|
|||
/*
|
||||
* 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: src/sys/fs/smbfs/smbfs_io.c,v 1.7 2001/12/02 08:56:58 bp Exp $
|
||||
*
|
||||
*/
|
||||
#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 <sys/vmmeter.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;
|
||||
|
||||
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_td, 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 thread *td;
|
||||
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;*/
|
||||
td = uiop->uio_td;
|
||||
if (vp->v_type == VDIR) {
|
||||
lks = LK_EXCLUSIVE;/*lockstatus(&vp->v_lock, td);*/
|
||||
if (lks == LK_SHARED)
|
||||
vn_lock(vp, LK_UPGRADE | LK_RETRY, td);
|
||||
error = smbfs_readvdir(vp, uiop, cred);
|
||||
if (lks == LK_SHARED)
|
||||
vn_lock(vp, LK_DOWNGRADE | LK_RETRY, td);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* biosize = SSTOCN(smp->sm_share)->sc_txmax;*/
|
||||
if (np->n_flag & NMODIFIED) {
|
||||
smbfs_attr_cacheremove(vp);
|
||||
error = VOP_GETATTR(vp, &vattr, cred, td);
|
||||
if (error)
|
||||
return error;
|
||||
np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
|
||||
} else {
|
||||
error = VOP_GETATTR(vp, &vattr, cred, td);
|
||||
if (error)
|
||||
return error;
|
||||
if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) {
|
||||
error = smbfs_vinvalbuf(vp, V_SAVE, cred, td, 1);
|
||||
if (error)
|
||||
return error;
|
||||
np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
|
||||
}
|
||||
}
|
||||
smb_makescred(&scred, td, 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;
|
||||
struct thread *td;
|
||||
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);*/
|
||||
td = uiop->uio_td;
|
||||
p = td->td_proc;
|
||||
if (ioflag & (IO_APPEND | IO_SYNC)) {
|
||||
if (np->n_flag & NMODIFIED) {
|
||||
smbfs_attr_cacheremove(vp);
|
||||
error = smbfs_vinvalbuf(vp, V_SAVE, cred, td, 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, td);
|
||||
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) {
|
||||
PROC_LOCK(td->td_proc);
|
||||
psignal(td->td_proc, SIGXFSZ);
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
return EFBIG;
|
||||
}
|
||||
smb_makescred(&scred, td, 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 thread *td)
|
||||
{
|
||||
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_td = td;
|
||||
|
||||
smb_makescred(&scred, td, 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 vop_stdgetpages(ap);
|
||||
#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 thread *td;
|
||||
struct ucred *cred;
|
||||
struct smbmount *smp;
|
||||
struct smbnode *np;
|
||||
struct smb_cred scred;
|
||||
vm_page_t *pages;
|
||||
|
||||
vp = ap->a_vp;
|
||||
td = curthread; /* XXX */
|
||||
cred = td->td_proc->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, td, 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);
|
||||
cnt.v_vnodein++;
|
||||
cnt.v_vnodepgsin += count;
|
||||
|
||||
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_td = td;
|
||||
|
||||
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)
|
||||
vm_page_free(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;
|
||||
vm_page_undirty(m);
|
||||
} 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 {
|
||||
vm_page_free(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 thread *td;
|
||||
struct ucred *cred;
|
||||
|
||||
#ifdef SMBFS_RWGENERIC
|
||||
td = curthread; /* XXX */
|
||||
cred = td->td_proc->p_ucred; /* XXX */
|
||||
VOP_OPEN(vp, FWRITE, cred, td);
|
||||
error = vop_stdputpages(ap);
|
||||
VOP_CLOSE(vp, FWRITE, cred, td);
|
||||
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;
|
||||
|
||||
td = curthread; /* XXX */
|
||||
cred = td->td_proc->p_ucred; /* XXX */
|
||||
/* VOP_OPEN(vp, FWRITE, cred, td);*/
|
||||
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);
|
||||
cnt.v_vnodeout++;
|
||||
cnt.v_vnodepgsout += count;
|
||||
|
||||
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_td = td;
|
||||
SMBVDEBUG("ofs=%d,resid=%d\n",(int)uio.uio_offset, uio.uio_resid);
|
||||
|
||||
smb_makescred(&scred, td, cred);
|
||||
error = smb_write(smp->sm_share, np->n_fid, &uio, &scred);
|
||||
/* VOP_CLOSE(vp, FWRITE, cred, td);*/
|
||||
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;
|
||||
vm_page_undirty(pages[i]);
|
||||
}
|
||||
}
|
||||
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, td, intrflg)
|
||||
struct vnode *vp;
|
||||
int flags;
|
||||
struct ucred *cred;
|
||||
struct thread *td;
|
||||
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(td->td_proc);
|
||||
if (error == EINTR && intrflg)
|
||||
return EINTR;
|
||||
}
|
||||
np->n_flag |= NFLUSHINPROG;
|
||||
error = vinvalbuf(vp, flags, cred, td, 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, td, slpflag, 0);
|
||||
}
|
||||
np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
|
||||
if (np->n_flag & NFLUSHWANT) {
|
||||
np->n_flag &= ~NFLUSHWANT;
|
||||
wakeup((caddr_t)&np->n_flag);
|
||||
}
|
||||
return (error);
|
||||
}
|
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* 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: src/sys/fs/smbfs/smbfs_node.c,v 1.5 2001/12/20 22:42:26 dillon Exp $
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <netsmb/smb.h>
|
||||
#include <netsmb/smb_conn.h>
|
||||
#include <netsmb/smb_subr.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_extern.h>
|
||||
/*#include <vm/vm_page.h>
|
||||
#include <vm/vm_object.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, td) lockmgr(&smp->sm_hashlock, LK_EXCLUSIVE, NULL, td)
|
||||
#define smbfs_hash_unlock(smp, td) lockmgr(&smp->sm_hashlock, LK_RELEASE, NULL, td)
|
||||
|
||||
|
||||
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
|
||||
#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 thread *td = curthread; /* 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, td);
|
||||
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, td);
|
||||
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, td);
|
||||
if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td) != 0)
|
||||
goto retry;
|
||||
*vpp = vp;
|
||||
return 0;
|
||||
}
|
||||
smbfs_hash_unlock(smp, td);
|
||||
/*
|
||||
* 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", VLKTIMEOUT, LK_CANRECURSE);
|
||||
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
|
||||
|
||||
smbfs_hash_lock(smp, td);
|
||||
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, td);
|
||||
*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 thread *a_p;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct thread *td = ap->a_td;
|
||||
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, td);
|
||||
|
||||
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, td);
|
||||
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 thread *a_td;
|
||||
} */ *ap;
|
||||
{
|
||||
struct thread *td = ap->a_td;
|
||||
struct ucred *cred = td->td_proc->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, td, 1);
|
||||
smb_makescred(&scred, td, 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, td);
|
||||
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;
|
||||
}
|
|
@ -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: src/sys/fs/smbfs/smbfs_node.h,v 1.1 2001/04/10 07:59:05 bp Exp $
|
||||
*/
|
||||
#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_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -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: src/sys/fs/smbfs/smbfs_subr.c,v 1.1 2001/04/10 07:59:05 bp Exp $
|
||||
*/
|
||||
#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;
|
||||
}
|
|
@ -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: src/sys/fs/smbfs/smbfs_subr.h,v 1.2 2001/12/10 08:09:46 obrien Exp $
|
||||
*/
|
||||
#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, __func__ ,## args)
|
||||
|
||||
#ifdef SMB_VNODE_DEBUG
|
||||
#define SMBVDEBUG(format, args...) printf("%s: "format, __func__ ,## 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_ */
|
|
@ -0,0 +1,502 @@
|
|||
/*
|
||||
* 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: src/sys/fs/smbfs/smbfs_vfsops.c,v 1.5 2001/12/13 13:08:34 sheldonh Exp $
|
||||
*/
|
||||
#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 <sys/module.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 thread *);
|
||||
static int smbfs_quotactl(struct mount *, int, uid_t, caddr_t, struct thread *);
|
||||
static int smbfs_root(struct mount *, struct vnode **);
|
||||
static int smbfs_start(struct mount *, int, struct thread *);
|
||||
static int smbfs_statfs(struct mount *, struct statfs *, struct thread *);
|
||||
static int smbfs_sync(struct mount *, int, struct ucred *, struct thread *);
|
||||
static int smbfs_unmount(struct mount *, int, struct thread *);
|
||||
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);
|
||||
MODULE_DEPEND(smbfs, libmchain, 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 thread *td)
|
||||
{
|
||||
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, td, td->td_proc->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, td);
|
||||
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, td);
|
||||
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 thread *td)
|
||||
{
|
||||
struct smbmount *smp = VFSTOSMBFS(mp);
|
||||
struct smb_cred scred;
|
||||
int error, flags;
|
||||
|
||||
SMBVDEBUG("smbfs_unmount: flags=%04x\n", mntflags);
|
||||
flags = 0;
|
||||
if (mntflags & MNT_FORCE)
|
||||
flags |= FORCECLOSE;
|
||||
/* There is 1 extra root vnode reference from smbfs_mount(). */
|
||||
error = vflush(mp, 1, flags);
|
||||
if (error)
|
||||
return error;
|
||||
smb_makescred(&scred, td, td->td_proc->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 thread *td = curthread;
|
||||
struct ucred *cred = td->td_proc->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, td);
|
||||
}
|
||||
smb_makescred(&scred, td, 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, td)
|
||||
struct mount *mp;
|
||||
int flags;
|
||||
struct thread *td;
|
||||
{
|
||||
SMBVDEBUG("flags=%04x\n", flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do operations associated with quotas, not supported
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
smbfs_quotactl(mp, cmd, uid, arg, td)
|
||||
struct mount *mp;
|
||||
int cmd;
|
||||
uid_t uid;
|
||||
caddr_t arg;
|
||||
struct thread *td;
|
||||
{
|
||||
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(curthread, 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 thread *td)
|
||||
{
|
||||
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, td, td->td_proc->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, td)
|
||||
struct mount *mp;
|
||||
int waitfor;
|
||||
struct ucred *cred;
|
||||
struct thread *td;
|
||||
{
|
||||
struct vnode *vp;
|
||||
int error, allerror = 0;
|
||||
/*
|
||||
* Force stale buffer cache information to be flushed.
|
||||
*/
|
||||
loop:
|
||||
for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist);
|
||||
vp != NULL;
|
||||
vp = TAILQ_NEXT(vp, v_nmntvnodes)) {
|
||||
/*
|
||||
* 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, td))
|
||||
goto loop;
|
||||
error = VOP_FSYNC(vp, cred, waitfor, td);
|
||||
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 */
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue