18d9e5a45SAxel Dörfler/*
2f6d3241dSAxel Dörfler * Copyright 2003-2011, Haiku, Inc. All Rights Reserved.
38d9e5a45SAxel Dörfler * Distributed under the terms of the MIT License.
48d9e5a45SAxel Dörfler *
58d9e5a45SAxel Dörfler * Authors:
68d9e5a45SAxel Dörfler *		Ingo Weinhold, bonefish@cs.tu-berlin.de
78d9e5a45SAxel Dörfler */
88d9e5a45SAxel Dörfler
9a0973602SAxel Dörfler
10b41bbb4aSAxel Dörfler/*!	\file PartitionMap.cpp
11852d12efSIngo Weinhold	\brief Definitions for "intel" style partitions and implementation
12852d12efSIngo Weinhold		   of related classes.
13852d12efSIngo Weinhold*/
14852d12efSIngo Weinhold
15a0973602SAxel Dörfler
16852d12efSIngo Weinhold#include <stdio.h>
17852d12efSIngo Weinhold#include <stdlib.h>
18852d12efSIngo Weinhold#include <string.h>
19852d12efSIngo Weinhold
20deeb2f39SIngo Weinhold#ifndef _USER_MODE
21deeb2f39SIngo Weinhold#	include <util/kernel_cpp.h>
2227ba18f4SAxel Dörfler#	include <KernelExport.h>
23deeb2f39SIngo Weinhold#else
24deeb2f39SIngo Weinhold#	include <new>
25deeb2f39SIngo Weinhold#endif
26b132797eSAxel Dörfler#ifndef _BOOT_MODE
27b132797eSAxel Dörfler#	include <DiskDeviceTypes.h>
28b132797eSAxel Dörfler#else
29b132797eSAxel Dörfler#	include <boot/partitions.h>
30b132797eSAxel Dörfler#endif
31852d12efSIngo Weinhold
32852d12efSIngo Weinhold#include "PartitionMap.h"
33852d12efSIngo Weinhold
3450b6109cSMarcus Overhagen
3527ba18f4SAxel Dörfler//#define TRACE_ENABLED
3650b6109cSMarcus Overhagen#ifdef TRACE_ENABLED
3750b6109cSMarcus Overhagen#	ifdef _USER_MODE
3850b6109cSMarcus Overhagen#		define TRACE(x) printf x
3950b6109cSMarcus Overhagen#	else
4050b6109cSMarcus Overhagen#		define TRACE(x) dprintf x
4150b6109cSMarcus Overhagen#	endif
4227ba18f4SAxel Dörfler#else
4327ba18f4SAxel Dörfler#	define TRACE(x) ;
4450b6109cSMarcus Overhagen#endif
45852d12efSIngo Weinhold
46deeb2f39SIngo Weinholdusing std::nothrow;
47deeb2f39SIngo Weinhold
48852d12efSIngo Weinhold
49f3794156SIngo Weinholdstatic const char* const kUnrecognizedTypeString = "Unrecognized Type ";
50f3794156SIngo Weinholdstatic const size_t kUnrecognizedTypeStringLength = 18;
51f3794156SIngo Weinhold
52852d12efSIngo Weinholdstatic const struct partition_type kPartitionTypes[] = {
53d57dba3cSNiels Sascha Reedijk    // Can be created (in display order)
54d57dba3cSNiels Sascha Reedijk    { 0x00, "empty", true },
55d57dba3cSNiels Sascha Reedijk    { 0x0f, INTEL_EXTENDED_PARTITION_NAME, true },
56d57dba3cSNiels Sascha Reedijk    { 0x0c, "FAT 32-bit, LBA-mapped", true },
57d57dba3cSNiels Sascha Reedijk    { 0x82, "Linux swap", true },
58d57dba3cSNiels Sascha Reedijk    { 0x83, "Linux native", true },
59d57dba3cSNiels Sascha Reedijk    { 0xa5, "FreeBSD", true },
60d57dba3cSNiels Sascha Reedijk    { 0xa6, "OpenBSD", true },
61d57dba3cSNiels Sascha Reedijk    { 0xa9, "NetBSD", true },
62d57dba3cSNiels Sascha Reedijk    { 0xa8, "MacOS X", true },
63d57dba3cSNiels Sascha Reedijk    { 0xab, "MacOS X boot", true },
64d57dba3cSNiels Sascha Reedijk    { 0xaf, "MacOS X HFS/HFS+", true },
65d57dba3cSNiels Sascha Reedijk    { 0x4d, "QNX 4", true },
66d57dba3cSNiels Sascha Reedijk    { 0xb3, "QNX 6", true },
67d57dba3cSNiels Sascha Reedijk    { 0xeb, BFS_NAME, true },
68d57dba3cSNiels Sascha Reedijk    // Known file system types
69d57dba3cSNiels Sascha Reedijk    { 0x01, "FAT 12-bit", false},
70d57dba3cSNiels Sascha Reedijk    { 0x02, "Xenix root", false },
71d57dba3cSNiels Sascha Reedijk    { 0x03, "Xenix user", false },
72d57dba3cSNiels Sascha Reedijk    { 0x04, "FAT 16-bit (dos 3.0)", false },
73d57dba3cSNiels Sascha Reedijk    { 0x05, INTEL_EXTENDED_PARTITION_NAME, false },
74d57dba3cSNiels Sascha Reedijk    { 0x06, "FAT 16-bit (dos 3.31)", false },
75d57dba3cSNiels Sascha Reedijk    { 0x07, "Windows NT, OS/2 IFS, Advanced Unix", false },
76d57dba3cSNiels Sascha Reedijk    { 0x08, "AIX", false },
77d57dba3cSNiels Sascha Reedijk    { 0x09, "AIX bootable", false },
78d57dba3cSNiels Sascha Reedijk    { 0x0a, "OS/2 Boot Manager", false },
79d57dba3cSNiels Sascha Reedijk    { 0x0b, "FAT 32-bit", false },
80d57dba3cSNiels Sascha Reedijk    { 0x0e, "FAT 16-bit, LBA-mapped", false },
81d57dba3cSNiels Sascha Reedijk    { 0x10, "OPUS", false },
82d57dba3cSNiels Sascha Reedijk    { 0x11, "Hidden FAT 12-bit", false },
83d57dba3cSNiels Sascha Reedijk    { 0x12, "Compaq diagnostic", false },
84d57dba3cSNiels Sascha Reedijk    { 0x14, "Hidden FAT 16-bit", false },
85d57dba3cSNiels Sascha Reedijk    { 0x16, "Hidden FAT 16-bit", false },
86d57dba3cSNiels Sascha Reedijk    { 0x17, "Hidden HPFS/NTFS", false },
87d57dba3cSNiels Sascha Reedijk    { 0x18, "AST SmartSleep", false },
88d57dba3cSNiels Sascha Reedijk    { 0x1b, "Hidden W95 FAT 32-bit", false },
89d57dba3cSNiels Sascha Reedijk    { 0x1c, "Hidden W95 FAT 32-bit", false },
90d57dba3cSNiels Sascha Reedijk    { 0x1e, "Hidden W95 FAT 16-bit", false },
91d57dba3cSNiels Sascha Reedijk    { 0x24, "NEC DOS", false },
92d57dba3cSNiels Sascha Reedijk    { 0x39, "Plan 9", false },
93d57dba3cSNiels Sascha Reedijk    { 0x3c, "PartitionMagic", false },
94d57dba3cSNiels Sascha Reedijk    { 0x40, "Venix 80286", false },
95d57dba3cSNiels Sascha Reedijk    { 0x41, "PPC PReP Boot", false },
96d57dba3cSNiels Sascha Reedijk    { 0x42, "Windows 2000 marker (proprietary extended)",
97d57dba3cSNiels Sascha Reedijk    false },
98d57dba3cSNiels Sascha Reedijk    { 0x4e, "QNX 4 2nd part", false },
99d57dba3cSNiels Sascha Reedijk    { 0x4f, "QNX 4 3rd part", false },
100d57dba3cSNiels Sascha Reedijk    { 0x50, "OnTrack DM", false },
101d57dba3cSNiels Sascha Reedijk    { 0x51, "OnTrack DM6 Aux", false },
102d57dba3cSNiels Sascha Reedijk    { 0x52, "CP/M", false },
103d57dba3cSNiels Sascha Reedijk    { 0x53, "OnTrack DM6 Aux", false },
104d57dba3cSNiels Sascha Reedijk    { 0x54, "OnTrack DM6", false },
105d57dba3cSNiels Sascha Reedijk    { 0x55, "EZ-Drive", false },
106d57dba3cSNiels Sascha Reedijk    { 0x56, "Golden Bow", false },
107d57dba3cSNiels Sascha Reedijk    { 0x5c, "Priam Edisk", false },
108d57dba3cSNiels Sascha Reedijk    { 0x61, "SpeedStor", false },
109d57dba3cSNiels Sascha Reedijk    { 0x63, "GNU HURD", false },
110d57dba3cSNiels Sascha Reedijk    { 0x64, "Novell Netware", false },
111d57dba3cSNiels Sascha Reedijk    { 0x65, "Novell Netware", false },
112d57dba3cSNiels Sascha Reedijk    { 0x70, "DiskSecure Mult", false },
113d57dba3cSNiels Sascha Reedijk    { 0x75, "PC/IX", false },
114d57dba3cSNiels Sascha Reedijk    { 0x78, "XOSL boot loader", false },
115d57dba3cSNiels Sascha Reedijk    { 0x80, "Old Minix", false },
116d57dba3cSNiels Sascha Reedijk    { 0x81, "Minix", false },
117d57dba3cSNiels Sascha Reedijk    { 0x84, "OS/2 hidden", false },
118d57dba3cSNiels Sascha Reedijk    { 0x85, /*"Linux extendend partition"*/INTEL_EXTENDED_PARTITION_NAME,
119d57dba3cSNiels Sascha Reedijk    false },
120d57dba3cSNiels Sascha Reedijk    { 0x86, "NTFS volume set", false },
121cfeeb9aeSthreedeyes    { 0x87, "NTFS volume set", true },
122d57dba3cSNiels Sascha Reedijk    { 0x88, "Linux plaintext", false },
123d57dba3cSNiels Sascha Reedijk    { 0x8e, "Linux LVM", false },
124d57dba3cSNiels Sascha Reedijk    { 0x93, "Amoeba", false },
125d57dba3cSNiels Sascha Reedijk    { 0x94, "Amoeba BBT", false },
126d57dba3cSNiels Sascha Reedijk    { 0x9f, "BSD/OS", false },
127d57dba3cSNiels Sascha Reedijk    { 0xa0, "IBM Hibernation", false },
128d57dba3cSNiels Sascha Reedijk    { 0xa7, "NextSTEP", false },
129d57dba3cSNiels Sascha Reedijk    { 0xb1, "QNX 6", false},
130d57dba3cSNiels Sascha Reedijk    { 0xb2, "QNX 6", false},
131d57dba3cSNiels Sascha Reedijk    { 0xb7, "BSDI fs", false },
132d57dba3cSNiels Sascha Reedijk    { 0xb8, "BSDI swap", false },
133d57dba3cSNiels Sascha Reedijk    { 0xbe, "Solaris 8 boot", false },
134d57dba3cSNiels Sascha Reedijk    { 0xbf, "Solaris 10", false },
135d57dba3cSNiels Sascha Reedijk    { 0xc1, "DR-DOS FAT", false },
136d57dba3cSNiels Sascha Reedijk    { 0xc4, "DR-DOS FAT", false },
137d57dba3cSNiels Sascha Reedijk    { 0xc6, "DR-DOS FAT", false },
138d57dba3cSNiels Sascha Reedijk    { 0xc7, "Syrinx", false },
139d57dba3cSNiels Sascha Reedijk    { 0xe4, "SpeedStor", false },
140d57dba3cSNiels Sascha Reedijk    { 0xee, "GPT", false },
141d57dba3cSNiels Sascha Reedijk    { 0xef, "EFI", false },
142d57dba3cSNiels Sascha Reedijk    { 0xfb, "VMware VMFS", false },
143d57dba3cSNiels Sascha Reedijk    { 0xfc, "VMware VMKCORE", false },
144d57dba3cSNiels Sascha Reedijk    { 0xfd, "Linux raid auto", false },
145d57dba3cSNiels Sascha Reedijk    { 0, NULL, false }
146852d12efSIngo Weinhold};
147852d12efSIngo Weinhold
14892b8ea1dSIngo Weinholdstatic const struct partition_type kPartitionContentTypes[] = {
14992b8ea1dSIngo Weinhold#ifndef _USER_MODE
15092b8ea1dSIngo Weinhold	{ 0x01, kPartitionTypeFAT12 },
151245df7abSJérôme Duval	{ 0x07, kPartitionTypeEXFAT },
15292b8ea1dSIngo Weinhold	{ 0x0c, kPartitionTypeFAT32 },
15392b8ea1dSIngo Weinhold	{ 0x0f, kPartitionTypeIntelExtended },
15401929b0cSJérôme Duval	{ 0x83, kPartitionTypeBTRFS },
15592b8ea1dSIngo Weinhold	{ 0x83, kPartitionTypeEXT2 },
15692b8ea1dSIngo Weinhold	{ 0x83, kPartitionTypeEXT3 },
15792b8ea1dSIngo Weinhold	{ 0x83, kPartitionTypeReiser },
15892b8ea1dSIngo Weinhold	{ 0xaf, kPartitionTypeHFS },
15992b8ea1dSIngo Weinhold	{ 0xaf, kPartitionTypeHFSPlus },
16092b8ea1dSIngo Weinhold	{ 0xeb, kPartitionTypeBFS },
16192b8ea1dSIngo Weinhold#endif
16292b8ea1dSIngo Weinhold	{ 0, NULL }
16392b8ea1dSIngo Weinhold};
16492b8ea1dSIngo Weinhold
1650e9f724cSAxel Dörfler
166199f3324SAxel Dörflerstatic const char*
167852d12efSIngo Weinholdpartition_type_string(uint8 type)
168852d12efSIngo Weinhold{
169852d12efSIngo Weinhold	int32 i;
170878bda67SStephan Aßmus	for (i = 0; kPartitionTypes[i].name ; i++) {
171852d12efSIngo Weinhold		if (type == kPartitionTypes[i].type)
172852d12efSIngo Weinhold			return kPartitionTypes[i].name;
173852d12efSIngo Weinhold	}
174852d12efSIngo Weinhold	return NULL;
175852d12efSIngo Weinhold}
176852d12efSIngo Weinhold
177199f3324SAxel Dörfler
178852d12efSIngo Weinholdvoid
179199f3324SAxel Dörflerget_partition_type_string(uint8 type, char* buffer)
180852d12efSIngo Weinhold{
181852d12efSIngo Weinhold	if (buffer) {
182199f3324SAxel Dörfler		if (const char* typeString = partition_type_string(type))
183199f3324SAxel Dörfler			strcpy(buffer, typeString);
184852d12efSIngo Weinhold		else
185f3794156SIngo Weinhold			sprintf(buffer, "%s0x%x", kUnrecognizedTypeString, type);
186852d12efSIngo Weinhold	}
187852d12efSIngo Weinhold}
188852d12efSIngo Weinhold
189852d12efSIngo Weinhold
1900e9f724cSAxel Dörflerstatic int
191199f3324SAxel Dörflercmp_partition_offset(const void* p1, const void* p2)
1920e9f724cSAxel Dörfler{
193199f3324SAxel Dörfler	const Partition* partition1 = *(const Partition**)p1;
194199f3324SAxel Dörfler	const Partition* partition2 = *(const Partition**)p2;
195199f3324SAxel Dörfler
1960e9f724cSAxel Dörfler	if (partition1->Offset() < partition2->Offset())
1970e9f724cSAxel Dörfler		return -1;
198199f3324SAxel Dörfler	if (partition1->Offset() > partition2->Offset())
1990e9f724cSAxel Dörfler		return 1;
200199f3324SAxel Dörfler
2010e9f724cSAxel Dörfler	return 0;
2020e9f724cSAxel Dörfler}
2030e9f724cSAxel Dörfler
2040e9f724cSAxel Dörfler
2050e9f724cSAxel Dörflerstatic int
206199f3324SAxel Dörflercmp_offset(const void* o1, const void* o2)
2070e9f724cSAxel Dörfler{
2080e9f724cSAxel Dörfler	off_t offset1 = *static_cast<const off_t*>(o1);
2090e9f724cSAxel Dörfler	off_t offset2 = *static_cast<const off_t*>(o2);
210199f3324SAxel Dörfler
2110e9f724cSAxel Dörfler	if (offset1 < offset2)
2120e9f724cSAxel Dörfler		return -1;
213199f3324SAxel Dörfler	if (offset1 > offset2)
2140e9f724cSAxel Dörfler		return 1;
215199f3324SAxel Dörfler
2160e9f724cSAxel Dörfler	return 0;
2170e9f724cSAxel Dörfler}
2180e9f724cSAxel Dörfler
2190e9f724cSAxel Dörfler
2200e9f724cSAxel Dörflerstatic bool
221199f3324SAxel Dörfleris_inside_partitions(off_t location, const Partition** partitions, int32 count)
2220e9f724cSAxel Dörfler{
2230e9f724cSAxel Dörfler	bool result = false;
2240e9f724cSAxel Dörfler	if (count > 0) {
2250e9f724cSAxel Dörfler		// binary search
2260e9f724cSAxel Dörfler		int32 lower = 0;
2270e9f724cSAxel Dörfler		int32 upper = count - 1;
2280e9f724cSAxel Dörfler		while (lower < upper) {
2290e9f724cSAxel Dörfler			int32 mid = (lower + upper) / 2;
2301987b05aSBryce Groff			const Partition* midPartition = partitions[mid];
2310e9f724cSAxel Dörfler			if (location >= midPartition->Offset() + midPartition->Size())
2320e9f724cSAxel Dörfler				lower = mid + 1;
2330e9f724cSAxel Dörfler			else
2340e9f724cSAxel Dörfler				upper = mid;
2350e9f724cSAxel Dörfler		}
2361987b05aSBryce Groff		const Partition* partition = partitions[lower];
2370e9f724cSAxel Dörfler		result = (location >= partition->Offset() &&
2380e9f724cSAxel Dörfler				  location < partition->Offset() + partition->Size());
2390e9f724cSAxel Dörfler	}
2400e9f724cSAxel Dörfler	return result;
2410e9f724cSAxel Dörfler}
2420e9f724cSAxel Dörfler
2430e9f724cSAxel Dörfler
24492b8ea1dSIngo Weinhold//	#pragma mark - PartitionType
24592b8ea1dSIngo Weinhold
24692b8ea1dSIngo Weinhold
24792b8ea1dSIngo WeinholdPartitionType::PartitionType()
248199f3324SAxel Dörfler	:
249199f3324SAxel Dörfler	fType(0),
250199f3324SAxel Dörfler	fValid(false)
25192b8ea1dSIngo Weinhold{
25292b8ea1dSIngo Weinhold}
25392b8ea1dSIngo Weinhold
254199f3324SAxel Dörfler
255199f3324SAxel Dörfler/*!	\brief Sets the \a type via its ID.
256288102e6SIngo Weinhold	\param type ID of the partition type, it is in the range [0..255].
257288102e6SIngo Weinhold*/
258260bb9a2SIngo Weinholdbool
25992b8ea1dSIngo WeinholdPartitionType::SetType(uint8 type)
26092b8ea1dSIngo Weinhold{
261288102e6SIngo Weinhold	fType = type;
262288102e6SIngo Weinhold	fValid = partition_type_string(type);
263260bb9a2SIngo Weinhold	return fValid;
26492b8ea1dSIngo Weinhold}
26592b8ea1dSIngo Weinhold
266199f3324SAxel Dörfler
267199f3324SAxel Dörfler/*!	\brief Sets the type via its string name.
268288102e6SIngo Weinhold	\param typeName Name of the partition type.
269288102e6SIngo Weinhold*/
270260bb9a2SIngo Weinholdbool
2711987b05aSBryce GroffPartitionType::SetType(const char* typeName)
27292b8ea1dSIngo Weinhold{
27392b8ea1dSIngo Weinhold	for (int32 i = 0; kPartitionTypes[i].name ; i++) {
274288102e6SIngo Weinhold		if (!strcmp(typeName, kPartitionTypes[i].name)) {
275288102e6SIngo Weinhold			fType = kPartitionTypes[i].type;
276288102e6SIngo Weinhold			fValid = true;
277260bb9a2SIngo Weinhold			return fValid;
27892b8ea1dSIngo Weinhold		}
27992b8ea1dSIngo Weinhold	}
280f3794156SIngo Weinhold
281f3794156SIngo Weinhold	// If this is an unrecognized type, parse the type number.
282f3794156SIngo Weinhold	if (strncmp(typeName, kUnrecognizedTypeString,
283f3794156SIngo Weinhold			kUnrecognizedTypeStringLength) == 0) {
284f3794156SIngo Weinhold		long type = strtol(typeName + kUnrecognizedTypeStringLength, NULL, 0);
285f3794156SIngo Weinhold		if (type != 0 && type <= 255) {
286f3794156SIngo Weinhold			fType = type;
287f3794156SIngo Weinhold			fValid = true;
288f3794156SIngo Weinhold			return fValid;
289f3794156SIngo Weinhold		}
290f3794156SIngo Weinhold	}
291f3794156SIngo Weinhold
292288102e6SIngo Weinhold	fValid = false;
293260bb9a2SIngo Weinhold	return fValid;
29492b8ea1dSIngo Weinhold}
29592b8ea1dSIngo Weinhold
296199f3324SAxel Dörfler
297199f3324SAxel Dörfler/*!	\brief Converts content type to the partition type that fits best.
298288102e6SIngo Weinhold	\param content_type Name of the content type, it is standardized by system.
299288102e6SIngo Weinhold*/
300260bb9a2SIngo Weinholdbool
3011987b05aSBryce GroffPartitionType::SetContentType(const char* contentType)
30292b8ea1dSIngo Weinhold{
30392b8ea1dSIngo Weinhold	for (int32 i = 0; kPartitionContentTypes[i].name ; i++) {
304288102e6SIngo Weinhold		if (!strcmp(contentType, kPartitionContentTypes[i].name)) {
305288102e6SIngo Weinhold			fType = kPartitionContentTypes[i].type;
306288102e6SIngo Weinhold			fValid = true;
307260bb9a2SIngo Weinhold			return fValid;
30892b8ea1dSIngo Weinhold		}
30992b8ea1dSIngo Weinhold	}
310288102e6SIngo Weinhold	fValid = false;
311260bb9a2SIngo Weinhold	return fValid;
31292b8ea1dSIngo Weinhold}
31392b8ea1dSIngo Weinhold
314199f3324SAxel Dörfler
315199f3324SAxel Dörfler/*!	\brief Finds next supported partition.
316288102e6SIngo Weinhold*/
317c6aab459SIngo Weinholdbool
31892b8ea1dSIngo WeinholdPartitionType::FindNext()
31992b8ea1dSIngo Weinhold{
32092b8ea1dSIngo Weinhold	for (int32 i = 0; kPartitionTypes[i].name; i++) {
321288102e6SIngo Weinhold		if (fType < kPartitionTypes[i].type) {
322288102e6SIngo Weinhold			fType = kPartitionTypes[i].type;
323288102e6SIngo Weinhold			fValid = true;
324c6aab459SIngo Weinhold			return true;
32592b8ea1dSIngo Weinhold		}
32692b8ea1dSIngo Weinhold	}
327288102e6SIngo Weinhold	fValid = false;
328c6aab459SIngo Weinhold	return false;
32992b8ea1dSIngo Weinhold}
33092b8ea1dSIngo Weinhold
33192b8ea1dSIngo Weinhold
332199f3324SAxel Dörfler/*!	\fn bool PartitionType::IsValid() const
333288102e6SIngo Weinhold	\brief Check whether the current type is valid.
334288102e6SIngo Weinhold*/
335288102e6SIngo Weinhold
336199f3324SAxel Dörfler/*!	\fn bool PartitionType::IsEmpty() const
337288102e6SIngo Weinhold	\brief Check whether the current type describes empty type.
338288102e6SIngo Weinhold*/
339288102e6SIngo Weinhold
340199f3324SAxel Dörfler/*!	\fn bool PartitionType::IsExtended() const
341288102e6SIngo Weinhold	\brief Check whether the current type describes extended partition type.
342288102e6SIngo Weinhold*/
343288102e6SIngo Weinhold
344199f3324SAxel Dörfler/*!	\fn uint8 PartitionType::Type() const
345288102e6SIngo Weinhold	\brief Returns ID of the current type.
346288102e6SIngo Weinhold*/
347288102e6SIngo Weinhold
348199f3324SAxel Dörfler/*!	\fn void PartitionType::GetTypeString(char *buffer) const
349288102e6SIngo Weinhold	\brief Returns string name of the current type.
350288102e6SIngo Weinhold	\param buffer Buffer where the name is stored, has to be allocated with
351288102e6SIngo Weinhold	sufficient length.
352288102e6SIngo Weinhold*/
353288102e6SIngo Weinhold
354288102e6SIngo Weinhold
3550e9f724cSAxel Dörfler//	#pragma mark - Partition
3560e9f724cSAxel Dörfler
357852d12efSIngo Weinhold
358852d12efSIngo WeinholdPartition::Partition()
35927ba18f4SAxel Dörfler	:
360b41bbb4aSAxel Dörfler	fPartitionTableOffset(0),
36127ba18f4SAxel Dörfler	fOffset(0),
36227ba18f4SAxel Dörfler	fSize(0),
36327ba18f4SAxel Dörfler	fType(0),
36427ba18f4SAxel Dörfler	fActive(false)
365852d12efSIngo Weinhold{
366852d12efSIngo Weinhold}
367852d12efSIngo Weinhold
368199f3324SAxel Dörfler
369b41bbb4aSAxel DörflerPartition::Partition(const partition_descriptor* descriptor, off_t tableOffset,
370199f3324SAxel Dörfler		off_t baseOffset, uint32 blockSize)
37127ba18f4SAxel Dörfler	:
372b41bbb4aSAxel Dörfler	fPartitionTableOffset(0),
37327ba18f4SAxel Dörfler	fOffset(0),
37427ba18f4SAxel Dörfler	fSize(0),
37527ba18f4SAxel Dörfler	fType(0),
37627ba18f4SAxel Dörfler	fActive(false)
377852d12efSIngo Weinhold{
378199f3324SAxel Dörfler	SetTo(descriptor, tableOffset, baseOffset, blockSize);
379852d12efSIngo Weinhold}
380852d12efSIngo Weinhold
381199f3324SAxel Dörfler
382852d12efSIngo Weinholdvoid
3831987b05aSBryce GroffPartition::SetTo(const partition_descriptor* descriptor, off_t tableOffset,
384199f3324SAxel Dörfler	off_t baseOffset, uint32 blockSize)
385852d12efSIngo Weinhold{
38627ba18f4SAxel Dörfler	TRACE(("Partition::SetTo(): active: %x\n", descriptor->active));
387199f3324SAxel Dörfler	SetTo(baseOffset + (off_t)descriptor->start * blockSize,
388199f3324SAxel Dörfler		(off_t)descriptor->size * blockSize, descriptor->type,
389199f3324SAxel Dörfler		descriptor->active, tableOffset, blockSize);
390260bb9a2SIngo Weinhold}
391260bb9a2SIngo Weinhold
392260bb9a2SIngo Weinhold
393260bb9a2SIngo Weinholdvoid
394260bb9a2SIngo WeinholdPartition::SetTo(off_t offset, off_t size, uint8 type, bool active,
395199f3324SAxel Dörfler	off_t tableOffset, uint32 blockSize)
396260bb9a2SIngo Weinhold{
397b41bbb4aSAxel Dörfler	fPartitionTableOffset = tableOffset;
398260bb9a2SIngo Weinhold	fOffset = offset;
399260bb9a2SIngo Weinhold	fSize = size;
400260bb9a2SIngo Weinhold	fType = type;
401260bb9a2SIngo Weinhold	fActive = active;
402199f3324SAxel Dörfler	fBlockSize = blockSize;
403260bb9a2SIngo Weinhold
404852d12efSIngo Weinhold	if (fSize == 0)
405852d12efSIngo Weinhold		Unset();
406852d12efSIngo Weinhold}
407852d12efSIngo Weinhold
408260bb9a2SIngo Weinhold
409852d12efSIngo Weinholdvoid
410852d12efSIngo WeinholdPartition::Unset()
411852d12efSIngo Weinhold{
412b41bbb4aSAxel Dörfler	fPartitionTableOffset = 0;
413852d12efSIngo Weinhold	fOffset = 0;
414852d12efSIngo Weinhold	fSize = 0;
415852d12efSIngo Weinhold	fType = 0;
416852d12efSIngo Weinhold	fActive = false;
417852d12efSIngo Weinhold}
418852d12efSIngo Weinhold
419199f3324SAxel Dörfler
420852d12efSIngo Weinholdbool
421db5c68caSIngo WeinholdPartition::CheckLocation(off_t sessionSize) const
422852d12efSIngo Weinhold{
4235e144a36SStephan Aßmus	if (fBlockSize == 0)
424841fd969SStephan Aßmus		return false;
425b41bbb4aSAxel Dörfler	// offsets and size must be block aligned, partition table and partition must
426b41bbb4aSAxel Dörfler	// lie within the session
427199f3324SAxel Dörfler	if (fPartitionTableOffset % fBlockSize != 0) {
428b41bbb4aSAxel Dörfler		TRACE(("Partition::CheckLocation() - bad partition table offset: %lld "
4291987b05aSBryce Groff			"(session: %lld), (fBlockSize: %ld)\n", fPartitionTableOffset,
4301987b05aSBryce Groff			sessionSize, fBlockSize));
4311dedfc14SStephan Aßmus		return false;
4321dedfc14SStephan Aßmus	}
433199f3324SAxel Dörfler	if (fOffset % fBlockSize != 0) {
4341dedfc14SStephan Aßmus		TRACE(("Partition::CheckLocation() - bad offset: %lld "
4351dedfc14SStephan Aßmus			"(session: %lld)\n", fOffset, sessionSize));
4361dedfc14SStephan Aßmus		return false;
4371dedfc14SStephan Aßmus	}
438199f3324SAxel Dörfler	if (fSize % fBlockSize != 0) {
4391dedfc14SStephan Aßmus		TRACE(("Partition::CheckLocation() - bad size: %lld "
4401dedfc14SStephan Aßmus			"(session: %lld)\n", fSize, sessionSize));
4411dedfc14SStephan Aßmus		return false;
4421dedfc14SStephan Aßmus	}
443b41bbb4aSAxel Dörfler	if (fPartitionTableOffset < 0 || fPartitionTableOffset >= sessionSize) {
444b41bbb4aSAxel Dörfler		TRACE(("Partition::CheckLocation() - partition table offset outside "
445b41bbb4aSAxel Dörfler			"session: %lld (session size: %lld)\n", fPartitionTableOffset,
446b41bbb4aSAxel Dörfler			sessionSize));
4471dedfc14SStephan Aßmus		return false;
4481dedfc14SStephan Aßmus	}
4491dedfc14SStephan Aßmus	if (fOffset < 0) {
4501dedfc14SStephan Aßmus		TRACE(("Partition::CheckLocation() - offset before session: %lld "
4511dedfc14SStephan Aßmus			"(session: %lld)\n", fOffset, sessionSize));
4521dedfc14SStephan Aßmus		return false;
4531dedfc14SStephan Aßmus	}
4541dedfc14SStephan Aßmus	if (fOffset + fSize > sessionSize) {
4551dedfc14SStephan Aßmus		TRACE(("Partition::CheckLocation() - end after session: %lld "
4561dedfc14SStephan Aßmus			"(session: %lld)\n", fOffset + fSize, sessionSize));
4571dedfc14SStephan Aßmus		return false;
4581dedfc14SStephan Aßmus	}
4591dedfc14SStephan Aßmus	return true;
460852d12efSIngo Weinhold}
461852d12efSIngo Weinhold
462852d12efSIngo Weinhold
463e4c0070fSMichael Lotzbool
464a0973602SAxel DörflerPartition::FitSizeToSession(off_t sessionSize)
465a0973602SAxel Dörfler{
466a0973602SAxel Dörfler	// To work around buggy (or older) BIOS, we shrink the partition size to
467a0973602SAxel Dörfler	// always fit into its session - this should improve detection of boot
468a0973602SAxel Dörfler	// partitions (see bug #238 for more information).
469a0973602SAxel Dörfler	// Also, the drive size is obviously reported differently sometimes; this
470a0973602SAxel Dörfler	// should let us read problematic drives - let the file system figure out
471a0973602SAxel Dörfler	// if something is wrong.
472e4c0070fSMichael Lotz	if (sessionSize < fOffset + fSize && sessionSize > fOffset) {
473a0973602SAxel Dörfler		fSize = sessionSize - fOffset;
474e4c0070fSMichael Lotz		return true;
475e4c0070fSMichael Lotz	}
476e4c0070fSMichael Lotz
477e4c0070fSMichael Lotz	return false;
478a0973602SAxel Dörfler}
479a0973602SAxel Dörfler
480a0973602SAxel Dörfler
4810e9f724cSAxel Dörfler//	#pragma mark - PrimaryPartition
4820e9f724cSAxel Dörfler
483852d12efSIngo Weinhold
484852d12efSIngo WeinholdPrimaryPartition::PrimaryPartition()
4851987b05aSBryce Groff	:
4861987b05aSBryce Groff	Partition(),
487199f3324SAxel Dörfler	fHead(NULL),
488199f3324SAxel Dörfler	fTail(NULL),
489199f3324SAxel Dörfler	fLogicalPartitionCount(0)
490852d12efSIngo Weinhold{
491852d12efSIngo Weinhold}
492852d12efSIngo Weinhold
493199f3324SAxel Dörfler
494852d12efSIngo Weinholdvoid
495b41bbb4aSAxel DörflerPrimaryPartition::SetTo(const partition_descriptor* descriptor,
496199f3324SAxel Dörfler	off_t tableOffset, uint32 blockSize)
497852d12efSIngo Weinhold{
498852d12efSIngo Weinhold	Unset();
499199f3324SAxel Dörfler	Partition::SetTo(descriptor, tableOffset, 0, blockSize);
500852d12efSIngo Weinhold}
501852d12efSIngo Weinhold
502260bb9a2SIngo Weinhold
503260bb9a2SIngo Weinholdvoid
504199f3324SAxel DörflerPrimaryPartition::SetTo(off_t offset, off_t size, uint8 type, bool active,
505199f3324SAxel Dörfler	uint32 blockSize)
506260bb9a2SIngo Weinhold{
507260bb9a2SIngo Weinhold	Unset();
508199f3324SAxel Dörfler	Partition::SetTo(offset, size, type, active, 0, blockSize);
509260bb9a2SIngo Weinhold}
510260bb9a2SIngo Weinhold
511260bb9a2SIngo Weinhold
512852d12efSIngo Weinholdvoid
513852d12efSIngo WeinholdPrimaryPartition::Unset()
514852d12efSIngo Weinhold{
5151987b05aSBryce Groff	while (LogicalPartition* partition = fHead) {
516852d12efSIngo Weinhold		fHead = partition->Next();
517852d12efSIngo Weinhold		delete partition;
518852d12efSIngo Weinhold	}
519852d12efSIngo Weinhold	fHead = NULL;
520852d12efSIngo Weinhold	fTail = NULL;
521852d12efSIngo Weinhold	fLogicalPartitionCount = 0;
522852d12efSIngo Weinhold	Partition::Unset();
523852d12efSIngo Weinhold}
524852d12efSIngo Weinhold
525bf95c9aeSIngo Weinhold
526bf95c9aeSIngo Weinholdstatus_t
527bf95c9aeSIngo WeinholdPrimaryPartition::Assign(const PrimaryPartition& other)
528bf95c9aeSIngo Weinhold{
529bf95c9aeSIngo Weinhold	partition_descriptor descriptor;
5301987b05aSBryce Groff	other.GetPartitionDescriptor(&descriptor);
531199f3324SAxel Dörfler	SetTo(&descriptor, 0, other.BlockSize());
532bf95c9aeSIngo Weinhold
533bf95c9aeSIngo Weinhold	const LogicalPartition* otherLogical = other.fHead;
534bf95c9aeSIngo Weinhold	while (otherLogical) {
535b41bbb4aSAxel Dörfler		off_t tableOffset = otherLogical->PartitionTableOffset();
5361987b05aSBryce Groff		otherLogical->GetPartitionDescriptor(&descriptor);
537bf95c9aeSIngo Weinhold
538bf95c9aeSIngo Weinhold		LogicalPartition* logical = new(nothrow) LogicalPartition(
539b41bbb4aSAxel Dörfler			&descriptor, tableOffset, this);
540bf95c9aeSIngo Weinhold		if (!logical)
541bf95c9aeSIngo Weinhold			return B_NO_MEMORY;
542bf95c9aeSIngo Weinhold
543bf95c9aeSIngo Weinhold		AddLogicalPartition(logical);
544bf95c9aeSIngo Weinhold
545bf95c9aeSIngo Weinhold		otherLogical = otherLogical->Next();
546bf95c9aeSIngo Weinhold	}
547bf95c9aeSIngo Weinhold
548bf95c9aeSIngo Weinhold	return B_OK;
549bf95c9aeSIngo Weinhold}
550bf95c9aeSIngo Weinhold
551bf95c9aeSIngo Weinhold
5521987b05aSBryce Groffvoid
5531987b05aSBryce GroffPrimaryPartition::GetPartitionDescriptor(partition_descriptor* descriptor) const
5541987b05aSBryce Groff{
5551987b05aSBryce Groff	if (IsEmpty()) {
5561987b05aSBryce Groff		memset(descriptor, 0, sizeof(partition_descriptor));
5571987b05aSBryce Groff	} else {
5581987b05aSBryce Groff		descriptor->start = Offset() / BlockSize();
5591987b05aSBryce Groff		descriptor->size = Size() / BlockSize();
5601987b05aSBryce Groff		descriptor->type = Type();
5611987b05aSBryce Groff		descriptor->active = Active() ? 0x80 : 0x00;
56230cf9c3cSAdrien Destugues		descriptor->begin.SetUnused();
56330cf9c3cSAdrien Destugues		descriptor->end.SetUnused();
5641987b05aSBryce Groff	}
5651987b05aSBryce Groff}
5661987b05aSBryce Groff
5671987b05aSBryce Groff
568199f3324SAxel DörflerLogicalPartition*
569852d12efSIngo WeinholdPrimaryPartition::LogicalPartitionAt(int32 index) const
570852d12efSIngo Weinhold{
5711987b05aSBryce Groff	LogicalPartition* partition = NULL;
572852d12efSIngo Weinhold	if (index >= 0 && index < fLogicalPartitionCount) {
573852d12efSIngo Weinhold		for (partition = fHead; index > 0; index--)
574852d12efSIngo Weinhold			partition = partition->Next();
575852d12efSIngo Weinhold	}
576852d12efSIngo Weinhold	return partition;
577852d12efSIngo Weinhold}
578852d12efSIngo Weinhold
579199f3324SAxel Dörfler
580852d12efSIngo Weinholdvoid
581199f3324SAxel DörflerPrimaryPartition::AddLogicalPartition(LogicalPartition* partition)
582852d12efSIngo Weinhold{
583e9a10566SStephan Aßmus	if (!partition)
584e9a10566SStephan Aßmus		return;
585e9a10566SStephan Aßmus
586e9a10566SStephan Aßmus	partition->SetPrimaryPartition(this);
587e9a10566SStephan Aßmus	partition->SetPrevious(fTail);
588e9a10566SStephan Aßmus	if (fTail) {
589e9a10566SStephan Aßmus		fTail->SetNext(partition);
590e9a10566SStephan Aßmus		fTail = partition;
591e9a10566SStephan Aßmus	} else
592e9a10566SStephan Aßmus		fHead = fTail = partition;
593199f3324SAxel Dörfler
594e9a10566SStephan Aßmus	partition->SetNext(NULL);
595e9a10566SStephan Aßmus
596e9a10566SStephan Aßmus	fLogicalPartitionCount++;
597852d12efSIngo Weinhold}
598852d12efSIngo Weinhold
599199f3324SAxel Dörfler
60092b8ea1dSIngo Weinholdvoid
601199f3324SAxel DörflerPrimaryPartition::RemoveLogicalPartition(LogicalPartition* partition)
60292b8ea1dSIngo Weinhold{
60392b8ea1dSIngo Weinhold	if (!partition || partition->GetPrimaryPartition() != this)
60492b8ea1dSIngo Weinhold		return;
605199f3324SAxel Dörfler
6061987b05aSBryce Groff	LogicalPartition* prev = partition->Previous();
6071987b05aSBryce Groff	LogicalPartition* next = partition->Next();
60892b8ea1dSIngo Weinhold
60992b8ea1dSIngo Weinhold	if (prev)
61092b8ea1dSIngo Weinhold		prev->SetNext(next);
61192b8ea1dSIngo Weinhold	else
61292b8ea1dSIngo Weinhold		fHead = next;
61392b8ea1dSIngo Weinhold	if (next)
61492b8ea1dSIngo Weinhold		next->SetPrevious(prev);
61592b8ea1dSIngo Weinhold	else
61692b8ea1dSIngo Weinhold		fTail = prev;
617e9a10566SStephan Aßmus
61892b8ea1dSIngo Weinhold	fLogicalPartitionCount--;
61992b8ea1dSIngo Weinhold
62092b8ea1dSIngo Weinhold	partition->SetNext(NULL);
62192b8ea1dSIngo Weinhold	partition->SetPrevious(NULL);
62292b8ea1dSIngo Weinhold	partition->SetPrimaryPartition(NULL);
62392b8ea1dSIngo Weinhold}
62492b8ea1dSIngo Weinhold
625852d12efSIngo Weinhold
6260e9f724cSAxel Dörfler//	#pragma mark - LogicalPartition
6270e9f724cSAxel Dörfler
628852d12efSIngo Weinhold
629852d12efSIngo WeinholdLogicalPartition::LogicalPartition()
6301987b05aSBryce Groff	:
6311987b05aSBryce Groff	Partition(),
632199f3324SAxel Dörfler	fPrimary(NULL),
633199f3324SAxel Dörfler	fNext(NULL),
634199f3324SAxel Dörfler	fPrevious(NULL)
635852d12efSIngo Weinhold{
636852d12efSIngo Weinhold}
637852d12efSIngo Weinhold
638199f3324SAxel Dörfler
639199f3324SAxel DörflerLogicalPartition::LogicalPartition(const partition_descriptor* descriptor,
640199f3324SAxel Dörfler		off_t tableOffset, PrimaryPartition* primary)
6411987b05aSBryce Groff	:
6421987b05aSBryce Groff	Partition(),
643199f3324SAxel Dörfler	fPrimary(NULL),
644199f3324SAxel Dörfler	fNext(NULL),
645199f3324SAxel Dörfler	fPrevious(NULL)
646852d12efSIngo Weinhold{
647b41bbb4aSAxel Dörfler	SetTo(descriptor, tableOffset, primary);
648852d12efSIngo Weinhold}
649852d12efSIngo Weinhold
650199f3324SAxel Dörfler
651852d12efSIngo Weinholdvoid
652199f3324SAxel DörflerLogicalPartition::SetTo(const partition_descriptor* descriptor,
653199f3324SAxel Dörfler	off_t tableOffset, PrimaryPartition* primary)
654852d12efSIngo Weinhold{
655852d12efSIngo Weinhold	Unset();
656852d12efSIngo Weinhold	if (descriptor && primary) {
657aecd884eSStephan Aßmus		// There are two types of LogicalPartitions. There are so called
658aecd884eSStephan Aßmus		// "inner extended" partitions and the "real" logical partitions
659aecd884eSStephan Aßmus		// which contain data. The "inner extended" partitions don't contain
660b41bbb4aSAxel Dörfler		// data and are only used to point to the next partition table in the
661b41bbb4aSAxel Dörfler		// linked list of logical partitions. For "inner extended" partitions,
662aecd884eSStephan Aßmus		// the baseOffset is in relation to the (first sector of the)
663aecd884eSStephan Aßmus		// "primary extended" partition, in another words, all inner extended
664aecd884eSStephan Aßmus		// partitions use the same base offset for reference.
665aecd884eSStephan Aßmus		// The data containing, real logical partitions use the offset of the
666b41bbb4aSAxel Dörfler		// partition table that contains their partition descriptor as their
667b41bbb4aSAxel Dörfler		// baseOffset.
668b41bbb4aSAxel Dörfler		off_t baseOffset = descriptor->is_extended()
669b41bbb4aSAxel Dörfler			? primary->Offset() : tableOffset;
670199f3324SAxel Dörfler		Partition::SetTo(descriptor, tableOffset, baseOffset,
671199f3324SAxel Dörfler			primary->BlockSize());
672852d12efSIngo Weinhold		fPrimary = primary;
673852d12efSIngo Weinhold	}
674852d12efSIngo Weinhold}
675852d12efSIngo Weinhold
676260bb9a2SIngo Weinhold
677260bb9a2SIngo Weinholdvoid
678260bb9a2SIngo WeinholdLogicalPartition::SetTo(off_t offset, off_t size, uint8 type, bool active,
6791987b05aSBryce Groff	off_t tableOffset, PrimaryPartition* primary)
680260bb9a2SIngo Weinhold{
681260bb9a2SIngo Weinhold	Unset();
682260bb9a2SIngo Weinhold	if (primary) {
683199f3324SAxel Dörfler		Partition::SetTo(offset, size, type, active, tableOffset,
684199f3324SAxel Dörfler			primary->BlockSize());
685260bb9a2SIngo Weinhold		fPrimary = primary;
686260bb9a2SIngo Weinhold	}
687260bb9a2SIngo Weinhold}
688260bb9a2SIngo Weinhold
689260bb9a2SIngo Weinhold
690852d12efSIngo Weinholdvoid
691852d12efSIngo WeinholdLogicalPartition::Unset()
692852d12efSIngo Weinhold{
693852d12efSIngo Weinhold	fPrimary = NULL;
694852d12efSIngo Weinhold	fNext = NULL;
69592b8ea1dSIngo Weinhold	fPrevious = NULL;
696852d12efSIngo Weinhold	Partition::Unset();
697852d12efSIngo Weinhold}
698852d12efSIngo Weinhold
699852d12efSIngo Weinhold
7001987b05aSBryce Groffvoid
7011987b05aSBryce GroffLogicalPartition::GetPartitionDescriptor(partition_descriptor* descriptor,
7021987b05aSBryce Groff	bool inner) const
7031987b05aSBryce Groff{
7041987b05aSBryce Groff	PrimaryPartition* primary = GetPrimaryPartition();
7051987b05aSBryce Groff	if (inner) {
7061987b05aSBryce Groff		descriptor->start = (PartitionTableOffset() - primary->Offset())
7071987b05aSBryce Groff			/ BlockSize();
7081987b05aSBryce Groff		descriptor->type = primary->Type();
7091987b05aSBryce Groff	} else {
7101987b05aSBryce Groff		descriptor->start = (Offset() - PartitionTableOffset()) / BlockSize();
7111987b05aSBryce Groff		descriptor->type = Type();
7121987b05aSBryce Groff	}
7131987b05aSBryce Groff
7141987b05aSBryce Groff	descriptor->size = Size() / BlockSize();
7151987b05aSBryce Groff	descriptor->active = 0x00;
71630cf9c3cSAdrien Destugues	descriptor->begin.SetUnused();
71730cf9c3cSAdrien Destugues	descriptor->end.SetUnused();
7181987b05aSBryce Groff}
7191987b05aSBryce Groff
7201987b05aSBryce Groff
7210e9f724cSAxel Dörfler//	#pragma mark - PartitionMap
7220e9f724cSAxel Dörfler
723852d12efSIngo Weinhold
724852d12efSIngo WeinholdPartitionMap::PartitionMap()
725852d12efSIngo Weinhold{
726bf95c9aeSIngo Weinhold	for (int32 i = 0; i < 4; i++)
727bf95c9aeSIngo Weinhold		fPrimaries[i].SetIndex(i);
728852d12efSIngo Weinhold}
729852d12efSIngo Weinhold
730b41bbb4aSAxel Dörfler
731852d12efSIngo WeinholdPartitionMap::~PartitionMap()
732852d12efSIngo Weinhold{
733852d12efSIngo Weinhold}
734852d12efSIngo Weinhold
735b41bbb4aSAxel Dörfler
736852d12efSIngo Weinholdvoid
737852d12efSIngo WeinholdPartitionMap::Unset()
738852d12efSIngo Weinhold{
739852d12efSIngo Weinhold	for (int32 i = 0; i < 4; i++)
740852d12efSIngo Weinhold		fPrimaries[i].Unset();
741852d12efSIngo Wei