diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 93d60196ec..0ddafcac14 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -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(_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; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 7139d76ee4..a02fa2bb03 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -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, diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index d4090cb01d..9426e3c2ae 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -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++; diff --git a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp index b134504eee..c769d803c7 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -372,7 +372,7 @@ nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos, OpenFileCookie* cookie = reinterpret_cast(_cookie); - return inode->Write(cookie, pos, buffer, *length); + return inode->Write(cookie, pos, buffer, length); }