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