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
31static status_t
32ProcessStream(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
41FSLocation::~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
57FSLocations::~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
71AttrValue::AttrValue()
72	:
73	fAttribute(0),
74	fFreePointer(false)
75{
76}
77
78
79AttrValue::~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
90DirEntry::DirEntry()
91	:
92	fName(NULL),
93	fAttrs(NULL),
94	fAttrCount(0)
95{
96}
97
98
99DirEntry::~DirEntry()
100{
101	free(const_cast<char*>(fName));
102	delete[] fAttrs;
103}
104
105
106ReplyInterpreter::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
119ReplyInterpreter::~ReplyInterpreter()
120{
121	delete fReply;
122}
123
124
125void
126ReplyInterpreter::_ParseHeader()
127{
128	CALLED();
129
130	fNFS4Error = fReply->Stream().GetUInt();
131	fReply->Stream().GetOpaque(NULL);
132	fReply->Stream().GetUInt();
133}
134
135
136status_t
137ReplyInterpreter::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
157status_t
158ReplyInterpreter::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
175status_t
176ReplyInterpreter::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
190status_t
191ReplyInterpreter::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
213static 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
223status_t
224ReplyInterpreter::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
236status_t
237ReplyInterpreter::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
261status_t
262ReplyInterpreter::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
278status_t
279ReplyInterpreter::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
296status_t
297ReplyInterpreter::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
316status_t
317ReplyInterpreter::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
334status_t
335ReplyInterpreter::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
412status_t
413ReplyInterpreter::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
430status_t
431ReplyInterpreter::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
447status_t
448ReplyInterpreter::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
513status_t
514ReplyInterpreter::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
529status_t
530ReplyInterpreter::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
546status_t
547ReplyInterpreter::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
568status_t
569ReplyInterpreter::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
585status_t
586ReplyInterpreter::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
601status_t
602ReplyInterpreter::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
618const char**
619ReplyInterpreter::_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
638out:
639	for (uint32 j = 0; j < i; j++)
640		free(path[i]);
641	delete[] path;
642	return NULL;
643}
644
645
646status_t
647ReplyInterpreter::_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
888status_t
889ReplyInterpreter::_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
920status_t
921ReplyInterpreter::_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