xref: /haiku/src/add-ons/disk_systems/bfs/BFSAddOn.cpp (revision d374a27286b8a52974a97dba0d5966ea026a665d)
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 
24 #ifdef ASSERT
25 #	undef ASSERT
26 #endif
27 
28 #include "bfs.h"
29 #include "bfs_control.h"
30 #include "bfs_disk_system.h"
31 
32 
33 using std::nothrow;
34 
35 
36 static const uint32 kDiskSystemFlags =
37 	0
38 //	| B_DISK_SYSTEM_SUPPORTS_CHECKING
39 //	| B_DISK_SYSTEM_SUPPORTS_REPAIRING
40 //	| B_DISK_SYSTEM_SUPPORTS_RESIZING
41 //	| B_DISK_SYSTEM_SUPPORTS_MOVING
42 //	| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME
43 //	| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS
44 	| B_DISK_SYSTEM_SUPPORTS_INITIALIZING
45 	| B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
46 //	| B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING
47 //	| B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING_WHILE_MOUNTED
48 	| B_DISK_SYSTEM_SUPPORTS_CHECKING_WHILE_MOUNTED
49 	| B_DISK_SYSTEM_SUPPORTS_REPAIRING_WHILE_MOUNTED
50 //	| B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED
51 //	| B_DISK_SYSTEM_SUPPORTS_MOVING_WHILE_MOUNTED
52 //	| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME_WHILE_MOUNTED
53 //	| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS_WHILE_MOUNTED
54 ;
55 
56 
57 // #pragma mark - BFSAddOn
58 
59 
60 BFSAddOn::BFSAddOn()
61 	: BDiskSystemAddOn(kPartitionTypeBFS, kDiskSystemFlags)
62 {
63 }
64 
65 
66 BFSAddOn::~BFSAddOn()
67 {
68 }
69 
70 
71 status_t
72 BFSAddOn::CreatePartitionHandle(BMutablePartition* partition,
73 	BPartitionHandle** _handle)
74 {
75 	BFSPartitionHandle* handle = new(nothrow) BFSPartitionHandle(partition);
76 	if (!handle)
77 		return B_NO_MEMORY;
78 
79 	status_t error = handle->Init();
80 	if (error != B_OK) {
81 		delete handle;
82 		return error;
83 	}
84 
85 	*_handle = handle;
86 	return B_OK;
87 }
88 
89 
90 bool
91 BFSAddOn::CanInitialize(const BMutablePartition* partition)
92 {
93 	// TODO: Check partition size.
94 	return true;
95 }
96 
97 
98 status_t
99 BFSAddOn::ValidateInitialize(const BMutablePartition* partition, BString* name,
100 	const char* parameterString)
101 {
102 	if (!CanInitialize(partition) || !name)
103 		return B_BAD_VALUE;
104 
105 	// validate name
106 
107 	// truncate, if it is too long
108 	if (name->Length() >= BFS_DISK_NAME_LENGTH)
109 		name->Truncate(BFS_DISK_NAME_LENGTH - 1);
110 
111 	// replace '/' by '-'
112 	name->ReplaceAll('/', '-');
113 
114 	// check parameters
115 	initialize_parameters parameters;
116 	status_t error = parse_initialize_parameters(parameterString, parameters);
117 	if (error != B_OK)
118 		return error;
119 
120 	return B_OK;
121 }
122 
123 
124 status_t
125 BFSAddOn::Initialize(BMutablePartition* partition, const char* name,
126 	const char* parameterString, BPartitionHandle** _handle)
127 {
128 	if (!CanInitialize(partition) || check_volume_name(name) != B_OK)
129 		return B_BAD_VALUE;
130 
131 	initialize_parameters parameters;
132 	status_t error = parse_initialize_parameters(parameterString, parameters);
133 	if (error != B_OK)
134 		return error;
135 
136 	// create the handle
137 	BFSPartitionHandle* handle = new(nothrow) BFSPartitionHandle(partition);
138 	if (!handle)
139 		return B_NO_MEMORY;
140 	ObjectDeleter<BFSPartitionHandle> handleDeleter(handle);
141 
142 	// init the partition
143 	error = partition->SetContentType(Name());
144 	if (error != B_OK)
145 		return error;
146 // TODO: The content type could as well be set by the caller.
147 
148 	partition->SetContentName(name);
149 	partition->SetContentParameters(parameterString);
150 	uint32 blockSize = parameters.blockSize;
151 	partition->SetBlockSize(blockSize);
152 	partition->SetContentSize(partition->Size() / blockSize * blockSize);
153 	partition->Changed(B_PARTITION_CHANGED_INITIALIZATION);
154 
155 	*_handle = handleDeleter.Detach();
156 
157 	return B_OK;
158 }
159 
160 
161 status_t
162 BFSAddOn::GetParameterEditor(B_PARAMETER_EDITOR_TYPE type,
163 	BPartitionParameterEditor** editor)
164 {
165 	*editor = NULL;
166 	if (type == B_INITIALIZE_PARAMETER_EDITOR) {
167 		try {
168 			*editor = new InitializeBFSEditor();
169 		} catch (std::bad_alloc) {
170 			return B_NO_MEMORY;
171 		}
172 		return B_OK;
173 	}
174 	return B_NOT_SUPPORTED;
175 }
176 
177 
178 // #pragma mark - BFSPartitionHandle
179 
180 
181 BFSPartitionHandle::BFSPartitionHandle(BMutablePartition* partition)
182 	: BPartitionHandle(partition)
183 {
184 }
185 
186 
187 BFSPartitionHandle::~BFSPartitionHandle()
188 {
189 }
190 
191 
192 status_t
193 BFSPartitionHandle::Init()
194 {
195 // TODO: Check parameters.
196 	return B_OK;
197 }
198 
199 
200 uint32
201 BFSPartitionHandle::SupportedOperations(uint32 mask)
202 {
203 	return kDiskSystemFlags & mask;
204 }
205 
206 
207 status_t
208 BFSPartitionHandle::Repair(bool checkOnly)
209 {
210 	BVolume volume(Partition()->VolumeID());
211 	BDirectory directory;
212 	volume.GetRootDirectory(&directory);
213 	BPath path;
214 	path.SetTo(&directory, ".");
215 
216 	int fd = open(path.Path(), O_RDONLY);
217 	if (fd < 0)
218 	    return errno;
219 
220 	struct check_control result;
221 	memset(&result, 0, sizeof(result));
222 	result.magic = BFS_IOCTL_CHECK_MAGIC;
223 	result.flags = !checkOnly ? BFS_FIX_BITMAP_ERRORS : 0;
224 	if (!checkOnly) {
225 		//printf("will fix any severe errors!\n");
226 		result.flags |= BFS_REMOVE_WRONG_TYPES | BFS_REMOVE_INVALID
227 			| BFS_FIX_NAME_MISMATCHES;
228 	}
229 
230 	// start checking
231 	if (ioctl(fd, BFS_IOCTL_START_CHECKING, &result, sizeof(result)) < 0)
232 	    return errno;
233 
234 	off_t attributeDirectories = 0, attributes = 0;
235 	off_t files = 0, directories = 0, indices = 0;
236 	off_t counter = 0;
237 
238 	// check all files and report errors
239 	while (ioctl(fd, BFS_IOCTL_CHECK_NEXT_NODE, &result,
240 			sizeof(result)) == 0) {
241 		if (++counter % 50 == 0)
242 			printf("%9Ld nodes processed\x1b[1A\n", counter);
243 
244 		if (result.errors) {
245 			printf("%s (inode = %lld)", result.name, result.inode);
246 			if (result.errors & BFS_MISSING_BLOCKS)
247 				printf(", some blocks weren't allocated");
248 			if (result.errors & BFS_BLOCKS_ALREADY_SET)
249 				printf(", has blocks already set");
250 			if (result.errors & BFS_INVALID_BLOCK_RUN)
251 				printf(", has invalid block run(s)");
252 			if (result.errors & BFS_COULD_NOT_OPEN)
253 				printf(", could not be opened");
254 			if (result.errors & BFS_WRONG_TYPE)
255 				printf(", has wrong type");
256 			if (result.errors & BFS_NAMES_DONT_MATCH)
257 				printf(", names don't match");
258 			putchar('\n');
259 		}
260 		if ((result.mode & (S_INDEX_DIR | 0777)) == S_INDEX_DIR)
261 			indices++;
262 		else if (result.mode & S_ATTR_DIR)
263 			attributeDirectories++;
264 		else if (result.mode & S_ATTR)
265 			attributes++;
266 		else if (S_ISDIR(result.mode))
267 			directories++;
268 		else
269 			files++;
270 	}
271 
272 	// stop checking
273 	if (ioctl(fd, BFS_IOCTL_STOP_CHECKING, &result, sizeof(result)) != 0) {
274 		close(fd);
275 		return errno;
276 	}
277 
278 	close(fd);
279 
280 	printf("\t%lld nodes checked,\n\t%lld blocks not allocated,"
281 		"\n\t%lld blocks already set,\n\t%lld blocks could be freed\n\n",
282 		counter, result.stats.missing, result.stats.already_set,
283 		result.stats.freed);
284 	printf("\tfiles\t\t%lld\n\tdirectories\t%lld\n\tattributes\t%lld\n\tattr. "
285 		"dirs\t%lld\n\tindices\t\t%lld\n", files, directories, attributes,
286 		attributeDirectories, indices);
287 
288 	if (result.status == B_ENTRY_NOT_FOUND)
289 		result.status = B_OK;
290 
291 	return result.status;
292 }
293 
294 
295 // #pragma mark -
296 
297 
298 status_t
299 get_disk_system_add_ons(BList* addOns)
300 {
301 	BFSAddOn* addOn = new(nothrow) BFSAddOn;
302 	if (!addOn)
303 		return B_NO_MEMORY;
304 
305 	if (!addOns->AddItem(addOn)) {
306 		delete addOn;
307 		return B_NO_MEMORY;
308 	}
309 
310 	return B_OK;
311 }
312