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