nfs4: Add support for O_APPEND mode
This commit is contained in:
@@ -1022,21 +1022,39 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
|
||||
|
||||
status_t
|
||||
Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
|
||||
size_t length)
|
||||
size_t *_length)
|
||||
{
|
||||
uint32 size = 0;
|
||||
uint32 len = 0;
|
||||
uint64 fileSize;
|
||||
const char* buffer = reinterpret_cast<const char*>(_buffer);
|
||||
|
||||
while (size < length) {
|
||||
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);
|
||||
pos + size, *_length - size);
|
||||
|
||||
status_t result = request.Send(cookie);
|
||||
if (result != B_OK)
|
||||
@@ -1044,6 +1062,16 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
// append: race condition
|
||||
if (reply.NFS4Error() == NFS4ERR_NOT_SAME) {
|
||||
if (size == 0)
|
||||
continue;
|
||||
else {
|
||||
*_length = size;
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// filehandle has expired
|
||||
if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) {
|
||||
_LookUpFilehandle();
|
||||
@@ -1074,6 +1102,12 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
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;
|
||||
@@ -1084,6 +1118,8 @@ Inode::Write(OpenFileCookie* cookie, off_t pos, const void* _buffer,
|
||||
} while (true);
|
||||
}
|
||||
|
||||
*_length = size;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
status_t Read(OpenFileCookie* cookie, off_t pos,
|
||||
void* buffer, size_t* length);
|
||||
status_t Write(OpenFileCookie* cookie, off_t pos,
|
||||
const void* buffer, size_t length);
|
||||
const void* buffer, size_t *_length);
|
||||
|
||||
status_t OpenDir(OpenDirCookie* cookie);
|
||||
status_t ReadDir(void* buffer, uint32 size,
|
||||
|
||||
@@ -573,6 +573,11 @@ RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr,
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i < count && attr[i].fAttribute == FATTR4_SIZE) {
|
||||
str.AddUHyper(attr[i].fData.fValue64);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i < count && attr[i].fAttribute == FATTR4_MODE) {
|
||||
str.AddUInt(attr[i].fData.fValue32);
|
||||
i++;
|
||||
|
||||
@@ -372,7 +372,7 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
|
||||
|
||||
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
|
||||
|
||||
return inode->Write(cookie, pos, buffer, *length);
|
||||
return inode->Write(cookie, pos, buffer, length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user