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