1 // kernel_emu.cpp 2 3 #include "kernel_emu.h" 4 5 #include <stdarg.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 9 #include "RequestPort.h" 10 #include "Requests.h" 11 #include "RequestThread.h" 12 #include "UserlandFSServer.h" 13 #include "UserlandRequestHandler.h" 14 15 16 // Taken from the Haiku Storage Kit (storage_support.cpp) 17 /*! The length of the first component is returned as well as the index at 18 which the next one starts. These values are only valid, if the function 19 returns \c B_OK. 20 \param path the path to be parsed 21 \param length the variable the length of the first component is written 22 into 23 \param nextComponent the variable the index of the next component is 24 written into. \c 0 is returned, if there is no next component. 25 \return \c B_OK, if \a path is not \c NULL, \c B_BAD_VALUE otherwise 26 */ 27 static status_t 28 parse_first_path_component(const char *path, int32& length, 29 int32& nextComponent) 30 { 31 status_t error = (path ? B_OK : B_BAD_VALUE); 32 if (error == B_OK) { 33 int32 i = 0; 34 // find first '/' or end of name 35 for (; path[i] != '/' && path[i] != '\0'; i++); 36 // handle special case "/..." (absolute path) 37 if (i == 0 && path[i] != '\0') 38 i = 1; 39 length = i; 40 // find last '/' or end of name 41 for (; path[i] == '/' && path[i] != '\0'; i++); 42 if (path[i] == '\0') // this covers "" as well 43 nextComponent = 0; 44 else 45 nextComponent = i; 46 } 47 return error; 48 } 49 50 // new_path 51 int 52 UserlandFS::KernelEmu::new_path(const char *path, char **copy) 53 { 54 // check errors and special cases 55 if (!copy) 56 return B_BAD_VALUE; 57 if (!path) { 58 *copy = NULL; 59 return B_OK; 60 } 61 int32 len = strlen(path); 62 if (len < 1) 63 return B_ENTRY_NOT_FOUND; 64 bool appendDot = (path[len - 1] == '/'); 65 if (appendDot) 66 len++; 67 if (len >= B_PATH_NAME_LENGTH) 68 return B_NAME_TOO_LONG; 69 // check the path components 70 const char *remainder = path; 71 int32 length, nextComponent; 72 do { 73 status_t error 74 = parse_first_path_component(remainder, length, nextComponent); 75 if (error != B_OK) 76 return error; 77 if (length >= B_FILE_NAME_LENGTH) 78 error = B_NAME_TOO_LONG; 79 remainder += nextComponent; 80 } while (nextComponent != 0); 81 // clone the path 82 char *copiedPath = (char*)malloc(len + 1); 83 if (!copiedPath) 84 return B_NO_MEMORY; 85 strcpy(copiedPath, path); 86 // append a dot, if desired 87 if (appendDot) { 88 copiedPath[len] = '.'; 89 copiedPath[len] = '\0'; 90 } 91 *copy = copiedPath; 92 return B_OK; 93 } 94 95 // free_path 96 void 97 UserlandFS::KernelEmu::free_path(char *p) 98 { 99 free(p); 100 } 101 102 103 // #pragma mark - 104 105 106 // get_port_and_fs 107 static status_t 108 get_port_and_fs(RequestPort** port, FileSystem** fileSystem) 109 { 110 // get the request thread 111 RequestThread* thread = RequestThread::GetCurrentThread(); 112 if (thread) { 113 *port = thread->GetPort(); 114 *fileSystem = thread->GetFileSystem(); 115 } else { 116 *port = UserlandFSServer::GetNotificationRequestPort(); 117 *fileSystem = UserlandFSServer::GetFileSystem(); 118 if (!*port || !*fileSystem) 119 return B_BAD_VALUE; 120 } 121 return B_OK; 122 } 123 124 // notify_listener 125 status_t 126 UserlandFS::KernelEmu::notify_listener(int32 operation, uint32 details, 127 dev_t device, ino_t oldDirectory, ino_t directory, 128 ino_t node, const char* oldName, const char* name) 129 { 130 // get the request port and the file system 131 RequestPort* port; 132 FileSystem* fileSystem; 133 status_t error = get_port_and_fs(&port, &fileSystem); 134 if (error != B_OK) 135 return error; 136 137 // prepare the request 138 RequestAllocator allocator(port->GetPort()); 139 NotifyListenerRequest* request; 140 error = AllocateRequest(allocator, &request); 141 if (error != B_OK) 142 return error; 143 144 request->operation = operation; 145 request->details = details; 146 request->device = device; 147 request->oldDirectory = oldDirectory; 148 request->directory = directory; 149 request->node = node; 150 error = allocator.AllocateString(request->oldName, oldName); 151 if (error != B_OK) 152 return error; 153 error = allocator.AllocateString(request->name, name); 154 if (error != B_OK) 155 return error; 156 157 // send the request 158 UserlandRequestHandler handler(fileSystem, NOTIFY_LISTENER_REPLY); 159 NotifyListenerReply* reply; 160 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 161 if (error != B_OK) 162 return error; 163 RequestReleaser requestReleaser(port, reply); 164 165 // process the reply 166 if (reply->error != B_OK) 167 return reply->error; 168 return error; 169 } 170 171 // notify_select_event 172 status_t 173 UserlandFS::KernelEmu::notify_select_event(selectsync *sync, uint32 ref, 174 uint8 event, bool unspecifiedEvent) 175 { 176 // get the request port and the file system 177 RequestPort* port; 178 FileSystem* fileSystem; 179 status_t error = get_port_and_fs(&port, &fileSystem); 180 if (error != B_OK) 181 return error; 182 183 // prepare the request 184 RequestAllocator allocator(port->GetPort()); 185 NotifySelectEventRequest* request; 186 error = AllocateRequest(allocator, &request); 187 if (error != B_OK) 188 return error; 189 190 request->sync = sync; 191 request->ref = ref; 192 request->event = event; 193 request->unspecifiedEvent = unspecifiedEvent; 194 195 // send the request 196 UserlandRequestHandler handler(fileSystem, NOTIFY_SELECT_EVENT_REPLY); 197 NotifySelectEventReply* reply; 198 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 199 if (error != B_OK) 200 return error; 201 RequestReleaser requestReleaser(port, reply); 202 203 // process the reply 204 if (reply->error != B_OK) 205 return reply->error; 206 return error; 207 } 208 209 // send_notification 210 status_t 211 UserlandFS::KernelEmu::notify_query(port_id targetPort, int32 token, 212 int32 operation, dev_t device, ino_t directory, const char* name, 213 ino_t node) 214 { 215 // get the request port and the file system 216 RequestPort* port; 217 FileSystem* fileSystem; 218 status_t error = get_port_and_fs(&port, &fileSystem); 219 if (error != B_OK) 220 return error; 221 222 // prepare the request 223 RequestAllocator allocator(port->GetPort()); 224 NotifyQueryRequest* request; 225 error = AllocateRequest(allocator, &request); 226 if (error != B_OK) 227 return error; 228 229 request->port = targetPort; 230 request->token = token; 231 request->operation = operation; 232 request->device = device; 233 request->directory = directory; 234 request->node = node; 235 error = allocator.AllocateString(request->name, name); 236 if (error != B_OK) 237 return error; 238 239 // send the request 240 UserlandRequestHandler handler(fileSystem, NOTIFY_QUERY_REPLY); 241 NotifyQueryReply* reply; 242 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 243 if (error != B_OK) 244 return error; 245 RequestReleaser requestReleaser(port, reply); 246 247 // process the reply 248 if (reply->error != B_OK) 249 return reply->error; 250 return error; 251 } 252 253 254 // #pragma mark - 255 256 257 // get_vnode 258 status_t 259 UserlandFS::KernelEmu::get_vnode(dev_t nsid, ino_t vnid, fs_vnode* data) 260 { 261 // get the request port and the file system 262 RequestPort* port; 263 FileSystem* fileSystem; 264 status_t error = get_port_and_fs(&port, &fileSystem); 265 if (error != B_OK) 266 return error; 267 268 // prepare the request 269 RequestAllocator allocator(port->GetPort()); 270 GetVNodeRequest* request; 271 error = AllocateRequest(allocator, &request); 272 if (error != B_OK) 273 return error; 274 275 request->nsid = nsid; 276 request->vnid = vnid; 277 278 // send the request 279 UserlandRequestHandler handler(fileSystem, GET_VNODE_REPLY); 280 GetVNodeReply* reply; 281 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 282 if (error != B_OK) 283 return error; 284 RequestReleaser requestReleaser(port, reply); 285 286 // process the reply 287 if (reply->error != B_OK) 288 return reply->error; 289 *data = reply->node; 290 return error; 291 } 292 293 // put_vnode 294 status_t 295 UserlandFS::KernelEmu::put_vnode(dev_t nsid, ino_t vnid) 296 { 297 // get the request port and the file system 298 RequestPort* port; 299 FileSystem* fileSystem; 300 status_t error = get_port_and_fs(&port, &fileSystem); 301 if (error != B_OK) 302 return error; 303 304 // prepare the request 305 RequestAllocator allocator(port->GetPort()); 306 PutVNodeRequest* request; 307 error = AllocateRequest(allocator, &request); 308 if (error != B_OK) 309 return error; 310 311 request->nsid = nsid; 312 request->vnid = vnid; 313 314 // send the request 315 UserlandRequestHandler handler(fileSystem, PUT_VNODE_REPLY); 316 PutVNodeReply* reply; 317 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 318 if (error != B_OK) 319 return error; 320 RequestReleaser requestReleaser(port, reply); 321 322 // process the reply 323 if (reply->error != B_OK) 324 return reply->error; 325 return error; 326 } 327 328 // new_vnode 329 status_t 330 UserlandFS::KernelEmu::new_vnode(dev_t nsid, ino_t vnid, fs_vnode data) 331 { 332 // get the request port and the file system 333 RequestPort* port; 334 FileSystem* fileSystem; 335 status_t error = get_port_and_fs(&port, &fileSystem); 336 if (error != B_OK) 337 return error; 338 339 // prepare the request 340 RequestAllocator allocator(port->GetPort()); 341 NewVNodeRequest* request; 342 error = AllocateRequest(allocator, &request); 343 if (error != B_OK) 344 return error; 345 346 request->nsid = nsid; 347 request->vnid = vnid; 348 request->node = data; 349 350 // send the request 351 UserlandRequestHandler handler(fileSystem, NEW_VNODE_REPLY); 352 NewVNodeReply* reply; 353 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 354 if (error != B_OK) 355 return error; 356 RequestReleaser requestReleaser(port, reply); 357 358 // process the reply 359 if (reply->error != B_OK) 360 return reply->error; 361 return error; 362 } 363 364 // publish_vnode 365 status_t 366 UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, 367 fs_vnode data) 368 { 369 // get the request port and the file system 370 RequestPort* port; 371 FileSystem* fileSystem; 372 status_t error = get_port_and_fs(&port, &fileSystem); 373 if (error != B_OK) 374 return error; 375 376 // prepare the request 377 RequestAllocator allocator(port->GetPort()); 378 PublishVNodeRequest* request; 379 error = AllocateRequest(allocator, &request); 380 if (error != B_OK) 381 return error; 382 383 request->nsid = nsid; 384 request->vnid = vnid; 385 request->node = data; 386 387 // send the request 388 UserlandRequestHandler handler(fileSystem, PUBLISH_VNODE_REPLY); 389 PublishVNodeReply* reply; 390 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 391 if (error != B_OK) 392 return error; 393 RequestReleaser requestReleaser(port, reply); 394 395 // process the reply 396 if (reply->error != B_OK) 397 return reply->error; 398 return error; 399 } 400 401 // remove_vnode 402 status_t 403 UserlandFS::KernelEmu::remove_vnode(dev_t nsid, ino_t vnid) 404 { 405 // get the request port and the file system 406 RequestPort* port; 407 FileSystem* fileSystem; 408 status_t error = get_port_and_fs(&port, &fileSystem); 409 if (error != B_OK) 410 return error; 411 412 // prepare the request 413 RequestAllocator allocator(port->GetPort()); 414 RemoveVNodeRequest* request; 415 error = AllocateRequest(allocator, &request); 416 if (error != B_OK) 417 return error; 418 419 request->nsid = nsid; 420 request->vnid = vnid; 421 422 // send the request 423 UserlandRequestHandler handler(fileSystem, REMOVE_VNODE_REPLY); 424 RemoveVNodeReply* reply; 425 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 426 if (error != B_OK) 427 return error; 428 RequestReleaser requestReleaser(port, reply); 429 430 // process the reply 431 if (reply->error != B_OK) 432 return reply->error; 433 return error; 434 } 435 436 // unremove_vnode 437 status_t 438 UserlandFS::KernelEmu::unremove_vnode(dev_t nsid, ino_t vnid) 439 { 440 // get the request port and the file system 441 RequestPort* port; 442 FileSystem* fileSystem; 443 status_t error = get_port_and_fs(&port, &fileSystem); 444 if (error != B_OK) 445 return error; 446 447 // prepare the request 448 RequestAllocator allocator(port->GetPort()); 449 UnremoveVNodeRequest* request; 450 error = AllocateRequest(allocator, &request); 451 if (error != B_OK) 452 return error; 453 454 request->nsid = nsid; 455 request->vnid = vnid; 456 457 // send the request 458 UserlandRequestHandler handler(fileSystem, UNREMOVE_VNODE_REPLY); 459 UnremoveVNodeReply* reply; 460 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 461 if (error != B_OK) 462 return error; 463 RequestReleaser requestReleaser(port, reply); 464 465 // process the reply 466 if (reply->error != B_OK) 467 return reply->error; 468 return error; 469 } 470 471 // get_vnode_removed 472 status_t 473 UserlandFS::KernelEmu::get_vnode_removed(dev_t nsid, ino_t vnid, 474 bool* removed) 475 { 476 // get the request port and the file system 477 RequestPort* port; 478 FileSystem* fileSystem; 479 status_t error = get_port_and_fs(&port, &fileSystem); 480 if (error != B_OK) 481 return error; 482 483 // prepare the request 484 RequestAllocator allocator(port->GetPort()); 485 GetVNodeRemovedRequest* request; 486 error = AllocateRequest(allocator, &request); 487 if (error != B_OK) 488 return error; 489 490 request->nsid = nsid; 491 request->vnid = vnid; 492 493 // send the request 494 UserlandRequestHandler handler(fileSystem, GET_VNODE_REMOVED_REPLY); 495 GetVNodeRemovedReply* reply; 496 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 497 if (error != B_OK) 498 return error; 499 RequestReleaser requestReleaser(port, reply); 500 501 // process the reply 502 *removed = reply->removed; 503 return reply->error; 504 } 505 506 // #pragma mark - 507 508 // kernel_debugger 509 void 510 UserlandFS::KernelEmu::kernel_debugger(const char *message) 511 { 512 debugger(message); 513 } 514 515 // vpanic 516 void 517 UserlandFS::KernelEmu::vpanic(const char *format, va_list args) 518 { 519 char buffer[1024]; 520 strcpy(buffer, "PANIC: "); 521 int32 prefixLen = strlen(buffer); 522 int bufferSize = sizeof(buffer) - prefixLen; 523 524 // no vsnprintf() on PPC 525 #if defined(__INTEL__) 526 vsnprintf(buffer + prefixLen, bufferSize - 1, format, args); 527 #else 528 vsprintf(buffer + prefixLen, format, args); 529 #endif 530 531 buffer[sizeof(buffer) - 1] = '\0'; 532 debugger(buffer); 533 } 534 535 // panic 536 void 537 UserlandFS::KernelEmu::panic(const char *format, ...) 538 { 539 va_list args; 540 va_start(args, format); 541 vpanic(format, args); 542 va_end(args); 543 } 544 545 // vdprintf 546 void 547 UserlandFS::KernelEmu::vdprintf(const char *format, va_list args) 548 { 549 vprintf(format, args); 550 } 551 552 // dprintf 553 void 554 UserlandFS::KernelEmu::dprintf(const char *format, ...) 555 { 556 va_list args; 557 va_start(args, format); 558 vdprintf(format, args); 559 va_end(args); 560 } 561 562 void 563 UserlandFS::KernelEmu::dump_block(const char *buffer, int size, 564 const char *prefix) 565 { 566 // TODO: Implement! 567 } 568 569 // parse_expression 570 //ulong 571 //parse_expression(char *str) 572 //{ 573 // return 0; 574 //} 575 576 // add_debugger_command 577 int 578 UserlandFS::KernelEmu::add_debugger_command(char *name, 579 int (*func)(int argc, char **argv), char *help) 580 { 581 return B_OK; 582 } 583 584 // remove_debugger_command 585 int 586 UserlandFS::KernelEmu::remove_debugger_command(char *name, 587 int (*func)(int argc, char **argv)) 588 { 589 return B_OK; 590 } 591 592 // parse_expression 593 uint32 594 UserlandFS::KernelEmu::parse_expression(const char *string) 595 { 596 return 0; 597 } 598 599 600 // kprintf 601 //void 602 //kprintf(const char *format, ...) 603 //{ 604 //} 605 606 // spawn_kernel_thread 607 thread_id 608 UserlandFS::KernelEmu::spawn_kernel_thread(thread_entry function, 609 const char *threadName, long priority, void *arg) 610 { 611 return spawn_thread(function, threadName, priority, arg); 612 } 613