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
ProcessStream(RPC::Reply * reply,const char * callName)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
~FSLocation()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
~FSLocations()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
AttrValue()71 AttrValue::AttrValue()
72 :
73 fAttribute(0),
74 fFreePointer(false)
75 {
76 }
77
78
~AttrValue()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
DirEntry()90 DirEntry::DirEntry()
91 :
92 fName(NULL),
93 fAttrs(NULL),
94 fAttrCount(0)
95 {
96 }
97
98
~DirEntry()99 DirEntry::~DirEntry()
100 {
101 free(const_cast<char*>(fName));
102 delete[] fAttrs;
103 }
104
105
ReplyInterpreter(RPC::Reply * reply)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
~ReplyInterpreter()119 ReplyInterpreter::~ReplyInterpreter()
120 {
121 delete fReply;
122 }
123
124
125 void
_ParseHeader()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
Access(uint32 * supported,uint32 * allowed)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
Close()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
Commit()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
Create(uint64 * before,uint64 * after,bool & atomic)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
CountBits(uint32 v)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
GetAttr(AttrValue ** attrs,uint32 * count)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
GetFH(FileHandle * fh)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
Link(uint64 * before,uint64 * after,bool & atomic)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
Lock(LockInfo * linfo)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
LockT(uint64 * pos,uint64 * len,LockType * type)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
LockU(LockInfo * linfo)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
Open(uint32 * id,uint32 * seq,bool * confirm,OpenDelegationData * delegData,ChangeInfo * changeInfo)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
OpenConfirm(uint32 * stateSeq)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
Read(void * buffer,uint32 * size,bool * eof)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
ReadDir(uint64 * cookie,uint64 * cookieVerf,DirEntry ** dirents,uint32 * _count,bool * eof)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
ReadLink(void * buffer,uint32 * size,uint32 maxSize)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
Remove(uint64 * before,uint64 * after,bool & atomic)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
Rename(uint64 * fromBefore,uint64 * fromAfter,bool & fromAtomic,uint64 * toBefore,uint64 * toAfter,bool & toAtomic)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
SetAttr()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
SetClientID(uint64 * clientid,uint64 * verifier)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
Write(uint32 * size)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**
_GetPath(XDR::ReadStream & stream)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
_DecodeAttrs(XDR::ReadStream & str,AttrValue ** attrs,uint32 * count)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
_OperationError(Opcode op)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
_NFS4ErrorToHaiku(uint32 x)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