int smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen, struct smbfattr *fap, struct smb_cred *scred) { struct smbfs_fctx *ctx; int error; if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) { memset(fap, 0, sizeof(*fap)); fap->fa_attr = SMB_FA_DIR; fap->fa_ino = 2; return 0; } if (nmlen == 1 && name[0] == '.') { error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); return error; } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') { error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap, scred); printf("%s: knows NOTHING about '..'\n", __func__); return error; } error = smbfs_findopen(dnp, name, nmlen, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx); if (error) return error; ctx->f_flags |= SMBFS_RDD_FINDSINGLE; error = smbfs_findnext(ctx, 1, scred); if (error == 0) { *fap = ctx->f_attr; if (name == NULL) fap->fa_ino = dnp->n_ino; /* * Check the returned file name case exactly * matches requested file name. ctx->f_nmlen is * guaranteed to always match nmlen. */ if (nmlen > 0 && strncmp(name, ctx->f_name, nmlen) != 0) error = ENOENT; } smbfs_findclose(ctx, scred); return error; }
int smbfs_smb_lookup(struct smbnode *dnp, const char *name, int nmlen, struct smbfattr *fap, struct smb_cred *scred) { struct smbfs_fctx *ctx; int error; if (dnp == NULL || (dnp->n_ino == 2 && name == NULL)) { bzero(fap, sizeof(*fap)); fap->fa_attr = SMB_FA_DIR; fap->fa_ino = 2; return 0; } if (nmlen == 1 && name[0] == '.') { error = smbfs_smb_lookup(dnp, NULL, 0, fap, scred); return error; } else if (nmlen == 2 && name[0] == '.' && name[1] == '.') { error = smbfs_smb_lookup(VTOSMB(dnp->n_parent), NULL, 0, fap, scred); kprintf("%s: knows NOTHING about '..'\n", __func__); return error; } error = smbfs_findopen(dnp, name, nmlen, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scred, &ctx); if (error) return error; ctx->f_flags |= SMBFS_RDD_FINDSINGLE; error = smbfs_findnext(ctx, 1, scred); if (error == 0) { *fap = ctx->f_attr; if (name == NULL) fap->fa_ino = dnp->n_ino; } smbfs_findclose(ctx, scred); return error; }
int smbfs_mkdir(void *v) { struct vop_mkdir_v3_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vattr *a_vap; } */ *ap = v; struct vnode *dvp = ap->a_dvp; /* struct vattr *vap = ap->a_vap;*/ struct vnode *vp; struct componentname *cnp = ap->a_cnp; struct smbnode *dnp = VTOSMB(dvp); struct smb_cred scred; struct smbfattr fattr; const char *name = cnp->cn_nameptr; int len = cnp->cn_namelen; int error; if ((name[0] == '.') && ((len == 1) || ((len == 2) && (name[1] == '.')))){ error = EEXIST; goto out; } smb_makescred(&scred, curlwp, cnp->cn_cred); error = smbfs_smb_mkdir(dnp, name, len, &scred); if (error) goto out; error = smbfs_smb_lookup(dnp, name, len, &fattr, &scred); if (error) goto out; error = smbfs_nget(VTOVFS(dvp), dvp, name, len, &fattr, &vp); if (error) goto out; VOP_UNLOCK(vp); *ap->a_vpp = vp; out: VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK); return (error); }
/* * smbfs_create call * Create a regular file. On entry the directory to contain the file being * created is locked. We must release before we return. */ int smbfs_create(void *v) { struct vop_create_v3_args /* { struct vnode *a_dvp; struct vnode **a_vpp; struct componentname *a_cnp; struct vattr *a_vap; } */ *ap = v; struct vnode *dvp = ap->a_dvp; struct vattr *vap = ap->a_vap; struct componentname *cnp = ap->a_cnp; struct smbnode *dnp = VTOSMB(dvp); struct smbfattr fattr; struct smb_cred scred; const char *name = cnp->cn_nameptr; int nmlen = cnp->cn_namelen; int error = EINVAL; if (vap->va_type != VREG) goto out; smb_makescred(&scred, curlwp, cnp->cn_cred); error = smbfs_smb_create(dnp, name, nmlen, &scred); if (error) goto out; error = smbfs_smb_lookup(dnp, name, nmlen, &fattr, &scred); if (error) goto out; error = smbfs_nget(VTOVFS(dvp), dvp, name, nmlen, &fattr, ap->a_vpp); if (error) goto out; VOP_UNLOCK(*ap->a_vpp); cache_enter(dvp, *ap->a_vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags); out: VN_KNOTE(dvp, NOTE_WRITE); return (error); }
/* * Return locked root vnode of a filesystem */ static int smbfs_root(struct mount *mp, struct vnode **vpp) { struct thread *td = curthread; /* XXX */ struct smbmount *smp = VFSTOSMBFS(mp); struct vnode *vp; struct smbnode *np; struct smbfattr fattr; struct ucred *cred; 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); } if (td->td_proc) cred = td->td_proc->p_ucred; else cred = proc0.p_ucred; 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; vsetflags(vp, VROOT); np = VTOSMB(vp); smp->sm_root = np; *vpp = vp; return 0; }
/* * Get root vnode of the smbfs filesystem, and store it in sm_root. */ static int smbfs_setroot(struct mount *mp) { struct smbmount *smp = VFSTOSMBFS(mp); struct vnode *vp; struct smbfattr fattr; struct lwp *l = curlwp; kauth_cred_t cred = l->l_cred; struct smb_cred scred; int error; KASSERT(smp->sm_root == NULL); smb_makescred(&scred, l, 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; /* * Someone might have already set sm_root while we slept * in smb_lookup or malloc/getnewvnode. */ if (smp->sm_root) vput(vp); else { vp->v_vflag |= VV_ROOT; smp->sm_root = VTOSMB(vp); /* Keep reference, but unlock */ VOP_UNLOCK(vp, 0); } return (0); }
/* * smbfs_getattr call from vfs. */ int smbfs_getattr(void *v) { struct vop_getattr_args /* { struct vnode *a_vp; struct vattr *a_vap; kauth_cred_t a_cred; } */ *ap = v; struct vnode *vp = ap->a_vp; struct smbnode *np = VTOSMB(vp); struct vattr *va=ap->a_vap; struct smbfattr fattr; struct smb_cred scred; u_quad_t oldsize; int error; SMBVDEBUG("%p: '%.*s' isroot %d\n", vp, (int) np->n_nmlen, np->n_name, (vp->v_vflag & VV_ROOT) != 0); if ((error = smbfs_attr_cachelookup(vp, va)) == 0) return (0); SMBVDEBUG0("not in the cache\n"); smb_makescred(&scred, curlwp, ap->a_cred); oldsize = np->n_size; error = smbfs_smb_lookup(np, NULL, 0, &fattr, &scred); if (error) { SMBVDEBUG("error %d\n", error); return error; } smbfs_attr_cacheenter(vp, &fattr); smbfs_attr_cachelookup(vp, va); if ((np->n_flag & NOPEN) != 0) np->n_size = oldsize; return 0; }
/* * Return locked root vnode of a filesystem */ static int smbfs_root(struct mount *mp, int flags, struct vnode **vpp) { struct smbmount *smp = VFSTOSMBFS(mp); struct vnode *vp; struct smbnode *np; struct smbfattr fattr; struct thread *td; struct ucred *cred; struct smb_cred *scred; int error; td = curthread; cred = td->td_ucred; if (smp->sm_root) { *vpp = SMBTOV(smp->sm_root); return vget(*vpp, LK_EXCLUSIVE | LK_RETRY, td); } scred = smbfs_malloc_scred(); smb_makescred(scred, td, cred); error = smbfs_smb_lookup(NULL, NULL, 0, &fattr, scred); if (error) goto out; error = smbfs_nget(mp, NULL, NULL, 0, &fattr, &vp); if (error) goto out; ASSERT_VOP_LOCKED(vp, "smbfs_root"); vp->v_vflag |= VV_ROOT; np = VTOSMB(vp); smp->sm_root = np; *vpp = vp; out: smbfs_free_scred(scred); return error; }