/* * This routine traverse the b+ tree representing directory * looking for file named 'name'. Returns buf struct and hpfsdirent * pointer. Calling routine is supposed to brelse buffer. * name is supposed in Unix encodeing. */ int hpfs_genlookupbyname ( struct hpfsnode *dhp, char *name, int namelen, struct buf **bpp, struct hpfsdirent **depp) { struct hpfsmount *hpmp = dhp->h_hpmp; struct buf *bp; struct dirblk *dp; struct hpfsdirent *dep; lsn_t lsn; int error, res; dprintf(("hpfs_genlookupbyname(0x%x, %s (%d)): \n", dhp->h_no, name, namelen)); lsn = ((alleaf_t *)dhp->h_fn.fn_abd)->al_lsn; dive: error = hpfs_breaddirblk (hpmp, lsn, &bp); if (error) return (error); dp = (struct dirblk *) bp->b_data; dep = D_DIRENT(dp); while(!(dep->de_flag & DE_END)) { dprintf(("no: 0x%x, size: %d, name: %2d:%.*s, flag: 0x%x\n", dep->de_fnode, dep->de_size, dep->de_namelen, dep->de_namelen, dep->de_name, dep->de_flag)); res = hpfs_cmpfname(hpmp, name, namelen, dep->de_name, dep->de_namelen, dep->de_cpid); if (res == 0) { *bpp = bp; *depp = dep; return (0); } else if (res < 0) break; dep = (hpfsdirent_t *)(((caddr_t)dep) + dep->de_reclen); } if (dep->de_flag & DE_DOWN) { lsn = DE_DOWNLSN(dep); brelse(bp); goto dive; } brelse(bp); return (ENOENT); }
/* * hpfs_readdir(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred, * int *a_ncookies, off_t **cookies) */ int hpfs_readdir(struct vop_readdir_args *ap) { struct vnode *vp = ap->a_vp; struct hpfsnode *hp = VTOHP(vp); struct hpfsmount *hpmp = hp->h_hpmp; struct uio *uio = ap->a_uio; int ncookies = 0, i, num, cnum; int error = 0; struct buf *bp; struct dirblk *dp; struct hpfsdirent *dep; lsn_t olsn; lsn_t lsn; int level; dprintf(("hpfs_readdir(0x%x, 0x%x, 0x%lx): ", hp->h_no, (u_int32_t)uio->uio_offset, uio->uio_resid)); /* * As we need to fake up . and .., and the remaining directory structure * can't be expressed in one off_t as well, we just increment uio_offset * by 1 for each entry. * * num is the entry we need to start reporting * cnum is the current entry */ if (uio->uio_offset < 0 || uio->uio_offset > INT_MAX) return(EINVAL); if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY)) != 0) return (error); num = uio->uio_offset; cnum = 0; if( num <= cnum ) { dprintf((". faked, ")); if (vop_write_dirent(&error, uio, hp->h_no, DT_DIR, 1, ".")) goto done; if (error) goto done; ncookies ++; } cnum++; if( num <= cnum ) { dprintf((".. faked, ")); if (vop_write_dirent(&error, uio, hp->h_fn.fn_parent, DT_DIR, 2, "..")) goto readdone; if (error) goto done; ncookies ++; } cnum++; lsn = ((alleaf_t *)hp->h_fn.fn_abd)->al_lsn; olsn = 0; level = 1; dive: dprintf(("[dive 0x%x] ", lsn)); error = bread(hp->h_devvp, dbtodoff(lsn), D_BSIZE, &bp); if (error) { brelse(bp); goto done; } dp = (struct dirblk *) bp->b_data; if (dp->d_magic != D_MAGIC) { kprintf("hpfs_readdir: MAGIC DOESN'T MATCH\n"); brelse(bp); error = EINVAL; goto done; } dep = D_DIRENT(dp); if (olsn) { dprintf(("[restore 0x%x] ", olsn)); while(!(dep->de_flag & DE_END) ) { if((dep->de_flag & DE_DOWN) && (olsn == DE_DOWNLSN(dep))) break; dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen); } if((dep->de_flag & DE_DOWN) && (olsn == DE_DOWNLSN(dep))) { if (dep->de_flag & DE_END) goto blockdone; if (!(dep->de_flag & DE_SPECIAL)) { if (num <= cnum) { if (hpfs_de_uiomove(&error, hpmp, dep, uio)) { brelse(bp); dprintf(("[resid] ")); goto readdone; } if (error) { brelse (bp); goto done; } ncookies++; } cnum++; } dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen); } else { kprintf("hpfs_readdir: ERROR! oLSN not found\n"); brelse(bp); error = EINVAL; goto done; } } olsn = 0; while(!(dep->de_flag & DE_END)) { if(dep->de_flag & DE_DOWN) { lsn = DE_DOWNLSN(dep); brelse(bp); level++; goto dive; } if (!(dep->de_flag & DE_SPECIAL)) { if (num <= cnum) { if (hpfs_de_uiomove(&error, hpmp, dep, uio)) { brelse(bp); dprintf(("[resid] ")); goto readdone; } if (error) { brelse (bp); goto done; } ncookies++; } cnum++; } dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen); } if(dep->de_flag & DE_DOWN) { dprintf(("[enddive] ")); lsn = DE_DOWNLSN(dep); brelse(bp); level++; goto dive; } blockdone: dprintf(("[EOB] ")); olsn = lsn; lsn = dp->d_parent; brelse(bp); level--; dprintf(("[level %d] ", level)); if (level > 0) goto dive; /* undive really */ if (ap->a_eofflag) { dprintf(("[EOF] ")); *ap->a_eofflag = 1; } readdone: uio->uio_offset = cnum; dprintf(("[readdone]\n")); if (!error && ap->a_ncookies != NULL) { off_t *cookies; off_t *cookiep; dprintf(("%d cookies, ",ncookies)); if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) panic("hpfs_readdir: unexpected uio from NFS server"); cookies = kmalloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK); for (cookiep = cookies, i=0; i < ncookies; i++) *cookiep++ = ++num; *ap->a_ncookies = ncookies; *ap->a_cookies = cookies; } done: vn_unlock(ap->a_vp); return (error); }