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 fAttribute(0), 38 fFreePointer(false) 39 { 40 } 41 42 43 AttrValue::~AttrValue() 44 { 45 if (fFreePointer) 46 free(fData.fPointer); 47 if (fAttribute == FATTR4_FS_LOCATIONS) 48 delete fData.fLocations; 49 } 50 51 52 DirEntry::DirEntry() 53 : 54 fName(NULL), 55 fAttrs(NULL), 56 fAttrCount(0) 57 { 58 } 59 60 61 DirEntry::~DirEntry() 62 { 63 free(const_cast<char*>(fName)); 64 delete[] fAttrs; 65 } 66 67 68 ReplyInterpreter::ReplyInterpreter(RPC::Reply* reply) 69 : 70 fNFS4Error(NFS4_OK), 71 fDecodeError(false), 72 fReply(reply) 73 { 74 if (reply != NULL) 75 _ParseHeader(); 76 } 77 78 79 ReplyInterpreter::~ReplyInterpreter() 80 { 81 delete fReply; 82 } 83 84 85 void 86 ReplyInterpreter::_ParseHeader() 87 { 88 fNFS4Error = fReply->Stream().GetUInt(); 89 fReply->Stream().GetOpaque(NULL); 90 fReply->Stream().GetUInt(); 91 } 92 93 94 status_t 95 ReplyInterpreter::Access(uint32* supported, uint32* allowed) 96 { 97 status_t res = _OperationError(OpAccess); 98 if (res != B_OK) 99 return res; 100 101 uint32 support = fReply->Stream().GetUInt(); 102 uint32 allow = fReply->Stream().GetUInt(); 103 104 if (supported != NULL) 105 *supported = support; 106 if (allowed != NULL) 107 *allowed = allow; 108 109 return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; 110 } 111 112 113 status_t 114 ReplyInterpreter::Close() 115 { 116 status_t res = _OperationError(OpClose); 117 if (res != B_OK) 118 return res; 119 120 fReply->Stream().GetUInt(); 121 fReply->Stream().GetUInt(); 122 fReply->Stream().GetUInt(); 123 fReply->Stream().GetUInt(); 124 125 return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; 126 } 127 128 129 status_t 130 ReplyInterpreter::Commit() 131 { 132 status_t res = _OperationError(OpCommit); 133 if (res != B_OK) 134 return res; 135 136 fReply->Stream().GetOpaque(NULL); 137 138 return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; 139 } 140 141 142 status_t 143 ReplyInterpreter::Create(uint64* before, uint64* after, bool& atomic) 144 { 145 status_t res = _OperationError(OpCreate); 146 if (res != B_OK) 147 return res; 148 149 atomic = fReply->Stream().GetBoolean(); 150 *before = fReply->Stream().GetUHyper(); 151 *after = fReply->Stream().GetUHyper(); 152 153 uint32 count = fReply->Stream().GetUInt(); 154 for (uint32 i = 0; i < count; i++) 155 fReply->Stream().GetUInt(); 156 157 return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; 158 } 159 160 161 // Bit Twiddling Hacks 162 // http://graphics.stanford.edu/~seander/bithacks.html 163 static inline uint32 CountBits(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(OpLockT); 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 *eof = fReply->Stream().GetBoolean(); 425 426 *_count = count; 427 *dirents = entries; 428 429 return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; 430 } 431 432 433 status_t 434 ReplyInterpreter::ReadLink(void* buffer, uint32* size, uint32 maxSize) 435 { 436 status_t res = _OperationError(OpReadLink); 437 if (res != B_OK) 438 return res; 439 440 const void* ptr = fReply->Stream().GetOpaque(size); 441 memcpy(buffer, ptr, min_c(*size, maxSize)); 442 443 return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; 444 } 445 446 447 status_t 448 ReplyInterpreter::Remove(uint64* before, uint64* after, bool& atomic) 449 { 450 status_t res = _OperationError(OpRemove); 451 if (res != B_OK) 452 return res; 453 454 atomic = fReply->Stream().GetBoolean(); 455 *before = fReply->Stream().GetUHyper(); 456 *after = fReply->Stream().GetUHyper(); 457 458 return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; 459 } 460 461 462 status_t 463 ReplyInterpreter::Rename(uint64* fromBefore, uint64* fromAfter, 464 bool& fromAtomic, uint64* toBefore, uint64* toAfter, bool& toAtomic) 465 { 466 status_t res = _OperationError(OpRename); 467 if (res != B_OK) 468 return res; 469 470 fromAtomic = fReply->Stream().GetBoolean(); 471 *fromBefore = fReply->Stream().GetUHyper(); 472 *fromAfter = fReply->Stream().GetUHyper(); 473 474 toAtomic = fReply->Stream().GetBoolean(); 475 *toBefore = fReply->Stream().GetUHyper(); 476 *toAfter = fReply->Stream().GetUHyper(); 477 return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; 478 } 479 480 481 status_t 482 ReplyInterpreter::SetAttr() 483 { 484 status_t res = _OperationError(OpSetAttr); 485 if (res != B_OK) 486 return res; 487 488 uint32 bcount = fReply->Stream().GetUInt(); 489 for (uint32 i = 0; i < bcount; i++) 490 fReply->Stream().GetUInt(); 491 492 return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; 493 } 494 495 496 status_t 497 ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier) 498 { 499 status_t res = _OperationError(OpSetClientID); 500 if (res != B_OK) 501 return res; 502 503 *clientid = fReply->Stream().GetUHyper(); 504 *verifier = fReply->Stream().GetUHyper(); 505 506 return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; 507 } 508 509 510 status_t 511 ReplyInterpreter::Write(uint32* size) 512 { 513 status_t res = _OperationError(OpWrite); 514 if (res != B_OK) 515 return res; 516 517 *size = fReply->Stream().GetUInt(); 518 fReply->Stream().GetInt(); 519 fReply->Stream().GetUHyper(); 520 521 return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; 522 } 523 524 525 static const char* 526 sFlattenPathname(XDR::ReadStream& str) 527 { 528 uint32 count = str.GetUInt(); 529 char* pathname = NULL; 530 uint32 size = 0; 531 for (uint32 i = 0; i < count; i++) { 532 const char* path = str.GetString(); 533 size += strlen(path) + 1; 534 if (pathname == NULL) { 535 pathname = reinterpret_cast<char*>(malloc(strlen(path + 1))); 536 pathname[0] = '\0'; 537 } else { 538 *pathname++ = '/'; 539 pathname = reinterpret_cast<char*>(realloc(pathname, size)); 540 } 541 strcat(pathname, path); 542 free(const_cast<char*>(path)); 543 } 544 545 return pathname; 546 } 547 548 549 status_t 550 ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs, 551 uint32* count) 552 { 553 uint32 bcount = fReply->Stream().GetUInt(); 554 uint32* bitmap = new(std::nothrow) uint32[bcount]; 555 if (bitmap == NULL) 556 return B_NO_MEMORY; 557 558 uint32 attr_count = 0; 559 for (uint32 i = 0; i < bcount; i++) { 560 bitmap[i] = str.GetUInt(); 561 attr_count += CountBits(bitmap[i]); 562 } 563 564 if (attr_count == 0) { 565 *attrs = NULL; 566 *count = 0; 567 return B_OK; 568 } else if (attr_count > FATTR4_MAXIMUM_ATTR_ID) 569 return B_BAD_VALUE; 570 571 uint32 size; 572 const void* ptr = str.GetOpaque(&size); 573 XDR::ReadStream stream(const_cast<void*>(ptr), size); 574 575 AttrValue* values = new(std::nothrow) AttrValue[attr_count]; 576 if (values == NULL) { 577 delete[] bitmap; 578 return B_NO_MEMORY; 579 } 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 = sFlattenPathname(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 = sFlattenPathname(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 delete[] bitmap; 778 779 *count = attr_count; 780 *attrs = values; 781 return str.IsEOF() ? B_BAD_VALUE : B_OK; 782 } 783 784 785 status_t 786 ReplyInterpreter::_OperationError(Opcode op) 787 { 788 if (fDecodeError) 789 return B_BAD_VALUE; 790 791 if (fReply == NULL) 792 return B_NOT_INITIALIZED; 793 794 if (fReply->Error() != B_OK || fReply->Stream().IsEOF()) { 795 fDecodeError = true; 796 return fReply->Error(); 797 } 798 799 if (fReply->Stream().GetInt() != op) { 800 fDecodeError = true; 801 return B_BAD_VALUE; 802 } 803 804 status_t result = _NFS4ErrorToHaiku(fReply->Stream().GetUInt()); 805 if (result != B_OK) 806 fDecodeError = true; 807 return result; 808 } 809 810 811 status_t 812 ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x) 813 { 814 switch (x) { 815 case NFS4_OK: return B_OK; 816 case NFS4ERR_PERM: return B_PERMISSION_DENIED; 817 case NFS4ERR_NOENT: return B_ENTRY_NOT_FOUND; 818 case NFS4ERR_IO: return B_IO_ERROR; 819 case NFS4ERR_NXIO: return B_DEVICE_NOT_FOUND; 820 case NFS4ERR_ACCESS: return B_NOT_ALLOWED; 821 case NFS4ERR_EXIST: return B_FILE_EXISTS; 822 case NFS4ERR_XDEV: return B_CROSS_DEVICE_LINK; 823 case NFS4ERR_NOTDIR: return B_NOT_A_DIRECTORY; 824 case NFS4ERR_ISDIR: return B_IS_A_DIRECTORY; 825 case NFS4ERR_INVAL: return B_BAD_VALUE; 826 case NFS4ERR_FBIG: return B_FILE_TOO_LARGE; 827 case NFS4ERR_NOTSUPP: return B_UNSUPPORTED; 828 case NFS4ERR_ROFS: return B_READ_ONLY_DEVICE; 829 case NFS4ERR_NAMETOOLONG: return B_NAME_TOO_LONG; 830 case NFS4ERR_NOTEMPTY: return B_DIRECTORY_NOT_EMPTY; 831 // ... 832 case NFS4ERR_DELAY: 833 case NFS4ERR_DENIED: 834 case NFS4ERR_LOCKED: 835 case NFS4ERR_GRACE: 836 return B_WOULD_BLOCK; 837 838 case NFS4ERR_STALE: 839 case NFS4ERR_FHEXPIRED: 840 return B_FILE_NOT_FOUND; 841 // ... 842 default: return B_ERROR; 843 } 844 } 845 846