vfs: check userland buffers before reading them.
[haiku.git] / src / system / boot / loader / file_systems / bfs / bfs.cpp
blob0fdae9b5d6d57217af1a9f42af5e502e4086246d
1 /*
2 * Copyright 2003-2013, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include <string.h>
10 #include <stdio.h>
12 #include <boot/partitions.h>
13 #include <boot/platform.h>
14 #include <boot/vfs.h>
16 #include "Volume.h"
17 #include "Directory.h"
18 #include "Utility.h"
21 #define TRACE_BFS 0
22 #if TRACE_BFS
23 # define TRACE(x) dprintf x
24 #else
25 # define TRACE(x) ;
26 #endif
29 using namespace BFS;
30 using std::nothrow;
33 Volume::Volume(boot::Partition *partition)
35 fRootNode(NULL)
37 fDevice = open_node(partition, O_RDONLY);
38 if (fDevice < B_OK)
39 return;
41 if (read_pos(fDevice, 512, &fSuperBlock, sizeof(disk_super_block)) < B_OK)
42 return;
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;
50 if (!IsValidSuperBlock())
51 return;
52 #else
53 return;
54 #endif
57 TRACE(("bfs: we do have a valid superblock (name = %s)!\n", fSuperBlock.name));
59 fRootNode = new(nothrow) BFS::Directory(*this, Root());
60 if (fRootNode == NULL)
61 return;
63 if (fRootNode->InitCheck() < B_OK) {
64 TRACE(("bfs: init check for root node failed\n"));
65 delete fRootNode;
66 fRootNode = NULL;
67 return;
72 Volume::~Volume()
74 close(fDevice);
78 status_t
79 Volume::InitCheck()
81 if (fDevice < B_OK)
82 return B_ERROR;
84 return fRootNode != NULL ? B_OK : B_ERROR;
88 bool
89 Volume::IsValidSuperBlock()
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;
104 return true;
108 status_t
109 Volume::ValidateBlockRun(block_run run)
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;
119 return B_OK;
123 block_run
124 Volume::ToBlockRun(off_t block) const
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;
134 // #pragma mark -
137 float
138 bfs_identify_file_system(boot::Partition *partition)
140 Volume volume(partition);
142 return volume.InitCheck() < B_OK ? 0 : 0.8;
146 static status_t
147 bfs_get_file_system(boot::Partition *partition, ::Directory **_root)
149 Volume *volume = new(nothrow) Volume(partition);
150 if (volume == NULL)
151 return B_NO_MEMORY;
153 if (volume->InitCheck() < B_OK) {
154 delete volume;
155 return B_ERROR;
158 *_root = volume->RootNode();
159 return B_OK;
163 file_system_module_info gBFSFileSystemModule = {
164 "file_systems/bfs/v1",
165 kPartitionTypeBFS,
166 bfs_identify_file_system,
167 bfs_get_file_system