1*8f6e076eSmickey /* $OpenBSD: cd9660_lookup.c,v 1.12 2006/01/25 21:15:55 mickey Exp $ */ 2053e05a2Sniklas /* $NetBSD: cd9660_lookup.c,v 1.18 1997/05/08 16:19:59 mycroft Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /*- 5df930be7Sderaadt * Copyright (c) 1989, 1993, 1994 6df930be7Sderaadt * The Regents of the University of California. All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * This code is derived from software contributed to Berkeley 9df930be7Sderaadt * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension 10df930be7Sderaadt * Support code is derived from software contributed to Berkeley 11df930be7Sderaadt * by Atsushi Murai (amurai@spec.co.jp). 12df930be7Sderaadt * 13df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 14df930be7Sderaadt * modification, are permitted provided that the following conditions 15df930be7Sderaadt * are met: 16df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 17df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 18df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 19df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 20df930be7Sderaadt * documentation and/or other materials provided with the distribution. 2129295d1cSmillert * 3. Neither the name of the University nor the names of its contributors 22df930be7Sderaadt * may be used to endorse or promote products derived from this software 23df930be7Sderaadt * without specific prior written permission. 24df930be7Sderaadt * 25df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35df930be7Sderaadt * SUCH DAMAGE. 36df930be7Sderaadt * 37df930be7Sderaadt * from: @(#)ufs_lookup.c 7.33 (Berkeley) 5/19/91 38df930be7Sderaadt * 39df930be7Sderaadt * @(#)cd9660_lookup.c 8.5 (Berkeley) 12/5/94 40df930be7Sderaadt */ 41df930be7Sderaadt 42df930be7Sderaadt #include <sys/param.h> 43df930be7Sderaadt #include <sys/namei.h> 44df930be7Sderaadt #include <sys/buf.h> 45df930be7Sderaadt #include <sys/file.h> 46df930be7Sderaadt #include <sys/vnode.h> 47df930be7Sderaadt #include <sys/mount.h> 489d71829cSniklas #include <sys/systm.h> 49*8f6e076eSmickey #include <sys/malloc.h> 50df930be7Sderaadt 51df930be7Sderaadt #include <isofs/cd9660/iso.h> 52053e05a2Sniklas #include <isofs/cd9660/cd9660_extern.h> 53df930be7Sderaadt #include <isofs/cd9660/cd9660_node.h> 54df930be7Sderaadt #include <isofs/cd9660/iso_rrip.h> 55df930be7Sderaadt #include <isofs/cd9660/cd9660_rrip.h> 56df930be7Sderaadt 57df930be7Sderaadt struct nchstats iso_nchstats; 58df930be7Sderaadt 59df930be7Sderaadt /* 60df930be7Sderaadt * Convert a component of a pathname into a pointer to a locked inode. 61df930be7Sderaadt * This is a very central and rather complicated routine. 62df930be7Sderaadt * If the file system is not maintained in a strict tree hierarchy, 63df930be7Sderaadt * this can result in a deadlock situation (see comments in code below). 64df930be7Sderaadt * 65df930be7Sderaadt * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 66df930be7Sderaadt * whether the name is to be looked up, created, renamed, or deleted. 67df930be7Sderaadt * When CREATE, RENAME, or DELETE is specified, information usable in 68df930be7Sderaadt * creating, renaming, or deleting a directory entry may be calculated. 69df930be7Sderaadt * If flag has LOCKPARENT or'ed into it and the target of the pathname 70df930be7Sderaadt * exists, lookup returns both the target and its parent directory locked. 71df930be7Sderaadt * When creating or renaming and LOCKPARENT is specified, the target may 72df930be7Sderaadt * not be ".". When deleting and LOCKPARENT is specified, the target may 73df930be7Sderaadt * be "."., but the caller must check to ensure it does an vrele and iput 74df930be7Sderaadt * instead of two iputs. 75df930be7Sderaadt * 76053e05a2Sniklas * Overall outline of cd9660_lookup: 77df930be7Sderaadt * 78df930be7Sderaadt * check accessibility of directory 79df930be7Sderaadt * look for name in cache, if found, then if at end of path 80df930be7Sderaadt * and deleting or creating, drop it, else return name 81df930be7Sderaadt * search for name in directory, to found or notfound 82df930be7Sderaadt * notfound: 83df930be7Sderaadt * if creating, return locked directory, leaving info on available slots 84df930be7Sderaadt * else return error 85df930be7Sderaadt * found: 86df930be7Sderaadt * if at end of path and deleting, return information to allow delete 87df930be7Sderaadt * if at end of path and rewriting (RENAME and LOCKPARENT), lock target 88df930be7Sderaadt * inode and return info to allow rewrite 89df930be7Sderaadt * if not at end, add name to cache; if at end and neither creating 90df930be7Sderaadt * nor deleting, add name to cache 91df930be7Sderaadt * 92df930be7Sderaadt * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode unlocked. 93df930be7Sderaadt */ 94df930be7Sderaadt int 959d71829cSniklas cd9660_lookup(v) 969d71829cSniklas void *v; 979d71829cSniklas { 98df930be7Sderaadt struct vop_lookup_args /* { 99df930be7Sderaadt struct vnode *a_dvp; 100df930be7Sderaadt struct vnode **a_vpp; 101df930be7Sderaadt struct componentname *a_cnp; 1029d71829cSniklas } */ *ap = v; 103df930be7Sderaadt register struct vnode *vdp; /* vnode for directory being searched */ 104df930be7Sderaadt register struct iso_node *dp; /* inode for directory being searched */ 105df930be7Sderaadt register struct iso_mnt *imp; /* file system that directory is in */ 106df930be7Sderaadt struct buf *bp; /* a buffer of directory entries */ 1079d71829cSniklas struct iso_directory_record *ep = NULL; 1089d71829cSniklas /* the current directory entry */ 109df930be7Sderaadt int entryoffsetinblock; /* offset of ep in bp's buffer */ 1109d71829cSniklas int saveoffset = -1; /* offset of last directory entry in dir */ 111df930be7Sderaadt int numdirpasses; /* strategy for directory search */ 112df930be7Sderaadt doff_t endsearch; /* offset to end directory search */ 113df930be7Sderaadt struct vnode *pdp; /* saved dp during symlink work */ 114df930be7Sderaadt struct vnode *tdp; /* returned by cd9660_vget_internal */ 115df930be7Sderaadt u_long bmask; /* block offset mask */ 116df930be7Sderaadt int lockparent; /* 1 => lockparent flag is set */ 117df930be7Sderaadt int wantparent; /* 1 => wantparent or lockparent flag */ 118df930be7Sderaadt int error; 119df930be7Sderaadt ino_t ino = 0; 120df930be7Sderaadt int reclen; 121df930be7Sderaadt u_short namelen; 122*8f6e076eSmickey char *altname; 123df930be7Sderaadt int res; 124df930be7Sderaadt int assoc, len; 125df930be7Sderaadt char *name; 126df930be7Sderaadt struct vnode **vpp = ap->a_vpp; 127df930be7Sderaadt struct componentname *cnp = ap->a_cnp; 128df930be7Sderaadt struct ucred *cred = cnp->cn_cred; 12909308f32Sart int flags; 130df930be7Sderaadt int nameiop = cnp->cn_nameiop; 13107feb63cScsapuntz struct proc *p = cnp->cn_proc; 132df930be7Sderaadt 13309308f32Sart cnp->cn_flags &= ~PDIRUNLOCK; 13409308f32Sart flags = cnp->cn_flags; 13509308f32Sart 136df930be7Sderaadt bp = NULL; 137df930be7Sderaadt *vpp = NULL; 138df930be7Sderaadt vdp = ap->a_dvp; 139df930be7Sderaadt dp = VTOI(vdp); 140df930be7Sderaadt imp = dp->i_mnt; 141df930be7Sderaadt lockparent = flags & LOCKPARENT; 142df930be7Sderaadt wantparent = flags & (LOCKPARENT|WANTPARENT); 143df930be7Sderaadt 144df930be7Sderaadt /* 145df930be7Sderaadt * Check accessiblity of directory. 146df930be7Sderaadt */ 1479d71829cSniklas if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 0) 148df930be7Sderaadt return (error); 149df930be7Sderaadt 15007feb63cScsapuntz if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && 15107feb63cScsapuntz (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 15207feb63cScsapuntz return (EROFS); 15307feb63cScsapuntz 154df930be7Sderaadt /* 155df930be7Sderaadt * We now have a segment name to search for, and a directory to search. 156df930be7Sderaadt * 157df930be7Sderaadt * Before tediously performing a linear scan of the directory, 158df930be7Sderaadt * check the name cache to see if the directory/name pair 159df930be7Sderaadt * we are looking for is known already. 160df930be7Sderaadt */ 16109308f32Sart if ((error = cache_lookup(vdp, vpp, cnp)) >= 0) 162df930be7Sderaadt return (error); 163df930be7Sderaadt 164df930be7Sderaadt len = cnp->cn_namelen; 165df930be7Sderaadt name = cnp->cn_nameptr; 166df930be7Sderaadt /* 167df930be7Sderaadt * A leading `=' means, we are looking for an associated file 168df930be7Sderaadt */ 1699d71829cSniklas assoc = (imp->iso_ftype != ISO_FTYPE_RRIP && *name == ASSOCCHAR); 1709d71829cSniklas if (assoc) { 171df930be7Sderaadt len--; 172df930be7Sderaadt name++; 173df930be7Sderaadt } 174df930be7Sderaadt 175df930be7Sderaadt /* 176df930be7Sderaadt * If there is cached information on a previous search of 177df930be7Sderaadt * this directory, pick up where we last left off. 178df930be7Sderaadt * We cache only lookups as these are the most common 179df930be7Sderaadt * and have the greatest payoff. Caching CREATE has little 180df930be7Sderaadt * benefit as it usually must search the entire directory 181df930be7Sderaadt * to determine that the entry does not exist. Caching the 182df930be7Sderaadt * location of the last DELETE or RENAME has not reduced 183df930be7Sderaadt * profiling time and hence has been removed in the interest 184df930be7Sderaadt * of simplicity. 185df930be7Sderaadt */ 186df930be7Sderaadt bmask = imp->im_bmask; 187df930be7Sderaadt if (nameiop != LOOKUP || dp->i_diroff == 0 || 188df930be7Sderaadt dp->i_diroff > dp->i_size) { 189df930be7Sderaadt entryoffsetinblock = 0; 190df930be7Sderaadt dp->i_offset = 0; 191df930be7Sderaadt numdirpasses = 1; 192df930be7Sderaadt } else { 193df930be7Sderaadt dp->i_offset = dp->i_diroff; 194df930be7Sderaadt if ((entryoffsetinblock = dp->i_offset & bmask) && 195574066a2Scsapuntz (error = cd9660_bufatoff(dp, (off_t)dp->i_offset, NULL, 196574066a2Scsapuntz &bp))) 197df930be7Sderaadt return (error); 198df930be7Sderaadt numdirpasses = 2; 199df930be7Sderaadt iso_nchstats.ncs_2passes++; 200df930be7Sderaadt } 201df930be7Sderaadt endsearch = dp->i_size; 202df930be7Sderaadt 203df930be7Sderaadt searchloop: 204df930be7Sderaadt while (dp->i_offset < endsearch) { 205df930be7Sderaadt /* 206df930be7Sderaadt * If offset is on a block boundary, 207df930be7Sderaadt * read the next directory block. 208df930be7Sderaadt * Release previous if it exists. 209df930be7Sderaadt */ 210df930be7Sderaadt if ((dp->i_offset & bmask) == 0) { 211df930be7Sderaadt if (bp != NULL) 212df930be7Sderaadt brelse(bp); 213574066a2Scsapuntz error = cd9660_bufatoff(dp, (off_t)dp->i_offset, 2149d71829cSniklas NULL, &bp); 2159d71829cSniklas if (error) 216df930be7Sderaadt return (error); 217df930be7Sderaadt entryoffsetinblock = 0; 218df930be7Sderaadt } 219df930be7Sderaadt /* 220df930be7Sderaadt * Get pointer to next entry. 221df930be7Sderaadt */ 222df930be7Sderaadt ep = (struct iso_directory_record *) 223df930be7Sderaadt ((char *)bp->b_data + entryoffsetinblock); 224df930be7Sderaadt 225df930be7Sderaadt reclen = isonum_711(ep->length); 226df930be7Sderaadt if (reclen == 0) { 227df930be7Sderaadt /* skip to next block, if any */ 228df930be7Sderaadt dp->i_offset = 229df930be7Sderaadt (dp->i_offset & ~bmask) + imp->logical_block_size; 230df930be7Sderaadt continue; 231df930be7Sderaadt } 232df930be7Sderaadt 233df930be7Sderaadt if (reclen < ISO_DIRECTORY_RECORD_SIZE) 234df930be7Sderaadt /* illegal entry, stop */ 235df930be7Sderaadt break; 236df930be7Sderaadt 237df930be7Sderaadt if (entryoffsetinblock + reclen > imp->logical_block_size) 238df930be7Sderaadt /* entries are not allowed to cross boundaries */ 239df930be7Sderaadt break; 240df930be7Sderaadt 241df930be7Sderaadt namelen = isonum_711(ep->name_len); 242df930be7Sderaadt 243df930be7Sderaadt if (reclen < ISO_DIRECTORY_RECORD_SIZE + namelen) 244df930be7Sderaadt /* illegal entry, stop */ 245df930be7Sderaadt break; 246df930be7Sderaadt 247df930be7Sderaadt /* 248df930be7Sderaadt * Check for a name match. 249df930be7Sderaadt */ 250df930be7Sderaadt switch (imp->iso_ftype) { 251df930be7Sderaadt default: 252df930be7Sderaadt if ((!(isonum_711(ep->flags)&4)) == !assoc) { 253df930be7Sderaadt if ((len == 1 254df930be7Sderaadt && *name == '.') 255df930be7Sderaadt || (flags & ISDOTDOT)) { 256df930be7Sderaadt if (namelen == 1 257df930be7Sderaadt && ep->name[0] == ((flags & ISDOTDOT) ? 1 : 0)) { 258df930be7Sderaadt /* 259df930be7Sderaadt * Save directory entry's inode number and 260df930be7Sderaadt * release directory buffer. 261df930be7Sderaadt */ 262df930be7Sderaadt dp->i_ino = isodirino(ep, imp); 263df930be7Sderaadt goto found; 264df930be7Sderaadt } 265df930be7Sderaadt if (namelen != 1 266df930be7Sderaadt || ep->name[0] != 0) 267df930be7Sderaadt goto notfound; 268df930be7Sderaadt } else if (!(res = isofncmp(name, len, 26949f343b7Sd ep->name, namelen, imp->joliet_level))) { 270df930be7Sderaadt if (isonum_711(ep->flags)&2) 271df930be7Sderaadt ino = isodirino(ep, imp); 272df930be7Sderaadt else 273df930be7Sderaadt ino = dbtob(bp->b_blkno) 274df930be7Sderaadt + entryoffsetinblock; 275df930be7Sderaadt saveoffset = dp->i_offset; 276df930be7Sderaadt } else if (ino) 277df930be7Sderaadt goto foundino; 278df930be7Sderaadt #ifdef NOSORTBUG /* On some CDs directory entries are not sorted correctly */ 279df930be7Sderaadt else if (res < 0) 280df930be7Sderaadt goto notfound; 281df930be7Sderaadt else if (res > 0 && numdirpasses == 2) 282df930be7Sderaadt numdirpasses++; 283df930be7Sderaadt #endif 284df930be7Sderaadt } 285df930be7Sderaadt break; 286df930be7Sderaadt case ISO_FTYPE_RRIP: 287df930be7Sderaadt if (isonum_711(ep->flags)&2) 288df930be7Sderaadt ino = isodirino(ep, imp); 289df930be7Sderaadt else 290df930be7Sderaadt ino = dbtob(bp->b_blkno) + entryoffsetinblock; 291df930be7Sderaadt dp->i_ino = ino; 292*8f6e076eSmickey MALLOC(altname, char *, NAME_MAX, M_TEMP, M_WAITOK); 293df930be7Sderaadt cd9660_rrip_getname(ep,altname,&namelen,&dp->i_ino,imp); 294df930be7Sderaadt if (namelen == cnp->cn_namelen 295*8f6e076eSmickey && !bcmp(name,altname,namelen)) { 296*8f6e076eSmickey FREE(altname, M_TEMP); 297df930be7Sderaadt goto found; 298*8f6e076eSmickey } 299*8f6e076eSmickey FREE(altname, M_TEMP); 300df930be7Sderaadt ino = 0; 301df930be7Sderaadt break; 302df930be7Sderaadt } 303df930be7Sderaadt dp->i_offset += reclen; 304df930be7Sderaadt entryoffsetinblock += reclen; 305df930be7Sderaadt } 306df930be7Sderaadt if (ino) { 307df930be7Sderaadt foundino: 308df930be7Sderaadt dp->i_ino = ino; 309df930be7Sderaadt if (saveoffset != dp->i_offset) { 310df930be7Sderaadt if (lblkno(imp, dp->i_offset) != 311df930be7Sderaadt lblkno(imp, saveoffset)) { 312df930be7Sderaadt if (bp != NULL) 313df930be7Sderaadt brelse(bp); 314574066a2Scsapuntz if ((error = cd9660_bufatoff(dp, 3159d71829cSniklas (off_t)saveoffset, NULL, &bp)) != 0) 316df930be7Sderaadt return (error); 317df930be7Sderaadt } 318df930be7Sderaadt entryoffsetinblock = saveoffset & bmask; 319df930be7Sderaadt ep = (struct iso_directory_record *) 320df930be7Sderaadt ((char *)bp->b_data + entryoffsetinblock); 321df930be7Sderaadt dp->i_offset = saveoffset; 322df930be7Sderaadt } 323df930be7Sderaadt goto found; 324df930be7Sderaadt } 325df930be7Sderaadt notfound: 326df930be7Sderaadt /* 327df930be7Sderaadt * If we started in the middle of the directory and failed 328df930be7Sderaadt * to find our target, we must check the beginning as well. 329df930be7Sderaadt */ 330df930be7Sderaadt if (numdirpasses == 2) { 331df930be7Sderaadt numdirpasses--; 332df930be7Sderaadt dp->i_offset = 0; 333df930be7Sderaadt endsearch = dp->i_diroff; 334df930be7Sderaadt goto searchloop; 335df930be7Sderaadt } 336df930be7Sderaadt if (bp != NULL) 337df930be7Sderaadt brelse(bp); 338df930be7Sderaadt 339df930be7Sderaadt /* 340df930be7Sderaadt * Insert name into cache (as non-existent) if appropriate. 341df930be7Sderaadt */ 342df930be7Sderaadt if (cnp->cn_flags & MAKEENTRY) 343df930be7Sderaadt cache_enter(vdp, *vpp, cnp); 344df930be7Sderaadt if (nameiop == CREATE || nameiop == RENAME) 345df930be7Sderaadt return (EJUSTRETURN); 346df930be7Sderaadt return (ENOENT); 347df930be7Sderaadt 348df930be7Sderaadt found: 349df930be7Sderaadt if (numdirpasses == 2) 350df930be7Sderaadt iso_nchstats.ncs_pass2++; 351df930be7Sderaadt 352df930be7Sderaadt /* 353df930be7Sderaadt * Found component in pathname. 354df930be7Sderaadt * If the final component of path name, save information 355df930be7Sderaadt * in the cache as to where the entry was found. 356df930be7Sderaadt */ 357df930be7Sderaadt if ((flags & ISLASTCN) && nameiop == LOOKUP) 358df930be7Sderaadt dp->i_diroff = dp->i_offset; 359df930be7Sderaadt 360df930be7Sderaadt /* 361df930be7Sderaadt * Step through the translation in the name. We do not `iput' the 362df930be7Sderaadt * directory because we may need it again if a symbolic link 363df930be7Sderaadt * is relative to the current directory. Instead we save it 364df930be7Sderaadt * unlocked as "pdp". We must get the target inode before unlocking 365df930be7Sderaadt * the directory to insure that the inode will not be removed 366df930be7Sderaadt * before we get it. We prevent deadlock by always fetching 367df930be7Sderaadt * inodes from the root, moving down the directory tree. Thus 368df930be7Sderaadt * when following backward pointers ".." we must unlock the 369df930be7Sderaadt * parent directory before getting the requested directory. 370df930be7Sderaadt * There is a potential race condition here if both the current 371df930be7Sderaadt * and parent directories are removed before the `iget' for the 372df930be7Sderaadt * inode associated with ".." returns. We hope that this occurs 373df930be7Sderaadt * infrequently since we cannot avoid this race condition without 374df930be7Sderaadt * implementing a sophisticated deadlock detection algorithm. 375df930be7Sderaadt * Note also that this simple deadlock detection scheme will not 376df930be7Sderaadt * work if the file system has any hard links other than ".." 377df930be7Sderaadt * that point backwards in the directory structure. 378df930be7Sderaadt */ 379df930be7Sderaadt pdp = vdp; 380df930be7Sderaadt /* 381df930be7Sderaadt * If ino is different from dp->i_ino, 382df930be7Sderaadt * it's a relocated directory. 383df930be7Sderaadt */ 384df930be7Sderaadt if (flags & ISDOTDOT) { 38512e8170cScsapuntz brelse(bp); 38607feb63cScsapuntz VOP_UNLOCK(pdp, 0, p); /* race to get the inode */ 38709308f32Sart cnp->cn_flags |= PDIRUNLOCK; 388df930be7Sderaadt error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp, 38912e8170cScsapuntz dp->i_ino != ino, NULL); 390df930be7Sderaadt if (error) { 39109308f32Sart if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0) 39209308f32Sart cnp->cn_flags &= ~PDIRUNLOCK; 393df930be7Sderaadt return (error); 394df930be7Sderaadt } 39509308f32Sart if (lockparent && (flags & ISLASTCN)) { 39609308f32Sart if ((error = vn_lock(pdp, LK_EXCLUSIVE, p))) { 397df930be7Sderaadt vput(tdp); 398df930be7Sderaadt return (error); 399df930be7Sderaadt } 40009308f32Sart cnp->cn_flags &= ~PDIRUNLOCK; 40109308f32Sart } 402df930be7Sderaadt *vpp = tdp; 403df930be7Sderaadt } else if (dp->i_number == dp->i_ino) { 404df930be7Sderaadt brelse(bp); 405df930be7Sderaadt VREF(vdp); /* we want ourself, ie "." */ 406df930be7Sderaadt *vpp = vdp; 407df930be7Sderaadt } else { 408df930be7Sderaadt error = cd9660_vget_internal(vdp->v_mount, dp->i_ino, &tdp, 409df930be7Sderaadt dp->i_ino != ino, ep); 410df930be7Sderaadt brelse(bp); 411df930be7Sderaadt if (error) 412df930be7Sderaadt return (error); 41309308f32Sart if (!lockparent || !(flags & ISLASTCN)) { 41407feb63cScsapuntz VOP_UNLOCK(pdp, 0, p); 41509308f32Sart cnp->cn_flags |= PDIRUNLOCK; 41609308f32Sart } 417df930be7Sderaadt *vpp = tdp; 418df930be7Sderaadt } 419df930be7Sderaadt 420df930be7Sderaadt /* 421df930be7Sderaadt * Insert name into cache if appropriate. 422df930be7Sderaadt */ 423df930be7Sderaadt if (cnp->cn_flags & MAKEENTRY) 424df930be7Sderaadt cache_enter(vdp, *vpp, cnp); 425df930be7Sderaadt return (0); 426df930be7Sderaadt } 427df930be7Sderaadt 428df930be7Sderaadt /* 429df930be7Sderaadt * Return buffer with the contents of block "offset" from the beginning of 430df930be7Sderaadt * directory "ip". If "res" is non-zero, fill it in with a pointer to the 431df930be7Sderaadt * remaining space in the directory. 432df930be7Sderaadt */ 433df930be7Sderaadt int 434574066a2Scsapuntz cd9660_bufatoff(struct iso_node *ip, off_t offset, char **res, 435574066a2Scsapuntz struct buf **bpp) 4369d71829cSniklas { 437574066a2Scsapuntz struct iso_mnt *imp; 438df930be7Sderaadt struct buf *bp; 439df930be7Sderaadt daddr_t lbn; 440df930be7Sderaadt int bsize, error; 441574066a2Scsapuntz struct vnode *vp = ITOV(ip); 442df930be7Sderaadt 443df930be7Sderaadt imp = ip->i_mnt; 444574066a2Scsapuntz lbn = lblkno(imp, offset); 445df930be7Sderaadt bsize = blksize(imp, ip, lbn); 446df930be7Sderaadt 447574066a2Scsapuntz if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) { 448df930be7Sderaadt brelse(bp); 449574066a2Scsapuntz *bpp = NULL; 450df930be7Sderaadt return (error); 451df930be7Sderaadt } 452574066a2Scsapuntz if (res) 453574066a2Scsapuntz *res = (char *)bp->b_data + blkoff(imp, offset); 454574066a2Scsapuntz *bpp = bp; 455df930be7Sderaadt return (0); 456df930be7Sderaadt } 457