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