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