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 170 LogicalPartition extended; 171 LogicalPartition nonExtended; 172 if (error == B_OK) { 173 for (int32 i = 0; error == B_OK && i < 4; i++) { 174 const partition_descriptor *descriptor = &fPTS->table[i]; 175 LogicalPartition *partition = NULL; 176 if (!descriptor->is_empty()) { 177 if (descriptor->is_extended()) { 178 if (extended.IsEmpty()) { 179 extended.SetTo(descriptor, offset, primary); 180 partition = &extended; 181 } else { 182 // only one extended partition allowed 183 error = B_BAD_DATA; 184 TRACE(("intel: _ParseExtended(): " 185 "only one extended partition allowed\n")); 186 } 187 } else { 188 if (nonExtended.IsEmpty()) { 189 nonExtended.SetTo(descriptor, offset, primary); 190 partition = &nonExtended; 191 } else { 192 // only one non-extended partition allowed 193 error = B_BAD_DATA; 194 TRACE(("intel: _ParseExtended(): only one " 195 "non-extended partition allowed\n")); 196 } 197 } 198 #ifdef _BOOT_MODE 199 // work-around potential BIOS problems 200 if (partition) 201 partition->AdjustSize(fSessionSize); 202 #endif 203 // check the partition's location 204 if (partition && !partition->CheckLocation(fSessionSize)) { 205 error = B_BAD_DATA; 206 TRACE(("intel: _ParseExtended(): Invalid partition " 207 "location: pts: %lld, offset: %lld, size: %lld\n", 208 partition->PTSOffset(), partition->Offset(), 209 partition->Size())); 210 } 211 } 212 } 213 } 214 215 // add non-extended partition to list 216 if (error == B_OK && !nonExtended.IsEmpty()) { 217 LogicalPartition *partition 218 = new(nothrow) LogicalPartition(nonExtended); 219 if (partition) 220 primary->AddLogicalPartition(partition); 221 else 222 error = B_NO_MEMORY; 223 } 224 225 // prepare to parse next extended partition 226 if (error == B_OK && !extended.IsEmpty()) 227 offset = extended.Offset(); 228 else 229 break; 230 } 231 232 return error; 233 } 234 235 // _ReadPTS 236 status_t 237 PartitionMapParser::_ReadPTS(off_t offset, partition_table_sector *pts) 238 { 239 status_t error = B_OK; 240 if (!pts) 241 pts = fPTS; 242 int32 toRead = sizeof(partition_table_sector); 243 // check the offset 244 if (offset < 0 || offset + toRead > fSessionSize) { 245 error = B_BAD_VALUE; 246 TRACE(("intel: _ReadPTS(): bad offset: %Ld\n", offset)); 247 // read 248 } else if (read_pos(fDeviceFD, fSessionOffset + offset, pts, toRead) 249 != toRead) { 250 #ifndef _BOOT_MODE 251 error = errno; 252 if (error == B_OK) 253 error = B_IO_ERROR; 254 #else 255 error = B_IO_ERROR; 256 #endif 257 TRACE(("intel: _ReadPTS(): reading the PTS failed: %lx\n", error)); 258 } 259 return error; 260 } 261 262