xref: /haiku/src/system/boot/loader/file_systems/bfs/bfs.cpp (revision 91c0454716f24a7454b20f7a54cfe32e288e3710)
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