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, int32 blockSize) 42 : fDeviceFD(deviceFD), 43 fSessionOffset(sessionOffset), 44 fSessionSize(sessionSize), 45 fBlockSize(blockSize), 46 fPTS(NULL), 47 fMap(NULL) 48 { 49 } 50 51 // destructor 52 PartitionMapParser::~PartitionMapParser() 53 { 54 } 55 56 // Parse 57 status_t 58 PartitionMapParser::Parse(const uint8 *block, PartitionMap *map) 59 { 60 status_t error = (map ? B_OK : B_BAD_VALUE); 61 if (error == B_OK) { 62 fMap = map; 63 fMap->Unset(); 64 if (block) { 65 const partition_table_sector *pts 66 = (const partition_table_sector*)block; 67 error = _ParsePrimary(pts); 68 } else { 69 partition_table_sector pts; 70 error = _ReadPTS(0, &pts); 71 if (error == B_OK) 72 error = _ParsePrimary(&pts); 73 } 74 75 // If we don't have any partitions it might also just be an 76 // empty partition map, but we still can't do much with it 77 if (error == B_OK 78 && (fMap->CountNonEmptyPartitions() == 0 79 || !fMap->Check(fSessionSize, fBlockSize))) { 80 error = B_BAD_DATA; 81 } 82 fMap = NULL; 83 } 84 return error; 85 } 86 87 // _ParsePrimary 88 status_t 89 PartitionMapParser::_ParsePrimary(const partition_table_sector *pts) 90 { 91 if (pts == NULL) 92 return B_BAD_VALUE; 93 94 // check the signature 95 if (pts->signature != kPartitionTableSectorSignature) { 96 TRACE(("intel: _ParsePrimary(): invalid PTS signature\n")); 97 return B_BAD_DATA; 98 } 99 100 // examine the table 101 for (int32 i = 0; i < 4; i++) { 102 const partition_descriptor *descriptor = &pts->table[i]; 103 PrimaryPartition *partition = fMap->PrimaryPartitionAt(i); 104 partition->SetTo(descriptor, 0, fBlockSize); 105 106 #ifdef _BOOT_MODE 107 // work-around potential BIOS problems 108 partition->AdjustSize(fSessionSize); 109 #endif 110 // ignore, if location is bad 111 if (!partition->CheckLocation(fSessionSize, fBlockSize)) { 112 TRACE(("intel: _ParsePrimary(): partition %ld: bad location, " 113 "ignoring\n", i)); 114 partition->Unset(); 115 } 116 } 117 118 // allocate a PTS buffer 119 fPTS = new(nothrow) partition_table_sector; 120 if (fPTS == NULL) 121 return B_NO_MEMORY; 122 123 // parse extended partitions 124 status_t error = B_OK; 125 for (int32 i = 0; error == B_OK && i < 4; i++) { 126 PrimaryPartition *primary = fMap->PrimaryPartitionAt(i); 127 if (primary->IsExtended()) 128 error = _ParseExtended(primary, primary->Offset()); 129 } 130 131 // cleanup 132 delete fPTS; 133 fPTS = NULL; 134 135 return error; 136 } 137 138 // _ParseExtended 139 status_t 140 PartitionMapParser::_ParseExtended(PrimaryPartition *primary, off_t offset) 141 { 142 status_t error = B_OK; 143 int32 partitionCount = 0; 144 while (error == B_OK) { 145 // check for cycles 146 if (++partitionCount > kMaxLogicalPartitionCount) { 147 TRACE(("intel: _ParseExtended(): Maximal number of logical " 148 "partitions for extended partition reached. Cycle?\n")); 149 error = B_BAD_DATA; 150 } 151 152 // read the PTS 153 if (error == B_OK) 154 error = _ReadPTS(offset); 155 156 // check the signature 157 if (error == B_OK 158 && fPTS->signature != kPartitionTableSectorSignature) { 159 TRACE(("intel: _ParseExtended(): invalid PTS signature\n")); 160 error = B_BAD_DATA; 161 } 162 163 // ignore the PTS, if any error occured till now 164 if (error != B_OK) { 165 TRACE(("intel: _ParseExtended(): ignoring this PTS\n")); 166 error = B_OK; 167 break; 168 } 169 170 // examine the table 171 LogicalPartition extended; 172 LogicalPartition nonExtended; 173 if (error == B_OK) { 174 for (int32 i = 0; error == B_OK && i < 4; i++) { 175 const partition_descriptor *descriptor = &fPTS->table[i]; 176 LogicalPartition *partition = NULL; 177 if (!descriptor->is_empty()) { 178 if (descriptor->is_extended()) { 179 if (extended.IsEmpty()) { 180 extended.SetTo(descriptor, offset, fBlockSize, 181 primary); 182 partition = &extended; 183 } else { 184 // only one extended partition allowed 185 error = B_BAD_DATA; 186 TRACE(("intel: _ParseExtended(): " 187 "only one extended partition allowed\n")); 188 } 189 } else { 190 if (nonExtended.IsEmpty()) { 191 nonExtended.SetTo(descriptor, offset, fBlockSize, 192 primary); 193 partition = &nonExtended; 194 } else { 195 // only one non-extended partition allowed 196 error = B_BAD_DATA; 197 TRACE(("intel: _ParseExtended(): only one " 198 "non-extended partition allowed\n")); 199 } 200 } 201 #ifdef _BOOT_MODE 202 // work-around potential BIOS problems 203 if (partition) 204 partition->AdjustSize(fSessionSize); 205 #endif 206 // check the partition's location 207 if (partition && !partition->CheckLocation(fSessionSize, 208 fBlockSize)) { 209 error = B_BAD_DATA; 210 TRACE(("intel: _ParseExtended(): Invalid partition " 211 "location: pts: %lld, offset: %lld, size: %lld\n", 212 partition->PTSOffset(), partition->Offset(), 213 partition->Size())); 214 } 215 } 216 } 217 } 218 219 // add non-extended partition to list 220 if (error == B_OK && !nonExtended.IsEmpty()) { 221 LogicalPartition *partition 222 = new(nothrow) LogicalPartition(nonExtended); 223 if (partition) 224 primary->AddLogicalPartition(partition); 225 else 226 error = B_NO_MEMORY; 227 } 228 229 // prepare to parse next extended partition 230 if (error == B_OK && !extended.IsEmpty()) 231 offset = extended.Offset(); 232 else 233 break; 234 } 235 236 return error; 237 } 238 239 // _ReadPTS 240 status_t 241 PartitionMapParser::_ReadPTS(off_t offset, partition_table_sector *pts) 242 { 243 status_t error = B_OK; 244 if (!pts) 245 pts = fPTS; 246 int32 toRead = sizeof(partition_table_sector); 247 // check the offset 248 if (offset < 0 || offset + toRead > fSessionSize) { 249 error = B_BAD_VALUE; 250 TRACE(("intel: _ReadPTS(): bad offset: %Ld\n", offset)); 251 // read 252 } else if (read_pos(fDeviceFD, fSessionOffset + offset, pts, toRead) 253 != toRead) { 254 #ifndef _BOOT_MODE 255 error = errno; 256 if (error == B_OK) 257 error = B_IO_ERROR; 258 #else 259 error = B_IO_ERROR; 260 #endif 261 TRACE(("intel: _ReadPTS(): reading the PTS failed: %lx\n", error)); 262 } 263 return error; 264 } 265 266