xref: /haiku/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp (revision 75fe7b90bbb751ea161dc6d4c81a3f8e694047b5)
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::Create()
130 {
131 	status_t res = _OperationError(OpCreate);
132 	if (res != B_OK)
133 		return res;
134 
135 	fReply->Stream().GetBoolean();
136 	fReply->Stream().GetUHyper();
137 	fReply->Stream().GetUHyper();
138 	uint32 count = fReply->Stream().GetUInt();
139 	for (uint32 i; i < count; i++)
140 		fReply->Stream().GetUInt();
141 
142 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
143 }
144 
145 
146 
147 // Bit Twiddling Hacks
148 // http://graphics.stanford.edu/~seander/bithacks.html
149 static inline uint32 sCountBits(uint32 v)
150 {
151 	v = v - ((v >> 1) & 0x55555555);
152 	v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
153 	return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
154 }
155 
156 
157 status_t
158 ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count)
159 {
160 	status_t res = _OperationError(OpGetAttr);
161 	if (res != B_OK)
162 		return res;
163 
164 	return _DecodeAttrs(fReply->Stream(), attrs, count);
165 }
166 
167 
168 status_t
169 ReplyInterpreter::GetFH(FileHandle* fh)
170 {
171 	status_t res = _OperationError(OpGetFH);
172 	if (res != B_OK)
173 		return res;
174 
175 	uint32 size;
176 	const void* ptr = fReply->Stream().GetOpaque(&size);
177 	if (ptr == NULL || size > NFS4_FHSIZE)
178 		return B_BAD_VALUE;
179 
180 	if (fh != NULL) {
181 		fh->fSize = size;
182 		memcpy(fh->fData, ptr, size);
183 	}
184 
185 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
186 }
187 
188 
189 status_t
190 ReplyInterpreter::Link()
191 {
192 	status_t res = _OperationError(OpLink);
193 	if (res != B_OK)
194 		return res;
195 
196 	fReply->Stream().GetBoolean();
197 	fReply->Stream().GetUHyper();
198 	fReply->Stream().GetUHyper();
199 
200 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
201 }
202 
203 
204 status_t
205 ReplyInterpreter::Lock(LockInfo* linfo)
206 {
207 	status_t res = _OperationError(OpLock);
208 	if (res != B_OK)
209 		return res;
210 
211 	linfo->fOwner->fStateSeq = fReply->Stream().GetUInt();
212 	linfo->fOwner->fStateId[0] = fReply->Stream().GetUInt();
213 	linfo->fOwner->fStateId[1] = fReply->Stream().GetUInt();
214 	linfo->fOwner->fStateId[2] = fReply->Stream().GetUInt();
215 
216 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
217 }
218 
219 
220 status_t
221 ReplyInterpreter::LockT(uint64* pos, uint64* len, LockType* type)
222 {
223 	status_t res = _OperationError(OpLockU);
224 	if (res != B_WOULD_BLOCK || NFS4Error() != NFS4ERR_DENIED)
225 		return res;
226 
227 	*pos = fReply->Stream().GetUHyper();
228 	*len = fReply->Stream().GetUHyper();
229 	*type = static_cast<LockType>(fReply->Stream().GetInt());
230 
231 	fReply->Stream().GetUHyper();
232 	fReply->Stream().GetOpaque(NULL);
233 
234 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
235 }
236 
237 
238 status_t
239 ReplyInterpreter::LockU(LockInfo* linfo)
240 {
241 	status_t res = _OperationError(OpLockU);
242 	if (res != B_OK)
243 		return res;
244 
245 	linfo->fOwner->fStateSeq = fReply->Stream().GetUInt();
246 	linfo->fOwner->fStateId[0] = fReply->Stream().GetUInt();
247 	linfo->fOwner->fStateId[1] = fReply->Stream().GetUInt();
248 	linfo->fOwner->fStateId[2] = fReply->Stream().GetUInt();
249 
250 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
251 }
252 
253 
254 status_t
255 ReplyInterpreter::Open(uint32* id, uint32* seq, bool* confirm)
256 {
257 	status_t res = _OperationError(OpOpen);
258 	if (res != B_OK)
259 		return res;
260 
261 	*seq = fReply->Stream().GetUInt();
262 	id[0] = fReply->Stream().GetUInt();
263 	id[1] = fReply->Stream().GetUInt();
264 	id[2] = fReply->Stream().GetUInt();
265 
266 	// change info
267 	fReply->Stream().GetBoolean();
268 	fReply->Stream().GetUHyper();
269 	fReply->Stream().GetUHyper();
270 
271 	uint32 flags = fReply->Stream().GetUInt();
272 	*confirm = (flags & OPEN4_RESULT_CONFIRM) == OPEN4_RESULT_CONFIRM;
273 
274 	// attrmask
275 	uint32 bcount = fReply->Stream().GetUInt();
276 	for (uint32 i = 0; i < bcount; i++)
277 		fReply->Stream().GetUInt();
278 
279 	// delegation info
280 	fReply->Stream().GetUInt();
281 
282 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
283 }
284 
285 
286 status_t
287 ReplyInterpreter::OpenConfirm(uint32* stateSeq)
288 {
289 	status_t res = _OperationError(OpOpenConfirm);
290 	if (res != B_OK)
291 		return res;
292 
293 	*stateSeq = fReply->Stream().GetUInt();
294 	fReply->Stream().GetUInt();
295 	fReply->Stream().GetUInt();
296 	fReply->Stream().GetUInt();
297 
298 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
299 }
300 
301 
302 status_t
303 ReplyInterpreter::Read(void* buffer, uint32* size, bool* eof)
304 {
305 	status_t res = _OperationError(OpRead);
306 	if (res != B_OK)
307 		return res;
308 
309 	*eof = fReply->Stream().GetBoolean();
310 	const void* ptr = fReply->Stream().GetOpaque(size);
311 	memcpy(buffer, ptr, *size);
312 
313 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
314 }
315 
316 
317 status_t
318 ReplyInterpreter::ReadDir(uint64* cookie, uint64* cookieVerf,
319 	DirEntry** dirents, uint32* _count,	bool* eof)
320 {
321 	status_t res = _OperationError(OpReadDir);
322 	if (res != B_OK)
323 		return res;
324 
325 	*cookieVerf = fReply->Stream().GetUHyper();
326 
327 	bool isNext;
328 	uint32 count = 0;
329 	DirEntry* entries = new(std::nothrow) DirEntry[*_count];
330 	if (entries == NULL)
331 		return B_NO_MEMORY;
332 
333 	isNext = fReply->Stream().GetBoolean();
334 	while (isNext && count < *_count) {
335 		*cookie = fReply->Stream().GetUHyper();
336 
337 		entries[count].fName = fReply->Stream().GetString();
338 		_DecodeAttrs(fReply->Stream(), &entries[count].fAttrs,
339 			&entries[count].fAttrCount);
340 
341 		count++;
342 
343 		isNext = fReply->Stream().GetBoolean();
344 	}
345 	if (!isNext)
346 		*eof = fReply->Stream().GetBoolean();
347 	else
348 		*eof = false;
349 
350 	*_count = count;
351 	*dirents = entries;
352 
353 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
354 }
355 
356 
357 status_t
358 ReplyInterpreter::ReadLink(void* buffer, uint32* size, uint32 maxSize)
359 {
360 	status_t res = _OperationError(OpReadLink);
361 	if (res != B_OK)
362 		return res;
363 
364 	const void* ptr = fReply->Stream().GetOpaque(size);
365 	memcpy(buffer, ptr, min_c(*size, maxSize));
366 
367 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
368 }
369 
370 
371 status_t
372 ReplyInterpreter::Remove()
373 {
374 	status_t res = _OperationError(OpRemove);
375 	if (res != B_OK)
376 		return res;
377 
378 	fReply->Stream().GetBoolean();
379 	fReply->Stream().GetUHyper();
380 	fReply->Stream().GetUHyper();
381 
382 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
383 }
384 
385 
386 status_t
387 ReplyInterpreter::Rename()
388 {
389 	status_t res = _OperationError(OpRename);
390 	if (res != B_OK)
391 		return res;
392 
393 	fReply->Stream().GetBoolean();
394 	fReply->Stream().GetUHyper();
395 	fReply->Stream().GetUHyper();
396 
397 	fReply->Stream().GetBoolean();
398 	fReply->Stream().GetUHyper();
399 	fReply->Stream().GetUHyper();
400 
401 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
402 }
403 
404 
405 status_t
406 ReplyInterpreter::SetAttr()
407 {
408 	status_t res = _OperationError(OpSetAttr);
409 	if (res != B_OK)
410 		return res;
411 
412 	uint32 bcount = fReply->Stream().GetUInt();
413 	for (uint32 i = 0; i < bcount; i++)
414 		fReply->Stream().GetUInt();
415 
416 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
417 }
418 
419 
420 status_t
421 ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier)
422 {
423 	status_t res = _OperationError(OpSetClientID);
424 	if (res != B_OK)
425 		return res;
426 
427 	*clientid = fReply->Stream().GetUHyper();
428 	*verifier = fReply->Stream().GetUHyper();
429 
430 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
431 }
432 
433 
434 status_t
435 ReplyInterpreter::Write(uint32* size)
436 {
437 	status_t res = _OperationError(OpWrite);
438 	if (res != B_OK)
439 		return res;
440 
441 	*size = fReply->Stream().GetUInt();
442 	fReply->Stream().GetInt();
443 	fReply->Stream().GetUHyper();
444 
445 	return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK;
446 }
447 
448 
449 static const char*
450 sFlattenPathname(XDR::ReadStream& str)
451 {
452 	uint32 count = str.GetUInt();
453 	char* pathname = NULL;
454 	uint32 size = 0;
455 	for (uint32 i = 0; i < count; i++) {
456 		const char* path = str.GetString();
457 		size += strlen(path) + 1;
458 		if (pathname == NULL) {
459 			pathname = reinterpret_cast<char*>(malloc(strlen(path + 1)));
460 			pathname[0] = '\0';
461 		} else {
462 			*pathname++ = '/';
463 			pathname = reinterpret_cast<char*>(realloc(pathname, size));
464 		}
465 		strcat(pathname, path);
466 		free(const_cast<char*>(path));
467 	}
468 
469 	return pathname;
470 }
471 
472 
473 status_t
474 ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs,
475 	uint32* count)
476 {
477 	uint32 bcount = fReply->Stream().GetUInt();
478 	uint32 *bitmap = new(std::nothrow) uint32[bcount];
479 	if (bitmap == NULL)
480 		return B_NO_MEMORY;
481 
482 	uint32 attr_count = 0;
483 	for (uint32 i = 0; i < bcount; i++) {
484 		bitmap[i] = str.GetUInt();
485 		attr_count += sCountBits(bitmap[i]);
486 	}
487 
488 	if (attr_count == 0) {
489 		*attrs = NULL;
490 		*count = 0;
491 		return B_OK;
492 	} else if (attr_count > FATTR4_MAXIMUM_ATTR_ID)
493 		return B_BAD_VALUE;
494 
495 	uint32 size;
496 	const void* ptr = str.GetOpaque(&size);
497 	XDR::ReadStream stream(const_cast<void*>(ptr), size);
498 
499 	AttrValue* values = new(std::nothrow) AttrValue[attr_count];
500 	if (values == NULL) {
501 		delete[] bitmap;
502 		return B_NO_MEMORY;
503 	}
504 
505 	uint32 current = 0;
506 
507 	if (sIsAttrSet(FATTR4_SUPPORTED_ATTRS, bitmap, bcount)) {
508 		values[current].fAttribute = FATTR4_SUPPORTED_ATTRS;
509 		uint32 count = stream.GetInt();
510 		uint32 i;
511 		// two uint32 are enough for NFS4, not for NFS4.1
512 		for (i = 0; i < min_c(count, 2); i++)
513 			((uint32*)&values[current].fData.fValue64)[i] = stream.GetUInt();
514 		for (; i < count; i++)
515 			stream.GetUInt();
516 		current++;
517 	}
518 
519 	if (sIsAttrSet(FATTR4_TYPE, bitmap, bcount)) {
520 		values[current].fAttribute = FATTR4_TYPE;
521 		values[current].fData.fValue32 = stream.GetInt();
522 		current++;
523 	}
524 
525 	if (sIsAttrSet(FATTR4_FH_EXPIRE_TYPE, bitmap, bcount)) {
526 		values[current].fAttribute = FATTR4_FH_EXPIRE_TYPE;
527 		values[current].fData.fValue32 = stream.GetUInt();
528 		current++;
529 	}
530 
531 	if (sIsAttrSet(FATTR4_CHANGE, bitmap, bcount)) {
532 		values[current].fAttribute = FATTR4_CHANGE;
533 		values[current].fData.fValue64 = stream.GetUHyper();
534 		current++;
535 	}
536 
537 	if (sIsAttrSet(FATTR4_SIZE, bitmap, bcount)) {
538 		values[current].fAttribute = FATTR4_SIZE;
539 		values[current].fData.fValue64 = stream.GetUHyper();
540 		current++;
541 	}
542 
543 	if (sIsAttrSet(FATTR4_FSID, bitmap, bcount)) {
544 		values[current].fAttribute = FATTR4_FSID;
545 		values[current].fFreePointer = true;
546 
547 		FileSystemId fsid;
548 		fsid.fMajor = stream.GetUHyper();
549 		fsid.fMinor = stream.GetUHyper();
550 
551 		values[current].fData.fPointer = malloc(sizeof(fsid));
552 		memcpy(values[current].fData.fPointer, &fsid, sizeof(fsid));
553 		current++;
554 	}
555 
556 	if (sIsAttrSet(FATTR4_LEASE_TIME, bitmap, bcount)) {
557 		values[current].fAttribute = FATTR4_LEASE_TIME;
558 		values[current].fData.fValue32 = stream.GetUInt();
559 		current++;
560 	}
561 
562 	if (sIsAttrSet(FATTR4_FILEID, bitmap, bcount)) {
563 		values[current].fAttribute = FATTR4_FILEID;
564 		values[current].fData.fValue64 = stream.GetUHyper();
565 		current++;
566 	}
567 
568 	if (sIsAttrSet(FATTR4_FILES_FREE, bitmap, bcount)) {
569 		values[current].fAttribute = FATTR4_FILES_FREE;
570 		values[current].fData.fValue64 = stream.GetUHyper();
571 		current++;
572 	}
573 
574 	if (sIsAttrSet(FATTR4_FILES_TOTAL, bitmap, bcount)) {
575 		values[current].fAttribute = FATTR4_FILES_TOTAL;
576 		values[current].fData.fValue64 = stream.GetUHyper();
577 		current++;
578 	}
579 
580 	if (sIsAttrSet(FATTR4_FS_LOCATIONS, bitmap, bcount)) {
581 		values[current].fAttribute = FATTR4_FS_LOCATIONS;
582 
583 		FSLocations* locs = new FSLocations;
584 		locs->fRootPath = sFlattenPathname(stream);
585 		locs->fCount = stream.GetUInt();
586 		locs->fLocations = new FSLocation[locs->fCount];
587 		for (uint32 i = 0; i < locs->fCount; i++) {
588 			locs->fLocations[i].fRootPath = sFlattenPathname(stream);
589 			locs->fLocations[i].fCount = stream.GetUInt();
590 			locs->fLocations[i].fLocations =
591 				new const char*[locs->fLocations[i].fCount];
592 			for (uint32 j = 0; j < locs->fLocations[i].fCount; j++)
593 				locs->fLocations[i].fLocations[j] = stream.GetString();
594 		}
595 		values[current].fData.fLocations = locs;
596 		current++;
597 	}
598 
599 	if (sIsAttrSet(FATTR4_MAXREAD, bitmap, bcount)) {
600 		values[current].fAttribute = FATTR4_MAXREAD;
601 		values[current].fData.fValue64 = stream.GetUHyper();
602 		current++;
603 	}
604 
605 	if (sIsAttrSet(FATTR4_MAXWRITE, bitmap, bcount)) {
606 		values[current].fAttribute = FATTR4_MAXWRITE;
607 		values[current].fData.fValue64 = stream.GetUHyper();
608 		current++;
609 	}
610 
611 	if (sIsAttrSet(FATTR4_MODE, bitmap, bcount)) {
612 		values[current].fAttribute = FATTR4_MODE;
613 		values[current].fData.fValue32 = stream.GetUInt();
614 		current++;
615 	}
616 
617 	if (sIsAttrSet(FATTR4_NUMLINKS, bitmap, bcount)) {
618 		values[current].fAttribute = FATTR4_NUMLINKS;
619 		values[current].fData.fValue32 = stream.GetUInt();
620 		current++;
621 	}
622 
623 	if (sIsAttrSet(FATTR4_OWNER, bitmap, bcount)) {
624 		values[current].fAttribute = FATTR4_OWNER;
625 		values[current].fFreePointer = true;
626 		values[current].fData.fPointer = stream.GetString();
627 		current++;
628 	}
629 
630 	if (sIsAttrSet(FATTR4_OWNER_GROUP, bitmap, bcount)) {
631 		values[current].fAttribute = FATTR4_OWNER_GROUP;
632 		values[current].fFreePointer = true;
633 		values[current].fData.fPointer = stream.GetString();
634 		current++;
635 	}
636 
637 	if (sIsAttrSet(FATTR4_SPACE_FREE, bitmap, bcount)) {
638 		values[current].fAttribute = FATTR4_SPACE_FREE;
639 		values[current].fData.fValue64 = stream.GetUHyper();
640 		current++;
641 	}
642 
643 	if (sIsAttrSet(FATTR4_SPACE_TOTAL, bitmap, bcount)) {
644 		values[current].fAttribute = FATTR4_SPACE_TOTAL;
645 		values[current].fData.fValue64 = stream.GetUHyper();
646 		current++;
647 	}
648 
649 	if (sIsAttrSet(FATTR4_TIME_ACCESS, bitmap, bcount)) {
650 		values[current].fAttribute = FATTR4_TIME_ACCESS;
651 		values[current].fFreePointer = true;
652 
653 		struct timespec ts;
654 		ts.tv_sec = static_cast<time_t>(stream.GetHyper());
655 		ts.tv_nsec = static_cast<long>(stream.GetUInt());
656 
657 		values[current].fData.fPointer = malloc(sizeof(ts));
658 		memcpy(values[current].fData.fPointer, &ts, sizeof(ts));
659 		current++;
660 	}
661 
662 	if (sIsAttrSet(FATTR4_TIME_CREATE, bitmap, bcount)) {
663 		values[current].fAttribute = FATTR4_TIME_CREATE;
664 		values[current].fFreePointer = true;
665 
666 		struct timespec ts;
667 		ts.tv_sec = static_cast<time_t>(stream.GetHyper());
668 		ts.tv_nsec = static_cast<long>(stream.GetUInt());
669 
670 		values[current].fData.fPointer = malloc(sizeof(ts));
671 		memcpy(values[current].fData.fPointer, &ts, sizeof(ts));
672 		current++;
673 	}
674 
675 	if (sIsAttrSet(FATTR4_TIME_METADATA, bitmap, bcount)) {
676 		values[current].fAttribute = FATTR4_TIME_METADATA;
677 		values[current].fFreePointer = true;
678 
679 		struct timespec ts;
680 		ts.tv_sec = static_cast<time_t>(stream.GetHyper());
681 		ts.tv_nsec = static_cast<long>(stream.GetUInt());
682 
683 		values[current].fData.fPointer = malloc(sizeof(ts));
684 		memcpy(values[current].fData.fPointer, &ts, sizeof(ts));
685 		current++;
686 	}
687 
688 	if (sIsAttrSet(FATTR4_TIME_MODIFY, bitmap, bcount)) {
689 		values[current].fAttribute = FATTR4_TIME_MODIFY;
690 		values[current].fFreePointer = true;
691 
692 		struct timespec ts;
693 		ts.tv_sec = static_cast<time_t>(stream.GetHyper());
694 		ts.tv_nsec = static_cast<long>(stream.GetUInt());
695 
696 		values[current].fData.fPointer = malloc(sizeof(ts));
697 		memcpy(values[current].fData.fPointer, &ts, sizeof(ts));
698 		current++;
699 	}
700 
701 	delete[] bitmap;
702 
703 	*count = attr_count;
704 	*attrs = values;
705 	return str.IsEOF() ? B_BAD_VALUE : B_OK;
706 }
707 
708 
709 status_t
710 ReplyInterpreter::_OperationError(Opcode op)
711 {
712 	if (fDecodeError)
713 		return B_BAD_VALUE;
714 
715 	if (fReply == NULL)
716 		return B_NOT_INITIALIZED;
717 
718 	if (fReply->Error() != B_OK || fReply->Stream().IsEOF()) {
719 		fDecodeError = true;
720 		return fReply->Error();
721 	}
722 
723 	if (fReply->Stream().GetInt() != op) {
724 		fDecodeError = true;
725 		return B_BAD_VALUE;
726 	}
727 
728 	status_t result = _NFS4ErrorToHaiku(fReply->Stream().GetUInt());
729 	if (result != B_OK)
730 		fDecodeError = true;
731 	return result;
732 }
733 
734 
735 status_t
736 ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x)
737 {
738 	switch (x) {
739 		case NFS4_OK:			return B_OK;
740 		case NFS4ERR_PERM:		return B_PERMISSION_DENIED;
741 		case NFS4ERR_NOENT:		return B_ENTRY_NOT_FOUND;
742 		case NFS4ERR_IO:		return B_IO_ERROR;
743 		case NFS4ERR_NXIO:		return B_DEVICE_NOT_FOUND;
744 		case NFS4ERR_ACCESS:	return B_NOT_ALLOWED;
745 		case NFS4ERR_EXIST:		return B_FILE_EXISTS;
746 		case NFS4ERR_XDEV:		return B_CROSS_DEVICE_LINK;
747 		case NFS4ERR_NOTDIR:	return B_NOT_A_DIRECTORY;
748 		case NFS4ERR_ISDIR:		return B_IS_A_DIRECTORY;
749 		case NFS4ERR_INVAL:		return B_BAD_VALUE;
750 		case NFS4ERR_FBIG:		return B_FILE_TOO_LARGE;
751 		// ...
752 		case NFS4ERR_DELAY:
753 		case NFS4ERR_DENIED:
754 		case NFS4ERR_LOCKED:
755 		case NFS4ERR_GRACE:
756 								return B_WOULD_BLOCK;
757 		case NFS4ERR_FHEXPIRED:	return B_ENTRY_NOT_FOUND;
758 		// ...
759 		default:				return B_ERROR;
760 	}
761 }
762 
763