nfs4: Add read_dir() hook
This commit is contained in:
@@ -30,7 +30,8 @@ Filesystem::~Filesystem()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath)
|
Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
|
||||||
|
dev_t id)
|
||||||
{
|
{
|
||||||
RequestBuilder req(ProcCompound);
|
RequestBuilder req(ProcCompound);
|
||||||
req.PutRootFH();
|
req.PutRootFH();
|
||||||
@@ -97,14 +98,14 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath)
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
if (count != 1 || values[0].fAttribute != FATTR4_FH_EXPIRE_TYPE) {
|
if (count != 1 || values[0].fAttribute != FATTR4_FH_EXPIRE_TYPE) {
|
||||||
delete values;
|
delete[] values;
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently, only persistent filehandles are supported. That will be
|
// Currently, only persistent filehandles are supported. That will be
|
||||||
// changed soon.
|
// changed soon.
|
||||||
if (values[0].fData.fValue32 != FH4_PERSISTENT) {
|
if (values[0].fData.fValue32 != FH4_PERSISTENT) {
|
||||||
delete values;
|
delete[] values;
|
||||||
return B_UNSUPPORTED;
|
return B_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,8 +113,9 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath)
|
|||||||
fs->fFHExpiryType = values[0].fData.fValue32;
|
fs->fFHExpiryType = values[0].fData.fValue32;
|
||||||
memcpy(&fs->fRootFH, &fh, sizeof(Filehandle));
|
memcpy(&fs->fRootFH, &fh, sizeof(Filehandle));
|
||||||
fs->fServer = serv;
|
fs->fServer = serv;
|
||||||
|
fs->fDevId = id;
|
||||||
|
|
||||||
delete values;
|
delete[] values;
|
||||||
|
|
||||||
*pfs = fs;
|
*pfs = fs;
|
||||||
|
|
||||||
@@ -124,6 +126,6 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath)
|
|||||||
Inode*
|
Inode*
|
||||||
Filesystem::CreateRootInode()
|
Filesystem::CreateRootInode()
|
||||||
{
|
{
|
||||||
return new(std::nothrow)Inode(this, fRootFH);
|
return new(std::nothrow)Inode(this, fRootFH, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class Inode;
|
|||||||
class Filesystem {
|
class Filesystem {
|
||||||
public:
|
public:
|
||||||
static status_t Mount(Filesystem** pfs, RPC::Server* serv,
|
static status_t Mount(Filesystem** pfs, RPC::Server* serv,
|
||||||
const char* path);
|
const char* path, dev_t id);
|
||||||
~Filesystem();
|
~Filesystem();
|
||||||
|
|
||||||
Inode* CreateRootInode();
|
Inode* CreateRootInode();
|
||||||
@@ -27,6 +27,7 @@ public:
|
|||||||
inline RPC::Server* Server();
|
inline RPC::Server* Server();
|
||||||
inline uint64 GetId();
|
inline uint64 GetId();
|
||||||
|
|
||||||
|
inline dev_t DevId() const;
|
||||||
private:
|
private:
|
||||||
Filesystem();
|
Filesystem();
|
||||||
|
|
||||||
@@ -37,6 +38,7 @@ private:
|
|||||||
RPC::Server* fServer;
|
RPC::Server* fServer;
|
||||||
|
|
||||||
vint64 fId;
|
vint64 fId;
|
||||||
|
dev_t fDevId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -54,5 +56,12 @@ Filesystem::GetId()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline dev_t
|
||||||
|
Filesystem::DevId() const
|
||||||
|
{
|
||||||
|
return fDevId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // FILESYSTEM_H
|
#endif // FILESYSTEM_H
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "Inode.h"
|
#include "Inode.h"
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "ReplyInterpreter.h"
|
#include "ReplyInterpreter.h"
|
||||||
@@ -17,9 +18,10 @@
|
|||||||
|
|
||||||
// Creating Inode object from Filehandle probably is not a good idea when
|
// Creating Inode object from Filehandle probably is not a good idea when
|
||||||
// filehandles are volatile.
|
// filehandles are volatile.
|
||||||
Inode::Inode(Filesystem* fs, const Filehandle &fh)
|
Inode::Inode(Filesystem* fs, const Filehandle &fh, Inode* parent)
|
||||||
:
|
:
|
||||||
fFilesystem(fs)
|
fFilesystem(fs),
|
||||||
|
fParent(parent)
|
||||||
{
|
{
|
||||||
memcpy(&fHandle, &fh, sizeof(fh));
|
memcpy(&fHandle, &fh, sizeof(fh));
|
||||||
|
|
||||||
@@ -53,7 +55,7 @@ Inode::Inode(Filesystem* fs, const Filehandle &fh)
|
|||||||
// FATTR4_TYPE is mandatory
|
// FATTR4_TYPE is mandatory
|
||||||
fType = values[0].fData.fValue32;
|
fType = values[0].fData.fValue32;
|
||||||
|
|
||||||
delete values;
|
delete[] values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -82,8 +84,10 @@ Inode::Stat(struct stat* st)
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
// FATTR4_SIZE is mandatory
|
// FATTR4_SIZE is mandatory
|
||||||
if (count < 1 || values[0].fAttribute != FATTR4_SIZE)
|
if (count < 1 || values[0].fAttribute != FATTR4_SIZE) {
|
||||||
|
delete[] values;
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
}
|
||||||
st->st_size = values[0].fData.fValue64;
|
st->st_size = values[0].fData.fValue64;
|
||||||
|
|
||||||
uint32 next = 1;
|
uint32 next = 1;
|
||||||
@@ -103,7 +107,7 @@ Inode::Stat(struct stat* st)
|
|||||||
st->st_uid = 0;
|
st->st_uid = 0;
|
||||||
st->st_gid = 0;
|
st->st_gid = 0;
|
||||||
|
|
||||||
delete values;
|
delete[] values;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +139,126 @@ Inode::OpenDir(uint64* cookie)
|
|||||||
if (allowed & ACCESS4_READ != ACCESS4_READ)
|
if (allowed & ACCESS4_READ != ACCESS4_READ)
|
||||||
return B_PERMISSION_DENIED;
|
return B_PERMISSION_DENIED;
|
||||||
|
|
||||||
|
cookie[0] = 0;
|
||||||
|
cookie[1] = 2;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie,
|
||||||
|
bool* eof)
|
||||||
|
{
|
||||||
|
RequestBuilder req(ProcCompound);
|
||||||
|
req.PutFH(fHandle);
|
||||||
|
|
||||||
|
Attribute attr[] = { FATTR4_FILEID };
|
||||||
|
req.ReadDir(*count, cookie, attr, sizeof(attr) / sizeof(Attribute));
|
||||||
|
|
||||||
|
RPC::Reply *rpl;
|
||||||
|
fFilesystem->Server()->SendCall(req.Request(), &rpl);
|
||||||
|
ReplyInterpreter reply(rpl);
|
||||||
|
|
||||||
|
status_t result;
|
||||||
|
result = reply.PutFH();
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return reply.ReadDir(cookie, dirents, count, eof);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::_FillDirEntry(struct dirent* de, ino_t id, const char* name, uint32 pos,
|
||||||
|
uint32 size)
|
||||||
|
{
|
||||||
|
uint32 nameSize = strlen(name);
|
||||||
|
const uint32 entSize = sizeof(struct dirent);
|
||||||
|
|
||||||
|
if (pos + entSize + nameSize > size)
|
||||||
|
return B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
de->d_dev = fFilesystem->DevId();
|
||||||
|
de->d_ino = id;
|
||||||
|
de->d_reclen = entSize + nameSize;
|
||||||
|
if (de->d_reclen % 8 != 0)
|
||||||
|
de->d_reclen += 8 - de->d_reclen % 8;
|
||||||
|
|
||||||
|
strcpy(de->d_name, name);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie)
|
||||||
|
{
|
||||||
|
uint32 count = 0;
|
||||||
|
uint32 pos = 0;
|
||||||
|
uint32 this_count;
|
||||||
|
bool eof = false;
|
||||||
|
|
||||||
|
char* buffer = reinterpret_cast<char*>(_buffer);
|
||||||
|
|
||||||
|
if (cookie[0] == 0 && cookie[1] == 2 && count < *_count) {
|
||||||
|
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
|
||||||
|
|
||||||
|
_FillDirEntry(de, fFileId, ".", pos, size);
|
||||||
|
|
||||||
|
pos += de->d_reclen;
|
||||||
|
count++;
|
||||||
|
cookie[1]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cookie[0] == 0 && cookie[1] == 1 && count < *_count) {
|
||||||
|
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
|
||||||
|
|
||||||
|
if (fParent != NULL)
|
||||||
|
_FillDirEntry(de, fParent->fFileId, "..", pos, size);
|
||||||
|
else
|
||||||
|
_FillDirEntry(de, fFileId, "..", pos, size);
|
||||||
|
|
||||||
|
pos += de->d_reclen;
|
||||||
|
count++;
|
||||||
|
cookie[1]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (count < *_count && !eof) {
|
||||||
|
this_count = *_count;
|
||||||
|
DirEntry* dirents;
|
||||||
|
|
||||||
|
status_t result = _ReadDirOnce(&dirents, &this_count, cookie, &eof);
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
uint32 i;
|
||||||
|
for (i = 0; i < this_count; i++) {
|
||||||
|
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
|
||||||
|
|
||||||
|
ino_t id;
|
||||||
|
if (dirents[i].fAttrCount == 1)
|
||||||
|
id = _FileIdToInoT(dirents[i].fAttrs[0].fData.fValue64);
|
||||||
|
else
|
||||||
|
id = _FileIdToInoT(fFilesystem->GetId());
|
||||||
|
|
||||||
|
const char* name = dirents[i].fName;
|
||||||
|
if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) {
|
||||||
|
eof = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += de->d_reclen;
|
||||||
|
}
|
||||||
|
delete[] dirents;
|
||||||
|
count += i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0 && this_count > 0)
|
||||||
|
return B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
|
*_count = count;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,35 +15,54 @@
|
|||||||
|
|
||||||
#include "Filesystem.h"
|
#include "Filesystem.h"
|
||||||
#include "NFS4Defs.h"
|
#include "NFS4Defs.h"
|
||||||
|
#include "ReplyInterpreter.h"
|
||||||
|
|
||||||
|
|
||||||
class Inode {
|
class Inode {
|
||||||
public:
|
public:
|
||||||
Inode(Filesystem* fs, const Filehandle &fh);
|
Inode(Filesystem* fs, const Filehandle &fh,
|
||||||
|
Inode* parent);
|
||||||
|
|
||||||
inline ino_t ID() const;
|
inline ino_t ID() const;
|
||||||
inline mode_t Type() const;
|
inline mode_t Type() const;
|
||||||
|
|
||||||
status_t Stat(struct stat* st);
|
status_t Stat(struct stat* st);
|
||||||
status_t OpenDir(uint64* cookie);
|
status_t OpenDir(uint64* cookie);
|
||||||
|
status_t ReadDir(void* buffer, uint32 size,
|
||||||
|
uint32* count, uint64* cookie);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
status_t _ReadDirOnce(DirEntry** dirents, uint32* count,
|
||||||
|
uint64* cookie, bool* eof);
|
||||||
|
status_t _FillDirEntry(struct dirent* de, ino_t id,
|
||||||
|
const char* name, uint32 pos, uint32 size);
|
||||||
|
|
||||||
|
static inline ino_t _FileIdToInoT(uint64 fileid);
|
||||||
|
|
||||||
uint64 fFileId;
|
uint64 fFileId;
|
||||||
uint32 fType;
|
uint32 fType;
|
||||||
|
|
||||||
Filehandle fHandle;
|
Filehandle fHandle;
|
||||||
Filesystem* fFilesystem;
|
Filesystem* fFilesystem;
|
||||||
|
Inode* fParent;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline ino_t
|
||||||
|
Inode::_FileIdToInoT(uint64 fileid)
|
||||||
|
{
|
||||||
|
if (sizeof(ino_t) >= sizeof(uint64))
|
||||||
|
return fileid;
|
||||||
|
else
|
||||||
|
return (ino_t)fileid ^ (fileid >>
|
||||||
|
(sizeof(uint64) - sizeof(ino_t)) * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline ino_t
|
inline ino_t
|
||||||
Inode::ID() const
|
Inode::ID() const
|
||||||
{
|
{
|
||||||
if (sizeof(ino_t) >= sizeof(uint64))
|
return _FileIdToInoT(fFileId);
|
||||||
return fFileId;
|
|
||||||
else
|
|
||||||
return (ino_t)fFileId ^ (fFileId >>
|
|
||||||
(sizeof(uint64) - sizeof(ino_t)) * 8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ enum Opcode {
|
|||||||
OpGetFH = 10,
|
OpGetFH = 10,
|
||||||
OpLookUp = 15,
|
OpLookUp = 15,
|
||||||
OpPutFH = 22,
|
OpPutFH = 22,
|
||||||
OpPutRootFH = 24
|
OpPutRootFH = 24,
|
||||||
|
OpReadDir = 26
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Access {
|
enum Access {
|
||||||
|
|||||||
@@ -14,6 +14,22 @@
|
|||||||
#include <util/kernel_cpp.h>
|
#include <util/kernel_cpp.h>
|
||||||
|
|
||||||
|
|
||||||
|
DirEntry::DirEntry()
|
||||||
|
:
|
||||||
|
fName(NULL),
|
||||||
|
fAttrs(NULL),
|
||||||
|
fAttrCount(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DirEntry::~DirEntry()
|
||||||
|
{
|
||||||
|
free(const_cast<char*>(fName));
|
||||||
|
delete[] fAttrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ReplyInterpreter::ReplyInterpreter(RPC::Reply* reply)
|
ReplyInterpreter::ReplyInterpreter(RPC::Reply* reply)
|
||||||
:
|
:
|
||||||
fReply(reply)
|
fReply(reply)
|
||||||
@@ -75,6 +91,74 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count)
|
|||||||
if (res != B_OK)
|
if (res != B_OK)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
|
return _DecodeAttrs(fReply->Stream(), attrs, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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::ReadDir(uint64* cookie, DirEntry** dirents, uint32* _count,
|
||||||
|
bool* eof)
|
||||||
|
{
|
||||||
|
status_t res = _OperationError(OpReadDir);
|
||||||
|
if (res != B_OK)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
cookie[1] = fReply->Stream().GetUHyper();
|
||||||
|
|
||||||
|
bool isNext;
|
||||||
|
uint32 count = 0;
|
||||||
|
DirEntry* entries = new(std::nothrow) DirEntry[*_count];
|
||||||
|
if (entries == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
isNext = fReply->Stream().GetBoolean();
|
||||||
|
while (isNext && count <= *_count) {
|
||||||
|
cookie[0] = fReply->Stream().GetUHyper();
|
||||||
|
|
||||||
|
entries[count].fName = fReply->Stream().GetString();
|
||||||
|
_DecodeAttrs(fReply->Stream(), &entries[count].fAttrs,
|
||||||
|
&entries[count].fAttrCount);
|
||||||
|
|
||||||
|
count++;
|
||||||
|
|
||||||
|
isNext = fReply->Stream().GetBoolean();
|
||||||
|
}
|
||||||
|
if (!isNext)
|
||||||
|
*eof = fReply->Stream().GetBoolean();
|
||||||
|
else
|
||||||
|
*eof = false;
|
||||||
|
|
||||||
|
*_count = count;
|
||||||
|
*dirents = entries;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs,
|
||||||
|
uint32* count)
|
||||||
|
{
|
||||||
uint32 bcount = fReply->Stream().GetUInt();
|
uint32 bcount = fReply->Stream().GetUInt();
|
||||||
uint32 *bitmap = new(std::nothrow) uint32[bcount];
|
uint32 *bitmap = new(std::nothrow) uint32[bcount];
|
||||||
if (bitmap == NULL)
|
if (bitmap == NULL)
|
||||||
@@ -82,17 +166,17 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count)
|
|||||||
|
|
||||||
uint32 attr_count = 0;
|
uint32 attr_count = 0;
|
||||||
for (uint32 i = 0; i < bcount; i++) {
|
for (uint32 i = 0; i < bcount; i++) {
|
||||||
bitmap[i] = fReply->Stream().GetUInt();
|
bitmap[i] = str.GetUInt();
|
||||||
attr_count += sCountBits(bitmap[i]);
|
attr_count += sCountBits(bitmap[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 size;
|
uint32 size;
|
||||||
const void* ptr = fReply->Stream().GetOpaque(&size);
|
const void* ptr = str.GetOpaque(&size);
|
||||||
XDR::ReadStream stream(const_cast<void*>(ptr), size);
|
XDR::ReadStream stream(const_cast<void*>(ptr), size);
|
||||||
|
|
||||||
AttrValue* values = new(std::nothrow) AttrValue[attr_count];
|
AttrValue* values = new(std::nothrow) AttrValue[attr_count];
|
||||||
if (values == NULL) {
|
if (values == NULL) {
|
||||||
delete bitmap;
|
delete[] bitmap;
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +218,7 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count)
|
|||||||
current++;
|
current++;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete bitmap;
|
delete[] bitmap;
|
||||||
|
|
||||||
*count = attr_count;
|
*count = attr_count;
|
||||||
*attrs = values;
|
*attrs = values;
|
||||||
@@ -142,27 +226,6 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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
|
status_t
|
||||||
ReplyInterpreter::_OperationError(Opcode op)
|
ReplyInterpreter::_OperationError(Opcode op)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,6 +24,15 @@ struct AttrValue {
|
|||||||
} fData;
|
} fData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DirEntry {
|
||||||
|
const char* fName;
|
||||||
|
AttrValue* fAttrs;
|
||||||
|
uint32 fAttrCount;
|
||||||
|
|
||||||
|
DirEntry();
|
||||||
|
~DirEntry();
|
||||||
|
};
|
||||||
|
|
||||||
class ReplyInterpreter {
|
class ReplyInterpreter {
|
||||||
public:
|
public:
|
||||||
ReplyInterpreter(RPC::Reply* reply);
|
ReplyInterpreter(RPC::Reply* reply);
|
||||||
@@ -35,8 +44,12 @@ public:
|
|||||||
inline status_t LookUp();
|
inline status_t LookUp();
|
||||||
inline status_t PutFH();
|
inline status_t PutFH();
|
||||||
inline status_t PutRootFH();
|
inline status_t PutRootFH();
|
||||||
|
status_t ReadDir(uint64* cookie, DirEntry** dirents,
|
||||||
|
uint32* count, bool* eof);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
status_t _DecodeAttrs(XDR::ReadStream& stream, AttrValue** attrs,
|
||||||
|
uint32* count);
|
||||||
status_t _OperationError(Opcode op);
|
status_t _OperationError(Opcode op);
|
||||||
|
|
||||||
static status_t _NFS4ErrorToHaiku(uint32 x);
|
static status_t _NFS4ErrorToHaiku(uint32 x);
|
||||||
|
|||||||
@@ -62,18 +62,7 @@ RequestBuilder::GetAttr(Attribute* attrs, uint32 count)
|
|||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
fRequest->Stream().AddUInt(OpGetAttr);
|
fRequest->Stream().AddUInt(OpGetAttr);
|
||||||
|
_AttrBitmap(fRequest->Stream(), attrs, count);
|
||||||
// 2 is safe in NFS4, not in NFS4.1 though
|
|
||||||
uint32 bitmap[2];
|
|
||||||
memset(bitmap, 0, sizeof(bitmap));
|
|
||||||
for (uint32 i = 0; i < count; i++) {
|
|
||||||
bitmap[attrs[i] / 32] |= 1 << attrs[i] % 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 bcount = bitmap[1] != 0 ? 2 : 1;
|
|
||||||
fRequest->Stream().AddUInt(bcount);
|
|
||||||
for (uint32 i = 0; i < bcount; i++)
|
|
||||||
fRequest->Stream().AddUInt(bitmap[i]);
|
|
||||||
|
|
||||||
fOpCount++;
|
fOpCount++;
|
||||||
|
|
||||||
@@ -145,6 +134,32 @@ RequestBuilder::PutRootFH()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
RequestBuilder::ReadDir(uint32 count, uint64* cookie, Attribute* attrs,
|
||||||
|
uint32 attr_count)
|
||||||
|
{
|
||||||
|
(void)count;
|
||||||
|
|
||||||
|
if (fProcedure != ProcCompound)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (fRequest == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
fRequest->Stream().AddUInt(OpReadDir);
|
||||||
|
fRequest->Stream().AddUHyper(cookie[0]);
|
||||||
|
fRequest->Stream().AddUHyper(cookie[1]);
|
||||||
|
|
||||||
|
// consider predicting this values basing on count or buffer size
|
||||||
|
fRequest->Stream().AddUInt(0x2000);
|
||||||
|
fRequest->Stream().AddUInt(0x8000);
|
||||||
|
_AttrBitmap(fRequest->Stream(), attrs, attr_count);
|
||||||
|
|
||||||
|
fOpCount++;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RPC::Call*
|
RPC::Call*
|
||||||
RequestBuilder::Request()
|
RequestBuilder::Request()
|
||||||
{
|
{
|
||||||
@@ -157,3 +172,21 @@ RequestBuilder::Request()
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
RequestBuilder::_AttrBitmap(XDR::WriteStream& stream, Attribute* attrs,
|
||||||
|
uint32 count)
|
||||||
|
{
|
||||||
|
// 2 is safe in NFS4, not in NFS4.1 though
|
||||||
|
uint32 bitmap[2];
|
||||||
|
memset(bitmap, 0, sizeof(bitmap));
|
||||||
|
for (uint32 i = 0; i < count; i++) {
|
||||||
|
bitmap[attrs[i] / 32] |= 1 << attrs[i] % 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 bcount = bitmap[1] != 0 ? 2 : 1;
|
||||||
|
stream.AddUInt(bcount);
|
||||||
|
for (uint32 i = 0; i < bcount; i++)
|
||||||
|
stream.AddUInt(bitmap[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,10 +27,15 @@ public:
|
|||||||
status_t LookUp(const char* name);
|
status_t LookUp(const char* name);
|
||||||
status_t PutFH(const Filehandle& fh);
|
status_t PutFH(const Filehandle& fh);
|
||||||
status_t PutRootFH();
|
status_t PutRootFH();
|
||||||
|
status_t ReadDir(uint32 count, uint64* cookie,
|
||||||
|
Attribute* attrs, uint32 attr_count);
|
||||||
|
|
||||||
RPC::Call* Request();
|
RPC::Call* Request();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void _AttrBitmap(XDR::WriteStream& stream,
|
||||||
|
Attribute* attrs, uint32 count);
|
||||||
|
|
||||||
uint32 fOpCount;
|
uint32 fOpCount;
|
||||||
XDR::Stream::Position fOpCountPosition;
|
XDR::Stream::Position fOpCountPosition;
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags,
|
|||||||
|
|
||||||
Filesystem* fs;
|
Filesystem* fs;
|
||||||
// hardcoded path
|
// hardcoded path
|
||||||
result = Filesystem::Mount(&fs, server, "haiku/src/add-ons/kernel");
|
result = Filesystem::Mount(&fs, server, "haiku/src/add-ons/kernel",
|
||||||
|
volume->id);
|
||||||
if (result != B_OK) {
|
if (result != B_OK) {
|
||||||
gRPCServerManager->Release(server);
|
gRPCServerManager->Release(server);
|
||||||
return result;
|
return result;
|
||||||
@@ -98,7 +99,7 @@ nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat)
|
|||||||
static status_t
|
static status_t
|
||||||
nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie)
|
nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie)
|
||||||
{
|
{
|
||||||
uint64* cookie = new(std::nothrow) uint64;
|
uint64* cookie = new(std::nothrow) uint64[2];
|
||||||
if (cookie == NULL)
|
if (cookie == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
*_cookie = cookie;
|
*_cookie = cookie;
|
||||||
@@ -122,11 +123,21 @@ nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* cookie)
|
|||||||
static status_t
|
static status_t
|
||||||
nfs4_free_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie)
|
nfs4_free_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie)
|
||||||
{
|
{
|
||||||
delete reinterpret_cast<uint64*>(cookie);
|
delete[] reinterpret_cast<uint64*>(cookie);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie,
|
||||||
|
struct dirent* buffer, size_t bufferSize, uint32* _num)
|
||||||
|
{
|
||||||
|
uint64* cookie = reinterpret_cast<uint64*>(_cookie);
|
||||||
|
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
|
||||||
|
return inode->ReadDir(buffer, bufferSize, _num, cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
nfs4_init()
|
nfs4_init()
|
||||||
{
|
{
|
||||||
@@ -223,7 +234,7 @@ fs_vnode_ops gNFSv4VnodeOps = {
|
|||||||
nfs4_open_dir,
|
nfs4_open_dir,
|
||||||
nfs4_close_dir,
|
nfs4_close_dir,
|
||||||
nfs4_free_dir_cookie,
|
nfs4_free_dir_cookie,
|
||||||
NULL, // read_dir()
|
nfs4_read_dir,
|
||||||
NULL, // rewind_dir,
|
NULL, // rewind_dir,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user