status_t read_table_of_contents(int fd, scsi_toc_toc *toc, size_t length) { status_t status = read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_TOC, (uint8*)toc, length); if (status < B_OK) return status; // make sure the values in the TOC make sense int32 lastTrack = toc->last_track + 1 - toc->first_track; size_t dataLength = B_BENDIAN_TO_HOST_INT16(toc->data_length) + 2; if (dataLength < sizeof(scsi_toc_toc) || lastTrack <= 0) return B_BAD_DATA; if (length > dataLength) length = dataLength; length -= sizeof(scsi_toc_general); if (lastTrack * sizeof(scsi_toc_track) > length) toc->last_track = length / sizeof(scsi_toc_track) + toc->first_track; dump_toc(toc); return B_OK; }
void AHCIPort::ScsiUnmap(scsi_ccb* request, scsi_unmap_parameter_list* unmapBlocks) { // Determine how many ranges we'll need // We assume that the SCSI unmap ranges cannot be merged together uint32 scsiRangeCount = B_BENDIAN_TO_HOST_INT16( unmapBlocks->block_data_length) / sizeof(scsi_unmap_block_descriptor); uint32 lbaRangeCount = 0; for (uint32 i = 0; i < scsiRangeCount; i++) { lbaRangeCount += ((uint32)B_BENDIAN_TO_HOST_INT32( unmapBlocks->blocks[i].block_count) + 65534) / 65535; } uint32 lbaRangesSize = lbaRangeCount * sizeof(uint64); uint64* lbaRanges = (uint64*)malloc(lbaRangesSize); if (lbaRanges == NULL) { TRACE("out of memory when allocating %" B_PRIu32 " unmap ranges\n", lbaRangeCount); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); return; } MemoryDeleter deleter(lbaRanges); for (uint32 i = 0, scsiIndex = 0; scsiIndex < scsiRangeCount; scsiIndex++) { uint64 lba = (uint64)B_BENDIAN_TO_HOST_INT64( unmapBlocks->blocks[scsiIndex].lba); uint64 blocksLeft = (uint32)B_BENDIAN_TO_HOST_INT32( unmapBlocks->blocks[scsiIndex].block_count); while (blocksLeft > 0) { uint16 blocks = blocksLeft > 65535 ? 65535 : (uint16)blocksLeft; lbaRanges[i++] = B_HOST_TO_LENDIAN_INT64( ((uint64)blocks << 48) | lba); lba += blocks; blocksLeft -= blocks; } } sata_request sreq; sreq.SetATA48Command(ATA_COMMAND_DATA_SET_MANAGEMENT, 0, (lbaRangesSize + 511) / 512); sreq.SetFeature(1); sreq.SetData(lbaRanges, lbaRangesSize); ExecuteSataRequest(&sreq); sreq.WaitForCompletion(); if ((sreq.CompletionStatus() & ATA_ERR) != 0) { TRACE("trim failed (%" B_PRIu32 " ranges)!\n", lbaRangeCount); request->subsys_status = SCSI_REQ_CMP_ERR; } else request->subsys_status = SCSI_REQ_CMP; request->data_resid = 0; request->device_status = SCSI_STATUS_GOOD; gSCSI->finished(request, 1); }
int32 ethernet_deframe(net_device* device, net_buffer* buffer) { //dprintf("asked to deframe buffer for device %s\n", device->name); NetBufferHeaderRemover<ether_header> bufferHeader(buffer); if (bufferHeader.Status() != B_OK) return bufferHeader.Status(); ether_header& header = bufferHeader.Data(); uint16 type = B_BENDIAN_TO_HOST_INT16(header.type); struct sockaddr_dl& source = *(struct sockaddr_dl*)buffer->source; struct sockaddr_dl& destination = *(struct sockaddr_dl*)buffer->destination; source.sdl_len = sizeof(sockaddr_dl); source.sdl_family = AF_LINK; source.sdl_index = device->index; source.sdl_type = IFT_ETHER; source.sdl_e_type = header.type; source.sdl_nlen = source.sdl_slen = 0; source.sdl_alen = ETHER_ADDRESS_LENGTH; memcpy(source.sdl_data, header.source, ETHER_ADDRESS_LENGTH); destination.sdl_len = sizeof(sockaddr_dl); destination.sdl_family = AF_LINK; destination.sdl_index = device->index; destination.sdl_type = IFT_ETHER; destination.sdl_e_type = header.type; destination.sdl_nlen = destination.sdl_slen = 0; destination.sdl_alen = ETHER_ADDRESS_LENGTH; memcpy(destination.sdl_data, header.destination, ETHER_ADDRESS_LENGTH); // Mark buffer if it was a broadcast/multicast packet if (!memcmp(header.destination, kBroadcastAddress, ETHER_ADDRESS_LENGTH)) buffer->flags |= MSG_BCAST; else if ((header.destination[0] & 0x01) != 0) buffer->flags |= MSG_MCAST; // Translate the ethernet specific type to a generic one if possible switch (type) { case ETHER_TYPE_IP: buffer->type = B_NET_FRAME_TYPE_IPV4; break; case ETHER_TYPE_IPV6: buffer->type = B_NET_FRAME_TYPE_IPV6; break; case ETHER_TYPE_IPX: buffer->type = B_NET_FRAME_TYPE_IPX; break; default: buffer->type = B_NET_FRAME_TYPE(IFT_ETHER, type); break; } return B_OK; }
// -------------------------------------------------- static uint16 ttf_get_uint16(FILE * ttf) { uint16 v; if (fread(&v, 1, 2, ttf) != 2) return 0; return B_BENDIAN_TO_HOST_INT16(v); }
void swap_words(void *data, size_t size) { uint16 *word = (uint16 *)data; size_t count = size / 2; while (count--) { *word = B_BENDIAN_TO_HOST_INT16(*word); word++; } }
/*! \brief Creates a new Disc object by parsing the given table of contents entries and checking the resultant data structure for errors and warnings. If successful, subsequent calls to InitCheck() will return \c B_OK, elsewise they will return an error code. */ Disc::Disc(int fd) : fInitStatus(B_NO_INIT), fSessionList(new List) { DEBUG_INIT_ETC("Disc", ("fd: %d", fd)); uchar data[kBlockSize]; /* if (!error) error = sessionInfo && index >= 0 ? B_OK : B_BAD_VALUE; int32 session = index+1; // Check for a valid session index if (session < 1 || session > 99) error = B_ENTRY_NOT_FOUND; */ status_t error = fSessionList ? B_OK : B_NO_MEMORY; // Attempt to read the table of contents, first in lba mode, then in msf // mode if (!error) error = read_table_of_contents(fd, 1, data, kBlockSize, false); if (error) { TRACE(("%s: lba read_toc failed, trying msf instead\n", kModuleDebugName)); error = read_table_of_contents(fd, 1, data, kBlockSize, true); } // Interpret the data returned, if successful if (!error) { cdrom_table_of_contents_header* header; cdrom_full_table_of_contents_entry* entries; int count; header = (cdrom_table_of_contents_header*)data; entries = (cdrom_full_table_of_contents_entry*)(data + 4); header->length = B_BENDIAN_TO_HOST_INT16(header->length); count = (header->length - 2) / sizeof(cdrom_full_table_of_contents_entry); count = _AdjustForYellowBook(entries, count); error = _ParseTableOfContents(entries, count); // Dump(); if (!error) { _SortAndRemoveDuplicates(); error = _CheckForErrorsAndWarnings(); } } PRINT(("Setting init status to 0x%" B_PRIx32 ", `%s'\n", error, strerror(error))); fInitStatus = error; }
status_t BRawNetBuffer::ReadUint16(uint16& value) { uint16 netVal; ssize_t sizeW = fBuffer.ReadAt(fReadPosition, &netVal, sizeof(uint16)); if (sizeW == 0) return B_ERROR; value= B_BENDIAN_TO_HOST_INT16(netVal); fReadPosition += sizeof(uint16); return B_OK; }
status_t BNetBuffer::RemoveUint16(uint16& data) { uint16 be_data; status_t result = RemoveData((void*)&be_data, sizeof(uint16)); if (result != B_OK) return result; data = B_BENDIAN_TO_HOST_INT16(be_data); return B_OK; }
static void dump_full_table_of_contents(uchar* data, uint16 dataLength) { cdrom_table_of_contents_header* header = (cdrom_table_of_contents_header*)data; cdrom_full_table_of_contents_entry* entries = (cdrom_full_table_of_contents_entry*)(data + 4); int headerLength = B_BENDIAN_TO_HOST_INT16(header->length); if (dataLength < headerLength) { TRACE(("dump_full_table_of_contents: warning, data buffer not large " "enough (%d < %d)\n", dataLength, headerLength)); headerLength = dataLength; } TRACE(("%s: table of contents dump:\n", kModuleDebugName)); TRACE(("--------------------------------------------------\n")); TRACE(("header:\n")); TRACE((" length = %d\n", headerLength)); TRACE((" first = %d\n", header->first)); TRACE((" last = %d\n", header->last)); int count = (headerLength - 2) / sizeof(cdrom_full_table_of_contents_entry); TRACE(("\n")); TRACE(("entry count = %d\n", count)); for (int i = 0; i < count; i++) { TRACE(("\n")); TRACE(("entry #%d:\n", i)); TRACE((" session = %d\n", entries[i].session)); TRACE((" adr = %d\n", entries[i].adr)); TRACE((" control = %d (%s track, copy %s)\n", entries[i].control, (entries[i].control & kControlDataTrack ? "data" : "audio"), (entries[i].control & kControlCopyPermitted ? "permitted" : "prohibited"))); TRACE((" tno = %d\n", entries[i].tno)); TRACE((" point = %d (0x%.2x)\n", entries[i].point, entries[i].point)); TRACE((" minutes = %d\n", entries[i].minutes)); TRACE((" frames = %d\n", entries[i].seconds)); TRACE((" seconds = %d\n", entries[i].frames)); TRACE((" zero = %d\n", entries[i].zero)); TRACE((" pminutes = %d\n", entries[i].pminutes)); TRACE((" pseconds = %d\n", entries[i].pseconds)); TRACE((" pframes = %d\n", entries[i].pframes)); TRACE((" lba = %lld\n", msf_to_lba(make_msf_address(entries[i].pminutes, entries[i].pseconds, entries[i].pframes)))); } TRACE(("--------------------------------------------------\n")); }
void AHCIPort::ScsiExecuteRequest(scsi_ccb *request) { // TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length); if (fIsATAPI) { bool isWrite = false; switch (request->flags & SCSI_DIR_MASK) { case SCSI_DIR_NONE: ASSERT(request->data_length == 0); break; case SCSI_DIR_IN: ASSERT(request->data_length > 0); break; case SCSI_DIR_OUT: isWrite = true; ASSERT(request->data_length > 0); break; default: panic("CDB has invalid direction mask"); } // TRACE("AHCIPort::ScsiExecuteRequest ATAPI: port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length); sata_request *sreq = new(std::nothrow) sata_request(request); if (sreq == NULL) { TRACE("out of memory when allocating atapi request\n"); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); return; } sreq->set_atapi_cmd(request->data_length); // uint8 *data = (uint8*) sreq->ccb()->cdb; // for (int i = 0; i < 16; i += 8) { // TRACE(" %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1], data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]); // } ExecuteSataRequest(sreq, isWrite); return; } if (request->cdb[0] == SCSI_OP_REQUEST_SENSE) { panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n"); return; } if (!fDevicePresent) { TRACE("no device present on port %d\n", fIndex); request->subsys_status = SCSI_DEV_NOT_THERE; gSCSI->finished(request, 1); return; } request->subsys_status = SCSI_REQ_CMP; switch (request->cdb[0]) { case SCSI_OP_TEST_UNIT_READY: ScsiTestUnitReady(request); break; case SCSI_OP_INQUIRY: ScsiInquiry(request); break; case SCSI_OP_READ_CAPACITY: ScsiReadCapacity(request); break; case SCSI_OP_SERVICE_ACTION_IN: if ((request->cdb[1] & 0x1f) == SCSI_SAI_READ_CAPACITY_16) ScsiReadCapacity16(request); else { request->subsys_status = SCSI_REQ_INVALID; gSCSI->finished(request, 1); } break; case SCSI_OP_SYNCHRONIZE_CACHE: ScsiSynchronizeCache(request); break; case SCSI_OP_READ_6: case SCSI_OP_WRITE_6: { const scsi_cmd_rw_6 *cmd = (const scsi_cmd_rw_6 *)request->cdb; uint32 position = ((uint32)cmd->high_lba << 16) | ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba; size_t length = cmd->length != 0 ? cmd->length : 256; bool isWrite = request->cdb[0] == SCSI_OP_WRITE_6; ScsiReadWrite(request, position, length, isWrite); break; } case SCSI_OP_READ_10: case SCSI_OP_WRITE_10: { const scsi_cmd_rw_10 *cmd = (const scsi_cmd_rw_10 *)request->cdb; uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba); size_t length = B_BENDIAN_TO_HOST_INT16(cmd->length); bool isWrite = request->cdb[0] == SCSI_OP_WRITE_10; if (length) { ScsiReadWrite(request, position, length, isWrite); } else { TRACE("AHCIPort::ScsiExecuteRequest error: transfer without " "data!\n"); request->subsys_status = SCSI_REQ_INVALID; gSCSI->finished(request, 1); } break; } case SCSI_OP_READ_12: case SCSI_OP_WRITE_12: { const scsi_cmd_rw_12 *cmd = (const scsi_cmd_rw_12 *)request->cdb; uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba); size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length); bool isWrite = request->cdb[0] == SCSI_OP_WRITE_12; if (length) { ScsiReadWrite(request, position, length, isWrite); } else { TRACE("AHCIPort::ScsiExecuteRequest error: transfer without " "data!\n"); request->subsys_status = SCSI_REQ_INVALID; gSCSI->finished(request, 1); } break; } case SCSI_OP_READ_16: case SCSI_OP_WRITE_16: { const scsi_cmd_rw_16 *cmd = (const scsi_cmd_rw_16 *)request->cdb; uint64 position = B_BENDIAN_TO_HOST_INT64(cmd->lba); size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length); bool isWrite = request->cdb[0] == SCSI_OP_WRITE_16; if (length) { ScsiReadWrite(request, position, length, isWrite); } else { TRACE("AHCIPort::ScsiExecuteRequest error: transfer without " "data!\n"); request->subsys_status = SCSI_REQ_INVALID; gSCSI->finished(request, 1); } break; } case SCSI_OP_WRITE_SAME_16: { const scsi_cmd_wsame_16 *cmd = (const scsi_cmd_wsame_16 *)request->cdb; // SCSI unmap is used for trim, otherwise we don't support it if (!cmd->unmap) { TRACE("%s port %d: unsupported request opcode 0x%02x\n", __func__, fIndex, request->cdb[0]); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); break; } if (!fTrim) { // Drive doesn't support trim (or atapi) // Just say it was successful and quit request->subsys_status = SCSI_REQ_CMP; } else { TRACE("%s unimplemented: TRIM call\n", __func__); // TODO: Make Serial ATA (sata_request?) trim call here. request->subsys_status = SCSI_REQ_ABORTED; } gSCSI->finished(request, 1); break; } default: TRACE("AHCIPort::ScsiExecuteRequest port %d unsupported request " "opcode 0x%02x\n", fIndex, request->cdb[0]); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); } }
void AHCIPort::ScsiExecuteRequest(scsi_ccb *request) { // TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length); if (fIsATAPI) { bool isWrite = false; switch (request->flags & SCSI_DIR_MASK) { case SCSI_DIR_NONE: ASSERT(request->data_length == 0); break; case SCSI_DIR_IN: ASSERT(request->data_length > 0); break; case SCSI_DIR_OUT: isWrite = true; ASSERT(request->data_length > 0); break; default: panic("CDB has invalid direction mask"); } // TRACE("AHCIPort::ScsiExecuteRequest ATAPI: port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length); sata_request *sreq = new(std::nothrow) sata_request(request); sreq->set_atapi_cmd(request->data_length); // uint8 *data = (uint8*) sreq->ccb()->cdb; // for (int i = 0; i < 16; i += 8) { // TRACE(" %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1], data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]); // } ExecuteSataRequest(sreq, isWrite); return; } if (request->cdb[0] == SCSI_OP_REQUEST_SENSE) { panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n"); return; } if (!fDevicePresent) { TRACE("no device present on port %d\n", fIndex); request->subsys_status = SCSI_DEV_NOT_THERE; gSCSI->finished(request, 1); return; } request->subsys_status = SCSI_REQ_CMP; switch (request->cdb[0]) { case SCSI_OP_TEST_UNIT_READY: ScsiTestUnitReady(request); break; case SCSI_OP_INQUIRY: ScsiInquiry(request); break; case SCSI_OP_READ_CAPACITY: ScsiReadCapacity(request); break; case SCSI_OP_SYNCHRONIZE_CACHE: ScsiSynchronizeCache(request); break; case SCSI_OP_READ_6: case SCSI_OP_WRITE_6: { scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb; uint32 position = ((uint32)cmd->high_lba << 16) | ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba; size_t length = cmd->length != 0 ? cmd->length : 256; bool isWrite = request->cdb[0] == SCSI_OP_WRITE_6; ScsiReadWrite(request, position, length, isWrite); break; } case SCSI_OP_READ_10: case SCSI_OP_WRITE_10: { scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb; uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba); size_t length = B_BENDIAN_TO_HOST_INT16(cmd->length); bool isWrite = request->cdb[0] == SCSI_OP_WRITE_10; if (length) { ScsiReadWrite(request, position, length, isWrite); } else { TRACE("AHCIPort::ScsiExecuteRequest error: transfer without data!\n"); request->subsys_status = SCSI_REQ_INVALID; gSCSI->finished(request, 1); } break; } case SCSI_OP_READ_12: case SCSI_OP_WRITE_12: { scsi_cmd_rw_12 *cmd = (scsi_cmd_rw_12 *)request->cdb; uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba); size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length); bool isWrite = request->cdb[0] == SCSI_OP_WRITE_12; if (length) { ScsiReadWrite(request, position, length, isWrite); } else { TRACE("AHCIPort::ScsiExecuteRequest error: transfer without data!\n"); request->subsys_status = SCSI_REQ_INVALID; gSCSI->finished(request, 1); } break; } default: TRACE("AHCIPort::ScsiExecuteRequest port %d unsupported request opcode 0x%02x\n", fIndex, request->cdb[0]); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); } }
/*! Execute SCSI command */ void ata_exec_io(ide_device_info *device, ide_qrequest *qrequest) { scsi_ccb *request = qrequest->request; SHOW_FLOW(3, "command=%x", request->cdb[0]); // ATA devices have one LUN only if (request->target_lun != 0) { request->subsys_status = SCSI_SEL_TIMEOUT; finish_request(qrequest, false); return; } // starting a request means deleting sense, so don't do it if // the command wants to read it if (request->cdb[0] != SCSI_OP_REQUEST_SENSE) start_request(device, qrequest); switch (request->cdb[0]) { case SCSI_OP_TEST_UNIT_READY: ata_test_unit_ready(device, qrequest); break; case SCSI_OP_REQUEST_SENSE: ide_request_sense(device, qrequest); return; case SCSI_OP_FORMAT: /* FORMAT UNIT */ // we could forward request to disk, but modern disks cannot // be formatted anyway, so we just refuse request // (exceptions are removable media devices, but to my knowledge // they don't have to be formatted as well) set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); break; case SCSI_OP_INQUIRY: ata_inquiry(device, qrequest); break; case SCSI_OP_MODE_SELECT_10: ata_mode_select_10(device, qrequest); break; case SCSI_OP_MODE_SENSE_10: ata_mode_sense_10(device, qrequest); break; case SCSI_OP_MODE_SELECT_6: case SCSI_OP_MODE_SENSE_6: // we've told SCSI bus manager to emulates these commands set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); break; case SCSI_OP_RESERVE: case SCSI_OP_RELEASE: // though mandatory, this doesn't make much sense in a // single initiator environment; so what set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); break; case SCSI_OP_START_STOP: { scsi_cmd_ssu *cmd = (scsi_cmd_ssu *)request->cdb; // with no LoEj bit set, we should only allow/deny further access // we ignore that (unsupported for ATA) // with LoEj bit set, we should additionally either load or eject the medium // (start = 0 - eject; start = 1 - load) if (!cmd->start) // we must always flush cache if start = 0 ata_flush_cache(device, qrequest); if (cmd->load_eject) ata_load_eject(device, qrequest, cmd->start); break; } case SCSI_OP_PREVENT_ALLOW: { scsi_cmd_prevent_allow *cmd = (scsi_cmd_prevent_allow *)request->cdb; ata_prevent_allow(device, cmd->prevent); break; } case SCSI_OP_READ_CAPACITY: read_capacity(device, qrequest); break; case SCSI_OP_VERIFY: // does anyone uses this function? // effectly, it does a read-and-compare, which IDE doesn't support set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); break; case SCSI_OP_SYNCHRONIZE_CACHE: // we ignore range and immediate bit, we always immediately flush everything ata_flush_cache(device, qrequest); break; // sadly, there are two possible read/write operation codes; // at least, the third one, read/write(12), is not valid for DAS case SCSI_OP_READ_6: case SCSI_OP_WRITE_6: { scsi_cmd_rw_6 *cmd = (scsi_cmd_rw_6 *)request->cdb; uint32 pos; size_t length; pos = ((uint32)cmd->high_lba << 16) | ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba; length = cmd->length != 0 ? cmd->length : 256; SHOW_FLOW(3, "READ6/WRITE6 pos=%lx, length=%lx", pos, length); ata_send_rw(device, qrequest, pos, length, cmd->opcode == SCSI_OP_WRITE_6); return; } case SCSI_OP_READ_10: case SCSI_OP_WRITE_10: { scsi_cmd_rw_10 *cmd = (scsi_cmd_rw_10 *)request->cdb; uint32 pos; size_t length; pos = B_BENDIAN_TO_HOST_INT32(cmd->lba); length = B_BENDIAN_TO_HOST_INT16(cmd->length); if (length != 0) { ata_send_rw(device, qrequest, pos, length, cmd->opcode == SCSI_OP_WRITE_10); } else { // we cannot transfer zero blocks (apart from LBA48) finish_request(qrequest, false); } return; } default: set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_OPCODE); } finish_checksense(qrequest); }
static void ata_mode_sense_10(ide_device_info *device, ide_qrequest *qrequest) { scsi_ccb *request = qrequest->request; scsi_cmd_mode_sense_10 *cmd = (scsi_cmd_mode_sense_10 *)request->cdb; scsi_mode_param_header_10 param_header; scsi_modepage_control control; scsi_mode_param_block_desc block_desc; size_t totalLength = sizeof(scsi_mode_param_header_10) + sizeof(scsi_mode_param_block_desc) + sizeof(scsi_modepage_control); scsi_mode_param_dev_spec_da devspec = { _res0_0 : 0, dpo_fua : 0, _res0_6 : 0, write_protected : 0 }; uint32 allocationLength; SHOW_FLOW0(1, "Hi!"); allocationLength = B_BENDIAN_TO_HOST_INT16(cmd->allocation_length); // we answer control page requests and "all pages" requests // (as the latter are the same as the first) if ((cmd->page_code != SCSI_MODEPAGE_CONTROL && cmd->page_code != SCSI_MODEPAGE_ALL) || (cmd->page_control != SCSI_MODE_SENSE_PC_CURRENT && cmd->page_control != SCSI_MODE_SENSE_PC_SAVED)) { set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD); return; } //param_header = (scsi_mode_param_header_10 *)request->data; param_header.mode_data_length = B_HOST_TO_BENDIAN_INT16(totalLength - 1); param_header.medium_type = 0; // XXX standard is a bit vague here param_header.dev_spec_parameter = *(uint8 *)&devspec; param_header.block_desc_length = B_HOST_TO_BENDIAN_INT16(sizeof(scsi_mode_param_block_desc)); copy_sg_data(request, 0, allocationLength, ¶m_header, sizeof(param_header), false); /*block_desc = (scsi_mode_param_block_desc *)(request->data + sizeof(*param_header));*/ memset(&block_desc, 0, sizeof(block_desc)); // density is reserved (0), descriptor apply to entire medium (num_blocks=0) // remains the blocklen to be set block_desc.high_blocklen = 0; block_desc.med_blocklen = 512 >> 8; block_desc.low_blocklen = 512 & 0xff; copy_sg_data(request, sizeof(param_header), allocationLength, &block_desc, sizeof(block_desc), false); /*contr = (scsi_modepage_contr *)(request->data + sizeof(*param_header) + ((uint16)param_header->high_block_desc_len << 8) + param_header->low_block_desc_len);*/ memset(&control, 0, sizeof(control)); control.RLEC = false; control.DQue = !device->CQ_enabled; control.QErr = false; // when a command fails we requeue all // lost commands automagically control.QAM = SCSI_QAM_UNRESTRICTED; copy_sg_data(request, sizeof(param_header) + B_BENDIAN_TO_HOST_INT16(param_header.block_desc_length), allocationLength, &control, sizeof(control), false); // the number of bytes that were transferred to buffer is // restricted by allocation length and by request data buffer size totalLength = min(totalLength, allocationLength); totalLength = min(totalLength, request->data_length); request->data_resid = request->data_length - totalLength; } /*! Emulate modifying control page */ static bool ata_mode_select_control_page(ide_device_info *device, ide_qrequest *qrequest, scsi_modepage_control *page) { if (page->header.page_length != sizeof(*page) - sizeof(page->header)) { set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_LIST_LENGTH_ERR); return false; } // we only support enabling/disabling command queuing enable_CQ(device, !page->DQue); return true; } /*! Emulate MODE SELECT 10 command */ static void ata_mode_select_10(ide_device_info *device, ide_qrequest *qrequest) { scsi_ccb *request = qrequest->request; scsi_cmd_mode_select_10 *cmd = (scsi_cmd_mode_select_10 *)request->cdb; scsi_mode_param_header_10 param_header; scsi_modepage_header page_header; uint32 totalLength; uint32 modepageOffset; char modepage_buffer[64]; // !!! enlarge this to support longer mode pages if (cmd->save_pages || cmd->pf != 1) { set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_CDB_FIELD); return; } totalLength = min(request->data_length, B_BENDIAN_TO_HOST_INT16(cmd->param_list_length)); // first, retrieve page header to get size of different chunks //param_header = (scsi_mode_param_header_10 *)request->data; if (!copy_sg_data(request, 0, totalLength, ¶m_header, sizeof(param_header), true)) goto err; totalLength = min(totalLength, B_BENDIAN_TO_HOST_INT16(param_header.mode_data_length) + 1UL); // this is the start of the first mode page; // we ignore the block descriptor silently modepageOffset = sizeof(param_header) + B_BENDIAN_TO_HOST_INT16(param_header.block_desc_length); // go through list of pages while (modepageOffset < totalLength) { uint32 pageLength; // get header to know how long page is if (!copy_sg_data(request, modepageOffset, totalLength, &page_header, sizeof(page_header), true)) goto err; // get size of one page and copy it to buffer pageLength = page_header.page_length + sizeof(scsi_modepage_header); // the buffer has a maximum size - this is really standard compliant but // sufficient for our needs if (pageLength > sizeof(modepage_buffer)) goto err; if (!copy_sg_data(request, modepageOffset, totalLength, &modepage_buffer, min(pageLength, sizeof(modepage_buffer)), true)) goto err; // modify page; // currently, we only support the control mode page switch (page_header.page_code) { case SCSI_MODEPAGE_CONTROL: if (!ata_mode_select_control_page(device, qrequest, (scsi_modepage_control *)modepage_buffer)) return; break; default: set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_INV_PARAM_LIST_FIELD); return; } modepageOffset += pageLength; } if (modepageOffset != totalLength) goto err; request->data_resid = request->data_length - totalLength; return; // if we arrive here, data length was incorrect err: set_sense(device, SCSIS_KEY_ILLEGAL_REQUEST, SCSIS_ASC_PARAM_LIST_LENGTH_ERR); }
/*! get inquiry data returns true on success */ static bool scsi_scan_get_inquiry(scsi_ccb *worker_req, scsi_res_inquiry *new_inquiry_data) { scsi_cmd_inquiry *cmd = (scsi_cmd_inquiry *)worker_req->cdb; scsi_device_info *device = worker_req->device; SHOW_FLOW0(3, ""); // in case not whole structure gets transferred, we set remaining data to zero memset(new_inquiry_data, 0, sizeof(*new_inquiry_data)); cmd->opcode = SCSI_OP_INQUIRY; cmd->lun = device->target_lun; cmd->evpd = 0; cmd->page_code = 0; cmd->allocation_length = sizeof(*new_inquiry_data); worker_req->sg_list = NULL; worker_req->data = (uchar *)new_inquiry_data; worker_req->data_length = sizeof(*new_inquiry_data); worker_req->cdb_length = 6; worker_req->timeout = SCSI_STD_TIMEOUT; worker_req->sort = -1; worker_req->flags = SCSI_DIR_IN; scsi_sync_io(worker_req); switch (worker_req->subsys_status) { case SCSI_REQ_CMP: { char vendor[9], product[17], rev[5]; SHOW_FLOW0(3, "send successfully"); // we could check transmission length here, but as we reset // missing bytes before, we get kind of valid data anyway (hopefully) strlcpy(vendor, new_inquiry_data->vendor_ident, sizeof(vendor)); strlcpy(product, new_inquiry_data->product_ident, sizeof(product)); strlcpy(rev, new_inquiry_data->product_rev, sizeof(rev)); SHOW_INFO(3, "device type: %d, qualifier: %d, removable: %d, ANSI version: %d, response data format: %d\n" "vendor: %s, product: %s, rev: %s", new_inquiry_data->device_type, new_inquiry_data->device_qualifier, new_inquiry_data->removable_medium, new_inquiry_data->ansi_version, new_inquiry_data->response_data_format, vendor, product, rev); SHOW_INFO(3, "additional_length: %d", new_inquiry_data->additional_length + 4); // time to show standards the device conforms to; // unfortunately, ATAPI CD-ROM drives tend to tell that they have // only minimal info (36 bytes), but still they return (valid!) 96 bytes - // bad luck if (std::min((int)cmd->allocation_length, new_inquiry_data->additional_length + 4) >= (int)offsetof(scsi_res_inquiry, _res74)) { int i, previousStandard = -1; for (i = 0; i < 8; ++i) { int standard = B_BENDIAN_TO_HOST_INT16( new_inquiry_data->version_descriptor[i]); // omit standards reported twice if (standard != previousStandard && standard != 0) SHOW_INFO(3, "standard: %04x", standard); previousStandard = standard; } } //snooze( 1000000 ); /* { unsigned int i; for( i = 0; i < worker_req->data_length - worker_req->data_resid; ++i ) { dprintf( "%2x ", *((char *)new_inquiry_data + i) ); } dprintf( "\n" ); }*/ return true; } default: return false; } }
void AHCIPort::ScsiExecuteRequest(scsi_ccb* request) { // TRACE("AHCIPort::ScsiExecuteRequest port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length); if (fIsATAPI) { bool isWrite = false; switch (request->flags & SCSI_DIR_MASK) { case SCSI_DIR_NONE: ASSERT(request->data_length == 0); break; case SCSI_DIR_IN: ASSERT(request->data_length > 0); break; case SCSI_DIR_OUT: isWrite = true; ASSERT(request->data_length > 0); break; default: panic("CDB has invalid direction mask"); } // TRACE("AHCIPort::ScsiExecuteRequest ATAPI: port %d, opcode 0x%02x, length %u\n", fIndex, request->cdb[0], request->cdb_length); sata_request* sreq = new(std::nothrow) sata_request(request); if (sreq == NULL) { TRACE("out of memory when allocating atapi request\n"); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); return; } sreq->SetATAPICommand(request->data_length); // uint8* data = (uint8*) sreq->ccb()->cdb; // for (int i = 0; i < 16; i += 8) { // TRACE(" %02x %02x %02x %02x %02x %02x %02x %02x\n", data[i], data[i+1], data[i+2], data[i+3], data[i+4], data[i+5], data[i+6], data[i+7]); // } ExecuteSataRequest(sreq, isWrite); return; } if (request->cdb[0] == SCSI_OP_REQUEST_SENSE) { panic("ahci: SCSI_OP_REQUEST_SENSE not yet supported\n"); return; } if (!fDevicePresent) { TRACE("no device present on port %d\n", fIndex); request->subsys_status = SCSI_DEV_NOT_THERE; gSCSI->finished(request, 1); return; } request->subsys_status = SCSI_REQ_CMP; switch (request->cdb[0]) { case SCSI_OP_TEST_UNIT_READY: ScsiTestUnitReady(request); break; case SCSI_OP_INQUIRY: ScsiInquiry(request); break; case SCSI_OP_READ_CAPACITY: ScsiReadCapacity(request); break; case SCSI_OP_SERVICE_ACTION_IN: if ((request->cdb[1] & 0x1f) == SCSI_SAI_READ_CAPACITY_16) ScsiReadCapacity16(request); else { request->subsys_status = SCSI_REQ_INVALID; gSCSI->finished(request, 1); } break; case SCSI_OP_SYNCHRONIZE_CACHE: ScsiSynchronizeCache(request); break; case SCSI_OP_READ_6: case SCSI_OP_WRITE_6: { const scsi_cmd_rw_6* cmd = (const scsi_cmd_rw_6*)request->cdb; uint32 position = ((uint32)cmd->high_lba << 16) | ((uint32)cmd->mid_lba << 8) | (uint32)cmd->low_lba; size_t length = cmd->length != 0 ? cmd->length : 256; bool isWrite = request->cdb[0] == SCSI_OP_WRITE_6; ScsiReadWrite(request, position, length, isWrite); break; } case SCSI_OP_READ_10: case SCSI_OP_WRITE_10: { const scsi_cmd_rw_10* cmd = (const scsi_cmd_rw_10*)request->cdb; uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba); size_t length = B_BENDIAN_TO_HOST_INT16(cmd->length); bool isWrite = request->cdb[0] == SCSI_OP_WRITE_10; if (length) { ScsiReadWrite(request, position, length, isWrite); } else { TRACE("AHCIPort::ScsiExecuteRequest error: transfer without " "data!\n"); request->subsys_status = SCSI_REQ_INVALID; gSCSI->finished(request, 1); } break; } case SCSI_OP_READ_12: case SCSI_OP_WRITE_12: { const scsi_cmd_rw_12* cmd = (const scsi_cmd_rw_12*)request->cdb; uint32 position = B_BENDIAN_TO_HOST_INT32(cmd->lba); size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length); bool isWrite = request->cdb[0] == SCSI_OP_WRITE_12; if (length) { ScsiReadWrite(request, position, length, isWrite); } else { TRACE("AHCIPort::ScsiExecuteRequest error: transfer without " "data!\n"); request->subsys_status = SCSI_REQ_INVALID; gSCSI->finished(request, 1); } break; } case SCSI_OP_READ_16: case SCSI_OP_WRITE_16: { const scsi_cmd_rw_16* cmd = (const scsi_cmd_rw_16*)request->cdb; uint64 position = B_BENDIAN_TO_HOST_INT64(cmd->lba); size_t length = B_BENDIAN_TO_HOST_INT32(cmd->length); bool isWrite = request->cdb[0] == SCSI_OP_WRITE_16; if (length) { ScsiReadWrite(request, position, length, isWrite); } else { TRACE("AHCIPort::ScsiExecuteRequest error: transfer without " "data!\n"); request->subsys_status = SCSI_REQ_INVALID; gSCSI->finished(request, 1); } break; } case SCSI_OP_UNMAP: { const scsi_cmd_unmap* cmd = (const scsi_cmd_unmap*)request->cdb; if (!fTrimSupported) { TRACE("%s port %d: unsupported request opcode 0x%02x\n", __func__, fIndex, request->cdb[0]); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); break; } scsi_unmap_parameter_list* unmapBlocks = (scsi_unmap_parameter_list*)request->data; if (unmapBlocks == NULL || B_BENDIAN_TO_HOST_INT16(cmd->length) != request->data_length || B_BENDIAN_TO_HOST_INT16(unmapBlocks->data_length) != request->data_length - 1) { TRACE("%s port %d: invalid unmap parameter data length\n", __func__, fIndex); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); } else { ScsiUnmap(request, unmapBlocks); } break; } default: TRACE("AHCIPort::ScsiExecuteRequest port %d unsupported request " "opcode 0x%02x\n", fIndex, request->cdb[0]); request->subsys_status = SCSI_REQ_ABORTED; gSCSI->finished(request, 1); } }
status_t read_cdtext(int fd, struct cdtext &cdtext) { uint8 *buffer = (uint8 *)malloc(kBufferSize); if (buffer == NULL) return B_NO_MEMORY; // do it twice, just in case... // (at least my CD-ROM sometimes returned broken data on first try) read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_CD_TEXT, buffer, kBufferSize); if (read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_CD_TEXT, buffer, kBufferSize) != B_OK) { free(buffer); return B_ERROR; } scsi_toc_general *header = (scsi_toc_general *)buffer; size_t packLength = B_BENDIAN_TO_HOST_INT16(header->data_length) - 2; cdtext_pack_data *pack = (cdtext_pack_data *)(header + 1); cdtext_pack_data *lastPack = NULL; uint8 state = 0; char text[256]; while (true) { size_t length = sizeof(text); uint8 id = 0, track = 0; if (!parse_pack_data(pack, packLength, lastPack, id, track, state, text, length)) break; switch (id) { case kTrackID: if (track == 0) { if (cdtext.album == NULL) cdtext.album = copy_string(text); } else if (track <= kMaxTracks) { if (cdtext.titles[track - 1] == NULL) cdtext.titles[track - 1] = copy_string(text); if (track > cdtext.track_count) cdtext.track_count = track; } break; case kArtistID: if (track == 0) { if (cdtext.artist == NULL) cdtext.artist = copy_string(text); } else if (track <= kMaxTracks) { if (cdtext.artists[track - 1] == NULL) cdtext.artists[track - 1] = copy_string(text); } break; default: if (is_string_id(id)) dprintf("UNKNOWN %u: \"%s\"\n", id, text); break; } } free(buffer); if (cdtext.artist == NULL || cdtext.album == NULL) return B_ERROR; for (int i = 0; i < cdtext.track_count; i++) { if (cdtext.titles[i] == NULL) return B_ERROR; } sanitize_string(cdtext.artist); sanitize_album(cdtext); sanitize_titles(cdtext); correct_case(cdtext); dump_cdtext(cdtext); return B_OK; }
uint16 RequiredProgramVersion() const { return B_BENDIAN_TO_HOST_INT16(required_program_version); }
uint16 Version() const { return B_BENDIAN_TO_HOST_INT16(version); }
status_t PackageReader::Init(int fd, bool keepFD) { fFD = fd; fOwnsFD = keepFD; // stat it struct stat st; if (fstat(fFD, &st) < 0) { fErrorOutput->PrintError("Error: Failed to access package file: %s\n", strerror(errno)); return errno; } // read the header hpkg_header header; status_t error = _ReadBuffer(0, &header, sizeof(header)); if (error != B_OK) return error; // check the header // magic if (B_BENDIAN_TO_HOST_INT32(header.magic) != B_HPKG_MAGIC) { fErrorOutput->PrintError("Error: Invalid package file: Invalid " "magic\n"); return B_BAD_DATA; } // header size fHeapOffset = B_BENDIAN_TO_HOST_INT16(header.header_size); if ((size_t)fHeapOffset < sizeof(hpkg_header)) { fErrorOutput->PrintError("Error: Invalid package file: Invalid header " "size (%llu)\n", fHeapOffset); return B_BAD_DATA; } // version if (B_BENDIAN_TO_HOST_INT16(header.version) != B_HPKG_VERSION) { fErrorOutput->PrintError("Error: Invalid/unsupported package file " "version (%d)\n", B_BENDIAN_TO_HOST_INT16(header.version)); return B_BAD_DATA; } // total size fTotalSize = B_BENDIAN_TO_HOST_INT64(header.total_size); if (fTotalSize != (uint64)st.st_size) { fErrorOutput->PrintError("Error: Invalid package file: Total size in " "header (%llu) doesn't agree with total file size (%lld)\n", fTotalSize, st.st_size); return B_BAD_DATA; } // package attributes length and compression fPackageAttributesCompression = B_BENDIAN_TO_HOST_INT32(header.attributes_compression); fPackageAttributesCompressedLength = B_BENDIAN_TO_HOST_INT32(header.attributes_length_compressed); fPackageAttributesUncompressedLength = B_BENDIAN_TO_HOST_INT32(header.attributes_length_uncompressed); if (const char* errorString = _CheckCompression( fPackageAttributesCompression, fPackageAttributesCompressedLength, fPackageAttributesUncompressedLength)) { fErrorOutput->PrintError("Error: Invalid package file: package " "attributes section: %s\n", errorString); return B_BAD_DATA; } // TOC length and compression fTOCCompression = B_BENDIAN_TO_HOST_INT32(header.toc_compression); fTOCCompressedLength = B_BENDIAN_TO_HOST_INT64(header.toc_length_compressed); fTOCUncompressedLength = B_BENDIAN_TO_HOST_INT64(header.toc_length_uncompressed); if (const char* errorString = _CheckCompression(fTOCCompression, fTOCCompressedLength, fTOCUncompressedLength)) { fErrorOutput->PrintError("Error: Invalid package file: TOC section: " "%s\n", errorString); return B_BAD_DATA; } // TOC subsections fTOCAttributeTypesLength = B_BENDIAN_TO_HOST_INT64(header.toc_attribute_types_length); fTOCAttributeTypesCount = B_BENDIAN_TO_HOST_INT64(header.toc_attribute_types_count); fTOCStringsLength = B_BENDIAN_TO_HOST_INT64(header.toc_strings_length); fTOCStringsCount = B_BENDIAN_TO_HOST_INT64(header.toc_strings_count); if (fTOCAttributeTypesLength > fTOCUncompressedLength || fTOCStringsLength > fTOCUncompressedLength - fTOCAttributeTypesLength || fTOCAttributeTypesCount > fTOCAttributeTypesLength || fTOCStringsCount > fTOCStringsLength) { fErrorOutput->PrintError("Error: Invalid package file: Invalid TOC " "subsections description\n"); return B_BAD_DATA; } // check whether the sections fit together if (fPackageAttributesCompressedLength > fTotalSize || fTOCCompressedLength > fTotalSize - fPackageAttributesCompressedLength || fHeapOffset > fTotalSize - fPackageAttributesCompressedLength - fTOCCompressedLength) { fErrorOutput->PrintError("Error: Invalid package file: The sum of the " "sections sizes is greater than the package size\n"); return B_BAD_DATA; } fPackageAttributesOffset = fTotalSize - fPackageAttributesCompressedLength; fTOCSectionOffset = fPackageAttributesOffset - fTOCCompressedLength; fHeapSize = fTOCSectionOffset - fHeapOffset; // TOC size sanity check if (fTOCUncompressedLength > kMaxTOCSize) { fErrorOutput->PrintError("Error: Package file TOC section size " "is %llu bytes. This is beyond the reader's sanity limit\n", fTOCUncompressedLength); return B_UNSUPPORTED; } // allocate a scratch buffer fScratchBuffer = new(std::nothrow) uint8[kScratchBufferSize]; if (fScratchBuffer == NULL) { fErrorOutput->PrintError("Error: Out of memory!\n"); return B_NO_MEMORY; } fScratchBufferSize = kScratchBufferSize; // read in the complete TOC fTOCSection = new(std::nothrow) uint8[fTOCUncompressedLength]; if (fTOCSection == NULL) { fErrorOutput->PrintError("Error: Out of memory!\n"); return B_NO_MEMORY; } error = _ReadCompressedBuffer(fTOCSectionOffset, fTOCSection, fTOCCompressedLength, fTOCUncompressedLength, fTOCCompression); if (error != B_OK) return error; // start parsing the TOC fCurrentTOCOffset = 0; // attribute types error = _ParseTOCAttributeTypes(); if (error != B_OK) return error; fCurrentTOCOffset += fTOCAttributeTypesLength; // strings error = _ParseTOCStrings(); if (error != B_OK) return error; fCurrentTOCOffset += fTOCStringsLength; return B_OK; }
status_t PackageReader::_ReadAttributeValue(uint8 type, uint8 encoding, AttributeValue& _value) { switch (type) { case B_HPKG_ATTRIBUTE_TYPE_INT: case B_HPKG_ATTRIBUTE_TYPE_UINT: { uint64 intValue; status_t error; switch (encoding) { case B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT: { uint8 value; error = _Read(value); intValue = value; break; } case B_HPKG_ATTRIBUTE_ENCODING_INT_16_BIT: { uint16 value; error = _Read(value); intValue = B_BENDIAN_TO_HOST_INT16(value); break; } case B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT: { uint32 value; error = _Read(value); intValue = B_BENDIAN_TO_HOST_INT32(value); break; } case B_HPKG_ATTRIBUTE_ENCODING_INT_64_BIT: { uint64 value; error = _Read(value); intValue = B_BENDIAN_TO_HOST_INT64(value); break; } default: { fErrorOutput->PrintError("Error: Invalid TOC section: " "invalid encoding %d for int value type %d\n", encoding, type); return B_BAD_VALUE; } } if (error != B_OK) return error; if (type == B_HPKG_ATTRIBUTE_TYPE_INT) _value.SetTo((int64)intValue); else _value.SetTo(intValue); return B_OK; } case B_HPKG_ATTRIBUTE_TYPE_STRING: { if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE) { uint64 index; status_t error = _ReadUnsignedLEB128(index); if (error != B_OK) return error; if (index > fTOCStringsCount) { fErrorOutput->PrintError("Error: Invalid TOC section: " "string reference out of bounds\n"); return B_BAD_DATA; } _value.SetTo(fStrings[index]); } else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_STRING_INLINE) { const char* string; status_t error = _ReadString(string); if (error != B_OK) return error; _value.SetTo(string); } else { fErrorOutput->PrintError("Error: Invalid TOC section: invalid " "string encoding (%u)\n", encoding); return B_BAD_DATA; } return B_OK; } case B_HPKG_ATTRIBUTE_TYPE_RAW: { uint64 size; status_t error = _ReadUnsignedLEB128(size); if (error != B_OK) return error; if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) { uint64 offset; error = _ReadUnsignedLEB128(offset); if (error != B_OK) return error; if (offset > fHeapSize || size > fHeapSize - offset) { fErrorOutput->PrintError("Error: Invalid TOC section: " "invalid data reference\n"); return B_BAD_DATA; } _value.SetToData(size, fHeapOffset + offset); } else if (encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) { if (size > B_HPKG_MAX_INLINE_DATA_SIZE) { fErrorOutput->PrintError("Error: Invalid TOC section: " "inline data too long\n"); return B_BAD_DATA; } const void* buffer; error = _GetTOCBuffer(size, buffer); if (error != B_OK) return error; _value.SetToData(size, buffer); } else { fErrorOutput->PrintError("Error: Invalid TOC section: invalid " "raw encoding (%u)\n", encoding); return B_BAD_DATA; } return B_OK; } default: fErrorOutput->PrintError("Error: Invalid TOC section: invalid " "value type: %d\n", type); return B_BAD_DATA; } }