void PartitionHandle::CheckEBR(u8 PartNum, sec_t ebr_lba)
{
	EXTENDED_BOOT_RECORD *ebr = (EXTENDED_BOOT_RECORD*)MEM2_alloc(MAX_BYTES_PER_SECTOR);
	if(ebr == NULL)
		return;
	sec_t next_erb_lba = 0;

	do
	{
		// Read and validate the extended boot record
		if(!interface->readSectors(ebr_lba + next_erb_lba, 1, ebr))
		{
			MEM2_free(ebr);
			return;
		}
		if(ebr->signature != EBR_SIGNATURE && ebr->signature != EBR_SIGNATURE_MOD)
		{
			MEM2_free(ebr);
			return;
		}

		if(le32(ebr->partition.block_count) > 0 && !IsExisting(ebr_lba + next_erb_lba + le32(ebr->partition.lba_start)))
		{
			AddPartition(PartFromType(ebr->partition.type), ebr_lba + next_erb_lba + le32(ebr->partition.lba_start),
					le32(ebr->partition.block_count), (ebr->partition.status == PARTITION_BOOTABLE), ebr->partition.type, PartNum);
		}
		// Get the start sector of the current partition
		// and the next extended boot record in the chain
		next_erb_lba = le32(ebr->next_ebr.lba_start);
	}
	while(next_erb_lba > 0);

	MEM2_free(ebr);
}
BranchSection::BranchSection(BranchPartition& p)
{
    partitions.clear();
    m_partitionNum = 0;
    AddPartition(p);

}
void PartitionHandle::CheckEBR(int PartNum, sec_t ebr_lba)
{
	EXTENDED_BOOT_RECORD *ebr = (EXTENDED_BOOT_RECORD *) malloc(MAX_SECTOR_SIZE);
	if(!ebr)
		return;

	sec_t next_erb_lba = 0;

	do
	{
		// Read and validate the extended boot record
		if (!interface->readSectors(ebr_lba + next_erb_lba, 1, ebr))
			break;

		if (ebr->signature != EBR_SIGNATURE)
			break;

		PARTITION_RECORD * partition = (PARTITION_RECORD *) &ebr->partition;

		if(le32(partition->block_count) > 0)
		{
			AddPartition(PartFromType(partition->type), ebr_lba + next_erb_lba + le32(partition->lba_start),
						 le32(partition->block_count), (partition->status == PARTITION_BOOTABLE),
						 partition->type, PartNum, ebr_lba + next_erb_lba);
		}
		// Get the start sector of the current partition
		// and the next extended boot record in the chain
		next_erb_lba = le32(ebr->next_ebr.lba_start);
	}
	while(next_erb_lba > 0);

	free(ebr);
}
int PartitionHandle::CheckGPT(int PartNum)
{
	GPT_HEADER *gpt_header = (GPT_HEADER *) malloc(MAX_SECTOR_SIZE);
	if(!gpt_header)
		return -1;

	// Read and validate the extended boot record
	if (!interface->readSectors(1, 1, gpt_header)) {
		free(gpt_header);
		return -1;
	}

	if(strncmp(gpt_header->magic, "EFI PART", 8) != 0) {
		free(gpt_header);
		return -1;
	}

	gpt_header->part_table_lba = le64(gpt_header->part_table_lba);
	gpt_header->part_entries = le32(gpt_header->part_entries);
	gpt_header->part_entry_size = le32(gpt_header->part_entry_size);
	gpt_header->part_entry_checksum = le32(gpt_header->part_entry_checksum);

	u8 * sector_buf = (u8 *) malloc(MAX_SECTOR_SIZE);
	if(!sector_buf) {
		free(gpt_header);
		return -1;
	}

	u64 next_lba = gpt_header->part_table_lba;

	for(u32 i = 0; i < gpt_header->part_entries; ++i)
	{
		if (!interface->readSectors(next_lba, 1, sector_buf))
			break;

		for(u32 n = 0; n < sectorSize/gpt_header->part_entry_size; ++n, ++i)
		{
			GUID_PART_ENTRY * part_entry = (GUID_PART_ENTRY *) (sector_buf+gpt_header->part_entry_size*n);

			if(memcmp(part_entry->part_type_guid, TYPE_UNUSED, 16) == 0)
				continue;

			bool bootable = (memcmp(part_entry->part_type_guid, TYPE_BIOS, 16) == 0);

			AddPartition("GUID-Entry", le64(part_entry->part_first_lba), le64(part_entry->part_last_lba),
						 bootable, PARTITION_TYPE_GPT, PartNum);
		}

		next_lba++;
	}

	free(sector_buf);
	free(gpt_header);

	return 0;
}
int PartitionHandle::FindPartitions()
{
	MASTER_BOOT_RECORD *mbr = (MASTER_BOOT_RECORD *) malloc(MAX_SECTOR_SIZE);
	if(!mbr)
		return -1;

	// Read the first sector on the device
	if (!interface->readSectors(0, 1, mbr)) {
		free(mbr);
		return -1;
	}

	// If this is the devices master boot record
	if (mbr->signature != MBR_SIGNATURE) {
		free(mbr);
		return -1;
	}

	for (int i = 0; i < 4; i++)
	{
		PARTITION_RECORD * partition = (PARTITION_RECORD *) &mbr->partitions[i];

		if(partition->type == PARTITION_TYPE_GPT)
		{
			int ret = CheckGPT(i);
			if(ret == 0)
				break;
		}

		if(partition->type == PARTITION_TYPE_DOS33_EXTENDED || partition->type == PARTITION_TYPE_WIN95_EXTENDED)
		{
			CheckEBR(i, le32(partition->lba_start));
			continue;
		}

		if(le32(partition->block_count) > 0)
		{
			AddPartition(PartFromType(partition->type), le32(partition->lba_start),
						 le32(partition->block_count), (partition->status == PARTITION_BOOTABLE),
						 partition->type, i);
		}
	}

	free(mbr);

	return 0;
}
s8 PartitionHandle::FindPartitions()
{
	MASTER_BOOT_RECORD *mbr = (MASTER_BOOT_RECORD*)MEM2_alloc(MAX_BYTES_PER_SECTOR);
	if(mbr == NULL)
		return -1;

	// Read the first sector on the device
	if(!interface->readSectors(0, 1, mbr))
	{
		MEM2_free(mbr);
		return -1;
	}

	// If this is the devices master boot record
	if(mbr->signature != MBR_SIGNATURE && mbr->signature != MBR_SIGNATURE_MOD)
	{
		MEM2_free(mbr);
		return -1;
	}

	for(u8 i = 0; i < 4; i++)
	{
		PARTITION_RECORD *partition = (PARTITION_RECORD *)&mbr->partitions[i];

		if(partition->type == PARTITION_TYPE_GPT)
		{
			s8 ret = CheckGPT(i);
			if(ret == 0) // if it's a GPT we don't need to go on looking through the mbr anymore
				return ret;
		}
		if(partition->type == PARTITION_TYPE_DOS33_EXTENDED || partition->type == PARTITION_TYPE_WIN95_EXTENDED)
		{
			CheckEBR(i, le32(partition->lba_start));
			continue;
		}
		if(le32(partition->block_count) > 0 && !IsExisting(le32(partition->lba_start)))
		{
			AddPartition(PartFromType(partition->type), le32(partition->lba_start),
					le32(partition->block_count), (partition->status == PARTITION_BOOTABLE), partition->type, i);
		}
	}
	MEM2_free(mbr);
	return 0;
}
PartitionListRow*
PartitionListView::AddPartition(BPartition* partition)
{
	PartitionListRow* partitionrow = FindRow(partition->ID());

	// forget about it if this partition is already in the listview
	if (partitionrow != NULL)
		return partitionrow;

	// create the row for this partition
	partitionrow = new PartitionListRow(partition);

	// see if this partition has a parent, or should have
	// a parent (add it in this case)
	PartitionListRow* parent = NULL;
	if (partition->Parent() != NULL) {
		// check if it is in the listview
		parent = FindRow(partition->Parent()->ID());
		// If parent of this partition is not yet in the list
		if (parent == NULL) {
			// add it
			parent = AddPartition(partition->Parent());
		}
	}

	// find a proper insertion index based on the on-disk offset
	int32 index = _InsertIndexForOffset(parent, partition->Offset());

	// add the row, parent may be NULL (add at top level)
	AddRow(partitionrow, index, parent);

	// make sure the row is initially expanded
	ExpandOrCollapse(partitionrow, true);

	return partitionrow;
}
static int FindPartitions(int device) {
	int i;
	int devnum = 0;

	// clear list
	for (i = 0; i < MAX_DEVICES; i++) {
		part[device][i].name[0] = 0;
		part[device][i].mount[0] = 0;
		part[device][i].sector = 0;
		part[device][i].interface = NULL;
		part[device][i].type = 0;
	}

	DISC_INTERFACE *interface;

	switch(device){
		case DEVICE_ATAPI:
			interface = (DISC_INTERFACE *) & xenon_atapi_ops;
			break;
		case DEVICE_ATA:
			interface = (DISC_INTERFACE *) & xenon_ata_ops;
			break;
		case DEVICE_USB:
			interface = (DISC_INTERFACE *) & usb2mass_ops;
			break;
	}


	MASTER_BOOT_RECORD mbr;
	PARTITION_RECORD *partition = NULL;
	devnum = 0;
	sec_t part_lba = 0;

	union {
		u8 buffer[BYTES_PER_SECTOR];
		MASTER_BOOT_RECORD mbr;
		EXTENDED_BOOT_RECORD ebr;
		NTFS_BOOT_SECTOR boot;
	} sector;

	if(device == DEVICE_ATAPI){
		AddPartition(0, device, T_ISO9660, &devnum);
		return devnum;
	}

	// Read the first sector on the device
	if (!interface->readSectors(0, 1, &sector.buffer)) {
		//errno = EIO;
		return -1;
	}

	// If this is the devices master boot record
	debug_printf("0x%x\n", sector.mbr.signature);
	if (sector.mbr.signature == MBR_SIGNATURE) {
		memcpy(&mbr, &sector, sizeof (MASTER_BOOT_RECORD));
		debug_printf("Valid Master Boot Record found\n");

		// Search the partition table for all partitions (max. 4 primary partitions)
		for (i = 0; i < 4; i++) {
			partition = &mbr.partitions[i];
			part_lba = le32_to_cpu(mbr.partitions[i].lba_start);

			debug_printf(
					"Partition %i: %s, sector %u, type 0x%x\n",
					i + 1,
					partition->status == PARTITION_STATUS_BOOTABLE ? "bootable (active)"
					: "non-bootable", part_lba, partition->type);

			// Figure out what type of partition this is
			switch (partition->type) {
					// NTFS partition
				case PARTITION_TYPE_NTFS:
				{
					debug_printf("Partition %i: Claims to be NTFS\n", i + 1);

					// Read and validate the NTFS partition
					if (interface->readSectors(part_lba, 1, &sector)) {
						debug_printf("sector.boot.oem_id: 0x%x\n", sector.boot.oem_id);
						debug_printf("NTFS_OEM_ID: 0x%x\n", NTFS_OEM_ID);
						if (sector.boot.oem_id == NTFS_OEM_ID) {
							debug_printf("Partition %i: Valid NTFS boot sector found\n", i + 1);
							AddPartition(part_lba, device, T_NTFS, &devnum);
						} else {
							debug_printf("Partition %i: Invalid NTFS boot sector, not actually NTFS\n", i + 1);
						}
					}
					break;
				}
					// DOS 3.3+ or Windows 95 extended partition
				case PARTITION_TYPE_DOS33_EXTENDED:
				case PARTITION_TYPE_WIN95_EXTENDED:
				{
					debug_printf("Partition %i: Claims to be Extended\n", i + 1);

					// Walk the extended partition chain, finding all NTFS partitions within it
					sec_t ebr_lba = part_lba;
					sec_t next_erb_lba = 0;
					do {
						// Read and validate the extended boot record
						if (interface->readSectors(ebr_lba + next_erb_lba, 1, &sector)) {
							if (sector.ebr.signature == EBR_SIGNATURE) {
								debug_printf(
										"Logical Partition @ %d: %s type 0x%x\n",
										ebr_lba + next_erb_lba,
										sector.ebr.partition.status
										== PARTITION_STATUS_BOOTABLE ? "bootable (active)"
										: "non-bootable",
										sector.ebr.partition.type);

								// Get the start sector of the current partition
								// and the next extended boot record in the chain
								part_lba = ebr_lba + next_erb_lba
										+ le32_to_cpu(
										sector.ebr.partition.lba_start);
								next_erb_lba = le32_to_cpu(
										sector.ebr.next_ebr.lba_start);

								if (sector.ebr.partition.type == PARTITION_TYPE_LINUX) {
									debug_printf("Partition : type ext2/3/4 found\n");
									AddPartition(part_lba, device, T_EXT2, &devnum);
								}// Check if this partition has a valid NTFS boot record
								else if (interface->readSectors(part_lba, 1, &sector)) {
									if (sector.boot.oem_id == NTFS_OEM_ID) {
										debug_printf(
												"Logical Partition @ %d: Valid NTFS boot sector found\n",
												part_lba);
										if (sector.ebr.partition.type
												!= PARTITION_TYPE_NTFS) {
											debug_printf(
													"Logical Partition @ %d: Is NTFS but type is 0x%x; 0x%x was expected\n",
													part_lba,
													sector.ebr.partition.type,
													PARTITION_TYPE_NTFS);
										}
										AddPartition(part_lba, device, T_NTFS, &devnum);
									} else if (!memcmp(sector.buffer
											+ BPB_FAT16_fileSysType, FAT_SIG,
											sizeof (FAT_SIG)) || !memcmp(
											sector.buffer
											+ BPB_FAT32_fileSysType,
											FAT_SIG, sizeof (FAT_SIG))) {
										debug_printf("Partition : Valid FAT boot sector found\n");
										AddPartition(part_lba, device, T_FAT, &devnum);
									}
								}
							} else {
								next_erb_lba = 0;
							}
						}
					} while (next_erb_lba);
					break;
				}
				case PARTITION_TYPE_LINUX:
				{
					debug_printf("Partition %i: Claims to be LINUX\n", i + 1);

					// Read and validate the EXT2 partition
					AddPartition(part_lba, device, T_EXT2, &devnum);
					break;
				}
					// Ignore empty partitions
				case PARTITION_TYPE_EMPTY:
					debug_printf("Partition %i: Claims to be empty\n", i + 1);
					// Unknown or unsupported partition type
				default:
				{
					// Check if this partition has a valid NTFS boot record anyway,
					// it might be misrepresented due to a lazy partition editor
					if (interface->readSectors(part_lba, 1, &sector)) {
						if (sector.boot.oem_id == NTFS_OEM_ID) {
							debug_printf("Partition %i: Valid NTFS boot sector found\n", i + 1);
							if (partition->type != PARTITION_TYPE_NTFS) {
								debug_printf(
										"Partition %i: Is NTFS but type is 0x%x; 0x%x was expected\n",
										i + 1, partition->type,
										PARTITION_TYPE_NTFS);
							}
							AddPartition(part_lba, device, T_NTFS, &devnum);
						} else if (!memcmp(sector.buffer + BPB_FAT16_fileSysType,
								FAT_SIG, sizeof (FAT_SIG)) || !memcmp(
								sector.buffer + BPB_FAT32_fileSysType, FAT_SIG,
								sizeof (FAT_SIG))) {
							debug_printf("Partition : Valid FAT boot sector found\n");
							AddPartition(part_lba, device, T_FAT, &devnum);
						} else {
							debug_printf("Trying : ext partition\n");
							AddPartition(part_lba, device, T_EXT2, &devnum);
						}
					}
					break;
				}
			}
		}
	}
	if (devnum == 0) // it is assumed this device has no master boot record or no partitions found
	{
		debug_printf("No Master Boot Record was found or no partitions found!\n");

		// As a last-ditched effort, search the first 64 sectors of the device for stray NTFS/FAT partitions
		for (i = 0; i < 64; i++) {
			if (interface->readSectors(i, 1, &sector)) {
				if (sector.boot.oem_id == NTFS_OEM_ID) {
					debug_printf("Valid NTFS boot sector found at sector %d!\n", i);
					AddPartition(i, device, T_NTFS, &devnum);
					break;
				} else if (!memcmp(sector.buffer + BPB_FAT16_fileSysType, FAT_SIG,
						sizeof (FAT_SIG)) || !memcmp(sector.buffer
						+ BPB_FAT32_fileSysType, FAT_SIG, sizeof (FAT_SIG))) {
					debug_printf("Partition : Valid FAT boot sector found\n");
					AddPartition(i, device, T_FAT, &devnum);
					break;
				} else {
					debug_printf("Trying : ext partition\n");
					AddPartition(part_lba, device, T_EXT2, &devnum);
				}
			}
		}
	}
	return devnum;
}
// Attempt to improve this by adding partitions or expanding partitions.
void ColPartitionSet::ImproveColumnCandidate(WidthCallback* cb,
                                             PartSetVector* src_sets) {
  int set_size = src_sets->size();
  // Iterate over the provided column sets, as each one may have something
  // to improve this.
  for (int i = 0; i < set_size; ++i) {
    ColPartitionSet* column_set = src_sets->get(i);
    if (column_set == NULL)
      continue;
    // Iterate over the parts in this and column_set, adding bigger or
    // new parts in column_set to this.
    ColPartition_IT part_it(&parts_);
    ASSERT_HOST(!part_it.empty());
    int prev_right = MIN_INT32;
    part_it.mark_cycle_pt();
    ColPartition_IT col_it(&column_set->parts_);
    for (col_it.mark_cycle_pt(); !col_it.cycled_list(); col_it.forward()) {
      ColPartition* col_part = col_it.data();
      if (col_part->blob_type() < BRT_UNKNOWN)
        continue;  // Ignore image partitions.
      int col_left = col_part->left_key();
      int col_right = col_part->right_key();
      // Sync-up part_it (in this) so it matches the col_part in column_set.
      ColPartition* part = part_it.data();
      while (!part_it.at_last() && part->right_key() < col_left) {
        prev_right = part->right_key();
        part_it.forward();
        part = part_it.data();
      }
      int part_left = part->left_key();
      int part_right = part->right_key();
      if (part_right < col_left || col_right < part_left) {
        // There is no overlap so this is a new partition.
        AddPartition(col_part->ShallowCopy(), &part_it);
        continue;
      }
      // Check the edges of col_part to see if they can improve part.
      bool part_width_ok = cb->Run(part->KeyWidth(part_left, part_right));
      if (col_left < part_left && col_left > prev_right) {
        // The left edge of the column is better and it doesn't overlap,
        // so we can potentially expand it.
        int col_box_left = col_part->BoxLeftKey();
        bool tab_width_ok = cb->Run(part->KeyWidth(col_left, part_right));
        bool box_width_ok = cb->Run(part->KeyWidth(col_box_left, part_right));
        if (tab_width_ok || (!part_width_ok )) {
          // The tab is leaving the good column metric at least as good as
          // it was before, so use the tab.
          part->CopyLeftTab(*col_part, false);
          part->SetColumnGoodness(cb);
        } else if (col_box_left < part_left &&
                   (box_width_ok || !part_width_ok)) {
          // The box is leaving the good column metric at least as good as
          // it was before, so use the box.
          part->CopyLeftTab(*col_part, true);
          part->SetColumnGoodness(cb);
        }
        part_left = part->left_key();
      }
      if (col_right > part_right &&
          (part_it.at_last() ||
           part_it.data_relative(1)->left_key() > col_right)) {
        // The right edge is better, so we can possibly expand it.
        int col_box_right = col_part->BoxRightKey();
        bool tab_width_ok = cb->Run(part->KeyWidth(part_left, col_right));
        bool box_width_ok = cb->Run(part->KeyWidth(part_left, col_box_right));
        if (tab_width_ok || (!part_width_ok )) {
          // The tab is leaving the good column metric at least as good as
          // it was before, so use the tab.
          part->CopyRightTab(*col_part, false);
          part->SetColumnGoodness(cb);
        } else if (col_box_right > part_right &&
                   (box_width_ok || !part_width_ok)) {
          // The box is leaving the good column metric at least as good as
          // it was before, so use the box.
          part->CopyRightTab(*col_part, true);
          part->SetColumnGoodness(cb);
        }
      }
    }
  }
  ComputeCoverage();
}
bool PartitionHandle::Mount(int pos, const char *name, bool forceFAT)
{
	if(valid(pos))
		UnMount(pos);

	if(!name)
		return false;

	if(pos >= (int)MountNameList.size())
		MountNameList.resize(pos + 1);

	MountNameList[pos] = name;
	char DeviceSyn[10];
	memcpy(DeviceSyn, name, 8);
	strcat(DeviceSyn, ":");
	DeviceSyn[9] = '\0';

	//! Some stupid partition manager think they don't need to edit the freaken MBR.
	//! So we need to check the first 64 sectors and see if some partition is there.
	//! libfat does that by default so let's use it.
	if(forceFAT && (strlen(GetFSName(pos)) == 0 || strcmp(GetFSName(pos), "Unknown") == 0))
	{
		if(fatMount(MountNameList[pos].c_str(), interface, 0, CACHE, SECTORS))
		{
			sec_t FAT_startSector = FindFirstValidPartition(interface);
			AddPartition("FAT", FAT_startSector, 0xdeadbeaf, true, 0x0c, 0);
			gprintf("FAT Partition at %s (forceFAT) mounted.\n", DeviceSyn);
			SetWbfsHandle(pos, NULL);
			return true;
		}
	}
	if(!valid(pos))
		return false;

	SetWbfsHandle(pos, NULL);
	if(strncmp(GetFSName(pos), "FAT", 3) == 0 || strcmp(GetFSName(pos), "GUID-Entry") == 0)
	{
		if(fatMount(MountNameList[pos].c_str(), interface, GetLBAStart(pos), CACHE, SECTORS))
		{
			gprintf("FAT Partition at %s mounted.\n", DeviceSyn);
			PartitionList[pos].FSName = "FAT";
			return true;
		}
	}
	else if(strncmp(GetFSName(pos), "NTFS", 4) == 0 || strcmp(GetFSName(pos), "GUID-Entry") == 0)
	{
		if(ntfsMount(MountNameList[pos].c_str(), interface, GetLBAStart(pos), CACHE, SECTORS, NTFS_SHOW_HIDDEN_FILES | NTFS_RECOVER))
		{
			gprintf("NTFS Partition at %s mounted.\n", DeviceSyn);
			PartitionList[pos].FSName = "NTFS";
			return true;
		}
	}
	else if(strncmp(GetFSName(pos), "LINUX", 5) == 0 || strcmp(GetFSName(pos), "GUID-Entry") == 0)
	{
		if(ext2Mount(MountNameList[pos].c_str(), interface, GetLBAStart(pos), CACHE, SECTORS, EXT2_FLAG_DEFAULT))
		{
			gprintf("EXT Partition at %s mounted.\n", DeviceSyn);
			PartitionList[pos].FSName = "LINUX";
			return true;
		}
	}
	else if(strncmp(GetFSName(pos), "WBFS", 4) == 0)
	{
		if(interface == &__io_usbstorage2_port0 || interface == &__io_usbstorage2_port1)
			SetWbfsHandle(pos, wbfs_open_partition(__WBFS_ReadUSB, __WBFS_WriteUSB, NULL, USBStorage2_GetSectorSize(), GetSecCount(pos), GetLBAStart(pos), 0));
		else if(interface == &__io_sdhc)
			SetWbfsHandle(pos, wbfs_open_partition(__WBFS_ReadSDHC, __WBFS_WriteSDHC, NULL, 512, GetSecCount(pos), GetLBAStart(pos), 0));
		if(GetWbfsHandle(pos))
		{
			gprintf("WBFS Partition at %s mounted.\n", DeviceSyn);
			PartitionList[pos].FSName = "WBFS";
			return true;
		}
	}
	/* FAIL */
	MountNameList[pos].clear();
	return false;
}