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