1 /* 2 * Copyright 1999, Be Incorporated. All Rights Reserved. 3 * This file may be used under the terms of the Be Sample Code License. 4 * 5 * Copyright 2001, pinc Software. All Rights Reserved. 6 */ 7 8 9 #include "iso9660.h" 10 11 #include <ctype.h> 12 13 #ifndef FS_SHELL 14 # include <dirent.h> 15 # include <fcntl.h> 16 # include <stdlib.h> 17 # include <string.h> 18 # include <sys/stat.h> 19 # include <time.h> 20 # include <unistd.h> 21 22 # include <ByteOrder.h> 23 # include <Drivers.h> 24 # include <KernelExport.h> 25 # include <fs_cache.h> 26 #endif 27 28 #include "rock_ridge.h" 29 30 //#define TRACE_ISO9660 1 31 #if TRACE_ISO9660 32 # define TRACE(x) dprintf x 33 #else 34 # define TRACE(x) ; 35 #endif 36 37 38 // Just needed here 39 static status_t unicode_to_utf8(const char *src, int32 *srcLen, char *dst, 40 int32 *dstLen); 41 42 43 // ISO9660 should start with this string 44 const char *kISO9660IDString = "CD001"; 45 46 47 static int 48 get_device_block_size(int fd) 49 { 50 device_geometry geometry; 51 52 if (ioctl(fd, B_GET_GEOMETRY, &geometry, sizeof(device_geometry)) < 0) { 53 struct stat st; 54 if (fstat(fd, &st) < 0 || S_ISDIR(st.st_mode)) 55 return 0; 56 57 return 512; /* just assume it's a plain old file or something */ 58 } 59 60 return geometry.bytes_per_sector; 61 } 62 63 64 // From EncodingComversions.cpp 65 66 // Pierre's (modified) Uber Macro 67 68 // NOTE: iso9660 seems to store the unicode text in big-endian form 69 #define u_to_utf8(str, uni_str)\ 70 {\ 71 if ((B_BENDIAN_TO_HOST_INT16(uni_str[0])&0xff80) == 0)\ 72 *str++ = B_BENDIAN_TO_HOST_INT16(*uni_str++);\ 73 else if ((B_BENDIAN_TO_HOST_INT16(uni_str[0])&0xf800) == 0) {\ 74 str[0] = 0xc0|(B_BENDIAN_TO_HOST_INT16(uni_str[0])>>6);\ 75 str[1] = 0x80|(B_BENDIAN_TO_HOST_INT16(*uni_str++)&0x3f);\ 76 str += 2;\ 77 } else if ((B_BENDIAN_TO_HOST_INT16(uni_str[0])&0xfc00) != 0xd800) {\ 78 str[0] = 0xe0|(B_BENDIAN_TO_HOST_INT16(uni_str[0])>>12);\ 79 str[1] = 0x80|((B_BENDIAN_TO_HOST_INT16(uni_str[0])>>6)&0x3f);\ 80 str[2] = 0x80|(B_BENDIAN_TO_HOST_INT16(*uni_str++)&0x3f);\ 81 str += 3;\ 82 } else {\ 83 int val;\ 84 val = ((B_BENDIAN_TO_HOST_INT16(uni_str[0])-0xd7c0)<<10) | (B_BENDIAN_TO_HOST_INT16(uni_str[1])&0x3ff);\ 85 str[0] = 0xf0 | (val>>18);\ 86 str[1] = 0x80 | ((val>>12)&0x3f);\ 87 str[2] = 0x80 | ((val>>6)&0x3f);\ 88 str[3] = 0x80 | (val&0x3f);\ 89 uni_str += 2; str += 4;\ 90 }\ 91 } 92 93 94 static status_t 95 unicode_to_utf8(const char *src, int32 *srcLen, char *dst, int32 *dstLen) 96 { 97 int32 srcLimit = *srcLen; 98 int32 dstLimit = *dstLen; 99 int32 srcCount = 0; 100 int32 dstCount = 0; 101 102 for (srcCount = 0; srcCount < srcLimit; srcCount += 2) { 103 uint16 *UNICODE = (uint16 *)&src[srcCount]; 104 uint8 utf8[4]; 105 uint8 *UTF8 = utf8; 106 int32 utf8Len; 107 int32 j; 108 109 u_to_utf8(UTF8, UNICODE); 110 111 utf8Len = UTF8 - utf8; 112 if (dstCount + utf8Len > dstLimit) 113 break; 114 115 for (j = 0; j < utf8Len; j++) 116 dst[dstCount + j] = utf8[j]; 117 dstCount += utf8Len; 118 } 119 120 *srcLen = srcCount; 121 *dstLen = dstCount; 122 123 return dstCount > 0 ? B_NO_ERROR : B_ERROR; 124 } 125 126 127 static void 128 sanitize_iso_name(iso9660_inode* node, bool removeTrailingPoints) 129 { 130 // Get rid of semicolons, which are used to delineate file versions. 131 if (char* semi = strchr(node->name, ';')) { 132 semi[0] = '\0'; 133 node->name_length = semi - node->name; 134 } 135 136 if (removeTrailingPoints) { 137 // Get rid of trailing points 138 if (node->name_length > 2 && node->name[node->name_length - 1] == '.') 139 node->name[--node->name_length] = '\0'; 140 } 141 } 142 143 144 static int 145 init_volume_date(ISOVolDate *date, char *buffer) 146 { 147 memcpy(date, buffer, ISO_VOL_DATE_SIZE); 148 return 0; 149 } 150 151 152 static int 153 init_node_date(ISORecDate *date, char *buffer) 154 { 155 memcpy(date, buffer, sizeof(struct ISORecDate)); 156 return 0; 157 } 158 159 160 static status_t 161 InitVolDesc(iso9660_volume *volume, char *buffer) 162 { 163 TRACE(("InitVolDesc - ENTER\n")); 164 165 volume->volDescType = *(uint8 *)buffer; 166 buffer += sizeof(volume->volDescType); 167 168 const size_t kStdIDStringLen = sizeof(volume->stdIDString) - 1; 169 volume->stdIDString[kStdIDStringLen] = '\0'; 170 strncpy(volume->stdIDString, buffer, kStdIDStringLen); 171 buffer += kStdIDStringLen; 172 173 volume->volDescVersion = *(uint8 *)buffer; 174 buffer += sizeof(volume->volDescVersion); 175 176 buffer += sizeof(volume->unused1); // skip unused 8th byte 177 178 const size_t kSystemIDStringLen = sizeof(volume->systemIDString) - 1; 179 volume->systemIDString[kSystemIDStringLen] = '\0'; 180 strncpy(volume->systemIDString, buffer, kSystemIDStringLen); 181 buffer += kSystemIDStringLen; 182 TRACE(("InitVolDesc - system id string is %s\n", volume->systemIDString)); 183 184 const size_t kVolIDStringLen = sizeof(volume->volIDString) - 1; 185 volume->volIDString[kVolIDStringLen] = '\0'; 186 strncpy(volume->volIDString, buffer, kVolIDStringLen); 187 buffer += kVolIDStringLen; 188 TRACE(("InitVolDesc - volume id string is %s\n", volume->volIDString)); 189 190 buffer += sizeof(volume->unused2) - 1; // skip unused 73-80 bytes 191 192 volume->volSpaceSize[LSB_DATA] = *(uint32 *)buffer; 193 buffer += sizeof(volume->volSpaceSize[LSB_DATA]); 194 volume->volSpaceSize[MSB_DATA] = *(uint32 *)buffer; 195 buffer += sizeof(volume->volSpaceSize[MSB_DATA]); 196 197 buffer += sizeof(volume->unused3) - 1; // skip unused 89-120 bytes 198 199 volume->volSetSize[LSB_DATA] = *(uint16*)buffer; 200 buffer += sizeof(volume->volSetSize[LSB_DATA]); 201 volume->volSetSize[MSB_DATA] = *(uint16*)buffer; 202 buffer += sizeof(volume->volSetSize[MSB_DATA]); 203 204 volume->volSeqNum[LSB_DATA] = *(uint16*)buffer; 205 buffer += sizeof(volume->volSeqNum[LSB_DATA]); 206 volume->volSeqNum[MSB_DATA] = *(uint16*)buffer; 207 buffer += sizeof(volume->volSeqNum[MSB_DATA]); 208 209 volume->logicalBlkSize[LSB_DATA] = *(uint16*)buffer; 210 buffer += sizeof(volume->logicalBlkSize[LSB_DATA]); 211 volume->logicalBlkSize[MSB_DATA] = *(uint16*)buffer; 212 buffer += sizeof(volume->logicalBlkSize[MSB_DATA]); 213 214 volume->pathTblSize[LSB_DATA] = *(uint32*)buffer; 215 buffer += sizeof(volume->pathTblSize[LSB_DATA]); 216 volume->pathTblSize[MSB_DATA] = *(uint32*)buffer; 217 buffer += sizeof(volume->pathTblSize[MSB_DATA]); 218 219 volume->lPathTblLoc[LSB_DATA] = *(uint16*)buffer; 220 buffer += sizeof(volume->lPathTblLoc[LSB_DATA]); 221 volume->lPathTblLoc[MSB_DATA] = *(uint16*)buffer; 222 buffer += sizeof(volume->lPathTblLoc[MSB_DATA]); 223 224 volume->optLPathTblLoc[LSB_DATA] = *(uint16*)buffer; 225 buffer += sizeof(volume->optLPathTblLoc[LSB_DATA]); 226 volume->optLPathTblLoc[MSB_DATA] = *(uint16*)buffer; 227 buffer += sizeof(volume->optLPathTblLoc[MSB_DATA]); 228 229 volume->mPathTblLoc[LSB_DATA] = *(uint16*)buffer; 230 buffer += sizeof(volume->mPathTblLoc[LSB_DATA]); 231 volume->mPathTblLoc[MSB_DATA] = *(uint16*)buffer; 232 buffer += sizeof(volume->mPathTblLoc[MSB_DATA]); 233 234 volume->optMPathTblLoc[LSB_DATA] = *(uint16*)buffer; 235 buffer += sizeof(volume->optMPathTblLoc[LSB_DATA]); 236 volume->optMPathTblLoc[MSB_DATA] = *(uint16*)buffer; 237 buffer += sizeof(volume->optMPathTblLoc[MSB_DATA]); 238 239 // Fill in directory record. 240 volume->joliet_level = 0; 241 InitNode(volume, &volume->rootDirRec, buffer, NULL); 242 243 volume->rootDirRec.id = ISO_ROOTNODE_ID; 244 buffer += ISO_ROOT_DIR_REC_SIZE; 245 246 const size_t kVolSetIDStringLen = sizeof(volume->volSetIDString) - 1; 247 volume->volSetIDString[kVolSetIDStringLen] = '\0'; 248 strncpy(volume->volSetIDString, buffer, kVolSetIDStringLen); 249 buffer += kVolSetIDStringLen; 250 TRACE(("InitVolDesc - volume set id string is %s\n", volume->volSetIDString)); 251 252 const size_t kPubIDStringLen = sizeof(volume->pubIDString) - 1; 253 volume->pubIDString[kPubIDStringLen] = '\0'; 254 strncpy(volume->pubIDString, buffer, kPubIDStringLen); 255 buffer += kPubIDStringLen; 256 TRACE(("InitVolDesc - volume pub id string is %s\n", volume->pubIDString)); 257 258 const size_t kDataPreparerLen = sizeof(volume->dataPreparer) - 1; 259 volume->dataPreparer[kDataPreparerLen] = '\0'; 260 strncpy(volume->dataPreparer, buffer, kDataPreparerLen); 261 buffer += kDataPreparerLen; 262 TRACE(("InitVolDesc - volume dataPreparer string is %s\n", volume->dataPreparer)); 263 264 const size_t kAppIDStringLen = sizeof(volume->appIDString) - 1; 265 volume->appIDString[kAppIDStringLen] = '\0'; 266 strncpy(volume->appIDString, buffer, kAppIDStringLen); 267 buffer += kAppIDStringLen; 268 TRACE(("InitVolDesc - volume app id string is %s\n", volume->appIDString)); 269 270 const size_t kCopyrightLen = sizeof(volume->copyright) - 1; 271 volume->copyright[kCopyrightLen] = '\0'; 272 strncpy(volume->copyright, buffer, kCopyrightLen); 273 buffer += kCopyrightLen; 274 TRACE(("InitVolDesc - copyright is %s\n", volume->copyright)); 275 276 const size_t kAbstractFNameLen = sizeof(volume->abstractFName) - 1; 277 volume->abstractFName[kAbstractFNameLen] = '\0'; 278 strncpy(volume->abstractFName, buffer, kAbstractFNameLen); 279 buffer += kAbstractFNameLen; 280 281 const size_t kBiblioFNameLen = sizeof(volume->biblioFName) - 1; 282 volume->biblioFName[kBiblioFNameLen] = '\0'; 283 strncpy(volume->biblioFName, buffer, kBiblioFNameLen); 284 buffer += kBiblioFNameLen; 285 286 init_volume_date(&volume->createDate, buffer); 287 buffer += ISO_VOL_DATE_SIZE; 288 289 init_volume_date(&volume->modDate, buffer); 290 buffer += ISO_VOL_DATE_SIZE; 291 292 init_volume_date(&volume->expireDate, buffer); 293 buffer += ISO_VOL_DATE_SIZE; 294 295 init_volume_date(&volume->effectiveDate, buffer); 296 buffer += ISO_VOL_DATE_SIZE; 297 298 volume->fileStructVers = *(uint8*)buffer; 299 return B_OK; 300 } 301 302 303 static status_t 304 parse_rock_ridge(iso9660_volume* volume, iso9660_inode* node, char* buffer, 305 char* end, bool relocated) 306 { 307 // Now we're at the start of the rock ridge stuff 308 char* altName = NULL; 309 char* slName = NULL; 310 char* newSlName = NULL; 311 uint16 altNameSize = 0; 312 uint16 slNameSize = 0; 313 uint8 length = 0; 314 bool done = false; 315 316 TRACE(("RR: Start of extensions at %p\n", buffer)); 317 318 while (!done) { 319 buffer += length; 320 if (buffer + 2 >= end) 321 break; 322 length = *(uint8*)(buffer + 2); 323 if (buffer + length > end) 324 break; 325 if (length == 0) 326 break; 327 328 switch (((int)buffer[0] << 8) + buffer[1]) { 329 // Stat structure stuff 330 case 'PX': 331 { 332 uint8 bytePos = 3; 333 TRACE(("RR: found PX, length %u\n", length)); 334 node->attr.pxVer = *(uint8*)(buffer + bytePos++); 335 336 // st_mode 337 node->attr.stat[LSB_DATA].st_mode 338 = *(mode_t*)(buffer + bytePos); 339 bytePos += 4; 340 node->attr.stat[MSB_DATA].st_mode 341 = *(mode_t*)(buffer + bytePos); 342 bytePos += 4; 343 344 // st_nlink 345 node->attr.stat[LSB_DATA].st_nlink 346 = *(nlink_t*)(buffer+bytePos); 347 bytePos += 4; 348 node->attr.stat[MSB_DATA].st_nlink 349 = *(nlink_t*)(buffer + bytePos); 350 bytePos += 4; 351 352 // st_uid 353 node->attr.stat[LSB_DATA].st_uid 354 = *(uid_t*)(buffer + bytePos); 355 bytePos += 4; 356 node->attr.stat[MSB_DATA].st_uid 357 = *(uid_t*)(buffer + bytePos); 358 bytePos += 4; 359 360 // st_gid 361 node->attr.stat[LSB_DATA].st_gid 362 = *(gid_t*)(buffer + bytePos); 363 bytePos += 4; 364 node->attr.stat[MSB_DATA].st_gid 365 = *(gid_t*)(buffer + bytePos); 366 bytePos += 4; 367 break; 368 } 369 370 case 'PN': 371 TRACE(("RR: found PN, length %u\n", length)); 372 break; 373 374 // Symbolic link info 375 case 'SL': 376 { 377 uint8 bytePos = 3; 378 uint8 addPos = 0; 379 bool slDone = false; 380 bool useSeparator = true; 381 382 TRACE(("RR: found SL, length %u\n", length)); 383 TRACE(("Buffer is at %p\n", buffer)); 384 TRACE(("Current length is %u\n", slNameSize)); 385 //kernel_debugger(""); 386 node->attr.slVer = *(uint8*)(buffer + bytePos++); 387 #if TRACE_ISO9660 388 uint8 slFlags = *(uint8*)(buffer + bytePos++); 389 TRACE(("sl flags are %u\n", slFlags)); 390 #else 391 // skip symlink flags 392 ++bytePos; 393 #endif 394 while (!slDone && bytePos < length) { 395 uint8 compFlag = *(uint8*)(buffer + bytePos++); 396 uint8 compLen = *(uint8*)(buffer + bytePos++); 397 398 if (slName == NULL) 399 useSeparator = false; 400 401 addPos = slNameSize; 402 403 TRACE(("sl comp flags are %u, length is %u\n", compFlag, compLen)); 404 TRACE(("Current name size is %u\n", slNameSize)); 405 406 switch (compFlag) { 407 case SLCP_CONTINUE: 408 useSeparator = false; 409 default: 410 // Add the component to the total path. 411 slNameSize += compLen; 412 if (useSeparator) 413 slNameSize++; 414 newSlName = (char*)realloc(slName, 415 slNameSize + 1); 416 if (newSlName == NULL) { 417 free(slName); 418 return B_NO_MEMORY; 419 } 420 slName = newSlName; 421 422 if (useSeparator) { 423 TRACE(("Adding separator\n")); 424 slName[addPos++] = '/'; 425 } 426 427 TRACE(("doing memcopy of %u bytes at offset %d\n", compLen, addPos)); 428 memcpy(slName + addPos, buffer + bytePos, 429 compLen); 430 431 addPos += compLen; 432 useSeparator = true; 433 break; 434 435 case SLCP_CURRENT: 436 TRACE(("InitNode - found link to current directory\n")); 437 slNameSize += 2; 438 newSlName = (char*)realloc(slName, 439 slNameSize + 1); 440 if (newSlName == NULL) { 441 free(slName); 442 return B_NO_MEMORY; 443 } 444 slName = newSlName; 445 446 memcpy(slName + addPos, "./", 2); 447 useSeparator = false; 448 break; 449 450 case SLCP_PARENT: 451 slNameSize += 3; 452 newSlName = (char*)realloc(slName, 453 slNameSize + 1); 454 if (newSlName == NULL) { 455 free(slName); 456 return B_NO_MEMORY; 457 } 458 slName = newSlName; 459 460 memcpy(slName + addPos, "../", 3); 461 useSeparator = false; 462 break; 463 464 case SLCP_ROOT: 465 TRACE(("InitNode - found link to root directory\n")); 466 slNameSize += 1; 467 newSlName = (char*)realloc(slName, 468 slNameSize + 1); 469 if (newSlName == NULL) { 470 free(slName); 471 return B_NO_MEMORY; 472 } 473 slName = newSlName; 474 memcpy(slName + addPos, "/", 1); 475 useSeparator = false; 476 break; 477 478 case SLCP_VOLROOT: 479 slDone = true; 480 break; 481 482 case SLCP_HOST: 483 slDone = true; 484 break; 485 } 486 if (slName != NULL) 487 slName[slNameSize] = '\0'; 488 bytePos += compLen; 489 TRACE(("Current sl name is \'%s\'\n", slName)); 490 } 491 node->attr.slName = slName; 492 TRACE(("InitNode = symlink name is \'%s\'\n", slName)); 493 break; 494 } 495 496 // Altername name 497 case 'NM': 498 { 499 uint8 bytePos = 3; 500 uint8 flags = 0; 501 uint16 oldEnd = altNameSize; 502 503 altNameSize += length - 5; 504 char* newAltName = (char*)realloc(altName, altNameSize + 1); 505 if (newAltName == NULL) { 506 free(altName); 507 return B_NO_MEMORY; 508 } 509 altName = newAltName; 510 511 TRACE(("RR: found NM, length %u\n", length)); 512 // Read flag and version. 513 node->attr.nmVer = *(uint8 *)(buffer + bytePos++); 514 flags = *(uint8 *)(buffer + bytePos++); 515 516 TRACE(("RR: nm buffer is %s, start at %p\n", (buffer + bytePos), 517 buffer + bytePos)); 518 519 // Build the file name. 520 memcpy(altName + oldEnd, buffer + bytePos, length - 5); 521 altName[altNameSize] = '\0'; 522 TRACE(("RR: alt name is %s\n", altName)); 523 524 // If the name is not continued in another record, update 525 // the record name. 526 if (!(flags & NM_CONTINUE)) { 527 // Get rid of the ISO name, replace with RR name. 528 if (node->name != NULL) 529 free(node->name); 530 node->name = altName; 531 node->name_length = altNameSize; 532 } 533 break; 534 } 535 536 // Deep directory record masquerading as a file. 537 case 'CL': 538 { 539 TRACE(("RR: found CL, length %u\n", length)); 540 // Reinitialize the node with the information at the 541 // "." entry of the pointed to directory data 542 node->startLBN[LSB_DATA] = *(uint32*)(buffer+4); 543 node->startLBN[MSB_DATA] = *(uint32*)(buffer+8); 544 545 char* buffer = (char*)block_cache_get(volume->fBlockCache, 546 node->startLBN[FS_DATA_FORMAT]); 547 if (buffer == NULL) 548 break; 549 550 InitNode(volume, node, buffer, NULL, true); 551 block_cache_put(volume->fBlockCache, 552 node->startLBN[FS_DATA_FORMAT]); 553 break; 554 } 555 556 case 'PL': 557 TRACE(("RR: found PL, length %u\n", length)); 558 break; 559 560 case 'RE': 561 // Relocated directory, we should skip. 562 TRACE(("RR: found RE, length %u\n", length)); 563 if (!relocated) 564 return B_UNSUPPORTED; 565 break; 566 567 case 'TF': 568 TRACE(("RR: found TF, length %u\n", length)); 569 break; 570 571 case 'RR': 572 TRACE(("RR: found RR, length %u\n", length)); 573 break; 574 575 case 'SF': 576 TRACE(("RR: found SF, sparse files not supported!\n")); 577 // TODO: support sparse files 578 return B_UNSUPPORTED; 579 580 default: 581 if (buffer[0] == '\0') { 582 TRACE(("RR: end of extensions\n")); 583 done = true; 584 } else 585 TRACE(("RR: Unknown tag %c%c\n", buffer[0], buffer[1])); 586 break; 587 } 588 } 589 590 return B_OK; 591 } 592 593 // #pragma mark - ISO-9660 specific exported functions 594 595 596 status_t 597 ISOMount(const char *path, uint32 flags, iso9660_volume **_newVolume, 598 bool allowJoliet) 599 { 600 // path: path to device (eg, /dev/disk/scsi/030/raw) 601 // partition: partition number on device ???? 602 // flags: currently unused 603 604 // determine if it is an ISO volume. 605 char buffer[ISO_PVD_SIZE]; 606 bool done = false; 607 bool isISO = false; 608 off_t offset = 0x8000; 609 ssize_t retval; 610 partition_info partitionInfo; 611 int deviceBlockSize; 612 iso9660_volume *volume; 613 614 (void)flags; 615 616 TRACE(("ISOMount - ENTER\n")); 617 618 volume = (iso9660_volume *)calloc(sizeof(iso9660_volume), 1); 619 if (volume == NULL) { 620 TRACE(("ISOMount - mem error \n")); 621 return B_NO_MEMORY; 622 } 623 624 memset(&partitionInfo, 0, sizeof(partition_info)); 625 626 /* open and lock the device */ 627 volume->fdOfSession = open(path, O_RDONLY); 628 629 /* try to open the raw device to get access to the other sessions as well */ 630 if (volume->fdOfSession >= 0) { 631 if (ioctl(volume->fdOfSession, B_GET_PARTITION_INFO, &partitionInfo, 632 sizeof(partition_info)) < 0) { 633 TRACE(("B_GET_PARTITION_INFO: ioctl returned error\n")); 634 strcpy(partitionInfo.device, path); 635 } 636 TRACE(("ISOMount: open device/file \"%s\"\n", partitionInfo.device)); 637 638 volume->fd = open(partitionInfo.device, O_RDONLY); 639 } 640 641 if (volume->fdOfSession < 0 || volume->fd < 0) { 642 close(volume->fd); 643 close(volume->fdOfSession); 644 645 TRACE(("ISO9660 ERROR - Unable to open <%s>\n", path)); 646 free(volume); 647 return B_BAD_VALUE; 648 } 649 650 deviceBlockSize = get_device_block_size(volume->fdOfSession); 651 if (deviceBlockSize < 0) { 652 TRACE(("ISO9660 ERROR - device block size is 0\n")); 653 close(volume->fd); 654 close(volume->fdOfSession); 655 656 free(volume); 657 return B_BAD_VALUE; 658 } 659 660 volume->joliet_level = 0; 661 while (!done && offset < 0x10000) { 662 retval = read_pos(volume->fdOfSession, offset, (void*)buffer, 663 ISO_PVD_SIZE); 664 if (retval < ISO_PVD_SIZE) { 665 isISO = false; 666 break; 667 } 668 669 if (strncmp(buffer + 1, kISO9660IDString, 5) == 0) { 670 if (*buffer == 0x01 && !isISO) { 671 // ISO_VD_PRIMARY 672 off_t maxBlocks; 673 674 TRACE(("ISOMount: Is an ISO9660 volume, initting rec\n")); 675 676 InitVolDesc(volume, buffer); 677 strncpy(volume->devicePath,path,127); 678 volume->id = ISO_ROOTNODE_ID; 679 TRACE(("ISO9660: volume->blockSize = %d\n", volume->logicalBlkSize[FS_DATA_FORMAT])); 680 681 #if TRACE_ISO9660 682 int multiplier = deviceBlockSize / volume->logicalBlkSize[FS_DATA_FORMAT]; 683 TRACE(("ISOMount: block size multiplier is %d\n", multiplier)); 684 #endif 685 686 // if the session is on a real device, size != 0 687 if (partitionInfo.size != 0) { 688 maxBlocks = (partitionInfo.size + partitionInfo.offset) 689 / volume->logicalBlkSize[FS_DATA_FORMAT]; 690 } else 691 maxBlocks = volume->volSpaceSize[FS_DATA_FORMAT]; 692 693 /* Initialize access to the cache so that we can do cached i/o */ 694 TRACE(("ISO9660: cache init: dev %d, max blocks %lld\n", volume->fd, maxBlocks)); 695 volume->fBlockCache = block_cache_create(volume->fd, maxBlocks, 696 volume->logicalBlkSize[FS_DATA_FORMAT], true); 697 isISO = true; 698 } else if (*buffer == 0x02 && isISO && allowJoliet) { 699 // ISO_VD_SUPPLEMENTARY 700 701 // JOLIET extension 702 // test escape sequence for level of UCS-2 characterset 703 if (buffer[88] == 0x25 && buffer[89] == 0x2f) { 704 switch (buffer[90]) { 705 case 0x40: volume->joliet_level = 1; break; 706 case 0x43: volume->joliet_level = 2; break; 707 case 0x45: volume->joliet_level = 3; break; 708 } 709 710 TRACE(("ISO9660 Extensions: Microsoft Joliet Level %d\n", volume->joliet_level)); 711 712 // Because Joliet-stuff starts at other sector, 713 // update root directory record. 714 if (volume->joliet_level > 0) { 715 InitNode(volume, &volume->rootDirRec, &buffer[156], 716 NULL); 717 } 718 } 719 } else if (*(unsigned char *)buffer == 0xff) { 720 // ISO_VD_END 721 done = true; 722 } else 723 TRACE(("found header %d\n",*buffer)); 724 } 725 offset += 0x800; 726 } 727 728 if (!isISO) { 729 // It isn't an ISO disk. 730 close(volume->fdOfSession); 731 close(volume->fd); 732 free(volume); 733 734 TRACE(("ISOMount: Not an ISO9660 volume!\n")); 735 return B_BAD_VALUE; 736 } 737 738 TRACE(("ISOMount - EXIT, returning %p\n", volume)); 739 *_newVolume = volume; 740 return B_OK; 741 } 742 743 744 /*! Reads in a single directory entry and fills in the values in the 745 dirent struct. Uses the cookie to keep track of the current block 746 and position within the block. Also uses the cookie to determine when 747 it has reached the end of the directory file. 748 */ 749 status_t 750 ISOReadDirEnt(iso9660_volume *volume, dircookie *cookie, struct dirent *dirent, 751 size_t bufferSize) 752 { 753 int result = B_NO_ERROR; 754 bool done = false; 755 756 TRACE(("ISOReadDirEnt - ENTER\n")); 757 758 while (!done) { 759 off_t totalRead = cookie->pos + (cookie->block - cookie->startBlock) 760 * volume->logicalBlkSize[FS_DATA_FORMAT]; 761 762 // If we're at the end of the data in a block, move to the next block. 763 char *blockData; 764 while (true) { 765 blockData 766 = (char*)block_cache_get(volume->fBlockCache, cookie->block); 767 if (blockData != NULL && *(blockData + cookie->pos) == 0) { 768 // NULL data, move to next block. 769 block_cache_put(volume->fBlockCache, cookie->block); 770 blockData = NULL; 771 totalRead 772 += volume->logicalBlkSize[FS_DATA_FORMAT] - cookie->pos; 773 cookie->pos = 0; 774 cookie->block++; 775 } else 776 break; 777 778 if (totalRead >= cookie->totalSize) 779 break; 780 } 781 782 off_t cacheBlock = cookie->block; 783 784 if (blockData != NULL && totalRead < cookie->totalSize) { 785 iso9660_inode node; 786 size_t bytesRead = 0; 787 result = InitNode(volume, &node, blockData + cookie->pos, 788 &bytesRead); 789 790 // if we hit an entry that we don't support, we just skip it 791 if (result != B_OK && result != B_UNSUPPORTED) 792 break; 793 794 if (result == B_OK && (node.flags & ISO_IS_ASSOCIATED_FILE) == 0) { 795 size_t nameBufferSize = bufferSize - offsetof(struct dirent, d_name); 796 797 dirent->d_dev = volume->id; 798 dirent->d_ino = ((ino_t)cookie->block << 30) 799 + (cookie->pos & 0x3fffffff); 800 dirent->d_reclen = offsetof(struct dirent, d_name) + node.name_length + 1; 801 802 if (node.name_length <= nameBufferSize) { 803 // need to do some size checking here. 804 strlcpy(dirent->d_name, node.name, node.name_length + 1); 805 TRACE(("ISOReadDirEnt - success, name is %s, block %lld, " 806 "pos %lld, inode id %lld\n", dirent->d_name, cookie->block, 807 cookie->pos, dirent->d_ino)); 808 } else { 809 // TODO: this can be just normal if we support reading more 810 // than one entry. 811 TRACE(("ISOReadDirEnt - ERROR, name %s does not fit in " 812 "buffer of size %d\n", node.name, (int)nameBufferSize)); 813 result = B_BAD_VALUE; 814 } 815 816 done = true; 817 } 818 819 cookie->pos += bytesRead; 820 821 if (cookie->pos == volume->logicalBlkSize[FS_DATA_FORMAT]) { 822 cookie->pos = 0; 823 cookie->block++; 824 } 825 } else { 826 if (totalRead >= cookie->totalSize) 827 result = B_ENTRY_NOT_FOUND; 828 else 829 result = B_NO_MEMORY; 830 done = true; 831 } 832 833 if (blockData != NULL) 834 block_cache_put(volume->fBlockCache, cacheBlock); 835 } 836 837 TRACE(("ISOReadDirEnt - EXIT, result is %s, vnid is %Lu\n", 838 strerror(result), dirent->d_ino)); 839 840 return result; 841 } 842 843 844 status_t 845 InitNode(iso9660_volume* volume, iso9660_inode* node, char* buffer, 846 size_t* _bytesRead, bool relocated) 847 { 848 uint8 recordLength = *(uint8*)buffer++; 849 size_t nameLength; 850 851 TRACE(("InitNode - ENTER, bufstart is %p, record length is %d bytes\n", 852 buffer, recordLength)); 853 854 if (_bytesRead != NULL) 855 *_bytesRead = recordLength; 856 if (recordLength == 0) 857 return B_ENTRY_NOT_FOUND; 858 859 char* end = buffer + recordLength; 860 861 if (!relocated) { 862 node->cache = NULL; 863 node->name = NULL; 864 node->attr.slName = NULL; 865 memset(node->attr.stat, 0, sizeof(node->attr.stat)); 866 } else 867 free(node->attr.slName); 868 869 node->extAttrRecLen = *(uint8*)buffer++; 870 TRACE(("InitNode - ext attr length is %d\n", (int)node->extAttrRecLen)); 871 872 node->startLBN[LSB_DATA] = *(uint32*)buffer; 873 buffer += 4; 874 node->startLBN[MSB_DATA] = *(uint32*)buffer; 875 buffer += 4; 876 TRACE(("InitNode - data start LBN is %d\n", 877 (int)node->startLBN[FS_DATA_FORMAT])); 878 879 node->dataLen[LSB_DATA] = *(uint32*)buffer; 880 buffer += 4; 881 node->dataLen[MSB_DATA] = *(uint32*)buffer; 882 buffer += 4; 883 TRACE(("InitNode - data length is %d\n", 884 (int)node->dataLen[FS_DATA_FORMAT])); 885 886 init_node_date(&node->recordDate, buffer); 887 buffer += 7; 888 889 node->flags = *(uint8*)buffer; 890 buffer++; 891 TRACE(("InitNode - flags are %d\n", node->flags)); 892 893 node->fileUnitSize = *(uint8*)buffer; 894 buffer++; 895 TRACE(("InitNode - fileUnitSize is %d\n", node->fileUnitSize)); 896 897 node->interleaveGapSize = *(uint8*)buffer; 898 buffer++; 899 TRACE(("InitNode - interleave gap size = %d\n", node->interleaveGapSize)); 900 901 node->volSeqNum = *(uint32*)buffer; 902 buffer += 4; 903 TRACE(("InitNode - volume seq num is %d\n", (int)node->volSeqNum)); 904 905 nameLength = *(uint8*)buffer; 906 buffer++; 907 908 // for relocated directories we take the name from the placeholder entry 909 if (!relocated) { 910 node->name_length = nameLength; 911 TRACE(("InitNode - file id length is %" B_PRIu32 "\n", 912 node->name_length)); 913 } 914 915 // Set defaults, in case there is no RockRidge stuff. 916 node->attr.stat[FS_DATA_FORMAT].st_mode |= (node->flags & ISO_IS_DIR) != 0 917 ? S_IFDIR | S_IXUSR | S_IRUSR | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH 918 : S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; 919 920 if (node->name_length == 0) { 921 TRACE(("InitNode - File ID String is 0 length\n")); 922 return B_ENTRY_NOT_FOUND; 923 } 924 925 if (!relocated) { 926 // JOLIET extension: 927 // on joliet discs, buffer[0] can be 0 for Unicoded filenames, 928 // so I've added a check here to test explicitely for 929 // directories (which have length 1) 930 // Take care of "." and "..", the first two dirents are 931 // these in iso. 932 if (node->name_length == 1 && buffer[0] == 0) { 933 node->name = strdup("."); 934 node->name_length = 1; 935 } else if (node->name_length == 1 && buffer[0] == 1) { 936 node->name = strdup(".."); 937 node->name_length = 2; 938 } else if (volume->joliet_level > 0) { 939 // JOLIET extension: convert Unicode16 string to UTF8 940 // Assume that the unicode->utf8 conversion produces 4 byte 941 // utf8 characters, and allocate that much space 942 node->name = (char*)malloc(node->name_length * 2 + 1); 943 if (node->name == NULL) 944 return B_NO_MEMORY; 945 946 int32 sourceLength = node->name_length; 947 int32 destLength = node->name_length * 2; 948 949 status_t status = unicode_to_utf8(buffer, &sourceLength, 950 node->name, &destLength); 951 if (status < B_OK) { 952 dprintf("iso9660: error converting unicode->utf8\n"); 953 return status; 954 } 955 956 node->name[destLength] = '\0'; 957 node->name_length = destLength; 958 959 sanitize_iso_name(node, false); 960 } else { 961 node->name = (char*)malloc(node->name_length + 1); 962 if (node->name == NULL) 963 return B_NO_MEMORY; 964 965 // convert all characters to lower case 966 for (uint32 i = 0; i < node->name_length; i++) 967 node->name[i] = tolower(buffer[i]); 968 969 node->name[node->name_length] = '\0'; 970 971 sanitize_iso_name(node, true); 972 } 973 974 if (node->name == NULL) { 975 TRACE(("InitNode - unable to allocate memory!\n")); 976 return B_NO_MEMORY; 977 } 978 } 979 980 buffer += nameLength; 981 if (nameLength % 2 == 0) 982 buffer++; 983 984 TRACE(("DirRec ID String is: %s\n", node->name)); 985 986 return parse_rock_ridge(volume, node, buffer, end, relocated); 987 } 988 989 990 status_t 991 ConvertRecDate(ISORecDate* inDate, time_t* outDate) 992 { 993 time_t time; 994 int days, i, year; 995 int8_t tz; 996 997 year = inDate->year - 70; 998 tz = inDate->offsetGMT; 999 1000 if (year < 0) { 1001 time = 0; 1002 } else { 1003 const int monlen[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 1004 1005 days = (year * 365); 1006 1007 if (year > 2) 1008 days += (year + 1)/ 4; 1009 1010 for (i = 1; (i < inDate->month) && (i < 12); i++) { 1011 days += monlen[i-1]; 1012 } 1013 1014 if (((year + 2) % 4) == 0 && inDate->month > 2) 1015 days++; 1016 1017 days += inDate->date - 1; 1018 time = ((((days*24) + inDate->hour) * 60 + inDate->minute) * 60) 1019 + inDate->second; 1020 1021 if (-48 <= tz && tz <= 52) 1022 time -= tz * 15 * 60; 1023 } 1024 *outDate = time; 1025 return 0; 1026 } 1027 1028