1 /* 2 * Copyright 2003-2009, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Bryce Groff, brycegroff@gmail.com 7 */ 8 9 #include "PartitionMapWriter.h" 10 11 #include <errno.h> 12 #include <stdio.h> 13 #include <string.h> 14 #include <unistd.h> 15 16 #include <new> 17 18 #ifndef _USER_MODE 19 #include <debug.h> 20 #endif 21 22 #ifndef _USER_MODE 23 # include <KernelExport.h> 24 #endif 25 26 #include "PartitionMap.h" 27 28 using std::nothrow; 29 30 31 #define TRACE_ENABLED 32 #ifdef TRACE_ENABLED 33 # ifdef _USER_MODE 34 # define TRACE(x) printf x 35 # else 36 # define TRACE(x) dprintf x 37 # endif 38 #endif 39 40 41 #if defined(__i386__) || defined(__x86_64__) 42 # ifndef _USER_MODE 43 # define MBR_HEADER "MBR.h" 44 # include MBR_HEADER 45 # endif 46 #endif 47 48 49 bool 50 check_logical_location(const LogicalPartition* child, 51 const PrimaryPartition* parent) 52 { 53 if (child->PartitionTableOffset() % child->BlockSize() != 0) { 54 TRACE(("check_logical_location() - PartitionTableOffset: %" B_PRId64 " " 55 "not a multiple of media's block size: %" B_PRId32 "\n", 56 child->PartitionTableOffset(), child->BlockSize())); 57 return false; 58 } 59 if (child->Offset() % child->BlockSize() != 0) { 60 TRACE(("check_logical_location() - Parition offset: %" B_PRId64 " " 61 "is not a multiple of block size: %" B_PRId32 "\n", child->Offset(), 62 child->BlockSize())); 63 return false; 64 } 65 if (child->Size() % child->BlockSize() != 0) { 66 TRACE(("check_logical_location() - Size: (%" B_PRId64 ") is not a " 67 "multiple of block size: (%" B_PRId32 ")\n", child->Size(), 68 child->BlockSize())); 69 return false; 70 } 71 if (child->PartitionTableOffset() < parent->Offset() 72 || child->PartitionTableOffset() >= parent->Offset() 73 + parent->Size()) { 74 TRACE(("check_logical_location() - Partition table: (%" B_PRId64 ") not" 75 " within extended partition (start: %" B_PRId64 "), (end: " 76 "%" B_PRId64 ")\n", child->PartitionTableOffset(), parent->Offset(), 77 parent->Offset() + parent->Size())); 78 return false; 79 } 80 if (child->Offset() + child->Size() > parent->Offset() + parent->Size()) { 81 TRACE(("check_logical_location() - logical paritition does not lie " 82 "within extended partition\n")); 83 return false; 84 } 85 return true; 86 } 87 88 89 PartitionMapWriter::PartitionMapWriter(int deviceFD, uint32 blockSize) 90 : 91 fDeviceFD(deviceFD), 92 fBlockSize(blockSize) 93 { 94 } 95 96 97 PartitionMapWriter::~PartitionMapWriter() 98 { 99 } 100 101 102 status_t 103 PartitionMapWriter::WriteMBR(const PartitionMap* map, bool writeBootCode) 104 { 105 if (map == NULL) 106 return B_BAD_VALUE; 107 108 partition_table partitionTable; 109 status_t error = _ReadBlock(0, partitionTable); 110 if (error != B_OK) 111 return error; 112 #ifdef MBR_HEADER 113 if (writeBootCode) { 114 // the boot code must be small enough to fit in the code area 115 STATIC_ASSERT(kMBRSize <= sizeof(partitionTable.code_area)); 116 partitionTable.clear_code_area(); 117 partitionTable.fill_code_area(kMBR, kMBRSize); 118 } 119 #endif 120 121 partitionTable.signature = kPartitionTableSectorSignature; 122 123 for (int i = 0; i < 4; i++) { 124 partition_descriptor* descriptor = &partitionTable.table[i]; 125 const PrimaryPartition* partition = map->PrimaryPartitionAt(i); 126 127 partition->GetPartitionDescriptor(descriptor); 128 } 129 130 error = _WriteBlock(0, partitionTable); 131 return error; 132 } 133 134 135 status_t 136 PartitionMapWriter::WriteLogical(const LogicalPartition* logical, 137 const PrimaryPartition* primary, bool clearCode) 138 { 139 if (logical == NULL || primary == NULL) 140 return B_BAD_VALUE; 141 142 if (!check_logical_location(logical, primary)) 143 return B_BAD_DATA; 144 145 partition_table partitionTable; 146 if (clearCode) { 147 partitionTable.clear_code_area(); 148 } else { 149 status_t error = _ReadBlock(logical->PartitionTableOffset(), 150 partitionTable); 151 if (error != B_OK) 152 return error; 153 } 154 155 partitionTable.signature = kPartitionTableSectorSignature; 156 157 partition_descriptor* descriptor = &partitionTable.table[0]; 158 logical->GetPartitionDescriptor(descriptor); 159 160 descriptor = &partitionTable.table[1]; 161 if (logical->Next() != NULL) 162 logical->Next()->GetPartitionDescriptor(descriptor, true); 163 else 164 memset(descriptor, 0, sizeof(partition_descriptor)); 165 166 // last two descriptors are empty 167 for (int32 i = 2; i < 4; i++) { 168 descriptor = &partitionTable.table[i]; 169 memset(descriptor, 0, sizeof(partition_descriptor)); 170 } 171 172 status_t error = _WriteBlock(logical->PartitionTableOffset(), 173 partitionTable); 174 return error; 175 } 176 177 178 status_t 179 PartitionMapWriter::WriteExtendedHead(const LogicalPartition* logical, 180 const PrimaryPartition* primary, bool clearCode) 181 { 182 if (primary == NULL) 183 return B_BAD_VALUE; 184 185 partition_table partitionTable; 186 if (clearCode) { 187 partitionTable.clear_code_area(); 188 } else { 189 status_t error = _ReadBlock(primary->Offset(), partitionTable); 190 if (error != B_OK) 191 return error; 192 } 193 194 partitionTable.signature = kPartitionTableSectorSignature; 195 partition_descriptor* descriptor; 196 if (logical == NULL) { 197 for (int32 i = 0; i < 4; i++) { 198 descriptor = &partitionTable.table[i]; 199 memset(descriptor, 0, sizeof(partition_descriptor)); 200 } 201 } else { 202 LogicalPartition partition; 203 partition.SetPartitionTableOffset(primary->Offset()); 204 partition.SetBlockSize(logical->BlockSize()); 205 partition.SetOffset(logical->Offset()); 206 partition.SetSize(logical->Size()); 207 partition.SetType(logical->Type()); 208 209 // set the logicals partition table to the correct location 210 descriptor = &partitionTable.table[0]; 211 partition.GetPartitionDescriptor(descriptor); 212 213 descriptor = &partitionTable.table[1]; 214 LogicalPartition* next = logical->Next(); 215 if (next != NULL) 216 next->GetPartitionDescriptor(descriptor, true); 217 else 218 memset(descriptor, 0, sizeof(partition_descriptor)); 219 220 // last two descriptors are empty 221 for (int32 i = 2; i < 4; i++) { 222 descriptor = &partitionTable.table[i]; 223 memset(descriptor, 0, sizeof(partition_descriptor)); 224 } 225 } 226 227 status_t error = _WriteBlock(primary->Offset(), partitionTable); 228 if (error != B_OK) 229 return error; 230 231 return B_OK; 232 } 233 234 235 236 status_t 237 PartitionMapWriter::ClearExtendedHead(const PrimaryPartition* primary) 238 { 239 if (primary == NULL) 240 return B_BAD_VALUE; 241 242 partition_table partitionTable; 243 partitionTable.clear_code_area(); 244 partitionTable.signature = kPartitionTableSectorSignature; 245 246 partition_descriptor* descriptor; 247 for (int32 i = 0; i < 4; i++) { 248 descriptor = &partitionTable.table[i]; 249 memset(descriptor, 0, sizeof(partition_descriptor)); 250 } 251 252 status_t error = _WriteBlock(primary->Offset(), partitionTable); 253 if (error != B_OK) 254 return error; 255 256 return B_OK; 257 } 258 259 260 status_t 261 PartitionMapWriter::_ReadBlock(off_t partitionOffset, 262 partition_table& partitionTable) 263 { 264 if (partitionOffset < 0) 265 return B_BAD_VALUE; 266 // TODO: If fBlockSize > sizeof(partition_table) then stop/read NULL after 267 if (read_pos(fDeviceFD, partitionOffset, &partitionTable, 268 sizeof(partitionTable)) != sizeof(partitionTable)) { 269 status_t error = errno; 270 if (error == B_OK) 271 error = B_IO_ERROR; 272 273 return error; 274 } 275 276 return B_OK; 277 } 278 279 280 status_t 281 PartitionMapWriter::_WriteBlock(off_t partitionOffset, 282 const partition_table& partitionTable) 283 { 284 if (partitionOffset < 0) 285 return B_BAD_VALUE; 286 // TODO: maybe clear the rest of the block if 287 // fBlockSize > sizeof(partition_table)? 288 if (write_pos(fDeviceFD, partitionOffset, &partitionTable, 289 sizeof(partitionTable)) != sizeof(partitionTable)) { 290 status_t error = errno; 291 if (error == B_OK) 292 error = B_IO_ERROR; 293 294 return error; 295 } 296 297 return B_OK; 298 } 299 300