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, uint8 event, 174 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->event = event; 192 request->unspecifiedEvent = unspecifiedEvent; 193 194 // send the request 195 UserlandRequestHandler handler(fileSystem, NOTIFY_SELECT_EVENT_REPLY); 196 NotifySelectEventReply* reply; 197 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 198 if (error != B_OK) 199 return error; 200 RequestReleaser requestReleaser(port, reply); 201 202 // process the reply 203 if (reply->error != B_OK) 204 return reply->error; 205 return error; 206 } 207 208 // send_notification 209 status_t 210 UserlandFS::KernelEmu::notify_query(port_id targetPort, int32 token, 211 int32 operation, dev_t device, ino_t directory, const char* name, 212 ino_t node) 213 { 214 // get the request port and the file system 215 RequestPort* port; 216 FileSystem* fileSystem; 217 status_t error = get_port_and_fs(&port, &fileSystem); 218 if (error != B_OK) 219 return error; 220 221 // prepare the request 222 RequestAllocator allocator(port->GetPort()); 223 NotifyQueryRequest* request; 224 error = AllocateRequest(allocator, &request); 225 if (error != B_OK) 226 return error; 227 228 request->port = targetPort; 229 request->token = token; 230 request->operation = operation; 231 request->device = device; 232 request->directory = directory; 233 request->node = node; 234 error = allocator.AllocateString(request->name, name); 235 if (error != B_OK) 236 return error; 237 238 // send the request 239 UserlandRequestHandler handler(fileSystem, NOTIFY_QUERY_REPLY); 240 NotifyQueryReply* reply; 241 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 242 if (error != B_OK) 243 return error; 244 RequestReleaser requestReleaser(port, reply); 245 246 // process the reply 247 if (reply->error != B_OK) 248 return reply->error; 249 return error; 250 } 251 252 253 // #pragma mark - 254 255 256 // get_vnode 257 status_t 258 UserlandFS::KernelEmu::get_vnode(dev_t nsid, ino_t vnid, fs_vnode* data) 259 { 260 // get the request port and the file system 261 RequestPort* port; 262 FileSystem* fileSystem; 263 status_t error = get_port_and_fs(&port, &fileSystem); 264 if (error != B_OK) 265 return error; 266 267 // prepare the request 268 RequestAllocator allocator(port->GetPort()); 269 GetVNodeRequest* request; 270 error = AllocateRequest(allocator, &request); 271 if (error != B_OK) 272 return error; 273 274 request->nsid = nsid; 275 request->vnid = vnid; 276 277 // send the request 278 UserlandRequestHandler handler(fileSystem, GET_VNODE_REPLY); 279 GetVNodeReply* reply; 280 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 281 if (error != B_OK) 282 return error; 283 RequestReleaser requestReleaser(port, reply); 284 285 // process the reply 286 if (reply->error != B_OK) 287 return reply->error; 288 *data = reply->node; 289 return error; 290 } 291 292 // put_vnode 293 status_t 294 UserlandFS::KernelEmu::put_vnode(dev_t nsid, ino_t vnid) 295 { 296 // get the request port and the file system 297 RequestPort* port; 298 FileSystem* fileSystem; 299 status_t error = get_port_and_fs(&port, &fileSystem); 300 if (error != B_OK) 301 return error; 302 303 // prepare the request 304 RequestAllocator allocator(port->GetPort()); 305 PutVNodeRequest* request; 306 error = AllocateRequest(allocator, &request); 307 if (error != B_OK) 308 return error; 309 310 request->nsid = nsid; 311 request->vnid = vnid; 312 313 // send the request 314 UserlandRequestHandler handler(fileSystem, PUT_VNODE_REPLY); 315 PutVNodeReply* reply; 316 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 317 if (error != B_OK) 318 return error; 319 RequestReleaser requestReleaser(port, reply); 320 321 // process the reply 322 if (reply->error != B_OK) 323 return reply->error; 324 return error; 325 } 326 327 // new_vnode 328 status_t 329 UserlandFS::KernelEmu::new_vnode(dev_t nsid, ino_t vnid, fs_vnode data) 330 { 331 // get the request port and the file system 332 RequestPort* port; 333 FileSystem* fileSystem; 334 status_t error = get_port_and_fs(&port, &fileSystem); 335 if (error != B_OK) 336 return error; 337 338 // prepare the request 339 RequestAllocator allocator(port->GetPort()); 340 NewVNodeRequest* request; 341 error = AllocateRequest(allocator, &request); 342 if (error != B_OK) 343 return error; 344 345 request->nsid = nsid; 346 request->vnid = vnid; 347 request->node = data; 348 349 // send the request 350 UserlandRequestHandler handler(fileSystem, NEW_VNODE_REPLY); 351 NewVNodeReply* reply; 352 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 353 if (error != B_OK) 354 return error; 355 RequestReleaser requestReleaser(port, reply); 356 357 // process the reply 358 if (reply->error != B_OK) 359 return reply->error; 360 return error; 361 } 362 363 // publish_vnode 364 status_t 365 UserlandFS::KernelEmu::publish_vnode(dev_t nsid, ino_t vnid, 366 fs_vnode data) 367 { 368 // get the request port and the file system 369 RequestPort* port; 370 FileSystem* fileSystem; 371 status_t error = get_port_and_fs(&port, &fileSystem); 372 if (error != B_OK) 373 return error; 374 375 // prepare the request 376 RequestAllocator allocator(port->GetPort()); 377 PublishVNodeRequest* request; 378 error = AllocateRequest(allocator, &request); 379 if (error != B_OK) 380 return error; 381 382 request->nsid = nsid; 383 request->vnid = vnid; 384 request->node = data; 385 386 // send the request 387 UserlandRequestHandler handler(fileSystem, PUBLISH_VNODE_REPLY); 388 PublishVNodeReply* reply; 389 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 390 if (error != B_OK) 391 return error; 392 RequestReleaser requestReleaser(port, reply); 393 394 // process the reply 395 if (reply->error != B_OK) 396 return reply->error; 397 return error; 398 } 399 400 // remove_vnode 401 status_t 402 UserlandFS::KernelEmu::remove_vnode(dev_t nsid, ino_t vnid) 403 { 404 // get the request port and the file system 405 RequestPort* port; 406 FileSystem* fileSystem; 407 status_t error = get_port_and_fs(&port, &fileSystem); 408 if (error != B_OK) 409 return error; 410 411 // prepare the request 412 RequestAllocator allocator(port->GetPort()); 413 RemoveVNodeRequest* request; 414 error = AllocateRequest(allocator, &request); 415 if (error != B_OK) 416 return error; 417 418 request->nsid = nsid; 419 request->vnid = vnid; 420 421 // send the request 422 UserlandRequestHandler handler(fileSystem, REMOVE_VNODE_REPLY); 423 RemoveVNodeReply* reply; 424 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 425 if (error != B_OK) 426 return error; 427 RequestReleaser requestReleaser(port, reply); 428 429 // process the reply 430 if (reply->error != B_OK) 431 return reply->error; 432 return error; 433 } 434 435 // unremove_vnode 436 status_t 437 UserlandFS::KernelEmu::unremove_vnode(dev_t nsid, ino_t vnid) 438 { 439 // get the request port and the file system 440 RequestPort* port; 441 FileSystem* fileSystem; 442 status_t error = get_port_and_fs(&port, &fileSystem); 443 if (error != B_OK) 444 return error; 445 446 // prepare the request 447 RequestAllocator allocator(port->GetPort()); 448 UnremoveVNodeRequest* request; 449 error = AllocateRequest(allocator, &request); 450 if (error != B_OK) 451 return error; 452 453 request->nsid = nsid; 454 request->vnid = vnid; 455 456 // send the request 457 UserlandRequestHandler handler(fileSystem, UNREMOVE_VNODE_REPLY); 458 UnremoveVNodeReply* reply; 459 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 460 if (error != B_OK) 461 return error; 462 RequestReleaser requestReleaser(port, reply); 463 464 // process the reply 465 if (reply->error != B_OK) 466 return reply->error; 467 return error; 468 } 469 470 // get_vnode_removed 471 status_t 472 UserlandFS::KernelEmu::get_vnode_removed(dev_t nsid, ino_t vnid, 473 bool* removed) 474 { 475 // get the request port and the file system 476 RequestPort* port; 477 FileSystem* fileSystem; 478 status_t error = get_port_and_fs(&port, &fileSystem); 479 if (error != B_OK) 480 return error; 481 482 // prepare the request 483 RequestAllocator allocator(port->GetPort()); 484 GetVNodeRemovedRequest* request; 485 error = AllocateRequest(allocator, &request); 486 if (error != B_OK) 487 return error; 488 489 request->nsid = nsid; 490 request->vnid = vnid; 491 492 // send the request 493 UserlandRequestHandler handler(fileSystem, GET_VNODE_REMOVED_REPLY); 494 GetVNodeRemovedReply* reply; 495 error = port->SendRequest(&allocator, &handler, (Request**)&reply); 496 if (error != B_OK) 497 return error; 498 RequestReleaser requestReleaser(port, reply); 499 500 // process the reply 501 *removed = reply->removed; 502 return reply->error; 503 } 504 505 // #pragma mark - 506 507 // kernel_debugger 508 void 509 UserlandFS::KernelEmu::kernel_debugger(const char *message) 510 { 511 debugger(message); 512 } 513 514 // vpanic 515 void 516 UserlandFS::KernelEmu::vpanic(const char *format, va_list args) 517 { 518 char buffer[1024]; 519 strcpy(buffer, "PANIC: "); 520 int32 prefixLen = strlen(buffer); 521 int bufferSize = sizeof(buffer) - prefixLen; 522 523 // no vsnprintf() on PPC 524 #if defined(__INTEL__) 525 vsnprintf(buffer + prefixLen, bufferSize - 1, format, args); 526 #else 527 vsprintf(buffer + prefixLen, format, args); 528 #endif 529 530 buffer[sizeof(buffer) - 1] = '\0'; 531 debugger(buffer); 532 } 533 534 // panic 535 void 536 UserlandFS::KernelEmu::panic(const char *format, ...) 537 { 538 va_list args; 539 va_start(args, format); 540 vpanic(format, args); 541 va_end(args); 542 } 543 544 // vdprintf 545 void 546 UserlandFS::KernelEmu::vdprintf(const char *format, va_list args) 547 { 548 vprintf(format, args); 549 } 550 551 // dprintf 552 void 553 UserlandFS::KernelEmu::dprintf(const char *format, ...) 554 { 555 va_list args; 556 va_start(args, format); 557 vdprintf(format, args); 558 va_end(args); 559 } 560 561 void 562 UserlandFS::KernelEmu::dump_block(const char *buffer, int size, 563 const char *prefix) 564 { 565 // TODO: Implement! 566 } 567 568 // parse_expression 569 //ulong 570 //parse_expression(char *str) 571 //{ 572 // return 0; 573 //} 574 575 // add_debugger_command 576 int 577 UserlandFS::KernelEmu::add_debugger_command(char *name, 578 int (*func)(int argc, char **argv), char *help) 579 { 580 return B_OK; 581 } 582 583 // remove_debugger_command 584 int 585 UserlandFS::KernelEmu::remove_debugger_command(char *name, 586 int (*func)(int argc, char **argv)) 587 { 588 return B_OK; 589 } 590 591 // parse_expression 592 uint32 593 UserlandFS::KernelEmu::parse_expression(const char *string) 594 { 595 return 0; 596 } 597 598 599 // kprintf 600 //void 601 //kprintf(const char *format, ...) 602 //{ 603 //} 604 605 // spawn_kernel_thread 606 thread_id 607 UserlandFS::KernelEmu::spawn_kernel_thread(thread_entry function, 608 const char *threadName, long priority, void *arg) 609 { 610 return spawn_thread(function, threadName, priority, arg); 611 } 612