vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / disk_systems / bfs / BFSAddOn.cpp
blob8fd7d64b3b75242092a45110ec07f40d9e19d4db
1 /*
2 * Copyright 2007, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2008-2012, Axel Dörfler, axeld@pinc-software.de.
5 * Distributed under the terms of the MIT License.
6 */
9 #include "BFSAddOn.h"
10 #include "InitializeParameterEditor.h"
12 #include <new>
14 #include <Directory.h>
15 #include <List.h>
16 #include <Path.h>
17 #include <Volume.h>
19 #include <DiskDeviceTypes.h>
20 #include <MutablePartition.h>
22 #include <AutoDeleter.h>
23 #include <StringForSize.h>
25 #ifdef ASSERT
26 # undef ASSERT
27 #endif
29 #include "bfs.h"
30 #include "bfs_control.h"
31 #include "bfs_disk_system.h"
34 using std::nothrow;
37 static const uint32 kDiskSystemFlags =
39 // | B_DISK_SYSTEM_SUPPORTS_CHECKING
40 // | B_DISK_SYSTEM_SUPPORTS_REPAIRING
41 // | B_DISK_SYSTEM_SUPPORTS_RESIZING
42 // | B_DISK_SYSTEM_SUPPORTS_MOVING
43 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME
44 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS
45 | B_DISK_SYSTEM_SUPPORTS_INITIALIZING
46 | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
47 // | B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING
48 // | B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING_WHILE_MOUNTED
49 | B_DISK_SYSTEM_SUPPORTS_CHECKING_WHILE_MOUNTED
50 | B_DISK_SYSTEM_SUPPORTS_REPAIRING_WHILE_MOUNTED
51 // | B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED
52 // | B_DISK_SYSTEM_SUPPORTS_MOVING_WHILE_MOUNTED
53 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME_WHILE_MOUNTED
54 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS_WHILE_MOUNTED
58 static BString
59 size_string(double size)
61 BString string;
62 char* buffer = string.LockBuffer(256);
63 string_for_size(size, buffer, 256);
65 string.UnlockBuffer();
66 return string;
70 // #pragma mark - BFSAddOn
73 BFSAddOn::BFSAddOn()
74 : BDiskSystemAddOn(kPartitionTypeBFS, kDiskSystemFlags)
79 BFSAddOn::~BFSAddOn()
84 status_t
85 BFSAddOn::CreatePartitionHandle(BMutablePartition* partition,
86 BPartitionHandle** _handle)
88 BFSPartitionHandle* handle = new(nothrow) BFSPartitionHandle(partition);
89 if (!handle)
90 return B_NO_MEMORY;
92 status_t error = handle->Init();
93 if (error != B_OK) {
94 delete handle;
95 return error;
98 *_handle = handle;
99 return B_OK;
103 bool
104 BFSAddOn::CanInitialize(const BMutablePartition* partition)
106 // TODO: Check partition size.
107 return true;
111 status_t
112 BFSAddOn::ValidateInitialize(const BMutablePartition* partition, BString* name,
113 const char* parameterString)
115 if (!CanInitialize(partition) || !name)
116 return B_BAD_VALUE;
118 // validate name
120 // truncate, if it is too long
121 if (name->Length() >= BFS_DISK_NAME_LENGTH)
122 name->Truncate(BFS_DISK_NAME_LENGTH - 1);
124 // replace '/' by '-'
125 name->ReplaceAll('/', '-');
127 // check parameters
128 initialize_parameters parameters;
129 status_t error = parse_initialize_parameters(parameterString, parameters);
130 if (error != B_OK)
131 return error;
133 return B_OK;
137 status_t
138 BFSAddOn::Initialize(BMutablePartition* partition, const char* name,
139 const char* parameterString, BPartitionHandle** _handle)
141 if (!CanInitialize(partition) || check_volume_name(name) != B_OK)
142 return B_BAD_VALUE;
144 initialize_parameters parameters;
145 status_t error = parse_initialize_parameters(parameterString, parameters);
146 if (error != B_OK)
147 return error;
149 // create the handle
150 BFSPartitionHandle* handle = new(nothrow) BFSPartitionHandle(partition);
151 if (!handle)
152 return B_NO_MEMORY;
153 ObjectDeleter<BFSPartitionHandle> handleDeleter(handle);
155 // init the partition
156 error = partition->SetContentType(Name());
157 if (error != B_OK)
158 return error;
159 // TODO: The content type could as well be set by the caller.
161 partition->SetContentName(name);
162 partition->SetContentParameters(parameterString);
163 uint32 blockSize = parameters.blockSize;
164 partition->SetBlockSize(blockSize);
165 partition->SetContentSize(partition->Size() / blockSize * blockSize);
166 partition->Changed(B_PARTITION_CHANGED_INITIALIZATION);
168 *_handle = handleDeleter.Detach();
170 return B_OK;
174 status_t
175 BFSAddOn::GetParameterEditor(B_PARAMETER_EDITOR_TYPE type,
176 BPartitionParameterEditor** editor)
178 *editor = NULL;
179 if (type == B_INITIALIZE_PARAMETER_EDITOR) {
180 try {
181 *editor = new InitializeBFSEditor();
182 } catch (std::bad_alloc) {
183 return B_NO_MEMORY;
185 return B_OK;
187 return B_NOT_SUPPORTED;
191 // #pragma mark - BFSPartitionHandle
194 BFSPartitionHandle::BFSPartitionHandle(BMutablePartition* partition)
195 : BPartitionHandle(partition)
200 BFSPartitionHandle::~BFSPartitionHandle()
205 status_t
206 BFSPartitionHandle::Init()
208 // TODO: Check parameters.
209 return B_OK;
213 uint32
214 BFSPartitionHandle::SupportedOperations(uint32 mask)
216 return kDiskSystemFlags & mask;
220 status_t
221 BFSPartitionHandle::Repair(bool checkOnly)
223 BVolume volume(Partition()->VolumeID());
224 BDirectory directory;
225 volume.GetRootDirectory(&directory);
226 BPath path;
227 path.SetTo(&directory, ".");
229 int fd = open(path.Path(), O_RDONLY);
230 if (fd < 0)
231 return errno;
233 FileDescriptorCloser closer(fd);
235 struct check_control result;
236 memset(&result, 0, sizeof(result));
237 result.magic = BFS_IOCTL_CHECK_MAGIC;
238 result.flags = 0;
239 if (!checkOnly) {
240 //printf("will fix any severe errors!\n");
241 result.flags |= BFS_FIX_BITMAP_ERRORS | BFS_REMOVE_WRONG_TYPES
242 | BFS_REMOVE_INVALID | BFS_FIX_NAME_MISMATCHES | BFS_FIX_BPLUSTREES;
245 // start checking
246 if (ioctl(fd, BFS_IOCTL_START_CHECKING, &result, sizeof(result)) < 0)
247 return errno;
249 uint64 attributeDirectories = 0, attributes = 0;
250 uint64 files = 0, directories = 0, indices = 0;
251 uint64 counter = 0;
252 uint32 previousPass = result.pass;
254 // check all files and report errors
255 while (ioctl(fd, BFS_IOCTL_CHECK_NEXT_NODE, &result,
256 sizeof(result)) == 0) {
257 if (++counter % 50 == 0)
258 printf("%9" B_PRId64 " nodes processed\x1b[1A\n", counter);
260 if (result.pass == BFS_CHECK_PASS_BITMAP) {
261 if (result.errors) {
262 printf("%s (inode = %" B_PRIdINO ")", result.name, result.inode);
263 if ((result.errors & BFS_MISSING_BLOCKS) != 0)
264 printf(", some blocks weren't allocated");
265 if ((result.errors & BFS_BLOCKS_ALREADY_SET) != 0)
266 printf(", has blocks already set");
267 if ((result.errors & BFS_INVALID_BLOCK_RUN) != 0)
268 printf(", has invalid block run(s)");
269 if ((result.errors & BFS_COULD_NOT_OPEN) != 0)
270 printf(", could not be opened");
271 if ((result.errors & BFS_WRONG_TYPE) != 0)
272 printf(", has wrong type");
273 if ((result.errors & BFS_NAMES_DONT_MATCH) != 0)
274 printf(", names don't match");
275 if ((result.errors & BFS_INVALID_BPLUSTREE) != 0)
276 printf(", invalid b+tree");
277 putchar('\n');
280 if ((result.mode & (S_INDEX_DIR | 0777)) == S_INDEX_DIR)
281 indices++;
282 else if (result.mode & S_ATTR_DIR)
283 attributeDirectories++;
284 else if (result.mode & S_ATTR)
285 attributes++;
286 else if (S_ISDIR(result.mode))
287 directories++;
288 else
289 files++;
290 } else if (result.pass == BFS_CHECK_PASS_INDEX) {
291 if (previousPass != result.pass) {
292 printf("Recreating broken index b+trees...\n");
293 previousPass = result.pass;
294 counter = 0;
299 // stop checking
300 if (ioctl(fd, BFS_IOCTL_STOP_CHECKING, &result, sizeof(result)) != 0)
301 return errno;
303 printf(" %" B_PRIu64 " nodes checked,\n\t%" B_PRIu64 " blocks not "
304 "allocated,\n\t%" B_PRIu64 " blocks already set,\n\t%" B_PRIu64
305 " blocks could be freed\n\n", counter, result.stats.missing,
306 result.stats.already_set, result.stats.freed);
307 printf("\tfiles\t\t%" B_PRIu64 "\n\tdirectories\t%" B_PRIu64 "\n"
308 "\tattributes\t%" B_PRIu64 "\n\tattr. dirs\t%" B_PRIu64 "\n"
309 "\tindices\t\t%" B_PRIu64 "\n", files, directories, attributes,
310 attributeDirectories, indices);
312 printf("\n\tdirect block runs\t\t%" B_PRIu64 " (%s)\n",
313 result.stats.direct_block_runs, size_string(1.0
314 * result.stats.blocks_in_direct
315 * result.stats.block_size).String());
316 printf("\tindirect block runs\t\t%" B_PRIu64 " (in %" B_PRIu64
317 " array blocks, %s)\n", result.stats.indirect_block_runs,
318 result.stats.indirect_array_blocks,
319 size_string(1.0 * result.stats.blocks_in_indirect
320 * result.stats.block_size).String());
321 printf("\tdouble indirect block runs\t%" B_PRIu64 " (in %" B_PRIu64
322 " array blocks, %s)\n", result.stats.double_indirect_block_runs,
323 result.stats.double_indirect_array_blocks,
324 size_string(1.0 * result.stats.blocks_in_double_indirect
325 * result.stats.block_size).String());
326 // TODO: this is currently not maintained correctly
327 //printf("\tpartial block runs\t%" B_PRIu64 "\n",
328 // result.stats.partial_block_runs);
330 if (result.status == B_ENTRY_NOT_FOUND)
331 result.status = B_OK;
333 return result.status;
337 // #pragma mark -
340 status_t
341 get_disk_system_add_ons(BList* addOns)
343 BFSAddOn* addOn = new(nothrow) BFSAddOn;
344 if (!addOn)
345 return B_NO_MEMORY;
347 if (!addOns->AddItem(addOn)) {
348 delete addOn;
349 return B_NO_MEMORY;
352 return B_OK;