nfs4: Add read_dir() hook
This commit is contained in:
parent
821f13b077
commit
4b48348f97
@ -30,7 +30,8 @@ Filesystem::~Filesystem()
|
||||
|
||||
|
||||
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);
|
||||
req.PutRootFH();
|
||||
@ -97,14 +98,14 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath)
|
||||
return result;
|
||||
|
||||
if (count != 1 || values[0].fAttribute != FATTR4_FH_EXPIRE_TYPE) {
|
||||
delete values;
|
||||
delete[] values;
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
// Currently, only persistent filehandles are supported. That will be
|
||||
// changed soon.
|
||||
if (values[0].fData.fValue32 != FH4_PERSISTENT) {
|
||||
delete values;
|
||||
delete[] values;
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
@ -112,8 +113,9 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath)
|
||||
fs->fFHExpiryType = values[0].fData.fValue32;
|
||||
memcpy(&fs->fRootFH, &fh, sizeof(Filehandle));
|
||||
fs->fServer = serv;
|
||||
fs->fDevId = id;
|
||||
|
||||
delete values;
|
||||
delete[] values;
|
||||
|
||||
*pfs = fs;
|
||||
|
||||
@ -124,6 +126,6 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath)
|
||||
Inode*
|
||||
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 {
|
||||
public:
|
||||
static status_t Mount(Filesystem** pfs, RPC::Server* serv,
|
||||
const char* path);
|
||||
const char* path, dev_t id);
|
||||
~Filesystem();
|
||||
|
||||
Inode* CreateRootInode();
|
||||
@ -27,6 +27,7 @@ public:
|
||||
inline RPC::Server* Server();
|
||||
inline uint64 GetId();
|
||||
|
||||
inline dev_t DevId() const;
|
||||
private:
|
||||
Filesystem();
|
||||
|
||||
@ -37,6 +38,7 @@ private:
|
||||
RPC::Server* fServer;
|
||||
|
||||
vint64 fId;
|
||||
dev_t fDevId;
|
||||
};
|
||||
|
||||
|
||||
@ -54,5 +56,12 @@ Filesystem::GetId()
|
||||
}
|
||||
|
||||
|
||||
inline dev_t
|
||||
Filesystem::DevId() const
|
||||
{
|
||||
return fDevId;
|
||||
}
|
||||
|
||||
|
||||
#endif // FILESYSTEM_H
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "Inode.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ReplyInterpreter.h"
|
||||
@ -17,9 +18,10 @@
|
||||
|
||||
// Creating Inode object from Filehandle probably is not a good idea when
|
||||
// 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));
|
||||
|
||||
@ -53,7 +55,7 @@ Inode::Inode(Filesystem* fs, const Filehandle &fh)
|
||||
// FATTR4_TYPE is mandatory
|
||||
fType = values[0].fData.fValue32;
|
||||
|
||||
delete values;
|
||||
delete[] values;
|
||||
}
|
||||
|
||||
|
||||
@ -82,8 +84,10 @@ Inode::Stat(struct stat* st)
|
||||
return result;
|
||||
|
||||
// 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;
|
||||
}
|
||||
st->st_size = values[0].fData.fValue64;
|
||||
|
||||
uint32 next = 1;
|
||||
@ -103,7 +107,7 @@ Inode::Stat(struct stat* st)
|
||||
st->st_uid = 0;
|
||||
st->st_gid = 0;
|
||||
|
||||
delete values;
|
||||
delete[] values;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -135,6 +139,126 @@ Inode::OpenDir(uint64* cookie)
|
||||
if (allowed & ACCESS4_READ != ACCESS4_READ)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -15,35 +15,54 @@
|
||||
|
||||
#include "Filesystem.h"
|
||||
#include "NFS4Defs.h"
|
||||
#include "ReplyInterpreter.h"
|
||||
|
||||
|
||||
class Inode {
|
||||
public:
|
||||
Inode(Filesystem* fs, const Filehandle &fh);
|
||||
Inode(Filesystem* fs, const Filehandle &fh,
|
||||
Inode* parent);
|
||||
|
||||
inline ino_t ID() const;
|
||||
inline mode_t Type() const;
|
||||
inline ino_t ID() const;
|
||||
inline mode_t Type() const;
|
||||
|
||||
status_t Stat(struct stat* st);
|
||||
status_t OpenDir(uint64* cookie);
|
||||
status_t Stat(struct stat* st);
|
||||
status_t OpenDir(uint64* cookie);
|
||||
status_t ReadDir(void* buffer, uint32 size,
|
||||
uint32* count, uint64* cookie);
|
||||
|
||||
private:
|
||||
uint64 fFileId;
|
||||
uint32 fType;
|
||||
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);
|
||||
|
||||
Filehandle fHandle;
|
||||
Filesystem* fFilesystem;
|
||||
static inline ino_t _FileIdToInoT(uint64 fileid);
|
||||
|
||||
uint64 fFileId;
|
||||
uint32 fType;
|
||||
|
||||
Filehandle fHandle;
|
||||
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
|
||||
Inode::ID() const
|
||||
{
|
||||
if (sizeof(ino_t) >= sizeof(uint64))
|
||||
return fFileId;
|
||||
else
|
||||
return (ino_t)fFileId ^ (fFileId >>
|
||||
(sizeof(uint64) - sizeof(ino_t)) * 8);
|
||||
return _FileIdToInoT(fFileId);
|
||||
}
|
||||
|
||||
|
||||
|
@ -32,7 +32,8 @@ enum Opcode {
|
||||
OpGetFH = 10,
|
||||
OpLookUp = 15,
|
||||
OpPutFH = 22,
|
||||
OpPutRootFH = 24
|
||||
OpPutRootFH = 24,
|
||||
OpReadDir = 26
|
||||
};
|
||||
|
||||
enum Access {
|
||||
|
@ -14,6 +14,22 @@
|
||||
#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)
|
||||
:
|
||||
fReply(reply)
|
||||
@ -75,6 +91,74 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count)
|
||||
if (res != B_OK)
|
||||
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 *bitmap = new(std::nothrow) uint32[bcount];
|
||||
if (bitmap == NULL)
|
||||
@ -82,17 +166,17 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count)
|
||||
|
||||
uint32 attr_count = 0;
|
||||
for (uint32 i = 0; i < bcount; i++) {
|
||||
bitmap[i] = fReply->Stream().GetUInt();
|
||||
bitmap[i] = str.GetUInt();
|
||||
attr_count += sCountBits(bitmap[i]);
|
||||
}
|
||||
|
||||
uint32 size;
|
||||
const void* ptr = fReply->Stream().GetOpaque(&size);
|
||||
const void* ptr = str.GetOpaque(&size);
|
||||
XDR::ReadStream stream(const_cast<void*>(ptr), size);
|
||||
|
||||
AttrValue* values = new(std::nothrow) AttrValue[attr_count];
|
||||
if (values == NULL) {
|
||||
delete bitmap;
|
||||
delete[] bitmap;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
@ -134,7 +218,7 @@ ReplyInterpreter::GetAttr(AttrValue** attrs, uint32* count)
|
||||
current++;
|
||||
}
|
||||
|
||||
delete bitmap;
|
||||
delete[] bitmap;
|
||||
|
||||
*count = attr_count;
|
||||
*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
|
||||
ReplyInterpreter::_OperationError(Opcode op)
|
||||
{
|
||||
|
@ -24,6 +24,15 @@ struct AttrValue {
|
||||
} fData;
|
||||
};
|
||||
|
||||
struct DirEntry {
|
||||
const char* fName;
|
||||
AttrValue* fAttrs;
|
||||
uint32 fAttrCount;
|
||||
|
||||
DirEntry();
|
||||
~DirEntry();
|
||||
};
|
||||
|
||||
class ReplyInterpreter {
|
||||
public:
|
||||
ReplyInterpreter(RPC::Reply* reply);
|
||||
@ -35,8 +44,12 @@ public:
|
||||
inline status_t LookUp();
|
||||
inline status_t PutFH();
|
||||
inline status_t PutRootFH();
|
||||
status_t ReadDir(uint64* cookie, DirEntry** dirents,
|
||||
uint32* count, bool* eof);
|
||||
|
||||
private:
|
||||
status_t _DecodeAttrs(XDR::ReadStream& stream, AttrValue** attrs,
|
||||
uint32* count);
|
||||
status_t _OperationError(Opcode op);
|
||||
|
||||
static status_t _NFS4ErrorToHaiku(uint32 x);
|
||||
|
@ -62,18 +62,7 @@ RequestBuilder::GetAttr(Attribute* attrs, uint32 count)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fRequest->Stream().AddUInt(OpGetAttr);
|
||||
|
||||
// 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]);
|
||||
_AttrBitmap(fRequest->Stream(), attrs, count);
|
||||
|
||||
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*
|
||||
RequestBuilder::Request()
|
||||
{
|
||||
@ -157,3 +172,21 @@ RequestBuilder::Request()
|
||||
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 PutFH(const Filehandle& fh);
|
||||
status_t PutRootFH();
|
||||
status_t ReadDir(uint32 count, uint64* cookie,
|
||||
Attribute* attrs, uint32 attr_count);
|
||||
|
||||
RPC::Call* Request();
|
||||
|
||||
private:
|
||||
void _AttrBitmap(XDR::WriteStream& stream,
|
||||
Attribute* attrs, uint32 count);
|
||||
|
||||
uint32 fOpCount;
|
||||
XDR::Stream::Position fOpCountPosition;
|
||||
|
||||
|
@ -42,7 +42,8 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags,
|
||||
|
||||
Filesystem* fs;
|
||||
// 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) {
|
||||
gRPCServerManager->Release(server);
|
||||
return result;
|
||||
@ -98,7 +99,7 @@ nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat)
|
||||
static status_t
|
||||
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)
|
||||
return B_NO_MEMORY;
|
||||
*_cookie = cookie;
|
||||
@ -122,11 +123,21 @@ nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* cookie)
|
||||
static status_t
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
nfs4_init()
|
||||
{
|
||||
@ -223,7 +234,7 @@ fs_vnode_ops gNFSv4VnodeOps = {
|
||||
nfs4_open_dir,
|
||||
nfs4_close_dir,
|
||||
nfs4_free_dir_cookie,
|
||||
NULL, // read_dir()
|
||||
nfs4_read_dir,
|
||||
NULL, // rewind_dir,
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user