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) < 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) < 0) { 632 TRACE(("B_GET_PARTITION_INFO: ioctl returned error\n")); 633 strcpy(partitionInfo.device, path); 634 } 635 TRACE(("ISOMount: open device/file \"%s\"\n", partitionInfo.device)); 636 637 volume->fd = open(partitionInfo.device, O_RDONLY); 638 } 639 640 if (volume->fdOfSession < 0 || volume->fd < 0) { 641 close(volume->fd); 642 close(volume->fdOfSession); 643 644 TRACE(("ISO9660 ERROR - Unable to open <%s>\n", path)); 645 free(volume); 646 return B_BAD_VALUE; 647 } 648 649 deviceBlockSize = get_device_block_size(volume->fdOfSession); 650 if (deviceBlockSize < 0) { 651 TRACE(("ISO9660 ERROR - device block size is 0\n")); 652 close(volume->fd); 653 close(volume->fdOfSession); 654 655 free(volume); 656 return B_BAD_VALUE; 657 } 658 659 volume->joliet_level = 0; 660 while (!done && offset < 0x10000) { 661 retval = read_pos(volume->fdOfSession, offset, (void*)buffer, 662 ISO_PVD_SIZE); 663 if (retval < ISO_PVD_SIZE) { 664 isISO = false; 665 break; 666 } 667 668 if (strncmp(buffer + 1, kISO9660IDString, 5) == 0) { 669 if (*buffer == 0x01 && !isISO) { 670 // ISO_VD_PRIMARY 671 off_t maxBlocks; 672 673 TRACE(("ISOMount: Is an ISO9660 volume, initting rec\n")); 674 675 InitVolDesc(volume, buffer); 676 strncpy(volume->devicePath,path,127); 677 volume->id = ISO_ROOTNODE_ID; 678 TRACE(("ISO9660: volume->blockSize = %d\n", volume->logicalBlkSize[FS_DATA_FORMAT])); 679 680 #if TRACE_ISO9660 681 int multiplier = deviceBlockSize / volume->logicalBlkSize[FS_DATA_FORMAT]; 682 TRACE(("ISOMount: block size multiplier is %d\n", multiplier)); 683 #endif 684 685 // if the session is on a real device, size != 0 686 if (partitionInfo.size != 0) { 687 maxBlocks = (partitionInfo.size + partitionInfo.offset) 688 / volume->logicalBlkSize[FS_DATA_FORMAT]; 689 } else 690 maxBlocks = volume->volSpaceSize[FS_DATA_FORMAT]; 691 692 /* Initialize access to the cache so that we can do cached i/o */ 693 TRACE(("ISO9660: cache init: dev %d, max blocks %Ld\n", volume->fd, maxBlocks)); 694 volume->fBlockCache = block_cache_create(volume->fd, maxBlocks, 695 volume->logicalBlkSize[FS_DATA_FORMAT], true); 696 isISO = true; 697 } else if (*buffer == 0x02 && isISO && allowJoliet) { 698 // ISO_VD_SUPPLEMENTARY 699 700 // JOLIET extension 701 // test escape sequence for level of UCS-2 characterset 702 if (buffer[88] == 0x25 && buffer[89] == 0x2f) { 703 switch (buffer[90]) { 704 case 0x40: volume->joliet_level = 1; break; 705 case 0x43: volume->joliet_level = 2; break; 706 case 0x45: volume->joliet_level = 3; break; 707 } 708 709 TRACE(("ISO9660 Extensions: Microsoft Joliet Level %d\n", volume->joliet_level)); 710 711 // Because Joliet-stuff starts at other sector, 712 // update root directory record. 713 if (volume->joliet_level > 0) { 714 InitNode(volume, &volume->rootDirRec, &buffer[156], 715 NULL); 716 } 717 } 718 } else if (*(unsigned char *)buffer == 0xff) { 719 // ISO_VD_END 720 done = true; 721 } else 722 TRACE(("found header %d\n",*buffer)); 723 } 724 offset += 0x800; 725 } 726 727 if (!isISO) { 728 // It isn't an ISO disk. 729 close(volume->fdOfSession); 730 close(volume->fd); 731 free(volume); 732 733 TRACE(("ISOMount: Not an ISO9660 volume!\n")); 734 return B_BAD_VALUE; 735 } 736 737 TRACE(("ISOMount - EXIT, returning %p\n", volume)); 738 *_newVolume = volume; 739 return B_OK; 740 } 741 742 743 /*! Reads in a single directory entry and fills in the values in the 744 dirent struct. Uses the cookie to keep track of the current block 745 and position within the block. Also uses the cookie to determine when 746 it has reached the end of the directory file. 747 */ 748 status_t 749 ISOReadDirEnt(iso9660_volume *volume, dircookie *cookie, struct dirent *dirent, 750 size_t bufferSize) 751 { 752 int result = B_NO_ERROR; 753 bool done = false; 754 755 TRACE(("ISOReadDirEnt - ENTER\n")); 756 757 while (!done) { 758 off_t totalRead = cookie->pos + (cookie->block - cookie->startBlock) 759 * volume->logicalBlkSize[FS_DATA_FORMAT]; 760 761 // If we're at the end of the data in a block, move to the next block. 762 char *blockData; 763 while (true) { 764 blockData 765 = (char*)block_cache_get(volume->fBlockCache, cookie->block); 766 if (blockData != NULL && *(blockData + cookie->pos) == 0) { 767 // NULL data, move to next block. 768 block_cache_put(volume->fBlockCache, cookie->block); 769 blockData = NULL; 770 totalRead 771 += volume->logicalBlkSize[FS_DATA_FORMAT] - cookie->pos; 772 cookie->pos = 0; 773 cookie->block++; 774 } else 775 break; 776 777 if (totalRead >= cookie->totalSize) 778 break; 779 } 780 781 off_t cacheBlock = cookie->block; 782 783 if (blockData != NULL && totalRead < cookie->totalSize) { 784 iso9660_inode node; 785 size_t bytesRead = 0; 786 result = InitNode(volume, &node, blockData + cookie->pos, 787 &bytesRead); 788 789 // if we hit an entry that we don't support, we just skip it 790 if (result != B_OK && result != B_UNSUPPORTED) 791 break; 792 793 if (result == B_OK && (node.flags & ISO_IS_ASSOCIATED_FILE) == 0) { 794 size_t nameBufferSize = bufferSize - sizeof(struct dirent); 795 796 dirent->d_dev = volume->id; 797 dirent->d_ino = ((ino_t)cookie->block << 30) 798 + (cookie->pos & 0x3fffffff); 799 dirent->d_reclen = sizeof(struct dirent) + node.name_length + 1; 800 801 if (node.name_length <= nameBufferSize) { 802 // need to do some size checking here. 803 strlcpy(dirent->d_name, node.name, node.name_length + 1); 804 TRACE(("ISOReadDirEnt - success, name is %s, block %Ld, " 805 "pos %Ld, inode id %Ld\n", dirent->d_name, cookie->block, 806 cookie->pos, dirent->d_ino)); 807 } else { 808 // TODO: this can be just normal if we support reading more 809 // than one entry. 810 TRACE(("ISOReadDirEnt - ERROR, name %s does not fit in " 811 "buffer of size %d\n", node.name, (int)nameBufferSize)); 812 result = B_BAD_VALUE; 813 } 814 815 done = true; 816 } 817 818 cookie->pos += bytesRead; 819 820 if (cookie->pos == volume->logicalBlkSize[FS_DATA_FORMAT]) { 821 cookie->pos = 0; 822 cookie->block++; 823 } 824 } else { 825 if (totalRead >= cookie->totalSize) 826 result = B_ENTRY_NOT_FOUND; 827 else 828 result = B_NO_MEMORY; 829 done = true; 830 } 831 832 if (blockData != NULL) 833 block_cache_put(volume->fBlockCache, cacheBlock); 834 } 835 836 TRACE(("ISOReadDirEnt - EXIT, result is %s, vnid is %Lu\n", 837 strerror(result), dirent->d_ino)); 838 839 return result; 840 } 841 842 843 status_t 844 InitNode(iso9660_volume* volume, iso9660_inode* node, char* buffer, 845 size_t* _bytesRead, bool relocated) 846 { 847 uint8 recordLength = *(uint8*)buffer++; 848 size_t nameLength; 849 850 TRACE(("InitNode - ENTER, bufstart is %p, record length is %d bytes\n", 851 buffer, recordLength)); 852 853 if (_bytesRead != NULL) 854 *_bytesRead = recordLength; 855 if (recordLength == 0) 856 return B_ENTRY_NOT_FOUND; 857 858 char* end = buffer + recordLength; 859 860 if (!relocated) { 861 node->cache = NULL; 862 node->name = NULL; 863 node->attr.slName = NULL; 864 memset(node->attr.stat, 0, sizeof(node->attr.stat)); 865 } else 866 free(node->attr.slName); 867 868 node->extAttrRecLen = *(uint8*)buffer++; 869 TRACE(("InitNode - ext attr length is %d\n", (int)node->extAttrRecLen)); 870 871 node->startLBN[LSB_DATA] = *(uint32*)buffer; 872 buffer += 4; 873 node->startLBN[MSB_DATA] = *(uint32*)buffer; 874 buffer += 4; 875 TRACE(("InitNode - data start LBN is %d\n", 876 (int)node->startLBN[FS_DATA_FORMAT])); 877 878 node->dataLen[LSB_DATA] = *(uint32*)buffer; 879 buffer += 4; 880 node->dataLen[MSB_DATA] = *(uint32*)buffer; 881 buffer += 4; 882 TRACE(("InitNode - data length is %d\n", 883 (int)node->dataLen[FS_DATA_FORMAT])); 884 885 init_node_date(&node->recordDate, buffer); 886 buffer += 7; 887 888 node->flags = *(uint8*)buffer; 889 buffer++; 890 TRACE(("InitNode - flags are %d\n", node->flags)); 891 892 node->fileUnitSize = *(uint8*)buffer; 893 buffer++; 894 TRACE(("InitNode - fileUnitSize is %d\n", node->fileUnitSize)); 895 896 node->interleaveGapSize = *(uint8*)buffer; 897 buffer++; 898 TRACE(("InitNode - interleave gap size = %d\n", node->interleaveGapSize)); 899 900 node->volSeqNum = *(uint32*)buffer; 901 buffer += 4; 902 TRACE(("InitNode - volume seq num is %d\n", (int)node->volSeqNum)); 903 904 nameLength = *(uint8*)buffer; 905 buffer++; 906 907 // for relocated directories we take the name from the placeholder entry 908 if (!relocated) { 909 node->name_length = nameLength; 910 TRACE(("InitNode - file id length is %" B_PRIu32 "\n", 911 node->name_length)); 912 } 913 914 // Set defaults, in case there is no RockRidge stuff. 915 node->attr.stat[FS_DATA_FORMAT].st_mode |= (node->flags & ISO_IS_DIR) != 0 916 ? S_IFDIR | S_IXUSR | S_IRUSR | S_IXGRP | S_IRGRP | S_IXOTH | S_IROTH 917 : S_IFREG | S_IRUSR | S_IRGRP | S_IROTH; 918 919 if (node->name_length == 0) { 920 TRACE(("InitNode - File ID String is 0 length\n")); 921 return B_ENTRY_NOT_FOUND; 922 } 923 924 if (!relocated) { 925 // JOLIET extension: 926 // on joliet discs, buffer[0] can be 0 for Unicoded filenames, 927 // so I've added a check here to test explicitely for 928 // directories (which have length 1) 929 // Take care of "." and "..", the first two dirents are 930 // these in iso. 931 if (node->name_length == 1 && buffer[0] == 0) { 932 node->name = strdup("."); 933 node->name_length = 1; 934 } else if (node->name_length == 1 && buffer[0] == 1) { 935 node->name = strdup(".."); 936 node->name_length = 2; 937 } else if (volume->joliet_level > 0) { 938 // JOLIET extension: convert Unicode16 string to UTF8 939 // Assume that the unicode->utf8 conversion produces 4 byte 940 // utf8 characters, and allocate that much space 941 node->name = (char*)malloc(node->name_length * 2 + 1); 942 if (node->name == NULL) 943 return B_NO_MEMORY; 944 945 int32 sourceLength = node->name_length; 946 int32 destLength = node->name_length * 2; 947 948 status_t status = unicode_to_utf8(buffer, &sourceLength, 949 node->name, &destLength); 950 if (status < B_OK) { 951 dprintf("iso9660: error converting unicode->utf8\n"); 952 return status; 953 } 954 955 node->name[destLength] = '\0'; 956 node->name_length = destLength; 957 958 sanitize_iso_name(node, false); 959 } else { 960 node->name = (char*)malloc(node->name_length + 1); 961 if (node->name == NULL) 962 return B_NO_MEMORY; 963 964 // convert all characters to lower case 965 for (uint32 i = 0; i < node->name_length; i++) 966 node->name[i] = tolower(buffer[i]); 967 968 node->name[node->name_length] = '\0'; 969 970 sanitize_iso_name(node, true); 971 } 972 973 if (node->name == NULL) { 974 TRACE(("InitNode - unable to allocate memory!\n")); 975 return B_NO_MEMORY; 976 } 977 } 978 979 buffer += nameLength; 980 if (nameLength % 2 == 0) 981 buffer++; 982 983 TRACE(("DirRec ID String is: %s\n", node->name)); 984 985 return parse_rock_ridge(volume, node, buffer, end, relocated); 986 } 987 988 989 status_t 990 ConvertRecDate(ISORecDate* inDate, time_t* outDate) 991 { 992 time_t time; 993 int days, i, year; 994 int8_t tz; 995 996 year = inDate->year - 70; 997 tz = inDate->offsetGMT; 998 999 if (year < 0) { 1000 time = 0; 1001 } else { 1002 const int monlen[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 1003 1004 days = (year * 365); 1005 1006 if (year > 2) 1007 days += (year + 1)/ 4; 1008 1009 for (i = 1; (i < inDate->month) && (i < 12); i++) { 1010 days += monlen[i-1]; 1011 } 1012 1013 if (((year + 2) % 4) == 0 && inDate->month > 2) 1014 days++; 1015 1016 days += inDate->date - 1; 1017 time = ((((days*24) + inDate->hour) * 60 + inDate->minute) * 60) 1018 + inDate->second; 1019 1020 if (-48 <= tz && tz <= 52) 1021 time -= tz * 15 * 60; 1022 } 1023 *outDate = time; 1024 return 0; 1025 } 1026 1027