예제 #1
0
bool
PartitionMap::Check(off_t sessionSize) const
{
	int32 partitionCount = CountPartitions();

	// 1. check partition locations
	for (int32 i = 0; i < partitionCount; i++) {
		if (!PartitionAt(i)->CheckLocation(sessionSize))
			return false;
	}

	// 2. check overlapping of partitions and location of partition tables
	bool result = true;
	Partition** byOffset = new(nothrow) Partition*[partitionCount];
	off_t* tableOffsets = new(nothrow) off_t[partitionCount - 3];
	if (byOffset && tableOffsets) {
		// fill the arrays
		int32 byOffsetCount = 0;
		int32 tableOffsetCount = 1;	// primary partition table
		tableOffsets[0] = 0;
		for (int32 i = 0; i < partitionCount; i++) {
			Partition* partition = (Partition*)PartitionAt(i);
			if (!partition->IsExtended())
				byOffset[byOffsetCount++] = partition;

			// add only logical partition partition table locations
			if (i >= 4) {
				tableOffsets[tableOffsetCount++]
					= partition->PartitionTableOffset();
			}
		}

		// sort the arrays
		qsort(byOffset, byOffsetCount, sizeof(Partition*),
			cmp_partition_offset);
		qsort(tableOffsets, tableOffsetCount, sizeof(off_t), cmp_offset);

		// check for overlappings
		off_t nextOffset = 0;
		for (int32 i = 0; i < byOffsetCount; i++) {
			Partition* partition = byOffset[i];
			if (partition->Offset() < nextOffset && i > 0) {
				Partition* previousPartition = byOffset[i - 1];
				off_t previousSize = previousPartition->Size()
					- (nextOffset - partition->Offset());
				TRACE(("intel: PartitionMap::Check(): "));
				if (previousSize == 0) {
					previousPartition->Unset();
					TRACE(("partition offset hides previous partition."
						" Removing previous partition from disk layout.\n"));
				} else {
					TRACE(("overlapping partitions! Setting partition %ld "
						"size to %lld\n", i - 1, previousSize));
					previousPartition->SetSize(previousSize);
				}
			}
			nextOffset = partition->Offset() + partition->Size();
		}

		// check uniqueness of partition table offsets and whether they lie
		// outside of the non-extended partitions
		if (result) {
			for (int32 i = 0; i < tableOffsetCount; i++) {
				if (i > 0 && tableOffsets[i] == tableOffsets[i - 1]) {
					TRACE(("intel: PartitionMap::Check(): same partition table "
						"for different extended partitions!\n"));
					result = false;
					break;
				} else if (is_inside_partitions(tableOffsets[i],
						(const Partition**)byOffset, byOffsetCount)) {
					TRACE(("intel: PartitionMap::Check(): a partition table "
						"lies inside a non-extended partition!\n"));
					result = false;
					break;
				}
			}
		}
	} else
		result = false;		// no memory: assume failure

	// cleanup
	delete[] byOffset;
	delete[] tableOffsets;

	return result;
}