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