From 1ec6b0c1f74d5cc239bf210740ad35b9479b8ef6 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 21 Jun 2012 21:57:42 +0200 Subject: [PATCH] nfs4: Add rename() hook --- .../kernel/file_systems/nfs4/Inode.cpp | 58 +++++++++++++++++++ src/add-ons/kernel/file_systems/nfs4/Inode.h | 2 + .../kernel/file_systems/nfs4/NFS4Defs.h | 2 + .../file_systems/nfs4/ReplyInterpreter.cpp | 22 ++++++- .../file_systems/nfs4/ReplyInterpreter.h | 9 +++ .../file_systems/nfs4/RequestBuilder.cpp | 33 +++++++++++ .../kernel/file_systems/nfs4/RequestBuilder.h | 2 + src/add-ons/kernel/file_systems/nfs4/XDR.cpp | 2 +- src/add-ons/kernel/file_systems/nfs4/XDR.h | 2 +- .../file_systems/nfs4/kernel_interface.cpp | 12 +++- 10 files changed, 140 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index d4e9e20bb4..b663991c7a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -210,6 +210,64 @@ Inode::LookUp(const char* name, ino_t* id) } +// Rename may cause some problems if filehandles are volatile and local Inode +// object exists for renamed node. It's stored filename will become invalid +// and, consequnetly, filehandle restoration will fail. Probably, it will +// be much easier to solve this problem if more metadata is cached. +status_t +Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) +{ + if (from->fFilesystem != to->fFilesystem) + return B_DONT_DO_THAT; + + do { + RPC::Server* serv = from->fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(from->fHandle); + req.SaveFH(); + req.PutFH(to->fHandle); + req.Rename(fromName, toName); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + // filehandle has expired + if (reply.NFS4Error() == NFS4ERR_FHEXPIRED) { + from->_LookUpFilehandle(); + to->_LookUpFilehandle(); + continue; + } + + // filesystem has been moved + if (reply.NFS4Error() == NFS4ERR_MOVED) { + from->fFilesystem->Migrate(from->fHandle, serv); + to->fFilesystem->Migrate(to->fHandle, serv); + continue; + } + + result = reply.PutFH(); + if (result != B_OK) + return result; + + result = reply.SaveFH(); + if (result != B_OK) + return result; + + result = reply.PutFH(); + if (result != B_OK) + return result; + + + return reply.Rename(); + } while (true); +} + + status_t Inode::ReadLink(void* buffer, size_t* length) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index c1e7464426..0265dde6df 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -32,6 +32,8 @@ public: status_t LookUp(const char* name, ino_t* id); status_t ReadLink(void* buffer, size_t* length); + 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); diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index fefe9efb39..c6c7ce4b74 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -34,7 +34,9 @@ enum Opcode { OpRead = 25, OpReadDir = 26, OpReadLink = 27, + OpRename = 29, OpRenew = 30, + OpSaveFH = 32, OpSetClientID = 35, OpSetClientIDConfirm = 36 }; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp index 69ba2f9ad2..0207d323c1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.cpp @@ -289,6 +289,26 @@ ReplyInterpreter::ReadLink(void* buffer, uint32* size, uint32 maxSize) return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; } + +status_t +ReplyInterpreter::Rename() +{ + status_t res = _OperationError(OpRename); + if (res != B_OK) + return res; + + fReply->Stream().GetBoolean(); + fReply->Stream().GetUHyper(); + fReply->Stream().GetUHyper(); + + fReply->Stream().GetBoolean(); + fReply->Stream().GetUHyper(); + fReply->Stream().GetUHyper(); + + return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; +} + + status_t ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier) { @@ -556,7 +576,7 @@ ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x) case NFS4ERR_NOENT: return B_ENTRY_NOT_FOUND; case NFS4ERR_IO: return B_IO_ERROR; case NFS4ERR_NXIO: return B_DEVICE_NOT_FOUND; - case NFS4ERR_ACCESS: return B_PERMISSION_DENIED; + case NFS4ERR_ACCESS: return B_NOT_ALLOWED; case NFS4ERR_EXIST: return B_FILE_EXISTS; case NFS4ERR_XDEV: return B_CROSS_DEVICE_LINK; case NFS4ERR_NOTDIR: return B_NOT_A_DIRECTORY; diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index f2ed9168e1..a96262973a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -78,7 +78,9 @@ public: status_t ReadDir(uint64* cookie, uint64* cookieVerf, DirEntry** dirents, uint32* count, bool* eof); status_t ReadLink(void* buffer, uint32* size, uint32 maxSize); + status_t Rename(); inline status_t Renew(); + inline status_t SaveFH(); status_t SetClientID(uint64* clientid, uint64* verifier); inline status_t SetClientIDConfirm(); @@ -161,6 +163,13 @@ ReplyInterpreter::Renew() } +inline status_t +ReplyInterpreter::SaveFH() +{ + return _OperationError(OpSaveFH); +} + + inline status_t ReplyInterpreter::SetClientIDConfirm() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index dbfdd377f8..628ea3f865 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -308,6 +308,24 @@ RequestBuilder::ReadLink() } +status_t +RequestBuilder::Rename(const char* from, const char* to) +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpRename); + fRequest->Stream().AddString(from); + fRequest->Stream().AddString(to); + + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::Renew(uint64 clientId) { @@ -325,6 +343,21 @@ RequestBuilder::Renew(uint64 clientId) } +status_t +RequestBuilder::SaveFH() +{ + if (fProcedure != ProcCompound) + return B_BAD_VALUE; + if (fRequest == NULL) + return B_NO_MEMORY; + + fRequest->Stream().AddUInt(OpSaveFH); + fOpCount++; + + return B_OK; +} + + status_t RequestBuilder::SetClientID(const RPC::Server* serv) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 12005dba89..26823c4e39 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -44,7 +44,9 @@ public: uint64 cookieVerf, Attribute* attrs, uint32 attrCount); status_t ReadLink(); + status_t Rename(const char* from, const char* to); status_t Renew(uint64 clientId); + status_t SaveFH(); status_t SetClientID(const RPC::Server* serv); status_t SetClientIDConfirm(uint64 id, uint64 ver); diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.cpp b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp index 73455c99b0..423d444e0f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/XDR.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.cpp @@ -270,7 +270,7 @@ status_t WriteStream::AddString(const char* str, uint32 maxlen) { uint32 len = strlen(str); - uint32 size = min_c(maxlen, len); + uint32 size = maxlen == 0 ? len : min_c(maxlen, len); return AddOpaque(str, size); } diff --git a/src/add-ons/kernel/file_systems/nfs4/XDR.h b/src/add-ons/kernel/file_systems/nfs4/XDR.h index 6f9aee292b..5d5300e321 100644 --- a/src/add-ons/kernel/file_systems/nfs4/XDR.h +++ b/src/add-ons/kernel/file_systems/nfs4/XDR.h @@ -76,7 +76,7 @@ public: inline status_t AddBoolean(bool x); - status_t AddString(const char* str, uint32 maxlen); + status_t AddString(const char* str, uint32 maxlen = 0); status_t AddOpaque(const void* ptr, uint32 size); status_t AddOpaque(const WriteStream& stream); 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 6ed7b435e3..4598d8637a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -212,6 +212,16 @@ nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer, } +static status_t +nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName, + fs_vnode* toDir, const char* toName) +{ + Inode* fromInode = reinterpret_cast(fromDir->private_node); + Inode* toInode = reinterpret_cast(toDir->private_node); + return Inode::Rename(fromInode, toInode, fromName, toName); +} + + static status_t nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode) { @@ -425,7 +435,7 @@ fs_vnode_ops gNFSv4VnodeOps = { NULL, // link() NULL, // unlink() - NULL, // rename() + nfs4_rename, nfs4_access, nfs4_read_stat,