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