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 st->st_blksize=XDRInPacketGetInt32(reply); 663 st->st_rdev=XDRInPacketGetInt32(reply); 664 st->st_blocks=XDRInPacketGetInt32(reply); 665 XDRInPacketGetInt32(reply); // fsid 666 st->st_ino=XDRInPacketGetInt32(reply); 667 st->st_atime=XDRInPacketGetInt32(reply); 668 XDRInPacketGetInt32(reply); // usecs 669 st->st_mtime=st->st_crtime=XDRInPacketGetInt32(reply); 670 XDRInPacketGetInt32(reply); // usecs 671 st->st_ctime=XDRInPacketGetInt32(reply); 672 XDRInPacketGetInt32(reply); // usecs 673 } 674 675 676 status_t 677 map_nfs_to_system_error(status_t nfsstatus) 678 { 679 switch (nfsstatus) { 680 case NFS_OK: 681 return B_OK; 682 683 case NFSERR_PERM: 684 return EPERM; 685 686 case NFSERR_NOENT: 687 return ENOENT; 688 689 case NFSERR_IO: 690 return EIO; 691 692 case NFSERR_NXIO: 693 return ENXIO; 694 695 case NFSERR_ACCES: 696 return EACCES; 697 698 case NFSERR_EXIST: 699 return EEXIST; 700 701 case NFSERR_NODEV: 702 return ENODEV; 703 704 case NFSERR_NOTDIR: 705 return ENOTDIR; 706 707 case NFSERR_ISDIR: 708 return EISDIR; 709 710 case NFSERR_FBIG: 711 return EFBIG; 712 713 case NFSERR_NOSPC: 714 return ENOSPC; 715 716 case NFSERR_ROFS: 717 return EROFS; 718 719 case NFSERR_NAMETOOLONG: 720 return ENAMETOOLONG; 721 722 case NFSERR_NOTEMPTY: 723 return ENOTEMPTY; 724 725 case NFSERR_STALE: 726 return C_ERROR_STALE; 727 728 default: 729 return B_ERROR; 730 } 731 } 732 733 734 nfs_fhandle 735 handle_from_vnid(fs_nspace *ns, ino_t vnid) 736 { 737 fs_node *current; 738 739 while (acquire_sem(ns->sem) == B_INTERRUPTED); 740 741 current = ns->first; 742 743 while (current != NULL && current->vnid != vnid) 744 current = current->next; 745 746 while (release_sem(ns->sem) == B_INTERRUPTED); 747 748 return current->fhandle; 749 } 750 751 752 void 753 insert_node(fs_nspace *ns, fs_node *node) 754 { 755 fs_node *current; 756 757 while (acquire_sem(ns->sem) == B_INTERRUPTED); 758 759 current = ns->first; 760 761 while (current != NULL && current->vnid != node->vnid) 762 current = current->next; 763 764 if (current) { 765 free(node); 766 while (release_sem(ns->sem) == B_INTERRUPTED); 767 return; 768 } 769 770 node->next = ns->first; 771 ns->first = node; 772 773 while (release_sem (ns->sem) == B_INTERRUPTED); 774 } 775 776 777 void 778 remove_node(fs_nspace *ns, ino_t vnid) 779 { 780 fs_node *current; 781 fs_node *previous; 782 783 while (acquire_sem(ns->sem) == B_INTERRUPTED); 784 785 current = ns->first; 786 previous = NULL; 787 788 while (current != NULL && current->vnid != vnid) { 789 previous = current; 790 current = current->next; 791 } 792 793 if (current) { 794 if (previous) 795 previous->next = current->next; 796 else 797 ns->first = current->next; 798 799 free(current); 800 } 801 802 while (release_sem(ns->sem) == B_INTERRUPTED); 803 } 804 805 806 // #pragma mark - 807 808 809 static status_t 810 fs_read_vnode(fs_volume *_volume, ino_t vnid, fs_vnode *_node, int *_type, 811 uint32 *_flags, bool r) 812 { 813 fs_nspace *ns; 814 fs_node *current; 815 816 ns = _volume->private_volume; 817 818 if (!r) { 819 while (acquire_sem(ns->sem) == B_INTERRUPTED); 820 } 821 822 current = ns->first; 823 824 while (current != NULL && current->vnid != vnid) 825 current = current->next; 826 827 if (!current) 828 return EINVAL; 829 830 current->vnid = vnid; 831 _node->private_node = current; 832 _node->ops = &sNFSVnodeOps; 833 *_type = current->mode; 834 *_flags = 0; 835 836 if (!r) { 837 while (release_sem(ns->sem) == B_INTERRUPTED); 838 } 839 840 return B_OK; 841 } 842 843 844 static status_t 845 fs_release_vnode(fs_volume *_volume, fs_vnode *node, bool r) 846 { 847 (void) _volume; 848 (void) node; 849 (void) r; 850 return B_OK; 851 } 852 853 854 static status_t 855 fs_walk(fs_volume *_volume, fs_vnode *_base, const char *file, ino_t *vnid) 856 { 857 fs_node *dummy; 858 status_t result; 859 fs_nspace *ns; 860 fs_node *base; 861 //dprintf("nfs: walk(%s)\n", file);//XXX:mmu_man:debug 862 863 ns = _volume->private_volume; 864 base = _base->private_node; 865 866 if (!strcmp(".", file)) 867 *vnid = base->vnid; 868 else { 869 fs_node *newNode = (fs_node *)malloc(sizeof(fs_node)); 870 struct stat st; 871 872 if ((result = nfs_lookup(ns, &base->fhandle, file, &newNode->fhandle, 873 &st)) < B_OK) { 874 free(newNode); 875 return result; 876 } 877 878 newNode->vnid = st.st_ino; 879 newNode->mode = st.st_mode; 880 *vnid = newNode->vnid; 881 882 insert_node(ns, newNode); 883 } 884 885 if ((result = get_vnode (_volume, *vnid, (void **)&dummy)) < B_OK) 886 return result; 887 888 return B_OK; 889 } 890 891 892 static status_t 893 fs_opendir(fs_volume *_volume, fs_vnode *_node, void **_cookie) 894 { 895 fs_nspace *ns; 896 fs_node *node; 897 nfs_cookie **cookie; 898 899 struct stat st; 900 status_t result; 901 902 ns = _volume->private_volume; 903 node = _node->private_node; 904 cookie = (nfs_cookie **)_cookie; 905 906 if ((result = nfs_getattr(ns, &node->fhandle, &st)) < B_OK) 907 return result; 908 909 if (!S_ISDIR(st.st_mode)) 910 return ENOTDIR; 911 912 *cookie = (nfs_cookie *)malloc(sizeof(nfs_cookie)); 913 memset((*cookie)->opaque,0,NFS_COOKIESIZE); 914 915 return B_OK; 916 } 917 918 919 static status_t 920 fs_closedir(fs_volume *_volume, fs_vnode *_node, void *cookie) 921 { 922 (void) _volume; 923 (void) _node; 924 (void) cookie; 925 return B_OK; 926 } 927 928 929 static status_t 930 fs_rewinddir(fs_volume *_volume, fs_vnode *_node, void *_cookie) 931 { 932 nfs_cookie *cookie = (nfs_cookie *)_cookie; 933 (void) _volume; 934 (void) _node; 935 memset (cookie->opaque, 0, NFS_COOKIESIZE); 936 937 return B_OK; 938 } 939 940 941 static status_t 942 fs_readdir(fs_volume *_volume, fs_vnode *_node, void *_cookie, 943 struct dirent *buf, size_t bufsize, uint32 *num) 944 { 945 nfs_cookie *cookie = (nfs_cookie *)_cookie; 946 int32 max = *num; 947 int32 eof; 948 949 fs_nspace *ns; 950 fs_node *node; 951 952 size_t count = min_c(6000, max * 300); 953 954 *num = 0; 955 956 ns = _volume->private_volume; 957 node = _node->private_node; 958 959 do { 960 ino_t vnid; 961 char *filename; 962 uint8 *replyBuf; 963 struct XDROutPacket call; 964 struct XDRInPacket reply; 965 int32 status; 966 967 XDROutPacketInit(&call); 968 XDRInPacketInit(&reply); 969 970 XDROutPacketAddFixed(&call, node->fhandle.opaque, NFS_FHSIZE); 971 XDROutPacketAddFixed(&call, cookie->opaque, NFS_COOKIESIZE); 972 XDROutPacketAddInt32(&call, count); 973 974 replyBuf = send_rpc_call (ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 975 NFSPROC_READDIR, &call); 976 977 if (!replyBuf) { 978 XDRInPacketDestroy(&reply); 979 XDROutPacketDestroy(&call); 980 return B_ERROR; 981 } 982 983 XDRInPacketSetTo(&reply, replyBuf, 0); 984 985 if (!is_successful_reply(&reply)) { 986 XDRInPacketDestroy(&reply); 987 XDROutPacketDestroy(&call); 988 return B_ERROR; 989 } 990 991 status = XDRInPacketGetInt32(&reply); 992 993 if (status != NFS_OK) { 994 XDRInPacketDestroy(&reply); 995 XDROutPacketDestroy(&call); 996 return map_nfs_to_system_error(status); 997 } 998 999 while (XDRInPacketGetInt32(&reply) == 1) { 1000 nfs_cookie newCookie; 1001 1002 vnid=XDRInPacketGetInt32(&reply); 1003 filename=XDRInPacketGetString(&reply); 1004 1005 XDRInPacketGetFixed(&reply, newCookie.opaque, NFS_COOKIESIZE); 1006 1007 //if (strcmp(".",filename)&&strcmp("..",filename)) 1008 //if ((ns->rootid != node->vnid) || (strcmp(".",filename)&&strcmp("..",filename))) 1009 if (conf_ls_root_parent 1010 || ((ns->rootid != node->vnid) || strcmp("..", filename))) { 1011 status_t result; 1012 struct stat st; 1013 1014 fs_node *newNode = (fs_node *)malloc(sizeof(fs_node)); 1015 newNode->vnid = vnid; 1016 1017 if ((result = nfs_lookup(ns, &node->fhandle, filename, 1018 &newNode->fhandle, &st)) < B_OK) { 1019 free (filename); 1020 free(newNode); 1021 XDRInPacketDestroy (&reply); 1022 XDROutPacketDestroy (&call); 1023 return result; 1024 } 1025 1026 newNode->mode = st.st_mode; 1027 insert_node(ns,newNode); 1028 1029 if (bufsize < 2 * (sizeof(dev_t) + sizeof(ino_t)) 1030 + sizeof(unsigned short) + strlen(filename) + 1) { 1031 XDRInPacketDestroy(&reply); 1032 XDROutPacketDestroy(&call); 1033 return B_OK; 1034 } 1035 1036 buf->d_dev = ns->nsid; 1037 buf->d_pdev = ns->nsid; 1038 buf->d_ino = vnid; 1039 buf->d_pino = node->vnid; 1040 buf->d_reclen = 2 * (sizeof(dev_t) + sizeof(ino_t)) 1041 + sizeof(unsigned short) + strlen(filename) + 1; 1042 strcpy (buf->d_name,filename); 1043 // if ((ns->rootid == node->vnid))//XXX:mmu_man:test 1044 // 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); 1045 1046 bufsize -= buf->d_reclen; 1047 buf = (struct dirent *)((char *)buf + buf->d_reclen); 1048 1049 memcpy(cookie->opaque, newCookie.opaque, NFS_COOKIESIZE); 1050 1051 (*num)++; 1052 } else { 1053 memcpy(cookie->opaque, newCookie.opaque, NFS_COOKIESIZE); 1054 } 1055 1056 free (filename); 1057 1058 if ((*num) == max) { 1059 XDRInPacketDestroy(&reply); 1060 XDROutPacketDestroy(&call); 1061 return B_OK; 1062 } 1063 } 1064 1065 eof=XDRInPacketGetInt32(&reply); 1066 1067 XDRInPacketDestroy (&reply); 1068 XDROutPacketDestroy (&call); 1069 } 1070 while (eof == 0); 1071 1072 return B_OK; 1073 } 1074 1075 1076 static status_t 1077 fs_free_dircookie(fs_volume *_volume, fs_vnode *_node, void *cookie) 1078 { 1079 (void) _volume; 1080 (void) _node; 1081 free(cookie); 1082 return B_OK; 1083 } 1084 1085 1086 static status_t 1087 fs_rstat(fs_volume *_volume, fs_vnode *_node, struct stat *st) 1088 { 1089 fs_nspace *ns; 1090 fs_node *node; 1091 status_t result; 1092 1093 ns = _volume->private_volume; 1094 node = _node->private_node; 1095 1096 //dprintf("nfs: rstat()\n");//XXX:mmu_man:debug 1097 if ((result = nfs_getattr(ns, &node->fhandle, st)) < B_OK) 1098 return result; 1099 1100 st->st_dev = ns->nsid; 1101 //st->st_nlink = 1; //XXX:mmu_man:test 1102 return B_OK; 1103 } 1104 1105 1106 void 1107 fs_nspaceInit(struct fs_nspace *nspace) 1108 { 1109 RPCPendingCallsInit(&nspace->pendingCalls); 1110 } 1111 1112 1113 void 1114 fs_nspaceDestroy(struct fs_nspace *nspace) 1115 { 1116 RPCPendingCallsDestroy(&nspace->pendingCalls); 1117 } 1118 1119 1120 static status_t 1121 parse_nfs_params(const char *str, struct mount_nfs_params *params) 1122 { 1123 const char *p, *e; 1124 long v; 1125 int i; 1126 // sprintf(buf, "nfs:%s:%s,uid=%u,gid=%u,hostname=%s", 1127 if (!str || !params) 1128 return EINVAL; 1129 if (strncmp(str, "nfs:", 4)) 1130 return EINVAL; 1131 dprintf("nfs:ip!\n"); 1132 p = str + 4; 1133 e = strchr(p, ':'); 1134 if (!e) 1135 return EINVAL; 1136 params->server = malloc(e - p + 1); 1137 params->server[e - p] = '\0'; 1138 strncpy(params->server, p, e - p); 1139 // hack 1140 params->serverIP = 0; 1141 v = strtol(p, (char **)&p, 10); 1142 dprintf("IP:%ld.", v); 1143 if (!p) 1144 return EINVAL; 1145 params->serverIP |= (v << 24); 1146 p++; 1147 v = strtol(p, (char **)&p, 10); 1148 dprintf("%ld.", v); 1149 if (!p) 1150 return EINVAL; 1151 params->serverIP |= (v << 16); 1152 p++; 1153 v = strtol(p, (char **)&p, 10); 1154 dprintf("%ld.", v); 1155 if (!p) 1156 return EINVAL; 1157 params->serverIP |= (v << 8); 1158 p++; 1159 v = strtol(p, (char **)&p, 10); 1160 dprintf("%ld\n", v); 1161 if (!p) 1162 return EINVAL; 1163 params->serverIP |= (v); 1164 if (*p++ != ':') 1165 return EINVAL; 1166 1167 e = strchr(p, ','); 1168 i = (e) ? (e - p) : (strlen(p)); 1169 1170 params->_export = malloc(i + 1); 1171 params->_export[i] = '\0'; 1172 strncpy(params->_export, p, i); 1173 1174 p = strstr(str, "hostname="); 1175 if (!p) 1176 return EINVAL; 1177 dprintf("nfs:hn!\n"); 1178 p += 9; 1179 e = strchr(p, ','); 1180 i = (e) ? (e - p) : (strlen(p)); 1181 1182 params->hostname = malloc(i + 1); 1183 params->hostname[i] = '\0'; 1184 strncpy(params->hostname, p, i); 1185 1186 p = strstr(str, "uid="); 1187 dprintf("nfs:uid!\n"); 1188 if (p) { 1189 p += 4; 1190 v = strtol(p, (char **)&p, 10); 1191 params->uid = v; 1192 } 1193 dprintf("nfs:gid!\n"); 1194 p = strstr(str, "gid="); 1195 if (p) { 1196 p += 4; 1197 v = strtol(p, (char **)&p, 10); 1198 params->gid = v; 1199 } 1200 dprintf("nfs: ip:%08x server:'%s' export:'%s' hostname:'%s' uid=%d gid=%d \n", 1201 params->serverIP, params->server, params->_export, 1202 params->hostname, params->uid, params->gid); 1203 return B_OK; 1204 } 1205 1206 1207 static status_t 1208 fs_mount(fs_volume *_vol, const char *devname, uint32 flags, const char *_parms, ino_t *vnid) 1209 { 1210 status_t result; 1211 fs_nspace *ns; 1212 fs_node *rootNode; 1213 struct stat st; 1214 1215 if (_parms == NULL) 1216 return EINVAL; 1217 1218 dprintf("nfs: mount(%" B_PRId32 ", %s, %08" B_PRIx32 ")\n", _vol->id, 1219 devname, flags); 1220 dprintf("nfs: nfs_params: %s\n", _parms); 1221 1222 // HAIKU: this should go to std_ops 1223 if (!refcount) 1224 read_config(); 1225 1226 1227 result = ENOMEM; 1228 ns = (fs_nspace *)malloc(sizeof(fs_nspace)); 1229 if (!ns) 1230 goto err_nspace; 1231 fs_nspaceInit(ns); 1232 1233 ns->nsid = _vol->id; 1234 1235 ns->params.server = NULL; 1236 ns->params._export = NULL; 1237 ns->params.hostname = NULL; 1238 if ((result = parse_nfs_params(_parms, &ns->params)) < 0) 1239 goto err_params; 1240 ns->xid = 0; 1241 ns->mountAddr.sin_family = AF_INET; 1242 ns->mountAddr.sin_addr.s_addr = htonl(ns->params.serverIP); 1243 memset(ns->mountAddr.sin_zero, 0, sizeof(ns->mountAddr.sin_zero)); 1244 1245 if ((result = create_socket(ns)) < B_OK) { 1246 dprintf("nfs: could not create socket (%" B_PRId32 ")\n", result); 1247 goto err_socket; 1248 } 1249 1250 if ((result = init_postoffice(ns)) < B_OK) { 1251 dprintf("nfs: could not init_postoffice() (%" B_PRId32 ")\n", result); 1252 goto err_postoffice; 1253 } 1254 1255 if ((result = get_remote_address(ns, MOUNT_PROGRAM, MOUNT_VERSION, 1256 PMAP_IPPROTO_UDP, &ns->mountAddr)) < B_OK) { 1257 dprintf("could not get_remote_address() (%" B_PRId32 ")\n", result); 1258 goto err_sem; 1259 } 1260 1261 memcpy(&ns->nfsAddr, &ns->mountAddr, sizeof(ns->mountAddr)); 1262 dprintf("nfs: mountd at %08x:%d\n", ns->mountAddr.sin_addr.s_addr, ntohs(ns->mountAddr.sin_port)); 1263 1264 if ((result = get_remote_address(ns, NFS_PROGRAM, NFS_VERSION, 1265 PMAP_IPPROTO_UDP, &ns->nfsAddr)) < B_OK) 1266 goto err_sem; 1267 dprintf("nfs: nfsd at %08x:%d\n", ns->nfsAddr.sin_addr.s_addr, ntohs(ns->nfsAddr.sin_port)); 1268 // result = connect_socket(ns); 1269 //dprintf("nfs: connect: %s\n", strerror(result)); 1270 1271 if ((result = create_sem(1, "nfs_sem")) < B_OK) 1272 goto err_sem; 1273 1274 ns->sem = result; 1275 1276 set_sem_owner(ns->sem, B_SYSTEM_TEAM); 1277 1278 result = ENOMEM; 1279 rootNode = (fs_node *)malloc(sizeof(fs_node)); 1280 if (!rootNode) 1281 goto err_rootvn; 1282 rootNode->next = NULL; 1283 1284 if ((result = nfs_mount(ns, ns->params._export, &rootNode->fhandle)) < B_OK) 1285 goto err_mount; 1286 1287 if ((result = nfs_getattr(ns, &rootNode->fhandle, &st)) < B_OK) 1288 goto err_publish; 1289 1290 ns->rootid = st.st_ino; 1291 rootNode->vnid = ns->rootid; 1292 1293 *vnid = ns->rootid; 1294 1295 _vol->private_volume = ns; 1296 _vol->ops = &sNFSVolumeOps; 1297 1298 // TODO: set right mode 1299 if ((result = publish_vnode(_vol, *vnid, rootNode, &sNFSVnodeOps, 1300 S_IFDIR, 0)) < B_OK) 1301 goto err_publish; 1302 1303 ns->first = rootNode; 1304 1305 return B_OK; 1306 1307 err_publish: 1308 // XXX: unmount ?? 1309 err_mount: 1310 free(rootNode); 1311 err_rootvn: 1312 delete_sem (ns->sem); 1313 err_sem: 1314 shutdown_postoffice(ns); 1315 goto err_socket; 1316 err_postoffice: 1317 close(ns->s); 1318 err_socket: 1319 err_params: 1320 free(ns->params.hostname); 1321 free(ns->params._export); 1322 free(ns->params.server); 1323 1324 fs_nspaceDestroy(ns); 1325 free(ns); 1326 err_nspace: 1327 1328 if (result >= 0) { 1329 dprintf("nfs:bad error from mount!\n"); 1330 result = EINVAL; 1331 } 1332 dprintf("nfs: error in nfs_mount: %s\n", strerror(result)); 1333 return result; 1334 } 1335 1336 1337 static status_t 1338 fs_unmount(fs_volume *_volume) 1339 { 1340 fs_nspace *ns = (fs_nspace *)_volume->private_volume; 1341 free(ns->params.hostname); 1342 free(ns->params._export); 1343 free(ns->params.server); 1344 1345 while (ns->first) { 1346 fs_node *next = ns->first->next; 1347 free(ns->first); 1348 ns->first = next; 1349 } 1350 1351 // We need to put the reference to our root node ourselves 1352 put_vnode(_volume, ns->rootid); 1353 1354 delete_sem(ns->sem); 1355 shutdown_postoffice(ns); 1356 fs_nspaceDestroy(ns); 1357 free(ns); 1358 return B_OK; 1359 } 1360 1361 1362 static status_t 1363 fs_rfsstat(fs_volume *_volume, struct fs_info *info) 1364 { 1365 fs_nspace *ns; 1366 struct XDROutPacket call; 1367 struct XDRInPacket reply; 1368 nfs_fhandle rootHandle; 1369 uint8 *replyBuf; 1370 int32 status; 1371 1372 ns = (fs_nspace *)_volume->private_volume; 1373 1374 rootHandle = handle_from_vnid (ns,ns->rootid); 1375 //dprintf("nfs: rfsstat()\n");//XXX:mmu_man:debug 1376 1377 XDROutPacketInit(&call); 1378 XDRInPacketInit(&reply); 1379 1380 XDROutPacketAddFixed(&call, rootHandle.opaque, NFS_FHSIZE); 1381 1382 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 1383 NFSPROC_STATFS, &call); 1384 if (replyBuf == NULL) { 1385 XDRInPacketDestroy(&reply); 1386 XDROutPacketDestroy(&call); 1387 return EHOSTUNREACH; 1388 } 1389 1390 XDRInPacketSetTo(&reply, replyBuf, 0); 1391 1392 if (!is_successful_reply(&reply)) { 1393 XDRInPacketDestroy(&reply); 1394 XDROutPacketDestroy(&call); 1395 return B_ERROR; 1396 } 1397 1398 status = XDRInPacketGetInt32(&reply); 1399 if (status != NFS_OK) { 1400 XDRInPacketDestroy(&reply); 1401 XDROutPacketDestroy(&call); 1402 //dprintf("nfs: rfsstat() error 0x%08lx\n", map_nfs_to_system_error(status)); 1403 return map_nfs_to_system_error(status); 1404 } 1405 1406 info->dev = ns->nsid; 1407 info->root = ns->rootid; 1408 info->flags = NFS_FS_FLAGS; 1409 1410 XDRInPacketGetInt32(&reply); // tsize 1411 1412 info->block_size = XDRInPacketGetInt32(&reply); 1413 info->io_size = 8192; 1414 info->total_blocks = XDRInPacketGetInt32(&reply); 1415 info->free_blocks = XDRInPacketGetInt32(&reply); 1416 info->total_nodes = 100; 1417 info->free_nodes = 100; 1418 strcpy(info->volume_name, "nfs://"); 1419 strcat(info->volume_name, ns->params.server); 1420 strcat(info->volume_name, ns->params._export); 1421 strcpy(info->fsh_name, "nfs"); 1422 1423 XDRInPacketDestroy(&reply); 1424 XDROutPacketDestroy(&call); 1425 return B_OK; 1426 } 1427 1428 1429 static status_t 1430 fs_open(fs_volume *_volume, fs_vnode *_node, int omode, void **_cookie) 1431 { 1432 fs_nspace *ns; 1433 fs_node *node; 1434 struct stat st; 1435 status_t result; 1436 fs_file_cookie **cookie; 1437 1438 ns = _volume->private_volume; 1439 node = _node->private_node; 1440 cookie = (fs_file_cookie **)_cookie; 1441 1442 if ((result = nfs_getattr(ns, &node->fhandle, &st)) < B_OK) 1443 return result; 1444 1445 if (S_ISDIR(st.st_mode)) { 1446 /* permit opening of directories */ 1447 if (conf_allow_dir_open) { 1448 *cookie = NULL; 1449 return B_OK; 1450 } else 1451 return EISDIR; 1452 } 1453 1454 *cookie = (fs_file_cookie *)malloc(sizeof(fs_file_cookie)); 1455 (*cookie)->omode = omode; 1456 (*cookie)->original_size = st.st_size; 1457 (*cookie)->st = st; 1458 1459 return B_OK; 1460 } 1461 1462 1463 static status_t 1464 fs_close(fs_volume *_volume, fs_vnode *_node, void *cookie) 1465 { 1466 (void) _volume; 1467 (void) _node; 1468 (void) cookie; 1469 /* //XXX:mmu_man:why that ?? makes Tracker go nuts updating the stats 1470 if ((cookie->omode & O_RDWR)||(cookie->omode & O_WRONLY)) 1471 return my_notify_listener (B_STAT_CHANGED,ns->nsid,0,0,node->vnid,NULL); 1472 */ 1473 return B_OK; 1474 } 1475 1476 1477 static status_t 1478 fs_free_cookie(fs_volume *_volume, fs_vnode *_node, void *cookie) 1479 { 1480 (void) _volume; 1481 (void) _node; 1482 free(cookie); 1483 return B_OK; 1484 } 1485 1486 1487 static status_t 1488 fs_read(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos, 1489 void *buf, size_t *len) 1490 { 1491 fs_nspace *ns; 1492 fs_node *node; 1493 fs_file_cookie *cookie; 1494 size_t max = *len; 1495 *len = 0; 1496 1497 ns = _volume->private_volume; 1498 node = _node->private_node; 1499 cookie = (fs_file_cookie *)_cookie; 1500 1501 if (!cookie) 1502 return EISDIR; /* do not permit reading of directories */ 1503 1504 while ((*len) < max) { 1505 size_t count = min_c(NFS_MAXDATA, max - (*len)); 1506 struct XDROutPacket call; 1507 struct XDRInPacket reply; 1508 int32 status; 1509 uint8 *replyBuf; 1510 struct stat st; 1511 size_t readbytes; 1512 1513 XDROutPacketInit(&call); 1514 XDRInPacketInit(&reply); 1515 1516 XDROutPacketAddFixed(&call, &node->fhandle.opaque, NFS_FHSIZE); 1517 XDROutPacketAddInt32(&call, pos); 1518 XDROutPacketAddInt32(&call, count); 1519 XDROutPacketAddInt32(&call, 0); 1520 1521 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 1522 NFSPROC_READ, &call); 1523 if (replyBuf == NULL) { 1524 XDRInPacketDestroy(&reply); 1525 XDROutPacketDestroy(&call); 1526 return B_ERROR; 1527 } 1528 1529 XDRInPacketSetTo(&reply, replyBuf, 0); 1530 1531 if (!is_successful_reply(&reply)) { 1532 XDRInPacketDestroy(&reply); 1533 XDROutPacketDestroy(&call); 1534 return B_ERROR; 1535 } 1536 1537 status = XDRInPacketGetInt32(&reply); 1538 if (status != NFS_OK) { 1539 XDRInPacketDestroy(&reply); 1540 XDROutPacketDestroy(&call); 1541 return map_nfs_to_system_error(status); 1542 } 1543 1544 get_nfs_attr(&reply, &st); 1545 cookie->st = st; 1546 1547 readbytes = XDRInPacketGetDynamic(&reply, buf); 1548 1549 buf = (char *)buf + readbytes; 1550 (*len) += readbytes; 1551 pos += readbytes; 1552 1553 XDRInPacketDestroy(&reply); 1554 XDROutPacketDestroy(&call); 1555 1556 if (pos >= st.st_size) 1557 break; 1558 } 1559 1560 return B_OK; 1561 } 1562 1563 1564 static status_t 1565 fs_write(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos, 1566 const void *buf, size_t *len) 1567 { 1568 fs_nspace *ns; 1569 fs_node *node; 1570 fs_file_cookie *cookie; 1571 size_t bytesWritten = 0; 1572 1573 ns = _volume->private_volume; 1574 node = _node->private_node; 1575 cookie = (fs_file_cookie *)_cookie; 1576 1577 if (!cookie) 1578 return EISDIR; /* do not permit reading of directories */ 1579 if (cookie->omode & O_APPEND) 1580 pos += cookie->original_size; 1581 1582 while (bytesWritten < *len) { 1583 size_t count = min_c(NFS_MAXDATA,(*len) - bytesWritten); 1584 1585 struct XDROutPacket call; 1586 struct XDRInPacket reply; 1587 int32 status; 1588 uint8 *replyBuf; 1589 struct stat st; 1590 1591 XDROutPacketInit(&call); 1592 XDRInPacketInit(&reply); 1593 1594 XDROutPacketAddFixed(&call, &node->fhandle.opaque, NFS_FHSIZE); 1595 XDROutPacketAddInt32(&call, 0); 1596 XDROutPacketAddInt32(&call, pos + bytesWritten); 1597 XDROutPacketAddInt32(&call, 0); 1598 XDROutPacketAddDynamic(&call, (const char *)buf + bytesWritten, count); 1599 1600 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 1601 NFSPROC_WRITE, &call); 1602 1603 if (!replyBuf) { 1604 XDRInPacketDestroy(&reply); 1605 XDROutPacketDestroy(&call); 1606 return B_ERROR; 1607 } 1608 1609 XDRInPacketSetTo(&reply, replyBuf, 0); 1610 1611 if (!is_successful_reply(&reply)) { 1612 XDRInPacketDestroy(&reply); 1613 XDROutPacketDestroy(&call); 1614 return B_ERROR; 1615 } 1616 1617 status = XDRInPacketGetInt32(&reply); 1618 1619 if (status != NFS_OK) { 1620 XDRInPacketDestroy(&reply); 1621 XDROutPacketDestroy(&call); 1622 return map_nfs_to_system_error(status); 1623 } 1624 1625 get_nfs_attr(&reply, &st); 1626 1627 cookie->st = st; 1628 1629 bytesWritten += count; 1630 1631 XDRInPacketDestroy(&reply); 1632 XDROutPacketDestroy(&call); 1633 } 1634 1635 return B_OK; 1636 } 1637 1638 1639 static status_t 1640 fs_wstat(fs_volume *_volume, fs_vnode *_node, const struct stat *st, uint32 mask) 1641 { 1642 fs_nspace *ns; 1643 fs_node *node; 1644 struct XDROutPacket call; 1645 struct XDRInPacket reply; 1646 1647 uint8 *replyBuf; 1648 int32 status; 1649 1650 ns = _volume->private_volume; 1651 node = _node->private_node; 1652 1653 XDROutPacketInit(&call); 1654 XDRInPacketInit(&reply); 1655 1656 XDROutPacketAddFixed(&call,node->fhandle.opaque,NFS_FHSIZE); 1657 1658 XDROutPacketAddInt32(&call, (mask & WSTAT_MODE) ? st->st_mode : -1); 1659 XDROutPacketAddInt32(&call, (mask & WSTAT_UID) ? st->st_uid : -1); 1660 XDROutPacketAddInt32(&call, (mask & WSTAT_GID) ? st->st_gid : -1); 1661 XDROutPacketAddInt32(&call, (mask & WSTAT_SIZE) ? st->st_size : -1); 1662 XDROutPacketAddInt32(&call, (mask & WSTAT_ATIME) ? st->st_atime : -1); 1663 XDROutPacketAddInt32(&call, (mask & WSTAT_ATIME) ? 0 : -1); 1664 XDROutPacketAddInt32(&call, (mask & WSTAT_MTIME) ? st->st_mtime : -1); 1665 XDROutPacketAddInt32(&call, (mask & WSTAT_MTIME) ? 0 : -1); 1666 1667 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 1668 NFSPROC_SETATTR, &call); 1669 1670 if (!replyBuf) { 1671 XDRInPacketDestroy(&reply); 1672 XDROutPacketDestroy(&call); 1673 return EHOSTUNREACH; 1674 } 1675 1676 XDRInPacketSetTo(&reply, replyBuf, 0); 1677 1678 if (!is_successful_reply(&reply)) { 1679 XDRInPacketDestroy(&reply); 1680 XDROutPacketDestroy(&call); 1681 return B_ERROR; 1682 } 1683 1684 status = XDRInPacketGetInt32(&reply); 1685 1686 if (status != NFS_OK) 1687 return map_nfs_to_system_error(status); 1688 1689 XDRInPacketDestroy(&reply); 1690 XDROutPacketDestroy(&call); 1691 1692 return notify_stat_changed(_volume->id, -1, node->vnid, mask); 1693 } 1694 1695 static status_t 1696 fs_wfsstat(fs_volume *_volume, const struct fs_info *info, uint32 mask) 1697 { 1698 (void) _volume; 1699 (void) info; 1700 (void) mask; 1701 return B_OK; 1702 } 1703 1704 static status_t 1705 fs_create(fs_volume *_volume, fs_vnode *_dir, const char *name, int omode, 1706 int perms, void **_cookie, ino_t *vnid) 1707 { 1708 nfs_fhandle fhandle; 1709 struct stat st; 1710 fs_file_cookie **cookie; 1711 1712 fs_nspace *ns; 1713 fs_node *dir; 1714 1715 status_t result; 1716 1717 ns = _volume->private_volume; 1718 dir = _dir->private_node; 1719 cookie = (fs_file_cookie **)_cookie; 1720 1721 result = nfs_lookup(ns,&dir->fhandle,name,&fhandle,&st); 1722 1723 if (result == B_OK) { 1724 void *dummy; 1725 fs_node *newNode = (fs_node *)malloc(sizeof(fs_node)); 1726 if (newNode == NULL) 1727 return B_NO_MEMORY; 1728 1729 newNode->fhandle = fhandle; 1730 newNode->vnid = st.st_ino; 1731 newNode->mode = st.st_mode; 1732 insert_node(ns, newNode); 1733 1734 *vnid = st.st_ino; 1735 1736 if ((result = get_vnode(_volume,*vnid,&dummy)) < B_OK) 1737 return result; 1738 1739 if (S_ISDIR(st.st_mode)) 1740 return EISDIR; 1741 1742 if (omode & O_EXCL) 1743 return EEXIST; 1744 1745 if (omode & O_TRUNC) 1746 { 1747 if ((result = nfs_truncate_file(ns, &fhandle, NULL)) < B_OK) 1748 return result; 1749 } 1750 1751 *cookie=(fs_file_cookie *)malloc(sizeof(fs_file_cookie)); 1752 if (*cookie == NULL) 1753 return B_NO_MEMORY; 1754 1755 (*cookie)->omode=omode; 1756 (*cookie)->original_size=st.st_size; 1757 (*cookie)->st=st; 1758 1759 return B_OK; 1760 } else if (result != ENOENT) { 1761 return result; 1762 } else { 1763 struct XDROutPacket call; 1764 struct XDRInPacket reply; 1765 1766 uint8 *replyBuf; 1767 int32 status; 1768 1769 fs_node *newNode; 1770 1771 if (!(omode & O_CREAT)) 1772 return ENOENT; 1773 1774 XDROutPacketInit(&call); 1775 XDRInPacketInit(&reply); 1776 1777 XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE); 1778 XDROutPacketAddString(&call, name); 1779 XDROutPacketAddInt32(&call, perms | S_IFREG); 1780 XDROutPacketAddInt32(&call, -1); 1781 XDROutPacketAddInt32(&call, -1); 1782 XDROutPacketAddInt32(&call, 0); 1783 XDROutPacketAddInt32(&call, time(NULL)); 1784 XDROutPacketAddInt32(&call, 0); 1785 XDROutPacketAddInt32(&call, time(NULL)); 1786 XDROutPacketAddInt32(&call, 0); 1787 1788 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 1789 NFSPROC_CREATE, &call); 1790 1791 if (!replyBuf) { 1792 XDRInPacketDestroy(&reply); 1793 XDROutPacketDestroy(&call); 1794 return B_ERROR; 1795 } 1796 1797 XDRInPacketSetTo(&reply, replyBuf, 0); 1798 1799 if (!is_successful_reply(&reply)) { 1800 XDRInPacketDestroy(&reply); 1801 XDROutPacketDestroy(&call); 1802 return B_ERROR; 1803 } 1804 1805 status = XDRInPacketGetInt32(&reply); 1806 1807 if (status != NFS_OK) { 1808 XDRInPacketDestroy(&reply); 1809 XDROutPacketDestroy(&call); 1810 return map_nfs_to_system_error(status); 1811 } 1812 1813 XDRInPacketGetFixed(&reply, fhandle.opaque, NFS_FHSIZE); 1814 1815 get_nfs_attr(&reply,&st); 1816 1817 newNode = (fs_node *)malloc(sizeof(fs_node)); 1818 if (newNode == NULL) { 1819 XDRInPacketDestroy(&reply); 1820 XDROutPacketDestroy(&call); 1821 return B_NO_MEMORY; 1822 } 1823 newNode->fhandle = fhandle; 1824 newNode->vnid = st.st_ino; 1825 newNode->mode = st.st_mode; 1826 1827 insert_node (ns, newNode); 1828 1829 *vnid = st.st_ino; 1830 *cookie = (fs_file_cookie *)malloc(sizeof(fs_file_cookie)); 1831 if (*cookie == NULL) { 1832 XDRInPacketDestroy(&reply); 1833 XDROutPacketDestroy(&call); 1834 return B_NO_MEMORY; 1835 } 1836 (*cookie)->omode = omode; 1837 (*cookie)->original_size = st.st_size; 1838 (*cookie)->st = st; 1839 1840 result = new_vnode(_volume, *vnid, newNode, &sNFSVnodeOps); 1841 1842 if (result < B_OK) { 1843 XDRInPacketDestroy(&reply); 1844 XDROutPacketDestroy(&call); 1845 return result; 1846 } 1847 1848 XDRInPacketDestroy(&reply); 1849 XDROutPacketDestroy(&call); 1850 return notify_entry_created(_volume->id, dir->vnid, name, *vnid); 1851 } 1852 } 1853 1854 1855 static status_t 1856 fs_unlink(fs_volume *_volume, fs_vnode *_dir, const char *name) 1857 { 1858 status_t result; 1859 fs_nspace *ns; 1860 fs_node *dir; 1861 fs_node *newNode; 1862 fs_node *dummy; 1863 1864 struct XDROutPacket call; 1865 struct XDRInPacket reply; 1866 1867 struct stat st; 1868 nfs_fhandle fhandle; 1869 uint8 *replyBuf; 1870 1871 int32 status; 1872 1873 ns = _volume->private_volume; 1874 dir = _dir->private_node; 1875 1876 XDROutPacketInit(&call); 1877 XDRInPacketInit(&reply); 1878 1879 if ((result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st)) < B_OK) { 1880 XDRInPacketDestroy(&reply); 1881 XDROutPacketDestroy(&call); 1882 return result; 1883 } 1884 1885 newNode = (fs_node *)malloc(sizeof(fs_node)); 1886 if (newNode == NULL) { 1887 XDRInPacketDestroy(&reply); 1888 XDROutPacketDestroy(&call); 1889 return B_NO_MEMORY; 1890 } 1891 newNode->fhandle = fhandle; 1892 newNode->vnid = st.st_ino; 1893 newNode->mode = st.st_mode; 1894 1895 insert_node(ns, newNode); 1896 1897 if ((result = get_vnode(_volume, st.st_ino, (void **)&dummy)) < B_OK) { 1898 XDRInPacketDestroy(&reply); 1899 XDROutPacketDestroy(&call); 1900 return result; 1901 } 1902 1903 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) { 1904 XDRInPacketDestroy(&reply); 1905 XDROutPacketDestroy(&call); 1906 return EISDIR; 1907 } 1908 1909 if ((result=remove_vnode(_volume,st.st_ino)) < B_OK) { 1910 XDRInPacketDestroy(&reply); 1911 XDROutPacketDestroy(&call); 1912 return result; 1913 } 1914 1915 if ((result=put_vnode(_volume, st.st_ino)) < B_OK) { 1916 XDRInPacketDestroy(&reply); 1917 XDROutPacketDestroy(&call); 1918 return result; 1919 } 1920 1921 XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE); 1922 XDROutPacketAddString(&call, name); 1923 1924 replyBuf=send_rpc_call (ns,&ns->nfsAddr,NFS_PROGRAM,NFS_VERSION,NFSPROC_REMOVE,&call); 1925 1926 if (!replyBuf) { 1927 XDRInPacketDestroy(&reply); 1928 XDROutPacketDestroy(&call); 1929 return EHOSTUNREACH; 1930 } 1931 1932 XDRInPacketSetTo(&reply, replyBuf, 0); 1933 1934 if (!is_successful_reply(&reply)) { 1935 XDRInPacketDestroy(&reply); 1936 XDROutPacketDestroy(&call); 1937 return B_ERROR; 1938 } 1939 1940 status = XDRInPacketGetInt32(&reply); 1941 1942 if (status != NFS_OK) { 1943 XDRInPacketDestroy(&reply); 1944 XDROutPacketDestroy(&call); 1945 return map_nfs_to_system_error(status); 1946 } 1947 1948 XDRInPacketDestroy(&reply); 1949 XDROutPacketDestroy(&call); 1950 1951 return notify_entry_removed(_volume->id, dir->vnid, name, st.st_ino); 1952 } 1953 1954 1955 static status_t 1956 fs_remove_vnode(fs_volume *_volume, fs_vnode *_node, bool r) 1957 { 1958 fs_nspace *ns = _volume->private_volume; 1959 fs_node *node = _node->private_node; 1960 1961 (void) r; 1962 1963 remove_node (ns, node->vnid); 1964 1965 return B_OK; 1966 } 1967 1968 1969 static status_t 1970 fs_mkdir(fs_volume *_volume, fs_vnode *_dir, const char *name, int perms) 1971 { 1972 fs_nspace *ns; 1973 fs_node *dir; 1974 1975 nfs_fhandle fhandle; 1976 struct stat st; 1977 fs_node *newNode; 1978 1979 status_t result; 1980 uint8 *replyBuf; 1981 int32 status; 1982 1983 struct XDROutPacket call; 1984 struct XDRInPacket reply; 1985 1986 ns = _volume->private_volume; 1987 dir = _dir->private_node; 1988 1989 XDROutPacketInit(&call); 1990 XDRInPacketInit(&reply); 1991 1992 result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st); 1993 1994 if (result == B_OK) { 1995 //void *dummy; 1996 1997 XDRInPacketDestroy(&reply); 1998 XDROutPacketDestroy(&call); 1999 // XXX: either OK or not get_vnode !!! ?? 2000 //if ((result=get_vnode(_volume,st.st_ino,&dummy))<B_OK) 2001 // return result; 2002 return EEXIST; 2003 } else if (result != ENOENT) { 2004 XDRInPacketDestroy(&reply); 2005 XDROutPacketDestroy(&call); 2006 return result; 2007 } 2008 2009 XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE); 2010 XDROutPacketAddString(&call, name); 2011 XDROutPacketAddInt32(&call, perms | S_IFDIR); 2012 XDROutPacketAddInt32(&call, -1); 2013 XDROutPacketAddInt32(&call, -1); 2014 XDROutPacketAddInt32(&call, -1); 2015 XDROutPacketAddInt32(&call, time(NULL)); 2016 XDROutPacketAddInt32(&call, 0); 2017 XDROutPacketAddInt32(&call, time(NULL)); 2018 XDROutPacketAddInt32(&call, 0); 2019 2020 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 2021 NFSPROC_MKDIR, &call); 2022 2023 if (!replyBuf) { 2024 XDRInPacketDestroy(&reply); 2025 XDROutPacketDestroy(&call); 2026 return B_ERROR; 2027 } 2028 2029 XDRInPacketSetTo(&reply, replyBuf, 0); 2030 2031 if (!is_successful_reply(&reply)) { 2032 XDRInPacketDestroy(&reply); 2033 XDROutPacketDestroy(&call); 2034 return B_ERROR; 2035 } 2036 2037 status = XDRInPacketGetInt32(&reply); 2038 2039 if (status != NFS_OK) { 2040 XDROutPacketDestroy(&call); 2041 return map_nfs_to_system_error(status); 2042 } 2043 2044 XDRInPacketGetFixed(&reply, fhandle.opaque, NFS_FHSIZE); 2045 2046 get_nfs_attr(&reply, &st); 2047 2048 newNode=(fs_node *)malloc(sizeof(fs_node)); 2049 if (newNode == NULL) { 2050 XDRInPacketDestroy(&reply); 2051 XDROutPacketDestroy(&call); 2052 return B_NO_MEMORY; 2053 } 2054 newNode->fhandle = fhandle; 2055 newNode->vnid = st.st_ino; 2056 newNode->mode = st.st_mode; 2057 2058 insert_node(ns, newNode); 2059 2060 XDRInPacketDestroy(&reply); 2061 XDROutPacketDestroy(&call); 2062 2063 return notify_entry_created(_volume->id, dir->vnid, name, st.st_ino); 2064 } 2065 2066 static status_t 2067 fs_rename(fs_volume *_volume, fs_vnode *_olddir, const char *oldname, 2068 fs_vnode *_newdir, const char *newname) 2069 { 2070 struct stat st; 2071 nfs_fhandle fhandle; 2072 status_t result; 2073 struct XDROutPacket call; 2074 struct XDRInPacket reply; 2075 int32 status; 2076 uint8 *replyBuf; 2077 fs_nspace *ns; 2078 fs_node *olddir; 2079 fs_node *newdir; 2080 2081 ns = _volume->private_volume; 2082 olddir = _olddir->private_node; 2083 newdir = _newdir->private_node; 2084 2085 XDROutPacketInit(&call); 2086 XDRInPacketInit(&reply); 2087 2088 if ((result = nfs_lookup(ns, &newdir->fhandle, newname, &fhandle, &st)) 2089 == B_OK) { 2090 if (S_ISREG(st.st_mode)) 2091 result = fs_unlink (_volume,_newdir,newname); 2092 else 2093 result = fs_rmdir (_volume,_newdir,newname); 2094 2095 if (result < B_OK) { 2096 XDRInPacketDestroy (&reply); 2097 XDROutPacketDestroy (&call); 2098 return result; 2099 } 2100 } 2101 2102 if ((result = nfs_lookup(ns, &olddir->fhandle, oldname, &fhandle, &st)) 2103 < B_OK) { 2104 XDRInPacketDestroy(&reply); 2105 XDROutPacketDestroy(&call); 2106 return result; 2107 } 2108 2109 XDROutPacketAddFixed(&call, olddir->fhandle.opaque, NFS_FHSIZE); 2110 XDROutPacketAddString(&call, oldname); 2111 XDROutPacketAddFixed(&call, newdir->fhandle.opaque, NFS_FHSIZE); 2112 XDROutPacketAddString(&call, newname); 2113 2114 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 2115 NFSPROC_RENAME, &call); 2116 2117 if (!replyBuf) { 2118 XDRInPacketDestroy(&reply); 2119 XDROutPacketDestroy(&call); 2120 return EHOSTUNREACH; 2121 } 2122 2123 XDRInPacketSetTo(&reply, replyBuf, 0); 2124 2125 if (!is_successful_reply(&reply)) { 2126 XDRInPacketDestroy(&reply); 2127 XDROutPacketDestroy(&call); 2128 return B_ERROR; 2129 } 2130 2131 status = XDRInPacketGetInt32(&reply); 2132 2133 if (status != NFS_OK) { 2134 XDRInPacketDestroy(&reply); 2135 XDROutPacketDestroy(&call); 2136 return map_nfs_to_system_error(status); 2137 } 2138 2139 XDRInPacketDestroy (&reply); 2140 XDROutPacketDestroy (&call); 2141 2142 return notify_entry_moved(_volume->id, olddir->vnid, oldname, newdir->vnid, 2143 newname, st.st_ino); 2144 } 2145 2146 2147 static status_t 2148 fs_rmdir(fs_volume *_volume, fs_vnode *_dir, const char *name) 2149 { 2150 fs_nspace *ns; 2151 fs_node *dir; 2152 2153 status_t result; 2154 fs_node *newNode; 2155 fs_node *dummy; 2156 struct XDROutPacket call; 2157 struct XDRInPacket reply; 2158 int32 status; 2159 uint8 *replyBuf; 2160 2161 struct stat st; 2162 nfs_fhandle fhandle; 2163 2164 ns = _volume->private_volume; 2165 dir = _dir->private_node; 2166 2167 XDROutPacketInit(&call); 2168 XDRInPacketInit(&reply); 2169 2170 if ((result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st)) < B_OK) { 2171 XDRInPacketDestroy(&reply); 2172 XDROutPacketDestroy(&call); 2173 return result; 2174 } 2175 2176 newNode = (fs_node *)malloc(sizeof(fs_node)); 2177 if (newNode == NULL) { 2178 XDRInPacketDestroy(&reply); 2179 XDROutPacketDestroy(&call); 2180 return B_NO_MEMORY; 2181 } 2182 newNode->fhandle = fhandle; 2183 newNode->vnid = st.st_ino; 2184 newNode->mode = st.st_mode; 2185 2186 insert_node(ns, newNode); 2187 2188 if ((result = get_vnode(_volume, st.st_ino, (void **)&dummy)) < B_OK) { 2189 XDRInPacketDestroy(&reply); 2190 XDROutPacketDestroy(&call); 2191 return result; 2192 } 2193 2194 if (!S_ISDIR(st.st_mode)) { 2195 XDRInPacketDestroy(&reply); 2196 XDROutPacketDestroy(&call); 2197 return ENOTDIR; 2198 } 2199 2200 if ((result = remove_vnode(_volume, st.st_ino)) < B_OK) { 2201 XDRInPacketDestroy(&reply); 2202 XDROutPacketDestroy(&call); 2203 return result; 2204 } 2205 2206 if ((result = put_vnode(_volume, st.st_ino)) < B_OK) { 2207 XDRInPacketDestroy(&reply); 2208 XDROutPacketDestroy(&call); 2209 return result; 2210 } 2211 2212 XDROutPacketAddFixed (&call, dir->fhandle.opaque, NFS_FHSIZE); 2213 XDROutPacketAddString(&call, name); 2214 2215 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 2216 NFSPROC_RMDIR, &call); 2217 2218 if (!replyBuf) { 2219 XDRInPacketDestroy(&reply); 2220 XDROutPacketDestroy(&call); 2221 return EHOSTUNREACH; 2222 } 2223 2224 XDRInPacketSetTo (&reply,replyBuf,0); 2225 2226 if (!is_successful_reply(&reply)) { 2227 XDRInPacketDestroy(&reply); 2228 XDROutPacketDestroy(&call); 2229 return B_ERROR; 2230 } 2231 2232 status = XDRInPacketGetInt32(&reply); 2233 2234 if (status != NFS_OK) { 2235 XDRInPacketDestroy(&reply); 2236 XDROutPacketDestroy(&call); 2237 return map_nfs_to_system_error(status); 2238 } 2239 2240 XDRInPacketDestroy(&reply); 2241 XDROutPacketDestroy(&call); 2242 return notify_entry_removed(_volume->id, dir->vnid, name, st.st_ino); 2243 } 2244 2245 2246 static status_t 2247 fs_readlink(fs_volume *_volume, fs_vnode *_node, char *buf, size_t *bufsize) 2248 { 2249 struct XDROutPacket call; 2250 uint8 *replyBuf; 2251 int32 status; 2252 size_t length; 2253 char data[NFS_MAXPATHLEN]; 2254 struct XDRInPacket reply; 2255 fs_nspace *ns; 2256 fs_node *node; 2257 2258 ns = _volume->private_volume; 2259 node = _node->private_node; 2260 2261 XDROutPacketInit(&call); 2262 XDRInPacketInit(&reply); 2263 2264 XDROutPacketAddFixed(&call, node->fhandle.opaque, NFS_FHSIZE); 2265 2266 replyBuf = send_rpc_call(ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 2267 NFSPROC_READLINK, &call); 2268 2269 if (!replyBuf) { 2270 XDRInPacketDestroy(&reply); 2271 XDROutPacketDestroy(&call); 2272 return EHOSTUNREACH; 2273 } 2274 2275 XDRInPacketSetTo (&reply, replyBuf, 0); 2276 2277 if (!is_successful_reply(&reply)) { 2278 XDRInPacketDestroy(&reply); 2279 XDROutPacketDestroy(&call); 2280 return B_ERROR; 2281 } 2282 2283 status = XDRInPacketGetInt32(&reply); 2284 2285 if (status != NFS_OK) { 2286 XDRInPacketDestroy(&reply); 2287 XDROutPacketDestroy (&call); 2288 return map_nfs_to_system_error(status); 2289 } 2290 2291 length = XDRInPacketGetDynamic(&reply, data); 2292 2293 length = min_c(length, *bufsize); 2294 memcpy(buf, data, length); 2295 *bufsize = length; 2296 2297 XDRInPacketDestroy(&reply); 2298 XDROutPacketDestroy(&call); 2299 return B_OK; 2300 } 2301 2302 static status_t 2303 fs_symlink(fs_volume *_volume, fs_vnode *_dir, const char *name, 2304 const char *path, int mode) 2305 { 2306 fs_nspace *ns; 2307 fs_node *dir; 2308 nfs_fhandle fhandle; 2309 struct stat st; 2310 struct XDROutPacket call; 2311 struct XDRInPacket reply; 2312 status_t result; 2313 uint8 *replyBuf; 2314 int32 status; 2315 fs_node *newNode; 2316 2317 ns = _volume->private_volume; 2318 dir = _dir->private_node; 2319 2320 XDROutPacketInit(&call); 2321 XDRInPacketInit(&reply); 2322 2323 result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st); 2324 2325 if (result == B_OK) { 2326 void *dummy; 2327 if ((result = get_vnode(_volume, st.st_ino, &dummy)) < B_OK) 2328 return result; 2329 2330 XDRInPacketDestroy(&reply); 2331 XDROutPacketDestroy(&call); 2332 return EEXIST; 2333 } else if (result != ENOENT) { 2334 XDRInPacketDestroy(&reply); 2335 XDROutPacketDestroy(&call); 2336 return result; 2337 } 2338 2339 XDROutPacketAddFixed(&call, dir->fhandle.opaque, NFS_FHSIZE); 2340 XDROutPacketAddString(&call, name); 2341 XDROutPacketAddString(&call, path); 2342 XDROutPacketAddInt32(&call, S_IFLNK); 2343 XDROutPacketAddInt32(&call, -1); 2344 XDROutPacketAddInt32(&call, -1); 2345 XDROutPacketAddInt32(&call, -1); 2346 XDROutPacketAddInt32(&call, time(NULL)); 2347 XDROutPacketAddInt32(&call, 0); 2348 XDROutPacketAddInt32(&call, time(NULL)); 2349 XDROutPacketAddInt32(&call, 0); 2350 2351 replyBuf = send_rpc_call (ns, &ns->nfsAddr, NFS_PROGRAM, NFS_VERSION, 2352 NFSPROC_SYMLINK, &call); 2353 2354 if (!replyBuf) { 2355 XDRInPacketDestroy(&reply); 2356 XDROutPacketDestroy(&call); 2357 return B_ERROR; 2358 } 2359 2360 XDRInPacketSetTo(&reply, replyBuf, 0); 2361 2362 if (!is_successful_reply(&reply)) { 2363 XDRInPacketDestroy(&reply); 2364 XDROutPacketDestroy(&call); 2365 return B_ERROR; 2366 } 2367 2368 status = XDRInPacketGetInt32(&reply); 2369 /* if (status!=NFS_OK) 2370 return map_nfs_to_system_error(status); 2371 2372 ignore status here, weird thing, nfsservers that is 2373 */ 2374 (void)status; 2375 2376 result = nfs_lookup(ns, &dir->fhandle, name, &fhandle, &st); 2377 2378 if (result < B_OK) { 2379 XDRInPacketDestroy(&reply); 2380 XDROutPacketDestroy(&call); 2381 return result; 2382 } 2383 2384 newNode = (fs_node *)malloc(sizeof(fs_node)); 2385 if (newNode == NULL) { 2386 XDRInPacketDestroy(&reply); 2387 XDROutPacketDestroy(&call); 2388 return B_NO_MEMORY; 2389 } 2390 newNode->fhandle = fhandle; 2391 newNode->vnid = st.st_ino; 2392 2393 insert_node(ns, newNode); 2394 2395 result = notify_entry_created (_volume->id, dir->vnid, name, st.st_ino); 2396 2397 XDRInPacketDestroy(&reply); 2398 XDROutPacketDestroy(&call); 2399 return result; 2400 } 2401 2402 2403 static status_t 2404 fs_access(fs_volume *_volume, fs_vnode *node, int mode) 2405 { 2406 (void) _volume; 2407 (void) node; 2408 (void) mode; 2409 /* XXX */ 2410 return B_OK; 2411 } 2412 2413 2414 static status_t 2415 nfs_std_ops(int32 op, ...) 2416 { 2417 switch (op) { 2418 case B_MODULE_INIT: 2419 return B_OK; 2420 case B_MODULE_UNINIT: 2421 return B_OK; 2422 2423 default: 2424 return B_ERROR; 2425 } 2426 } 2427 2428 2429 fs_volume_ops sNFSVolumeOps = { 2430 &fs_unmount, 2431 &fs_rfsstat, 2432 &fs_wfsstat, 2433 NULL, // no sync! 2434 &fs_read_vnode, 2435 2436 /* index directory & index operations */ 2437 NULL, // &fs_open_index_dir 2438 NULL, // &fs_close_index_dir 2439 NULL, // &fs_free_index_dir_cookie 2440 NULL, // &fs_read_index_dir 2441 NULL, // &fs_rewind_index_dir 2442 2443 NULL, // &fs_create_index 2444 NULL, // &fs_remove_index 2445 NULL, // &fs_stat_index 2446 2447 /* query operations */ 2448 NULL, // &fs_open_query, 2449 NULL, // &fs_close_query, 2450 NULL, // &fs_free_query_cookie, 2451 NULL, // &fs_read_query, 2452 NULL, // &fs_rewind_query, 2453 }; 2454 2455 2456 fs_vnode_ops sNFSVnodeOps = { 2457 /* vnode operations */ 2458 &fs_walk, 2459 NULL, // fs_get_vnode_name 2460 &fs_release_vnode, 2461 &fs_remove_vnode, 2462 2463 /* VM file access */ 2464 NULL, // &fs_can_page 2465 NULL, // &fs_read_pages 2466 NULL, // &fs_write_pages 2467 2468 NULL, // io() 2469 NULL, // cancel_io() 2470 2471 NULL, // &fs_get_file_map, 2472 2473 NULL, // &fs_ioctl 2474 NULL, // &fs_setflags, 2475 NULL, // &fs_select 2476 NULL, // &fs_deselect 2477 NULL, // &fs_fsync 2478 2479 &fs_readlink, 2480 &fs_symlink, 2481 2482 NULL, // &fs_link, 2483 &fs_unlink, 2484 &fs_rename, 2485 2486 &fs_access, 2487 &fs_rstat, 2488 &fs_wstat, 2489 NULL, // fs_preallocate() 2490 2491 /* file operations */ 2492 &fs_create, 2493 &fs_open, 2494 &fs_close, 2495 &fs_free_cookie, 2496 &fs_read, 2497 &fs_write, 2498 2499 /* directory operations */ 2500 &fs_mkdir, 2501 &fs_rmdir, 2502 &fs_opendir, 2503 &fs_closedir, 2504 &fs_free_dircookie, 2505 &fs_readdir, 2506 &fs_rewinddir, 2507 2508 /* attribute directory operations */ 2509 NULL, // &fs_open_attrdir, 2510 NULL, // &fs_close_attrdir, 2511 NULL, // &fs_free_attrdircookie, 2512 NULL, // &fs_read_attrdir, 2513 NULL, // &fs_rewind_attrdir, 2514 2515 /* attribute operations */ 2516 NULL, // &fs_create_attr 2517 NULL, // &fs_open_attr_h, 2518 NULL, // &fs_close_attr_h, 2519 NULL, // &fs_free_attr_cookie_h, 2520 NULL, // &fs_read_attr_h, 2521 NULL, // &fs_write_attr_h, 2522 2523 NULL, // &fs_read_attr_stat_h, 2524 NULL, // &fs_write_attr_stat 2525 NULL, // &fs_rename_attr 2526 NULL, // &fs_remove_attr 2527 }; 2528 2529 file_system_module_info sNFSFileSystem = { 2530 { 2531 "file_systems/nfs" B_CURRENT_FS_API_VERSION, 2532 0, 2533 nfs_std_ops, 2534 }, 2535 "nfs", // short name 2536 "Network File System v2", // pretty name 2537 B_DISK_SYSTEM_SUPPORTS_WRITING, // DDM flags 2538 2539 // scanning 2540 NULL, // fs_identify_partition, 2541 NULL, // fs_scan_partition, 2542 NULL, // fs_free_identify_partition_cookie, 2543 NULL, // free_partition_content_cookie() 2544 2545 &fs_mount, 2546 }; 2547 2548 module_info *modules[] = { 2549 (module_info *)&sNFSFileSystem, 2550 NULL, 2551 }; 2552