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