1 // KernelRequestHandler.cpp 2 3 #include "Compatibility.h" 4 #include "Debug.h" 5 #include "FileSystem.h" 6 #include "KernelRequestHandler.h" 7 #include "RequestPort.h" 8 #include "Requests.h" 9 #include "Volume.h" 10 11 #include <NodeMonitor.h> 12 13 // VolumePutter 14 class VolumePutter { 15 public: 16 VolumePutter(Volume* volume) : fVolume(volume) {} 17 ~VolumePutter() 18 { 19 if (fVolume) 20 fVolume->RemoveReference(); 21 } 22 23 private: 24 Volume *fVolume; 25 }; 26 27 // constructor 28 KernelRequestHandler::KernelRequestHandler(Volume* volume, uint32 expectedReply) 29 : RequestHandler(), 30 fFileSystem(volume->GetFileSystem()), 31 fVolume(volume), 32 fExpectedReply(expectedReply) 33 { 34 } 35 36 // constructor 37 KernelRequestHandler::KernelRequestHandler(FileSystem* fileSystem, 38 uint32 expectedReply) 39 : RequestHandler(), 40 fFileSystem(fileSystem), 41 fVolume(NULL), 42 fExpectedReply(expectedReply) 43 { 44 } 45 46 // destructor 47 KernelRequestHandler::~KernelRequestHandler() 48 { 49 } 50 51 // HandleRequest 52 status_t 53 KernelRequestHandler::HandleRequest(Request* request) 54 { 55 if (request->GetType() == fExpectedReply) { 56 fDone = true; 57 return B_OK; 58 } 59 switch (request->GetType()) { 60 // notifications 61 case NOTIFY_LISTENER_REQUEST: 62 return _HandleRequest((NotifyListenerRequest*)request); 63 case NOTIFY_SELECT_EVENT_REQUEST: 64 return _HandleRequest((NotifySelectEventRequest*)request); 65 case NOTIFY_QUERY_REQUEST: 66 return _HandleRequest((NotifyQueryRequest*)request); 67 // vnodes 68 case GET_VNODE_REQUEST: 69 return _HandleRequest((GetVNodeRequest*)request); 70 case PUT_VNODE_REQUEST: 71 return _HandleRequest((PutVNodeRequest*)request); 72 case NEW_VNODE_REQUEST: 73 return _HandleRequest((NewVNodeRequest*)request); 74 case PUBLISH_VNODE_REQUEST: 75 return _HandleRequest((PublishVNodeRequest*)request); 76 case REMOVE_VNODE_REQUEST: 77 return _HandleRequest((RemoveVNodeRequest*)request); 78 case UNREMOVE_VNODE_REQUEST: 79 return _HandleRequest((UnremoveVNodeRequest*)request); 80 case GET_VNODE_REMOVED_REQUEST: 81 return _HandleRequest((GetVNodeRemovedRequest*)request); 82 } 83 PRINT(("KernelRequestHandler::HandleRequest(): unexpected request: %lu\n", 84 request->GetType())); 85 return B_BAD_DATA; 86 } 87 88 // #pragma mark - 89 // #pragma mark ----- notifications ----- 90 91 // _HandleRequest 92 status_t 93 KernelRequestHandler::_HandleRequest(NotifyListenerRequest* request) 94 { 95 // check and executed the request 96 status_t result = B_OK; 97 if (fVolume && request->device != fVolume->GetID()) 98 result = B_BAD_VALUE; 99 100 // get the names 101 // name 102 char* name = (char*)request->name.GetData(); 103 int32 nameLen = request->name.GetSize(); 104 if (name && (nameLen <= 0)) 105 name = NULL; 106 else if (name) 107 name[nameLen - 1] = '\0'; // NULL-terminate to be safe 108 109 // old name 110 char* oldName = (char*)request->oldName.GetData(); 111 int32 oldNameLen = request->oldName.GetSize(); 112 if (oldName && (oldNameLen <= 0)) 113 oldName = NULL; 114 else if (oldName) 115 oldName[oldNameLen - 1] = '\0'; // NULL-terminate to be safe 116 117 // check the names 118 if (result == B_OK) { 119 switch (request->operation) { 120 case B_ENTRY_MOVED: 121 if (!oldName) { 122 ERROR(("NotifyListenerRequest: NULL oldName for " 123 "B_ENTRY_MOVED\n")); 124 result = B_BAD_VALUE; 125 break; 126 } 127 // fall through... 128 case B_ENTRY_CREATED: 129 case B_ENTRY_REMOVED: 130 case B_ATTR_CHANGED: 131 if (!name) { 132 ERROR(("NotifyListenerRequest: NULL name for opcode: %ld\n", 133 request->operation)); 134 result = B_BAD_VALUE; 135 } 136 break; 137 case B_STAT_CHANGED: 138 break; 139 } 140 } 141 142 // execute the request 143 if (result == B_OK) { 144 switch (request->operation) { 145 case B_ENTRY_CREATED: 146 PRINT(("notify_entry_created(%ld, %lld, \"%s\", %lld)\n", 147 request->device, request->directory, name, request->node)); 148 result = notify_entry_created(request->device, 149 request->directory, name, request->node); 150 break; 151 152 case B_ENTRY_REMOVED: 153 PRINT(("notify_entry_removed(%ld, %lld, \"%s\", %lld)\n", 154 request->device, request->directory, name, request->node)); 155 result = notify_entry_removed(request->device, 156 request->directory, name, request->node); 157 break; 158 159 case B_ENTRY_MOVED: 160 PRINT(("notify_entry_moved(%ld, %lld, \"%s\", %lld, \"%s\", " 161 "%lld)\n", request->device, request->oldDirectory, oldName, 162 request->directory, name, request->node)); 163 result = notify_entry_moved(request->device, 164 request->oldDirectory, oldName, request->directory, name, 165 request->node); 166 break; 167 168 case B_STAT_CHANGED: 169 PRINT(("notify_stat_changed(%ld, %lld, 0x%lx)\n", 170 request->device, request->node, request->details)); 171 result = notify_stat_changed(request->device, request->node, 172 request->details); 173 break; 174 175 case B_ATTR_CHANGED: 176 PRINT(("notify_attribute_changed(%ld, %lld, \"%s\", 0x%lx)\n", 177 request->device, request->node, name, 178 (int32)request->details)); 179 result = notify_attribute_changed(request->device, 180 request->node, name, (int32)request->details); 181 break; 182 183 default: 184 ERROR(("NotifyQueryRequest: unsupported operation: %ld\n", 185 request->operation)); 186 result = B_BAD_VALUE; 187 break; 188 } 189 } 190 191 // prepare the reply 192 RequestAllocator allocator(fPort->GetPort()); 193 NotifyListenerReply* reply; 194 status_t error = AllocateRequest(allocator, &reply); 195 if (error != B_OK) 196 return error; 197 198 reply->error = result; 199 200 // send the reply 201 return fPort->SendRequest(&allocator); 202 } 203 204 // _HandleRequest 205 status_t 206 KernelRequestHandler::_HandleRequest(NotifySelectEventRequest* request) 207 { 208 // check and executed the request 209 status_t result = B_OK; 210 if (fFileSystem->KnowsSelectSyncEntry(request->sync)) { 211 if (request->unspecifiedEvent) { 212 // old style add-ons can't provide an event argument; we shoot 213 // all events 214 notify_select_event(request->sync, B_SELECT_READ); 215 notify_select_event(request->sync, B_SELECT_WRITE); 216 notify_select_event(request->sync, B_SELECT_ERROR); 217 } else { 218 PRINT(("notify_select_event(%p, %d)\n", request->sync, 219 (int)request->event)); 220 notify_select_event(request->sync, request->event); 221 } 222 } else 223 result = B_BAD_VALUE; 224 225 // prepare the reply 226 RequestAllocator allocator(fPort->GetPort()); 227 NotifySelectEventReply* reply; 228 status_t error = AllocateRequest(allocator, &reply); 229 if (error != B_OK) 230 return error; 231 232 reply->error = result; 233 234 // send the reply 235 return fPort->SendRequest(&allocator); 236 } 237 238 // _HandleRequest 239 status_t 240 KernelRequestHandler::_HandleRequest(NotifyQueryRequest* request) 241 { 242 // check and executed the request 243 status_t result = B_OK; 244 if (fVolume && request->device != fVolume->GetID()) 245 result = B_BAD_VALUE; 246 247 // check the name 248 char* name = (char*)request->name.GetData(); 249 int32 nameLen = request->name.GetSize(); 250 if (!name || nameLen <= 0) { 251 ERROR(("NotifyQueryRequest: NULL name!\n")); 252 result = B_BAD_VALUE; 253 } else 254 name[nameLen - 1] = '\0'; // NULL-terminate to be safe 255 256 // execute the request 257 if (result == B_OK) { 258 switch (request->operation) { 259 case B_ENTRY_CREATED: 260 PRINT(("notify_query_entry_created(%ld, %ld, %ld, %lld," 261 " \"%s\", %lld)\n", request->port, request->token, 262 request->device, request->directory, name, request->node)); 263 result = notify_query_entry_created(request->port, 264 request->token, request->device, request->directory, name, 265 request->node); 266 break; 267 268 case B_ENTRY_REMOVED: 269 PRINT(("notify_query_entry_removed(%ld, %ld, %ld, %lld," 270 " \"%s\", %lld)\n", request->port, request->token, 271 request->device, request->directory, name, request->node)); 272 result = notify_query_entry_removed(request->port, 273 request->token, request->device, request->directory, name, 274 request->node); 275 break; 276 277 case B_ENTRY_MOVED: 278 default: 279 ERROR(("NotifyQueryRequest: unsupported operation: %ld\n", 280 request->operation)); 281 result = B_BAD_VALUE; 282 break; 283 } 284 } 285 286 // prepare the reply 287 RequestAllocator allocator(fPort->GetPort()); 288 NotifyQueryReply* reply; 289 status_t error = AllocateRequest(allocator, &reply); 290 if (error != B_OK) 291 return error; 292 293 reply->error = result; 294 295 // send the reply 296 return fPort->SendRequest(&allocator); 297 } 298 299 // #pragma mark - 300 // #pragma mark ----- vnodes ----- 301 302 // _HandleRequest 303 status_t 304 KernelRequestHandler::_HandleRequest(GetVNodeRequest* request) 305 { 306 // check and executed the request 307 Volume* volume = NULL; 308 status_t result = _GetVolume(request->nsid, &volume); 309 VolumePutter _(volume); 310 void* node; 311 if (result == B_OK) 312 result = volume->GetVNode(request->vnid, &node); 313 // prepare the reply 314 RequestAllocator allocator(fPort->GetPort()); 315 GetVNodeReply* reply; 316 status_t error = AllocateRequest(allocator, &reply); 317 if (error != B_OK) 318 return error; 319 reply->error = result; 320 reply->node = node; 321 // send the reply 322 return fPort->SendRequest(&allocator); 323 } 324 325 // _HandleRequest 326 status_t 327 KernelRequestHandler::_HandleRequest(PutVNodeRequest* request) 328 { 329 // check and executed the request 330 Volume* volume = NULL; 331 status_t result = _GetVolume(request->nsid, &volume); 332 VolumePutter _(volume); 333 if (result == B_OK) 334 result = volume->PutVNode(request->vnid); 335 // prepare the reply 336 RequestAllocator allocator(fPort->GetPort()); 337 PutVNodeReply* reply; 338 status_t error = AllocateRequest(allocator, &reply); 339 if (error != B_OK) 340 return error; 341 reply->error = result; 342 // send the reply 343 return fPort->SendRequest(&allocator); 344 } 345 346 // _HandleRequest 347 status_t 348 KernelRequestHandler::_HandleRequest(NewVNodeRequest* request) 349 { 350 // check and executed the request 351 Volume* volume = NULL; 352 status_t result = _GetVolume(request->nsid, &volume); 353 VolumePutter _(volume); 354 if (result == B_OK) 355 result = volume->NewVNode(request->vnid, request->node); 356 // prepare the reply 357 RequestAllocator allocator(fPort->GetPort()); 358 NewVNodeReply* reply; 359 status_t error = AllocateRequest(allocator, &reply); 360 if (error != B_OK) 361 return error; 362 reply->error = result; 363 // send the reply 364 return fPort->SendRequest(&allocator); 365 } 366 367 // _HandleRequest 368 status_t 369 KernelRequestHandler::_HandleRequest(PublishVNodeRequest* request) 370 { 371 // check and executed the request 372 Volume* volume = NULL; 373 status_t result = _GetVolume(request->nsid, &volume); 374 VolumePutter _(volume); 375 if (result == B_OK) 376 result = volume->PublishVNode(request->vnid, request->node); 377 378 // prepare the reply 379 RequestAllocator allocator(fPort->GetPort()); 380 PublishVNodeReply* reply; 381 status_t error = AllocateRequest(allocator, &reply); 382 if (error != B_OK) 383 return error; 384 385 reply->error = result; 386 387 // send the reply 388 return fPort->SendRequest(&allocator); 389 } 390 391 // _HandleRequest 392 status_t 393 KernelRequestHandler::_HandleRequest(RemoveVNodeRequest* request) 394 { 395 // check and executed the request 396 Volume* volume = NULL; 397 status_t result = _GetVolume(request->nsid, &volume); 398 VolumePutter _(volume); 399 if (result == B_OK) 400 result = volume->RemoveVNode(request->vnid); 401 // prepare the reply 402 RequestAllocator allocator(fPort->GetPort()); 403 RemoveVNodeReply* reply; 404 status_t error = AllocateRequest(allocator, &reply); 405 if (error != B_OK) 406 return error; 407 reply->error = result; 408 // send the reply 409 return fPort->SendRequest(&allocator); 410 } 411 412 // _HandleRequest 413 status_t 414 KernelRequestHandler::_HandleRequest(UnremoveVNodeRequest* request) 415 { 416 // check and executed the request 417 Volume* volume = NULL; 418 status_t result = _GetVolume(request->nsid, &volume); 419 VolumePutter _(volume); 420 if (result == B_OK) 421 result = volume->UnremoveVNode(request->vnid); 422 // prepare the reply 423 RequestAllocator allocator(fPort->GetPort()); 424 UnremoveVNodeReply* reply; 425 status_t error = AllocateRequest(allocator, &reply); 426 if (error != B_OK) 427 return error; 428 reply->error = result; 429 // send the reply 430 return fPort->SendRequest(&allocator); 431 } 432 433 // _HandleRequest 434 status_t 435 KernelRequestHandler::_HandleRequest(GetVNodeRemovedRequest* request) 436 { 437 // check and executed the request 438 Volume* volume = NULL; 439 status_t result = _GetVolume(request->nsid, &volume); 440 VolumePutter _(volume); 441 bool removed = false; 442 if (result == B_OK) 443 result = volume->GetVNodeRemoved(request->vnid, &removed); 444 445 // prepare the reply 446 RequestAllocator allocator(fPort->GetPort()); 447 GetVNodeRemovedReply* reply; 448 status_t error = AllocateRequest(allocator, &reply); 449 if (error != B_OK) 450 return error; 451 452 reply->error = result; 453 reply->removed = removed; 454 455 // send the reply 456 return fPort->SendRequest(&allocator); 457 } 458 459 // _GetVolume 460 status_t 461 KernelRequestHandler::_GetVolume(dev_t id, Volume** volume) 462 { 463 if (fVolume) { 464 if (fVolume->GetID() != id) { 465 *volume = NULL; 466 return B_BAD_VALUE; 467 } 468 fVolume->AddReference(); 469 *volume = fVolume; 470 return B_OK; 471 } 472 *volume = fFileSystem->GetVolume(id); 473 return (*volume ? B_OK : B_BAD_VALUE); 474 } 475 476