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