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