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