1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Directory operations for High Sierra filesystem 31 */ 32 33 #include <sys/types.h> 34 #include <sys/t_lock.h> 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/cred.h> 38 #include <sys/user.h> 39 #include <sys/vfs.h> 40 #include <sys/stat.h> 41 #include <sys/vnode.h> 42 #include <sys/mode.h> 43 #include <sys/dnlc.h> 44 #include <sys/cmn_err.h> 45 #include <sys/fbuf.h> 46 #include <sys/kmem.h> 47 #include <sys/policy.h> 48 #include <sys/sunddi.h> 49 #include <vm/hat.h> 50 #include <vm/as.h> 51 #include <vm/pvn.h> 52 #include <vm/seg.h> 53 #include <vm/seg_map.h> 54 #include <vm/seg_kmem.h> 55 #include <vm/page.h> 56 57 #include <sys/fs/hsfs_spec.h> 58 #include <sys/fs/hsfs_isospec.h> 59 #include <sys/fs/hsfs_node.h> 60 #include <sys/fs/hsfs_impl.h> 61 #include <sys/fs/hsfs_susp.h> 62 #include <sys/fs/hsfs_rrip.h> 63 64 #include <sys/sysinfo.h> 65 #include <sys/sysmacros.h> 66 #include <sys/errno.h> 67 #include <sys/debug.h> 68 #include <fs/fs_subr.h> 69 70 /* 71 * This macro expects a name that ends in '.' and returns TRUE if the 72 * name is not "." or ".." 73 */ 74 #define CAN_TRUNCATE_DOT(name, namelen) \ 75 (namelen > 1 && (namelen > 2 || name[0] != '.')) 76 77 enum dirblock_result { FOUND_ENTRY, WENT_PAST, HIT_END }; 78 79 /* 80 * These values determine whether we will try to read a file or dir; 81 * they may be patched via /etc/system to allow users to read 82 * record-oriented files. 83 */ 84 int ide_prohibited = IDE_PROHIBITED; 85 int hde_prohibited = HDE_PROHIBITED; 86 87 /* 88 * This variable determines if the HSFS code will use the 89 * directory name lookup cache. The default is for the cache to be used. 90 */ 91 static int hsfs_use_dnlc = 1; 92 93 /* 94 * This variable determines whether strict ISO-9660 directory ordering 95 * is to be assumed. If false (which it is by default), then when 96 * searching a directory of an ISO-9660 disk, we do not expect the 97 * entries to be sorted (as the spec requires), and so cannot terminate 98 * the search early. Unfortunately, some vendors are producing 99 * non-compliant disks. This variable exists to revert to the old 100 * behavior in case someone relies on this. This option is expected to be 101 * removed at some point in the future. 102 * 103 * Use "set hsfs:strict_iso9660_ordering = 1" in /etc/system to override. 104 */ 105 static int strict_iso9660_ordering = 0; 106 107 static void hs_hsnode_cache_reclaim(void *unused); 108 static void hs_addfreeb(struct hsfs *fsp, struct hsnode *hp); 109 static int nmcmp(char *a, char *b, int len, int is_rrip); 110 static enum dirblock_result process_dirblock(struct fbuf *fbp, uint_t *offset, 111 uint_t last_offset, char *nm, int nmlen, struct hsfs *fsp, 112 struct hsnode *dhp, struct vnode *dvp, struct vnode **vpp, 113 int *error, int is_rrip); 114 static int strip_trailing(struct hsfs *fsp, char *nm, int len); 115 static int uppercase_cp(char *from, char *to, int size); 116 117 /* 118 * hs_access 119 * Return 0 if the desired access may be granted. 120 * Otherwise return error code. 121 */ 122 int 123 hs_access(struct vnode *vp, mode_t m, struct cred *cred) 124 { 125 struct hsnode *hp; 126 int shift = 0; 127 128 /* 129 * Write access cannot be granted for a read-only medium 130 */ 131 if ((m & VWRITE) && !IS_DEVVP(vp)) 132 return (EROFS); 133 134 hp = VTOH(vp); 135 136 /* 137 * XXX - For now, use volume protections. 138 * Also, always grant EXEC access for directories 139 * if READ access is granted. 140 */ 141 if ((vp->v_type == VDIR) && (m & VEXEC)) { 142 m &= ~VEXEC; 143 m |= VREAD; 144 } 145 146 if (crgetuid(cred) != hp->hs_dirent.uid) { 147 shift += 3; 148 if (!groupmember((uid_t)hp->hs_dirent.gid, cred)) 149 shift += 3; 150 } 151 m &= ~(hp->hs_dirent.mode << shift); 152 if (m != 0) 153 return (secpolicy_vnode_access(cred, vp, hp->hs_dirent.uid, m)); 154 return (0); 155 } 156 157 #if ((HS_HASHSIZE & (HS_HASHSIZE - 1)) == 0) 158 #define HS_HASH(l) ((uint_t)(l) & (HS_HASHSIZE - 1)) 159 #else 160 #define HS_HASH(l) ((uint_t)(l) % HS_HASHSIZE) 161 #endif 162 #define HS_HPASH(hp) HS_HASH((hp)->hs_nodeid) 163 164 /* 165 * The tunable nhsnode is now a threshold for a dynamically allocated 166 * pool of hsnodes, not the size of a statically allocated table. 167 * When the number of hsnodes for a particular file system exceeds 168 * nhsnode, the allocate and free logic will try to reduce the number 169 * of allocated nodes by returning unreferenced nodes to the kmem_cache 170 * instead of putting them on the file system's private free list. 171 */ 172 int nhsnode = HS_HSNODESPACE / sizeof (struct hsnode); 173 174 struct kmem_cache *hsnode_cache; /* free hsnode cache */ 175 176 /* 177 * Initialize the cache of free hsnodes. 178 */ 179 void 180 hs_init_hsnode_cache(void) 181 { 182 /* 183 * A kmem_cache is used for the hsnodes 184 * No constructor because hsnodes are initialised by bzeroing. 185 */ 186 hsnode_cache = kmem_cache_create("hsfs_hsnode_cache", 187 sizeof (struct hsnode), 0, NULL, 188 NULL, hs_hsnode_cache_reclaim, NULL, NULL, 0); 189 } 190 191 /* 192 * System is short on memory, free up as much as possible 193 */ 194 /*ARGSUSED*/ 195 static void 196 hs_hsnode_cache_reclaim(void *unused) 197 { 198 struct hsfs *fsp; 199 struct hsnode *hp; 200 201 /* 202 * For each vfs in the hs_mounttab list 203 */ 204 mutex_enter(&hs_mounttab_lock); 205 for (fsp = hs_mounttab; fsp != NULL; fsp = fsp->hsfs_next) { 206 /* 207 * Purge the dnlc of all hsfs entries 208 */ 209 (void) dnlc_purge_vfsp(fsp->hsfs_vfs, 0); 210 211 /* 212 * For each entry in the free chain 213 */ 214 rw_enter(&fsp->hsfs_hash_lock, RW_WRITER); 215 mutex_enter(&fsp->hsfs_free_lock); 216 for (hp = fsp->hsfs_free_f; hp != NULL; hp = fsp->hsfs_free_f) { 217 /* 218 * Remove from chain 219 */ 220 fsp->hsfs_free_f = hp->hs_freef; 221 if (fsp->hsfs_free_f != NULL) { 222 fsp->hsfs_free_f->hs_freeb = NULL; 223 } else { 224 fsp->hsfs_free_b = NULL; 225 } 226 /* 227 * Free the node. Force it to be fully freed 228 * by setting the 3rd arg (nopage) to 1. 229 */ 230 hs_freenode(HTOV(hp), fsp, 1); 231 } 232 mutex_exit(&fsp->hsfs_free_lock); 233 rw_exit(&fsp->hsfs_hash_lock); 234 } 235 mutex_exit(&hs_mounttab_lock); 236 } 237 238 /* 239 * Add an hsnode to the end of the free list. 240 */ 241 static void 242 hs_addfreeb(struct hsfs *fsp, struct hsnode *hp) 243 { 244 struct hsnode *ep; 245 246 vn_invalid(HTOV(hp)); 247 mutex_enter(&fsp->hsfs_free_lock); 248 ep = fsp->hsfs_free_b; 249 fsp->hsfs_free_b = hp; /* hp is the last entry in free list */ 250 hp->hs_freef = NULL; 251 hp->hs_freeb = ep; /* point at previous last entry */ 252 if (ep == NULL) 253 fsp->hsfs_free_f = hp; /* hp is only entry in free list */ 254 else 255 ep->hs_freef = hp; /* point previous last entry at hp */ 256 257 mutex_exit(&fsp->hsfs_free_lock); 258 } 259 260 /* 261 * Get an hsnode from the front of the free list. 262 * Must be called with write hsfs_hash_lock held. 263 */ 264 static struct hsnode * 265 hs_getfree(struct hsfs *fsp) 266 { 267 struct hsnode *hp, **tp; 268 269 ASSERT(RW_WRITE_HELD(&fsp->hsfs_hash_lock)); 270 271 /* 272 * If the number of currently-allocated hsnodes is less than 273 * the hsnode count threshold (nhsnode), or if there are no 274 * nodes on the file system's local free list (which acts as a 275 * cache), call kmem_cache_alloc to get a new hsnode from 276 * kernel memory. 277 */ 278 mutex_enter(&fsp->hsfs_free_lock); 279 if ((fsp->hsfs_nohsnode < nhsnode) || (fsp->hsfs_free_f == NULL)) { 280 mutex_exit(&fsp->hsfs_free_lock); 281 hp = kmem_cache_alloc(hsnode_cache, KM_SLEEP); 282 fsp->hsfs_nohsnode++; 283 bzero((caddr_t)hp, sizeof (*hp)); 284 hp->hs_vnode = vn_alloc(KM_SLEEP); 285 return (hp); 286 } 287 hp = fsp->hsfs_free_f; 288 /* hp cannot be NULL, since we already checked this above */ 289 fsp->hsfs_free_f = hp->hs_freef; 290 if (fsp->hsfs_free_f != NULL) 291 fsp->hsfs_free_f->hs_freeb = NULL; 292 else 293 fsp->hsfs_free_b = NULL; 294 mutex_exit(&fsp->hsfs_free_lock); 295 296 for (tp = &fsp->hsfs_hash[HS_HPASH(hp)]; *tp != NULL; 297 tp = &(*tp)->hs_hash) { 298 if (*tp == hp) { 299 struct vnode *vp; 300 301 vp = HTOV(hp); 302 303 /* 304 * file is no longer referenced, destroy all old pages 305 */ 306 if (vn_has_cached_data(vp)) 307 /* 308 * pvn_vplist_dirty will abort all old pages 309 */ 310 (void) pvn_vplist_dirty(vp, (u_offset_t)0, 311 hsfs_putapage, B_INVAL, (struct cred *)NULL); 312 *tp = hp->hs_hash; 313 break; 314 } 315 } 316 if (hp->hs_dirent.sym_link != (char *)NULL) { 317 kmem_free(hp->hs_dirent.sym_link, 318 (size_t)(hp->hs_dirent.ext_size + 1)); 319 } 320 321 mutex_destroy(&hp->hs_contents_lock); 322 { 323 vnode_t *vp; 324 325 vp = hp->hs_vnode; 326 bzero((caddr_t)hp, sizeof (*hp)); 327 hp->hs_vnode = vp; 328 vn_reinit(vp); 329 } 330 return (hp); 331 } 332 333 /* 334 * Remove an hsnode from the free list. 335 */ 336 static void 337 hs_remfree(struct hsfs *fsp, struct hsnode *hp) 338 { 339 mutex_enter(&fsp->hsfs_free_lock); 340 if (hp->hs_freef != NULL) 341 hp->hs_freef->hs_freeb = hp->hs_freeb; 342 else 343 fsp->hsfs_free_b = hp->hs_freeb; 344 if (hp->hs_freeb != NULL) 345 hp->hs_freeb->hs_freef = hp->hs_freef; 346 else 347 fsp->hsfs_free_f = hp->hs_freef; 348 mutex_exit(&fsp->hsfs_free_lock); 349 } 350 351 /* 352 * Look for hsnode in hash list. 353 * Check equality of fsid and nodeid. 354 * If found, reactivate it if inactive. 355 * Must be entered with hsfs_hash_lock held. 356 */ 357 struct vnode * 358 hs_findhash(ino64_t nodeid, struct vfs *vfsp) 359 { 360 struct hsnode *tp; 361 struct hsfs *fsp; 362 363 fsp = VFS_TO_HSFS(vfsp); 364 365 ASSERT(RW_LOCK_HELD(&fsp->hsfs_hash_lock)); 366 367 for (tp = fsp->hsfs_hash[HS_HASH(nodeid)]; tp != NULL; 368 tp = tp->hs_hash) { 369 if (tp->hs_nodeid == nodeid) { 370 struct vnode *vp; 371 372 mutex_enter(&tp->hs_contents_lock); 373 vp = HTOV(tp); 374 VN_HOLD(vp); 375 if ((tp->hs_flags & HREF) == 0) { 376 tp->hs_flags |= HREF; 377 /* 378 * reactivating a free hsnode: 379 * remove from free list 380 */ 381 hs_remfree(fsp, tp); 382 } 383 mutex_exit(&tp->hs_contents_lock); 384 return (vp); 385 } 386 } 387 return (NULL); 388 } 389 390 static void 391 hs_addhash(struct hsfs *fsp, struct hsnode *hp) 392 { 393 ulong_t hashno; 394 395 ASSERT(RW_WRITE_HELD(&fsp->hsfs_hash_lock)); 396 397 hashno = HS_HPASH(hp); 398 hp->hs_hash = fsp->hsfs_hash[hashno]; 399 fsp->hsfs_hash[hashno] = hp; 400 } 401 402 /* 403 * Destroy all old pages and free the hsnodes 404 * Return 1 if busy (a hsnode is still referenced). 405 */ 406 int 407 hs_synchash(struct vfs *vfsp) 408 { 409 struct hsfs *fsp; 410 int i; 411 struct hsnode *hp, *nhp; 412 int busy = 0; 413 struct vnode *vp, *rvp; 414 415 fsp = VFS_TO_HSFS(vfsp); 416 rvp = fsp->hsfs_rootvp; 417 /* make sure no one can come in */ 418 rw_enter(&fsp->hsfs_hash_lock, RW_WRITER); 419 for (i = 0; i < HS_HASHSIZE; i++) { 420 for (hp = fsp->hsfs_hash[i]; hp != NULL; hp = hp->hs_hash) { 421 vp = HTOV(hp); 422 if ((hp->hs_flags & HREF) && (vp != rvp || 423 (vp == rvp && vp->v_count > 1))) { 424 busy = 1; 425 continue; 426 } 427 if (vn_has_cached_data(vp)) 428 (void) pvn_vplist_dirty(vp, (u_offset_t)0, 429 hsfs_putapage, B_INVAL, (struct cred *)NULL); 430 } 431 } 432 if (busy) { 433 rw_exit(&fsp->hsfs_hash_lock); 434 return (1); 435 } 436 437 /* now free the hsnodes */ 438 for (i = 0; i < HS_HASHSIZE; i++) { 439 for (hp = fsp->hsfs_hash[i]; hp != NULL; hp = nhp) { 440 nhp = hp->hs_hash; 441 /* 442 * We know there are no pages associated with 443 * all the hsnodes (they've all been released 444 * above). So remove from free list and 445 * free the entry with nopage set. 446 */ 447 vp = HTOV(hp); 448 if (vp != rvp) { 449 hs_remfree(fsp, hp); 450 hs_freenode(vp, fsp, 1); 451 } 452 } 453 } 454 455 ASSERT(fsp->hsfs_nohsnode == 1); 456 rw_exit(&fsp->hsfs_hash_lock); 457 /* release the root hsnode, this should free the final hsnode */ 458 VN_RELE(rvp); 459 460 return (0); 461 } 462 463 /* 464 * hs_makenode 465 * 466 * Construct an hsnode. 467 * Caller specifies the directory entry, the block number and offset 468 * of the directory entry, and the vfs pointer. 469 * note: off is the sector offset, not lbn offset 470 * if NULL is returned implies file system hsnode table full 471 */ 472 struct vnode * 473 hs_makenode( 474 struct hs_direntry *dp, 475 uint_t lbn, 476 uint_t off, 477 struct vfs *vfsp) 478 { 479 struct hsnode *hp; 480 struct vnode *vp; 481 struct hs_volume *hvp; 482 struct vnode *newvp; 483 struct hsfs *fsp; 484 ino64_t nodeid; 485 486 fsp = VFS_TO_HSFS(vfsp); 487 488 /* 489 * Construct the nodeid: in the case of a directory 490 * entry, this should point to the canonical dirent, the "." 491 * directory entry for the directory. This dirent is pointed 492 * to by all directory entries for that dir (including the ".") 493 * entry itself. 494 * In the case of a file, simply point to the dirent for that 495 * file (there are no hard links in Rock Ridge, so there's no 496 * need to determine what the canonical dirent is. 497 */ 498 if (dp->type == VDIR) { 499 lbn = dp->ext_lbn; 500 off = 0; 501 } 502 503 /* 504 * Normalize lbn and off before creating a nodeid 505 * and before storing them in a hs_node structure 506 */ 507 hvp = &fsp->hsfs_vol; 508 lbn += off >> hvp->lbn_shift; 509 off &= hvp->lbn_maxoffset; 510 nodeid = (ino64_t)MAKE_NODEID(lbn, off, vfsp); 511 512 /* look for hsnode in cache first */ 513 514 rw_enter(&fsp->hsfs_hash_lock, RW_READER); 515 516 if ((vp = hs_findhash(nodeid, vfsp)) == NULL) { 517 518 /* 519 * Not in cache. However, someone else may have come 520 * to the same conclusion and just put one in. Upgrade 521 * our lock to a write lock and look again. 522 */ 523 rw_exit(&fsp->hsfs_hash_lock); 524 rw_enter(&fsp->hsfs_hash_lock, RW_WRITER); 525 526 if ((vp = hs_findhash(nodeid, vfsp)) == NULL) { 527 /* 528 * Now we are really sure that the hsnode is not 529 * in the cache. Get one off freelist or else 530 * allocate one. Either way get a bzeroed hsnode. 531 */ 532 hp = hs_getfree(fsp); 533 534 bcopy((caddr_t)dp, (caddr_t)&hp->hs_dirent, 535 sizeof (*dp)); 536 /* 537 * We've just copied this pointer into hs_dirent, 538 * and don't want 2 references to same symlink. 539 */ 540 dp->sym_link = (char *)NULL; 541 542 /* 543 * No need to hold any lock because hsnode is not 544 * yet in the hash chain. 545 */ 546 mutex_init(&hp->hs_contents_lock, NULL, MUTEX_DEFAULT, 547 NULL); 548 hp->hs_dir_lbn = lbn; 549 hp->hs_dir_off = off; 550 hp->hs_nodeid = nodeid; 551 hp->hs_seq = 0; 552 hp->hs_flags = HREF; 553 if (off > HS_SECTOR_SIZE) 554 cmn_err(CE_WARN, "hs_makenode: bad offset"); 555 556 vp = HTOV(hp); 557 vp->v_vfsp = vfsp; 558 vp->v_type = dp->type; 559 vp->v_rdev = dp->r_dev; 560 vn_setops(vp, hsfs_vnodeops); 561 vp->v_data = (caddr_t)hp; 562 vn_exists(vp); 563 /* 564 * if it's a device, call specvp 565 */ 566 if (IS_DEVVP(vp)) { 567 rw_exit(&fsp->hsfs_hash_lock); 568 newvp = specvp(vp, vp->v_rdev, vp->v_type, 569 CRED()); 570 if (newvp == NULL) 571 cmn_err(CE_NOTE, 572 "hs_makenode: specvp failed"); 573 VN_RELE(vp); 574 return (newvp); 575 } 576 577 hs_addhash(fsp, hp); 578 579 } 580 } 581 582 if (dp->sym_link != (char *)NULL) { 583 kmem_free(dp->sym_link, (size_t)(dp->ext_size + 1)); 584 dp->sym_link = (char *)NULL; 585 } 586 587 rw_exit(&fsp->hsfs_hash_lock); 588 return (vp); 589 } 590 591 /* 592 * hs_freenode 593 * 594 * Deactivate an hsnode. 595 * Leave it on the hash list but put it on the free list. 596 * If the vnode does not have any pages, release the hsnode to the 597 * kmem_cache using kmem_cache_free, else put in back of the free list. 598 * 599 * This function can be called with the hsfs_free_lock held, but only 600 * when the code is guaranteed to go through the path where the 601 * node is freed entirely, and not the path where the node could go back 602 * on the free list (and where the free lock would need to be acquired). 603 */ 604 void 605 hs_freenode(vnode_t *vp, struct hsfs *fsp, int nopage) 606 { 607 struct hsnode **tp; 608 struct hsnode *hp = VTOH(vp); 609 610 ASSERT(RW_LOCK_HELD(&fsp->hsfs_hash_lock)); 611 612 if (nopage || (fsp->hsfs_nohsnode >= nhsnode)) { 613 /* remove this node from the hash list, if it's there */ 614 for (tp = &fsp->hsfs_hash[HS_HPASH(hp)]; *tp != NULL; 615 tp = &(*tp)->hs_hash) { 616 617 if (*tp == hp) { 618 *tp = hp->hs_hash; 619 break; 620 } 621 } 622 623 if (hp->hs_dirent.sym_link != (char *)NULL) { 624 kmem_free(hp->hs_dirent.sym_link, 625 (size_t)(hp->hs_dirent.ext_size + 1)); 626 hp->hs_dirent.sym_link = NULL; 627 } 628 if (vn_has_cached_data(vp)) { 629 /* clean all old pages */ 630 (void) pvn_vplist_dirty(vp, (u_offset_t)0, 631 hsfs_putapage, B_INVAL, (struct cred *)NULL); 632 /* XXX - can we remove pages by fiat like this??? */ 633 vp->v_pages = NULL; 634 } 635 mutex_destroy(&hp->hs_contents_lock); 636 vn_invalid(vp); 637 vn_free(vp); 638 kmem_cache_free(hsnode_cache, hp); 639 fsp->hsfs_nohsnode--; 640 return; 641 } 642 hs_addfreeb(fsp, hp); /* add to back of free list */ 643 } 644 645 /* 646 * hs_remakenode 647 * 648 * Reconstruct a vnode given the location of its directory entry. 649 * Caller specifies the the block number and offset 650 * of the directory entry, and the vfs pointer. 651 * Returns an error code or 0. 652 */ 653 int 654 hs_remakenode(uint_t lbn, uint_t off, struct vfs *vfsp, 655 struct vnode **vpp) 656 { 657 struct buf *secbp; 658 struct hsfs *fsp; 659 uint_t secno; 660 uchar_t *dirp; 661 struct hs_direntry hd; 662 int error; 663 664 /* Convert to sector and offset */ 665 fsp = VFS_TO_HSFS(vfsp); 666 if (off > HS_SECTOR_SIZE) { 667 cmn_err(CE_WARN, "hs_remakenode: bad offset"); 668 error = EINVAL; 669 goto end; 670 } 671 secno = LBN_TO_SEC(lbn, vfsp); 672 secbp = bread(fsp->hsfs_devvp->v_rdev, secno * 4, HS_SECTOR_SIZE); 673 674 error = geterror(secbp); 675 if (error != 0) { 676 cmn_err(CE_NOTE, "hs_remakenode: bread: error=(%d)", error); 677 goto end; 678 } 679 680 dirp = (uchar_t *)secbp->b_un.b_addr; 681 error = hs_parsedir(fsp, &dirp[off], &hd, (char *)NULL, (int *)NULL); 682 if (!error) { 683 *vpp = hs_makenode(&hd, lbn, off, vfsp); 684 if (*vpp == NULL) 685 error = ENFILE; 686 } 687 688 end: 689 brelse(secbp); 690 return (error); 691 } 692 693 694 /* 695 * hs_dirlook 696 * 697 * Look for a given name in a given directory. 698 * If found, construct an hsnode for it. 699 */ 700 int 701 hs_dirlook( 702 struct vnode *dvp, 703 char *name, 704 int namlen, /* length of 'name' */ 705 struct vnode **vpp, 706 struct cred *cred) 707 { 708 struct hsnode *dhp; 709 struct hsfs *fsp; 710 int error = 0; 711 uint_t offset; /* real offset in directory */ 712 uint_t last_offset; /* last index into current dir block */ 713 char *cmpname; /* case-folded name */ 714 int cmpname_size; /* how much memory we allocate for it */ 715 int cmpnamelen; 716 int adhoc_search; /* did we start at begin of dir? */ 717 int end; 718 uint_t hsoffset; 719 struct fbuf *fbp; 720 int bytes_wanted; 721 int dirsiz; 722 int is_rrip; 723 724 if (dvp->v_type != VDIR) 725 return (ENOTDIR); 726 727 if (error = hs_access(dvp, (mode_t)VEXEC, cred)) 728 return (error); 729 730 if (hsfs_use_dnlc && (*vpp = dnlc_lookup(dvp, name))) 731 return (0); 732 733 dhp = VTOH(dvp); 734 fsp = VFS_TO_HSFS(dvp->v_vfsp); 735 736 cmpname_size = (int)(fsp->hsfs_namemax + 1); 737 cmpname = kmem_alloc((size_t)cmpname_size, KM_SLEEP); 738 739 is_rrip = IS_RRIP_IMPLEMENTED(fsp); 740 741 if (namlen >= cmpname_size) 742 namlen = cmpname_size - 1; 743 /* 744 * For the purposes of comparing the name against dir entries, 745 * fold it to upper case. 746 */ 747 if (is_rrip) { 748 (void) strlcpy(cmpname, name, cmpname_size); 749 cmpnamelen = namlen; 750 } else { 751 /* 752 * If we don't consider a trailing dot as part of the filename, 753 * remove it from the specified name 754 */ 755 if ((fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) && 756 name[namlen-1] == '.' && 757 CAN_TRUNCATE_DOT(name, namlen)) 758 name[--namlen] = '\0'; 759 cmpnamelen = hs_uppercase_copy(name, cmpname, namlen); 760 } 761 762 /* make sure dirent is filled up with all info */ 763 if (dhp->hs_dirent.ext_size == 0) 764 hs_filldirent(dvp, &dhp->hs_dirent); 765 766 /* 767 * No lock is needed - hs_offset is used as starting 768 * point for searching the directory. 769 */ 770 offset = dhp->hs_offset; 771 hsoffset = offset; 772 adhoc_search = (offset != 0); 773 774 end = dhp->hs_dirent.ext_size; 775 dirsiz = end; 776 777 tryagain: 778 779 while (offset < end) { 780 bytes_wanted = MIN(MAXBSIZE, dirsiz - (offset & MAXBMASK)); 781 782 error = fbread(dvp, (offset_t)(offset & MAXBMASK), 783 (unsigned int)bytes_wanted, S_READ, &fbp); 784 if (error) 785 goto done; 786 787 last_offset = (offset & MAXBMASK) + fbp->fb_count; 788 789 switch (process_dirblock(fbp, &offset, last_offset, 790 cmpname, cmpnamelen, fsp, dhp, dvp, vpp, &error, 791 is_rrip)) { 792 case FOUND_ENTRY: 793 /* found an entry, either correct or not */ 794 goto done; 795 796 case WENT_PAST: 797 /* 798 * If we get here we know we didn't find it on the 799 * first pass. If adhoc_search, then we started a 800 * bit into the dir, and need to wrap around and 801 * search the first entries. If not, then we started 802 * at the beginning and didn't find it. 803 */ 804 if (adhoc_search) { 805 offset = 0; 806 end = hsoffset; 807 adhoc_search = 0; 808 goto tryagain; 809 } 810 error = ENOENT; 811 goto done; 812 813 case HIT_END: 814 goto tryagain; 815 } 816 } 817 /* 818 * End of all dir blocks, didn't find entry. 819 */ 820 if (adhoc_search) { 821 offset = 0; 822 end = hsoffset; 823 adhoc_search = 0; 824 goto tryagain; 825 } 826 error = ENOENT; 827 done: 828 /* 829 * If we found the entry, add it to the DNLC 830 * If the entry is a device file (assuming we support Rock Ridge), 831 * we enter the device vnode to the cache since that is what 832 * is in *vpp. 833 * That is ok since the CD-ROM is read-only, so (dvp,name) will 834 * always point to the same device. 835 */ 836 if (hsfs_use_dnlc && !error) 837 dnlc_enter(dvp, name, *vpp); 838 839 kmem_free(cmpname, (size_t)cmpname_size); 840 841 return (error); 842 } 843 844 /* 845 * hs_parsedir 846 * 847 * Parse a Directory Record into an hs_direntry structure. 848 * High Sierra and ISO directory are almost the same 849 * except the flag and date 850 */ 851 int 852 hs_parsedir( 853 struct hsfs *fsp, 854 uchar_t *dirp, 855 struct hs_direntry *hdp, 856 char *dnp, 857 int *dnlen) 858 { 859 char *on_disk_name; 860 int on_disk_namelen; 861 uchar_t flags; 862 int namelen; 863 int error; 864 int name_change_flag = 0; /* set if name was gotten in SUA */ 865 866 hdp->ext_lbn = HDE_EXT_LBN(dirp); 867 hdp->ext_size = HDE_EXT_SIZE(dirp); 868 hdp->xar_len = HDE_XAR_LEN(dirp); 869 hdp->intlf_sz = HDE_INTRLV_SIZE(dirp); 870 hdp->intlf_sk = HDE_INTRLV_SKIP(dirp); 871 hdp->sym_link = (char *)NULL; 872 873 if (fsp->hsfs_vol_type == HS_VOL_TYPE_HS) { 874 flags = HDE_FLAGS(dirp); 875 hs_parse_dirdate(HDE_cdate(dirp), &hdp->cdate); 876 hs_parse_dirdate(HDE_cdate(dirp), &hdp->adate); 877 hs_parse_dirdate(HDE_cdate(dirp), &hdp->mdate); 878 if ((flags & hde_prohibited) == 0) { 879 /* 880 * Skip files with the associated bit set. 881 */ 882 if (flags & HDE_ASSOCIATED) 883 return (EAGAIN); 884 hdp->type = VREG; 885 hdp->mode = HFREG; 886 hdp->nlink = 1; 887 } else if ((flags & hde_prohibited) == HDE_DIRECTORY) { 888 hdp->type = VDIR; 889 hdp->mode = HFDIR; 890 hdp->nlink = 2; 891 } else { 892 hs_log_bogus_disk_warning(fsp, 893 HSFS_ERR_UNSUP_TYPE, flags); 894 return (EINVAL); 895 } 896 hdp->uid = fsp -> hsfs_vol.vol_uid; 897 hdp->gid = fsp -> hsfs_vol.vol_gid; 898 hdp->mode = hdp-> mode | (fsp -> hsfs_vol.vol_prot & 0777); 899 } else if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO) { 900 flags = IDE_FLAGS(dirp); 901 hs_parse_dirdate(IDE_cdate(dirp), &hdp->cdate); 902 hs_parse_dirdate(IDE_cdate(dirp), &hdp->adate); 903 hs_parse_dirdate(IDE_cdate(dirp), &hdp->mdate); 904 905 if ((flags & ide_prohibited) == 0) { 906 /* 907 * Skip files with the associated bit set. 908 */ 909 if (flags & IDE_ASSOCIATED) 910 return (EAGAIN); 911 hdp->type = VREG; 912 hdp->mode = HFREG; 913 hdp->nlink = 1; 914 } else if ((flags & ide_prohibited) == IDE_DIRECTORY) { 915 hdp->type = VDIR; 916 hdp->mode = HFDIR; 917 hdp->nlink = 2; 918 } else { 919 hs_log_bogus_disk_warning(fsp, 920 HSFS_ERR_UNSUP_TYPE, flags); 921 return (EINVAL); 922 } 923 hdp->uid = fsp -> hsfs_vol.vol_uid; 924 hdp->gid = fsp -> hsfs_vol.vol_gid; 925 hdp->mode = hdp-> mode | (fsp -> hsfs_vol.vol_prot & 0777); 926 927 /* 928 * Having this all filled in, let's see if we have any 929 * SUA susp to look at. 930 */ 931 if (IS_SUSP_IMPLEMENTED(fsp)) { 932 error = parse_sua((uchar_t *)dnp, dnlen, 933 &name_change_flag, dirp, hdp, fsp, 934 (uchar_t *)NULL, NULL); 935 if (error) { 936 if (hdp->sym_link) { 937 kmem_free(hdp->sym_link, 938 (size_t)(hdp->ext_size + 1)); 939 hdp->sym_link = (char *)NULL; 940 } 941 return (error); 942 } 943 } 944 } 945 hdp->xar_prot = (HDE_PROTECTION & flags) != 0; 946 947 #if dontskip 948 if (hdp->xar_len > 0) { 949 cmn_err(CE_NOTE, "hsfs: extended attributes not supported"); 950 return (EINVAL); 951 } 952 #endif 953 954 /* check interleaf size and skip factor */ 955 /* must both be zero or non-zero */ 956 if (hdp->intlf_sz + hdp->intlf_sk) { 957 if ((hdp->intlf_sz == 0) || (hdp->intlf_sk == 0)) { 958 cmn_err(CE_NOTE, 959 "hsfs: interleaf size or skip factor error"); 960 return (EINVAL); 961 } 962 if (hdp->ext_size == 0) { 963 cmn_err(CE_NOTE, 964 "hsfs: interleaving specified on zero length file"); 965 return (EINVAL); 966 } 967 } 968 969 if (HDE_VOL_SET(dirp) != 1) { 970 if (fsp->hsfs_vol.vol_set_size != 1 && 971 fsp->hsfs_vol.vol_set_size != HDE_VOL_SET(dirp)) { 972 cmn_err(CE_NOTE, "hsfs: multivolume file?"); 973 return (EINVAL); 974 } 975 } 976 977 /* 978 * If the name changed, then the NM field for RRIP was hit and 979 * we should not copy the name again, just return. 980 */ 981 if (NAME_HAS_CHANGED(name_change_flag)) 982 return (0); 983 984 /* 985 * Fall back to the ISO name. Note that as in process_dirblock, 986 * the on-disk filename length must be validated against ISO 987 * limits - which, in case of RR present but no RR name found, 988 * are NOT identical to fsp->hsfs_namemax on this filesystem. 989 */ 990 on_disk_name = (char *)HDE_name(dirp); 991 on_disk_namelen = (int)HDE_NAME_LEN(dirp); 992 993 if (on_disk_namelen > ISO_FILE_NAMELEN) { 994 hs_log_bogus_disk_warning(fsp, HSFS_ERR_BAD_FILE_LEN, 0); 995 on_disk_namelen = ISO_FILE_NAMELEN; 996 } 997 if (dnp != NULL) { 998 namelen = hs_namecopy(on_disk_name, dnp, on_disk_namelen, 999 fsp->hsfs_flags); 1000 if ((fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) && 1001 dnp[ namelen-1 ] == '.' && CAN_TRUNCATE_DOT(dnp, namelen)) 1002 dnp[ --namelen ] = '\0'; 1003 } else 1004 namelen = on_disk_namelen; 1005 if (dnlen != NULL) 1006 *dnlen = namelen; 1007 1008 return (0); 1009 } 1010 1011 /* 1012 * hs_namecopy 1013 * 1014 * Parse a file/directory name into UNIX form. 1015 * Delete trailing blanks, upper-to-lower case, add NULL terminator. 1016 * Returns the (possibly new) length. 1017 */ 1018 int 1019 hs_namecopy(char *from, char *to, int size, ulong_t flags) 1020 { 1021 uint_t i; 1022 uchar_t c; 1023 int lastspace; 1024 int maplc; 1025 1026 /* special handling for '.' and '..' */ 1027 if (size == 1) { 1028 if (*from == '\0') { 1029 *to++ = '.'; 1030 *to = '\0'; 1031 return (1); 1032 } else if (*from == '\1') { 1033 *to++ = '.'; 1034 *to++ = '.'; 1035 *to = '\0'; 1036 return (2); 1037 } 1038 } 1039 1040 maplc = (flags & HSFSMNT_NOMAPLCASE) == 0; 1041 for (i = 0, lastspace = -1; i < size; i++) { 1042 c = from[i]; 1043 if (c == ';') 1044 break; 1045 if (c <= ' ') { 1046 if (lastspace == -1) 1047 lastspace = i; 1048 } else 1049 lastspace = -1; 1050 if (maplc && (c >= 'A') && (c <= 'Z')) 1051 c += 'a' - 'A'; 1052 to[i] = c; 1053 } 1054 if (lastspace != -1) 1055 i = lastspace; 1056 to[i] = '\0'; 1057 return (i); 1058 } 1059 1060 /* 1061 * map a filename to upper case; 1062 * return 1 if found lowercase character 1063 */ 1064 static int 1065 uppercase_cp(char *from, char *to, int size) 1066 { 1067 uint_t i; 1068 uchar_t c; 1069 uchar_t had_lc = 0; 1070 1071 for (i = 0; i < size; i++) { 1072 c = *from++; 1073 if ((c >= 'a') && (c <= 'z')) { 1074 c -= ('a' - 'A'); 1075 had_lc = 1; 1076 } 1077 *to++ = c; 1078 } 1079 return (had_lc); 1080 } 1081 1082 /* 1083 * hs_uppercase_copy 1084 * 1085 * Convert a UNIX-style name into its HSFS equivalent. 1086 * Map to upper case. 1087 * Returns the (possibly new) length. 1088 */ 1089 int 1090 hs_uppercase_copy(char *from, char *to, int size) 1091 { 1092 uint_t i; 1093 uchar_t c; 1094 1095 /* special handling for '.' and '..' */ 1096 1097 if (size == 1 && *from == '.') { 1098 *to = '\0'; 1099 return (1); 1100 } else if (size == 2 && *from == '.' && *(from+1) == '.') { 1101 *to = '\1'; 1102 return (1); 1103 } 1104 1105 for (i = 0; i < size; i++) { 1106 c = *from++; 1107 if ((c >= 'a') && (c <= 'z')) 1108 c = c - 'a' + 'A'; 1109 *to++ = c; 1110 } 1111 return (size); 1112 } 1113 1114 void 1115 hs_filldirent(struct vnode *vp, struct hs_direntry *hdp) 1116 { 1117 struct buf *secbp; 1118 uint_t secno; 1119 offset_t secoff; 1120 struct hsfs *fsp; 1121 uchar_t *secp; 1122 int error; 1123 1124 if (vp->v_type != VDIR) { 1125 cmn_err(CE_WARN, "hsfs_filldirent: vp (0x%p) not a directory", 1126 (void *)vp); 1127 return; 1128 } 1129 1130 fsp = VFS_TO_HSFS(vp ->v_vfsp); 1131 secno = LBN_TO_SEC(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp); 1132 secoff = LBN_TO_BYTE(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp) & 1133 MAXHSOFFSET; 1134 secbp = bread(fsp->hsfs_devvp->v_rdev, secno * 4, HS_SECTOR_SIZE); 1135 error = geterror(secbp); 1136 if (error != 0) { 1137 cmn_err(CE_NOTE, "hs_filldirent: bread: error=(%d)", error); 1138 goto end; 1139 } 1140 1141 secp = (uchar_t *)secbp->b_un.b_addr; 1142 1143 /* quick check */ 1144 if (hdp->ext_lbn != HDE_EXT_LBN(&secp[secoff])) { 1145 cmn_err(CE_NOTE, "hsfs_filldirent: dirent not match"); 1146 /* keep on going */ 1147 } 1148 (void) hs_parsedir(fsp, &secp[secoff], hdp, (char *)NULL, (int *)NULL); 1149 1150 end: 1151 brelse(secbp); 1152 } 1153 1154 /* 1155 * Look through a directory block for a matching entry. 1156 * Note: this routine does an fbrelse() on the buffer passed in. 1157 */ 1158 static enum dirblock_result 1159 process_dirblock( 1160 struct fbuf *fbp, /* buffer containing dirblk */ 1161 uint_t *offset, /* lower index */ 1162 uint_t last_offset, /* upper index */ 1163 char *nm, /* upcase nm to compare against */ 1164 int nmlen, /* length of name */ 1165 struct hsfs *fsp, 1166 struct hsnode *dhp, 1167 struct vnode *dvp, 1168 struct vnode **vpp, 1169 int *error, /* return value: errno */ 1170 int is_rrip) /* 1 if rock ridge is implemented */ 1171 { 1172 uchar_t *blkp = (uchar_t *)fbp->fb_addr; /* dir block */ 1173 char *dname; /* name in directory entry */ 1174 int dnamelen; /* length of name */ 1175 struct hs_direntry hd; 1176 int hdlen; 1177 uchar_t *dirp; /* the directory entry */ 1178 int res; 1179 int parsedir_res; 1180 size_t rrip_name_size; 1181 int rr_namelen = 0; 1182 char *rrip_name_str = NULL; 1183 char *rrip_tmp_name = NULL; 1184 enum dirblock_result err = 0; 1185 int did_fbrelse = 0; 1186 char uppercase_name[ISO_FILE_NAMELEN]; 1187 1188 #define PD_return(retval) \ 1189 { err = retval; goto do_ret; } /* return after cleanup */ 1190 #define rel_offset(offset) \ 1191 ((offset) & MAXBOFFSET) /* index into cur blk */ 1192 1193 if (is_rrip) { 1194 rrip_name_size = RRIP_FILE_NAMELEN + 1; 1195 rrip_name_str = kmem_alloc(rrip_name_size, KM_SLEEP); 1196 rrip_tmp_name = kmem_alloc(rrip_name_size, KM_SLEEP); 1197 rrip_name_str[0] = '\0'; 1198 rrip_tmp_name[0] = '\0'; 1199 } 1200 1201 while (*offset < last_offset) { 1202 1203 /* 1204 * Directory Entries cannot span sectors. 1205 * 1206 * Unused bytes at the end of each sector are zeroed 1207 * according to ISO9660, but we cannot rely on this 1208 * since both media failures and maliciously corrupted 1209 * media may return arbitrary values. 1210 * We therefore have to check for consistency: 1211 * The size of a directory entry must be at least 1212 * 34 bytes (the size of the directory entry metadata), 1213 * or zero (indicating the end-of-sector condition). 1214 * For a non-zero directory entry size of less than 1215 * 34 Bytes, log a warning. 1216 * In any case, skip the rest of this sector and 1217 * continue with the next. 1218 */ 1219 hdlen = (int)((uchar_t) 1220 HDE_DIR_LEN(&blkp[rel_offset(*offset)])); 1221 1222 if (hdlen < HDE_ROOT_DIR_REC_SIZE || 1223 *offset + hdlen > last_offset) { 1224 /* 1225 * Advance to the next sector boundary 1226 */ 1227 *offset = roundup(*offset + 1, HS_SECTOR_SIZE); 1228 if (hdlen) 1229 hs_log_bogus_disk_warning(fsp, 1230 HSFS_ERR_TRAILING_JUNK, 0); 1231 continue; 1232 } 1233 1234 bzero(&hd, sizeof (hd)); 1235 1236 /* 1237 * Check the filename length in the ISO record for 1238 * plausibility and reset it to a safe value, in case 1239 * the name length byte is out of range. Since the ISO 1240 * name will be used as fallback if the rockridge name 1241 * is invalid/nonexistant, we must make sure not to 1242 * blow the bounds and initialize dnamelen to a sensible 1243 * value within the limits of ISO9660. 1244 * In addition to that, the ISO filename is part of the 1245 * directory entry. If the filename length is too large 1246 * to fit, the record is invalid and we'll advance to 1247 * the next. 1248 */ 1249 dirp = &blkp[rel_offset(*offset)]; 1250 dname = (char *)HDE_name(dirp); 1251 dnamelen = (int)((uchar_t)HDE_NAME_LEN(dirp)); 1252 if (dnamelen > hdlen - HDE_FDESIZE) { 1253 hs_log_bogus_disk_warning(fsp, 1254 HSFS_ERR_BAD_FILE_LEN, 0); 1255 goto skip_rec; 1256 } else if (dnamelen > ISO_FILE_NAMELEN) { 1257 hs_log_bogus_disk_warning(fsp, 1258 HSFS_ERR_BAD_FILE_LEN, 0); 1259 dnamelen = ISO_FILE_NAMELEN; 1260 } 1261 1262 /* 1263 * If the rock ridge is implemented, then we copy the name 1264 * from the SUA area to rrip_name_str. If no Alternate 1265 * name is found, then use the uppercase NM in the 1266 * rrip_name_str char array. 1267 */ 1268 if (is_rrip) { 1269 1270 rrip_name_str[0] = '\0'; 1271 rr_namelen = rrip_namecopy(nm, &rrip_name_str[0], 1272 &rrip_tmp_name[0], dirp, fsp, &hd); 1273 if (hd.sym_link) { 1274 kmem_free(hd.sym_link, 1275 (size_t)(hd.ext_size+1)); 1276 hd.sym_link = (char *)NULL; 1277 } 1278 1279 if (rr_namelen != -1) { 1280 dname = (char *)&rrip_name_str[0]; 1281 dnamelen = rr_namelen; 1282 } 1283 } 1284 1285 if (!is_rrip || rr_namelen == -1) { 1286 /* use iso name instead */ 1287 1288 int i; 1289 /* 1290 * make sure that we get rid of ';' in the dname of 1291 * an iso direntry, as we should have no knowledge 1292 * of file versions. 1293 */ 1294 1295 for (i = dnamelen - 1; 1296 (dname[i] != ';') && (i > 0); 1297 i--) 1298 continue; 1299 1300 if (dname[i] == ';') 1301 dnamelen = i; 1302 else 1303 dnamelen = strip_trailing(fsp, dname, dnamelen); 1304 1305 ASSERT(dnamelen <= ISO_FILE_NAMELEN); 1306 1307 if (uppercase_cp(dname, uppercase_name, dnamelen)) 1308 hs_log_bogus_disk_warning(fsp, 1309 HSFS_ERR_LOWER_CASE_NM, 0); 1310 dname = uppercase_name; 1311 if (!is_rrip && 1312 (fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) && 1313 dname[dnamelen - 1] == '.' && 1314 CAN_TRUNCATE_DOT(dname, dnamelen)) 1315 dname[--dnamelen] = '\0'; 1316 } 1317 1318 /* 1319 * Quickly screen for a non-matching entry, but not for RRIP. 1320 * This test doesn't work for lowercase vs. uppercase names. 1321 */ 1322 1323 /* if we saw a lower case name we can't do this test either */ 1324 if (strict_iso9660_ordering && !is_rrip && 1325 !HSFS_HAVE_LOWER_CASE(fsp) && *nm < *dname) { 1326 RESTORE_NM(rrip_tmp_name, nm); 1327 PD_return(WENT_PAST) 1328 } 1329 1330 if (*nm != *dname || nmlen != dnamelen) 1331 goto skip_rec; 1332 1333 if ((res = nmcmp(dname, nm, nmlen, is_rrip)) == 0) { 1334 /* name matches */ 1335 parsedir_res = hs_parsedir(fsp, dirp, &hd, 1336 (char *)NULL, (int *)NULL); 1337 if (!parsedir_res) { 1338 uint_t lbn; /* logical block number */ 1339 1340 lbn = dhp->hs_dirent.ext_lbn + 1341 dhp->hs_dirent.xar_len; 1342 /* 1343 * Need to do an fbrelse() on the buffer, 1344 * as hs_makenode() may try to acquire 1345 * hs_hashlock, which may not be required 1346 * while a page is locked. 1347 */ 1348 fbrelse(fbp, S_READ); 1349 did_fbrelse = 1; 1350 *vpp = hs_makenode(&hd, lbn, *offset, 1351 dvp->v_vfsp); 1352 if (*vpp == NULL) { 1353 *error = ENFILE; 1354 RESTORE_NM(rrip_tmp_name, nm); 1355 PD_return(FOUND_ENTRY) 1356 } 1357 1358 dhp->hs_offset = *offset; 1359 RESTORE_NM(rrip_tmp_name, nm); 1360 PD_return(FOUND_ENTRY) 1361 } else if (parsedir_res != EAGAIN) { 1362 /* improper dir entry */ 1363 *error = parsedir_res; 1364 RESTORE_NM(rrip_tmp_name, nm); 1365 PD_return(FOUND_ENTRY) 1366 } 1367 } else if (strict_iso9660_ordering && !is_rrip && 1368 !HSFS_HAVE_LOWER_CASE(fsp) && res < 0) { 1369 /* name < dir entry */ 1370 RESTORE_NM(rrip_tmp_name, nm); 1371 PD_return(WENT_PAST) 1372 } 1373 /* 1374 * name > dir entry, 1375 * look at next one. 1376 */ 1377 skip_rec: 1378 *offset += hdlen; 1379 RESTORE_NM(rrip_tmp_name, nm); 1380 } 1381 PD_return(HIT_END) 1382 1383 do_ret: 1384 if (rrip_name_str) 1385 kmem_free(rrip_name_str, rrip_name_size); 1386 if (rrip_tmp_name) 1387 kmem_free(rrip_tmp_name, rrip_name_size); 1388 if (!did_fbrelse) 1389 fbrelse(fbp, S_READ); 1390 return (err); 1391 #undef PD_return 1392 } 1393 1394 1395 /* 1396 * Compare the names, returning < 0 if a < b, 1397 * 0 if a == b, and > 0 if a > b. 1398 */ 1399 static int 1400 nmcmp(char *a, char *b, int len, int is_rrip) 1401 { 1402 while (len--) { 1403 if (*a == *b) { 1404 b++; a++; 1405 } else { 1406 /* if file version, stop */ 1407 if (! is_rrip && ((*a == ';') && (*b == '\0'))) 1408 return (0); 1409 return ((uchar_t)*b - (uchar_t)*a); 1410 } 1411 } 1412 return (0); 1413 } 1414 1415 /* 1416 * Strip trailing nulls or spaces from the name; 1417 * return adjusted length. If we find such junk, 1418 * log a non-conformant disk message. 1419 */ 1420 static int 1421 strip_trailing(struct hsfs *fsp, char *nm, int len) 1422 { 1423 char *c; 1424 int trailing_junk = 0; 1425 1426 for (c = nm + len - 1; c > nm; c--) { 1427 if (*c == ' ' || *c == '\0') 1428 trailing_junk = 1; 1429 else 1430 break; 1431 } 1432 1433 if (trailing_junk) 1434 hs_log_bogus_disk_warning(fsp, HSFS_ERR_TRAILING_JUNK, 0); 1435 1436 return ((int)(c - nm + 1)); 1437 } 1438