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