1 /* 2 * Copyright 2012 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Paweł Dziepak, pdziepak@quarnos.org 7 */ 8 9 10 #include <AutoDeleter.h> 11 12 #include "IdMap.h" 13 #include "Inode.h" 14 #include "NFS4Inode.h" 15 #include "Request.h" 16 17 18 status_t 19 NFS4Inode::GetChangeInfo(uint64* change, bool attrDir) 20 { 21 ASSERT(change != NULL); 22 23 uint32 attempt = 0; 24 do { 25 RPC::Server* serv = fFileSystem->Server(); 26 Request request(serv, fFileSystem); 27 RequestBuilder& req = request.Builder(); 28 29 if (attrDir) 30 req.PutFH(fInfo.fAttrDir); 31 else 32 req.PutFH(fInfo.fHandle); 33 34 Attribute attr[] = { FATTR4_CHANGE }; 35 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); 36 37 status_t result = request.Send(); 38 if (result != B_OK) 39 return result; 40 41 ReplyInterpreter& reply = request.Reply(); 42 43 if (HandleErrors(attempt, reply.NFS4Error(), serv)) 44 continue; 45 46 reply.PutFH(); 47 48 AttrValue* values; 49 uint32 count; 50 result = reply.GetAttr(&values, &count); 51 if (result != B_OK) 52 return result; 53 54 // FATTR4_CHANGE is mandatory 55 *change = values[0].fData.fValue64; 56 delete[] values; 57 58 return B_OK; 59 } while (true); 60 } 61 62 63 status_t 64 NFS4Inode::CommitWrites() 65 { 66 uint32 attempt = 0; 67 do { 68 RPC::Server* serv = fFileSystem->Server(); 69 Request request(serv, fFileSystem); 70 RequestBuilder& req = request.Builder(); 71 72 req.PutFH(fInfo.fHandle); 73 req.Commit(0, 0); 74 75 status_t result = request.Send(); 76 if (result != B_OK) 77 return result; 78 79 ReplyInterpreter& reply = request.Reply(); 80 81 if (HandleErrors(attempt, reply.NFS4Error(), serv)) 82 continue; 83 84 reply.PutFH(); 85 return reply.Commit(); 86 } while (true); 87 } 88 89 90 status_t 91 NFS4Inode::Access(uint32* allowed) 92 { 93 ASSERT(allowed != NULL); 94 95 uint32 attempt = 0; 96 do { 97 RPC::Server* serv = fFileSystem->Server(); 98 Request request(serv, fFileSystem); 99 RequestBuilder& req = request.Builder(); 100 101 req.PutFH(fInfo.fHandle); 102 req.Access(); 103 104 status_t result = request.Send(); 105 if (result != B_OK) 106 return result; 107 108 ReplyInterpreter& reply = request.Reply(); 109 110 if (HandleErrors(attempt, reply.NFS4Error(), serv)) 111 continue; 112 113 reply.PutFH(); 114 115 return reply.Access(NULL, allowed); 116 } while (true); 117 } 118 119 120 status_t 121 NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID, 122 FileHandle* handle, bool parent) 123 { 124 ASSERT(name != NULL); 125 126 uint32 attempt = 0; 127 do { 128 RPC::Server* serv = fFileSystem->Server(); 129 Request request(serv, fFileSystem); 130 RequestBuilder& req = request.Builder(); 131 132 (void)parent; // TODO: add support for named attributes 133 req.PutFH(fInfo.fHandle); 134 135 if (change != NULL) { 136 Attribute dirAttr[] = { FATTR4_CHANGE }; 137 req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute)); 138 } 139 140 if (!strcmp(name, "..")) 141 req.LookUpUp(); 142 else 143 req.LookUp(name); 144 145 if (handle != NULL) 146 req.GetFH(); 147 148 Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID }; 149 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); 150 151 status_t result = request.Send(); 152 if (result != B_OK) 153 return result; 154 155 ReplyInterpreter& reply = request.Reply(); 156 157 if (HandleErrors(attempt, reply.NFS4Error(), serv)) 158 continue; 159 160 reply.PutFH(); 161 162 AttrValue* values; 163 uint32 count; 164 if (change != NULL) { 165 result = reply.GetAttr(&values, &count); 166 if (result != B_OK) 167 return result; 168 169 *change = values[0].fData.fValue64; 170 delete[] values; 171 } 172 173 if (!strcmp(name, "..")) 174 result = reply.LookUpUp(); 175 else 176 result = reply.LookUp(); 177 if (result != B_OK) 178 return result; 179 180 if (handle != NULL) 181 reply.GetFH(handle); 182 183 result = reply.GetAttr(&values, &count); 184 if (result != B_OK) 185 return result; 186 187 // FATTR4_FSID is mandatory 188 FileSystemId* fsid 189 = reinterpret_cast<FileSystemId*>(values[0].fData.fPointer); 190 if (*fsid != fFileSystem->FsId()) { 191 delete[] values; 192 return B_ENTRY_NOT_FOUND; 193 } 194 195 if (fileID != NULL) { 196 if (count < 2 || values[1].fAttribute != FATTR4_FILEID) 197 *fileID = fFileSystem->AllocFileId(); 198 else 199 *fileID = values[1].fData.fValue64; 200 } 201 202 delete[] values; 203 204 return B_OK; 205 } while (true); 206 } 207 208 209 status_t 210 NFS4Inode::Link(Inode* dir, const char* name, ChangeInfo* changeInfo) 211 { 212 ASSERT(dir != NULL); 213 ASSERT(name != NULL); 214 ASSERT(changeInfo != NULL); 215 216 uint32 attempt = 0; 217 do { 218 RPC::Server* serv = fFileSystem->Server(); 219 Request request(serv, fFileSystem); 220 RequestBuilder& req = request.Builder(); 221 222 req.PutFH(fInfo.fHandle); 223 req.SaveFH(); 224 req.PutFH(dir->fInfo.fHandle); 225 req.Link(name); 226 227 status_t result = request.Send(); 228 if (result != B_OK) 229 return result; 230 231 ReplyInterpreter& reply = request.Reply(); 232 233 if (HandleErrors(attempt, reply.NFS4Error(), serv)) 234 continue; 235 236 reply.PutFH(); 237 reply.SaveFH(); 238 reply.PutFH(); 239 240 return reply.Link(&changeInfo->fBefore, &changeInfo->fAfter, 241 changeInfo->fAtomic); 242 } while (true); 243 } 244 245 246 status_t 247 NFS4Inode::ReadLink(void* buffer, size_t* length) 248 { 249 ASSERT(buffer != NULL); 250 ASSERT(length != NULL); 251 252 uint32 attempt = 0; 253 do { 254 RPC::Server* serv = fFileSystem->Server(); 255 Request request(serv, fFileSystem); 256 RequestBuilder& req = request.Builder(); 257 258 req.PutFH(fInfo.fHandle); 259 req.ReadLink(); 260 261 status_t result = request.Send(); 262 if (result != B_OK) 263 return result; 264 265 ReplyInterpreter& reply = request.Reply(); 266 267 if (HandleErrors(attempt, reply.NFS4Error(), serv)) 268 continue; 269 270 reply.PutFH(); 271 272 uint32 size; 273 result = reply.ReadLink(buffer, &size, *length); 274 *length = static_cast<size_t>(size); 275 276 return result; 277 } while (true); 278 } 279 280 281 status_t 282 NFS4Inode::GetStat(AttrValue** values, uint32* count, OpenAttrCookie* cookie) 283 { 284 ASSERT(values != NULL); 285 ASSERT(count != NULL); 286 287 uint32 attempt = 0; 288 do { 289 RPC::Server* serv = fFileSystem->Server(); 290 Request request(serv, fFileSystem); 291 RequestBuilder& req = request.Builder(); 292 293 if (cookie != NULL) 294 req.PutFH(cookie->fOpenState->fInfo.fHandle); 295 else 296 req.PutFH(fInfo.fHandle); 297 298 Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS, 299 FATTR4_OWNER, FATTR4_OWNER_GROUP, 300 FATTR4_TIME_ACCESS, FATTR4_TIME_CREATE, 301 FATTR4_TIME_METADATA, FATTR4_TIME_MODIFY }; 302 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); 303 304 status_t result = request.Send(cookie); 305 if (result != B_OK) 306 return result; 307 308 ReplyInterpreter& reply = request.Reply(); 309 310 if (HandleErrors(attempt, reply.NFS4Error(), serv)) 311 continue; 312 313 reply.PutFH(); 314 315 return reply.GetAttr(values, count); 316 } while (true); 317 } 318 319 320 status_t 321 NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount) 322 { 323 ASSERT(attrs != NULL); 324 325 uint32 attempt = 0; 326 do { 327 RPC::Server* serv = fFileSystem->Server(); 328 Request request(serv, fFileSystem); 329 RequestBuilder& req = request.Builder(); 330 331 if (state != NULL) { 332 req.PutFH(state->fInfo.fHandle); 333 req.SetAttr(state->fStateID, state->fStateSeq, attrs, attrCount); 334 } else { 335 req.PutFH(fInfo.fHandle); 336 req.SetAttr(NULL, 0, attrs, attrCount); 337 } 338 339 status_t result = request.Send(); 340 if (result != B_OK) 341 return result; 342 343 ReplyInterpreter& reply = request.Reply(); 344 345 if (HandleErrors(attempt, reply.NFS4Error(), serv)) 346 continue; 347 348 reply.PutFH(); 349 result = reply.SetAttr(); 350 351 if (result != B_OK) 352 return result; 353 354 return B_OK; 355 } while (true); 356 } 357 358 359 status_t 360 NFS4Inode::RenameNode(Inode* from, Inode* to, const char* fromName, 361 const char* toName, ChangeInfo* fromChange, ChangeInfo* toChange, 362 uint64* fileID, bool attribute) 363 { 364 ASSERT(from != NULL); 365 ASSERT(to != NULL); 366 ASSERT(fromName != NULL); 367 ASSERT(toName != NULL); 368 ASSERT(fromChange != NULL); 369 ASSERT(toChange != NULL); 370 371 uint32 attempt = 0; 372 do { 373 RPC::Server* server = from->fFileSystem->Server(); 374 Request request(server, from->fFileSystem); 375 RequestBuilder& req = request.Builder(); 376 377 if (attribute) 378 req.PutFH(from->fInfo.fAttrDir); 379 else 380 req.PutFH(from->fInfo.fHandle); 381 req.SaveFH(); 382 if (attribute) 383 req.PutFH(to->fInfo.fAttrDir); 384 else 385 req.PutFH(to->fInfo.fHandle); 386 req.Rename(fromName, toName); 387 388 if (!attribute) { 389 req.LookUp(toName); 390 Attribute attr[] = { FATTR4_FILEID }; 391 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); 392 } 393 394 status_t result = request.Send(); 395 if (result != B_OK) 396 return result; 397 398 ReplyInterpreter& reply = request.Reply(); 399 400 // If we have to wait, migrate to another server, etc then the first 401 // HandleErrors() will do that. However, if the file handles 402 // were invalid then we need to update both Inodes. 403 bool retry = from->HandleErrors(attempt, reply.NFS4Error(), server); 404 if (IsFileHandleInvalid(reply.NFS4Error())) 405 retry |= to->HandleErrors(attempt, reply.NFS4Error(), server); 406 if (retry) 407 continue; 408 409 reply.PutFH(); 410 reply.SaveFH(); 411 reply.PutFH(); 412 413 result = reply.Rename(&fromChange->fBefore, &fromChange->fAfter, 414 fromChange->fAtomic, &toChange->fBefore, &toChange->fAfter, 415 toChange->fAtomic); 416 if (result != B_OK) 417 return result; 418 419 if (!attribute) { 420 result = reply.LookUp(); 421 if (result != B_OK) 422 return result; 423 424 AttrValue* values; 425 uint32 count; 426 result = reply.GetAttr(&values, &count); 427 if (result != B_OK) 428 return result; 429 430 if (count == 0) 431 *fileID = from->fFileSystem->AllocFileId(); 432 else 433 *fileID = values[0].fData.fValue64; 434 435 delete[] values; 436 } 437 438 return B_OK; 439 } while (true); 440 } 441 442 443 status_t 444 NFS4Inode::CreateFile(const char* name, int mode, int perms, OpenState* state, 445 ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle, 446 OpenDelegationData* delegation) 447 { 448 ASSERT(name != NULL); 449 ASSERT(state != NULL); 450 ASSERT(changeInfo != NULL); 451 ASSERT(handle != NULL); 452 ASSERT(delegation != NULL); 453 454 bool confirm; 455 status_t result; 456 457 uint32 attempt = 0; 458 uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); 459 do { 460 state->fClientID = fFileSystem->NFSServer()->ClientId(); 461 462 RPC::Server* serv = fFileSystem->Server(); 463 Request request(serv, fFileSystem); 464 RequestBuilder& req = request.Builder(); 465 466 req.PutFH(fInfo.fHandle); 467 468 AttrValue cattr[2]; 469 uint32 i = 0; 470 if ((mode & O_TRUNC) == O_TRUNC) { 471 cattr[i].fAttribute = FATTR4_SIZE; 472 cattr[i].fFreePointer = false; 473 cattr[i].fData.fValue64 = 0; 474 i++; 475 } 476 cattr[i].fAttribute = FATTR4_MODE; 477 cattr[i].fFreePointer = false; 478 cattr[i].fData.fValue32 = perms; 479 i++; 480 481 req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), 482 state->fClientID, OPEN4_CREATE, fFileSystem->OpenOwner(), name, 483 cattr, i, (mode & O_EXCL) == O_EXCL); 484 485 req.GetFH(); 486 487 if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { 488 Attribute attr[] = { FATTR4_FILEID }; 489 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); 490 } 491 492 result = request.Send(); 493 if (result != B_OK) { 494 fFileSystem->OpenOwnerSequenceUnlock(sequence); 495 return result; 496 } 497 498 ReplyInterpreter& reply = request.Reply(); 499 500 result = reply.PutFH(); 501 if (result == B_OK) 502 sequence += IncrementSequence(reply.NFS4Error()); 503 504 if (HandleErrors(attempt, reply.NFS4Error(), serv, NULL, state, 505 &sequence)) { 506 continue; 507 } 508 509 result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, 510 delegation, changeInfo); 511 if (result != B_OK) { 512 fFileSystem->OpenOwnerSequenceUnlock(sequence); 513 return result; 514 } 515 516 reply.GetFH(handle); 517 518 if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { 519 AttrValue* values; 520 uint32 count; 521 result = reply.GetAttr(&values, &count); 522 if (result != B_OK) { 523 fFileSystem->OpenOwnerSequenceUnlock(sequence); 524 return result; 525 } 526 527 *fileID = values[0].fData.fValue64; 528 529 delete[] values; 530 } else 531 *fileID = fFileSystem->AllocFileId(); 532 533 break; 534 } while (true); 535 536 state->fOpened = true; 537 538 if (confirm) 539 result = ConfirmOpen(*handle, state, &sequence); 540 541 fFileSystem->OpenOwnerSequenceUnlock(sequence); 542 return result; 543 } 544 545 546 status_t 547 NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation) 548 { 549 ASSERT(state != NULL); 550 ASSERT(delegation != NULL); 551 552 bool confirm; 553 status_t result; 554 555 uint32 attempt = 0; 556 uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); 557 do { 558 state->fClientID = fFileSystem->NFSServer()->ClientId(); 559 560 RPC::Server* serv = fFileSystem->Server(); 561 Request request(serv, fFileSystem); 562 RequestBuilder& req = request.Builder(); 563 564 // Since we are opening the file using a pair (parentFH, name) we 565 // need to check for race conditions. 566 if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) { 567 req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle); 568 req.LookUp(fInfo.fNames->fNames.Head()->fName); 569 AttrValue attr; 570 attr.fAttribute = FATTR4_FILEID; 571 attr.fFreePointer = false; 572 attr.fData.fValue64 = fInfo.fFileId; 573 req.Verify(&attr, 1); 574 } else if (fFileSystem->ExpireType() == FH4_PERSISTENT) { 575 req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle); 576 req.LookUp(fInfo.fNames->fNames.Head()->fName); 577 AttrValue attr; 578 attr.fAttribute = FATTR4_FILEHANDLE; 579 attr.fFreePointer = true; 580 attr.fData.fPointer = malloc(sizeof(fInfo.fHandle)); 581 memcpy(attr.fData.fPointer, &fInfo.fHandle, sizeof(fInfo.fHandle)); 582 req.Verify(&attr, 1); 583 } 584 585 req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle); 586 req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID, 587 OPEN4_NOCREATE, fFileSystem->OpenOwner(), 588 fInfo.fNames->fNames.Head()->fName); 589 req.GetFH(); 590 591 result = request.Send(); 592 if (result != B_OK) { 593 fFileSystem->OpenOwnerSequenceUnlock(sequence); 594 return result; 595 } 596 597 ReplyInterpreter& reply = request.Reply(); 598 599 // Verify if the file we want to open is the file this Inode 600 // represents. 601 if (fFileSystem->IsAttrSupported(FATTR4_FILEID) 602 || fFileSystem->ExpireType() == FH4_PERSISTENT) { 603 reply.PutFH(); 604 result = reply.LookUp(); 605 if (result != B_OK) { 606 fFileSystem->OpenOwnerSequenceUnlock(sequence); 607 return result; 608 } 609 610 result = reply.Verify(); 611 if (result != B_OK && reply.NFS4Error() == NFS4ERR_NOT_SAME) { 612 fFileSystem->OpenOwnerSequenceUnlock(sequence); 613 return B_ENTRY_NOT_FOUND; 614 } 615 } 616 617 result = reply.PutFH(); 618 if (result == B_OK) 619 sequence += IncrementSequence(reply.NFS4Error()); 620 621 if (HandleErrors(attempt, reply.NFS4Error(), serv, NULL, state, 622 &sequence)) { 623 continue; 624 } 625 626 result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, 627 delegation); 628 if (result != B_OK) { 629 fFileSystem->OpenOwnerSequenceUnlock(sequence); 630 return result; 631 } 632 633 FileHandle handle; 634 result = reply.GetFH(&handle); 635 if (result != B_OK) { 636 fFileSystem->OpenOwnerSequenceUnlock(sequence); 637 return result; 638 } 639 640 break; 641 } while (true); 642 643 state->fOpened = true; 644 645 if (confirm) 646 result = ConfirmOpen(fInfo.fHandle, state, &sequence); 647 648 fFileSystem->OpenOwnerSequenceUnlock(sequence); 649 return result; 650 } 651 652 653 status_t 654 NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode, 655 OpenDelegationData* delegation, bool create) 656 { 657 ASSERT(name != NULL); 658 ASSERT(state != NULL); 659 ASSERT(delegation != NULL); 660 661 bool confirm; 662 status_t result; 663 664 uint32 attempt = 0; 665 uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); 666 do { 667 state->fClientID = fFileSystem->NFSServer()->ClientId(); 668 669 RPC::Server* serv = fFileSystem->Server(); 670 Request request(serv, fFileSystem); 671 RequestBuilder& req = request.Builder(); 672 673 req.PutFH(fInfo.fAttrDir); 674 req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID, 675 create ? OPEN4_CREATE : OPEN4_NOCREATE, fFileSystem->OpenOwner(), 676 name); 677 req.GetFH(); 678 679 result = request.Send(); 680 if (result != B_OK) { 681 fFileSystem->OpenOwnerSequenceUnlock(sequence); 682 return result; 683 } 684 685 ReplyInterpreter& reply = request.Reply(); 686 687 result = reply.PutFH(); 688 if (result == B_OK) 689 sequence += IncrementSequence(reply.NFS4Error()); 690 691 if (HandleErrors(attempt, reply.NFS4Error(), serv, NULL, state, 692 &sequence)) { 693 continue; 694 } 695 696 result = reply.Open(state->fStateID, &state->fStateSeq, &confirm, 697 delegation); 698 699 reply.GetFH(&state->fInfo.fHandle); 700 701 if (result != B_OK) { 702 fFileSystem->OpenOwnerSequenceUnlock(sequence); 703 return result; 704 } 705 706 break; 707 } while (true); 708 709 state->fOpened = true; 710 711 if (confirm) 712 result = ConfirmOpen(state->fInfo.fHandle, state, &sequence); 713 714 fFileSystem->OpenOwnerSequenceUnlock(sequence); 715 return result; 716 } 717 718 719 status_t 720 NFS4Inode::ReadFile(OpenStateCookie* cookie, OpenState* state, uint64 position, 721 uint32* length, void* buffer, bool* eof) 722 { 723 ASSERT(state != NULL); 724 ASSERT(length != NULL); 725 ASSERT(buffer != NULL); 726 ASSERT(eof != NULL); 727 728 uint32 attempt = 0; 729 do { 730 RPC::Server* serv = fFileSystem->Server(); 731 Request request(serv, fFileSystem); 732 RequestBuilder& req = request.Builder(); 733 734 req.PutFH(state->fInfo.fHandle); 735 req.Read(state->fStateID, state->fStateSeq, position, *length); 736 737 status_t result = request.Send(cookie); 738 if (result != B_OK) 739 return result; 740 741 ReplyInterpreter& reply = request.Reply(); 742 743 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie, state)) 744 continue; 745 746 reply.PutFH(); 747 result = reply.Read(buffer, length, eof); 748 if (result != B_OK) 749 return result; 750 751 return B_OK; 752 } while (true); 753 } 754 755 756 status_t 757 NFS4Inode::WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position, 758 uint32* length, const void* buffer, bool commit) 759 { 760 ASSERT(state != NULL); 761 ASSERT(length != NULL); 762 ASSERT(buffer != NULL); 763 764 uint32 attempt = 0; 765 do { 766 RPC::Server* serv = fFileSystem->Server(); 767 Request request(serv, fFileSystem); 768 RequestBuilder& req = request.Builder(); 769 770 req.PutFH(state->fInfo.fHandle); 771 772 req.Write(state->fStateID, state->fStateSeq, buffer, position, *length, 773 commit); 774 775 status_t result = request.Send(cookie); 776 if (result != B_OK) 777 return result; 778 779 ReplyInterpreter& reply = request.Reply(); 780 781 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie, state)) 782 continue; 783 784 reply.PutFH(); 785 786 result = reply.Write(length); 787 if (result != B_OK) 788 return result; 789 790 return B_OK; 791 } while (true); 792 } 793 794 795 status_t 796 NFS4Inode::CreateObject(const char* name, const char* path, int mode, 797 FileType type, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle, 798 bool parent) 799 { 800 ASSERT(name != NULL); 801 ASSERT(changeInfo != NULL); 802 ASSERT(handle != NULL); 803 804 uint32 attempt = 0; 805 do { 806 RPC::Server* serv = fFileSystem->Server(); 807 Request request(serv, fFileSystem); 808 RequestBuilder& req = request.Builder(); 809 810 (void)parent; // TODO: support named attributes 811 req.PutFH(fInfo.fHandle); 812 813 uint32 i = 0; 814 AttrValue cattr[1]; 815 cattr[i].fAttribute = FATTR4_MODE; 816 cattr[i].fFreePointer = false; 817 cattr[i].fData.fValue32 = mode; 818 i++; 819 820 switch (type) { 821 case NF4DIR: 822 req.Create(NF4DIR, name, cattr, i); 823 break; 824 case NF4LNK: 825 req.Create(NF4LNK, name, cattr, i, path); 826 break; 827 default: 828 return B_BAD_VALUE; 829 } 830 831 req.GetFH(); 832 833 if (fileID != NULL) { 834 Attribute attr[] = { FATTR4_FILEID }; 835 req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); 836 } 837 838 status_t result = request.Send(); 839 if (result != B_OK) 840 return result; 841 842 ReplyInterpreter& reply = request.Reply(); 843 844 if (HandleErrors(attempt, reply.NFS4Error(), serv)) 845 continue; 846 847 reply.PutFH(); 848 result = reply.Create(&changeInfo->fBefore, &changeInfo->fAfter, 849 changeInfo->fAtomic); 850 if (result != B_OK) 851 return result; 852 853 result = reply.GetFH(handle); 854 if (result != B_OK) 855 return result; 856 857 if (fileID != NULL) { 858 AttrValue* values; 859 uint32 count; 860 result = reply.GetAttr(&values, &count); 861 if (result != B_OK) 862 return result; 863 864 if (count == 0) 865 *fileID = fFileSystem->AllocFileId(); 866 else 867 *fileID = values[0].fData.fValue64; 868 869 delete[] values; 870 } 871 872 return B_OK; 873 } while (true); 874 } 875 876 877 status_t 878 NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo, 879 uint64* fileID) 880 { 881 ASSERT(name != NULL); 882 ASSERT(changeInfo != NULL); 883 884 uint32 attempt = 0; 885 do { 886 RPC::Server* serv = fFileSystem->Server(); 887 Request request(serv, fFileSystem); 888 RequestBuilder& req = request.Builder(); 889 890 req.PutFH(fInfo.fHandle); 891 req.LookUp(name); 892 AttrValue attr; 893 attr.fAttribute = FATTR4_TYPE; 894 attr.fFreePointer = false; 895 attr.fData.fValue32 = NF4DIR; 896 if (type == NF4DIR) 897 req.Verify(&attr, 1); 898 else 899 req.Nverify(&attr, 1); 900 901 if (type != NF4NAMEDATTR) { 902 Attribute idAttr[] = { FATTR4_FILEID }; 903 req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute)); 904 } 905 906 req.PutFH(fInfo.fHandle); 907 req.Remove(name); 908 909 status_t result = request.Send(); 910 if (result != B_OK) 911 return result; 912 913 ReplyInterpreter& reply = request.Reply(); 914 915 if (HandleErrors(attempt, reply.NFS4Error(), serv)) 916 continue; 917 918 reply.PutFH(); 919 result = reply.LookUp(); 920 if (result != B_OK) 921 return result; 922 923 if (type == NF4DIR) 924 result = reply.Verify(); 925 else 926 result = reply.Nverify(); 927 928 if (result == NFS4ERR_SAME && type != NF4DIR) 929 return B_IS_A_DIRECTORY; 930 if (result == NFS4ERR_NOT_SAME && type == NF4DIR) 931 return B_NOT_A_DIRECTORY; 932 if (result != B_OK) 933 return result; 934 935 if (type != NF4NAMEDATTR) { 936 AttrValue* values; 937 uint32 count; 938 result = reply.GetAttr(&values, &count); 939 if (result != B_OK) 940 return result; 941 942 if (count == 0) 943 *fileID = fFileSystem->AllocFileId(); 944 else 945 *fileID = values[0].fData.fValue64; 946 delete[] values; 947 } 948 949 reply.PutFH(); 950 return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter, 951 changeInfo->fAtomic); 952 } while (true); 953 } 954 955 956 status_t 957 NFS4Inode::ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie, 958 bool* eof, uint64* change, uint64* dirCookie, uint64* dirCookieVerf, 959 bool attribute) 960 { 961 ASSERT(dirents != NULL); 962 ASSERT(count != NULL); 963 ASSERT(eof != NULL); 964 965 uint32 attempt = 0; 966 do { 967 RPC::Server* serv = fFileSystem->Server(); 968 Request request(serv, fFileSystem); 969 RequestBuilder& req = request.Builder(); 970 971 if (attribute) 972 req.PutFH(fInfo.fAttrDir); 973 else 974 req.PutFH(fInfo.fHandle); 975 976 Attribute dirAttr[] = { FATTR4_CHANGE }; 977 if (*change == 0) 978 req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute)); 979 980 Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID }; 981 req.ReadDir(*dirCookie, *dirCookieVerf, attr, 982 sizeof(attr) / sizeof(Attribute)); 983 984 req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute)); 985 986 status_t result = request.Send(cookie); 987 if (result != B_OK) 988 return result; 989 990 ReplyInterpreter& reply = request.Reply(); 991 992 if (HandleErrors(attempt, reply.NFS4Error(), serv)) 993 continue; 994 995 reply.PutFH(); 996 997 AttrValue* before = NULL; 998 uint32 attrCount; 999 if (*change == 0) { 1000 result = reply.GetAttr(&before, &attrCount); 1001 if (result != B_OK) 1002 return result; 1003 } 1004 ArrayDeleter<AttrValue> beforeDeleter(before); 1005 1006 result = reply.ReadDir(dirCookie, dirCookieVerf, dirents, count, eof); 1007 if (result != B_OK) 1008 return result; 1009 1010 ArrayDeleter<DirEntry> entriesDeleter(*dirents); 1011 1012 AttrValue* after; 1013 result = reply.GetAttr(&after, &attrCount); 1014 if (result != B_OK) 1015 return result; 1016 1017 ArrayDeleter<AttrValue> afterDeleter(after); 1018 1019 if ((*change == 0 1020 && before[0].fData.fValue64 == after[0].fData.fValue64) 1021 || *change == after[0].fData.fValue64) 1022 *change = after[0].fData.fValue64; 1023 else 1024 return B_ERROR; 1025 1026 entriesDeleter.Detach(); 1027 return B_OK; 1028 } while (true); 1029 } 1030 1031 1032 status_t 1033 NFS4Inode::OpenAttrDir(FileHandle* handle) 1034 { 1035 ASSERT(handle != NULL); 1036 1037 uint32 attempt = 0; 1038 do { 1039 RPC::Server* serv = fFileSystem->Server(); 1040 Request request(serv, fFileSystem); 1041 RequestBuilder& req = request.Builder(); 1042 1043 req.PutFH(fInfo.fHandle); 1044 req.OpenAttrDir(true); 1045 req.GetFH(); 1046 1047 status_t result = request.Send(); 1048 if (result != B_OK) 1049 return result; 1050 1051 ReplyInterpreter& reply = request.Reply(); 1052 1053 if (HandleErrors(attempt, reply.NFS4Error(), serv)) 1054 continue; 1055 1056 reply.PutFH(); 1057 result = reply.OpenAttrDir(); 1058 if (result != B_OK) 1059 return result; 1060 1061 return reply.GetFH(handle); 1062 } while (true); 1063 } 1064 1065 1066 status_t 1067 NFS4Inode::TestLock(OpenFileCookie* cookie, LockType* type, uint64* position, 1068 uint64* length, bool& conflict) 1069 { 1070 ASSERT(cookie != NULL); 1071 ASSERT(type != NULL); 1072 ASSERT(position != NULL); 1073 ASSERT(length != NULL); 1074 1075 uint32 attempt = 0; 1076 do { 1077 RPC::Server* serv = fFileSystem->Server(); 1078 Request request(serv, fFileSystem); 1079 RequestBuilder& req = request.Builder(); 1080 1081 req.PutFH(fInfo.fHandle); 1082 req.LockT(*type, *position, *length, cookie->fOpenState); 1083 1084 status_t result = request.Send(); 1085 if (result != B_OK) 1086 return result; 1087 1088 ReplyInterpreter& reply = request.Reply(); 1089 if (reply.NFS4Error() != NFS4ERR_DENIED) { 1090 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie)) 1091 continue; 1092 } 1093 1094 reply.PutFH(); 1095 result = reply.LockT(position, length, type); 1096 if (reply.NFS4Error() == NFS4ERR_DENIED) { 1097 conflict = true; 1098 result = B_OK; 1099 } else if (reply.NFS4Error() == NFS4_OK) 1100 conflict = false; 1101 1102 return result; 1103 } while (true); 1104 1105 return B_OK; 1106 } 1107 1108 1109 status_t 1110 NFS4Inode::AcquireLock(OpenFileCookie* cookie, LockInfo* lockInfo, bool wait) 1111 { 1112 ASSERT(cookie != NULL); 1113 ASSERT(lockInfo != NULL); 1114 1115 uint32 attempt = 0; 1116 uint32 sequence = fFileSystem->OpenOwnerSequenceLock(); 1117 do { 1118 MutexLocker ownerLocker(lockInfo->fOwner->fLock); 1119 1120 RPC::Server* serv = fFileSystem->Server(); 1121 Request request(serv, fFileSystem); 1122 RequestBuilder& req = request.Builder(); 1123 1124 req.PutFH(fInfo.fHandle); 1125 req.Lock(cookie->fOpenState, lockInfo, &sequence); 1126 1127 status_t result = request.Send(); 1128 if (result != B_OK) { 1129 fFileSystem->OpenOwnerSequenceUnlock(sequence); 1130 return result; 1131 } 1132 1133 ReplyInterpreter& reply = request.Reply(); 1134 1135 result = reply.PutFH(); 1136 if (result == B_OK) 1137 sequence += IncrementSequence(reply.NFS4Error()); 1138 1139 result = reply.Lock(lockInfo); 1140 1141 ownerLocker.Unlock(); 1142 1143 if (reply.NFS4Error() != NFS4ERR_DENIED || wait) { 1144 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie, NULL, 1145 &sequence)) { 1146 continue; 1147 } 1148 } 1149 1150 fFileSystem->OpenOwnerSequenceUnlock(sequence); 1151 if (result != B_OK) 1152 return result; 1153 1154 return B_OK; 1155 } while (true); 1156 } 1157 1158 1159 status_t 1160 NFS4Inode::ReleaseLock(OpenFileCookie* cookie, LockInfo* lockInfo) 1161 { 1162 ASSERT(cookie != NULL); 1163 ASSERT(lockInfo != NULL); 1164 1165 uint32 attempt = 0; 1166 do { 1167 MutexLocker ownerLocker(lockInfo->fOwner->fLock); 1168 1169 RPC::Server* serv = fFileSystem->Server(); 1170 Request request(serv, fFileSystem); 1171 RequestBuilder& req = request.Builder(); 1172 1173 req.PutFH(fInfo.fHandle); 1174 req.LockU(lockInfo); 1175 1176 status_t result = request.Send(); 1177 if (result != B_OK) 1178 return result; 1179 1180 ReplyInterpreter& reply = request.Reply(); 1181 1182 reply.PutFH(); 1183 result = reply.LockU(lockInfo); 1184 1185 ownerLocker.Unlock(); 1186 if (HandleErrors(attempt, reply.NFS4Error(), serv, cookie)) 1187 continue; 1188 1189 if (result != B_OK) 1190 return result; 1191 1192 return B_OK; 1193 } while (true); 1194 } 1195 1196