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