1 /*- 2 * Copyright (c) 1982, 1986, 1989, 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 * @(#)cd9660_node.c 8.2 (Berkeley) 1/23/94 39 * $Id: cd9660_node.c,v 1.9 1995/02/21 18:41:30 bde Exp $ 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/mount.h> 45 #include <sys/proc.h> 46 #include <sys/file.h> 47 #include <sys/buf.h> 48 #include <sys/vnode.h> 49 #include <sys/kernel.h> 50 #include <sys/malloc.h> 51 #include <sys/stat.h> 52 53 #include <isofs/cd9660/iso.h> 54 #include <isofs/cd9660/cd9660_node.h> 55 #include <isofs/cd9660/iso_rrip.h> 56 57 #define INOHSZ 512 58 #if ((INOHSZ&(INOHSZ-1)) == 0) 59 #define INOHASH(dev,ino) (((dev)+((ino)>>12))&(INOHSZ-1)) 60 #else 61 #define INOHASH(dev,ino) (((unsigned)((dev)+((ino)>>12)))%INOHSZ) 62 #endif 63 64 union iso_ihead { 65 union iso_ihead *ih_head[2]; 66 struct iso_node *ih_chain[2]; 67 } iso_ihead[INOHSZ]; 68 69 #ifdef ISODEVMAP 70 #define DNOHSZ 64 71 #if ((DNOHSZ&(DNOHSZ-1)) == 0) 72 #define DNOHASH(dev,ino) (((dev)+((ino)>>12))&(DNOHSZ-1)) 73 #else 74 #define DNOHASH(dev,ino) (((unsigned)((dev)+((ino)>>12)))%DNOHSZ) 75 #endif 76 77 union iso_dhead { 78 union iso_dhead *dh_head[2]; 79 struct iso_dnode *dh_chain[2]; 80 } iso_dhead[DNOHSZ]; 81 #endif 82 83 /* 84 * Initialize hash links for inodes and dnodes. 85 */ 86 int 87 cd9660_init() 88 { 89 register int i; 90 register union iso_ihead *ih = iso_ihead; 91 #ifdef ISODEVMAP 92 register union iso_dhead *dh = iso_dhead; 93 #endif 94 95 for (i = INOHSZ; --i >= 0; ih++) { 96 ih->ih_head[0] = ih; 97 ih->ih_head[1] = ih; 98 } 99 #ifdef ISODEVMAP 100 for (i = DNOHSZ; --i >= 0; dh++) { 101 dh->dh_head[0] = dh; 102 dh->dh_head[1] = dh; 103 } 104 #endif 105 return (0); 106 } 107 108 #ifdef ISODEVMAP 109 /* 110 * Enter a new node into the device hash list 111 */ 112 struct iso_dnode * 113 iso_dmap(dev,ino,create) 114 dev_t dev; 115 ino_t ino; 116 int create; 117 { 118 struct iso_dnode *dp; 119 union iso_dhead *dh; 120 121 dh = &iso_dhead[DNOHASH(dev, ino)]; 122 for (dp = dh->dh_chain[0]; 123 dp != (struct iso_dnode *)dh; 124 dp = dp->d_forw) 125 if (ino == dp->i_number && dev == dp->i_dev) 126 return dp; 127 128 if (!create) 129 return (struct iso_dnode *)0; 130 131 MALLOC(dp,struct iso_dnode *,sizeof(struct iso_dnode),M_CACHE,M_WAITOK); 132 dp->i_dev = dev; 133 dp->i_number = ino; 134 insque(dp,dh); 135 136 return dp; 137 } 138 139 void 140 iso_dunmap(dev) 141 dev_t dev; 142 { 143 struct iso_dnode *dp, *dq; 144 union iso_dhead *dh; 145 146 for (dh = iso_dhead; dh < iso_dhead + DNOHSZ; dh++) { 147 for (dp = dh->dh_chain[0]; 148 dp != (struct iso_dnode *)dh; 149 dp = dq) { 150 dq = dp->d_forw; 151 if (dev == dp->i_dev) { 152 remque(dp); 153 FREE(dp,M_CACHE); 154 } 155 } 156 } 157 } 158 #endif 159 160 /* 161 * Look up a ISOFS dinode number to find its incore vnode. 162 * If it is not in core, read it in from the specified device. 163 * If it is in core, wait for the lock bit to clear, then 164 * return the inode locked. Detection and handling of mount 165 * points must be done by the calling routine. 166 */ 167 int 168 iso_iget(xp, ino, relocated, ipp, isodir) 169 struct iso_node *xp; 170 ino_t ino; 171 int relocated; 172 struct iso_node **ipp; 173 struct iso_directory_record *isodir; 174 { 175 dev_t dev = xp->i_dev; 176 struct mount *mntp = ITOV(xp)->v_mount; 177 register struct iso_node *ip, *iq; 178 register struct vnode *vp; 179 #ifdef ISODEVMAP 180 register struct iso_dnode *dp; 181 #endif 182 struct vnode *nvp; 183 struct buf *bp = NULL, *bp2 = NULL; 184 union iso_ihead *ih; 185 int error, result; 186 struct iso_mnt *imp; 187 188 ih = &iso_ihead[INOHASH(dev, ino)]; 189 loop: 190 for (ip = ih->ih_chain[0]; 191 ip != (struct iso_node *)ih; 192 ip = ip->i_forw) { 193 if (ino != ip->i_number || dev != ip->i_dev) 194 continue; 195 if ((ip->i_flag&ILOCKED) != 0) { 196 ip->i_flag |= IWANT; 197 (void) tsleep((caddr_t)ip, PINOD, "isoigt", 0); 198 goto loop; 199 } 200 if (vget(ITOV(ip), 1)) 201 goto loop; 202 *ipp = ip; 203 return 0; 204 } 205 /* 206 * Allocate a new vnode/iso_node. 207 */ 208 if ((error = getnewvnode(VT_ISOFS, mntp, cd9660_vnodeop_p, &nvp))) { 209 *ipp = 0; 210 return error; 211 } 212 MALLOC(ip, struct iso_node *, sizeof(struct iso_node), 213 M_ISOFSNODE, M_WAITOK); 214 bzero((caddr_t)ip, sizeof(struct iso_node)); 215 nvp->v_data = ip; 216 ip->i_vnode = nvp; 217 ip->i_flag = 0; 218 ip->i_devvp = 0; 219 ip->i_diroff = 0; 220 ip->i_lockf = 0; 221 222 /* 223 * Put it onto its hash chain and lock it so that other requests for 224 * this inode will block if they arrive while we are sleeping waiting 225 * for old data structures to be purged or for the contents of the 226 * disk portion of this inode to be read. 227 */ 228 ip->i_dev = dev; 229 ip->i_number = ino; 230 insque(ip, ih); 231 ISO_ILOCK(ip); 232 233 imp = VFSTOISOFS (mntp); 234 ip->i_mnt = imp; 235 ip->i_devvp = imp->im_devvp; 236 VREF(ip->i_devvp); 237 238 if (relocated) { 239 /* 240 * On relocated directories we must 241 * read the `.' entry out of a dir. 242 */ 243 ip->iso_start = ino >> imp->im_bshift; 244 if ((error = iso_blkatoff(ip,0,&bp))) { 245 vrele(ip->i_devvp); 246 remque(ip); 247 ip->i_forw = ip; 248 ip->i_back = ip; 249 iso_iput(ip); 250 *ipp = 0; 251 return error; 252 } 253 isodir = (struct iso_directory_record *)bp->b_un.b_addr; 254 } 255 256 ip->iso_extent = isonum_733(isodir->extent); 257 ip->i_size = isonum_733(isodir->size); 258 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent; 259 260 vp = ITOV(ip); 261 262 /* 263 * Setup time stamp, attribute 264 */ 265 vp->v_type = VNON; 266 switch (imp->iso_ftype) { 267 default: /* ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA */ 268 if ((imp->im_flags&ISOFSMNT_EXTATT) 269 && isonum_711(isodir->ext_attr_length)) 270 iso_blkatoff(ip,-isonum_711(isodir->ext_attr_length), 271 &bp2); 272 cd9660_defattr(isodir,ip,bp2,imp->iso_ftype ); 273 cd9660_deftstamp(isodir,ip,bp2,imp->iso_ftype ); 274 break; 275 case ISO_FTYPE_RRIP: 276 result = cd9660_rrip_analyze(isodir,ip,imp); 277 break; 278 } 279 if (bp2) 280 brelse(bp2); 281 if (bp) 282 brelse(bp); 283 284 /* 285 * Initialize the associated vnode 286 */ 287 vp->v_type = IFTOVT(ip->inode.iso_mode); 288 289 if ( vp->v_type == VFIFO ) { 290 vp->v_op = cd9660_fifoop_p; 291 } else if ( vp->v_type == VCHR || vp->v_type == VBLK ) { 292 /* 293 * if device, look at device number table for translation 294 */ 295 #ifdef ISODEVMAP 296 if (dp = iso_dmap(dev,ino,0)) 297 ip->inode.iso_rdev = dp->d_dev; 298 #endif 299 vp->v_op = cd9660_specop_p; 300 if ((nvp = checkalias(vp, ip->inode.iso_rdev, mntp))) { 301 /* 302 * Reinitialize aliased inode. 303 */ 304 vp = nvp; 305 iq = VTOI(vp); 306 iq->i_vnode = vp; 307 iq->i_flag = 0; 308 ISO_ILOCK(iq); 309 iq->i_dev = dev; 310 iq->i_number = ino; 311 iq->i_mnt = ip->i_mnt; 312 bcopy(&ip->iso_extent,&iq->iso_extent, 313 (char *)(ip + 1) - (char *)&ip->iso_extent); 314 insque(iq, ih); 315 /* 316 * Discard unneeded vnode 317 * (This introduces the need of INACTIVE modification) 318 */ 319 ip->inode.iso_mode = 0; 320 iso_iput(ip); 321 ip = iq; 322 } 323 } 324 325 if (ip->iso_extent == imp->root_extent) 326 vp->v_flag |= VROOT; 327 328 *ipp = ip; 329 return 0; 330 } 331 332 /* 333 * Unlock and decrement the reference count of an inode structure. 334 */ 335 int 336 iso_iput(ip) 337 register struct iso_node *ip; 338 { 339 340 if ((ip->i_flag & ILOCKED) == 0) 341 panic("iso_iput"); 342 ISO_IUNLOCK(ip); 343 vrele(ITOV(ip)); 344 return (0); 345 } 346 347 /* 348 * Last reference to an inode, write the inode out and if necessary, 349 * truncate and deallocate the file. 350 */ 351 int 352 cd9660_inactive(ap) 353 struct vop_inactive_args /* { 354 struct vnode *a_vp; 355 } */ *ap; 356 { 357 struct vnode *vp = ap->a_vp; 358 register struct iso_node *ip = VTOI(vp); 359 int error = 0; 360 361 if (prtactive && vp->v_usecount != 0) 362 vprint("cd9660_inactive: pushing active", vp); 363 364 ip->i_flag = 0; 365 /* 366 * If we are done with the inode, reclaim it 367 * so that it can be reused immediately. 368 */ 369 if (vp->v_usecount == 0 && ip->inode.iso_mode == 0) 370 vgone(vp); 371 return error; 372 } 373 374 /* 375 * Reclaim an inode so that it can be used for other purposes. 376 */ 377 int 378 cd9660_reclaim(ap) 379 struct vop_reclaim_args /* { 380 struct vnode *a_vp; 381 } */ *ap; 382 { 383 register struct vnode *vp = ap->a_vp; 384 register struct iso_node *ip = VTOI(vp); 385 386 if (prtactive && vp->v_usecount != 0) 387 vprint("cd9660_reclaim: pushing active", vp); 388 /* 389 * Remove the inode from its hash chain. 390 */ 391 remque(ip); 392 ip->i_forw = ip; 393 ip->i_back = ip; 394 /* 395 * Purge old data structures associated with the inode. 396 */ 397 cache_purge(vp); 398 if (ip->i_devvp) { 399 vrele(ip->i_devvp); 400 ip->i_devvp = 0; 401 } 402 FREE(vp->v_data, M_ISOFSNODE); 403 vp->v_data = NULL; 404 return 0; 405 } 406 407 /* 408 * Lock an inode. If its already locked, set the WANT bit and sleep. 409 */ 410 int 411 iso_ilock(ip) 412 register struct iso_node *ip; 413 { 414 415 while (ip->i_flag & ILOCKED) { 416 ip->i_flag |= IWANT; 417 if (ip->i_spare0 == curproc->p_pid) 418 panic("locking against myself"); 419 ip->i_spare1 = curproc->p_pid; 420 (void) tsleep((caddr_t)ip, PINOD, "isoilk", 0); 421 } 422 ip->i_spare1 = 0; 423 ip->i_spare0 = curproc->p_pid; 424 ip->i_flag |= ILOCKED; 425 return (0); 426 } 427 428 /* 429 * Unlock an inode. If WANT bit is on, wakeup. 430 */ 431 int 432 iso_iunlock(ip) 433 register struct iso_node *ip; 434 { 435 436 if ((ip->i_flag & ILOCKED) == 0) 437 vprint("iso_iunlock: unlocked inode", ITOV(ip)); 438 ip->i_spare0 = 0; 439 ip->i_flag &= ~ILOCKED; 440 if (ip->i_flag&IWANT) { 441 ip->i_flag &= ~IWANT; 442 wakeup((caddr_t)ip); 443 } 444 return (0); 445 } 446 447 /* 448 * File attributes 449 */ 450 void 451 cd9660_defattr(isodir,inop,bp,ftype) 452 struct iso_directory_record *isodir; 453 struct iso_node *inop; 454 struct buf *bp; 455 enum ISO_FTYPE ftype; 456 { 457 struct buf *bp2 = NULL; 458 struct iso_mnt *imp; 459 struct iso_extended_attributes *ap = NULL; 460 int off; 461 462 /* high sierra does not have timezone data, flag is one byte ahead */ 463 if (isonum_711(ftype == ISO_FTYPE_HIGH_SIERRA? 464 &isodir->date[6]: isodir->flags)&2) { 465 inop->inode.iso_mode = S_IFDIR; 466 /* 467 * If we return 2, fts() will assume there are no subdirectories 468 * (just links for the path and .), so instead we return 1. 469 */ 470 inop->inode.iso_links = 1; 471 } else { 472 inop->inode.iso_mode = S_IFREG; 473 inop->inode.iso_links = 1; 474 } 475 if (!bp 476 && ((imp = inop->i_mnt)->im_flags&ISOFSMNT_EXTATT) 477 && (off = isonum_711(isodir->ext_attr_length))) { 478 iso_blkatoff(inop,-off * imp->logical_block_size,&bp2); 479 bp = bp2; 480 } 481 if (bp) { 482 ap = (struct iso_extended_attributes *)bp->b_un.b_addr; 483 484 if (isonum_711(ap->version) == 1) { 485 if (!(ap->perm[0]&0x40)) 486 inop->inode.iso_mode |= VEXEC >> 6; 487 if (!(ap->perm[0]&0x10)) 488 inop->inode.iso_mode |= VREAD >> 6; 489 if (!(ap->perm[0]&4)) 490 inop->inode.iso_mode |= VEXEC >> 3; 491 if (!(ap->perm[0]&1)) 492 inop->inode.iso_mode |= VREAD >> 3; 493 if (!(ap->perm[1]&0x40)) 494 inop->inode.iso_mode |= VEXEC; 495 if (!(ap->perm[1]&0x10)) 496 inop->inode.iso_mode |= VREAD; 497 inop->inode.iso_uid = isonum_723(ap->owner); /* what about 0? */ 498 inop->inode.iso_gid = isonum_723(ap->group); /* what about 0? */ 499 } else 500 ap = NULL; 501 } 502 if (!ap) { 503 inop->inode.iso_mode |= VREAD|VEXEC|(VREAD|VEXEC)>>3|(VREAD|VEXEC)>>6; 504 inop->inode.iso_uid = (uid_t)0; 505 inop->inode.iso_gid = (gid_t)0; 506 } 507 if (bp2) 508 brelse(bp2); 509 } 510 511 /* 512 * Time stamps 513 */ 514 void 515 cd9660_deftstamp(isodir,inop,bp,ftype) 516 struct iso_directory_record *isodir; 517 struct iso_node *inop; 518 struct buf *bp; 519 enum ISO_FTYPE ftype; 520 { 521 struct buf *bp2 = NULL; 522 struct iso_mnt *imp; 523 struct iso_extended_attributes *ap = NULL; 524 int off; 525 526 if (!bp 527 && ((imp = inop->i_mnt)->im_flags&ISOFSMNT_EXTATT) 528 && (off = isonum_711(isodir->ext_attr_length))) { 529 iso_blkatoff(inop,-off * imp->logical_block_size,&bp2); 530 bp = bp2; 531 } 532 if (bp) { 533 ap = (struct iso_extended_attributes *)bp->b_un.b_addr; 534 535 if (ftype != ISO_FTYPE_HIGH_SIERRA 536 && isonum_711(ap->version) == 1) { 537 if (!cd9660_tstamp_conv17(ap->ftime,&inop->inode.iso_atime)) 538 cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_atime); 539 if (!cd9660_tstamp_conv17(ap->ctime,&inop->inode.iso_ctime)) 540 inop->inode.iso_ctime = inop->inode.iso_atime; 541 if (!cd9660_tstamp_conv17(ap->mtime,&inop->inode.iso_mtime)) 542 inop->inode.iso_mtime = inop->inode.iso_ctime; 543 } else 544 ap = NULL; 545 } 546 if (!ap) { 547 cd9660_tstamp_conv7(isodir->date,&inop->inode.iso_ctime,ftype); 548 inop->inode.iso_atime = inop->inode.iso_ctime; 549 inop->inode.iso_mtime = inop->inode.iso_ctime; 550 } 551 if (bp2) 552 brelse(bp2); 553 } 554 555 int 556 cd9660_tstamp_conv7(pi,pu,ftype) 557 char *pi; 558 struct timespec *pu; 559 enum ISO_FTYPE ftype; 560 { 561 int crtime, days; 562 int y, m, d, hour, minute, second, tz; 563 564 y = pi[0] + 1900; 565 m = pi[1]; 566 d = pi[2]; 567 hour = pi[3]; 568 minute = pi[4]; 569 second = pi[5]; 570 if(ftype != ISO_FTYPE_HIGH_SIERRA) 571 tz = pi[6]; 572 else 573 /* original high sierra misses timezone data */ 574 tz = 0; 575 576 if (y < 1970) { 577 pu->ts_sec = 0; 578 pu->ts_nsec = 0; 579 return 0; 580 } else { 581 #ifdef ORIGINAL 582 /* computes day number relative to Sept. 19th,1989 */ 583 /* don't even *THINK* about changing formula. It works! */ 584 days = 367*(y-1980)-7*(y+(m+9)/12)/4-3*((y+(m-9)/7)/100+1)/4+275*m/9+d-100; 585 #else 586 /* 587 * Changed :-) to make it relative to Jan. 1st, 1970 588 * and to disambiguate negative division 589 */ 590 days = 367*(y-1960)-7*(y+(m+9)/12)/4-3*((y+(m+9)/12-1)/100+1)/4+275*m/9+d-239; 591 #endif 592 crtime = ((((days * 24) + hour) * 60 + minute) * 60) + second; 593 594 /* timezone offset is unreliable on some disks */ 595 if (-48 <= tz && tz <= 52) 596 crtime -= tz * 15 * 60; 597 } 598 pu->ts_sec = crtime; 599 pu->ts_nsec = 0; 600 return 1; 601 } 602 603 static unsigned 604 cd9660_chars2ui(begin,len) 605 unsigned char *begin; 606 int len; 607 { 608 unsigned rc; 609 610 for (rc = 0; --len >= 0;) { 611 rc *= 10; 612 rc += *begin++ - '0'; 613 } 614 return rc; 615 } 616 617 int 618 cd9660_tstamp_conv17(pi,pu) 619 unsigned char *pi; 620 struct timespec *pu; 621 { 622 unsigned char buf[7]; 623 624 /* year:"0001"-"9999" -> -1900 */ 625 buf[0] = cd9660_chars2ui(pi,4) - 1900; 626 627 /* month: " 1"-"12" -> 1 - 12 */ 628 buf[1] = cd9660_chars2ui(pi + 4,2); 629 630 /* day: " 1"-"31" -> 1 - 31 */ 631 buf[2] = cd9660_chars2ui(pi + 6,2); 632 633 /* hour: " 0"-"23" -> 0 - 23 */ 634 buf[3] = cd9660_chars2ui(pi + 8,2); 635 636 /* minute:" 0"-"59" -> 0 - 59 */ 637 buf[4] = cd9660_chars2ui(pi + 10,2); 638 639 /* second:" 0"-"59" -> 0 - 59 */ 640 buf[5] = cd9660_chars2ui(pi + 12,2); 641 642 /* difference of GMT */ 643 buf[6] = pi[16]; 644 645 return cd9660_tstamp_conv7(buf, pu, ISO_FTYPE_DEFAULT); 646 } 647 648 void 649 isodirino(inump,isodir,imp) 650 ino_t *inump; 651 struct iso_directory_record *isodir; 652 struct iso_mnt *imp; 653 { 654 *inump = (isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length)) 655 * imp->logical_block_size; 656 } 657