nfs4: Add rename() hook

This commit is contained in:
Pawel Dziepak
2012-06-29 02:15:01 +02:00
parent be4c74ead3
commit 1ec6b0c1f7
10 changed files with 140 additions and 4 deletions
@@ -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 status_t
Inode::ReadLink(void* buffer, size_t* length) Inode::ReadLink(void* buffer, size_t* length)
{ {
@@ -32,6 +32,8 @@ public:
status_t LookUp(const char* name, ino_t* id); status_t LookUp(const char* name, ino_t* id);
status_t ReadLink(void* buffer, size_t* length); 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 Access(int mode);
status_t Stat(struct stat* st); status_t Stat(struct stat* st);
@@ -34,7 +34,9 @@ enum Opcode {
OpRead = 25, OpRead = 25,
OpReadDir = 26, OpReadDir = 26,
OpReadLink = 27, OpReadLink = 27,
OpRename = 29,
OpRenew = 30, OpRenew = 30,
OpSaveFH = 32,
OpSetClientID = 35, OpSetClientID = 35,
OpSetClientIDConfirm = 36 OpSetClientIDConfirm = 36
}; };
@@ -289,6 +289,26 @@ ReplyInterpreter::ReadLink(void* buffer, uint32* size, uint32 maxSize)
return fReply->Stream().IsEOF() ? B_BAD_VALUE : B_OK; 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 status_t
ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier) ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier)
{ {
@@ -556,7 +576,7 @@ ReplyInterpreter::_NFS4ErrorToHaiku(uint32 x)
case NFS4ERR_NOENT: return B_ENTRY_NOT_FOUND; case NFS4ERR_NOENT: return B_ENTRY_NOT_FOUND;
case NFS4ERR_IO: return B_IO_ERROR; case NFS4ERR_IO: return B_IO_ERROR;
case NFS4ERR_NXIO: return B_DEVICE_NOT_FOUND; 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_EXIST: return B_FILE_EXISTS;
case NFS4ERR_XDEV: return B_CROSS_DEVICE_LINK; case NFS4ERR_XDEV: return B_CROSS_DEVICE_LINK;
case NFS4ERR_NOTDIR: return B_NOT_A_DIRECTORY; case NFS4ERR_NOTDIR: return B_NOT_A_DIRECTORY;
@@ -78,7 +78,9 @@ public:
status_t ReadDir(uint64* cookie, uint64* cookieVerf, status_t ReadDir(uint64* cookie, uint64* cookieVerf,
DirEntry** dirents, uint32* count, bool* eof); DirEntry** dirents, uint32* count, bool* eof);
status_t ReadLink(void* buffer, uint32* size, uint32 maxSize); status_t ReadLink(void* buffer, uint32* size, uint32 maxSize);
status_t Rename();
inline status_t Renew(); inline status_t Renew();
inline status_t SaveFH();
status_t SetClientID(uint64* clientid, uint64* verifier); status_t SetClientID(uint64* clientid, uint64* verifier);
inline status_t SetClientIDConfirm(); inline status_t SetClientIDConfirm();
@@ -161,6 +163,13 @@ ReplyInterpreter::Renew()
} }
inline status_t
ReplyInterpreter::SaveFH()
{
return _OperationError(OpSaveFH);
}
inline status_t inline status_t
ReplyInterpreter::SetClientIDConfirm() ReplyInterpreter::SetClientIDConfirm()
{ {
@@ -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 status_t
RequestBuilder::Renew(uint64 clientId) 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 status_t
RequestBuilder::SetClientID(const RPC::Server* serv) RequestBuilder::SetClientID(const RPC::Server* serv)
{ {
@@ -44,7 +44,9 @@ public:
uint64 cookieVerf, Attribute* attrs, uint64 cookieVerf, Attribute* attrs,
uint32 attrCount); uint32 attrCount);
status_t ReadLink(); status_t ReadLink();
status_t Rename(const char* from, const char* to);
status_t Renew(uint64 clientId); status_t Renew(uint64 clientId);
status_t SaveFH();
status_t SetClientID(const RPC::Server* serv); status_t SetClientID(const RPC::Server* serv);
status_t SetClientIDConfirm(uint64 id, uint64 ver); status_t SetClientIDConfirm(uint64 id, uint64 ver);
+1 -1
View File
@@ -270,7 +270,7 @@ status_t
WriteStream::AddString(const char* str, uint32 maxlen) WriteStream::AddString(const char* str, uint32 maxlen)
{ {
uint32 len = strlen(str); uint32 len = strlen(str);
uint32 size = min_c(maxlen, len); uint32 size = maxlen == 0 ? len : min_c(maxlen, len);
return AddOpaque(str, size); return AddOpaque(str, size);
} }
+1 -1
View File
@@ -76,7 +76,7 @@ public:
inline status_t AddBoolean(bool x); 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 void* ptr, uint32 size);
status_t AddOpaque(const WriteStream& stream); status_t AddOpaque(const WriteStream& stream);
@@ -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<Inode*>(fromDir->private_node);
Inode* toInode = reinterpret_cast<Inode*>(toDir->private_node);
return Inode::Rename(fromInode, toInode, fromName, toName);
}
static status_t static status_t
nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode) nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode)
{ {
@@ -425,7 +435,7 @@ fs_vnode_ops gNFSv4VnodeOps = {
NULL, // link() NULL, // link()
NULL, // unlink() NULL, // unlink()
NULL, // rename() nfs4_rename,
nfs4_access, nfs4_access,
nfs4_read_stat, nfs4_read_stat,