/* * nwfs_getattr call from vfs. * * nwfs_getattr(struct vnode *a_vp, struct vattr *a_vap) */ static int nwfs_getattr(struct vop_getattr_args *ap) { thread_t td = curthread; /* XXX */ struct vnode *vp = ap->a_vp; struct nwnode *np = VTONW(vp); struct vattr *va=ap->a_vap; struct nwmount *nmp = VTONWFS(vp); struct nw_entry_info fattr; int error; u_int32_t oldsize; NCPVNDEBUG("%lx:%d: '%s' %d\n", (long)vp, nmp->n_volume, np->n_name, (vp->v_flag & VROOT) != 0); error = nwfs_attr_cachelookup(vp,va); if (!error) return 0; NCPVNDEBUG("not in cache\n"); oldsize = np->n_size; if (np->n_flag & NVOLUME) { error = ncp_obtain_info(nmp, np->n_fid.f_id, 0, NULL, &fattr, td,proc0.p_ucred); } else { error = ncp_obtain_info(nmp, np->n_fid.f_parent, np->n_nmlen, np->n_name, &fattr, td, proc0.p_ucred); } if (error) { NCPVNDEBUG("error %d\n", error); return error; } nwfs_attr_cacheenter(vp, &fattr); *va = np->n_vattr; if (np->opened) np->n_size = oldsize; return (0); }
/* * lookup name pointed by cnp in directory dvp and return file info in np. * May be I should create a little cache, but another way is to minimize * number of calls, on other hand, in multiprocess environment ... */ int ncp_lookup(struct vnode *dvp, int len, char *name, struct nw_entry_info *fap, struct thread *td,struct ucred *cred) { struct nwmount *nmp; struct nwnode *dnp; int error; if (!dvp || dvp->v_type != VDIR) { nwfs_printf("dvp is NULL or not a directory.\n"); return (ENOENT); } dnp = VTONW(dvp); nmp = VTONWFS(dvp); if (len == 1 && name[0] == '.') { if (dnp->n_flag & NVOLUME) { error = ncp_obtain_info(nmp, dnp->n_fid.f_id, 0, NULL, fap, td, cred); } else { error = ncp_obtain_info(nmp, dnp->n_fid.f_parent, dnp->n_nmlen, dnp->n_name, fap, td, cred); } return error; } else if (len == 2 && name[0] == '.' && name[1] == '.') { printf("%s: knows NOTHING about '..'\n", __func__); return EIO; } else { error = ncp_obtain_info(nmp, dnp->n_fid.f_id, len, name, fap, td, cred); } return error; }
/* * nwfs_ioctl(struct vnode *a_vp, u_long a_command, caddr_t a_data, * int a_fflag, struct ucred *a_cred) */ int nwfs_ioctl(struct vop_ioctl_args *ap) { int error; struct thread *td = curthread; /* XXX */ struct ucred *cred = ap->a_cred; struct vnode *vp = ap->a_vp; struct nwnode *np = VTONW(vp); struct nwmount *nmp = VTONWFS(vp); struct ncp_conn *conn = NWFSTOCONN(nmp); struct ncp_handle *hp; struct nw_entry_info *fap; void *data = ap->a_data; switch (ap->a_command) { case NWFSIOC_GETCONN: error = ncp_conn_lock(conn, td, cred, NCPM_READ); if (error) break; error = ncp_conn_gethandle(conn, td, &hp); ncp_conn_unlock(conn, td); if (error) break; *(int*)data = hp->nh_id; break; case NWFSIOC_GETEINFO: if ((error = VOP_EACCESS(vp, VEXEC, cred))) break; fap = data; error = ncp_obtain_info(nmp, np->n_fid.f_id, 0, NULL, fap, td, ap->a_cred); strcpy(fap->entryName, np->n_name); fap->nameLen = np->n_nmlen; break; case NWFSIOC_GETNS: if ((error = VOP_EACCESS(vp, VEXEC, cred))) break; *(int*)data = nmp->name_space; break; default: error = EINVAL; } return (error); }
/* Return locked vnode to root of a filesystem */ static int nwfs_root(struct mount *mp, struct vnode **vpp) { struct vnode *vp; struct nwmount *nmp; struct nwnode *np; struct ncp_conn *conn; struct nw_entry_info fattr; struct thread *td = curthread; /* XXX */ struct ucred *cred; int error, nsf, opt; u_char vol; KKASSERT(td->td_proc); cred = td->td_proc->p_ucred; nmp = VFSTONWFS(mp); conn = NWFSTOCONN(nmp); if (nmp->n_root) { *vpp = NWTOV(nmp->n_root); while (vget(*vpp, LK_EXCLUSIVE) != 0) /* XXX */ ; return 0; } error = ncp_lookup_volume(conn, nmp->m.mounted_vol, &vol, &nmp->n_rootent.f_id, td, cred); if (error) return ENOENT; nmp->n_volume = vol; error = ncp_get_namespaces(conn, vol, &nsf, td, cred); if (error) return ENOENT; if (nsf & NW_NSB_OS2) { NCPVODEBUG("volume %s has os2 namespace\n",nmp->m.mounted_vol); if ((nmp->m.flags & NWFS_MOUNT_NO_OS2) == 0) { nmp->name_space = NW_NS_OS2; nmp->m.nls.opt &= ~NWHP_DOS; } } opt = nmp->m.nls.opt; nsf = opt & (NWHP_UPPER | NWHP_LOWER); if (opt & NWHP_DOS) { if (nsf == (NWHP_UPPER | NWHP_LOWER)) { nmp->m.nls.opt &= ~(NWHP_LOWER | NWHP_UPPER); } else if (nsf == 0) { nmp->m.nls.opt |= NWHP_LOWER; } } else { if (nsf == (NWHP_UPPER | NWHP_LOWER)) { nmp->m.nls.opt &= ~(NWHP_LOWER | NWHP_UPPER); } } if (nmp->m.root_path[0]) { nmp->m.root_path[0]--; error = ncp_obtain_info(nmp, nmp->n_rootent.f_id, -nmp->m.root_path[0], nmp->m.root_path, &fattr, td, cred); if (error) { NCPFATAL("Invalid root path specified\n"); return ENOENT; } nmp->n_rootent.f_parent = fattr.dirEntNum; nmp->m.root_path[0]++; error = ncp_obtain_info(nmp, nmp->n_rootent.f_id, -nmp->m.root_path[0], nmp->m.root_path, &fattr, td, cred); if (error) { NCPFATAL("Invalid root path specified\n"); return ENOENT; } nmp->n_rootent.f_id = fattr.dirEntNum; } else { error = ncp_obtain_info(nmp, nmp->n_rootent.f_id, 0, NULL, &fattr, td, cred); if (error) { NCPFATAL("Can't obtain volume info\n"); return ENOENT; } fattr.nameLen = strlen(strcpy(fattr.entryName, NWFS_ROOTVOL)); nmp->n_rootent.f_parent = nmp->n_rootent.f_id; } error = nwfs_nget(mp, nmp->n_rootent, &fattr, NULL, &vp); if (error) return (error); vsetflags(vp, VROOT); np = VTONW(vp); if (nmp->m.root_path[0] == 0) np->n_flag |= NVOLUME; nmp->n_root = np; /* error = VOP_GETATTR(vp, &vattr); if (error) { vput(vp); NCPFATAL("Can't get root directory entry\n"); return error; }*/ *vpp = vp; return (0); }
/* * How to keep the brain busy ... * Currently lookup routine can make two lookup for vnode. This can be * avoided by reorg the code. * * nwfs_lookup(struct vnode *a_dvp, struct vnode **a_vpp, * struct componentname *a_cnp) */ int nwfs_lookup(struct vop_old_lookup_args *ap) { struct componentname *cnp = ap->a_cnp; struct vnode *dvp = ap->a_dvp; struct vnode **vpp = ap->a_vpp; int flags = cnp->cn_flags; struct vnode *vp; struct nwmount *nmp; struct mount *mp = dvp->v_mount; struct nwnode *dnp, *npp; struct nw_entry_info fattr, *fap; ncpfid fid; int nameiop=cnp->cn_nameiop; int lockparent, wantparent, error = 0, notfound; struct thread *td = cnp->cn_td; char _name[cnp->cn_namelen+1]; bcopy(cnp->cn_nameptr,_name,cnp->cn_namelen); _name[cnp->cn_namelen]=0; if (dvp->v_type != VDIR) return (ENOTDIR); if ((flags & CNP_ISDOTDOT) && (dvp->v_flag & VROOT)) { kprintf("nwfs_lookup: invalid '..'\n"); return EIO; } NCPVNDEBUG("%d '%s' in '%s' id=d\n", nameiop, _name, VTONW(dvp)->n_name/*, VTONW(dvp)->n_name*/); if ((mp->mnt_flag & MNT_RDONLY) && nameiop != NAMEI_LOOKUP) return (EROFS); if ((error = VOP_EACCESS(dvp, VEXEC, cnp->cn_cred))) return (error); lockparent = flags & CNP_LOCKPARENT; wantparent = flags & (CNP_LOCKPARENT | CNP_WANTPARENT); nmp = VFSTONWFS(mp); dnp = VTONW(dvp); /* kprintf("dvp %d:%d:%d\n", (int)mp, (int)dvp->v_flag & VROOT, (int)flags & CNP_ISDOTDOT); */ error = ncp_pathcheck(cnp->cn_nameptr, cnp->cn_namelen, &nmp->m.nls, (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) && (nmp->m.nls.opt & NWHP_NOSTRICT) == 0); if (error) return ENOENT; error = 0; *vpp = NULLVP; fap = NULL; if (flags & CNP_ISDOTDOT) { if (NWCMPF(&dnp->n_parent, &nmp->n_rootent)) { fid = nmp->n_rootent; fap = NULL; notfound = 0; } else { error = nwfs_lookupnp(nmp, dnp->n_parent, td, &npp); if (error) { return error; } fid = dnp->n_parent; fap = &fattr; /*np = *npp;*/ notfound = ncp_obtain_info(nmp, npp->n_dosfid, 0, NULL, fap, td, cnp->cn_cred); } } else { fap = &fattr; notfound = ncp_lookup(dvp, cnp->cn_namelen, cnp->cn_nameptr, fap, td, cnp->cn_cred); fid.f_id = fap->dirEntNum; if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') { fid.f_parent = dnp->n_fid.f_parent; } else fid.f_parent = dnp->n_fid.f_id; NCPVNDEBUG("call to ncp_lookup returned=%d\n",notfound); } if (notfound && notfound < 0x80 ) return (notfound); /* hard error */ if (notfound) { /* entry not found */ /* Handle RENAME or CREATE case... */ if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) && wantparent) { if (!lockparent) vn_unlock(dvp); return (EJUSTRETURN); } return ENOENT; }/* else { NCPVNDEBUG("Found entry %s with id=%d\n", fap->entryName, fap->dirEntNum); }*/ /* handle DELETE case ... */ if (nameiop == NAMEI_DELETE) { /* delete last component */ error = VOP_EACCESS(dvp, VWRITE, cnp->cn_cred); if (error) return (error); if (NWCMPF(&dnp->n_fid, &fid)) { /* we found ourselfs */ vref(dvp); *vpp = dvp; return 0; } error = nwfs_nget(mp, fid, fap, dvp, &vp); if (error) return (error); *vpp = vp; if (!lockparent) vn_unlock(dvp); return (0); } if (nameiop == NAMEI_RENAME && wantparent) { error = VOP_EACCESS(dvp, VWRITE, cnp->cn_cred); if (error) return (error); if (NWCMPF(&dnp->n_fid, &fid)) return EISDIR; error = nwfs_nget(mp, fid, fap, dvp, &vp); if (error) return (error); *vpp = vp; if (!lockparent) vn_unlock(dvp); return (0); } if (flags & CNP_ISDOTDOT) { vn_unlock(dvp); /* race to get the inode */ error = nwfs_nget(mp, fid, NULL, NULL, &vp); if (error) { vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); return (error); } if (lockparent) { error = vn_lock(dvp, LK_EXCLUSIVE | LK_FAILRECLAIM); if (error) { vput(vp); return (error); } } *vpp = vp; } else if (NWCMPF(&dnp->n_fid, &fid)) { vref(dvp); *vpp = dvp; } else { error = nwfs_nget(mp, fid, fap, dvp, &vp); if (error) return (error); *vpp = vp; NCPVNDEBUG("lookup: getnewvp!\n"); if (!lockparent) vn_unlock(dvp); } #if 0 /* XXX MOVE TO NREMOVE */ if ((cnp->cn_flags & CNP_MAKEENTRY)) { VTONW(*vpp)->n_ctime = VTONW(*vpp)->n_vattr.va_ctime.tv_sec; /* XXX */ } #endif return (0); }