1 /*- 2 * Copyright (c) 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 * %sccs.include.redist.c% 11 * 12 * @(#)cd9660_rrip.c 8.5 (Berkeley) 08/17/94 13 */ 14 15 #include <sys/param.h> 16 #include <sys/namei.h> 17 #include <sys/buf.h> 18 #include <sys/file.h> 19 #include <sys/vnode.h> 20 #include <sys/mount.h> 21 #include <sys/kernel.h> 22 #include <sys/stat.h> 23 #include <sys/types.h> 24 25 #include <sys/time.h> 26 27 #include <isofs/cd9660/iso.h> 28 #include <isofs/cd9660/cd9660_node.h> 29 #include <isofs/cd9660/cd9660_rrip.h> 30 #include <isofs/cd9660/iso_rrip.h> 31 32 /* 33 * POSIX file attribute 34 */ 35 static int 36 cd9660_rrip_attr(p,ana) 37 ISO_RRIP_ATTR *p; 38 ISO_RRIP_ANALYZE *ana; 39 { 40 ana->inop->inode.iso_mode = isonum_731(p->mode_l); 41 ana->inop->inode.iso_uid = (uid_t)isonum_731(p->uid_l); 42 ana->inop->inode.iso_gid = (gid_t)isonum_731(p->gid_l); 43 ana->inop->inode.iso_links = isonum_731(p->links_l); 44 ana->fields &= ~ISO_SUSP_ATTR; 45 return ISO_SUSP_ATTR; 46 } 47 48 static void 49 cd9660_rrip_defattr(isodir,ana) 50 struct iso_directory_record *isodir; 51 ISO_RRIP_ANALYZE *ana; 52 { 53 /* But this is a required field! */ 54 printf("RRIP without PX field?\n"); 55 cd9660_defattr(isodir,ana->inop,NULL); 56 } 57 58 /* 59 * Symbolic Links 60 */ 61 static int 62 cd9660_rrip_slink(p,ana) 63 ISO_RRIP_SLINK *p; 64 ISO_RRIP_ANALYZE *ana; 65 { 66 register ISO_RRIP_SLINK_COMPONENT *pcomp; 67 register ISO_RRIP_SLINK_COMPONENT *pcompe; 68 int len, wlen, cont; 69 char *outbuf, *inbuf; 70 71 pcomp = (ISO_RRIP_SLINK_COMPONENT *)p->component; 72 pcompe = (ISO_RRIP_SLINK_COMPONENT *)((char *)p + isonum_711(p->h.length)); 73 len = *ana->outlen; 74 outbuf = ana->outbuf; 75 cont = ana->cont; 76 77 /* 78 * Gathering a Symbolic name from each component with path 79 */ 80 for (; 81 pcomp < pcompe; 82 pcomp = (ISO_RRIP_SLINK_COMPONENT *)((char *)pcomp + ISO_RRIP_SLSIZ 83 + isonum_711(pcomp->clen))) { 84 85 if (!cont) { 86 if (len < ana->maxlen) { 87 len++; 88 *outbuf++ = '/'; 89 } 90 } 91 cont = 0; 92 93 inbuf = ".."; 94 wlen = 0; 95 96 switch (*pcomp->cflag) { 97 98 case ISO_SUSP_CFLAG_CURRENT: 99 /* Inserting Current */ 100 wlen = 1; 101 break; 102 103 case ISO_SUSP_CFLAG_PARENT: 104 /* Inserting Parent */ 105 wlen = 2; 106 break; 107 108 case ISO_SUSP_CFLAG_ROOT: 109 /* Inserting slash for ROOT */ 110 /* start over from beginning(?) */ 111 outbuf -= len; 112 len = 0; 113 break; 114 115 case ISO_SUSP_CFLAG_VOLROOT: 116 /* Inserting a mount point i.e. "/cdrom" */ 117 /* same as above */ 118 outbuf -= len; 119 len = 0; 120 inbuf = ana->imp->im_mountp->mnt_stat.f_mntonname; 121 wlen = strlen(inbuf); 122 break; 123 124 case ISO_SUSP_CFLAG_HOST: 125 /* Inserting hostname i.e. "kurt.tools.de" */ 126 inbuf = hostname; 127 wlen = hostnamelen; 128 break; 129 130 case ISO_SUSP_CFLAG_CONTINUE: 131 cont = 1; 132 /* fall thru */ 133 case 0: 134 /* Inserting component */ 135 wlen = isonum_711(pcomp->clen); 136 inbuf = pcomp->name; 137 break; 138 default: 139 printf("RRIP with incorrect flags?"); 140 wlen = ana->maxlen + 1; 141 break; 142 } 143 144 if (len + wlen > ana->maxlen) { 145 /* indicate error to caller */ 146 ana->cont = 1; 147 ana->fields = 0; 148 ana->outbuf -= *ana->outlen; 149 *ana->outlen = 0; 150 return 0; 151 } 152 153 bcopy(inbuf,outbuf,wlen); 154 outbuf += wlen; 155 len += wlen; 156 157 } 158 ana->outbuf = outbuf; 159 *ana->outlen = len; 160 ana->cont = cont; 161 162 if (!isonum_711(p->flags)) { 163 ana->fields &= ~ISO_SUSP_SLINK; 164 return ISO_SUSP_SLINK; 165 } 166 return 0; 167 } 168 169 /* 170 * Alternate name 171 */ 172 static int 173 cd9660_rrip_altname(p,ana) 174 ISO_RRIP_ALTNAME *p; 175 ISO_RRIP_ANALYZE *ana; 176 { 177 char *inbuf; 178 int wlen; 179 int cont; 180 181 inbuf = ".."; 182 wlen = 0; 183 cont = 0; 184 185 switch (*p->flags) { 186 case ISO_SUSP_CFLAG_CURRENT: 187 /* Inserting Current */ 188 wlen = 1; 189 break; 190 191 case ISO_SUSP_CFLAG_PARENT: 192 /* Inserting Parent */ 193 wlen = 2; 194 break; 195 196 case ISO_SUSP_CFLAG_HOST: 197 /* Inserting hostname i.e. "kurt.tools.de" */ 198 inbuf = hostname; 199 wlen = hostnamelen; 200 break; 201 202 case ISO_SUSP_CFLAG_CONTINUE: 203 cont = 1; 204 /* fall thru */ 205 case 0: 206 /* Inserting component */ 207 wlen = isonum_711(p->h.length) - 5; 208 inbuf = (char *)p + 5; 209 break; 210 211 default: 212 printf("RRIP with incorrect NM flags?\n"); 213 wlen = ana->maxlen + 1; 214 break; 215 } 216 217 if ((*ana->outlen += wlen) > ana->maxlen) { 218 /* treat as no name field */ 219 ana->fields &= ~ISO_SUSP_ALTNAME; 220 ana->outbuf -= *ana->outlen - wlen; 221 *ana->outlen = 0; 222 return 0; 223 } 224 225 bcopy(inbuf,ana->outbuf,wlen); 226 ana->outbuf += wlen; 227 228 if (!cont) { 229 ana->fields &= ~ISO_SUSP_ALTNAME; 230 return ISO_SUSP_ALTNAME; 231 } 232 return 0; 233 } 234 235 static void 236 cd9660_rrip_defname(isodir,ana) 237 struct iso_directory_record *isodir; 238 ISO_RRIP_ANALYZE *ana; 239 { 240 strcpy(ana->outbuf,".."); 241 switch (*isodir->name) { 242 default: 243 isofntrans(isodir->name,isonum_711(isodir->name_len), 244 ana->outbuf,ana->outlen, 245 1,isonum_711(isodir->flags)&4); 246 break; 247 case 0: 248 *ana->outlen = 1; 249 break; 250 case 1: 251 *ana->outlen = 2; 252 break; 253 } 254 } 255 256 /* 257 * Parent or Child Link 258 */ 259 static int 260 cd9660_rrip_pclink(p,ana) 261 ISO_RRIP_CLINK *p; 262 ISO_RRIP_ANALYZE *ana; 263 { 264 *ana->inump = isonum_733(p->dir_loc) << ana->imp->im_bshift; 265 ana->fields &= ~(ISO_SUSP_CLINK|ISO_SUSP_PLINK); 266 return *p->h.type == 'C' ? ISO_SUSP_CLINK : ISO_SUSP_PLINK; 267 } 268 269 /* 270 * Relocated directory 271 */ 272 static int 273 cd9660_rrip_reldir(p,ana) 274 ISO_RRIP_RELDIR *p; 275 ISO_RRIP_ANALYZE *ana; 276 { 277 /* special hack to make caller aware of RE field */ 278 *ana->outlen = 0; 279 ana->fields = 0; 280 return ISO_SUSP_RELDIR|ISO_SUSP_ALTNAME|ISO_SUSP_CLINK|ISO_SUSP_PLINK; 281 } 282 283 static int 284 cd9660_rrip_tstamp(p,ana) 285 ISO_RRIP_TSTAMP *p; 286 ISO_RRIP_ANALYZE *ana; 287 { 288 unsigned char *ptime; 289 290 ptime = p->time; 291 292 /* Check a format of time stamp (7bytes/17bytes) */ 293 if (!(*p->flags&ISO_SUSP_TSTAMP_FORM17)) { 294 if (*p->flags&ISO_SUSP_TSTAMP_CREAT) 295 ptime += 7; 296 297 if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) { 298 cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_mtime); 299 ptime += 7; 300 } else 301 bzero(&ana->inop->inode.iso_mtime,sizeof(struct timeval)); 302 303 if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) { 304 cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_atime); 305 ptime += 7; 306 } else 307 ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime; 308 309 if (*p->flags&ISO_SUSP_TSTAMP_ATTR) 310 cd9660_tstamp_conv7(ptime,&ana->inop->inode.iso_ctime); 311 else 312 ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime; 313 314 } else { 315 if (*p->flags&ISO_SUSP_TSTAMP_CREAT) 316 ptime += 17; 317 318 if (*p->flags&ISO_SUSP_TSTAMP_MODIFY) { 319 cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_mtime); 320 ptime += 17; 321 } else 322 bzero(&ana->inop->inode.iso_mtime,sizeof(struct timeval)); 323 324 if (*p->flags&ISO_SUSP_TSTAMP_ACCESS) { 325 cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_atime); 326 ptime += 17; 327 } else 328 ana->inop->inode.iso_atime = ana->inop->inode.iso_mtime; 329 330 if (*p->flags&ISO_SUSP_TSTAMP_ATTR) 331 cd9660_tstamp_conv17(ptime,&ana->inop->inode.iso_ctime); 332 else 333 ana->inop->inode.iso_ctime = ana->inop->inode.iso_mtime; 334 335 } 336 ana->fields &= ~ISO_SUSP_TSTAMP; 337 return ISO_SUSP_TSTAMP; 338 } 339 340 static void 341 cd9660_rrip_deftstamp(isodir,ana) 342 struct iso_directory_record *isodir; 343 ISO_RRIP_ANALYZE *ana; 344 { 345 cd9660_deftstamp(isodir,ana->inop,NULL); 346 } 347 348 /* 349 * POSIX device modes 350 */ 351 static int 352 cd9660_rrip_device(p,ana) 353 ISO_RRIP_DEVICE *p; 354 ISO_RRIP_ANALYZE *ana; 355 { 356 unsigned high, low; 357 358 high = isonum_733(p->dev_t_high_l); 359 low = isonum_733(p->dev_t_low_l); 360 361 if (high == 0) 362 ana->inop->inode.iso_rdev = makedev(major(low), minor(low)); 363 else 364 ana->inop->inode.iso_rdev = makedev(high, minor(low)); 365 ana->fields &= ~ISO_SUSP_DEVICE; 366 return ISO_SUSP_DEVICE; 367 } 368 369 /* 370 * Flag indicating 371 */ 372 static int 373 cd9660_rrip_idflag(p,ana) 374 ISO_RRIP_IDFLAG *p; 375 ISO_RRIP_ANALYZE *ana; 376 { 377 ana->fields &= isonum_711(p->flags)|~0xff; /* don't touch high bits */ 378 /* special handling of RE field */ 379 if (ana->fields&ISO_SUSP_RELDIR) 380 return cd9660_rrip_reldir(p,ana); 381 382 return ISO_SUSP_IDFLAG; 383 } 384 385 /* 386 * Continuation pointer 387 */ 388 static int 389 cd9660_rrip_cont(p,ana) 390 ISO_RRIP_CONT *p; 391 ISO_RRIP_ANALYZE *ana; 392 { 393 ana->iso_ce_blk = isonum_733(p->location); 394 ana->iso_ce_off = isonum_733(p->offset); 395 ana->iso_ce_len = isonum_733(p->length); 396 return ISO_SUSP_CONT; 397 } 398 399 /* 400 * System Use end 401 */ 402 static int 403 cd9660_rrip_stop(p,ana) 404 ISO_SUSP_HEADER *p; 405 ISO_RRIP_ANALYZE *ana; 406 { 407 return ISO_SUSP_STOP; 408 } 409 410 /* 411 * Extension reference 412 */ 413 static int 414 cd9660_rrip_extref(p,ana) 415 ISO_RRIP_EXTREF *p; 416 ISO_RRIP_ANALYZE *ana; 417 { 418 if (isonum_711(p->len_id) != 10 419 || bcmp((char *)p + 8,"RRIP_1991A",10) 420 || isonum_711(p->version) != 1) 421 return 0; 422 ana->fields &= ~ISO_SUSP_EXTREF; 423 return ISO_SUSP_EXTREF; 424 } 425 426 typedef struct { 427 char type[2]; 428 int (*func)(); 429 void (*func2)(); 430 int result; 431 } RRIP_TABLE; 432 433 static int 434 cd9660_rrip_loop(isodir,ana,table) 435 struct iso_directory_record *isodir; 436 ISO_RRIP_ANALYZE *ana; 437 RRIP_TABLE *table; 438 { 439 register RRIP_TABLE *ptable; 440 register ISO_SUSP_HEADER *phead; 441 register ISO_SUSP_HEADER *pend; 442 struct buf *bp = NULL; 443 int i; 444 char *pwhead; 445 int result; 446 447 /* 448 * Note: If name length is odd, 449 * it will be padding 1 byte after the name 450 */ 451 pwhead = isodir->name + isonum_711(isodir->name_len); 452 if (!(isonum_711(isodir->name_len)&1)) 453 pwhead++; 454 455 /* If it's not the '.' entry of the root dir obey SP field */ 456 if (*isodir->name != 0 457 || isonum_733(isodir->extent) != ana->imp->root_extent) 458 pwhead += ana->imp->rr_skip; 459 else 460 pwhead += ana->imp->rr_skip0; 461 462 phead = (ISO_SUSP_HEADER *)pwhead; 463 pend = (ISO_SUSP_HEADER *)((char *)isodir + isonum_711(isodir->length)); 464 465 result = 0; 466 while (1) { 467 ana->iso_ce_len = 0; 468 /* 469 * Note: "pend" should be more than one SUSP header 470 */ 471 while (pend >= phead + 1) { 472 if (isonum_711(phead->version) == 1) { 473 for (ptable = table; ptable->func; ptable++) { 474 if (*phead->type == *ptable->type 475 && phead->type[1] == ptable->type[1]) { 476 result |= ptable->func(phead,ana); 477 break; 478 } 479 } 480 if (!ana->fields) 481 break; 482 } 483 if (result&ISO_SUSP_STOP) { 484 result &= ~ISO_SUSP_STOP; 485 break; 486 } 487 /* plausibility check */ 488 if (isonum_711(phead->length) < sizeof(*phead)) 489 break; 490 /* 491 * move to next SUSP 492 * Hopefully this works with newer versions, too 493 */ 494 phead = (ISO_SUSP_HEADER *)((char *)phead + isonum_711(phead->length)); 495 } 496 497 if (ana->fields && ana->iso_ce_len) { 498 if (ana->iso_ce_blk >= ana->imp->volume_space_size 499 || ana->iso_ce_off + ana->iso_ce_len > ana->imp->logical_block_size 500 || bread(ana->imp->im_devvp, 501 ana->iso_ce_blk * ana->imp->logical_block_size / DEV_BSIZE, 502 ana->imp->logical_block_size,NOCRED,&bp)) 503 /* what to do now? */ 504 break; 505 phead = (ISO_SUSP_HEADER *)(bp->b_un.b_addr + ana->iso_ce_off); 506 pend = (ISO_SUSP_HEADER *) ((char *)phead + ana->iso_ce_len); 507 } else 508 break; 509 } 510 if (bp) 511 brelse(bp); 512 /* 513 * If we don't find the Basic SUSP stuffs, just set default value 514 * (attribute/time stamp) 515 */ 516 for (ptable = table; ptable->func2; ptable++) 517 if (!(ptable->result&result)) 518 ptable->func2(isodir,ana); 519 520 return result; 521 } 522 523 /* 524 * Get Attributes. 525 */ 526 static RRIP_TABLE rrip_table_analyze[] = { 527 { "PX", cd9660_rrip_attr, cd9660_rrip_defattr, ISO_SUSP_ATTR }, 528 { "TF", cd9660_rrip_tstamp, cd9660_rrip_deftstamp, ISO_SUSP_TSTAMP }, 529 { "PN", cd9660_rrip_device, 0, ISO_SUSP_DEVICE }, 530 { "RR", cd9660_rrip_idflag, 0, ISO_SUSP_IDFLAG }, 531 { "CE", cd9660_rrip_cont, 0, ISO_SUSP_CONT }, 532 { "ST", cd9660_rrip_stop, 0, ISO_SUSP_STOP }, 533 { "", 0, 0, 0 } 534 }; 535 536 int 537 cd9660_rrip_analyze(isodir,inop,imp) 538 struct iso_directory_record *isodir; 539 struct iso_node *inop; 540 struct iso_mnt *imp; 541 { 542 ISO_RRIP_ANALYZE analyze; 543 544 analyze.inop = inop; 545 analyze.imp = imp; 546 analyze.fields = ISO_SUSP_ATTR|ISO_SUSP_TSTAMP|ISO_SUSP_DEVICE; 547 548 return cd9660_rrip_loop(isodir,&analyze,rrip_table_analyze); 549 } 550 551 /* 552 * Get Alternate Name. 553 */ 554 static RRIP_TABLE rrip_table_getname[] = { 555 { "NM", cd9660_rrip_altname, cd9660_rrip_defname, ISO_SUSP_ALTNAME }, 556 { "CL", cd9660_rrip_pclink, 0, ISO_SUSP_CLINK|ISO_SUSP_PLINK }, 557 { "PL", cd9660_rrip_pclink, 0, ISO_SUSP_CLINK|ISO_SUSP_PLINK }, 558 { "RE", cd9660_rrip_reldir, 0, ISO_SUSP_RELDIR }, 559 { "RR", cd9660_rrip_idflag, 0, ISO_SUSP_IDFLAG }, 560 { "CE", cd9660_rrip_cont, 0, ISO_SUSP_CONT }, 561 { "ST", cd9660_rrip_stop, 0, ISO_SUSP_STOP }, 562 { "", 0, 0, 0 } 563 }; 564 565 int 566 cd9660_rrip_getname(isodir,outbuf,outlen,inump,imp) 567 struct iso_directory_record *isodir; 568 char *outbuf; 569 u_short *outlen; 570 ino_t *inump; 571 struct iso_mnt *imp; 572 { 573 ISO_RRIP_ANALYZE analyze; 574 RRIP_TABLE *tab; 575 576 analyze.outbuf = outbuf; 577 analyze.outlen = outlen; 578 analyze.maxlen = NAME_MAX; 579 analyze.inump = inump; 580 analyze.imp = imp; 581 analyze.fields = ISO_SUSP_ALTNAME|ISO_SUSP_RELDIR|ISO_SUSP_CLINK|ISO_SUSP_PLINK; 582 *outlen = 0; 583 584 tab = rrip_table_getname; 585 if (*isodir->name == 0 586 || *isodir->name == 1) { 587 cd9660_rrip_defname(isodir,&analyze); 588 589 analyze.fields &= ~ISO_SUSP_ALTNAME; 590 tab++; 591 } 592 593 return cd9660_rrip_loop(isodir,&analyze,tab); 594 } 595 596 /* 597 * Get Symbolic Link. 598 */ 599 static RRIP_TABLE rrip_table_getsymname[] = { 600 { "SL", cd9660_rrip_slink, 0, ISO_SUSP_SLINK }, 601 { "RR", cd9660_rrip_idflag, 0, ISO_SUSP_IDFLAG }, 602 { "CE", cd9660_rrip_cont, 0, ISO_SUSP_CONT }, 603 { "ST", cd9660_rrip_stop, 0, ISO_SUSP_STOP }, 604 { "", 0, 0, 0 } 605 }; 606 607 int 608 cd9660_rrip_getsymname(isodir,outbuf,outlen,imp) 609 struct iso_directory_record *isodir; 610 char *outbuf; 611 u_short *outlen; 612 struct iso_mnt *imp; 613 { 614 ISO_RRIP_ANALYZE analyze; 615 616 analyze.outbuf = outbuf; 617 analyze.outlen = outlen; 618 *outlen = 0; 619 analyze.maxlen = MAXPATHLEN; 620 analyze.cont = 1; /* don't start with a slash */ 621 analyze.imp = imp; 622 analyze.fields = ISO_SUSP_SLINK; 623 624 return (cd9660_rrip_loop(isodir,&analyze,rrip_table_getsymname)&ISO_SUSP_SLINK); 625 } 626 627 static RRIP_TABLE rrip_table_extref[] = { 628 { "ER", cd9660_rrip_extref, 0, ISO_SUSP_EXTREF }, 629 { "CE", cd9660_rrip_cont, 0, ISO_SUSP_CONT }, 630 { "ST", cd9660_rrip_stop, 0, ISO_SUSP_STOP }, 631 { "", 0, 0, 0 } 632 }; 633 634 /* 635 * Check for Rock Ridge Extension and return offset of its fields. 636 * Note: We insist on the ER field. 637 */ 638 int 639 cd9660_rrip_offset(isodir,imp) 640 struct iso_directory_record *isodir; 641 struct iso_mnt *imp; 642 { 643 ISO_RRIP_OFFSET *p; 644 ISO_RRIP_ANALYZE analyze; 645 646 imp->rr_skip0 = 0; 647 p = (ISO_RRIP_OFFSET *)(isodir->name + 1); 648 if (bcmp(p,"SP\7\1\276\357",6)) { 649 /* Maybe, it's a CDROM XA disc? */ 650 imp->rr_skip0 = 15; 651 p = (ISO_RRIP_OFFSET *)((char *)p + 15); 652 if (bcmp(p,"SP\7\1\276\357",6)) 653 return -1; 654 } 655 656 analyze.imp = imp; 657 analyze.fields = ISO_SUSP_EXTREF; 658 if (!(cd9660_rrip_loop(isodir,&analyze,rrip_table_extref)&ISO_SUSP_EXTREF)) 659 return -1; 660 661 return isonum_711(p->skip); 662 } 663