1 /* 2 * Copyright 2012-2020 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 "ReplyInterpreter.h" 11 12 #include <string.h> 13 14 #include <AutoDeleter.h> 15 #include <util/kernel_cpp.h> 16 17 #include "Cookie.h" 18 19 20 #define ERROR(x...) dprintf("nfs4: " x) 21 22 #ifdef DEBUG 23 #define TRACE(x...) dprintf("nfs4: " x) 24 #define CALLED() dprintf("nfs4: called %s", __func__) 25 #else 26 #define TRACE(x...) 27 #define CALLED() 28 #endif 29 30 31 static status_t 32 ProcessStream(RPC::Reply* reply, const char* callName) 33 { 34 status_t result = reply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; 35 if (result != B_OK) 36 TRACE("call %s failed!\n", callName); 37 return result; 38 } 39 40 41 FSLocation::~FSLocation() 42 { 43 CALLED(); 44 45 if (fRootPath != NULL) { 46 for (uint32 i = 0; fRootPath[i] != NULL; i++) 47 free(const_cast<char*>(fRootPath[i])); 48 } 49 delete[] fRootPath; 50 51 for (uint32 i = 0; i < fCount; i++) 52 free(const_cast<char*>(fLocations[i])); 53 delete[] fLocations; 54 } 55 56 57 FSLocations::~FSLocations() 58 { 59 CALLED(); 60 61 if (fRootPath != NULL) { 62 for (uint32 i = 0; fRootPath[i] != NULL; i++) 63 free(const_cast<char*>(fRootPath[i])); 64 } 65 delete[] fRootPath; 66 67 delete[] fLocations; 68 } 69 70 71 AttrValue::AttrValue() 72 : 73 fAttribute(0), 74 fFreePointer(false) 75 { 76 } 77 78 79 AttrValue::~AttrValue() 80 { 81 CALLED(); 82 83 if (fFreePointer) 84 free(fData.fPointer); 85 if (fAttribute == FATTR4_FS_LOCATIONS) 86 delete fData.fLocations; 87 } 88 89 90 DirEntry::DirEntry() 91 : 92 fName(NULL), 93 fAttrs(NULL), 94 fAttrCount(0) 95 { 96 } 97 98 99 DirEntry::~DirEntry() 100 { 101 free(const_cast<char*>(fName)); 102 delete[] fAttrs; 103 } 104 105 106 ReplyInterpreter::ReplyInterpreter(RPC::Reply* reply) 107 : 108 fNFS4Error(NFS4_OK), 109 fDecodeError(false), 110 fReply(reply) 111 { 112 CALLED(); 113 114 if (reply != NULL) 115 _ParseHeader(); 116 } 117 118 119 ReplyInterpreter::~ReplyInterpreter() 120 { 121 delete fReply; 122 } 123 124 125 void 126 ReplyInterpreter::_ParseHeader() 127 { 128 CALLED(); 129 130 fNFS4Error = fReply->Stream().GetUInt(); 131 fReply->Stream().GetOpaque(NULL); 132 fReply->Stream().GetUInt(); 133 } 134 135 136 status_t 137 ReplyInterpreter::Access(uint32* supported, uint32* allowed) 138 { 139 CALLED(); 140 141 status_t res = _OperationError(OpAccess); 142 if (res != B_OK) 143 return res; 144 145 uint32 support = fReply->Stream().GetUInt(); 146 uint32 allow = fReply->Stream().GetUInt(); 147 148 if (supported != NULL) 149 *supported = support; 150 if (allowed != NULL) 151 *allowed = allow; 152 153 return ProcessStream(fReply, __func__); 154 } 155 156 157 status_t 158 ReplyInterpreter::Close() 159 { 160 CALLED(); 161 162 status_t res = _OperationError(OpClose); 163 if (res != B_OK) 164 return res; 165 166 fReply->Stream().GetUInt(); 167 fReply->Stream().GetUInt(); 168 fReply->Stream().GetUInt(); 169 fReply->Stream().GetUInt(); 170 171 return ProcessStream(fReply, __func__); 172 } 173 174 175 status_t 176 ReplyInterpreter::Commit() 177 { 178 CALLED(); 179 180 status_t res = _OperationError(OpCommit); 181 if (res != B_OK) 182 return res; 183 184 fReply->Stream().GetOpaque(NULL); 185 186 return ProcessStream(fReply, __func__); 187 } 188 189 190 status_t 191 ReplyInterpreter::Create(uint64* before, uint64* after, bool& atomic) 192 { 193 CALLED(); 194 195 status_t res = _OperationError(OpCreate); 196 if (res != B_OK) 197 return res; 198 199 atomic = fReply->Stream().GetBoolean(); 200 *before = fReply->Stream().GetUHyper(); 201 *after = fReply->Stream().GetUHyper(); 202 203 uint32 count = fReply->Stream().GetUInt(); 204 for (uint32 i = 0; i < count; i++) 205 fReply->Stream().GetUInt(); 206 207 return ProcessStream(fReply, __func__); 208 } 209 210 211 // Bit Twiddling Hacks 212 // http://graphics.stanford.edu/~seander/bithacks.html 213 static inline uint32 CountBits(uint32 v) 214 { 215 CALLED(); 216 217 v = v - ((v >> 1) & 0x55555555); 218 v = (v & 0x33333333) + ((v >> 2) & 0x33333333); 219 return (((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; 220 } 221 222 223 status_t 224 ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count) 225 { 226 CALLED(); 227 228 status_t res = _OperationError(OpGetAttr); 229 if (res != B_OK) 230 return res; 231 232 return _DecodeAttrs(fReply->Stream(), attrs, count); 233 } 234 235 236 status_t 237 ReplyInterpreter::GetFH(FileHandle* fh) 238 { 239 CALLED(); 240 241 status_t res = _OperationError(OpGetFH); 242 if (res != B_OK) 243 return res; 244 245 uint32 size; 246 const void* ptr = fReply->Stream().GetOpaque(&size); 247 if (ptr == NULL || size > NFS4_FHSIZE) { 248 ERROR("Unable to %s!\n", __func__); 249 return B_BAD_VALUE; 250 } 251 252 if (fh != NULL) { 253 fh->fSize = size; 254 memcpy(fh->fData, ptr, size); 255 } 256 257 return ProcessStream(fReply, __func__); 258 } 259 260 261 status_t 262 ReplyInterpreter::Link(uint64* before, uint64* after, bool& atomic) 263 { 264 CALLED(); 265 266 status_t res = _OperationError(OpLink); 267 if (res != B_OK) 268 return res; 269 270 atomic = fReply->Stream().GetBoolean(); 271 *before = fReply->Stream().GetUHyper(); 272 *after = fReply->Stream().GetUHyper(); 273 274 return ProcessStream(fReply, __func__); 275 } 276 277 278 status_t 279 ReplyInterpreter::Lock(LockInfo* linfo) 280 { 281 CALLED(); 282 283 status_t res = _OperationError(OpLock); 284 if (res != B_OK) 285 return res; 286 287 linfo->fOwner->fStateSeq = fReply->Stream().GetUInt(); 288 linfo->fOwner->fStateId[0] = fReply->Stream().GetUInt(); 289 linfo->fOwner->fStateId[1] = fReply->Stream().GetUInt(); 290 linfo->fOwner->fStateId[2] = fReply->Stream().GetUInt(); 291 292 return ProcessStream(fReply, __func__); 293 } 294 295 296 status_t 297 ReplyInterpreter::LockT(uint64* pos, uint64* len, LockType* type) 298 { 299 CALLED(); 300 301 status_t res = _OperationError(OpLockT); 302 if (res != B_WOULD_BLOCK || NFS4Error() != NFS4ERR_DENIED) 303 return res; 304 305 *pos = fReply->Stream().GetUHyper(); 306 *len = fReply->Stream().GetUHyper(); 307 *type = static_cast<LockType>(fReply->Stream().GetInt()); 308 309 fReply->Stream().GetUHyper(); 310 fReply->Stream().GetOpaque(NULL); 311 312 return ProcessStream(fReply, __func__); 313 } 314 315 316 status_t 317 ReplyInterpreter::LockU(LockInfo* linfo) 318 { 319 CALLED(); 320 321 status_t res = _OperationError(OpLockU); 322 if (res != B_OK) 323 return res; 324 325 linfo->fOwner->fStateSeq = fReply->Stream().GetUInt(); 326 linfo->fOwner->fStateId[0] = fReply->Stream().GetUInt(); 327 linfo->fOwner->fStateId[1] = fReply->Stream().GetUInt(); 328 linfo->fOwner->fStateId[2] = fReply->Stream().GetUInt(); 329 330 return ProcessStream(fReply, __func__); 331 } 332 333 334 status_t 335 ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm, 336 OpenDelegationData* delegData, ChangeInfo* changeInfo) 337 { 338 CALLED(); 339 340 status_t res = _OperationError(OpOpen); 341 if (res != B_OK) 342 return res; 343 344 *seq = fReply->Stream().GetUInt(); 345 id[0] = fReply->Stream().GetUInt(); 346 id[1] = fReply->Stream().GetUInt(); 347 id[2] = fReply->Stream().GetUInt(); 348 349 // change info 350 bool atomic = fReply->Stream().GetBoolean(); 351 uint64 before = fReply->Stream().GetUHyper(); 352 uint64 after = fReply->Stream().GetUHyper(); 353 if (changeInfo != NULL) { 354 changeInfo->fAtomic = atomic; 355 changeInfo->fBefore = before; 356 changeInfo->fAfter = after; 357 } 358 359 uint32 flags = fReply->Stream().GetUInt(); 360 *confirm = (flags & OPEN4_RESULT_CONFIRM) == OPEN4_RESULT_CONFIRM; 361 362 // attrmask 363 uint32 bcount = fReply->Stream().GetUInt(); 364 for (uint32 i = 0; i < bcount; i++) 365 fReply->Stream().GetUInt(); 366 367 // delegation info 368 uint32 delegation = fReply->Stream().GetUInt(); 369 OpenDelegationData data; 370 if (delegData == NULL) 371 delegData = &data; 372 373 if (delegation == OPEN_DELEGATE_NONE) { 374 delegData->fType = OPEN_DELEGATE_NONE; 375 return ProcessStream(fReply, __func__); 376 } 377 378 delegData->fStateSeq = fReply->Stream().GetUInt(); 379 delegData->fStateID[0] = fReply->Stream().GetUInt(); 380 delegData->fStateID[1] = fReply->Stream().GetUInt(); 381 delegData->fStateID[2] = fReply->Stream().GetUInt(); 382 383 delegData->fRecall = fReply->Stream().GetBoolean(); 384 385 switch (delegation) { 386 case OPEN_DELEGATE_READ: 387 delegData->fType = OPEN_DELEGATE_READ; 388 break; 389 case OPEN_DELEGATE_WRITE: 390 delegData->fType = OPEN_DELEGATE_WRITE; 391 392 int32 limitBy = fReply->Stream().GetInt(); 393 if (limitBy == NFS_LIMIT_SIZE) 394 delegData->fSpaceLimit = fReply->Stream().GetUHyper(); 395 else if (limitBy == NFS_LIMIT_BLOCKS) { 396 uint32 numBlocks = fReply->Stream().GetUInt(); 397 delegData->fSpaceLimit = fReply->Stream().GetUInt() * numBlocks; 398 } 399 break; 400 } 401 402 // ACE data 403 fReply->Stream().GetUInt(); 404 fReply->Stream().GetUInt(); 405 fReply->Stream().GetUInt(); 406 fReply->Stream().GetOpaque(NULL); 407 408 return ProcessStream(fReply, __func__); 409 } 410 411 412 status_t 413 ReplyInterpreter::OpenConfirm(uint32* stateSeq) 414 { 415 CALLED(); 416 417 status_t res = _OperationError(OpOpenConfirm); 418 if (res != B_OK) 419 return res; 420 421 *stateSeq = fReply->Stream().GetUInt(); 422 fReply->Stream().GetUInt(); 423 fReply->Stream().GetUInt(); 424 fReply->Stream().GetUInt(); 425 426 return ProcessStream(fReply, __func__); 427 } 428 429 430 status_t 431 ReplyInterpreter::Read(void* buffer, uint32* size, bool* eof) 432 { 433 CALLED(); 434 435 status_t res = _OperationError(OpRead); 436 if (res != B_OK) 437 return res; 438 439 *eof = fReply->Stream().GetBoolean(); 440 const void* ptr = fReply->Stream().GetOpaque(size); 441 memcpy(buffer, ptr, *size); 442 443 return ProcessStream(fReply, __func__); 444 } 445 446 447 status_t 448 ReplyInterpreter::ReadDir(uint64* cookie, uint64* cookieVerf, 449 DirEntry** dirents, uint32* _count, bool* eof) 450 { 451 CALLED(); 452 453 status_t res = _OperationError(OpReadDir); 454 if (res != B_OK) 455 return res; 456 457 *cookieVerf = fReply->Stream().GetUHyper(); 458 459 bool isNext; 460 uint32 count = 0; 461 462 // TODO: using list instead of array would make this much more elegant 463 // and efficient 464 XDR::Stream::Position dataStart = fReply->Stream().Current(); 465 isNext = fReply->Stream().GetBoolean(); 466 while (isNext) { 467 fReply->Stream().GetUHyper(); 468 469 free(fReply->Stream().GetString()); 470 AttrValue* values; 471 uint32 attrCount; 472 _DecodeAttrs(fReply->Stream(), &values, &attrCount); 473 delete[] values; 474 475 count++; 476 477 isNext = fReply->Stream().GetBoolean(); 478 } 479 480 DirEntry* entries = new(std::nothrow) DirEntry[count]; 481 if (entries == NULL) 482 return B_NO_MEMORY; 483 484 count = 0; 485 fReply->Stream().SetPosition(dataStart); 486 isNext = fReply->Stream().GetBoolean(); 487 while (isNext) { 488 *cookie = fReply->Stream().GetUHyper(); 489 490 entries[count].fName = fReply->Stream().GetString(); 491 _DecodeAttrs(fReply->Stream(), &entries[count].fAttrs, 492 &entries[count].fAttrCount); 493 494 count++; 495 496 isNext = fReply->Stream().GetBoolean(); 497 } 498 *eof = fReply->Stream().GetBoolean(); 499 500 *_count = count; 501 *dirents = entries; 502 503 if (fReply->Stream().IsEOF()) { 504 delete[] entries; 505 ERROR("Unable to %s!\n", __func__); 506 return B_BAD_VALUE; 507 } 508 509 return B_OK; 510 } 511 512 513 status_t 514 ReplyInterpreter::ReadLink(void* buffer, uint32* size, uint32 maxSize) 515 { 516 CALLED(); 517 518 status_t res = _OperationError(OpReadLink); 519 if (res != B_OK) 520 return res; 521 522 const void* ptr = fReply->Stream().GetOpaque(size); 523 memcpy(buffer, ptr, min_c(*size, maxSize)); 524 525 return ProcessStream(fReply, __func__); 526 } 527 528 529 status_t 530 ReplyInterpreter::Remove(uint64* before, uint64* after, bool& atomic) 531 { 532 CALLED(); 533 534 status_t res = _OperationError(OpRemove); 535 if (res != B_OK) 536 return res; 537 538 atomic = fReply->Stream().GetBoolean(); 539 *before = fReply->Stream().GetUHyper(); 540 *after = fReply->Stream().GetUHyper(); 541 542 return ProcessStream(fReply, __func__); 543 } 544 545 546 status_t 547 ReplyInterpreter::Rename(uint64* fromBefore, uint64* fromAfter, 548 bool& fromAtomic, uint64* toBefore, uint64* toAfter, bool& toAtomic) 549 { 550 CALLED(); 551 552 status_t res = _OperationError(OpRename); 553 if (res != B_OK) 554 return res; 555 556 fromAtomic = fReply->Stream().GetBoolean(); 557 *fromBefore = fReply->Stream().GetUHyper(); 558 *fromAfter = fReply->Stream().GetUHyper(); 559 560 toAtomic = fReply->Stream().GetBoolean(); 561 *toBefore = fReply->Stream().GetUHyper(); 562 *toAfter = fReply->Stream().GetUHyper(); 563 564 return ProcessStream(fReply, __func__); 565 } 566 567 568 status_t 569 ReplyInterpreter::SetAttr() 570 { 571 CALLED(); 572 573 status_t res = _OperationError(OpSetAttr); 574 if (res != B_OK) 575 return res; 576 577 uint32 bcount = fReply->Stream().GetUInt(); 578 for (uint32 i = 0; i < bcount; i++) 579 fReply->Stream().GetUInt(); 580 581 return ProcessStream(fReply, __func__); 582 } 583 584 585 status_t 586 ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier) 587 { 588 CALLED(); 589 590 status_t res = _OperationError(OpSetClientID); 591 if (res != B_OK) 592 return res; 593 594 *clientid = fReply->Stream().GetUHyper(); 595 *verifier = fReply->Stream().GetUHyper(); 596 597 return ProcessStream(fReply, __func__); 598 } 599 600 601 status_t 602 ReplyInterpreter::Write(uint32* size) 603 { 604 CALLED(); 605 606 status_t res = _OperationError(OpWrite); 607 if (res != B_OK) 608 return res; 609 610 *size = fReply->Stream().GetUInt(); 611 fReply->Stream().GetInt(); 612 fReply->Stream().GetUHyper(); 613 614 return ProcessStream(fReply, __func__); 615 } 616 617 618 const char** 619 ReplyInterpreter::_GetPath(XDR::ReadStream& stream) 620 { 621 CALLED(); 622 623 uint32 count = stream.GetUInt(); 624 char** path = new char*[count + 1]; 625 if (path == NULL) 626 return NULL; 627 628 uint32 i; 629 for (i = 0; i < count; i++) { 630 path[i] = stream.GetString(); 631 if (path[i] == NULL) 632 goto out; 633 } 634 path[count] = NULL; 635 636 return const_cast<const char**>(path); 637 638 out: 639 for (uint32 j = 0; j < i; j++) 640 free(path[i]); 641 delete[] path; 642 return NULL; 643 } 644 645 646 status_t 647 ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, 648 uint32* count) 649 { 650 CALLED(); 651 652 uint32 bcount = fReply->Stream().GetUInt(); 653 uint32* bitmap = new(std::nothrow) uint32[bcount]; 654 if (bitmap == NULL) 655 return B_NO_MEMORY; 656 ArrayDeleter<uint32> _(bitmap); 657 658 uint32 attr_count = 0; 659 for (uint32 i = 0; i < bcount; i++) { 660 bitmap[i] = str.GetUInt(); 661 attr_count += CountBits(bitmap[i]); 662 } 663 664 if (attr_count == 0) { 665 *attrs = NULL; 666 *count = 0; 667 return B_OK; 668 } else if (attr_count > FATTR4_MAXIMUM_ATTR_ID) { 669 ERROR("too many attr!\n"); 670 return B_BAD_VALUE; 671 } 672 673 uint32 size; 674 const void* ptr = str.GetOpaque(&size); 675 XDR::ReadStream stream(const_cast<void*>(ptr), size); 676 677 AttrValue* values = new(std::nothrow) AttrValue[attr_count]; 678 if (values == NULL) 679 return B_NO_MEMORY; 680 681 uint32 current = 0; 682 683 if (sIsAttrSet(FATTR4_SUPPORTED_ATTRS, bitmap, bcount)) { 684 values[current].fAttribute = FATTR4_SUPPORTED_ATTRS; 685 uint32 count = stream.GetInt(); 686 uint32 i; 687 // two uint32 are enough for NFS4, not for NFS4.1 688 for (i = 0; i < min_c(count, 2); i++) 689 ((uint32*)&values[current].fData.fValue64)[i] = stream.GetUInt(); 690 for (; i < count; i++) 691 stream.GetUInt(); 692 current++; 693 } 694 695 if (sIsAttrSet(FATTR4_TYPE, bitmap, bcount)) { 696 values[current].fAttribute = FATTR4_TYPE; 697 values[current].fData.fValue32 = stream.GetInt(); 698 current++; 699 } 700 701 if (sIsAttrSet(FATTR4_FH_EXPIRE_TYPE, bitmap, bcount)) { 702 values[current].fAttribute = FATTR4_FH_EXPIRE_TYPE; 703 values[current].fData.fValue32 = stream.GetUInt(); 704 current++; 705 } 706 707 if (sIsAttrSet(FATTR4_CHANGE, bitmap, bcount)) { 708 values[current].fAttribute = FATTR4_CHANGE; 709 values[current].fData.fValue64 = stream.GetUHyper(); 710 current++; 711 } 712 713 if (sIsAttrSet(FATTR4_SIZE, bitmap, bcount)) { 714 values[current].fAttribute = FATTR4_SIZE; 715 values[current].fData.fValue64 = stream.GetUHyper(); 716 current++; 717 } 718 719 if (sIsAttrSet(FATTR4_FSID, bitmap, bcount)) { 720 values[current].fAttribute = FATTR4_FSID; 721 values[current].fFreePointer = true; 722 723 FileSystemId fsid; 724 fsid.fMajor = stream.GetUHyper(); 725 fsid.fMinor = stream.GetUHyper(); 726 727 values[current].fData.fPointer = malloc(sizeof(fsid)); 728 memcpy(values[current].fData.fPointer, &fsid, sizeof(fsid)); 729 current++; 730 } 731 732 if (sIsAttrSet(FATTR4_LEASE_TIME, bitmap, bcount)) { 733 values[current].fAttribute = FATTR4_LEASE_TIME; 734 values[current].fData.fValue32 = stream.GetUInt(); 735 current++; 736 } 737 738 if (sIsAttrSet(FATTR4_FILEID, bitmap, bcount)) { 739 values[current].fAttribute = FATTR4_FILEID; 740 values[current].fData.fValue64 = stream.GetUHyper(); 741 current++; 742 } 743 744 if (sIsAttrSet(FATTR4_FILES_FREE, bitmap, bcount)) { 745 values[current].fAttribute = FATTR4_FILES_FREE; 746 values[current].fData.fValue64 = stream.GetUHyper(); 747 current++; 748 } 749 750 if (sIsAttrSet(FATTR4_FILES_TOTAL, bitmap, bcount)) { 751 values[current].fAttribute = FATTR4_FILES_TOTAL; 752 values[current].fData.fValue64 = stream.GetUHyper(); 753 current++; 754 } 755 756 if (sIsAttrSet(FATTR4_FS_LOCATIONS, bitmap, bcount)) { 757 values[current].fAttribute = FATTR4_FS_LOCATIONS; 758 759 FSLocations* locs = new FSLocations; 760 locs->fRootPath = _GetPath(stream); 761 locs->fCount = stream.GetUInt(); 762 locs->fLocations = new FSLocation[locs->fCount]; 763 for (uint32 i = 0; i < locs->fCount; i++) { 764 locs->fLocations[i].fRootPath = _GetPath(stream); 765 locs->fLocations[i].fCount = stream.GetUInt(); 766 locs->fLocations[i].fLocations 767 = new const char*[locs->fLocations[i].fCount]; 768 for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) 769 locs->fLocations[i].fLocations[j] = stream.GetString(); 770 } 771 values[current].fData.fLocations = locs; 772 current++; 773 } 774 775 if (sIsAttrSet(FATTR4_MAXREAD, bitmap, bcount)) { 776 values[current].fAttribute = FATTR4_MAXREAD; 777 values[current].fData.fValue64 = stream.GetUHyper(); 778 current++; 779 } 780 781 if (sIsAttrSet(FATTR4_MAXWRITE, bitmap, bcount)) { 782 values[current].fAttribute = FATTR4_MAXWRITE; 783 values[current].fData.fValue64 = stream.GetUHyper(); 784 current++; 785 } 786 787 if (sIsAttrSet(FATTR4_MODE, bitmap, bcount)) { 788 values[current].fAttribute = FATTR4_MODE; 789 values[current].fData.fValue32 = stream.GetUInt(); 790 current++; 791 } 792 793 if (sIsAttrSet(FATTR4_NUMLINKS, bitmap, bcount)) { 794 values[current].fAttribute = FATTR4_NUMLINKS; 795 values[current].fData.fValue32 = stream.GetUInt(); 796 current++; 797 } 798 799 if (sIsAttrSet(FATTR4_OWNER, bitmap, bcount)) { 800 values[current].fAttribute = FATTR4_OWNER; 801 values[current].fFreePointer = true; 802 values[current].fData.fPointer = stream.GetString(); 803 current++; 804 } 805 806 if (sIsAttrSet(FATTR4_OWNER_GROUP, bitmap, bcount)) { 807 values[current].fAttribute = FATTR4_OWNER_GROUP; 808 values[current].fFreePointer = true; 809 values[current].fData.fPointer = stream.GetString(); 810 current++; 811 } 812 813 if (sIsAttrSet(FATTR4_SPACE_FREE, bitmap, bcount)) { 814 values[current].fAttribute = FATTR4_SPACE_FREE; 815 values[current].fData.fValue64 = stream.GetUHyper(); 816 current++; 817 } 818 819 if (sIsAttrSet(FATTR4_SPACE_TOTAL, bitmap, bcount)) { 820 values[current].fAttribute = FATTR4_SPACE_TOTAL; 821 values[current].fData.fValue64 = stream.GetUHyper(); 822 current++; 823 } 824 825 if (sIsAttrSet(FATTR4_TIME_ACCESS, bitmap, bcount)) { 826 values[current].fAttribute = FATTR4_TIME_ACCESS; 827 values[current].fFreePointer = true; 828 829 struct timespec ts; 830 ts.tv_sec = static_cast<time_t>(stream.GetHyper()); 831 ts.tv_nsec = static_cast<long>(stream.GetUInt()); 832 833 values[current].fData.fPointer = malloc(sizeof(ts)); 834 memcpy(values[current].fData.fPointer, &ts, sizeof(ts)); 835 current++; 836 } 837 838 if (sIsAttrSet(FATTR4_TIME_CREATE, bitmap, bcount)) { 839 values[current].fAttribute = FATTR4_TIME_CREATE; 840 values[current].fFreePointer = true; 841 842 struct timespec ts; 843 ts.tv_sec = static_cast<time_t>(stream.GetHyper()); 844 ts.tv_nsec = static_cast<long>(stream.GetUInt()); 845 846 values[current].fData.fPointer = malloc(sizeof(ts)); 847 memcpy(values[current].fData.fPointer, &ts, sizeof(ts)); 848 current++; 849 } 850 851 if (sIsAttrSet(FATTR4_TIME_METADATA, bitmap, bcount)) { 852 values[current].fAttribute = FATTR4_TIME_METADATA; 853 values[current].fFreePointer = true; 854 855 struct timespec ts; 856 ts.tv_sec = static_cast<time_t>(stream.GetHyper()); 857 ts.tv_nsec = static_cast<long>(stream.GetUInt()); 858 859 values[current].fData.fPointer = malloc(sizeof(ts)); 860 memcpy(values[current].fData.fPointer, &ts, sizeof(ts)); 861 current++; 862 } 863 864 if (sIsAttrSet(FATTR4_TIME_MODIFY, bitmap, bcount)) { 865 values[current].fAttribute = FATTR4_TIME_MODIFY; 866 values[current].fFreePointer = true; 867 868 struct timespec ts; 869 ts.tv_sec = static_cast<time_t>(stream.GetHyper()); 870 ts.tv_nsec = static_cast<long>(stream.GetUInt()); 871 872 values[current].fData.fPointer = malloc(sizeof(ts)); 873 memcpy(values[current].fData.fPointer, &ts, sizeof(ts)); 874 current++; 875 } 876 877 *count = attr_count; 878 *attrs = values; 879 if (str.IsEOF()) { 880 delete[] values; 881 ERROR("call %s failed!\n", __func__); 882 return B_BAD_VALUE; 883 } 884 return B_OK; 885 } 886 887 888 status_t 889 ReplyInterpreter::_OperationError(Opcode op) 890 { 891 if (fDecodeError) { 892 ERROR("Decode Error!\n"); 893 return B_BAD_VALUE; 894 } 895 896 if (fReply == NULL) 897 return B_NOT_INITIALIZED; 898 899 if (fReply->Error() != B_OK || fReply->Stream().IsEOF()) { 900 ERROR("Error not B_OK or empty stream!\n"); 901 fDecodeError = true; 902 return fReply->Error(); 903 } 904 905 if (fReply->Stream().GetInt() != op) { 906 ERROR("Stream GetInt != op!\n"); 907 fDecodeError = true; 908 return B_BAD_VALUE; 909 } 910 911 status_t result = _NFS4ErrorToHaiku(fReply->Stream().GetUInt()); 912 if (result != B_OK) { 913 ERROR("NFS Error: %s\n", strerror(result)); 914 fDecodeError = true; 915 } 916 return result; 917 } 918 919 920 status_t 921 ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x) 922 { 923 switch (x) { 924 case NFS4_OK: return B_OK; 925 case NFS4ERR_PERM: return B_PERMISSION_DENIED; 926 case NFS4ERR_NOENT: return B_ENTRY_NOT_FOUND; 927 case NFS4ERR_IO: return B_IO_ERROR; 928 case NFS4ERR_NXIO: return B_DEVICE_NOT_FOUND; 929 case NFS4ERR_ACCESS: return B_NOT_ALLOWED; 930 case NFS4ERR_EXIST: return B_FILE_EXISTS; 931 case NFS4ERR_XDEV: return B_CROSS_DEVICE_LINK; 932 case NFS4ERR_NOTDIR: return B_NOT_A_DIRECTORY; 933 case NFS4ERR_ISDIR: return B_IS_A_DIRECTORY; 934 case NFS4ERR_INVAL: return B_BAD_VALUE; 935 case NFS4ERR_FBIG: return B_FILE_TOO_LARGE; 936 case NFS4ERR_NOTSUPP: return B_UNSUPPORTED; 937 case NFS4ERR_ROFS: return B_READ_ONLY_DEVICE; 938 case NFS4ERR_NAMETOOLONG: return B_NAME_TOO_LONG; 939 case NFS4ERR_NOTEMPTY: return B_DIRECTORY_NOT_EMPTY; 940 // ... 941 case NFS4ERR_DELAY: 942 case NFS4ERR_DENIED: 943 case NFS4ERR_LOCKED: 944 case NFS4ERR_GRACE: 945 return B_WOULD_BLOCK; 946 947 case NFS4ERR_STALE: 948 case NFS4ERR_FHEXPIRED: 949 return B_ENTRY_NOT_FOUND; 950 // ... 951 default: return B_ERROR; 952 } 953 } 954 955