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 28using 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 49bool 50check_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 89PartitionMapWriter::PartitionMapWriter(int deviceFD, uint32 blockSize) 90 : 91 fDeviceFD(deviceFD), 92 fBlockSize(blockSize) 93{ 94} 95 96 97PartitionMapWriter::~PartitionMapWriter() 98{ 99} 100 101 102status_t 103PartitionMapWriter::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 135status_t 136PartitionMapWriter::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 178status_t 179PartitionMapWriter::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 236status_t 237PartitionMapWriter::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 260status_t 261PartitionMapWriter::_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 280status_t 281PartitionMapWriter::_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