diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index ab6c85bd0e..ebd28e7037 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include "Request.h" @@ -554,6 +556,93 @@ Inode::Stat(struct stat* st) } +status_t +Inode::WriteStat(const struct stat* st, uint32 mask) +{ + status_t result; + OpenFileCookie* cookie = NULL; + AttrValue attr[4]; + uint32 i = 0; + + if ((mask & B_STAT_SIZE) != 0) { + delete cookie; + cookie = new OpenFileCookie; + if (cookie == NULL) + return B_NO_MEMORY; + + result = Open(O_WRONLY, cookie); + if (result != B_OK) { + delete cookie; + return result; + } + + attr[i].fAttribute = FATTR4_SIZE; + attr[i].fFreePointer = false; + attr[i].fData.fValue64 = st->st_size; + i++; + } + + if ((mask & B_STAT_MODE) != 0) { + attr[i].fAttribute = FATTR4_MODE; + attr[i].fFreePointer = false; + attr[i].fData.fValue32 = st->st_mode; + i++; + } + + if ((mask & B_STAT_ACCESS_TIME) != 0) { + attr[i].fAttribute = FATTR4_TIME_ACCESS_SET; + attr[i].fFreePointer = true; + attr[i].fData.fPointer = malloc(sizeof(st->st_atime)); + memcpy(attr[i].fData.fPointer, &st->st_atime, sizeof(st->st_atime)); + i++; + } + + if ((mask & B_STAT_MODIFICATION_TIME) != 0) { + attr[i].fAttribute = FATTR4_TIME_MODIFY_SET; + attr[i].fFreePointer = true; + attr[i].fData.fPointer = malloc(sizeof(st->st_mtime)); + memcpy(attr[i].fData.fPointer, &st->st_mtime, sizeof(st->st_mtime)); + i++; + } + + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + if ((mask & B_STAT_SIZE) != 0) + req.SetAttr(cookie->fStateId, cookie->fStateSeq, attr, i); + else + req.SetAttr(NULL, 0, attr, i); + + status_t result = request.Send(); + if (result != B_OK) { + Close(cookie); + delete cookie; + return result; + } + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + result = reply.SetAttr(); + + if ((mask & B_STAT_SIZE) != 0) { + Close(cookie); + delete cookie; + } + + return result; + } while (true); + + return B_OK; +} + + static OpenAccess sModeToAccess(int mode) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 781f982faa..88fd1f9f73 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -40,8 +40,10 @@ public: status_t Remove(const char* name, FileType type); static status_t Rename(Inode* from, Inode* to, const char* fromName, const char* toName); + status_t Access(int mode); status_t Stat(struct stat* st); + status_t WriteStat(const struct stat* st, uint32 mask); status_t Create(const char* name, int mode, int perms, OpenFileCookie* cookie, ino_t* id); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index c4ebafa5d7..2268d56fc1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -41,6 +41,7 @@ enum Opcode { OpRename = 29, OpRenew = 30, OpSaveFH = 32, + OpSetAttr = 34, OpSetClientID = 35, OpSetClientIDConfirm = 36, OpVerify = 37, diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 088a50db98..981a775da9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -359,6 +359,21 @@ ReplyInterpreter::Rename() } +status_t +ReplyInterpreter::SetAttr() +{ + status_t res = _OperationError(OpSetAttr); + if (res != B_OK) + return res; + + uint32 bcount = fReply->Stream().GetUInt(); + for (uint32 i = 0; i < bcount; i++) + fReply->Stream().GetUInt(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + status_t ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier) { diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 89e334015e..aa504a5592 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -85,6 +85,7 @@ public: status_t Rename(); inline status_t Renew(); inline status_t SaveFH(); + status_t SetAttr(); status_t SetClientID(uint64* clientid, uint64* verifier); inline status_t SetClientIDConfirm(); inline status_t Verify(); diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index aa7460e5cd..a3108aa8b6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -444,6 +444,34 @@ RequestBuilder::SaveFH() } +status_t +RequestBuilder::SetAttr(const uint32* id, uint32 stateSeq, AttrValue* attr, + uint32 count) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpSetAttr); + fRequest->Stream().AddUInt(stateSeq); + if (id != NULL) { + fRequest->Stream().AddUInt(id[0]); + fRequest->Stream().AddUInt(id[1]); + fRequest->Stream().AddUInt(id[2]); + } else { + fRequest->Stream().AddUInt(0); + fRequest->Stream().AddUInt(0); + fRequest->Stream().AddUInt(0); + } + _EncodeAttrs(fRequest->Stream(), attr, count); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::SetClientID(const RPC::Server* serv) { @@ -601,6 +629,28 @@ RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr, i++; } + if (i < count && attr[i].fAttribute == FATTR4_TIME_ACCESS_SET) { + str.AddInt(1); // SET_TO_CLIENT_TIME4 + + struct timespec* ts = + reinterpret_cast(attr[i].fData.fPointer); + str.AddHyper(ts->tv_sec); + str.AddUInt(ts->tv_nsec); + + i++; + } + + if (i < count && attr[i].fAttribute == FATTR4_TIME_MODIFY_SET) { + str.AddInt(1); // SET_TO_CLIENT_TIME4 + + struct timespec* ts = + reinterpret_cast(attr[i].fData.fPointer); + str.AddHyper(ts->tv_sec); + str.AddUInt(ts->tv_nsec); + + i++; + } + stream.AddOpaque(str); } diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 89a7379a67..805d7005fb 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -56,6 +56,8 @@ public: status_t Rename(const char* from, const char* to); status_t Renew(uint64 clientId); status_t SaveFH(); + status_t SetAttr(const uint32* id, uint32 stateSeq, + AttrValue* attr, uint32 count); status_t SetClientID(const RPC::Server* serv); status_t SetClientIDConfirm(uint64 id, uint64 ver); status_t Verify(AttrValue* attr, uint32 count); 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 227791eaf7..dcb73c721f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -264,6 +264,15 @@ nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat) } +static status_t +nfs4_write_stat(fs_volume* volume, fs_vnode* vnode, const struct stat* stat, + uint32 statMask) +{ + Inode* inode = reinterpret_cast(vnode->private_node); + return inode->WriteStat(stat, statMask); +} + + static status_t nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode, int perms, void** _cookie, ino_t* _newVnodeID) @@ -523,7 +532,7 @@ fs_vnode_ops gNFSv4VnodeOps = { nfs4_access, nfs4_read_stat, - NULL, // write_stat() + nfs4_write_stat, NULL, // fs_preallocate() /* file operations */