nfs4: Put file and dir specific code in separate files
This commit is contained in:
parent
2f03ff09af
commit
2a73e4c578
@ -9,7 +9,6 @@
|
||||
|
||||
#include "Inode.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <NodeMonitor.h>
|
||||
@ -651,661 +650,6 @@ Inode::WriteStat(const struct stat* st, uint32 mask)
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
sConfirmOpen(Filesystem* fs, Filehandle& fh, OpenFileCookie* cookie)
|
||||
{
|
||||
Request request(fs->Server());
|
||||
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fh);
|
||||
req.OpenConfirm(cookie->fSequence++, cookie->fStateId,
|
||||
cookie->fStateSeq);
|
||||
|
||||
status_t result = request.Send();
|
||||
if (result != B_OK) {
|
||||
fs->RemoveOpenFile(cookie);
|
||||
return result;
|
||||
}
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
reply.PutFH();
|
||||
|
||||
result = reply.OpenConfirm(&cookie->fStateSeq);
|
||||
if (result != B_OK) {
|
||||
fs->RemoveOpenFile(cookie);
|
||||
return result;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
|
||||
ino_t* id)
|
||||
{
|
||||
bool confirm;
|
||||
status_t result;
|
||||
|
||||
cookie->fMode = mode;
|
||||
cookie->fSequence = 0;
|
||||
cookie->fLocks = NULL;
|
||||
|
||||
Filehandle fh;
|
||||
do {
|
||||
cookie->fClientId = fFilesystem->NFSServer()->ClientId();
|
||||
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1);
|
||||
|
||||
req.PutFH(fHandle);
|
||||
|
||||
AttrValue cattr[2];
|
||||
uint32 i = 0;
|
||||
if ((mode & O_TRUNC) == O_TRUNC) {
|
||||
cattr[i].fAttribute = FATTR4_SIZE;
|
||||
cattr[i].fFreePointer = false;
|
||||
cattr[i].fData.fValue64 = 0;
|
||||
i++;
|
||||
}
|
||||
cattr[i].fAttribute = FATTR4_MODE;
|
||||
cattr[i].fFreePointer = false;
|
||||
cattr[i].fData.fValue32 = perms;
|
||||
req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode),
|
||||
cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, name, cattr,
|
||||
i + 1, (mode & O_EXCL) == O_EXCL);
|
||||
|
||||
req.GetFH();
|
||||
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) {
|
||||
Attribute attr[] = { FATTR4_FILEID };
|
||||
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
||||
}
|
||||
|
||||
result = request.Send();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm);
|
||||
reply.GetFH(&fh);
|
||||
|
||||
uint64 fileId;
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) {
|
||||
AttrValue* values;
|
||||
uint32 count;
|
||||
result = reply.GetAttr(&values, &count);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
fileId = values[1].fData.fValue64;
|
||||
|
||||
delete[] values;
|
||||
} else
|
||||
fileId = fFilesystem->AllocFileId();
|
||||
|
||||
*id = _FileIdToInoT(fileId);
|
||||
|
||||
FileInfo fi;
|
||||
fi.fFileId = fileId;
|
||||
fi.fFH = fh;
|
||||
fi.fParent = fHandle;
|
||||
fi.fName = strdup(name);
|
||||
|
||||
char* path = reinterpret_cast<char*>(malloc(strlen(name) + 2 +
|
||||
strlen(fPath)));
|
||||
strcpy(path, fPath);
|
||||
strcat(path, "/");
|
||||
strcat(path, name);
|
||||
fi.fPath = path;
|
||||
|
||||
fFilesystem->InoIdMap()->AddEntry(fi, *id);
|
||||
|
||||
cookie->fFilesystem = fFilesystem;
|
||||
cookie->fHandle = fh;
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
fFilesystem->AddOpenFile(cookie);
|
||||
|
||||
if (confirm)
|
||||
return sConfirmOpen(fFilesystem, fh, cookie);
|
||||
else
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Open(int mode, OpenFileCookie* cookie)
|
||||
{
|
||||
bool confirm;
|
||||
status_t result;
|
||||
|
||||
cookie->fFilesystem = fFilesystem;
|
||||
cookie->fHandle = fHandle;
|
||||
cookie->fMode = mode;
|
||||
cookie->fSequence = 0;
|
||||
cookie->fLocks = NULL;
|
||||
|
||||
do {
|
||||
cookie->fClientId = fFilesystem->NFSServer()->ClientId();
|
||||
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1);
|
||||
|
||||
// Since we are opening the file using a pair (parentFH, name) we
|
||||
// need to check for race conditions.
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) {
|
||||
req.PutFH(fParentFH);
|
||||
req.LookUp(fName);
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_FILEID;
|
||||
attr.fFreePointer = false;
|
||||
attr.fData.fValue64 = fFileId;
|
||||
req.Verify(&attr, 1);
|
||||
} else if (fFilesystem->ExpireType() == FH4_PERSISTENT) {
|
||||
req.PutFH(fParentFH);
|
||||
req.LookUp(fName);
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_FILEHANDLE;
|
||||
attr.fFreePointer = true;
|
||||
attr.fData.fPointer = malloc(sizeof(fHandle));
|
||||
memcpy(attr.fData.fPointer, &fHandle, sizeof(fHandle));
|
||||
req.Verify(&attr, 1);
|
||||
}
|
||||
|
||||
req.PutFH(fParentFH);
|
||||
if ((mode & O_TRUNC) == O_TRUNC) {
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_SIZE;
|
||||
attr.fFreePointer = false;
|
||||
attr.fData.fValue64 = 0;
|
||||
req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode),
|
||||
cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, fName, &attr,
|
||||
1, false);
|
||||
} else
|
||||
req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode),
|
||||
cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, fName);
|
||||
|
||||
result = request.Send();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
// Verify if the file we want to open is the file this Inode
|
||||
// represents.
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID) ||
|
||||
fFilesystem->ExpireType() == FH4_PERSISTENT) {
|
||||
reply.PutFH();
|
||||
result = reply.LookUp();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
result = reply.Verify();
|
||||
if (result != B_OK && reply.NFS4Error() == NFS4ERR_NOT_SAME)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
else if (result != B_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
reply.PutFH();
|
||||
result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
fFilesystem->AddOpenFile(cookie);
|
||||
|
||||
if (confirm)
|
||||
return sConfirmOpen(fFilesystem, fHandle, cookie);
|
||||
else
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Close(OpenFileCookie* cookie)
|
||||
{
|
||||
fFilesystem->RemoveOpenFile(cookie);
|
||||
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
req.Close(cookie->fSequence++, cookie->fStateId,
|
||||
cookie->fStateSeq);
|
||||
|
||||
status_t result = request.Send();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
result = reply.Close();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
return B_OK;
|
||||
} while (true);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
|
||||
{
|
||||
bool eof = false;
|
||||
uint32 size = 0;
|
||||
uint32 len = 0;
|
||||
|
||||
while (size < *_length && !eof) {
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
req.Read(cookie->fStateId, cookie->fStateSeq, pos + size,
|
||||
*_length - size);
|
||||
|
||||
status_t result = request.Send(cookie);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
result = reply.Read(reinterpret_cast<char*>(buffer) + size, &len,
|
||||
&eof);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
size += len;
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
*_length = size;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
|
||||
size_t *_length)
|
||||
{
|
||||
uint32 size = 0;
|
||||
uint32 len = 0;
|
||||
uint64 fileSize;
|
||||
const char* buffer = reinterpret_cast<const char*>(_buffer);
|
||||
|
||||
while (size < *_length) {
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
if (size == 0 && (cookie->fMode & O_APPEND) == O_APPEND) {
|
||||
struct stat st;
|
||||
status_t result = Stat(&st);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
fileSize = st.st_size;
|
||||
pos = fileSize;
|
||||
}
|
||||
|
||||
req.PutFH(fHandle);
|
||||
if ((cookie->fMode & O_APPEND) == O_APPEND) {
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_SIZE;
|
||||
attr.fFreePointer = false;
|
||||
attr.fData.fValue64 = fileSize + size;
|
||||
req.Verify(&attr, 1);
|
||||
}
|
||||
req.Write(cookie->fStateId, cookie->fStateSeq, buffer + size,
|
||||
pos + size, *_length - size);
|
||||
|
||||
status_t result = request.Send(cookie);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
// append: race condition
|
||||
if (reply.NFS4Error() == NFS4ERR_NOT_SAME) {
|
||||
if (size == 0)
|
||||
continue;
|
||||
else {
|
||||
*_length = size;
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
|
||||
if ((cookie->fMode & O_APPEND) == O_APPEND) {
|
||||
result = reply.Verify();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = reply.Write(&len);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
size += len;
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
*_length = size;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::CreateDir(const char* name, int mode)
|
||||
{
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_MODE;
|
||||
attr.fFreePointer = false;
|
||||
attr.fData.fValue32 = mode;
|
||||
req.Create(NF4DIR, name, &attr, 1);
|
||||
|
||||
status_t result = request.Send();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
|
||||
return reply.Create();
|
||||
} while (true);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::OpenDir(OpenDirCookie* cookie)
|
||||
{
|
||||
if (fType != NF4DIR)
|
||||
return B_NOT_A_DIRECTORY;
|
||||
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
req.Access();
|
||||
|
||||
status_t result = request.Send();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
|
||||
uint32 allowed;
|
||||
result = reply.Access(NULL, &allowed);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
if (allowed & ACCESS4_READ != ACCESS4_READ)
|
||||
return B_PERMISSION_DENIED;
|
||||
|
||||
cookie->fFilesystem = fFilesystem;
|
||||
cookie->fCookie = 0;
|
||||
cookie->fCookieVerf = 2;
|
||||
|
||||
return B_OK;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
|
||||
bool* eof)
|
||||
{
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
|
||||
Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
|
||||
req.ReadDir(*count, cookie->fCookie, cookie->fCookieVerf, attr,
|
||||
sizeof(attr) / sizeof(Attribute));
|
||||
|
||||
status_t result = request.Send(cookie);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
return reply.ReadDir(&cookie->fCookie, &cookie->fCookieVerf, dirents,
|
||||
count, eof);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
|
||||
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::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
|
||||
{
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
req.LookUpUp();
|
||||
req.GetFH();
|
||||
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) {
|
||||
Attribute attr[] = { FATTR4_FILEID };
|
||||
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
||||
}
|
||||
|
||||
status_t result = request.Send();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
result = reply.LookUpUp();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
Filehandle fh;
|
||||
reply.GetFH(&fh);
|
||||
|
||||
uint64 fileId;
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) {
|
||||
AttrValue* values;
|
||||
uint32 count;
|
||||
reply.GetAttr(&values, &count);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
fileId = values[0].fData.fValue64;
|
||||
delete[] values;
|
||||
} else
|
||||
fileId = fFilesystem->AllocFileId();
|
||||
|
||||
return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
// TODO: Currently inode numbers returned by ReadDir are virtually random.
|
||||
// Apparently Haiku does not use that information (contrary to inode number
|
||||
// returned by LookUp) so fixing it can wait until directory caches are
|
||||
// implemented.
|
||||
// When directories are cached client should store inode numbers it assigned
|
||||
// to directroy entries and use them consequently.
|
||||
status_t
|
||||
Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
|
||||
OpenDirCookie* cookie)
|
||||
{
|
||||
uint32 count = 0;
|
||||
uint32 pos = 0;
|
||||
uint32 this_count;
|
||||
bool eof = false;
|
||||
|
||||
char* buffer = reinterpret_cast<char*>(_buffer);
|
||||
|
||||
if (cookie->fCookie == 0 && cookie->fCookieVerf == 2 && count < *_count) {
|
||||
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
|
||||
|
||||
_FillDirEntry(de, fFileId, ".", pos, size);
|
||||
|
||||
pos += de->d_reclen;
|
||||
count++;
|
||||
cookie->fCookieVerf--;
|
||||
}
|
||||
|
||||
if (cookie->fCookie == 0 && cookie->fCookieVerf == 1 && count < *_count) {
|
||||
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
|
||||
|
||||
if (strcmp(fName, "/"))
|
||||
_ReadDirUp(de, pos, size);
|
||||
else
|
||||
_FillDirEntry(de, _FileIdToInoT(fFileId), "..", pos, size);
|
||||
|
||||
pos += de->d_reclen;
|
||||
count++;
|
||||
cookie->fCookieVerf--;
|
||||
}
|
||||
|
||||
bool overflow = false;
|
||||
while (count < *_count && !eof) {
|
||||
this_count = *_count - count;
|
||||
DirEntry* dirents;
|
||||
|
||||
status_t result = _ReadDirOnce(&dirents, &this_count, cookie, &eof);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
uint32 i, entries = 0;
|
||||
for (i = 0; i < min_c(this_count, *_count - count); i++) {
|
||||
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
|
||||
|
||||
// FATTR4_FSID is mandatory
|
||||
void* data = dirents[i].fAttrs[0].fData.fPointer;
|
||||
FilesystemId* fsid = reinterpret_cast<FilesystemId*>(data);
|
||||
if (*fsid != fFilesystem->FsId())
|
||||
continue;
|
||||
|
||||
ino_t id;
|
||||
if (dirents[i].fAttrCount == 2)
|
||||
id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
|
||||
else
|
||||
id = _FileIdToInoT(fFilesystem->AllocFileId());
|
||||
|
||||
const char* name = dirents[i].fName;
|
||||
if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) {
|
||||
eof = true;
|
||||
overflow = true;
|
||||
break;
|
||||
}
|
||||
|
||||
pos += de->d_reclen;
|
||||
entries++;
|
||||
}
|
||||
delete[] dirents;
|
||||
count += entries;
|
||||
}
|
||||
|
||||
if (count == 0 && overflow)
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
*_count = count;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::TestLock(OpenFileCookie* cookie, struct flock* lock)
|
||||
{
|
||||
@ -1501,7 +845,6 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie)
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv,
|
||||
OpenFileCookie* cookie)
|
||||
|
@ -71,13 +71,13 @@ public:
|
||||
protected:
|
||||
Inode();
|
||||
|
||||
|
||||
bool _HandleErrors(uint32 nfs4Error,
|
||||
RPC::Server* serv,
|
||||
OpenFileCookie* cookie = NULL);
|
||||
|
||||
status_t _LookUpFilehandle();
|
||||
|
||||
status_t _ConfirmOpen(OpenFileCookie* cookie);
|
||||
|
||||
status_t _ReadDirOnce(DirEntry** dirents, uint32* count,
|
||||
OpenDirCookie* cookie, bool* eof);
|
||||
status_t _FillDirEntry(struct dirent* de, ino_t id,
|
||||
|
283
src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp
Normal file
283
src/add-ons/kernel/file_systems/nfs4/InodeDir.cpp
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright 2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Paweł Dziepak, pdziepak@quarnos.org
|
||||
*/
|
||||
|
||||
|
||||
#include "Inode.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Request.h"
|
||||
#include "RootInode.h"
|
||||
|
||||
|
||||
status_t
|
||||
Inode::CreateDir(const char* name, int mode)
|
||||
{
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_MODE;
|
||||
attr.fFreePointer = false;
|
||||
attr.fData.fValue32 = mode;
|
||||
req.Create(NF4DIR, name, &attr, 1);
|
||||
|
||||
status_t result = request.Send();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
|
||||
return reply.Create();
|
||||
} while (true);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::OpenDir(OpenDirCookie* cookie)
|
||||
{
|
||||
if (fType != NF4DIR)
|
||||
return B_NOT_A_DIRECTORY;
|
||||
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
req.Access();
|
||||
|
||||
status_t result = request.Send();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
|
||||
uint32 allowed;
|
||||
result = reply.Access(NULL, &allowed);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
if (allowed & ACCESS4_READ != ACCESS4_READ)
|
||||
return B_PERMISSION_DENIED;
|
||||
|
||||
cookie->fFilesystem = fFilesystem;
|
||||
cookie->fCookie = 0;
|
||||
cookie->fCookieVerf = 2;
|
||||
|
||||
return B_OK;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, OpenDirCookie* cookie,
|
||||
bool* eof)
|
||||
{
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
|
||||
Attribute attr[] = { FATTR4_FSID, FATTR4_FILEID };
|
||||
req.ReadDir(*count, cookie->fCookie, cookie->fCookieVerf, attr,
|
||||
sizeof(attr) / sizeof(Attribute));
|
||||
|
||||
status_t result = request.Send(cookie);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
return reply.ReadDir(&cookie->fCookie, &cookie->fCookieVerf, dirents,
|
||||
count, eof);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
|
||||
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::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
|
||||
{
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
req.LookUpUp();
|
||||
req.GetFH();
|
||||
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) {
|
||||
Attribute attr[] = { FATTR4_FILEID };
|
||||
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
||||
}
|
||||
|
||||
status_t result = request.Send();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
result = reply.LookUpUp();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
Filehandle fh;
|
||||
reply.GetFH(&fh);
|
||||
|
||||
uint64 fileId;
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) {
|
||||
AttrValue* values;
|
||||
uint32 count;
|
||||
reply.GetAttr(&values, &count);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
fileId = values[0].fData.fValue64;
|
||||
delete[] values;
|
||||
} else
|
||||
fileId = fFilesystem->AllocFileId();
|
||||
|
||||
return _FillDirEntry(de, _FileIdToInoT(fileId), "..", pos, size);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
// TODO: Currently inode numbers returned by ReadDir are virtually random.
|
||||
// Apparently Haiku does not use that information (contrary to inode number
|
||||
// returned by LookUp) so fixing it can wait until directory caches are
|
||||
// implemented.
|
||||
// When directories are cached client should store inode numbers it assigned
|
||||
// to directroy entries and use them consequently.
|
||||
status_t
|
||||
Inode::ReadDir(void* _buffer, uint32 size, uint32* _count,
|
||||
OpenDirCookie* cookie)
|
||||
{
|
||||
uint32 count = 0;
|
||||
uint32 pos = 0;
|
||||
uint32 this_count;
|
||||
bool eof = false;
|
||||
|
||||
char* buffer = reinterpret_cast<char*>(_buffer);
|
||||
|
||||
if (cookie->fCookie == 0 && cookie->fCookieVerf == 2 && count < *_count) {
|
||||
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
|
||||
|
||||
_FillDirEntry(de, fFileId, ".", pos, size);
|
||||
|
||||
pos += de->d_reclen;
|
||||
count++;
|
||||
cookie->fCookieVerf--;
|
||||
}
|
||||
|
||||
if (cookie->fCookie == 0 && cookie->fCookieVerf == 1 && count < *_count) {
|
||||
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
|
||||
|
||||
if (strcmp(fName, "/"))
|
||||
_ReadDirUp(de, pos, size);
|
||||
else
|
||||
_FillDirEntry(de, _FileIdToInoT(fFileId), "..", pos, size);
|
||||
|
||||
pos += de->d_reclen;
|
||||
count++;
|
||||
cookie->fCookieVerf--;
|
||||
}
|
||||
|
||||
bool overflow = false;
|
||||
while (count < *_count && !eof) {
|
||||
this_count = *_count - count;
|
||||
DirEntry* dirents;
|
||||
|
||||
status_t result = _ReadDirOnce(&dirents, &this_count, cookie, &eof);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
uint32 i, entries = 0;
|
||||
for (i = 0; i < min_c(this_count, *_count - count); i++) {
|
||||
struct dirent* de = reinterpret_cast<dirent*>(buffer + pos);
|
||||
|
||||
// FATTR4_FSID is mandatory
|
||||
void* data = dirents[i].fAttrs[0].fData.fPointer;
|
||||
FilesystemId* fsid = reinterpret_cast<FilesystemId*>(data);
|
||||
if (*fsid != fFilesystem->FsId())
|
||||
continue;
|
||||
|
||||
ino_t id;
|
||||
if (dirents[i].fAttrCount == 2)
|
||||
id = _FileIdToInoT(dirents[i].fAttrs[1].fData.fValue64);
|
||||
else
|
||||
id = _FileIdToInoT(fFilesystem->AllocFileId());
|
||||
|
||||
const char* name = dirents[i].fName;
|
||||
if (_FillDirEntry(de, id, name, pos, size) == B_BUFFER_OVERFLOW) {
|
||||
eof = true;
|
||||
overflow = true;
|
||||
break;
|
||||
}
|
||||
|
||||
pos += de->d_reclen;
|
||||
entries++;
|
||||
}
|
||||
delete[] dirents;
|
||||
count += entries;
|
||||
}
|
||||
|
||||
if (count == 0 && overflow)
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
*_count = count;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
413
src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
Normal file
413
src/add-ons/kernel/file_systems/nfs4/InodeRegular.cpp
Normal file
@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Copyright 2012 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Paweł Dziepak, pdziepak@quarnos.org
|
||||
*/
|
||||
|
||||
|
||||
#include "Inode.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <NodeMonitor.h>
|
||||
|
||||
#include "Request.h"
|
||||
|
||||
|
||||
status_t
|
||||
Inode::_ConfirmOpen(OpenFileCookie* cookie)
|
||||
{
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
req.OpenConfirm(cookie->fSequence++, cookie->fStateId,
|
||||
cookie->fStateSeq);
|
||||
|
||||
status_t result = request.Send();
|
||||
if (result != B_OK) {
|
||||
fFilesystem->RemoveOpenFile(cookie);
|
||||
return result;
|
||||
}
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
result = reply.OpenConfirm(&cookie->fStateSeq);
|
||||
if (result != B_OK) {
|
||||
fFilesystem->RemoveOpenFile(cookie);
|
||||
return result;
|
||||
}
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Create(const char* name, int mode, int perms, OpenFileCookie* cookie,
|
||||
ino_t* id)
|
||||
{
|
||||
bool confirm;
|
||||
status_t result;
|
||||
|
||||
cookie->fMode = mode;
|
||||
cookie->fSequence = 0;
|
||||
cookie->fLocks = NULL;
|
||||
|
||||
Filehandle fh;
|
||||
do {
|
||||
cookie->fClientId = fFilesystem->NFSServer()->ClientId();
|
||||
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1);
|
||||
|
||||
req.PutFH(fHandle);
|
||||
|
||||
AttrValue cattr[2];
|
||||
uint32 i = 0;
|
||||
if ((mode & O_TRUNC) == O_TRUNC) {
|
||||
cattr[i].fAttribute = FATTR4_SIZE;
|
||||
cattr[i].fFreePointer = false;
|
||||
cattr[i].fData.fValue64 = 0;
|
||||
i++;
|
||||
}
|
||||
cattr[i].fAttribute = FATTR4_MODE;
|
||||
cattr[i].fFreePointer = false;
|
||||
cattr[i].fData.fValue32 = perms;
|
||||
req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode),
|
||||
cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, name, cattr,
|
||||
i + 1, (mode & O_EXCL) == O_EXCL);
|
||||
|
||||
req.GetFH();
|
||||
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) {
|
||||
Attribute attr[] = { FATTR4_FILEID };
|
||||
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
||||
}
|
||||
|
||||
result = request.Send();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm);
|
||||
reply.GetFH(&fh);
|
||||
|
||||
uint64 fileId;
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) {
|
||||
AttrValue* values;
|
||||
uint32 count;
|
||||
result = reply.GetAttr(&values, &count);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
fileId = values[1].fData.fValue64;
|
||||
|
||||
delete[] values;
|
||||
} else
|
||||
fileId = fFilesystem->AllocFileId();
|
||||
|
||||
*id = _FileIdToInoT(fileId);
|
||||
|
||||
FileInfo fi;
|
||||
fi.fFileId = fileId;
|
||||
fi.fFH = fh;
|
||||
fi.fParent = fHandle;
|
||||
fi.fName = strdup(name);
|
||||
|
||||
char* path = reinterpret_cast<char*>(malloc(strlen(name) + 2 +
|
||||
strlen(fPath)));
|
||||
strcpy(path, fPath);
|
||||
strcat(path, "/");
|
||||
strcat(path, name);
|
||||
fi.fPath = path;
|
||||
|
||||
fFilesystem->InoIdMap()->AddEntry(fi, *id);
|
||||
|
||||
cookie->fFilesystem = fFilesystem;
|
||||
cookie->fHandle = fh;
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
fFilesystem->AddOpenFile(cookie);
|
||||
|
||||
if (confirm)
|
||||
return _ConfirmOpen(cookie);
|
||||
else
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Open(int mode, OpenFileCookie* cookie)
|
||||
{
|
||||
bool confirm;
|
||||
status_t result;
|
||||
|
||||
cookie->fFilesystem = fFilesystem;
|
||||
cookie->fHandle = fHandle;
|
||||
cookie->fMode = mode;
|
||||
cookie->fSequence = 0;
|
||||
cookie->fLocks = NULL;
|
||||
|
||||
do {
|
||||
cookie->fClientId = fFilesystem->NFSServer()->ClientId();
|
||||
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1);
|
||||
|
||||
// Since we are opening the file using a pair (parentFH, name) we
|
||||
// need to check for race conditions.
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID)) {
|
||||
req.PutFH(fParentFH);
|
||||
req.LookUp(fName);
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_FILEID;
|
||||
attr.fFreePointer = false;
|
||||
attr.fData.fValue64 = fFileId;
|
||||
req.Verify(&attr, 1);
|
||||
} else if (fFilesystem->ExpireType() == FH4_PERSISTENT) {
|
||||
req.PutFH(fParentFH);
|
||||
req.LookUp(fName);
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_FILEHANDLE;
|
||||
attr.fFreePointer = true;
|
||||
attr.fData.fPointer = malloc(sizeof(fHandle));
|
||||
memcpy(attr.fData.fPointer, &fHandle, sizeof(fHandle));
|
||||
req.Verify(&attr, 1);
|
||||
}
|
||||
|
||||
req.PutFH(fParentFH);
|
||||
if ((mode & O_TRUNC) == O_TRUNC) {
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_SIZE;
|
||||
attr.fFreePointer = false;
|
||||
attr.fData.fValue64 = 0;
|
||||
req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode),
|
||||
cookie->fClientId, OPEN4_CREATE, cookie->fOwnerId, fName, &attr,
|
||||
1, false);
|
||||
} else
|
||||
req.Open(CLAIM_NULL, cookie->fSequence++, sModeToAccess(mode),
|
||||
cookie->fClientId, OPEN4_NOCREATE, cookie->fOwnerId, fName);
|
||||
|
||||
result = request.Send();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv))
|
||||
continue;
|
||||
|
||||
// Verify if the file we want to open is the file this Inode
|
||||
// represents.
|
||||
if (fFilesystem->IsAttrSupported(FATTR4_FILEID) ||
|
||||
fFilesystem->ExpireType() == FH4_PERSISTENT) {
|
||||
reply.PutFH();
|
||||
result = reply.LookUp();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
result = reply.Verify();
|
||||
if (result != B_OK && reply.NFS4Error() == NFS4ERR_NOT_SAME)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
else if (result != B_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
reply.PutFH();
|
||||
result = reply.Open(cookie->fStateId, &cookie->fStateSeq, &confirm);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
fFilesystem->AddOpenFile(cookie);
|
||||
|
||||
if (confirm)
|
||||
return _ConfirmOpen(cookie);
|
||||
else
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Close(OpenFileCookie* cookie)
|
||||
{
|
||||
fFilesystem->RemoveOpenFile(cookie);
|
||||
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
req.Close(cookie->fSequence++, cookie->fStateId,
|
||||
cookie->fStateSeq);
|
||||
|
||||
status_t result = request.Send();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
result = reply.Close();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
return B_OK;
|
||||
} while (true);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
|
||||
{
|
||||
bool eof = false;
|
||||
uint32 size = 0;
|
||||
uint32 len = 0;
|
||||
|
||||
while (size < *_length && !eof) {
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fHandle);
|
||||
req.Read(cookie->fStateId, cookie->fStateSeq, pos + size,
|
||||
*_length - size);
|
||||
|
||||
status_t result = request.Send(cookie);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
result = reply.Read(reinterpret_cast<char*>(buffer) + size, &len,
|
||||
&eof);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
size += len;
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
*_length = size;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
|
||||
size_t *_length)
|
||||
{
|
||||
uint32 size = 0;
|
||||
uint32 len = 0;
|
||||
uint64 fileSize;
|
||||
const char* buffer = reinterpret_cast<const char*>(_buffer);
|
||||
|
||||
while (size < *_length) {
|
||||
do {
|
||||
RPC::Server* serv = fFilesystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
if (size == 0 && (cookie->fMode & O_APPEND) == O_APPEND) {
|
||||
struct stat st;
|
||||
status_t result = Stat(&st);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
fileSize = st.st_size;
|
||||
pos = fileSize;
|
||||
}
|
||||
|
||||
req.PutFH(fHandle);
|
||||
if ((cookie->fMode & O_APPEND) == O_APPEND) {
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_SIZE;
|
||||
attr.fFreePointer = false;
|
||||
attr.fData.fValue64 = fileSize + size;
|
||||
req.Verify(&attr, 1);
|
||||
}
|
||||
req.Write(cookie->fStateId, cookie->fStateSeq, buffer + size,
|
||||
pos + size, *_length - size);
|
||||
|
||||
status_t result = request.Send(cookie);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
// append: race condition
|
||||
if (reply.NFS4Error() == NFS4ERR_NOT_SAME) {
|
||||
if (size == 0)
|
||||
continue;
|
||||
else {
|
||||
*_length = size;
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (_HandleErrors(reply.NFS4Error(), serv, cookie))
|
||||
continue;
|
||||
|
||||
reply.PutFH();
|
||||
|
||||
if ((cookie->fMode & O_APPEND) == O_APPEND) {
|
||||
result = reply.Verify();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
result = reply.Write(&len);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
size += len;
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
*_length = size;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ KernelAddon nfs4 :
|
||||
Connection.cpp
|
||||
Filesystem.cpp
|
||||
Inode.cpp
|
||||
InodeDir.cpp
|
||||
InodeRegular.cpp
|
||||
kernel_interface.cpp
|
||||
NFS4Server.cpp
|
||||
ReplyInterpreter.cpp
|
||||
|
Loading…
Reference in New Issue
Block a user