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