2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Paweł Dziepak, pdziepak@quarnos.org
10 #include "ReplyInterpreter.h"
14 #include <AutoDeleter.h>
15 #include <util/kernel_cpp.h>
20 FSLocation::~FSLocation()
22 if (fRootPath
!= NULL
) {
23 for (uint32 i
= 0; fRootPath
[i
] != NULL
; i
++)
24 free(const_cast<char*>(fRootPath
[i
]));
28 for (uint32 i
= 0; i
< fCount
; i
++)
29 free(const_cast<char*>(fLocations
[i
]));
34 FSLocations::~FSLocations()
36 if (fRootPath
!= NULL
) {
37 for (uint32 i
= 0; fRootPath
[i
] != NULL
; i
++)
38 free(const_cast<char*>(fRootPath
[i
]));
46 AttrValue::AttrValue()
54 AttrValue::~AttrValue()
58 if (fAttribute
== FATTR4_FS_LOCATIONS
)
59 delete fData
.fLocations
;
74 free(const_cast<char*>(fName
));
79 ReplyInterpreter::ReplyInterpreter(RPC::Reply
* reply
)
90 ReplyInterpreter::~ReplyInterpreter()
97 ReplyInterpreter::_ParseHeader()
99 fNFS4Error
= fReply
->Stream().GetUInt();
100 fReply
->Stream().GetOpaque(NULL
);
101 fReply
->Stream().GetUInt();
106 ReplyInterpreter::Access(uint32
* supported
, uint32
* allowed
)
108 status_t res
= _OperationError(OpAccess
);
112 uint32 support
= fReply
->Stream().GetUInt();
113 uint32 allow
= fReply
->Stream().GetUInt();
115 if (supported
!= NULL
)
116 *supported
= support
;
120 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
125 ReplyInterpreter::Close()
127 status_t res
= _OperationError(OpClose
);
131 fReply
->Stream().GetUInt();
132 fReply
->Stream().GetUInt();
133 fReply
->Stream().GetUInt();
134 fReply
->Stream().GetUInt();
136 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
141 ReplyInterpreter::Commit()
143 status_t res
= _OperationError(OpCommit
);
147 fReply
->Stream().GetOpaque(NULL
);
149 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
154 ReplyInterpreter::Create(uint64
* before
, uint64
* after
, bool& atomic
)
156 status_t res
= _OperationError(OpCreate
);
160 atomic
= fReply
->Stream().GetBoolean();
161 *before
= fReply
->Stream().GetUHyper();
162 *after
= fReply
->Stream().GetUHyper();
164 uint32 count
= fReply
->Stream().GetUInt();
165 for (uint32 i
= 0; i
< count
; i
++)
166 fReply
->Stream().GetUInt();
168 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
172 // Bit Twiddling Hacks
173 // http://graphics.stanford.edu/~seander/bithacks.html
174 static inline uint32
CountBits(uint32 v
)
176 v
= v
- ((v
>> 1) & 0x55555555);
177 v
= (v
& 0x33333333) + ((v
>> 2) & 0x33333333);
178 return (((v
+ (v
>> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
183 ReplyInterpreter::GetAttr(AttrValue
** attrs
, uint32
* count
)
185 status_t res
= _OperationError(OpGetAttr
);
189 return _DecodeAttrs(fReply
->Stream(), attrs
, count
);
194 ReplyInterpreter::GetFH(FileHandle
* fh
)
196 status_t res
= _OperationError(OpGetFH
);
201 const void* ptr
= fReply
->Stream().GetOpaque(&size
);
202 if (ptr
== NULL
|| size
> NFS4_FHSIZE
)
207 memcpy(fh
->fData
, ptr
, size
);
210 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
215 ReplyInterpreter::Link(uint64
* before
, uint64
* after
, bool& atomic
)
217 status_t res
= _OperationError(OpLink
);
221 atomic
= fReply
->Stream().GetBoolean();
222 *before
= fReply
->Stream().GetUHyper();
223 *after
= fReply
->Stream().GetUHyper();
225 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
230 ReplyInterpreter::Lock(LockInfo
* linfo
)
232 status_t res
= _OperationError(OpLock
);
236 linfo
->fOwner
->fStateSeq
= fReply
->Stream().GetUInt();
237 linfo
->fOwner
->fStateId
[0] = fReply
->Stream().GetUInt();
238 linfo
->fOwner
->fStateId
[1] = fReply
->Stream().GetUInt();
239 linfo
->fOwner
->fStateId
[2] = fReply
->Stream().GetUInt();
241 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
246 ReplyInterpreter::LockT(uint64
* pos
, uint64
* len
, LockType
* type
)
248 status_t res
= _OperationError(OpLockT
);
249 if (res
!= B_WOULD_BLOCK
|| NFS4Error() != NFS4ERR_DENIED
)
252 *pos
= fReply
->Stream().GetUHyper();
253 *len
= fReply
->Stream().GetUHyper();
254 *type
= static_cast<LockType
>(fReply
->Stream().GetInt());
256 fReply
->Stream().GetUHyper();
257 fReply
->Stream().GetOpaque(NULL
);
259 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
264 ReplyInterpreter::LockU(LockInfo
* linfo
)
266 status_t res
= _OperationError(OpLockU
);
270 linfo
->fOwner
->fStateSeq
= fReply
->Stream().GetUInt();
271 linfo
->fOwner
->fStateId
[0] = fReply
->Stream().GetUInt();
272 linfo
->fOwner
->fStateId
[1] = fReply
->Stream().GetUInt();
273 linfo
->fOwner
->fStateId
[2] = fReply
->Stream().GetUInt();
275 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
280 ReplyInterpreter::Open(uint32
* id
, uint32
* seq
, bool* confirm
,
281 OpenDelegationData
* delegData
, ChangeInfo
* changeInfo
)
283 status_t res
= _OperationError(OpOpen
);
287 *seq
= fReply
->Stream().GetUInt();
288 id
[0] = fReply
->Stream().GetUInt();
289 id
[1] = fReply
->Stream().GetUInt();
290 id
[2] = fReply
->Stream().GetUInt();
293 bool atomic
= fReply
->Stream().GetBoolean();
294 uint64 before
= fReply
->Stream().GetUHyper();
295 uint64 after
= fReply
->Stream().GetUHyper();
296 if (changeInfo
!= NULL
) {
297 changeInfo
->fAtomic
= atomic
;
298 changeInfo
->fBefore
= before
;
299 changeInfo
->fAfter
= after
;
302 uint32 flags
= fReply
->Stream().GetUInt();
303 *confirm
= (flags
& OPEN4_RESULT_CONFIRM
) == OPEN4_RESULT_CONFIRM
;
306 uint32 bcount
= fReply
->Stream().GetUInt();
307 for (uint32 i
= 0; i
< bcount
; i
++)
308 fReply
->Stream().GetUInt();
311 uint32 delegation
= fReply
->Stream().GetUInt();
312 OpenDelegationData data
;
313 if (delegData
== NULL
)
316 if (delegation
== OPEN_DELEGATE_NONE
) {
317 delegData
->fType
= OPEN_DELEGATE_NONE
;
318 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
321 delegData
->fStateSeq
= fReply
->Stream().GetUInt();
322 delegData
->fStateID
[0] = fReply
->Stream().GetUInt();
323 delegData
->fStateID
[1] = fReply
->Stream().GetUInt();
324 delegData
->fStateID
[2] = fReply
->Stream().GetUInt();
326 delegData
->fRecall
= fReply
->Stream().GetBoolean();
328 switch (delegation
) {
329 case OPEN_DELEGATE_READ
:
330 delegData
->fType
= OPEN_DELEGATE_READ
;
332 case OPEN_DELEGATE_WRITE
:
333 delegData
->fType
= OPEN_DELEGATE_WRITE
;
335 int32 limitBy
= fReply
->Stream().GetInt();
336 if (limitBy
== NFS_LIMIT_SIZE
)
337 delegData
->fSpaceLimit
= fReply
->Stream().GetUHyper();
338 else if (limitBy
== NFS_LIMIT_BLOCKS
) {
339 uint32 numBlocks
= fReply
->Stream().GetUInt();
340 delegData
->fSpaceLimit
= fReply
->Stream().GetUInt() * numBlocks
;
346 fReply
->Stream().GetUInt();
347 fReply
->Stream().GetUInt();
348 fReply
->Stream().GetUInt();
349 fReply
->Stream().GetOpaque(NULL
);
351 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
356 ReplyInterpreter::OpenConfirm(uint32
* stateSeq
)
358 status_t res
= _OperationError(OpOpenConfirm
);
362 *stateSeq
= fReply
->Stream().GetUInt();
363 fReply
->Stream().GetUInt();
364 fReply
->Stream().GetUInt();
365 fReply
->Stream().GetUInt();
367 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
372 ReplyInterpreter::Read(void* buffer
, uint32
* size
, bool* eof
)
374 status_t res
= _OperationError(OpRead
);
378 *eof
= fReply
->Stream().GetBoolean();
379 const void* ptr
= fReply
->Stream().GetOpaque(size
);
380 memcpy(buffer
, ptr
, *size
);
382 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
387 ReplyInterpreter::ReadDir(uint64
* cookie
, uint64
* cookieVerf
,
388 DirEntry
** dirents
, uint32
* _count
, bool* eof
)
390 status_t res
= _OperationError(OpReadDir
);
394 *cookieVerf
= fReply
->Stream().GetUHyper();
399 // TODO: using list instead of array would make this much more elegant
401 XDR::Stream::Position dataStart
= fReply
->Stream().Current();
402 isNext
= fReply
->Stream().GetBoolean();
404 fReply
->Stream().GetUHyper();
406 free(fReply
->Stream().GetString());
409 _DecodeAttrs(fReply
->Stream(), &values
, &attrCount
);
414 isNext
= fReply
->Stream().GetBoolean();
417 DirEntry
* entries
= new(std::nothrow
) DirEntry
[count
];
422 fReply
->Stream().SetPosition(dataStart
);
423 isNext
= fReply
->Stream().GetBoolean();
425 *cookie
= fReply
->Stream().GetUHyper();
427 entries
[count
].fName
= fReply
->Stream().GetString();
428 _DecodeAttrs(fReply
->Stream(), &entries
[count
].fAttrs
,
429 &entries
[count
].fAttrCount
);
433 isNext
= fReply
->Stream().GetBoolean();
435 *eof
= fReply
->Stream().GetBoolean();
440 if (fReply
->Stream().IsEOF()) {
450 ReplyInterpreter::ReadLink(void* buffer
, uint32
* size
, uint32 maxSize
)
452 status_t res
= _OperationError(OpReadLink
);
456 const void* ptr
= fReply
->Stream().GetOpaque(size
);
457 memcpy(buffer
, ptr
, min_c(*size
, maxSize
));
459 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
464 ReplyInterpreter::Remove(uint64
* before
, uint64
* after
, bool& atomic
)
466 status_t res
= _OperationError(OpRemove
);
470 atomic
= fReply
->Stream().GetBoolean();
471 *before
= fReply
->Stream().GetUHyper();
472 *after
= fReply
->Stream().GetUHyper();
474 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
479 ReplyInterpreter::Rename(uint64
* fromBefore
, uint64
* fromAfter
,
480 bool& fromAtomic
, uint64
* toBefore
, uint64
* toAfter
, bool& toAtomic
)
482 status_t res
= _OperationError(OpRename
);
486 fromAtomic
= fReply
->Stream().GetBoolean();
487 *fromBefore
= fReply
->Stream().GetUHyper();
488 *fromAfter
= fReply
->Stream().GetUHyper();
490 toAtomic
= fReply
->Stream().GetBoolean();
491 *toBefore
= fReply
->Stream().GetUHyper();
492 *toAfter
= fReply
->Stream().GetUHyper();
493 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
498 ReplyInterpreter::SetAttr()
500 status_t res
= _OperationError(OpSetAttr
);
504 uint32 bcount
= fReply
->Stream().GetUInt();
505 for (uint32 i
= 0; i
< bcount
; i
++)
506 fReply
->Stream().GetUInt();
508 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
513 ReplyInterpreter::SetClientID(uint64
* clientid
, uint64
* verifier
)
515 status_t res
= _OperationError(OpSetClientID
);
519 *clientid
= fReply
->Stream().GetUHyper();
520 *verifier
= fReply
->Stream().GetUHyper();
522 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
527 ReplyInterpreter::Write(uint32
* size
)
529 status_t res
= _OperationError(OpWrite
);
533 *size
= fReply
->Stream().GetUInt();
534 fReply
->Stream().GetInt();
535 fReply
->Stream().GetUHyper();
537 return fReply
->Stream().IsEOF() ? B_BAD_VALUE
: B_OK
;
542 ReplyInterpreter::_GetPath(XDR::ReadStream
& stream
)
544 uint32 count
= stream
.GetUInt();
545 char** path
= new char*[count
+ 1];
550 for (i
= 0; i
< count
; i
++) {
551 path
[i
] = stream
.GetString();
557 return const_cast<const char**>(path
);
560 for (uint32 j
= 0; j
< i
; j
++)
568 ReplyInterpreter::_DecodeAttrs(XDR::ReadStream
& str
, AttrValue
** attrs
,
571 uint32 bcount
= fReply
->Stream().GetUInt();
572 uint32
* bitmap
= new(std::nothrow
) uint32
[bcount
];
575 ArrayDeleter
<uint32
> _(bitmap
);
577 uint32 attr_count
= 0;
578 for (uint32 i
= 0; i
< bcount
; i
++) {
579 bitmap
[i
] = str
.GetUInt();
580 attr_count
+= CountBits(bitmap
[i
]);
583 if (attr_count
== 0) {
587 } else if (attr_count
> FATTR4_MAXIMUM_ATTR_ID
)
591 const void* ptr
= str
.GetOpaque(&size
);
592 XDR::ReadStream
stream(const_cast<void*>(ptr
), size
);
594 AttrValue
* values
= new(std::nothrow
) AttrValue
[attr_count
];
600 if (sIsAttrSet(FATTR4_SUPPORTED_ATTRS
, bitmap
, bcount
)) {
601 values
[current
].fAttribute
= FATTR4_SUPPORTED_ATTRS
;
602 uint32 count
= stream
.GetInt();
604 // two uint32 are enough for NFS4, not for NFS4.1
605 for (i
= 0; i
< min_c(count
, 2); i
++)
606 ((uint32
*)&values
[current
].fData
.fValue64
)[i
] = stream
.GetUInt();
607 for (; i
< count
; i
++)
612 if (sIsAttrSet(FATTR4_TYPE
, bitmap
, bcount
)) {
613 values
[current
].fAttribute
= FATTR4_TYPE
;
614 values
[current
].fData
.fValue32
= stream
.GetInt();
618 if (sIsAttrSet(FATTR4_FH_EXPIRE_TYPE
, bitmap
, bcount
)) {
619 values
[current
].fAttribute
= FATTR4_FH_EXPIRE_TYPE
;
620 values
[current
].fData
.fValue32
= stream
.GetUInt();
624 if (sIsAttrSet(FATTR4_CHANGE
, bitmap
, bcount
)) {
625 values
[current
].fAttribute
= FATTR4_CHANGE
;
626 values
[current
].fData
.fValue64
= stream
.GetUHyper();
630 if (sIsAttrSet(FATTR4_SIZE
, bitmap
, bcount
)) {
631 values
[current
].fAttribute
= FATTR4_SIZE
;
632 values
[current
].fData
.fValue64
= stream
.GetUHyper();
636 if (sIsAttrSet(FATTR4_FSID
, bitmap
, bcount
)) {
637 values
[current
].fAttribute
= FATTR4_FSID
;
638 values
[current
].fFreePointer
= true;
641 fsid
.fMajor
= stream
.GetUHyper();
642 fsid
.fMinor
= stream
.GetUHyper();
644 values
[current
].fData
.fPointer
= malloc(sizeof(fsid
));
645 memcpy(values
[current
].fData
.fPointer
, &fsid
, sizeof(fsid
));
649 if (sIsAttrSet(FATTR4_LEASE_TIME
, bitmap
, bcount
)) {
650 values
[current
].fAttribute
= FATTR4_LEASE_TIME
;
651 values
[current
].fData
.fValue32
= stream
.GetUInt();
655 if (sIsAttrSet(FATTR4_FILEID
, bitmap
, bcount
)) {
656 values
[current
].fAttribute
= FATTR4_FILEID
;
657 values
[current
].fData
.fValue64
= stream
.GetUHyper();
661 if (sIsAttrSet(FATTR4_FILES_FREE
, bitmap
, bcount
)) {
662 values
[current
].fAttribute
= FATTR4_FILES_FREE
;
663 values
[current
].fData
.fValue64
= stream
.GetUHyper();
667 if (sIsAttrSet(FATTR4_FILES_TOTAL
, bitmap
, bcount
)) {
668 values
[current
].fAttribute
= FATTR4_FILES_TOTAL
;
669 values
[current
].fData
.fValue64
= stream
.GetUHyper();
673 if (sIsAttrSet(FATTR4_FS_LOCATIONS
, bitmap
, bcount
)) {
674 values
[current
].fAttribute
= FATTR4_FS_LOCATIONS
;
676 FSLocations
* locs
= new FSLocations
;
677 locs
->fRootPath
= _GetPath(stream
);
678 locs
->fCount
= stream
.GetUInt();
679 locs
->fLocations
= new FSLocation
[locs
->fCount
];
680 for (uint32 i
= 0; i
< locs
->fCount
; i
++) {
681 locs
->fLocations
[i
].fRootPath
= _GetPath(stream
);
682 locs
->fLocations
[i
].fCount
= stream
.GetUInt();
683 locs
->fLocations
[i
].fLocations
684 = new const char*[locs
->fLocations
[i
].fCount
];
685 for (uint32 j
= 0; j
< locs
->fLocations
[i
].fCount
; j
++)
686 locs
->fLocations
[i
].fLocations
[j
] = stream
.GetString();
688 values
[current
].fData
.fLocations
= locs
;
692 if (sIsAttrSet(FATTR4_MAXREAD
, bitmap
, bcount
)) {
693 values
[current
].fAttribute
= FATTR4_MAXREAD
;
694 values
[current
].fData
.fValue64
= stream
.GetUHyper();
698 if (sIsAttrSet(FATTR4_MAXWRITE
, bitmap
, bcount
)) {
699 values
[current
].fAttribute
= FATTR4_MAXWRITE
;
700 values
[current
].fData
.fValue64
= stream
.GetUHyper();
704 if (sIsAttrSet(FATTR4_MODE
, bitmap
, bcount
)) {
705 values
[current
].fAttribute
= FATTR4_MODE
;
706 values
[current
].fData
.fValue32
= stream
.GetUInt();
710 if (sIsAttrSet(FATTR4_NUMLINKS
, bitmap
, bcount
)) {
711 values
[current
].fAttribute
= FATTR4_NUMLINKS
;
712 values
[current
].fData
.fValue32
= stream
.GetUInt();
716 if (sIsAttrSet(FATTR4_OWNER
, bitmap
, bcount
)) {
717 values
[current
].fAttribute
= FATTR4_OWNER
;
718 values
[current
].fFreePointer
= true;
719 values
[current
].fData
.fPointer
= stream
.GetString();
723 if (sIsAttrSet(FATTR4_OWNER_GROUP
, bitmap
, bcount
)) {
724 values
[current
].fAttribute
= FATTR4_OWNER_GROUP
;
725 values
[current
].fFreePointer
= true;
726 values
[current
].fData
.fPointer
= stream
.GetString();
730 if (sIsAttrSet(FATTR4_SPACE_FREE
, bitmap
, bcount
)) {
731 values
[current
].fAttribute
= FATTR4_SPACE_FREE
;
732 values
[current
].fData
.fValue64
= stream
.GetUHyper();
736 if (sIsAttrSet(FATTR4_SPACE_TOTAL
, bitmap
, bcount
)) {
737 values
[current
].fAttribute
= FATTR4_SPACE_TOTAL
;
738 values
[current
].fData
.fValue64
= stream
.GetUHyper();
742 if (sIsAttrSet(FATTR4_TIME_ACCESS
, bitmap
, bcount
)) {
743 values
[current
].fAttribute
= FATTR4_TIME_ACCESS
;
744 values
[current
].fFreePointer
= true;
747 ts
.tv_sec
= static_cast<time_t>(stream
.GetHyper());
748 ts
.tv_nsec
= static_cast<long>(stream
.GetUInt());
750 values
[current
].fData
.fPointer
= malloc(sizeof(ts
));
751 memcpy(values
[current
].fData
.fPointer
, &ts
, sizeof(ts
));
755 if (sIsAttrSet(FATTR4_TIME_CREATE
, bitmap
, bcount
)) {
756 values
[current
].fAttribute
= FATTR4_TIME_CREATE
;
757 values
[current
].fFreePointer
= true;
760 ts
.tv_sec
= static_cast<time_t>(stream
.GetHyper());
761 ts
.tv_nsec
= static_cast<long>(stream
.GetUInt());
763 values
[current
].fData
.fPointer
= malloc(sizeof(ts
));
764 memcpy(values
[current
].fData
.fPointer
, &ts
, sizeof(ts
));
768 if (sIsAttrSet(FATTR4_TIME_METADATA
, bitmap
, bcount
)) {
769 values
[current
].fAttribute
= FATTR4_TIME_METADATA
;
770 values
[current
].fFreePointer
= true;
773 ts
.tv_sec
= static_cast<time_t>(stream
.GetHyper());
774 ts
.tv_nsec
= static_cast<long>(stream
.GetUInt());
776 values
[current
].fData
.fPointer
= malloc(sizeof(ts
));
777 memcpy(values
[current
].fData
.fPointer
, &ts
, sizeof(ts
));
781 if (sIsAttrSet(FATTR4_TIME_MODIFY
, bitmap
, bcount
)) {
782 values
[current
].fAttribute
= FATTR4_TIME_MODIFY
;
783 values
[current
].fFreePointer
= true;
786 ts
.tv_sec
= static_cast<time_t>(stream
.GetHyper());
787 ts
.tv_nsec
= static_cast<long>(stream
.GetUInt());
789 values
[current
].fData
.fPointer
= malloc(sizeof(ts
));
790 memcpy(values
[current
].fData
.fPointer
, &ts
, sizeof(ts
));
805 ReplyInterpreter::_OperationError(Opcode op
)
811 return B_NOT_INITIALIZED
;
813 if (fReply
->Error() != B_OK
|| fReply
->Stream().IsEOF()) {
815 return fReply
->Error();
818 if (fReply
->Stream().GetInt() != op
) {
823 status_t result
= _NFS4ErrorToHaiku(fReply
->Stream().GetUInt());
831 ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x
)
834 case NFS4_OK
: return B_OK
;
835 case NFS4ERR_PERM
: return B_PERMISSION_DENIED
;
836 case NFS4ERR_NOENT
: return B_ENTRY_NOT_FOUND
;
837 case NFS4ERR_IO
: return B_IO_ERROR
;
838 case NFS4ERR_NXIO
: return B_DEVICE_NOT_FOUND
;
839 case NFS4ERR_ACCESS
: return B_NOT_ALLOWED
;
840 case NFS4ERR_EXIST
: return B_FILE_EXISTS
;
841 case NFS4ERR_XDEV
: return B_CROSS_DEVICE_LINK
;
842 case NFS4ERR_NOTDIR
: return B_NOT_A_DIRECTORY
;
843 case NFS4ERR_ISDIR
: return B_IS_A_DIRECTORY
;
844 case NFS4ERR_INVAL
: return B_BAD_VALUE
;
845 case NFS4ERR_FBIG
: return B_FILE_TOO_LARGE
;
846 case NFS4ERR_NOTSUPP
: return B_UNSUPPORTED
;
847 case NFS4ERR_ROFS
: return B_READ_ONLY_DEVICE
;
848 case NFS4ERR_NAMETOOLONG
: return B_NAME_TOO_LONG
;
849 case NFS4ERR_NOTEMPTY
: return B_DIRECTORY_NOT_EMPTY
;
855 return B_WOULD_BLOCK
;
858 case NFS4ERR_FHEXPIRED
:
859 return B_FILE_NOT_FOUND
;
861 default: return B_ERROR
;