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