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