xref: /haiku/src/system/boot/loader/file_systems/bfs/bfs.cpp (revision 4d8811742fa447ec05b4993a16a0931bc29aafab)
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(%" B_PRId32 ",%d,%d)\n",
116 			run.AllocationGroup(), run.Start(), run.Length());
117 		return B_BAD_DATA;
118 	}
119 	return B_OK;
120 }
121 
122 
123 block_run
124 Volume::ToBlockRun(off_t block) const
125 {
126 	block_run run;
127 	run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(block >> fSuperBlock.AllocationGroupShift());
128 	run.start = HOST_ENDIAN_TO_BFS_INT16(block & ~((1LL << fSuperBlock.AllocationGroupShift()) - 1));
129 	run.length = HOST_ENDIAN_TO_BFS_INT16(1);
130 	return run;
131 }
132 
133 
134 //	#pragma mark -
135 
136 
137 float
138 bfs_identify_file_system(boot::Partition *partition)
139 {
140 	Volume volume(partition);
141 
142 	return volume.InitCheck() < B_OK ? 0 : 0.8;
143 }
144 
145 
146 static status_t
147 bfs_get_file_system(boot::Partition *partition, ::Directory **_root)
148 {
149 	Volume *volume = new(nothrow) Volume(partition);
150 	if (volume == NULL)
151 		return B_NO_MEMORY;
152 
153 	if (volume->InitCheck() < B_OK) {
154 		delete volume;
155 		return B_ERROR;
156 	}
157 
158 	*_root = volume->RootNode();
159 	return B_OK;
160 }
161 
162 
163 file_system_module_info gBFSFileSystemModule = {
164 	"file_systems/bfs/v1",
165 	kPartitionTypeBFS,
166 	bfs_identify_file_system,
167 	bfs_get_file_system
168 };
169 
170