nfs4: Put file and dir specific code in separate files
This commit is contained in:
@@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include "Inode.h"
|
#include "Inode.h"
|
||||||
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <NodeMonitor.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
|
status_t
|
||||||
Inode::TestLock(OpenFileCookie* cookie, struct flock* lock)
|
Inode::TestLock(OpenFileCookie* cookie, struct flock* lock)
|
||||||
{
|
{
|
||||||
@@ -1501,7 +845,6 @@ Inode::ReleaseAllLocks(OpenFileCookie* cookie)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv,
|
Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv,
|
||||||
OpenFileCookie* cookie)
|
OpenFileCookie* cookie)
|
||||||
|
|||||||
@@ -71,13 +71,13 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
Inode();
|
Inode();
|
||||||
|
|
||||||
|
|
||||||
bool _HandleErrors(uint32 nfs4Error,
|
bool _HandleErrors(uint32 nfs4Error,
|
||||||
RPC::Server* serv,
|
RPC::Server* serv,
|
||||||
OpenFileCookie* cookie = NULL);
|
OpenFileCookie* cookie = NULL);
|
||||||
|
|
||||||
status_t _LookUpFilehandle();
|
status_t _LookUpFilehandle();
|
||||||
|
|
||||||
|
status_t _ConfirmOpen(OpenFileCookie* cookie);
|
||||||
|
|
||||||
status_t _ReadDirOnce(DirEntry** dirents, uint32* count,
|
status_t _ReadDirOnce(DirEntry** dirents, uint32* count,
|
||||||
OpenDirCookie* cookie, bool* eof);
|
OpenDirCookie* cookie, bool* eof);
|
||||||
status_t _FillDirEntry(struct dirent* de, ino_t id,
|
status_t _FillDirEntry(struct dirent* de, ino_t id,
|
||||||
|
|||||||
@@ -0,0 +1,283 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Haiku, Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Paweł Dziepak, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,413 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Haiku, Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Paweł Dziepak, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
Connection.cpp
|
||||||
Filesystem.cpp
|
Filesystem.cpp
|
||||||
Inode.cpp
|
Inode.cpp
|
||||||
|
InodeDir.cpp
|
||||||
|
InodeRegular.cpp
|
||||||
kernel_interface.cpp
|
kernel_interface.cpp
|
||||||
NFS4Server.cpp
|
NFS4Server.cpp
|
||||||
ReplyInterpreter.cpp
|
ReplyInterpreter.cpp
|
||||||
|
|||||||
Reference in New Issue
Block a user