xref: /haiku/src/add-ons/disk_systems/bfs/BFSAddOn.cpp (revision 2600324b57fa31cdea1627d584d314f2a579c4a8)
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 #include "BFSAddOn.h"
9 
10 #include <new>
11 
12 #include <Directory.h>
13 #include <List.h>
14 #include <Path.h>
15 #include <Volume.h>
16 
17 #include <DiskDeviceTypes.h>
18 #include <MutablePartition.h>
19 
20 #include <AutoDeleter.h>
21 
22 #ifdef ASSERT
23 #	undef ASSERT
24 #endif
25 
26 #include "bfs.h"
27 #include "bfs_control.h"
28 #include "bfs_disk_system.h"
29 
30 
31 using std::nothrow;
32 
33 
34 static const uint32 kDiskSystemFlags =
35 	0
36 //	| B_DISK_SYSTEM_SUPPORTS_CHECKING
37 //	| B_DISK_SYSTEM_SUPPORTS_REPAIRING
38 //	| B_DISK_SYSTEM_SUPPORTS_RESIZING
39 //	| B_DISK_SYSTEM_SUPPORTS_MOVING
40 //	| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME
41 //	| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS
42 	| B_DISK_SYSTEM_SUPPORTS_INITIALIZING
43 	| B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
44 //	| B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING
45 //	| B_DISK_SYSTEM_SUPPORTS_DEFRAGMENTING_WHILE_MOUNTED
46 	| B_DISK_SYSTEM_SUPPORTS_CHECKING_WHILE_MOUNTED
47 	| B_DISK_SYSTEM_SUPPORTS_REPAIRING_WHILE_MOUNTED
48 //	| B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED
49 //	| B_DISK_SYSTEM_SUPPORTS_MOVING_WHILE_MOUNTED
50 //	| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME_WHILE_MOUNTED
51 //	| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS_WHILE_MOUNTED
52 ;
53 
54 
55 // #pragma mark - BFSAddOn
56 
57 
58 // constructor
59 BFSAddOn::BFSAddOn()
60 	: BDiskSystemAddOn(kPartitionTypeBFS, kDiskSystemFlags)
61 {
62 }
63 
64 
65 // destructor
66 BFSAddOn::~BFSAddOn()
67 {
68 }
69 
70 
71 // CreatePartitionHandle
72 status_t
73 BFSAddOn::CreatePartitionHandle(BMutablePartition* partition,
74 	BPartitionHandle** _handle)
75 {
76 	BFSPartitionHandle* handle = new(nothrow) BFSPartitionHandle(partition);
77 	if (!handle)
78 		return B_NO_MEMORY;
79 
80 	status_t error = handle->Init();
81 	if (error != B_OK) {
82 		delete handle;
83 		return error;
84 	}
85 
86 	*_handle = handle;
87 	return B_OK;
88 }
89 
90 
91 // CanInitialize
92 bool
93 BFSAddOn::CanInitialize(const BMutablePartition* partition)
94 {
95 	// TODO: Check partition size.
96 	return true;
97 }
98 
99 
100 // GetInitializationParameterEditor
101 status_t
102 BFSAddOn::GetInitializationParameterEditor(const BMutablePartition* partition,
103 	BDiskDeviceParameterEditor** editor)
104 {
105 	// TODO: Implement!
106 	*editor = NULL;
107 	return B_OK;
108 }
109 
110 
111 // ValidateInitialize
112 status_t
113 BFSAddOn::ValidateInitialize(const BMutablePartition* partition, BString* name,
114 	const char* parameterString)
115 {
116 	if (!CanInitialize(partition) || !name)
117 		return B_BAD_VALUE;
118 
119 	// validate name
120 
121 	// truncate, if it is too long
122 	if (name->Length() >= BFS_DISK_NAME_LENGTH)
123 		name->Truncate(BFS_DISK_NAME_LENGTH - 1);
124 
125 	// replace '/' by '-'
126 	name->ReplaceAll('/', '-');
127 
128 	// check parameters
129 	initialize_parameters parameters;
130 	status_t error = parse_initialize_parameters(parameterString, parameters);
131 	if (error != B_OK)
132 		return error;
133 
134 	return B_OK;
135 }
136 
137 
138 // Initialize
139 status_t
140 BFSAddOn::Initialize(BMutablePartition* partition, const char* name,
141 	const char* parameterString, BPartitionHandle** _handle)
142 {
143 	if (!CanInitialize(partition) || check_volume_name(name) != B_OK)
144 		return B_BAD_VALUE;
145 
146 	initialize_parameters parameters;
147 	status_t error = parse_initialize_parameters(parameterString, parameters);
148 	if (error != B_OK)
149 		return error;
150 
151 	// create the handle
152 	BFSPartitionHandle* handle = new(nothrow) BFSPartitionHandle(partition);
153 	if (!handle)
154 		return B_NO_MEMORY;
155 	ObjectDeleter<BFSPartitionHandle> handleDeleter(handle);
156 
157 	// init the partition
158 	error = partition->SetContentType(Name());
159 	if (error != B_OK)
160 		return error;
161 // TODO: The content type could as well be set by the caller.
162 
163 	partition->SetContentName(name);
164 	partition->SetContentParameters(parameterString);
165 	uint32 blockSize = parameters.blockSize;
166 	partition->SetBlockSize(blockSize);
167 	partition->SetContentSize(partition->Size() / blockSize * blockSize);
168 	partition->Changed(B_PARTITION_CHANGED_INITIALIZATION);
169 
170 	*_handle = handleDeleter.Detach();
171 
172 	return B_OK;
173 }
174 
175 
176 // #pragma mark - BFSPartitionHandle
177 
178 
179 BFSPartitionHandle::BFSPartitionHandle(BMutablePartition* partition)
180 	: BPartitionHandle(partition)
181 {
182 }
183 
184 
185 BFSPartitionHandle::~BFSPartitionHandle()
186 {
187 }
188 
189 
190 status_t
191 BFSPartitionHandle::Init()
192 {
193 // TODO: Check parameters.
194 	return B_OK;
195 }
196 
197 
198 uint32
199 BFSPartitionHandle::SupportedOperations(uint32 mask)
200 {
201 	return kDiskSystemFlags & mask;
202 }
203 
204 
205 status_t
206 BFSPartitionHandle::Repair(bool checkOnly)
207 {
208 	BVolume volume(Partition()->VolumeID());
209 	BDirectory directory;
210 	volume.GetRootDirectory(&directory);
211 	BPath path;
212 	path.SetTo(&directory, ".");
213 
214 	int fd = open(path.Path(), O_RDONLY);
215 	if (fd < 0) {
216 	    printf("chkbfs: error opening '.'\n");
217 	    return errno;
218 	}
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 	}
228 
229 	// start checking
230 	if (ioctl(fd, BFS_IOCTL_START_CHECKING, &result, sizeof(result)) < 0) {
231 	    printf("chkbfs: error starting!\n");
232 	    return errno;
233 	}
234 
235 	off_t attributeDirectories = 0, attributes = 0;
236 	off_t files = 0, directories = 0, indices = 0;
237 	off_t counter = 0;
238 
239 	// check all files and report errors
240 	while (ioctl(fd, BFS_IOCTL_CHECK_NEXT_NODE, &result, 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 = %Ld)", 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 	    printf("chkbfs: error stopping!\n");
275 
276 	close(fd);
277 
278 	printf("checked %Ld nodes, %Ld blocks not allocated, %Ld blocks already "
279 		"set, %Ld blocks could be freed\n", counter, result.stats.missing,
280 		result.stats.already_set, result.stats.freed);
281 	printf("\tfiles\t\t%Ld\n\tdirectories\t%Ld\n\tattributes\t%Ld\n\tattr. "
282 		"dirs\t%Ld\n\tindices\t\t%Ld\n", files, directories, attributes,
283 		attributeDirectories, indices);
284 
285 	if (result.status == B_ENTRY_NOT_FOUND)
286 		result.status = B_OK;
287 
288 	return result.status;
289 }
290 
291 
292 // #pragma mark -
293 
294 
295 // get_disk_system_add_ons
296 status_t
297 get_disk_system_add_ons(BList* addOns)
298 {
299 	BFSAddOn* addOn = new(nothrow) BFSAddOn;
300 	if (!addOn)
301 		return B_NO_MEMORY;
302 
303 	if (!addOns->AddItem(addOn)) {
304 		delete addOn;
305 		return B_NO_MEMORY;
306 	}
307 
308 	return B_OK;
309 }
310