1 #include <posix/stdlib.h> 2 3 #include "nfs_add_on.h" 4 #include <sys/socket.h> 5 6 #include "rpc.h" 7 #include "pmap.h" 8 #include "nfs.h" 9 #include "mount.h" 10 #include <errno.h> 11 #include <string.h> 12 #include <KernelExport.h> 13 #include <driver_settings.h> 14 #include <sys/stat.h> 15 #include <dirent.h> 16 #include <SupportDefs.h> 17 #include <ByteOrder.h> 18 #include <netinet/udp.h> 19 20 #ifndef UDP_SIZE_MAX 21 #define UDP_SIZE_MAX 65515 22 #endif 23 #define B_UDP_MAX_SIZE UDP_SIZE_MAX 24 25 static status_t fs_rmdir(fs_volume *_volume, fs_vnode *_dir, const char *name); 26 27 /* *** configuration *** */ 28 29 //#define NFS_FS_FLAGS B_FS_IS_SHARED 30 #define NFS_FS_FLAGS B_FS_IS_SHARED|B_FS_IS_PERSISTENT 31 32 /* port numbers: most NFS servers insist on the client port to be < 1024 (secure option) */ 33 /* ports to bind() to; we start at conf_high_port, then go down */ 34 static int16 conf_high_port = 1023; 35 static int16 conf_low_port = 900; 36 37 /* Allow open() to open directories too */ 38 static bool conf_allow_dir_open = true; 39 40 /* Do we list ".." in readdir(rootid) ? (the VFS corrects the dirents anyway) */ 41 /* this seems to be mandatory for Dano... BEntry::GetPath() needs that */ 42 static bool conf_ls_root_parent = true; 43 44 /* timeout when waiting for an answer to a call */ 45 static bigtime_t conf_call_timeout = 2000000; 46 47 /* number of retries when waiting for an anwser to a call */ 48 static unsigned long conf_call_tries = 3; 49 50 /* don't check who the answers come from for requests */ 51 bool conf_no_check_ip_xid = false; 52 53 static vint32 refcount = 0; /* we only want to read the config once ? */ 54 55 static status_t 56 read_config(void) 57 { 58 void *handle; 59 const char *str, *endptr; 60 61 handle = load_driver_settings("nfs"); 62 if (handle == NULL) 63 return ENOENT; 64 65 str = get_driver_parameter(handle, "high_port", NULL, NULL); 66 if (str) { 67 endptr = str + strlen(str); 68 conf_high_port = (int16)strtoul(str, (char **)&endptr, 10); 69 } 70 str = get_driver_parameter(handle, "low_port", NULL, NULL); 71 if (str) { 72 endptr = str + strlen(str); 73 conf_low_port = (int16)strtoul(str, (char **)&endptr, 10); 74 } 75 76 conf_allow_dir_open = get_driver_boolean_parameter(handle, "allow_dir_open", conf_allow_dir_open, true); 77 conf_ls_root_parent = get_driver_boolean_parameter(handle, "ls_root_parent", conf_ls_root_parent, true); 78 conf_no_check_ip_xid = get_driver_boolean_parameter(handle, "no_check_ip_xid", conf_no_check_ip_xid, true); 79 80 str = get_driver_parameter(handle, "call_timeout", NULL, NULL); 81 if (str) { 82 endptr = str + strlen(str); 83 conf_call_timeout = (bigtime_t)1000 * strtoul(str, (char **)&endptr, 10); 84 if (conf_call_timeout < 1000) 85 conf_call_timeout = 1000; 86 } 87 88 str = get_driver_parameter(handle, "call_tries", NULL, NULL); 89 if (str) { 90 endptr = str + strlen(str); 91 conf_call_tries = strtoul(str, (char **)&endptr, 10); 92 } 93 94 unload_driver_settings(handle); 95 return B_OK; 96 } 97 98 99 status_t 100 create_socket(fs_nspace *ns) 101 { 102 struct sockaddr_in addr; 103 uint16 port=conf_high_port; 104 105 ns->s=socket(AF_INET,SOCK_DGRAM,0); 106 107 if (ns->s<0) 108 return errno; 109 110 do 111 { 112 addr.sin_family=AF_INET; 113 addr.sin_addr.s_addr=htonl(INADDR_ANY); 114 //addr.sin_addr.s_addr=htonl(INADDR_LOOPBACK); 115 addr.sin_port=htons(port); 116 memset (addr.sin_zero,0,sizeof(addr.sin_zero)); 117 118 if (bind(ns->s,(const struct sockaddr *)&addr,sizeof(addr))<0) 119 { 120 if (errno!=EADDRINUSE) 121 { 122 int result=errno; 123 close(ns->s); 124 return result; 125 } 126 127 port--; 128 if (port==conf_low_port) 129 { 130 close(ns->s); 131 return B_ERROR; 132 } 133 } 134 else 135 break;//return B_OK; 136 } 137 while (true); 138 139 // doesn't seem to help with autoincrementing port on source address... 140 addr.sin_addr = ns->mountAddr.sin_addr; 141 addr.sin_port = htons(111); 142 //kconnect(ns->s,(const struct sockaddr *)&addr,sizeof(addr)); 143 144 return B_OK; 145 } 146 147 148 #if 0 149 static status_t 150 connect_socket(fs_nspace *ns) 151 { 152 uint16 port = conf_high_port; 153 154 struct sockaddr_in addr; 155 addr.sin_family = AF_INET; 156 addr.sin_addr.s_addr = htonl(INADDR_ANY); 157 //addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 158 addr.sin_port = htons(port); 159 memset(addr.sin_zero,0,sizeof(addr.sin_zero)); 160 161 if (kconnect(ns->s,(const struct sockaddr *)&ns->nfsAddr,sizeof(ns->nfsAddr))<0) 162 { 163 return -1; 164 } 165 return B_OK; 166 } 167 #endif 168 169 170 status_t 171 init_postoffice(fs_nspace *ns) 172 { 173 status_t result; 174 175 ns->tid=spawn_kernel_thread ((thread_func)postoffice_func,"NFSv2 Postoffice",B_NORMAL_PRIORITY,ns); 176 177 if (ns->tid<B_OK) 178 return ns->tid; 179 180 ns->quit=false; 181 182 result=resume_thread (ns->tid); 183 184 if (result<B_OK) 185 { 186 kill_thread (ns->tid); 187 188 return result; 189 } 190 191 return B_OK; 192 } 193 194 195 void 196 shutdown_postoffice(fs_nspace *ns) 197 { 198 status_t result; 199 200 ns->quit=true; 201 close(ns->s); 202 203 wait_for_thread (ns->tid,&result); 204 } 205 206 207 status_t 208 postoffice_func(fs_nspace *ns) 209 { 210 uint8 *buffer=(uint8 *)malloc(B_UDP_MAX_SIZE); 211 212 while (!ns->quit) { 213 struct sockaddr_in from; 214 socklen_t fromLen=sizeof(from); 215 216 ssize_t bytes = recvfrom(ns->s, buffer, B_UDP_MAX_SIZE, 0, 217 (struct sockaddr *)&from, &fromLen); 218 219 if (bytes >= 4) { 220 struct PendingCall *call; 221 int32 xid=B_BENDIAN_TO_HOST_INT32(*((int32 *)buffer)); 222 223 call=RPCPendingCallsFindAndRemovePendingCall(&ns->pendingCalls, xid, 224 &from); 225 226 if (call) { 227 call->buffer=(uint8 *)malloc(bytes); 228 memcpy(call->buffer, buffer, bytes); 229 230 while (release_sem (call->sem) == B_INTERRUPTED); 231 } else { 232 dprintf("nfs: postoffice: can't find pending call to remove " 233 "for xid %" B_PRId32 "\n", xid); 234 } 235 } 236 } 237 238 free (buffer); 239 240 return B_OK; 241 } 242 243 244 uint8 * 245 send_rpc_call(fs_nspace *ns, const struct sockaddr_in *addr, int32 prog, 246 int32 vers, int32 proc, const struct XDROutPacket *packet) 247 { 248 int32 xid; 249 size_t authSize; 250 struct PendingCall *pending; 251 int32 retries=conf_call_tries; 252 status_t result; 253 struct PendingCall *call; 254 255 struct XDROutPacket rpc_call; 256 XDROutPacketInit(&rpc_call); 257 258 xid=atomic_add(&ns->xid, 1); 259 #ifdef DEBUG_XID 260 //dbgprintxid(logfd1, xid); 261 #endif 262 263 XDROutPacketAddInt32(&rpc_call, xid); 264 XDROutPacketAddInt32(&rpc_call, RPC_CALL); 265 XDROutPacketAddInt32(&rpc_call, RPC_VERSION); 266 XDROutPacketAddInt32(&rpc_call, prog); 267 XDROutPacketAddInt32(&rpc_call, vers); 268 XDROutPacketAddInt32(&rpc_call, proc); 269 270 #if !defined(USE_SYSTEM_AUTHENTICATION) 271 XDROutPacketAddInt32(&rpc_call, RPC_AUTH_NONE); 272 XDROutPacketAddDynamic (&rpc_call, NULL, 0); 273 #else 274 XDROutPacketAddInt32(&rpc_call, RPC_AUTH_SYS); 275 authSize = 4 + 4 + ((strlen(ns->params.server) + 3) &~3) + 4 + 4 + 4; 276 XDROutPacketAddInt32(&rpc_call, authSize); 277 XDROutPacketAddInt32(&rpc_call, 0); 278 XDROutPacketAddString(&rpc_call, ns->params.server); 279 XDROutPacketAddInt32(&rpc_call, ns->params.uid); 280 XDROutPacketAddInt32(&rpc_call, ns->params.gid); 281 XDROutPacketAddInt32(&rpc_call, 0); 282 #endif 283 284 XDROutPacketAddInt32(&rpc_call, RPC_AUTH_NONE); 285 XDROutPacketAddDynamic (&rpc_call, NULL, 0); 286 287 XDROutPacketAppend (&rpc_call, packet); 288 289 pending = RPCPendingCallsAddPendingCall(&ns->pendingCalls, xid, addr); 290 #ifdef DEBUG_XID 291 checksemstate(xid, pending->sem, 0); 292 #endif 293 294 do { 295 ssize_t bytes; 296 do { 297 bytes = sendto(ns->s,(const void *)XDROutPacketBuffer(&rpc_call), 298 XDROutPacketLength(&rpc_call), 0, 299 (const struct sockaddr *)addr, sizeof(*addr)); 300 } 301 while (bytes < 0 && errno == EINTR); 302 303 do { 304 result = acquire_sem_etc (pending->sem, 1, B_TIMEOUT, 305 (retries) ? (conf_call_timeout) : (2*conf_call_timeout)); 306 } 307 while (result == B_INTERRUPTED); 308 309 retries--; 310 } while (result == B_TIMED_OUT && retries >= 0); 311 312 if (result >= B_OK) { 313 uint8 *buffer = pending->buffer; 314 pending->buffer = NULL; 315 SemaphorePoolPut(&ns->pendingCalls.fPool, pending->sem); 316 317 PendingCallDestroy(pending); 318 free(pending); 319 320 XDROutPacketDestroy(&rpc_call); 321 return buffer; 322 } 323 324 // we timed out 325 326 call = RPCPendingCallsFindAndRemovePendingCall(&ns->pendingCalls, xid, addr); 327 328 dprintf("nfs: xid %" B_PRId32 " timed out, removing from queue", xid); 329 330 #if 0 331 if (call==NULL) 332 { 333 #if 1 334 //XXX:mmu_man:??? 335 while (acquire_sem(pending->sem)==B_INTERRUPTED); 336 #else 337 status_t err; 338 /* NOTE(mmu_man): there can be a race condition here where the sem is returned 339 * to the pool without the correct value, compromising the next call using it. 340 * however it seems waiting forever can lead to lockups... 341 */ 342 while ((err = acquire_sem_etc(pending->sem,1,B_TIMEOUT,5000000))==B_INTERRUPTED); 343 dprintf("nfs: acquire(pending->sem) = 0x%08lx\n", err); 344 if (err == B_TIMED_OUT) 345 dprintf("nfs: timed out waiting on sem\n"); 346 #endif 347 } 348 #endif 349 350 /* mmu_man */ 351 if (call) /* if the call has been found and removed (atomic op), the sem hasn't been released */ 352 SemaphorePoolPut(&ns->pendingCalls.fPool, pending->sem); 353 else 354 delete_sem(pending->sem); /* else it's in an unknown state, forget it */ 355 356 PendingCallDestroy(pending); 357 free(pending); 358 359 XDROutPacketDestroy (&rpc_call); 360 return NULL; 361 } 362 363 364 bool 365 is_successful_reply(struct XDRInPacket *reply) 366 { 367 bool success = false; 368 369 int32 xid = XDRInPacketGetInt32(reply); 370 rpc_msg_type mtype=(rpc_msg_type)XDRInPacketGetInt32(reply); 371 rpc_reply_stat replyStat=(rpc_reply_stat)XDRInPacketGetInt32(reply); 372 (void)xid; 373 (void)mtype; 374 375 if (replyStat == RPC_MSG_DENIED) { 376 rpc_reject_stat rejectStat = (rpc_reject_stat)XDRInPacketGetInt32(reply); 377 378 if (rejectStat == RPC_RPC_MISMATCH) { 379 int32 low = XDRInPacketGetInt32(reply); 380 int32 high = XDRInPacketGetInt32(reply); 381 382 dprintf("nfs: RPC_MISMATCH (%" B_PRId32 ",%" B_PRId32 ")", low, 383 high); 384 } else { 385 rpc_auth_stat authStat = (rpc_auth_stat)XDRInPacketGetInt32(reply); 386 387 dprintf("nfs: RPC_AUTH_ERROR (%d)", authStat); 388 } 389 } else { 390 rpc_auth_flavor flavor = (rpc_auth_flavor)XDRInPacketGetInt32(reply); 391 char body[400]; 392 size_t bodyLength = XDRInPacketGetDynamic(reply, body); 393 394 rpc_accept_stat acceptStat = (rpc_accept_stat)XDRInPacketGetInt32(reply); 395 (void)flavor; 396 (void)bodyLength; 397 398 if (acceptStat == RPC_PROG_MISMATCH) { 399 int32 low = XDRInPacketGetInt32(reply); 400 int32 high = XDRInPacketGetInt32(reply); 401 402 dprintf("nfs: RPC_PROG_MISMATCH (%" B_PRId32 ",%" B_PRId32 ")", 403 low, high); 404 } else if (acceptStat != RPC_SUCCESS) 405 dprintf("nfs: Accepted but failed (%d)", acceptStat); 406 else 407 success = true; 408 } 409 410 return success; 411 } 412 413 414 status_t 415 get_remote_address(fs_nspace *ns, int32 prog, int32 vers, int32 prot, 416 struct sockaddr_in *addr) 417 { 418 struct XDROutPacket call; 419 uint8 *replyBuf; 420 421 XDROutPacketInit(&call); 422 423 addr->sin_port = htons(PMAP_PORT); 424 425 XDROutPacketAddInt32(&call, prog); 426 XDROutPacketAddInt32(&call, vers); 427 XDROutPacketAddInt32(&call, prot); 428 XDROutPacketAddInt32(&call, 0); 429 430 replyBuf = send_rpc_call(ns, addr, PMAP_PROGRAM, PMAP_VERSION, 431 PMAPPROC_GETPORT, &call); 432 433 if (replyBuf) { 434 struct XDRInPacket reply; 435 XDRInPacketInit(&reply); 436 437 XDRInPacketSetTo(&reply,replyBuf,0); 438 439 if (is_successful_reply(&reply)) { 440 addr->sin_port = htons(XDRInPacketGetInt32(&reply)); 441 memset(addr->sin_zero, 0, sizeof(addr->sin_zero)); 442 443 XDRInPacketDestroy(&reply); 444 XDROutPacketDestroy(&call); 445 return B_OK; 446 } 447 448 XDRInPacketDestroy(&reply); 449 } 450 451 XDROutPacketDestroy (&call); 452 return EHOSTUNREACH; 453 } 454 455 status_t 456 nfs_mount(fs_nspace *ns, const char *path, nfs_fhandle *fhandle) 457 { 458 struct XDROutPacket call; 459 struct XDRInPacket reply; 460 uint8 *replyBuf; 461 int32 fhstatus; 462 463 XDROutPacketInit(&call); 464 XDRInPacketInit(&reply); 465 466 XDROutPacketAddString(&call,path); 467 468 replyBuf = send_rpc_call(ns, &ns->mountAddr, MOUNT_PROGRAM, MOUNT_VERSION, 469 MOUNTPROC_MNT, &call); 470 471 if (!replyBuf) { 472 XDRInPacketDestroy(&reply); 473 XDROutPacketDestroy(&call); 474 return EHOSTUNREACH; 475 } 476 477 XDRInPacketSetTo(&reply, replyBuf, 0); 478 479 if (!is_successful_reply(&reply)) { 480 XDRInPacketDestroy(&reply); 481 XDROutPacketDestroy(&call); 482 return B_ERROR; 483 } 484 485 fhstatus = XDRInPacketGetInt32(&reply); 486 487 if (fhstatus != 0) { 488 XDRInPacketDestroy(&reply); 489 XDROutPacketDestroy(&call); 490 return map_nfs_to_system_error(fhstatus); 491 } 492 493 XDRInPacketGetFixed(&reply, fhandle->opaque, NFS_FHSIZE); 494 495 XDRInPacketDestroy(&reply); 496 XDROutPacketDestroy(&call); 497 return B_OK; 498 } 499 500 501 status_t 502 nfs_lookup (fs_nspace *ns, const nfs_fhandle *dir, const char *filename, 503 nfs_fhandle *fhandle, struct stat *st) 504 { 505 struct XDROutPacket call; 506 struct XDRInPacket reply; 507 int32 status; 508 uint8 *replyBuf; 509 510 XDROutPacketInit(&call); 511 XDRInPacketInit(&reply); 512 513 XDROutPacketAddFixed(&call, dir->opaque, NFS_FHSIZE); 514 XDROutPacketAddString(&call, filename); 515 516 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 517 NFSPROC_LOOKUP, &call); 518 519 if (!replyBuf) { 520 XDRInPacketDestroy(&reply); 521 XDROutPacketDestroy(&call); 522 return EHOSTUNREACH; 523 } 524 525 XDRInPacketSetTo(&reply, replyBuf, 0); 526 527 if (!is_successful_reply(&reply)) { 528 XDRInPacketDestroy(&reply); 529 XDROutPacketDestroy(&call); 530 return B_ERROR; 531 } 532 533 status = XDRInPacketGetInt32(&reply); 534 535 if (status != NFS_OK) { 536 XDRInPacketDestroy(&reply); 537 XDROutPacketDestroy(&call); 538 return map_nfs_to_system_error(status); 539 } 540 541 XDRInPacketGetFixed(&reply, fhandle->opaque, NFS_FHSIZE); 542 543 if (st) 544 get_nfs_attr(&reply, st); 545 546 XDRInPacketDestroy(&reply); 547 XDROutPacketDestroy(&call); 548 return B_OK; 549 } 550 551 552 status_t 553 nfs_getattr(fs_nspace *ns, const nfs_fhandle *fhandle, struct stat *st) 554 { 555 struct XDROutPacket call; 556 struct XDRInPacket reply; 557 uint8 *replyBuf; 558 int32 status; 559 560 XDROutPacketInit(&call); 561 XDRInPacketInit(&reply); 562 563 XDROutPacketAddFixed(&call, fhandle->opaque, NFS_FHSIZE); 564 565 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 566 NFSPROC_GETATTR, &call); 567 if (replyBuf == NULL) { 568 XDRInPacketDestroy(&reply); 569 XDROutPacketDestroy(&call); 570 return EHOSTUNREACH; 571 } 572 573 XDRInPacketSetTo(&reply, replyBuf, 0); 574 575 if (!is_successful_reply(&reply)) { 576 XDRInPacketDestroy(&reply); 577 XDROutPacketDestroy(&call); 578 return B_ERROR; 579 } 580 581 status = XDRInPacketGetInt32(&reply); 582 if (status != NFS_OK) { 583 XDRInPacketDestroy(&reply); 584 XDROutPacketDestroy(&call); 585 return map_nfs_to_system_error(status); 586 } 587 588 get_nfs_attr(&reply, st); 589 590 XDRInPacketDestroy(&reply); 591 XDROutPacketDestroy(&call); 592 return B_OK; 593 } 594 595 596 status_t 597 nfs_truncate_file(fs_nspace *ns, const nfs_fhandle *fhandle, struct stat *st) 598 { 599 struct XDROutPacket call; 600 struct XDRInPacket reply; 601 uint8 *replyBuf; 602 int32 status; 603 604 XDROutPacketInit(&call); 605 XDRInPacketInit(&reply); 606 607 XDROutPacketAddFixed(&call, fhandle->opaque, NFS_FHSIZE); 608 609 XDROutPacketAddInt32(&call, -1); 610 XDROutPacketAddInt32(&call, -1); 611 XDROutPacketAddInt32(&call, -1); 612 XDROutPacketAddInt32(&call, 0); 613 XDROutPacketAddInt32(&call, time(NULL)); 614 XDROutPacketAddInt32(&call, 0); 615 XDROutPacketAddInt32(&call, time(NULL)); 616 XDROutPacketAddInt32(&call, 0); 617 618 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 619 NFSPROC_SETATTR, &call); 620 if (replyBuf == NULL) { 621 XDRInPacketDestroy(&reply); 622 XDROutPacketDestroy(&call); 623 return EHOSTUNREACH; 624 } 625 626 XDRInPacketSetTo(&reply, replyBuf, 0); 627 628 if (!is_successful_reply(&reply)) { 629 XDRInPacketDestroy(&reply); 630 XDROutPacketDestroy(&call); 631 return B_ERROR; 632 } 633 634 status = XDRInPacketGetInt32(&reply); 635 if (status != NFS_OK) { 636 XDRInPacketDestroy(&reply); 637 XDROutPacketDestroy(&call); 638 return map_nfs_to_system_error(status); 639 } 640 641 if (st) 642 get_nfs_attr(&reply,st); 643 644 XDRInPacketDestroy(&reply); 645 XDROutPacketDestroy(&call); 646 return B_OK; 647 } 648 649 650 void 651 get_nfs_attr(struct XDRInPacket *reply, struct stat *st) 652 { 653 nfs_ftype ftype=(nfs_ftype)XDRInPacketGetInt32(reply); 654 (void) ftype; 655 st->st_mode=XDRInPacketGetInt32(reply); 656 657 st->st_dev=0; // just to be sure 658 st->st_nlink=XDRInPacketGetInt32(reply); 659 st->st_uid=XDRInPacketGetInt32(reply); 660 st->st_gid=XDRInPacketGetInt32(reply); 661 st->st_size=XDRInPacketGetInt32(reply); 662 #if 0 663 XDRInPacketGetInt32(reply); // blksize 664 st->st_blksize=NFS_MAXDATA; 665 #else 666 st->st_blksize=XDRInPacketGetInt32(reply); 667 #endif 668 st->st_rdev=XDRInPacketGetInt32(reply); 669 XDRInPacketGetInt32(reply); // blocks 670 XDRInPacketGetInt32(reply); // fsid 671 st->st_ino=XDRInPacketGetInt32(reply); 672 st->st_atime=XDRInPacketGetInt32(reply); 673 XDRInPacketGetInt32(reply); // usecs 674 st->st_mtime=st->st_crtime=XDRInPacketGetInt32(reply); 675 XDRInPacketGetInt32(reply); // usecs 676 st->st_ctime=XDRInPacketGetInt32(reply); 677 XDRInPacketGetInt32(reply); // usecs 678 } 679 680 681 status_t 682 map_nfs_to_system_error(status_t nfsstatus) 683 { 684 switch (nfsstatus) { 685 case NFS_OK: 686 return B_OK; 687 688 case NFSERR_PERM: 689 return EPERM; 690 691 case NFSERR_NOENT: 692 return ENOENT; 693 694 case NFSERR_IO: 695 return EIO; 696 697 case NFSERR_NXIO: 698 return ENXIO; 699 700 case NFSERR_ACCES: 701 return EACCES; 702 703 case NFSERR_EXIST: 704 return EEXIST; 705 706 case NFSERR_NODEV: 707 return ENODEV; 708 709 case NFSERR_NOTDIR: 710 return ENOTDIR; 711 712 case NFSERR_ISDIR: 713 return EISDIR; 714 715 case NFSERR_FBIG: 716 return EFBIG; 717 718 case NFSERR_NOSPC: 719 return ENOSPC; 720 721 case NFSERR_ROFS: 722 return EROFS; 723 724 case NFSERR_NAMETOOLONG: 725 return ENAMETOOLONG; 726 727 case NFSERR_NOTEMPTY: 728 return ENOTEMPTY; 729 730 case NFSERR_STALE: 731 return C_ERROR_STALE; 732 733 default: 734 return B_ERROR; 735 } 736 } 737 738 739 nfs_fhandle 740 handle_from_vnid(fs_nspace *ns, ino_t vnid) 741 { 742 fs_node *current; 743 744 while (acquire_sem(ns->sem) == B_INTERRUPTED); 745 746 current = ns->first; 747 748 while (current != NULL && current->vnid != vnid) 749 current = current->next; 750 751 while (release_sem(ns->sem) == B_INTERRUPTED); 752 753 return current->fhandle; 754 } 755 756 757 void 758 insert_node(fs_nspace *ns, fs_node *node) 759 { 760 fs_node *current; 761 762 while (acquire_sem(ns->sem) == B_INTERRUPTED); 763 764 current = ns->first; 765 766 while (current != NULL && current->vnid != node->vnid) 767 current = current->next; 768 769 if (current) { 770 free(node); 771 while (release_sem(ns->sem) == B_INTERRUPTED); 772 return; 773 } 774 775 node->next = ns->first; 776 ns->first = node; 777 778 while (release_sem (ns->sem) == B_INTERRUPTED); 779 } 780 781 782 void 783 remove_node(fs_nspace *ns, ino_t vnid) 784 { 785 fs_node *current; 786 fs_node *previous; 787 788 while (acquire_sem(ns->sem) == B_INTERRUPTED); 789 790 current = ns->first; 791 previous = NULL; 792 793 while (current != NULL && current->vnid != vnid) { 794 previous = current; 795 current = current->next; 796 } 797 798 if (current) { 799 if (previous) 800 previous->next = current->next; 801 else 802 ns->first = current->next; 803 804 free(current); 805 } 806 807 while (release_sem(ns->sem) == B_INTERRUPTED); 808 } 809 810 811 // #pragma mark - 812 813 814 static status_t 815 fs_read_vnode(fs_volume *_volume, ino_t vnid, fs_vnode *_node, int *_type, 816 uint32 *_flags, bool r) 817 { 818 fs_nspace *ns; 819 fs_node *current; 820 821 ns = _volume->private_volume; 822 823 if (!r) { 824 while (acquire_sem(ns->sem) == B_INTERRUPTED); 825 } 826 827 current = ns->first; 828 829 while (current != NULL && current->vnid != vnid) 830 current = current->next; 831 832 if (!current) 833 return EINVAL; 834 835 current->vnid = vnid; 836 _node->private_node = current; 837 _node->ops = &sNFSVnodeOps; 838 *_type = current->mode; 839 *_flags = 0; 840 841 if (!r) { 842 while (release_sem(ns->sem) == B_INTERRUPTED); 843 } 844 845 return B_OK; 846 } 847 848 849 static status_t 850 fs_release_vnode(fs_volume *_volume, fs_vnode *node, bool r) 851 { 852 (void) _volume; 853 (void) node; 854 (void) r; 855 return B_OK; 856 } 857 858 859 static status_t 860 fs_walk(fs_volume *_volume, fs_vnode *_base, const char *file, ino_t *vnid) 861 { 862 fs_node *dummy; 863 status_t result; 864 fs_nspace *ns; 865 fs_node *base; 866 //dprintf("nfs: walk(%s)\n", file);//XXX:mmu_man:debug 867 868 ns = _volume->private_volume; 869 base = _base->private_node; 870 871 if (!strcmp(".", file)) 872 *vnid = base->vnid; 873 else { 874 fs_node *newNode = (fs_node *)malloc(sizeof(fs_node)); 875 struct stat st; 876 877 if ((result = nfs_lookup(ns, &base->fhandle, file, &newNode->fhandle, 878 &st)) < B_OK) { 879 free(newNode); 880 return result; 881 } 882 883 newNode->vnid = st.st_ino; 884 newNode->mode = st.st_mode; 885 *vnid = newNode->vnid; 886 887 insert_node(ns, newNode); 888 } 889 890 if ((result = get_vnode (_volume, *vnid, (void **)&dummy)) < B_OK) 891 return result; 892 893 return B_OK; 894 } 895 896 897 static status_t 898 fs_opendir(fs_volume *_volume, fs_vnode *_node, void **_cookie) 899 { 900 fs_nspace *ns; 901 fs_node *node; 902 nfs_cookie **cookie; 903 904 struct stat st; 905 status_t result; 906 907 ns = _volume->private_volume; 908 node = _node->private_node; 909 cookie = (nfs_cookie **)_cookie; 910 911 if ((result = nfs_getattr(ns, &node->fhandle, &st)) < B_OK) 912 return result; 913 914 if (!S_ISDIR(st.st_mode)) 915 return ENOTDIR; 916 917 *cookie = (nfs_cookie *)malloc(sizeof(nfs_cookie)); 918 memset((*cookie)->opaque,0,NFS_COOKIESIZE); 919 920 return B_OK; 921 } 922 923 924 static status_t 925 fs_closedir(fs_volume *_volume, fs_vnode *_node, void *cookie) 926 { 927 (void) _volume; 928 (void) _node; 929 (void) cookie; 930 return B_OK; 931 } 932 933 934 static status_t 935 fs_rewinddir(fs_volume *_volume, fs_vnode *_node, void *_cookie) 936 { 937 nfs_cookie *cookie = (nfs_cookie *)_cookie; 938 (void) _volume; 939 (void) _node; 940 memset (cookie->opaque, 0, NFS_COOKIESIZE); 941 942 return B_OK; 943 } 944 945 946 static status_t 947 fs_readdir(fs_volume *_volume, fs_vnode *_node, void *_cookie, 948 struct dirent *buf, size_t bufsize, uint32 *num) 949 { 950 nfs_cookie *cookie = (nfs_cookie *)_cookie; 951 int32 max = *num; 952 int32 eof; 953 954 fs_nspace *ns; 955 fs_node *node; 956 957 size_t count = min_c(6000, max * 300); 958 959 *num = 0; 960 961 ns = _volume->private_volume; 962 node = _node->private_node; 963 964 do { 965 ino_t vnid; 966 char *filename; 967 uint8 *replyBuf; 968 struct XDROutPacket call; 969 struct XDRInPacket reply; 970 int32 status; 971 972 XDROutPacketInit(&call); 973 XDRInPacketInit(&reply); 974 975 XDROutPacketAddFixed(&call, node->fhandle.opaque, NFS_FHSIZE); 976 XDROutPacketAddFixed(&call, cookie->opaque, NFS_COOKIESIZE); 977 XDROutPacketAddInt32(&call, count); 978 979 replyBuf = send_rpc_call (ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 980 NFSPROC_READDIR, &call); 981 982 if (!replyBuf) { 983 XDRInPacketDestroy(&reply); 984 XDROutPacketDestroy(&call); 985 return B_ERROR; 986 } 987 988 XDRInPacketSetTo(&reply, replyBuf, 0); 989 990 if (!is_successful_reply(&reply)) { 991 XDRInPacketDestroy(&reply); 992 XDROutPacketDestroy(&call); 993 return B_ERROR; 994 } 995 996 status = XDRInPacketGetInt32(&reply); 997 998 if (status != NFS_OK) { 999 XDRInPacketDestroy(&reply); 1000 XDROutPacketDestroy(&call); 1001 return map_nfs_to_system_error(status); 1002 } 1003 1004 while (XDRInPacketGetInt32(&reply) == 1) { 1005 nfs_cookie newCookie; 1006 1007 vnid=XDRInPacketGetInt32(&reply); 1008 filename=XDRInPacketGetString(&reply); 1009 1010 XDRInPacketGetFixed(&reply, newCookie.opaque, NFS_COOKIESIZE); 1011 1012 //if (strcmp(".",filename)&&strcmp("..",filename)) 1013 //if ((ns->rootid != node->vnid) || (strcmp(".",filename)&&strcmp("..",filename))) 1014 if (conf_ls_root_parent 1015 || ((ns->rootid != node->vnid) || strcmp("..", filename))) { 1016 status_t result; 1017 struct stat st; 1018 1019 fs_node *newNode = (fs_node *)malloc(sizeof(fs_node)); 1020 newNode->vnid = vnid; 1021 1022 if ((result = nfs_lookup(ns, &node->fhandle, filename, 1023 &newNode->fhandle, &st)) < B_OK) { 1024 free (filename); 1025 free(newNode); 1026 XDRInPacketDestroy (&reply); 1027 XDROutPacketDestroy (&call); 1028 return result; 1029 } 1030 1031 newNode->mode = st.st_mode; 1032 insert_node(ns,newNode); 1033 1034 if (bufsize < 2 * (sizeof(dev_t) + sizeof(ino_t)) 1035 + sizeof(unsigned short) + strlen(filename) + 1) { 1036 XDRInPacketDestroy(&reply); 1037 XDROutPacketDestroy(&call); 1038 return B_OK; 1039 } 1040 1041 buf->d_dev = ns->nsid; 1042 buf->d_pdev = ns->nsid; 1043 buf->d_ino = vnid; 1044 buf->d_pino = node->vnid; 1045 buf->d_reclen = 2 * (sizeof(dev_t) + sizeof(ino_t)) 1046 + sizeof(unsigned short) + strlen(filename) + 1; 1047 strcpy (buf->d_name,filename); 1048 // if ((ns->rootid == node->vnid))//XXX:mmu_man:test 1049 // dprintf("nfs: dirent %d {d:%ld pd:%ld i:%lld pi:%lld '%s'}\n", *num, buf->d_dev, buf->d_pdev, buf->d_ino, buf->d_pino, buf->d_name); 1050 1051 bufsize -= buf->d_reclen; 1052 buf = (struct dirent *)((char *)buf + buf->d_reclen); 1053 1054 memcpy(cookie->opaque, newCookie.opaque, NFS_COOKIESIZE); 1055 1056 (*num)++; 1057 } else { 1058 memcpy(cookie->opaque, newCookie.opaque, NFS_COOKIESIZE); 1059 } 1060 1061 free (filename); 1062 1063 if ((*num) == max) { 1064 XDRInPacketDestroy(&reply); 1065 XDROutPacketDestroy(&call); 1066 return B_OK; 1067 } 1068 } 1069 1070 eof=XDRInPacketGetInt32(&reply); 1071 1072 XDRInPacketDestroy (&reply); 1073 XDROutPacketDestroy (&call); 1074 } 1075 while (eof == 0); 1076 1077 return B_OK; 1078 } 1079 1080 1081 static status_t 1082 fs_free_dircookie(fs_volume *_volume, fs_vnode *_node, void *cookie) 1083 { 1084 (void) _volume; 1085 (void) _node; 1086 free(cookie); 1087 return B_OK; 1088 } 1089 1090 1091 static status_t 1092 fs_rstat(fs_volume *_volume, fs_vnode *_node, struct stat *st) 1093 { 1094 fs_nspace *ns; 1095 fs_node *node; 1096 status_t result; 1097 1098 ns = _volume->private_volume; 1099 node = _node->private_node; 1100 1101 //dprintf("nfs: rstat()\n");//XXX:mmu_man:debug 1102 if ((result = nfs_getattr(ns, &node->fhandle, st)) < B_OK) 1103 return result; 1104 1105 st->st_dev = ns->nsid; 1106 //st->st_nlink = 1; //XXX:mmu_man:test 1107 return B_OK; 1108 } 1109 1110 1111 void 1112 fs_nspaceInit(struct fs_nspace *nspace) 1113 { 1114 RPCPendingCallsInit(&nspace->pendingCalls); 1115 } 1116 1117 1118 void 1119 fs_nspaceDestroy(struct fs_nspace *nspace) 1120 { 1121 RPCPendingCallsDestroy(&nspace->pendingCalls); 1122 } 1123 1124 1125 static status_t 1126 parse_nfs_params(const char *str, struct mount_nfs_params *params) 1127 { 1128 const char *p, *e; 1129 long v; 1130 int i; 1131 // sprintf(buf, "nfs:%s:%s,uid=%u,gid=%u,hostname=%s", 1132 if (!str || !params) 1133 return EINVAL; 1134 if (strncmp(str, "nfs:", 4)) 1135 return EINVAL; 1136 dprintf("nfs:ip!\n"); 1137 p = str + 4; 1138 e = strchr(p, ':'); 1139 if (!e) 1140 return EINVAL; 1141 params->server = malloc(e - p + 1); 1142 params->server[e - p] = '\0'; 1143 strncpy(params->server, p, e - p); 1144 // hack 1145 params->serverIP = 0; 1146 v = strtol(p, (char **)&p, 10); 1147 dprintf("IP:%ld.", v); 1148 if (!p) 1149 return EINVAL; 1150 params->serverIP |= (v << 24); 1151 p++; 1152 v = strtol(p, (char **)&p, 10); 1153 dprintf("%ld.", v); 1154 if (!p) 1155 return EINVAL; 1156 params->serverIP |= (v << 16); 1157 p++; 1158 v = strtol(p, (char **)&p, 10); 1159 dprintf("%ld.", v); 1160 if (!p) 1161 return EINVAL; 1162 params->serverIP |= (v << 8); 1163 p++; 1164 v = strtol(p, (char **)&p, 10); 1165 dprintf("%ld\n", v); 1166 if (!p) 1167 return EINVAL; 1168 params->serverIP |= (v); 1169 if (*p++ != ':') 1170 return EINVAL; 1171 1172 e = strchr(p, ','); 1173 i = (e) ? (e - p) : (strlen(p)); 1174 1175 params->_export = malloc(i + 1); 1176 params->_export[i] = '\0'; 1177 strncpy(params->_export, p, i); 1178 1179 p = strstr(str, "hostname="); 1180 if (!p) 1181 return EINVAL; 1182 dprintf("nfs:hn!\n"); 1183 p += 9; 1184 e = strchr(p, ','); 1185 i = (e) ? (e - p) : (strlen(p)); 1186 1187 params->hostname = malloc(i + 1); 1188 params->hostname[i] = '\0'; 1189 strncpy(params->hostname, p, i); 1190 1191 p = strstr(str, "uid="); 1192 dprintf("nfs:uid!\n"); 1193 if (p) { 1194 p += 4; 1195 v = strtol(p, (char **)&p, 10); 1196 params->uid = v; 1197 } 1198 dprintf("nfs:gid!\n"); 1199 p = strstr(str, "gid="); 1200 if (p) { 1201 p += 4; 1202 v = strtol(p, (char **)&p, 10); 1203 params->gid = v; 1204 } 1205 dprintf("nfs: ip:%08x server:'%s' export:'%s' hostname:'%s' uid=%d gid=%d \n", 1206 params->serverIP, params->server, params->_export, 1207 params->hostname, params->uid, params->gid); 1208 return B_OK; 1209 } 1210 1211 1212 static status_t 1213 fs_mount(fs_volume *_vol, const char *devname, uint32 flags, const char *_parms, ino_t *vnid) 1214 { 1215 status_t result; 1216 fs_nspace *ns; 1217 fs_node *rootNode; 1218 struct stat st; 1219 1220 if (_parms == NULL) 1221 return EINVAL; 1222 1223 dprintf("nfs: mount(%" B_PRId32 ", %s, %08" B_PRIx32 ")\n", _vol->id, 1224 devname, flags); 1225 dprintf("nfs: nfs_params: %s\n", _parms); 1226 1227 // HAIKU: this should go to std_ops 1228 if (!refcount) 1229 read_config(); 1230 1231 1232 result = ENOMEM; 1233 ns = (fs_nspace *)malloc(sizeof(fs_nspace)); 1234 if (!ns) 1235 goto err_nspace; 1236 fs_nspaceInit(ns); 1237 1238 ns->nsid = _vol->id; 1239 1240 ns->params.server = NULL; 1241 ns->params._export = NULL; 1242 ns->params.hostname = NULL; 1243 if ((result = parse_nfs_params(_parms, &ns->params)) < 0) 1244 goto err_params; 1245 ns->xid = 0; 1246 ns->mountAddr.sin_family = AF_INET; 1247 ns->mountAddr.sin_addr.s_addr = htonl(ns->params.serverIP); 1248 memset(ns->mountAddr.sin_zero, 0, sizeof(ns->mountAddr.sin_zero)); 1249 1250 if ((result = create_socket(ns)) < B_OK) { 1251 dprintf("nfs: could not create socket (%" B_PRId32 ")\n", result); 1252 goto err_socket; 1253 } 1254 1255 if ((result = init_postoffice(ns)) < B_OK) { 1256 dprintf("nfs: could not init_postoffice() (%" B_PRId32 ")\n", result); 1257 goto err_postoffice; 1258 } 1259 1260 if ((result = get_remote_address(ns, MOUNT_PROGRAM, MOUNT_VERSION, 1261 PMAP_IPPROTO_UDP, &ns->mountAddr)) < B_OK) { 1262 dprintf("could not get_remote_address() (%" B_PRId32 ")\n", result); 1263 goto err_sem; 1264 } 1265 1266 memcpy(&ns->nfsAddr, &ns->mountAddr, sizeof(ns->mountAddr)); 1267 dprintf("nfs: mountd at %08x:%d\n", ns->mountAddr.sin_addr.s_addr, ntohs(ns->mountAddr.sin_port)); 1268 1269 if ((result = get_remote_address(ns, NFS_PROGRAM, NFS_VERSION, 1270 PMAP_IPPROTO_UDP, &ns->nfsAddr)) < B_OK) 1271 goto err_sem; 1272 dprintf("nfs: nfsd at %08x:%d\n", ns->nfsAddr.sin_addr.s_addr, ntohs(ns->nfsAddr.sin_port)); 1273 // result = connect_socket(ns); 1274 //dprintf("nfs: connect: %s\n", strerror(result)); 1275 1276 if ((result = create_sem(1, "nfs_sem")) < B_OK) 1277 goto err_sem; 1278 1279 ns->sem = result; 1280 1281 set_sem_owner(ns->sem, B_SYSTEM_TEAM); 1282 1283 result = ENOMEM; 1284 rootNode = (fs_node *)malloc(sizeof(fs_node)); 1285 if (!rootNode) 1286 goto err_rootvn; 1287 rootNode->next = NULL; 1288 1289 if ((result = nfs_mount(ns, ns->params._export, &rootNode->fhandle)) < B_OK) 1290 goto err_mount; 1291 1292 if ((result = nfs_getattr(ns, &rootNode->fhandle, &st)) < B_OK) 1293 goto err_publish; 1294 1295 ns->rootid = st.st_ino; 1296 rootNode->vnid = ns->rootid; 1297 1298 *vnid = ns->rootid; 1299 1300 _vol->private_volume = ns; 1301 _vol->ops = &sNFSVolumeOps; 1302 1303 // TODO: set right mode 1304 if ((result = publish_vnode(_vol, *vnid, rootNode, &sNFSVnodeOps, 1305 S_IFDIR, 0)) < B_OK) 1306 goto err_publish; 1307 1308 ns->first = rootNode; 1309 1310 return B_OK; 1311 1312 err_publish: 1313 // XXX: unmount ?? 1314 err_mount: 1315 free(rootNode); 1316 err_rootvn: 1317 delete_sem (ns->sem); 1318 err_sem: 1319 shutdown_postoffice(ns); 1320 goto err_socket; 1321 err_postoffice: 1322 close(ns->s); 1323 err_socket: 1324 err_params: 1325 free(ns->params.hostname); 1326 free(ns->params._export); 1327 free(ns->params.server); 1328 1329 fs_nspaceDestroy(ns); 1330 free(ns); 1331 err_nspace: 1332 1333 if (result >= 0) { 1334 dprintf("nfs:bad error from mount!\n"); 1335 result = EINVAL; 1336 } 1337 dprintf("nfs: error in nfs_mount: %s\n", strerror(result)); 1338 return result; 1339 } 1340 1341 1342 static status_t 1343 fs_unmount(fs_volume *_volume) 1344 { 1345 fs_nspace *ns = (fs_nspace *)_volume->private_volume; 1346 free(ns->params.hostname); 1347 free(ns->params._export); 1348 free(ns->params.server); 1349 1350 while (ns->first) { 1351 fs_node *next = ns->first->next; 1352 free(ns->first); 1353 ns->first = next; 1354 } 1355 1356 // We need to put the reference to our root node ourselves 1357 put_vnode(_volume, ns->rootid); 1358 1359 delete_sem(ns->sem); 1360 shutdown_postoffice(ns); 1361 fs_nspaceDestroy(ns); 1362 free(ns); 1363 return B_OK; 1364 } 1365 1366 1367 static status_t 1368 fs_rfsstat(fs_volume *_volume, struct fs_info *info) 1369 { 1370 fs_nspace *ns; 1371 struct XDROutPacket call; 1372 struct XDRInPacket reply; 1373 nfs_fhandle rootHandle; 1374 uint8 *replyBuf; 1375 int32 status; 1376 1377 ns = (fs_nspace *)_volume->private_volume; 1378 1379 rootHandle = handle_from_vnid (ns,ns->rootid); 1380 //dprintf("nfs: rfsstat()\n");//XXX:mmu_man:debug 1381 1382 XDROutPacketInit(&call); 1383 XDRInPacketInit(&reply); 1384 1385 XDROutPacketAddFixed(&call, rootHandle.opaque, NFS_FHSIZE); 1386 1387 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 1388 NFSPROC_STATFS, &call); 1389 if (replyBuf == NULL) { 1390 XDRInPacketDestroy(&reply); 1391 XDROutPacketDestroy(&call); 1392 return EHOSTUNREACH; 1393 } 1394 1395 XDRInPacketSetTo(&reply, replyBuf, 0); 1396 1397 if (!is_successful_reply(&reply)) { 1398 XDRInPacketDestroy(&reply); 1399 XDROutPacketDestroy(&call); 1400 return B_ERROR; 1401 } 1402 1403 status = XDRInPacketGetInt32(&reply); 1404 if (status != NFS_OK) { 1405 XDRInPacketDestroy(&reply); 1406 XDROutPacketDestroy(&call); 1407 //dprintf("nfs: rfsstat() error 0x%08lx\n", map_nfs_to_system_error(status)); 1408 return map_nfs_to_system_error(status); 1409 } 1410 1411 info->dev = ns->nsid; 1412 info->root = ns->rootid; 1413 info->flags = NFS_FS_FLAGS; 1414 1415 XDRInPacketGetInt32(&reply); // tsize 1416 1417 info->block_size = XDRInPacketGetInt32(&reply); 1418 info->io_size = 8192; 1419 info->total_blocks = XDRInPacketGetInt32(&reply); 1420 info->free_blocks = XDRInPacketGetInt32(&reply); 1421 info->total_nodes = 100; 1422 info->free_nodes = 100; 1423 strcpy(info->volume_name, "nfs://"); 1424 strcat(info->volume_name, ns->params.server); 1425 strcat(info->volume_name, ns->params._export); 1426 strcpy(info->fsh_name, "nfs"); 1427 1428 XDRInPacketDestroy(&reply); 1429 XDROutPacketDestroy(&call); 1430 return B_OK; 1431 } 1432 1433 1434 static status_t 1435 fs_open(fs_volume *_volume, fs_vnode *_node, int omode, void **_cookie) 1436 { 1437 fs_nspace *ns; 1438 fs_node *node; 1439 struct stat st; 1440 status_t result; 1441 fs_file_cookie **cookie; 1442 1443 ns = _volume->private_volume; 1444 node = _node->private_node; 1445 cookie = (fs_file_cookie **)_cookie; 1446 1447 if ((result = nfs_getattr(ns, &node->fhandle, &st)) < B_OK) 1448 return result; 1449 1450 if (S_ISDIR(st.st_mode)) { 1451 /* permit opening of directories */ 1452 if (conf_allow_dir_open) { 1453 *cookie = NULL; 1454 return B_OK; 1455 } else 1456 return EISDIR; 1457 } 1458 1459 *cookie = (fs_file_cookie *)malloc(sizeof(fs_file_cookie)); 1460 (*cookie)->omode = omode; 1461 (*cookie)->original_size = st.st_size; 1462 (*cookie)->st = st; 1463 1464 return B_OK; 1465 } 1466 1467 1468 static status_t 1469 fs_close(fs_volume *_volume, fs_vnode *_node, void *cookie) 1470 { 1471 (void) _volume; 1472 (void) _node; 1473 (void) cookie; 1474 /* //XXX:mmu_man:why that ?? makes Tracker go nuts updating the stats 1475 if ((cookie->omode & O_RDWR)||(cookie->omode & O_WRONLY)) 1476 return my_notify_listener (B_STAT_CHANGED,ns->nsid,0,0,node->vnid,NULL); 1477 */ 1478 return B_OK; 1479 } 1480 1481 1482 static status_t 1483 fs_free_cookie(fs_volume *_volume, fs_vnode *_node, void *cookie) 1484 { 1485 (void) _volume; 1486 (void) _node; 1487 free(cookie); 1488 return B_OK; 1489 } 1490 1491 1492 static status_t 1493 fs_read(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos, 1494 void *buf, size_t *len) 1495 { 1496 fs_nspace *ns; 1497 fs_node *node; 1498 fs_file_cookie *cookie; 1499 size_t max = *len; 1500 *len = 0; 1501 1502 ns = _volume->private_volume; 1503 node = _node->private_node; 1504 cookie = (fs_file_cookie *)_cookie; 1505 1506 if (!cookie) 1507 return EISDIR; /* do not permit reading of directories */ 1508 1509 while ((*len) < max) { 1510 size_t count = min_c(NFS_MAXDATA, max - (*len)); 1511 struct XDROutPacket call; 1512 struct XDRInPacket reply; 1513 int32 status; 1514 uint8 *replyBuf; 1515 struct stat st; 1516 size_t readbytes; 1517 1518 XDROutPacketInit(&call); 1519 XDRInPacketInit(&reply); 1520 1521 XDROutPacketAddFixed(&call, &node->fhandle.opaque, NFS_FHSIZE); 1522 XDROutPacketAddInt32(&call, pos); 1523 XDROutPacketAddInt32(&call, count); 1524 XDROutPacketAddInt32(&call, 0); 1525 1526 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 1527 NFSPROC_READ, &call); 1528 if (replyBuf == NULL) { 1529 XDRInPacketDestroy(&reply); 1530 XDROutPacketDestroy(&call); 1531 return B_ERROR; 1532 } 1533 1534 XDRInPacketSetTo(&reply, replyBuf, 0); 1535 1536 if (!is_successful_reply(&reply)) { 1537 XDRInPacketDestroy(&reply); 1538 XDROutPacketDestroy(&call); 1539 return B_ERROR; 1540 } 1541 1542 status = XDRInPacketGetInt32(&reply); 1543 if (status != NFS_OK) { 1544 XDRInPacketDestroy(&reply); 1545 XDROutPacketDestroy(&call); 1546 return map_nfs_to_system_error(status); 1547 } 1548 1549 get_nfs_attr(&reply, &st); 1550 cookie->st = st; 1551 1552 readbytes = XDRInPacketGetDynamic(&reply, buf); 1553 1554 buf = (char *)buf + readbytes; 1555 (*len) += readbytes; 1556 pos += readbytes; 1557 1558 XDRInPacketDestroy(&reply); 1559 XDROutPacketDestroy(&call); 1560 1561 if (pos >= st.st_size) 1562 break; 1563 } 1564 1565 return B_OK; 1566 } 1567 1568 1569 static status_t 1570 fs_write(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos, 1571 const void *buf, size_t *len) 1572 { 1573 fs_nspace *ns; 1574 fs_node *node; 1575 fs_file_cookie *cookie; 1576 size_t bytesWritten = 0; 1577 1578 ns = _volume->private_volume; 1579 node = _node->private_node; 1580 cookie = (fs_file_cookie *)_cookie; 1581 1582 if (!cookie) 1583 return EISDIR; /* do not permit reading of directories */ 1584 if (cookie->omode & O_APPEND) 1585 pos += cookie->original_size; 1586 1587 while (bytesWritten < *len) { 1588 size_t count = min_c(NFS_MAXDATA,(*len) - bytesWritten); 1589 1590 struct XDROutPacket call; 1591 struct XDRInPacket reply; 1592 int32 status; 1593 uint8 *replyBuf; 1594 struct stat st; 1595 1596 XDROutPacketInit(&call); 1597 XDRInPacketInit(&reply); 1598 1599 XDROutPacketAddFixed(&call, &node->fhandle.opaque, NFS_FHSIZE); 1600 XDROutPacketAddInt32(&call, 0); 1601 XDROutPacketAddInt32(&call, pos + bytesWritten); 1602 XDROutPacketAddInt32(&call, 0); 1603 XDROutPacketAddDynamic(&call, (const char *)buf + bytesWritten, count); 1604 1605 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 1606 NFSPROC_WRITE, &call); 1607 1608 if (!replyBuf) { 1609 XDRInPacketDestroy(&reply); 1610 XDROutPacketDestroy(&call); 1611 return B_ERROR; 1612 } 1613 1614 XDRInPacketSetTo(&reply, replyBuf, 0); 1615 1616 if (!is_successful_reply(&reply)) { 1617 XDRInPacketDestroy(&reply); 1618 XDROutPacketDestroy(&call); 1619 return B_ERROR; 1620 } 1621 1622 status = XDRInPacketGetInt32(&reply); 1623 1624 if (status != NFS_OK) { 1625 XDRInPacketDestroy(&reply); 1626 XDROutPacketDestroy(&call); 1627 return map_nfs_to_system_error(status); 1628 } 1629 1630 get_nfs_attr(&reply, &st); 1631 1632 cookie->st = st; 1633 1634 bytesWritten += count; 1635 1636 XDRInPacketDestroy(&reply); 1637 XDROutPacketDestroy(&call); 1638 } 1639 1640 return B_OK; 1641 } 1642 1643 1644 static status_t 1645 fs_wstat(fs_volume *_volume, fs_vnode *_node, const struct stat *st, uint32 mask) 1646 { 1647 fs_nspace *ns; 1648 fs_node *node; 1649 struct XDROutPacket call; 1650 struct XDRInPacket reply; 1651 1652 uint8 *replyBuf; 1653 int32 status; 1654 1655 ns = _volume->private_volume; 1656 node = _node->private_node; 1657 1658 XDROutPacketInit(&call); 1659 XDRInPacketInit(&reply); 1660 1661 XDROutPacketAddFixed(&call,node->fhandle.opaque,NFS_FHSIZE); 1662 1663 XDROutPacketAddInt32(&call, (mask & WSTAT_MODE) ? st->st_mode : -1); 1664 XDROutPacketAddInt32(&call, (mask & WSTAT_UID) ? st->st_uid : -1); 1665 XDROutPacketAddInt32(&call, (mask & WSTAT_GID) ? st->st_gid : -1); 1666 XDROutPacketAddInt32(&call, (mask & WSTAT_SIZE) ? st->st_size : -1); 1667 XDROutPacketAddInt32(&call, (mask & WSTAT_ATIME) ? st->st_atime : -1); 1668 XDROutPacketAddInt32(&call, (mask & WSTAT_ATIME) ? 0 : -1); 1669 XDROutPacketAddInt32(&call, (mask & WSTAT_MTIME) ? st->st_mtime : -1); 1670 XDROutPacketAddInt32(&call, (mask & WSTAT_MTIME) ? 0 : -1); 1671 1672 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 1673 NFSPROC_SETATTR, &call); 1674 1675 if (!replyBuf) { 1676 XDRInPacketDestroy(&reply); 1677 XDROutPacketDestroy(&call); 1678 return EHOSTUNREACH; 1679 } 1680 1681 XDRInPacketSetTo(&reply, replyBuf, 0); 1682 1683 if (!is_successful_reply(&reply)) { 1684 XDRInPacketDestroy(&reply); 1685 XDROutPacketDestroy(&call); 1686 return B_ERROR; 1687 } 1688 1689 status = XDRInPacketGetInt32(&reply); 1690 1691 if (status != NFS_OK) 1692 return map_nfs_to_system_error(status); 1693 1694 XDRInPacketDestroy(&reply); 1695 XDROutPacketDestroy(&call); 1696 1697 return notify_stat_changed(_volume->id, node->vnid, mask); 1698 } 1699 1700 static status_t 1701 fs_wfsstat(fs_volume *_volume, const struct fs_info *info, uint32 mask) 1702 { 1703 (void) _volume; 1704 (void) info; 1705 (void) mask; 1706 return B_OK; 1707 } 1708 1709 static status_t 1710 fs_create(fs_volume *_volume, fs_vnode *_dir, const char *name, int omode, 1711 int perms, void **_cookie, ino_t *vnid) 1712 { 1713 nfs_fhandle fhandle; 1714 struct stat st; 1715 fs_file_cookie **cookie; 1716 1717 fs_nspace *ns; 1718 fs_node *dir; 1719 1720 status_t result; 1721 1722 ns = _volume->private_volume; 1723 dir = _dir->private_node; 1724 cookie = (fs_file_cookie **)_cookie; 1725 1726 result = nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st); 1727 1728 if (result == B_OK) { 1729 void *dummy; 1730 fs_node *newNode = (fs_node *)malloc(sizeof(fs_node)); 1731 if (newNode == NULL) 1732 return B_NO_MEMORY; 1733 1734 newNode->fhandle = fhandle; 1735 newNode->vnid = st.st_ino; 1736 newNode->mode = st.st_mode; 1737 insert_node(ns, newNode); 1738 1739 *vnid = st.st_ino; 1740 1741 if ((result = get_vnode(_volume,*vnid,&dummy)) < B_OK) 1742 return result; 1743 1744 if (S_ISDIR(st.st_mode)) 1745 return EISDIR; 1746 1747 if (omode & O_EXCL) 1748 return EEXIST; 1749 1750 if (omode & O_TRUNC) 1751 { 1752 if ((result = nfs_truncate_file(ns, &fhandle, NULL)) < B_OK) 1753 return result; 1754 } 1755 1756 *cookie=(fs_file_cookie *)malloc(sizeof(fs_file_cookie)); 1757 if (*cookie == NULL) 1758 return B_NO_MEMORY; 1759 1760 (*cookie)->omode=omode; 1761 (*cookie)->original_size=st.st_size; 1762 (*cookie)->st=st; 1763 1764 return B_OK; 1765 } else if (result != ENOENT) { 1766 return result; 1767 } else { 1768 struct XDROutPacket call; 1769 struct XDRInPacket reply; 1770 1771 uint8 *replyBuf; 1772 int32 status; 1773 1774 fs_node *newNode; 1775 1776 if (!(omode & O_CREAT)) 1777 return ENOENT; 1778 1779 XDROutPacketInit(&call); 1780 XDRInPacketInit(&reply); 1781 1782 XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE); 1783 XDROutPacketAddString(&call, name); 1784 XDROutPacketAddInt32(&call, perms | S_IFREG); 1785 XDROutPacketAddInt32(&call, -1); 1786 XDROutPacketAddInt32(&call, -1); 1787 XDROutPacketAddInt32(&call, 0); 1788 XDROutPacketAddInt32(&call, time(NULL)); 1789 XDROutPacketAddInt32(&call, 0); 1790 XDROutPacketAddInt32(&call, time(NULL)); 1791 XDROutPacketAddInt32(&call, 0); 1792 1793 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 1794 NFSPROC_CREATE, &call); 1795 1796 if (!replyBuf) { 1797 XDRInPacketDestroy(&reply); 1798 XDROutPacketDestroy(&call); 1799 return B_ERROR; 1800 } 1801 1802 XDRInPacketSetTo(&reply, replyBuf, 0); 1803 1804 if (!is_successful_reply(&reply)) { 1805 XDRInPacketDestroy(&reply); 1806 XDROutPacketDestroy(&call); 1807 return B_ERROR; 1808 } 1809 1810 status = XDRInPacketGetInt32(&reply); 1811 1812 if (status != NFS_OK) { 1813 XDRInPacketDestroy(&reply); 1814 XDROutPacketDestroy(&call); 1815 return map_nfs_to_system_error(status); 1816 } 1817 1818 XDRInPacketGetFixed(&reply, fhandle.opaque, NFS_FHSIZE); 1819 1820 get_nfs_attr(&reply,&st); 1821 1822 newNode = (fs_node *)malloc(sizeof(fs_node)); 1823 if (newNode == NULL) { 1824 XDRInPacketDestroy(&reply); 1825 XDROutPacketDestroy(&call); 1826 return B_NO_MEMORY; 1827 } 1828 newNode->fhandle = fhandle; 1829 newNode->vnid = st.st_ino; 1830 newNode->mode = st.st_mode; 1831 1832 insert_node (ns, newNode); 1833 1834 *vnid = st.st_ino; 1835 *cookie = (fs_file_cookie *)malloc(sizeof(fs_file_cookie)); 1836 if (*cookie == NULL) { 1837 XDRInPacketDestroy(&reply); 1838 XDROutPacketDestroy(&call); 1839 return B_NO_MEMORY; 1840 } 1841 (*cookie)->omode = omode; 1842 (*cookie)->original_size = st.st_size; 1843 (*cookie)->st = st; 1844 1845 result = new_vnode(_volume, *vnid, newNode, &sNFSVnodeOps); 1846 1847 if (result < B_OK) { 1848 XDRInPacketDestroy(&reply); 1849 XDROutPacketDestroy(&call); 1850 return result; 1851 } 1852 1853 XDRInPacketDestroy(&reply); 1854 XDROutPacketDestroy(&call); 1855 return notify_entry_created(_volume->id, dir->vnid, name, *vnid); 1856 } 1857 } 1858 1859 1860 static status_t 1861 fs_unlink(fs_volume *_volume, fs_vnode *_dir, const char *name) 1862 { 1863 status_t result; 1864 fs_nspace *ns; 1865 fs_node *dir; 1866 fs_node *newNode; 1867 fs_node *dummy; 1868 1869 struct XDROutPacket call; 1870 struct XDRInPacket reply; 1871 1872 struct stat st; 1873 nfs_fhandle fhandle; 1874 uint8 *replyBuf; 1875 1876 int32 status; 1877 1878 ns = _volume->private_volume; 1879 dir = _dir->private_node; 1880 1881 XDROutPacketInit(&call); 1882 XDRInPacketInit(&reply); 1883 1884 if ((result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st)) < B_OK) { 1885 XDRInPacketDestroy(&reply); 1886 XDROutPacketDestroy(&call); 1887 return result; 1888 } 1889 1890 newNode = (fs_node *)malloc(sizeof(fs_node)); 1891 if (newNode == NULL) { 1892 XDRInPacketDestroy(&reply); 1893 XDROutPacketDestroy(&call); 1894 return B_NO_MEMORY; 1895 } 1896 newNode->fhandle = fhandle; 1897 newNode->vnid = st.st_ino; 1898 newNode->mode = st.st_mode; 1899 1900 insert_node(ns, newNode); 1901 1902 if ((result = get_vnode(_volume, st.st_ino, (void **)&dummy)) < B_OK) { 1903 XDRInPacketDestroy(&reply); 1904 XDROutPacketDestroy(&call); 1905 return result; 1906 } 1907 1908 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { 1909 XDRInPacketDestroy(&reply); 1910 XDROutPacketDestroy(&call); 1911 return EISDIR; 1912 } 1913 1914 if ((result=remove_vnode(_volume,st.st_ino)) < B_OK) { 1915 XDRInPacketDestroy(&reply); 1916 XDROutPacketDestroy(&call); 1917 return result; 1918 } 1919 1920 if ((result=put_vnode(_volume, st.st_ino)) < B_OK) { 1921 XDRInPacketDestroy(&reply); 1922 XDROutPacketDestroy(&call); 1923 return result; 1924 } 1925 1926 XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE); 1927 XDROutPacketAddString(&call, name); 1928 1929 replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_REMOVE,&call); 1930 1931 if (!replyBuf) { 1932 XDRInPacketDestroy(&reply); 1933 XDROutPacketDestroy(&call); 1934 return EHOSTUNREACH; 1935 } 1936 1937 XDRInPacketSetTo(&reply, replyBuf, 0); 1938 1939 if (!is_successful_reply(&reply)) { 1940 XDRInPacketDestroy(&reply); 1941 XDROutPacketDestroy(&call); 1942 return B_ERROR; 1943 } 1944 1945 status = XDRInPacketGetInt32(&reply); 1946 1947 if (status != NFS_OK) { 1948 XDRInPacketDestroy(&reply); 1949 XDROutPacketDestroy(&call); 1950 return map_nfs_to_system_error(status); 1951 } 1952 1953 XDRInPacketDestroy(&reply); 1954 XDROutPacketDestroy(&call); 1955 1956 return notify_entry_removed(_volume->id, dir->vnid, name, st.st_ino); 1957 } 1958 1959 1960 static status_t 1961 fs_remove_vnode(fs_volume *_volume, fs_vnode *_node, bool r) 1962 { 1963 fs_nspace *ns = _volume->private_volume; 1964 fs_node *node = _node->private_node; 1965 1966 (void) r; 1967 1968 remove_node (ns, node->vnid); 1969 1970 return B_OK; 1971 } 1972 1973 1974 static status_t 1975 fs_mkdir(fs_volume *_volume, fs_vnode *_dir, const char *name, int perms) 1976 { 1977 fs_nspace *ns; 1978 fs_node *dir; 1979 1980 nfs_fhandle fhandle; 1981 struct stat st; 1982 fs_node *newNode; 1983 1984 status_t result; 1985 uint8 *replyBuf; 1986 int32 status; 1987 1988 struct XDROutPacket call; 1989 struct XDRInPacket reply; 1990 1991 ns = _volume->private_volume; 1992 dir = _dir->private_node; 1993 1994 XDROutPacketInit(&call); 1995 XDRInPacketInit(&reply); 1996 1997 result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st); 1998 1999 if (result == B_OK) { 2000 //void *dummy; 2001 2002 XDRInPacketDestroy(&reply); 2003 XDROutPacketDestroy(&call); 2004 // XXX: either OK or not get_vnode !!! ?? 2005 //if ((result=get_vnode(_volume,st.st_ino,&dummy))<B_OK) 2006 // return result; 2007 return EEXIST; 2008 } else if (result != ENOENT) { 2009 XDRInPacketDestroy(&reply); 2010 XDROutPacketDestroy(&call); 2011 return result; 2012 } 2013 2014 XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE); 2015 XDROutPacketAddString(&call, name); 2016 XDROutPacketAddInt32(&call, perms | S_IFDIR); 2017 XDROutPacketAddInt32(&call, -1); 2018 XDROutPacketAddInt32(&call, -1); 2019 XDROutPacketAddInt32(&call, -1); 2020 XDROutPacketAddInt32(&call, time(NULL)); 2021 XDROutPacketAddInt32(&call, 0); 2022 XDROutPacketAddInt32(&call, time(NULL)); 2023 XDROutPacketAddInt32(&call, 0); 2024 2025 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 2026 NFSPROC_MKDIR, &call); 2027 2028 if (!replyBuf) { 2029 XDRInPacketDestroy(&reply); 2030 XDROutPacketDestroy(&call); 2031 return B_ERROR; 2032 } 2033 2034 XDRInPacketSetTo(&reply, replyBuf, 0); 2035 2036 if (!is_successful_reply(&reply)) { 2037 XDRInPacketDestroy(&reply); 2038 XDROutPacketDestroy(&call); 2039 return B_ERROR; 2040 } 2041 2042 status = XDRInPacketGetInt32(&reply); 2043 2044 if (status != NFS_OK) { 2045 XDROutPacketDestroy(&call); 2046 return map_nfs_to_system_error(status); 2047 } 2048 2049 XDRInPacketGetFixed(&reply, fhandle.opaque, NFS_FHSIZE); 2050 2051 get_nfs_attr(&reply, &st); 2052 2053 newNode=(fs_node *)malloc(sizeof(fs_node)); 2054 if (newNode == NULL) { 2055 XDRInPacketDestroy(&reply); 2056 XDROutPacketDestroy(&call); 2057 return B_NO_MEMORY; 2058 } 2059 newNode->fhandle = fhandle; 2060 newNode->vnid = st.st_ino; 2061 newNode->mode = st.st_mode; 2062 2063 insert_node(ns, newNode); 2064 2065 XDRInPacketDestroy(&reply); 2066 XDROutPacketDestroy(&call); 2067 2068 return notify_entry_created(_volume->id, dir->vnid, name, st.st_ino); 2069 } 2070 2071 static status_t 2072 fs_rename(fs_volume *_volume, fs_vnode *_olddir, const char *oldname, 2073 fs_vnode *_newdir, const char *newname) 2074 { 2075 struct stat st; 2076 nfs_fhandle fhandle; 2077 status_t result; 2078 struct XDROutPacket call; 2079 struct XDRInPacket reply; 2080 int32 status; 2081 uint8 *replyBuf; 2082 fs_nspace *ns; 2083 fs_node *olddir; 2084 fs_node *newdir; 2085 2086 ns = _volume->private_volume; 2087 olddir = _olddir->private_node; 2088 newdir = _newdir->private_node; 2089 2090 XDROutPacketInit(&call); 2091 XDRInPacketInit(&reply); 2092 2093 if ((result = nfs_lookup(ns, &newdir->fhandle, newname, &fhandle, &st)) 2094 == B_OK) { 2095 if (S_ISREG(st.st_mode)) 2096 result = fs_unlink (_volume,_newdir,newname); 2097 else 2098 result = fs_rmdir (_volume,_newdir,newname); 2099 2100 if (result < B_OK) { 2101 XDRInPacketDestroy (&reply); 2102 XDROutPacketDestroy (&call); 2103 return result; 2104 } 2105 } 2106 2107 if ((result = nfs_lookup(ns, &olddir->fhandle, oldname, &fhandle, &st)) 2108 < B_OK) { 2109 XDRInPacketDestroy(&reply); 2110 XDROutPacketDestroy(&call); 2111 return result; 2112 } 2113 2114 XDROutPacketAddFixed(&call, olddir->fhandle.opaque, NFS_FHSIZE); 2115 XDROutPacketAddString(&call, oldname); 2116 XDROutPacketAddFixed(&call, newdir->fhandle.opaque, NFS_FHSIZE); 2117 XDROutPacketAddString(&call, newname); 2118 2119 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 2120 NFSPROC_RENAME, &call); 2121 2122 if (!replyBuf) { 2123 XDRInPacketDestroy(&reply); 2124 XDROutPacketDestroy(&call); 2125 return EHOSTUNREACH; 2126 } 2127 2128 XDRInPacketSetTo(&reply, replyBuf, 0); 2129 2130 if (!is_successful_reply(&reply)) { 2131 XDRInPacketDestroy(&reply); 2132 XDROutPacketDestroy(&call); 2133 return B_ERROR; 2134 } 2135 2136 status = XDRInPacketGetInt32(&reply); 2137 2138 if (status != NFS_OK) { 2139 XDRInPacketDestroy(&reply); 2140 XDROutPacketDestroy(&call); 2141 return map_nfs_to_system_error(status); 2142 } 2143 2144 XDRInPacketDestroy (&reply); 2145 XDROutPacketDestroy (&call); 2146 2147 return notify_entry_moved(_volume->id, olddir->vnid, oldname, newdir->vnid, 2148 newname, st.st_ino); 2149 } 2150 2151 2152 static status_t 2153 fs_rmdir(fs_volume *_volume, fs_vnode *_dir, const char *name) 2154 { 2155 fs_nspace *ns; 2156 fs_node *dir; 2157 2158 status_t result; 2159 fs_node *newNode; 2160 fs_node *dummy; 2161 struct XDROutPacket call; 2162 struct XDRInPacket reply; 2163 int32 status; 2164 uint8 *replyBuf; 2165 2166 struct stat st; 2167 nfs_fhandle fhandle; 2168 2169 ns = _volume->private_volume; 2170 dir = _dir->private_node; 2171 2172 XDROutPacketInit(&call); 2173 XDRInPacketInit(&reply); 2174 2175 if ((result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st)) < B_OK) { 2176 XDRInPacketDestroy(&reply); 2177 XDROutPacketDestroy(&call); 2178 return result; 2179 } 2180 2181 newNode = (fs_node *)malloc(sizeof(fs_node)); 2182 if (newNode == NULL) { 2183 XDRInPacketDestroy(&reply); 2184 XDROutPacketDestroy(&call); 2185 return B_NO_MEMORY; 2186 } 2187 newNode->fhandle = fhandle; 2188 newNode->vnid = st.st_ino; 2189 newNode->mode = st.st_mode; 2190 2191 insert_node(ns, newNode); 2192 2193 if ((result = get_vnode(_volume, st.st_ino, (void **)&dummy)) < B_OK) { 2194 XDRInPacketDestroy(&reply); 2195 XDROutPacketDestroy(&call); 2196 return result; 2197 } 2198 2199 if (!S_ISDIR(st.st_mode)) { 2200 XDRInPacketDestroy(&reply); 2201 XDROutPacketDestroy(&call); 2202 return ENOTDIR; 2203 } 2204 2205 if ((result = remove_vnode(_volume, st.st_ino)) < B_OK) { 2206 XDRInPacketDestroy(&reply); 2207 XDROutPacketDestroy(&call); 2208 return result; 2209 } 2210 2211 if ((result = put_vnode(_volume, st.st_ino)) < B_OK) { 2212 XDRInPacketDestroy(&reply); 2213 XDROutPacketDestroy(&call); 2214 return result; 2215 } 2216 2217 XDROutPacketAddFixed (&call, dir->fhandle.opaque, NFS_FHSIZE); 2218 XDROutPacketAddString(&call, name); 2219 2220 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 2221 NFSPROC_RMDIR, &call); 2222 2223 if (!replyBuf) { 2224 XDRInPacketDestroy(&reply); 2225 XDROutPacketDestroy(&call); 2226 return EHOSTUNREACH; 2227 } 2228 2229 XDRInPacketSetTo (&reply,replyBuf,0); 2230 2231 if (!is_successful_reply(&reply)) { 2232 XDRInPacketDestroy(&reply); 2233 XDROutPacketDestroy(&call); 2234 return B_ERROR; 2235 } 2236 2237 status = XDRInPacketGetInt32(&reply); 2238 2239 if (status != NFS_OK) { 2240 XDRInPacketDestroy(&reply); 2241 XDROutPacketDestroy(&call); 2242 return map_nfs_to_system_error(status); 2243 } 2244 2245 XDRInPacketDestroy(&reply); 2246 XDROutPacketDestroy(&call); 2247 return notify_entry_removed(_volume->id, dir->vnid, name, st.st_ino); 2248 } 2249 2250 2251 static status_t 2252 fs_readlink(fs_volume *_volume, fs_vnode *_node, char *buf, size_t *bufsize) 2253 { 2254 struct XDROutPacket call; 2255 uint8 *replyBuf; 2256 int32 status; 2257 size_t length; 2258 char data[NFS_MAXPATHLEN]; 2259 struct XDRInPacket reply; 2260 fs_nspace *ns; 2261 fs_node *node; 2262 2263 ns = _volume->private_volume; 2264 node = _node->private_node; 2265 2266 XDROutPacketInit(&call); 2267 XDRInPacketInit(&reply); 2268 2269 XDROutPacketAddFixed(&call, node->fhandle.opaque, NFS_FHSIZE); 2270 2271 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 2272 NFSPROC_READLINK, &call); 2273 2274 if (!replyBuf) { 2275 XDRInPacketDestroy(&reply); 2276 XDROutPacketDestroy(&call); 2277 return EHOSTUNREACH; 2278 } 2279 2280 XDRInPacketSetTo (&reply, replyBuf, 0); 2281 2282 if (!is_successful_reply(&reply)) { 2283 XDRInPacketDestroy(&reply); 2284 XDROutPacketDestroy(&call); 2285 return B_ERROR; 2286 } 2287 2288 status = XDRInPacketGetInt32(&reply); 2289 2290 if (status != NFS_OK) { 2291 XDRInPacketDestroy(&reply); 2292 XDROutPacketDestroy (&call); 2293 return map_nfs_to_system_error(status); 2294 } 2295 2296 length = XDRInPacketGetDynamic(&reply, data); 2297 2298 length = min_c(length, *bufsize); 2299 memcpy(buf, data, length); 2300 *bufsize = length; 2301 2302 XDRInPacketDestroy(&reply); 2303 XDROutPacketDestroy(&call); 2304 return B_OK; 2305 } 2306 2307 static status_t 2308 fs_symlink(fs_volume *_volume, fs_vnode *_dir, const char *name, 2309 const char *path, int mode) 2310 { 2311 fs_nspace *ns; 2312 fs_node *dir; 2313 nfs_fhandle fhandle; 2314 struct stat st; 2315 struct XDROutPacket call; 2316 struct XDRInPacket reply; 2317 status_t result; 2318 uint8 *replyBuf; 2319 int32 status; 2320 fs_node *newNode; 2321 2322 ns = _volume->private_volume; 2323 dir = _dir->private_node; 2324 2325 XDROutPacketInit(&call); 2326 XDRInPacketInit(&reply); 2327 2328 result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st); 2329 2330 if (result == B_OK) { 2331 void *dummy; 2332 if ((result = get_vnode(_volume, st.st_ino, &dummy)) < B_OK) 2333 return result; 2334 2335 XDRInPacketDestroy(&reply); 2336 XDROutPacketDestroy(&call); 2337 return EEXIST; 2338 } else if (result != ENOENT) { 2339 XDRInPacketDestroy(&reply); 2340 XDROutPacketDestroy(&call); 2341 return result; 2342 } 2343 2344 XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE); 2345 XDROutPacketAddString(&call, name); 2346 XDROutPacketAddString(&call, path); 2347 XDROutPacketAddInt32(&call, S_IFLNK); 2348 XDROutPacketAddInt32(&call, -1); 2349 XDROutPacketAddInt32(&call, -1); 2350 XDROutPacketAddInt32(&call, -1); 2351 XDROutPacketAddInt32(&call, time(NULL)); 2352 XDROutPacketAddInt32(&call, 0); 2353 XDROutPacketAddInt32(&call, time(NULL)); 2354 XDROutPacketAddInt32(&call, 0); 2355 2356 replyBuf = send_rpc_call (ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 2357 NFSPROC_SYMLINK, &call); 2358 2359 if (!replyBuf) { 2360 XDRInPacketDestroy(&reply); 2361 XDROutPacketDestroy(&call); 2362 return B_ERROR; 2363 } 2364 2365 XDRInPacketSetTo(&reply, replyBuf, 0); 2366 2367 if (!is_successful_reply(&reply)) { 2368 XDRInPacketDestroy(&reply); 2369 XDROutPacketDestroy(&call); 2370 return B_ERROR; 2371 } 2372 2373 status = XDRInPacketGetInt32(&reply); 2374 /* if (status!=NFS_OK) 2375 return map_nfs_to_system_error(status); 2376 2377 ignore status here, weird thing, nfsservers that is 2378 */ 2379 (void)status; 2380 2381 result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st); 2382 2383 if (result < B_OK) { 2384 XDRInPacketDestroy(&reply); 2385 XDROutPacketDestroy(&call); 2386 return result; 2387 } 2388 2389 newNode = (fs_node *)malloc(sizeof(fs_node)); 2390 if (newNode == NULL) { 2391 XDRInPacketDestroy(&reply); 2392 XDROutPacketDestroy(&call); 2393 return B_NO_MEMORY; 2394 } 2395 newNode->fhandle = fhandle; 2396 newNode->vnid = st.st_ino; 2397 2398 insert_node(ns, newNode); 2399 2400 result = notify_entry_created (_volume->id, dir->vnid, name, st.st_ino); 2401 2402 XDRInPacketDestroy(&reply); 2403 XDROutPacketDestroy(&call); 2404 return result; 2405 } 2406 2407 2408 static status_t 2409 fs_access(fs_volume *_volume, fs_vnode *node, int mode) 2410 { 2411 (void) _volume; 2412 (void) node; 2413 (void) mode; 2414 /* XXX */ 2415 return B_OK; 2416 } 2417 2418 2419 static status_t 2420 nfs_std_ops(int32 op, ...) 2421 { 2422 switch (op) { 2423 case B_MODULE_INIT: 2424 return B_OK; 2425 case B_MODULE_UNINIT: 2426 return B_OK; 2427 2428 default: 2429 return B_ERROR; 2430 } 2431 } 2432 2433 2434 fs_volume_ops sNFSVolumeOps = { 2435 &fs_unmount, 2436 &fs_rfsstat, 2437 &fs_wfsstat, 2438 NULL, // no sync! 2439 &fs_read_vnode, 2440 2441 /* index directory & index operations */ 2442 NULL, // &fs_open_index_dir 2443 NULL, // &fs_close_index_dir 2444 NULL, // &fs_free_index_dir_cookie 2445 NULL, // &fs_read_index_dir 2446 NULL, // &fs_rewind_index_dir 2447 2448 NULL, // &fs_create_index 2449 NULL, // &fs_remove_index 2450 NULL, // &fs_stat_index 2451 2452 /* query operations */ 2453 NULL, // &fs_open_query, 2454 NULL, // &fs_close_query, 2455 NULL, // &fs_free_query_cookie, 2456 NULL, // &fs_read_query, 2457 NULL, // &fs_rewind_query, 2458 }; 2459 2460 2461 fs_vnode_ops sNFSVnodeOps = { 2462 /* vnode operations */ 2463 &fs_walk, 2464 NULL, // fs_get_vnode_name 2465 &fs_release_vnode, 2466 &fs_remove_vnode, 2467 2468 /* VM file access */ 2469 NULL, // &fs_can_page 2470 NULL, // &fs_read_pages 2471 NULL, // &fs_write_pages 2472 2473 NULL, // io() 2474 NULL, // cancel_io() 2475 2476 NULL, // &fs_get_file_map, 2477 2478 NULL, // &fs_ioctl 2479 NULL, // &fs_setflags, 2480 NULL, // &fs_select 2481 NULL, // &fs_deselect 2482 NULL, // &fs_fsync 2483 2484 &fs_readlink, 2485 &fs_symlink, 2486 2487 NULL, // &fs_link, 2488 &fs_unlink, 2489 &fs_rename, 2490 2491 &fs_access, 2492 &fs_rstat, 2493 &fs_wstat, 2494 NULL, // fs_preallocate() 2495 2496 /* file operations */ 2497 &fs_create, 2498 &fs_open, 2499 &fs_close, 2500 &fs_free_cookie, 2501 &fs_read, 2502 &fs_write, 2503 2504 /* directory operations */ 2505 &fs_mkdir, 2506 &fs_rmdir, 2507 &fs_opendir, 2508 &fs_closedir, 2509 &fs_free_dircookie, 2510 &fs_readdir, 2511 &fs_rewinddir, 2512 2513 /* attribute directory operations */ 2514 NULL, // &fs_open_attrdir, 2515 NULL, // &fs_close_attrdir, 2516 NULL, // &fs_free_attrdircookie, 2517 NULL, // &fs_read_attrdir, 2518 NULL, // &fs_rewind_attrdir, 2519 2520 /* attribute operations */ 2521 NULL, // &fs_create_attr 2522 NULL, // &fs_open_attr_h, 2523 NULL, // &fs_close_attr_h, 2524 NULL, // &fs_free_attr_cookie_h, 2525 NULL, // &fs_read_attr_h, 2526 NULL, // &fs_write_attr_h, 2527 2528 NULL, // &fs_read_attr_stat_h, 2529 NULL, // &fs_write_attr_stat 2530 NULL, // &fs_rename_attr 2531 NULL, // &fs_remove_attr 2532 }; 2533 2534 file_system_module_info sNFSFileSystem = { 2535 { 2536 "file_systems/nfs" B_CURRENT_FS_API_VERSION, 2537 0, 2538 nfs_std_ops, 2539 }, 2540 "nfs", // short name 2541 "Network File System v2", // pretty name 2542 B_DISK_SYSTEM_SUPPORTS_WRITING, // DDM flags 2543 2544 // scanning 2545 NULL, // fs_identify_partition, 2546 NULL, // fs_scan_partition, 2547 NULL, // fs_free_identify_partition_cookie, 2548 NULL, // free_partition_content_cookie() 2549 2550 &fs_mount, 2551 }; 2552 2553 module_info *modules[] = { 2554 (module_info *)&sNFSFileSystem, 2555 NULL, 2556 }; 2557