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); }
/* * 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; }
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); scred = smbfs_malloc_scred(); 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) { error = EINVAL; goto out; } 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_parentino : 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(&de, DE_SIZE, uio); if (error) goto out; offset++; uio->uio_offset += DE_SIZE; } if (limit == 0) { error = 0; goto out; } 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); goto out; } 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; error = ENOENT ? 0 : error; goto out; } } 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(&de, DE_SIZE, uio); if (error) break; } if (error == ENOENT) error = 0; uio->uio_offset = offset * DE_SIZE; out: smbfs_free_scred(scred); return error; }
static int smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred) { struct smb_cred scred; struct smbfs_fctx *ctx; struct vnode *newvp; struct smbnode *np; int error, offset, retval; np = VTOSMB(vp); SMBVDEBUG("dirname='%s'\n", np->n_name); smb_makescred(&scred, uio->uio_td, cred); if (uio->uio_offset < 0 || uio->uio_offset > INT_MAX) return(EINVAL); error = 0; offset = uio->uio_offset; if (uio->uio_resid > 0 && offset < 1) { if (vop_write_dirent(&error, uio, np->n_ino, DT_DIR, 1, ".")) goto done; if (error) goto done; ++offset; } if (uio->uio_resid > 0 && offset < 2) { if (vop_write_dirent(&error, uio, np->n_parent ? VTOSMB(np->n_parent)->n_ino : 2, DT_DIR, 2, "..")) goto done; if (error) goto done; ++offset; } if (uio->uio_resid == 0) goto done; 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); ++np->n_dirofs; if (error) { smbfs_findclose(np->n_dirseq, &scred); np->n_dirseq = NULL; return error == ENOENT ? 0 : error; } } error = 0; while (uio->uio_resid > 0 && !error) { /* * Overestimate the size of a record a bit, doesn't really * hurt to be wrong here. */ error = smbfs_findnext(ctx, uio->uio_resid / _DIRENT_RECLEN(255) + 1, &scred); if (error) break; np->n_dirofs++; ++offset; retval = vop_write_dirent(&error, uio, ctx->f_attr.fa_ino, (ctx->f_attr.fa_attr & SMB_FA_DIR) ? DT_DIR : DT_REG, ctx->f_nmlen, ctx->f_name); if (retval) break; if (smbfs_fastlookup && !error) { error = smbfs_nget(vp->v_mount, vp, ctx->f_name, ctx->f_nmlen, &ctx->f_attr, &newvp); if (!error) vput(newvp); } } if (error == ENOENT) error = 0; done: uio->uio_offset = offset; return error; }