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