xref: /haiku/src/add-ons/kernel/partitioning_systems/intel/PartitionMapParser.cpp (revision 1b8f7f13a3dc70e0e903cb94248220b40b732204)
1 /*
2  * Copyright 2003-2006, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ingo Weinhold, bonefish@cs.tu-berlin.de
7  */
8 
9 
10 #ifndef _USER_MODE
11 #	include <KernelExport.h>
12 #endif
13 
14 #include <errno.h>
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <string.h>
18 
19 #include <new>
20 
21 #include "PartitionMap.h"
22 #include "PartitionMapParser.h"
23 
24 #define TRACE_ENABLED
25 
26 #ifdef TRACE_ENABLED
27 #	ifdef _USER_MODE
28 #		define TRACE(x) printf x
29 #	else
30 #		define TRACE(x) dprintf x
31 #	endif
32 #endif
33 
34 using std::nothrow;
35 
36 // Maximal number of logical partitions per extended partition we allow.
37 static const int32 kMaxLogicalPartitionCount = 128;
38 
39 // constructor
40 PartitionMapParser::PartitionMapParser(int deviceFD, off_t sessionOffset,
41 		off_t sessionSize)
42 	: fDeviceFD(deviceFD),
43 	  fSessionOffset(sessionOffset),
44 	  fSessionSize(sessionSize),
45 	  fPTS(NULL),
46 	  fMap(NULL)
47 {
48 }
49 
50 // destructor
51 PartitionMapParser::~PartitionMapParser()
52 {
53 }
54 
55 // Parse
56 status_t
57 PartitionMapParser::Parse(const uint8 *block, PartitionMap *map)
58 {
59 	status_t error = (map ? B_OK : B_BAD_VALUE);
60 	if (error == B_OK) {
61 		fMap = map;
62 		fMap->Unset();
63 		if (block) {
64 			const partition_table_sector *pts
65 				= (const partition_table_sector*)block;
66 			error = _ParsePrimary(pts);
67 		} else {
68 			partition_table_sector pts;
69 			error = _ReadPTS(0, &pts);
70 			if (error == B_OK)
71 				error = _ParsePrimary(&pts);
72 		}
73 
74 		if (error == B_OK && !fMap->Check(fSessionSize))
75 			error = B_BAD_DATA;
76 
77 		fMap = NULL;
78 	}
79 	return error;
80 }
81 
82 // _ParsePrimary
83 status_t
84 PartitionMapParser::_ParsePrimary(const partition_table_sector *pts)
85 {
86 	if (pts == NULL)
87 		return B_BAD_VALUE;
88 
89 	// check the signature
90 	if (pts->signature != kPartitionTableSectorSignature) {
91 		TRACE(("intel: _ParsePrimary(): invalid PTS signature\n"));
92 		return B_BAD_DATA;
93 	}
94 
95 	// examine the table
96 	for (int32 i = 0; i < 4; i++) {
97 		const partition_descriptor *descriptor = &pts->table[i];
98 		PrimaryPartition *partition = fMap->PrimaryPartitionAt(i);
99 		partition->SetTo(descriptor, 0);
100 
101 #ifdef _BOOT_MODE
102 		// work-around potential BIOS problems
103 		partition->AdjustSize(fSessionSize);
104 #endif
105 		// ignore, if location is bad
106 		if (!partition->CheckLocation(fSessionSize)) {
107 			TRACE(("intel: _ParsePrimary(): partition %ld: bad location, "
108 				"ignoring\n", i));
109 			partition->Unset();
110 		}
111 	}
112 
113 	// allocate a PTS buffer
114 	fPTS = new(nothrow) partition_table_sector;
115 	if (fPTS == NULL)
116 		return B_NO_MEMORY;
117 
118 	// parse extended partitions
119 	status_t error = B_OK;
120 	for (int32 i = 0; error == B_OK && i < 4; i++) {
121 		PrimaryPartition *primary = fMap->PrimaryPartitionAt(i);
122 		if (primary->IsExtended())
123 			error = _ParseExtended(primary, primary->Offset());
124 	}
125 
126 	// cleanup
127 	delete fPTS;
128 	fPTS = NULL;
129 
130 	return error;
131 }
132 
133 // _ParseExtended
134 status_t
135 PartitionMapParser::_ParseExtended(PrimaryPartition *primary, off_t offset)
136 {
137 	status_t error = B_OK;
138 	int32 partitionCount = 0;
139 	while (error == B_OK) {
140 		// check for cycles
141 		if (++partitionCount > kMaxLogicalPartitionCount) {
142 			TRACE(("intel: _ParseExtended(): Maximal number of logical "
143 				   "partitions for extended partition reached. Cycle?\n"));
144 			error = B_BAD_DATA;
145 		}
146 
147 		// read the PTS
148 		if (error == B_OK)
149 			error = _ReadPTS(offset);
150 
151 		// check the signature
152 		if (error == B_OK
153 			&& fPTS->signature != kPartitionTableSectorSignature) {
154 			TRACE(("intel: _ParseExtended(): invalid PTS signature\n"));
155 			error = B_BAD_DATA;
156 		}
157 
158 		// ignore the PTS, if any error occured till now
159 		if (error != B_OK) {
160 			TRACE(("intel: _ParseExtended(): ignoring this PTS\n"));
161 			error = B_OK;
162 			break;
163 		}
164 
165 		// examine the table
166 		LogicalPartition extended;
167 		LogicalPartition nonExtended;
168 		if (error == B_OK) {
169 			for (int32 i = 0; error == B_OK && i < 4; i++) {
170 				const partition_descriptor *descriptor = &fPTS->table[i];
171 				LogicalPartition *partition = NULL;
172 				if (!descriptor->is_empty()) {
173 					if (descriptor->is_extended()) {
174 						if (extended.IsEmpty()) {
175 							extended.SetTo(descriptor, offset, primary);
176 							partition = &extended;
177 						} else {
178 							// only one extended partition allowed
179 							error = B_BAD_DATA;
180 							TRACE(("intel: _ParseExtended(): "
181 								   "only one extended partition allowed\n"));
182 						}
183 					} else {
184 						if (nonExtended.IsEmpty()) {
185 							nonExtended.SetTo(descriptor, offset, primary);
186 							partition = &nonExtended;
187 						} else {
188 							// only one non-extended partition allowed
189 							error = B_BAD_DATA;
190 							TRACE(("intel: _ParseExtended(): only one "
191 								   "non-extended partition allowed\n"));
192 						}
193 					}
194 #ifdef _BOOT_MODE
195 					// work-around potential BIOS problems
196 					if (partition)
197 						partition->AdjustSize(fSessionSize);
198 #endif
199 					// check the partition's location
200 					if (partition && !partition->CheckLocation(fSessionSize)) {
201 						error = B_BAD_DATA;
202 						TRACE(("intel: _ParseExtended(): Invalid partition "
203 							"location: pts: %lld, offset: %lld, size: %lld\n",
204 							partition->PTSOffset(), partition->Offset(),
205 							partition->Size()));
206 					}
207 				}
208 			}
209 		}
210 
211 		// add non-extended partition to list
212 		if (error == B_OK && !nonExtended.IsEmpty()) {
213 			LogicalPartition *partition
214 				= new(nothrow) LogicalPartition(nonExtended);
215 			if (partition)
216 				primary->AddLogicalPartition(partition);
217 			else
218 				error = B_NO_MEMORY;
219 		}
220 
221 		// prepare to parse next extended partition
222 		if (error == B_OK && !extended.IsEmpty())
223 			offset = extended.Offset();
224 		else
225 			break;
226 	}
227 
228 	return error;
229 }
230 
231 // _ReadPTS
232 status_t
233 PartitionMapParser::_ReadPTS(off_t offset, partition_table_sector *pts)
234 {
235 	status_t error = B_OK;
236 	if (!pts)
237 		pts = fPTS;
238 	int32 toRead = sizeof(partition_table_sector);
239 	// check the offset
240 	if (offset < 0 || offset + toRead > fSessionSize) {
241 		error = B_BAD_VALUE;
242 		TRACE(("intel: _ReadPTS(): bad offset: %Ld\n", offset));
243 	// read
244 	} else if (read_pos(fDeviceFD, fSessionOffset + offset, pts, toRead)
245 						!= toRead) {
246 #ifndef _BOOT_MODE
247 		error = errno;
248 		if (error == B_OK)
249 			error = B_IO_ERROR;
250 #else
251 		error = B_IO_ERROR;
252 #endif
253 		TRACE(("intel: _ReadPTS(): reading the PTS failed: %lx\n", error));
254 	}
255 	return error;
256 }
257 
258