nfs4: Add rename() hook
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -34,7 +34,9 @@ enum Opcode {
|
||||
OpRead = 25,
|
||||
OpReadDir = 26,
|
||||
OpReadLink = 27,
|
||||
OpRename = 29,
|
||||
OpRenew = 30,
|
||||
OpSaveFH = 32,
|
||||
OpSetClientID = 35,
|
||||
OpSetClientIDConfirm = 36
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
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,
|
||||
|
||||
Reference in New Issue
Block a user