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