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