1 /* 2 * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "RootFileSystem.h" 8 9 #include <boot/partitions.h> 10 #include <boot/vfs.h> 11 #include <boot/platform.h> 12 #include <boot/stage2.h> 13 #include <boot/stdio.h> 14 #include <ddm_modules.h> 15 #include <util/kernel_cpp.h> 16 17 #include <unistd.h> 18 #include <string.h> 19 20 using namespace boot; 21 22 //#define TRACE_PARTITIONS 23 #ifdef TRACE_PARTITIONS 24 # define TRACE(x) dprintf x 25 #else 26 # define TRACE(x) ; 27 #endif 28 29 30 /* supported partition modules */ 31 32 static const partition_module_info *sPartitionModules[] = { 33 #ifdef BOOT_SUPPORT_PARTITION_AMIGA 34 &gAmigaPartitionModule, 35 #endif 36 #ifdef BOOT_SUPPORT_PARTITION_INTEL 37 &gIntelPartitionMapModule, 38 &gIntelExtendedPartitionModule, 39 #endif 40 #ifdef BOOT_SUPPORT_PARTITION_APPLE 41 &gApplePartitionModule, 42 #endif 43 }; 44 static const int32 sNumPartitionModules = sizeof(sPartitionModules) / sizeof(partition_module_info *); 45 46 /* supported file system modules */ 47 48 static file_system_module_info *sFileSystemModules[] = { 49 #ifdef BOOT_SUPPORT_FILE_SYSTEM_BFS 50 &gBFSFileSystemModule, 51 #endif 52 #ifdef BOOT_SUPPORT_FILE_SYSTEM_AMIGA_FFS 53 &gAmigaFFSFileSystemModule, 54 #endif 55 #ifdef BOOT_SUPPORT_FILE_SYSTEM_FAT 56 &gFATFileSystemModule, 57 #endif 58 #ifdef BOOT_SUPPORT_FILE_SYSTEM_HFS_PLUS 59 &gHFSPlusFileSystemModule, 60 #endif 61 #ifdef BOOT_SUPPORT_FILE_SYSTEM_TARFS 62 &gTarFileSystemModule, 63 #endif 64 }; 65 static const int32 sNumFileSystemModules = sizeof(sFileSystemModules) / sizeof(file_system_module_info *); 66 67 extern NodeList gPartitions; 68 69 70 namespace boot { 71 72 /** A convenience class to automatically close a 73 * file descriptor upon deconstruction. 74 */ 75 76 class NodeOpener { 77 public: 78 NodeOpener(Node *node, int mode) 79 { 80 fFD = open_node(node, mode); 81 } 82 83 ~NodeOpener() 84 { 85 close(fFD); 86 } 87 88 int Descriptor() const { return fFD; } 89 90 private: 91 int fFD; 92 }; 93 94 95 // #pragma mark - 96 97 98 Partition::Partition(int fd) 99 : 100 fParent(NULL), 101 fIsFileSystem(false), 102 fIsPartitioningSystem(false) 103 { 104 memset((partition_data *)this, 0, sizeof(partition_data)); 105 id = (partition_id)this; 106 107 // it's safe to close the file 108 fFD = dup(fd); 109 } 110 111 112 Partition::~Partition() 113 { 114 close(fFD); 115 } 116 117 118 ssize_t 119 Partition::ReadAt(void *cookie, off_t position, void *buffer, size_t bufferSize) 120 { 121 if (position > this->size) 122 return 0; 123 if (position < 0) 124 return B_BAD_VALUE; 125 126 if (position + bufferSize > this->size) 127 bufferSize = this->size - position; 128 129 return read_pos(fFD, this->offset + position, buffer, bufferSize); 130 } 131 132 133 ssize_t 134 Partition::WriteAt(void *cookie, off_t position, const void *buffer, size_t bufferSize) 135 { 136 if (position > this->size) 137 return 0; 138 if (position < 0) 139 return B_BAD_VALUE; 140 141 if (position + bufferSize > this->size) 142 bufferSize = this->size - position; 143 144 return write_pos(fFD, this->offset + position, buffer, bufferSize); 145 } 146 147 148 off_t 149 Partition::Size() const 150 { 151 struct stat stat; 152 if (fstat(fFD, &stat) == B_OK) 153 return stat.st_size; 154 155 return Node::Size(); 156 } 157 158 159 int32 160 Partition::Type() const 161 { 162 struct stat stat; 163 if (fstat(fFD, &stat) == B_OK) 164 return stat.st_mode; 165 166 return Node::Type(); 167 } 168 169 170 Partition * 171 Partition::AddChild() 172 { 173 Partition *child = new Partition(fFD); 174 if (child == NULL) 175 return NULL; 176 177 child->SetParent(this); 178 child_count++; 179 fChildren.Add(child); 180 181 return child; 182 } 183 184 185 status_t 186 Partition::_Mount(file_system_module_info *module, Directory **_fileSystem) 187 { 188 TRACE(("check for file_system: %s\n", module->pretty_name)); 189 190 Directory *fileSystem; 191 if (module->get_file_system(this, &fileSystem) == B_OK) { 192 gRoot->AddVolume(fileSystem, this); 193 if (_fileSystem) 194 *_fileSystem = fileSystem; 195 196 // remember the module name that mounted us 197 fModuleName = module->module_name; 198 199 fIsFileSystem = true; 200 return B_OK; 201 } 202 203 return B_BAD_VALUE; 204 } 205 206 207 status_t 208 Partition::Mount(Directory **_fileSystem, bool isBootDevice) 209 { 210 if (isBootDevice && gKernelArgs.boot_disk.booted_from_image) 211 return _Mount(&gTarFileSystemModule, _fileSystem); 212 213 for (int32 i = 0; i < sNumFileSystemModules; i++) { 214 status_t status = _Mount(sFileSystemModules[i], _fileSystem); 215 if (status == B_OK) 216 return B_OK; 217 } 218 219 return B_ENTRY_NOT_FOUND; 220 } 221 222 223 status_t 224 Partition::Scan(bool mountFileSystems, bool isBootDevice) 225 { 226 // scan for partitions first (recursively all eventual children as well) 227 228 TRACE(("Partition::Scan()\n")); 229 230 // if we were not booted from the real boot device, we won't scan 231 // the device we were booted from (which is likely to be a slow 232 // floppy or CD) 233 if (isBootDevice && gKernelArgs.boot_disk.booted_from_image) 234 return B_ENTRY_NOT_FOUND; 235 236 const partition_module_info *bestModule = NULL; 237 void *bestCookie = NULL; 238 float bestPriority = -1; 239 240 for (int32 i = 0; i < sNumPartitionModules; i++) { 241 const partition_module_info *module = sPartitionModules[i]; 242 void *cookie = NULL; 243 NodeOpener opener(this, O_RDONLY); 244 245 TRACE(("check for partitioning_system: %s\n", module->pretty_name)); 246 247 float priority 248 = module->identify_partition(opener.Descriptor(), this, &cookie); 249 if (priority < 0.0) 250 continue; 251 252 if (priority <= bestPriority) { 253 // the disk system recognized the partition worse than the currently 254 // best one 255 module->free_identify_partition_cookie(this, cookie); 256 continue; 257 } 258 259 // a new winner, replace the previous one 260 if (bestModule) 261 bestModule->free_identify_partition_cookie(this, bestCookie); 262 bestModule = module; 263 bestCookie = cookie; 264 bestPriority = priority; 265 } 266 267 // now let the best matching disk system scan the partition 268 if (bestModule) { 269 NodeOpener opener(this, O_RDONLY); 270 status_t status = bestModule->scan_partition(opener.Descriptor(), this, 271 bestCookie); 272 bestModule->free_identify_partition_cookie(this, bestCookie); 273 274 if (status != B_OK) { 275 dprintf("Partitioning module `%s' recognized the partition, but " 276 "failed to scan it\n", bestModule->pretty_name); 277 return status; 278 } 279 280 fIsPartitioningSystem = true; 281 282 content_type = bestModule->pretty_name; 283 flags |= B_PARTITION_PARTITIONING_SYSTEM; 284 285 // now that we've found something, check our children 286 // out as well! 287 288 NodeIterator iterator = fChildren.GetIterator(); 289 Partition *child = NULL; 290 291 while ((child = (Partition *)iterator.Next()) != NULL) { 292 TRACE(("*** scan child %p (start = %Ld, size = %Ld, parent = %p)!\n", 293 child, child->offset, child->size, child->Parent())); 294 295 child->Scan(mountFileSystems); 296 297 if (!mountFileSystems || child->IsFileSystem()) { 298 // move the partitions containing file systems to the partition list 299 fChildren.Remove(child); 300 gPartitions.Add(child); 301 } 302 } 303 304 // remove all unused children (we keep only file systems) 305 306 while ((child = (Partition *)fChildren.Head()) != NULL) { 307 fChildren.Remove(child); 308 delete child; 309 } 310 311 // remember the module name that identified us 312 fModuleName = bestModule->module.name; 313 314 return B_OK; 315 } 316 317 // scan for file systems 318 319 if (mountFileSystems) 320 return Mount(); 321 322 return B_ENTRY_NOT_FOUND; 323 } 324 325 } // namespace boot 326 327 328 // #pragma mark - 329 330 331 /** Scans the device passed in for partitioning systems. If none are found, 332 * a partition containing the whole device is created. 333 * All created partitions are added to the gPartitions list. 334 */ 335 336 status_t 337 add_partitions_for(int fd, bool mountFileSystems, bool isBootDevice) 338 { 339 TRACE(("add_partitions_for(fd = %d, mountFS = %s)\n", fd, mountFileSystems ? "yes" : "no")); 340 341 Partition *partition = new Partition(fd); 342 343 // set some magic/default values 344 partition->block_size = 512; 345 partition->size = partition->Size(); 346 347 // add this partition to the list of partitions, if it contains 348 // or might contain a file system 349 if ((partition->Scan(mountFileSystems, isBootDevice) == B_OK && partition->IsFileSystem()) 350 || (!partition->IsPartitioningSystem() && !mountFileSystems)) { 351 gPartitions.Add(partition); 352 return B_OK; 353 } 354 355 // if not, we'll need to tell the children that their parent is gone 356 357 NodeIterator iterator = gPartitions.GetIterator(); 358 Partition *child = NULL; 359 360 while ((child = (Partition *)iterator.Next()) != NULL) { 361 if (child->Parent() == partition) 362 child->SetParent(NULL); 363 } 364 365 delete partition; 366 return B_OK; 367 } 368 369 370 status_t 371 add_partitions_for(Node *device, bool mountFileSystems, bool isBootDevice) 372 { 373 TRACE(("add_partitions_for(%p, mountFS = %s)\n", device, mountFileSystems ? "yes" : "no")); 374 375 int fd = open_node(device, O_RDONLY); 376 if (fd < B_OK) 377 return fd; 378 379 status_t status = add_partitions_for(fd, mountFileSystems, isBootDevice); 380 if (status < B_OK) 381 dprintf("add_partitions_for(%d) failed: %ld\n", fd, status); 382 383 close(fd); 384 return B_OK; 385 } 386 387 388 partition_data * 389 create_child_partition(partition_id id, int32 index, partition_id childID) 390 { 391 Partition &partition = *(Partition *)id; 392 Partition *child = partition.AddChild(); 393 if (child == NULL) { 394 dprintf("creating partition failed: no memory\n"); 395 return NULL; 396 } 397 398 // we cannot do anything with the child here, because it was not 399 // yet initialized by the partition module. 400 TRACE(("new child partition!\n")); 401 402 return child; 403 } 404 405 406 partition_data * 407 get_child_partition(partition_id id, int32 index) 408 { 409 //Partition &partition = *(Partition *)id; 410 411 // ToDo: do we really have to implement this? 412 // The intel partition module doesn't really needs this for our mission... 413 414 return NULL; 415 } 416 417 418 partition_data * 419 get_parent_partition(partition_id id) 420 { 421 Partition &partition = *(Partition *)id; 422 423 return partition.Parent(); 424 } 425 426