1 /* 2 * Copyright 2003-2013, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <fcntl.h> 8 #include <unistd.h> 9 #include <string.h> 10 #include <stdio.h> 11 12 #include <boot/partitions.h> 13 #include <boot/platform.h> 14 #include <boot/vfs.h> 15 16 #include "Volume.h" 17 #include "Directory.h" 18 #include "Utility.h" 19 20 21 #define TRACE_BFS 0 22 #if TRACE_BFS 23 # define TRACE(x) dprintf x 24 #else 25 # define TRACE(x) ; 26 #endif 27 28 29 using namespace BFS; 30 using std::nothrow; 31 32 33 Volume::Volume(boot::Partition *partition) 34 : 35 fRootNode(NULL) 36 { 37 fDevice = open_node(partition, O_RDONLY); 38 if (fDevice < B_OK) 39 return; 40 41 if (read_pos(fDevice, 512, &fSuperBlock, sizeof(disk_super_block)) < B_OK) 42 return; 43 44 if (!IsValidSuperBlock()) { 45 #ifndef BFS_LITTLE_ENDIAN_ONLY 46 // try block 0 again (can only happen on the big endian BFS) 47 if (read_pos(fDevice, 0, &fSuperBlock, sizeof(disk_super_block)) < B_OK) 48 return; 49 50 if (!IsValidSuperBlock()) 51 return; 52 #else 53 return; 54 #endif 55 } 56 57 TRACE(("bfs: we do have a valid superblock (name = %s)!\n", fSuperBlock.name)); 58 59 fRootNode = new(nothrow) BFS::Directory(*this, Root()); 60 if (fRootNode == NULL) 61 return; 62 63 if (fRootNode->InitCheck() < B_OK) { 64 TRACE(("bfs: init check for root node failed\n")); 65 delete fRootNode; 66 fRootNode = NULL; 67 return; 68 } 69 } 70 71 72 Volume::~Volume() 73 { 74 close(fDevice); 75 } 76 77 78 status_t 79 Volume::InitCheck() 80 { 81 if (fDevice < B_OK) 82 return B_ERROR; 83 84 return fRootNode != NULL ? B_OK : B_ERROR; 85 } 86 87 88 bool 89 Volume::IsValidSuperBlock() 90 { 91 if (fSuperBlock.Magic1() != (int32)SUPER_BLOCK_MAGIC1 92 || fSuperBlock.Magic2() != (int32)SUPER_BLOCK_MAGIC2 93 || fSuperBlock.Magic3() != (int32)SUPER_BLOCK_MAGIC3 94 || (int32)fSuperBlock.block_size != fSuperBlock.inode_size 95 || fSuperBlock.ByteOrder() != SUPER_BLOCK_FS_LENDIAN 96 || (1UL << fSuperBlock.BlockShift()) != fSuperBlock.BlockSize() 97 || fSuperBlock.AllocationGroups() < 1 98 || fSuperBlock.AllocationGroupShift() < 1 99 || fSuperBlock.BlocksPerAllocationGroup() < 1 100 || fSuperBlock.NumBlocks() < 10 101 || fSuperBlock.AllocationGroups() != divide_roundup(fSuperBlock.NumBlocks(), 1L << fSuperBlock.AllocationGroupShift())) 102 return false; 103 104 return true; 105 } 106 107 108 status_t 109 Volume::ValidateBlockRun(block_run run) 110 { 111 if (run.AllocationGroup() < 0 || run.AllocationGroup() > (int32)AllocationGroups() 112 || run.Start() > (1UL << AllocationGroupShift()) 113 || run.length == 0 114 || uint32(run.Length() + run.Start()) > (1UL << AllocationGroupShift())) { 115 dprintf("bfs: invalid run(%ld,%d,%d)\n", run.AllocationGroup(), run.Start(), run.Length()); 116 return B_BAD_DATA; 117 } 118 return B_OK; 119 } 120 121 122 block_run 123 Volume::ToBlockRun(off_t block) const 124 { 125 block_run run; 126 run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(block >> fSuperBlock.AllocationGroupShift()); 127 run.start = HOST_ENDIAN_TO_BFS_INT16(block & ~((1LL << fSuperBlock.AllocationGroupShift()) - 1)); 128 run.length = HOST_ENDIAN_TO_BFS_INT16(1); 129 return run; 130 } 131 132 133 // #pragma mark - 134 135 136 float 137 bfs_identify_file_system(boot::Partition *partition) 138 { 139 Volume volume(partition); 140 141 return volume.InitCheck() < B_OK ? 0 : 0.8; 142 } 143 144 145 static status_t 146 bfs_get_file_system(boot::Partition *partition, ::Directory **_root) 147 { 148 Volume *volume = new(nothrow) Volume(partition); 149 if (volume == NULL) 150 return B_NO_MEMORY; 151 152 if (volume->InitCheck() < B_OK) { 153 delete volume; 154 return B_ERROR; 155 } 156 157 *_root = volume->RootNode(); 158 return B_OK; 159 } 160 161 162 file_system_module_info gBFSFileSystemModule = { 163 "file_systems/bfs/v1", 164 kPartitionTypeBFS, 165 bfs_identify_file_system, 166 bfs_get_file_system 167 }; 168 169