xref: /haiku/src/add-ons/disk_systems/bfs/BFSAddOn.cpp (revision 0d452c8f34013b611a54c746a71c05e28796eae2)
1 /*
2  * Copyright 2007, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de.
4  *
5  * Distributed under the terms of the MIT License.
6  */
7 
8 
9 #include "BFSAddOn.h"
10 #include "InitializeParameterEditor.h"
11 
12 #include <new>
13 
14 #include <Directory.h>
15 #include <List.h>
16 #include <Path.h>
17 #include <Volume.h>
18 
19 #include <DiskDeviceTypes.h>
20 #include <MutablePartition.h>
21 
22 #include <AutoDeleter.h>
23 #include <StringForSize.h>
24 
25 #ifdef ASSERT
26 #	undef ASSERT
27 #endif
28 
29 #include "bfs.h"
30 #include "bfs_control.h"
31 #include "bfs_disk_system.h"
32 
33 
34 using std::nothrow;
35 
36 
37 static const uint32 kDiskSystemFlags =
38 	0
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
55 ;
56 
57 
58 static BString
59 size_string(double size)
60 {
61 	BString string;
62 	char* buffer = string.LockBuffer(256);
63 	string_for_size(size, buffer, 256);
64 
65 	string.UnlockBuffer();
66 	return string;
67 }
68 
69 
70 // #pragma mark - BFSAddOn
71 
72 
73 BFSAddOn::BFSAddOn()
74 	: BDiskSystemAddOn(kPartitionTypeBFS, kDiskSystemFlags)
75 {
76 }
77 
78 
79 BFSAddOn::~BFSAddOn()
80 {
81 }
82 
83 
84 status_t
85 BFSAddOn::CreatePartitionHandle(BMutablePartition* partition,
86 	BPartitionHandle** _handle)
87 {
88 	BFSPartitionHandle* handle = new(nothrow) BFSPartitionHandle(partition);
89 	if (!handle)
90 		return B_NO_MEMORY;
91 
92 	status_t error = handle->Init();
93 	if (error != B_OK) {
94 		delete handle;
95 		return error;
96 	}
97 
98 	*_handle = handle;
99 	return B_OK;
100 }
101 
102 
103 bool
104 BFSAddOn::CanInitialize(const BMutablePartition* partition)
105 {
106 	// TODO: Check partition size.
107 	return true;
108 }
109 
110 
111 status_t
112 BFSAddOn::ValidateInitialize(const BMutablePartition* partition, BString* name,
113 	const char* parameterString)
114 {
115 	if (!CanInitialize(partition) || !name)
116 		return B_BAD_VALUE;
117 
118 	// validate name
119 
120 	// truncate, if it is too long
121 	if (name->Length() >= BFS_DISK_NAME_LENGTH)
122 		name->Truncate(BFS_DISK_NAME_LENGTH - 1);
123 
124 	// replace '/' by '-'
125 	name->ReplaceAll('/', '-');
126 
127 	// check parameters
128 	initialize_parameters parameters;
129 	status_t error = parse_initialize_parameters(parameterString, parameters);
130 	if (error != B_OK)
131 		return error;
132 
133 	return B_OK;
134 }
135 
136 
137 status_t
138 BFSAddOn::Initialize(BMutablePartition* partition, const char* name,
139 	const char* parameterString, BPartitionHandle** _handle)
140 {
141 	if (!CanInitialize(partition) || check_volume_name(name) != B_OK)
142 		return B_BAD_VALUE;
143 
144 	initialize_parameters parameters;
145 	status_t error = parse_initialize_parameters(parameterString, parameters);
146 	if (error != B_OK)
147 		return error;
148 
149 	// create the handle
150 	BFSPartitionHandle* handle = new(nothrow) BFSPartitionHandle(partition);
151 	if (!handle)
152 		return B_NO_MEMORY;
153 	ObjectDeleter<BFSPartitionHandle> handleDeleter(handle);
154 
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.
160 
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);
167 
168 	*_handle = handleDeleter.Detach();
169 
170 	return B_OK;
171 }
172 
173 
174 status_t
175 BFSAddOn::GetParameterEditor(B_PARAMETER_EDITOR_TYPE type,
176 	BPartitionParameterEditor** editor)
177 {
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;
184 		}
185 		return B_OK;
186 	}
187 	return B_NOT_SUPPORTED;
188 }
189 
190 
191 // #pragma mark - BFSPartitionHandle
192 
193 
194 BFSPartitionHandle::BFSPartitionHandle(BMutablePartition* partition)
195 	: BPartitionHandle(partition)
196 {
197 }
198 
199 
200 BFSPartitionHandle::~BFSPartitionHandle()
201 {
202 }
203 
204 
205 status_t
206 BFSPartitionHandle::Init()
207 {
208 // TODO: Check parameters.
209 	return B_OK;
210 }
211 
212 
213 uint32
214 BFSPartitionHandle::SupportedOperations(uint32 mask)
215 {
216 	return kDiskSystemFlags & mask;
217 }
218 
219 
220 status_t
221 BFSPartitionHandle::Repair(bool checkOnly)
222 {
223 	BVolume volume(Partition()->VolumeID());
224 	BDirectory directory;
225 	volume.GetRootDirectory(&directory);
226 	BPath path;
227 	path.SetTo(&directory, ".");
228 
229 	int fd = open(path.Path(), O_RDONLY);
230 	if (fd < 0)
231 	    return errno;
232 
233 	struct check_control result;
234 	memset(&result, 0, sizeof(result));
235 	result.magic = BFS_IOCTL_CHECK_MAGIC;
236 	result.flags = !checkOnly ? BFS_FIX_BITMAP_ERRORS : 0;
237 	if (!checkOnly) {
238 		//printf("will fix any severe errors!\n");
239 		result.flags |= BFS_REMOVE_WRONG_TYPES | BFS_REMOVE_INVALID
240 			| BFS_FIX_NAME_MISMATCHES;
241 	}
242 
243 	// start checking
244 	if (ioctl(fd, BFS_IOCTL_START_CHECKING, &result, sizeof(result)) < 0)
245 	    return errno;
246 
247 	uint64 attributeDirectories = 0, attributes = 0;
248 	uint64 files = 0, directories = 0, indices = 0;
249 	uint64 counter = 0;
250 
251 	// check all files and report errors
252 	while (ioctl(fd, BFS_IOCTL_CHECK_NEXT_NODE, &result,
253 			sizeof(result)) == 0) {
254 		if (++counter % 50 == 0)
255 			printf("%9Ld nodes processed\x1b[1A\n", counter);
256 
257 		if (result.errors) {
258 			printf("%s (inode = %lld)", result.name, result.inode);
259 			if (result.errors & BFS_MISSING_BLOCKS)
260 				printf(", some blocks weren't allocated");
261 			if (result.errors & BFS_BLOCKS_ALREADY_SET)
262 				printf(", has blocks already set");
263 			if (result.errors & BFS_INVALID_BLOCK_RUN)
264 				printf(", has invalid block run(s)");
265 			if (result.errors & BFS_COULD_NOT_OPEN)
266 				printf(", could not be opened");
267 			if (result.errors & BFS_WRONG_TYPE)
268 				printf(", has wrong type");
269 			if (result.errors & BFS_NAMES_DONT_MATCH)
270 				printf(", names don't match");
271 			putchar('\n');
272 		}
273 		if ((result.mode & (S_INDEX_DIR | 0777)) == S_INDEX_DIR)
274 			indices++;
275 		else if (result.mode & S_ATTR_DIR)
276 			attributeDirectories++;
277 		else if (result.mode & S_ATTR)
278 			attributes++;
279 		else if (S_ISDIR(result.mode))
280 			directories++;
281 		else
282 			files++;
283 	}
284 
285 	// stop checking
286 	if (ioctl(fd, BFS_IOCTL_STOP_CHECKING, &result, sizeof(result)) != 0) {
287 		close(fd);
288 		return errno;
289 	}
290 
291 	close(fd);
292 
293 	printf("\t%" B_PRIu64 " nodes checked,\n\t%" B_PRIu64 " blocks not "
294 		"allocated,\n\t%" B_PRIu64 " blocks already set,\n\t%" B_PRIu64
295 		" blocks could be freed\n\n", counter, result.stats.missing,
296 		result.stats.already_set, result.stats.freed);
297 	printf("\tfiles\t\t%" B_PRIu64 "\n\tdirectories\t%" B_PRIu64 "\n"
298 		"\tattributes\t%" B_PRIu64 "\n\tattr. dirs\t%" B_PRIu64 "\n"
299 		"\tindices\t\t%" B_PRIu64 "\n", files, directories, attributes,
300 		attributeDirectories, indices);
301 
302 	printf("\n\tdirect block runs\t\t%" B_PRIu64 " (%s)\n",
303 		result.stats.direct_block_runs, size_string(1.0
304 			* result.stats.blocks_in_direct
305 			* result.stats.block_size).String());
306 	printf("\tindirect block runs\t\t%" B_PRIu64 " (in %" B_PRIu64
307 		" array blocks, %s)\n", result.stats.indirect_block_runs,
308 		result.stats.indirect_array_blocks,
309 		size_string(1.0 * result.stats.blocks_in_indirect
310 			* result.stats.block_size).String());
311 	printf("\tdouble indirect block runs\t%" B_PRIu64 " (in %" B_PRIu64
312 		" array blocks, %s)\n", result.stats.double_indirect_block_runs,
313 		result.stats.double_indirect_array_blocks,
314 		size_string(1.0 * result.stats.blocks_in_double_indirect
315 			* result.stats.block_size).String());
316 	// TODO: this is currently not maintained correctly
317 	//printf("\tpartial block runs\t%" B_PRIu64 "\n",
318 	//	result.stats.partial_block_runs);
319 
320 	if (result.status == B_ENTRY_NOT_FOUND)
321 		result.status = B_OK;
322 
323 	return result.status;
324 }
325 
326 
327 // #pragma mark -
328 
329 
330 status_t
331 get_disk_system_add_ons(BList* addOns)
332 {
333 	BFSAddOn* addOn = new(nothrow) BFSAddOn;
334 	if (!addOn)
335 		return B_NO_MEMORY;
336 
337 	if (!addOns->AddItem(addOn)) {
338 		delete addOn;
339 		return B_NO_MEMORY;
340 	}
341 
342 	return B_OK;
343 }
344