diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 8c82e50edd..e58c558db9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -5,6 +5,7 @@ UsePrivateHeaders kernel ; KernelAddon nfs4 : Connection.cpp kernel_interface.cpp + ReplyInterpreter.cpp RequestBuilder.cpp RPCAuth.cpp RPCCall.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 7208d6f4f5..2762d5f114 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -9,6 +9,13 @@ #define NFS4DEFS_H +#define NFS4_FHSIZE 128 + +struct Filehandle { + uint8 fSize; + uint8 fFH[NFS4_FHSIZE]; +}; + enum Procedure { ProcNull = 0, ProcCompound = 1 diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp new file mode 100644 index 0000000000..4ff308137d --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -0,0 +1,181 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "ReplyInterpreter.h" + +#include + +#include + + +ReplyInterpreter::ReplyInterpreter(RPC::Reply* reply) + : + fReply(reply) +{ + fReply->Stream().GetUInt(); + fReply->Stream().GetOpaque(NULL); + fReply->Stream().GetUInt(); +} + + +ReplyInterpreter::~ReplyInterpreter() +{ + delete fReply; +} + + +status_t +ReplyInterpreter::Access(uint32* supported, uint32* allowed) +{ + status_t res = _OperationError(OpAccess); + if (res != B_OK) + return res; + + uint32 support = fReply->Stream().GetUInt(); + uint32 allow = fReply->Stream().GetUInt(); + + if (supported != NULL) + *supported = support; + if (allowed != NULL) + *allowed = allow; + + return B_OK; +} + + +// Bit Twiddling Hacks +// http://graphics.stanford.edu/~seander/bithacks.html +static inline uint32 sCountBits(uint32 v) +{ + v = v - ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; +} + + +static inline bool sIsAttrSet(Attribute attr, uint32* bitmap, uint32 count) +{ + if ((uint32)attr / 32 >= count) + return false; + + return (bitmap[attr / 32] & 1 << attr % 32) != 0; +} + + +status_t +ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count) +{ + status_t res = _OperationError(OpGetAttr); + if (res != B_OK) + return res; + + uint32 bcount = fReply->Stream().GetUInt(); + uint32 *bitmap = new(std::nothrow) uint32[bcount]; + if (bitmap == NULL) + return B_NO_MEMORY; + + uint32 attr_count = 0; + for (uint32 i = 0; i < bcount; i++) { + bitmap[i] = fReply->Stream().GetUInt(); + attr_count = sCountBits(bitmap[i]); + } + + uint32 size; + const void* ptr = fReply->Stream().GetOpaque(&size); + XDR::ReadStream stream(const_cast(ptr), size); + + AttrValue* values = new(std::nothrow) AttrValue[attr_count]; + if (values == NULL) { + delete bitmap; + return B_NO_MEMORY; + } + + uint32 current = 0; + + if (sIsAttrSet(FATTR4_TYPE, bitmap, bcount)) { + values[current].fAttribute = FATTR4_TYPE; + values[current].fData.fValue32 = stream.GetInt(); + current++; + } + + if (sIsAttrSet(FATTR4_FH_EXPIRE_TYPE, bitmap, bcount)) { + values[current].fAttribute = FATTR4_FH_EXPIRE_TYPE; + values[current].fData.fValue32 = stream.GetUInt(); + current++; + } + + if (sIsAttrSet(FATTR4_FILEID, bitmap, bcount)) { + values[current].fAttribute = FATTR4_FILEID; + values[current].fData.fValue64 = stream.GetUHyper(); + current++; + } + + delete bitmap; + + *count = attr_count; + *attrs = values; + return B_OK; +} + + +status_t +ReplyInterpreter::GetFH(Filehandle* fh) +{ + status_t res = _OperationError(OpGetFH); + if (res != B_OK) + return res; + + uint32 size; + const void* ptr = fReply->Stream().GetOpaque(&size); + if (ptr == NULL || size > NFS4_FHSIZE) + return B_BAD_VALUE; + + if (fh != NULL) { + fh->fSize = size; + memcpy(fh->fFH, ptr, size); + } + + return B_OK; +} + + +status_t +ReplyInterpreter::_OperationError(Opcode op) +{ + if (fReply->Error() != B_OK || fReply->Stream().IsEOF()) + return fReply->Error(); + + if (fReply->Stream().GetInt() != op) + return B_BAD_VALUE; + + return _NFS4ErrorToHaiku(fReply->Stream().GetUInt()); +} + + +status_t +ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x) +{ + switch (x) { + case NFS4_OK: return B_OK; + case NFS4ERR_PERM: return B_PERMISSION_DENIED; + case NFS4ERR_NOENT: return B_ENTRY_NOT_FOUND; + case NFS4ERR_IO: return B_IO_ERROR; + case NFS4ERR_NXIO: return B_DEVICE_NOT_FOUND; + case NFS4ERR_ACCESS: return B_PERMISSION_DENIED; + case NFS4ERR_EXIST: return B_FILE_EXISTS; + case NFS4ERR_XDEV: return B_CROSS_DEVICE_LINK; + case NFS4ERR_NOTDIR: return B_NOT_A_DIRECTORY; + case NFS4ERR_ISDIR: return B_IS_A_DIRECTORY; + case NFS4ERR_INVAL: return B_BAD_VALUE; + case NFS4ERR_FBIG: return B_FILE_TOO_LARGE; + // ... + default: return B_ERROR; + } +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h new file mode 100644 index 0000000000..83973b17dd --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -0,0 +1,62 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef REPLYINTERPRETER_H +#define REPLYINTERPRETER_H + + +#include + +#include "NFS4Defs.h" +#include "RPCReply.h" + + +struct AttrValue { + uint8 fAttribute; + union { + uint32 fValue32; + uint64 fValue64; + void* fPointer; + } fData; +}; + +class ReplyInterpreter { +public: + ReplyInterpreter(RPC::Reply* reply); + ~ReplyInterpreter(); + + status_t Access(uint32* supported, uint32* allowed); + status_t GetAttr(AttrValue** attrs, uint32* count); + status_t GetFH(Filehandle* fh); + inline status_t LookUp(); + inline status_t PutRootFH(); + +private: + status_t _OperationError(Opcode op); + + static status_t _NFS4ErrorToHaiku(uint32 x); + + RPC::Reply* fReply; +}; + + +inline status_t +ReplyInterpreter::LookUp() +{ + return _OperationError(OpLookUp); +} + + +inline status_t +ReplyInterpreter::PutRootFH() +{ + return _OperationError(OpPutRootFH); +} + + +#endif // REPLYINTERPRETER_H +