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// VolumePutter 12class VolumePutter { 13public: 14 VolumePutter(Volume* volume) : fVolume(volume) {} 15 ~VolumePutter() 16 { 17 if (fVolume) 18 fVolume->RemoveReference(); 19 } 20 21private: 22 Volume *fVolume; 23}; 24 25// constructor 26KernelRequestHandler::KernelRequestHandler(Volume* volume, uint32 expectedReply) 27 : RequestHandler(), 28 fFileSystem(volume->GetFileSystem()), 29 fVolume(volume), 30 fExpectedReply(expectedReply) 31{ 32} 33 34// constructor 35KernelRequestHandler::KernelRequestHandler(FileSystem* fileSystem, 36 uint32 expectedReply) 37 : RequestHandler(), 38 fFileSystem(fileSystem), 39 fVolume(NULL), 40 fExpectedReply(expectedReply) 41{ 42} 43 44// destructor 45KernelRequestHandler::~KernelRequestHandler() 46{ 47} 48 49// HandleRequest 50status_t 51KernelRequestHandler::HandleRequest(Request* request) 52{ 53 if (request->GetType() == fExpectedReply) { 54 fDone = true; 55 return B_OK; 56 } 57 switch (request->GetType()) { 58 // notifications 59 case NOTIFY_LISTENER_REQUEST: 60 return _HandleRequest((NotifyListenerRequest*)request); 61 case NOTIFY_SELECT_EVENT_REQUEST: 62 return _HandleRequest((NotifySelectEventRequest*)request); 63 case SEND_NOTIFICATION_REQUEST: 64 return _HandleRequest((SendNotificationRequest*)request); 65 // vnodes 66 case GET_VNODE_REQUEST: 67 return _HandleRequest((GetVNodeRequest*)request); 68 case PUT_VNODE_REQUEST: 69 return _HandleRequest((PutVNodeRequest*)request); 70 case NEW_VNODE_REQUEST: 71 return _HandleRequest((NewVNodeRequest*)request); 72 case REMOVE_VNODE_REQUEST: 73 return _HandleRequest((RemoveVNodeRequest*)request); 74 case UNREMOVE_VNODE_REQUEST: 75 return _HandleRequest((UnremoveVNodeRequest*)request); 76 case IS_VNODE_REMOVED_REQUEST: 77 return _HandleRequest((IsVNodeRemovedRequest*)request); 78 } 79PRINT(("KernelRequestHandler::HandleRequest(): unexpected request: %lu\n", 80request->GetType())); 81 return B_BAD_DATA; 82} 83 84// #pragma mark - 85// #pragma mark ----- notifications ----- 86 87// _HandleRequest 88status_t 89KernelRequestHandler::_HandleRequest(NotifyListenerRequest* request) 90{ 91 // check and executed the request 92 status_t result = B_OK; 93 if (fVolume && request->nsid != fVolume->GetID()) 94 result = B_BAD_VALUE; 95 // check the name 96 char* name = (char*)request->name.GetData(); 97 int32 nameLen = request->name.GetSize(); 98 if (name && (nameLen <= 0 || strnlen(name, nameLen) < 1)) 99 name = NULL; 100 else if (name) 101 name[nameLen - 1] = '\0'; 102 if (!name) { 103 switch (request->operation) { 104 case B_ENTRY_CREATED: 105 case B_ENTRY_MOVED: 106 case B_ATTR_CHANGED: 107 ERROR(("notify_listener(): NULL name for opcode: %ld\n", 108 request->operation)); 109 result = B_BAD_VALUE; 110 break; 111 case B_ENTRY_REMOVED: 112 case B_STAT_CHANGED: 113 break; 114 } 115 } 116 // execute the request 117 if (result == B_OK) { 118 PRINT(("notify_listener(%ld, %ld, %Ld, %Ld, %Ld, `%s')\n", 119 request->operation, request->nsid, request->vnida, request->vnidb, 120 request->vnidc, name)); 121 result = notify_listener(request->operation, request->nsid, 122 request->vnida, request->vnidb, request->vnidc, name); 123 } 124 // prepare the reply 125 RequestAllocator allocator(fPort->GetPort()); 126 NotifyListenerReply* reply; 127 status_t error = AllocateRequest(allocator, &reply); 128 if (error != B_OK) 129 return error; 130 reply->error = result; 131 // send the reply 132 return fPort->SendRequest(&allocator); 133} 134 135// _HandleRequest 136status_t 137KernelRequestHandler::_HandleRequest(NotifySelectEventRequest* request) 138{ 139 // check and executed the request 140 status_t result = B_OK; 141 if (fFileSystem->KnowsSelectSyncEntry(request->sync)) { 142 PRINT(("notify_select_event(%p, %lu)\n", request->sync, request->ref)); 143 notify_select_event(request->sync, request->ref); 144 } else 145 result = B_BAD_VALUE; 146 // prepare the reply 147 RequestAllocator allocator(fPort->GetPort()); 148 NotifySelectEventReply* reply; 149 status_t error = AllocateRequest(allocator, &reply); 150 if (error != B_OK) 151 return error; 152 reply->error = result; 153 // send the reply 154 return fPort->SendRequest(&allocator); 155} 156 157// _HandleRequest 158status_t 159KernelRequestHandler::_HandleRequest(SendNotificationRequest* request) 160{ 161 // check and executed the request 162 status_t result = B_OK; 163 if (fVolume && request->nsida != fVolume->GetID() 164 && request->nsidb != fVolume->GetID()) { 165 result = B_BAD_VALUE; 166 } 167 // check the name 168 char* name = (char*)request->name.GetData(); 169 int32 nameLen = request->name.GetSize(); 170 if (name && (nameLen <= 0 || strnlen(name, nameLen) < 1)) 171 name = NULL; 172 else if (name) 173 name[nameLen - 1] = '\0'; 174 if (!name) { 175 switch (request->operation) { 176 case B_ENTRY_CREATED: 177 case B_ENTRY_MOVED: 178 ERROR(("send_notification(): NULL name for opcode: %ld\n", 179 request->operation)); 180 result = B_BAD_VALUE; 181 break; 182 case B_ENTRY_REMOVED: 183 break; 184 } 185 } 186 // execute the request 187 if (result == B_OK) { 188 PRINT(("send_notification(%ld, %ld, %lu, %ld, %ld, %ld, %Ld, %Ld, %Ld, " 189 "`%s')\n", request->port, request->token, request->what, 190 request->operation, request->nsida, request->nsidb, request->vnida, 191 request->vnidb, request->vnidc, name)); 192 result = send_notification(request->port, request->token, request->what, 193 request->operation, request->nsida, request->nsidb, request->vnida, 194 request->vnidb, request->vnidc, name); 195 } 196 // prepare the reply 197 RequestAllocator allocator(fPort->GetPort()); 198 SendNotificationReply* reply; 199 status_t error = AllocateRequest(allocator, &reply); 200 if (error != B_OK) 201 return error; 202 reply->error = result; 203 // send the reply 204 return fPort->SendRequest(&allocator); 205} 206 207// #pragma mark - 208// #pragma mark ----- vnodes ----- 209 210// _HandleRequest 211status_t 212KernelRequestHandler::_HandleRequest(GetVNodeRequest* request) 213{ 214 // check and executed the request 215 Volume* volume = NULL; 216 status_t result = _GetVolume(request->nsid, &volume); 217 VolumePutter _(volume); 218 void* node; 219 if (result == B_OK) 220 result = volume->GetVNode(request->vnid, &node); 221 // prepare the reply 222 RequestAllocator allocator(fPort->GetPort()); 223 GetVNodeReply* reply; 224 status_t error = AllocateRequest(allocator, &reply); 225 if (error != B_OK) 226 return error; 227 reply->error = result; 228 reply->node = node; 229 // send the reply 230 return fPort->SendRequest(&allocator); 231} 232 233// _HandleRequest 234status_t 235KernelRequestHandler::_HandleRequest(PutVNodeRequest* request) 236{ 237 // check and executed the request 238 Volume* volume = NULL; 239 status_t result = _GetVolume(request->nsid, &volume); 240 VolumePutter _(volume); 241 if (result == B_OK) 242 result = volume->PutVNode(request->vnid); 243 // prepare the reply 244 RequestAllocator allocator(fPort->GetPort()); 245 PutVNodeReply* reply; 246 status_t error = AllocateRequest(allocator, &reply); 247 if (error != B_OK) 248 return error; 249 reply->error = result; 250 // send the reply 251 return fPort->SendRequest(&allocator); 252} 253 254// _HandleRequest 255status_t 256KernelRequestHandler::_HandleRequest(NewVNodeRequest* request) 257{ 258 // check and executed the request 259 Volume* volume = NULL; 260 status_t result = _GetVolume(request->nsid, &volume); 261 VolumePutter _(volume); 262 if (result == B_OK) 263 result = volume->NewVNode(request->vnid, request->node); 264 // prepare the reply 265 RequestAllocator allocator(fPort->GetPort()); 266 NewVNodeReply* reply; 267 status_t error = AllocateRequest(allocator, &reply); 268 if (error != B_OK) 269 return error; 270 reply->error = result; 271 // send the reply 272 return fPort->SendRequest(&allocator); 273} 274 275// _HandleRequest 276status_t 277KernelRequestHandler::_HandleRequest(RemoveVNodeRequest* request) 278{ 279 // check and executed the request 280 Volume* volume = NULL; 281 status_t result = _GetVolume(request->nsid, &volume); 282 VolumePutter _(volume); 283 if (result == B_OK) 284 result = volume->RemoveVNode(request->vnid); 285 // prepare the reply 286 RequestAllocator allocator(fPort->GetPort()); 287 RemoveVNodeReply* reply; 288 status_t error = AllocateRequest(allocator, &reply); 289 if (error != B_OK) 290 return error; 291 reply->error = result; 292 // send the reply 293 return fPort->SendRequest(&allocator); 294} 295 296// _HandleRequest 297status_t 298KernelRequestHandler::_HandleRequest(UnremoveVNodeRequest* request) 299{ 300 // check and executed the request 301 Volume* volume = NULL; 302 status_t result = _GetVolume(request->nsid, &volume); 303 VolumePutter _(volume); 304 if (result == B_OK) 305 result = volume->UnremoveVNode(request->vnid); 306 // prepare the reply 307 RequestAllocator allocator(fPort->GetPort()); 308 UnremoveVNodeReply* reply; 309 status_t error = AllocateRequest(allocator, &reply); 310 if (error != B_OK) 311 return error; 312 reply->error = result; 313 // send the reply 314 return fPort->SendRequest(&allocator); 315} 316 317// _HandleRequest 318status_t 319KernelRequestHandler::_HandleRequest(IsVNodeRemovedRequest* request) 320{ 321 // check and executed the request 322 Volume* volume = NULL; 323 status_t result = _GetVolume(request->nsid, &volume); 324 VolumePutter _(volume); 325 if (result == B_OK) 326 result = volume->IsVNodeRemoved(request->vnid); 327 // prepare the reply 328 RequestAllocator allocator(fPort->GetPort()); 329 IsVNodeRemovedReply* reply; 330 status_t error = AllocateRequest(allocator, &reply); 331 if (error != B_OK) 332 return error; 333 reply->error = (result < 0 ? result : B_OK); 334 reply->result = result; 335 // send the reply 336 return fPort->SendRequest(&allocator); 337} 338 339// _GetVolume 340status_t 341KernelRequestHandler::_GetVolume(nspace_id id, Volume** volume) 342{ 343 if (fVolume) { 344 if (fVolume->GetID() != id) { 345 *volume = NULL; 346 return B_BAD_VALUE; 347 } 348 fVolume->AddReference(); 349 *volume = fVolume; 350 return B_OK; 351 } 352 *volume = fFileSystem->GetVolume(id); 353 return (*volume ? B_OK : B_BAD_VALUE); 354} 355 356