nfs4: unlink() and remove_dir() should check node type
This commit is contained in:
@@ -214,13 +214,21 @@ Inode::LookUp(const char* name, ino_t* id)
|
|||||||
// more than one hard link and we delete the name it stores for filehandle
|
// more than one hard link and we delete the name it stores for filehandle
|
||||||
// restoration node will inocorectly become unavailable.
|
// restoration node will inocorectly become unavailable.
|
||||||
status_t
|
status_t
|
||||||
Inode::Remove(const char* name)
|
Inode::Remove(const char* name, FileType type)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
RPC::Server* serv = fFilesystem->Server();
|
RPC::Server* serv = fFilesystem->Server();
|
||||||
Request request(serv);
|
Request request(serv);
|
||||||
RequestBuilder& req = request.Builder();
|
RequestBuilder& req = request.Builder();
|
||||||
|
|
||||||
|
req.PutFH(fHandle);
|
||||||
|
req.LookUp(name);
|
||||||
|
AttrValue attr;
|
||||||
|
attr.fAttribute = FATTR4_TYPE;
|
||||||
|
attr.fFreePointer = false;
|
||||||
|
attr.fData.fValue32 = type;
|
||||||
|
req.Verify(&attr, 1);
|
||||||
|
|
||||||
req.PutFH(fHandle);
|
req.PutFH(fHandle);
|
||||||
req.Remove(name);
|
req.Remove(name);
|
||||||
|
|
||||||
@@ -242,6 +250,22 @@ Inode::Remove(const char* name)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = reply.PutFH();
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result = reply.LookUp();
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result = reply.Verify();
|
||||||
|
if (result == NFS4ERR_NOT_SAME && type == NF4REG)
|
||||||
|
return B_IS_A_DIRECTORY;
|
||||||
|
if (result == NFS4ERR_NOT_SAME && type == NF4DIR)
|
||||||
|
return B_NOT_A_DIRECTORY;
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
result = reply.PutFH();
|
result = reply.PutFH();
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ 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);
|
||||||
status_t Remove(const char* name);
|
status_t Remove(const char* name, FileType type);
|
||||||
static status_t Rename(Inode* from, Inode* to,
|
static status_t Rename(Inode* from, Inode* to,
|
||||||
const char* fromName, const char* toName);
|
const char* fromName, const char* toName);
|
||||||
status_t Access(int mode);
|
status_t Access(int mode);
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ enum Opcode {
|
|||||||
OpRenew = 30,
|
OpRenew = 30,
|
||||||
OpSaveFH = 32,
|
OpSaveFH = 32,
|
||||||
OpSetClientID = 35,
|
OpSetClientID = 35,
|
||||||
OpSetClientIDConfirm = 36
|
OpSetClientIDConfirm = 36,
|
||||||
|
OpVerify = 37
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Access {
|
enum Access {
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ public:
|
|||||||
inline status_t SaveFH();
|
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();
|
||||||
|
inline status_t Verify();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _ParseHeader();
|
void _ParseHeader();
|
||||||
@@ -178,5 +179,12 @@ ReplyInterpreter::SetClientIDConfirm()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline status_t
|
||||||
|
ReplyInterpreter::Verify()
|
||||||
|
{
|
||||||
|
return _OperationError(OpVerify);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // REPLYINTERPRETER_H
|
#endif // REPLYINTERPRETER_H
|
||||||
|
|
||||||
|
|||||||
@@ -432,6 +432,37 @@ RequestBuilder::SetClientIDConfirm(uint64 id, uint64 ver)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
RequestBuilder::Verify(AttrValue* attr, uint32 count)
|
||||||
|
{
|
||||||
|
if (fProcedure != ProcCompound)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (fRequest == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
fRequest->Stream().AddUInt(OpVerify);
|
||||||
|
|
||||||
|
Attribute* attrs =
|
||||||
|
reinterpret_cast<Attribute*>(malloc(sizeof(Attribute) * count));
|
||||||
|
for (uint32 i = 0; i < count; i++)
|
||||||
|
attrs[i] = static_cast<Attribute>(attr[i].fAttribute);
|
||||||
|
_AttrBitmap(fRequest->Stream(), attrs, count);
|
||||||
|
free(attrs);
|
||||||
|
|
||||||
|
uint32 i = 0;
|
||||||
|
XDR::WriteStream str;
|
||||||
|
if (i < count && attr[i].fAttribute == FATTR4_TYPE) {
|
||||||
|
str.AddUInt(attr[i].fData.fValue32);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
fRequest->Stream().AddOpaque(str);
|
||||||
|
fOpCount++;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RPC::Call*
|
RPC::Call*
|
||||||
RequestBuilder::Request()
|
RequestBuilder::Request()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <SupportDefs.h>
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
#include "NFS4Defs.h"
|
#include "NFS4Defs.h"
|
||||||
|
#include "ReplyInterpreter.h"
|
||||||
#include "RPCCall.h"
|
#include "RPCCall.h"
|
||||||
#include "RPCServer.h"
|
#include "RPCServer.h"
|
||||||
#include "XDR.h"
|
#include "XDR.h"
|
||||||
@@ -50,6 +51,7 @@ public:
|
|||||||
status_t SaveFH();
|
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);
|
||||||
|
status_t Verify(AttrValue* attr, uint32 count);
|
||||||
|
|
||||||
RPC::Call* Request();
|
RPC::Call* Request();
|
||||||
|
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ static status_t
|
|||||||
nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name)
|
nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name)
|
||||||
{
|
{
|
||||||
Inode* inode = reinterpret_cast<Inode*>(dir->private_node);
|
Inode* inode = reinterpret_cast<Inode*>(dir->private_node);
|
||||||
return inode->Remove(name);
|
return inode->Remove(name, NF4REG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -321,7 +321,7 @@ static status_t
|
|||||||
nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name)
|
nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name)
|
||||||
{
|
{
|
||||||
Inode* inode = reinterpret_cast<Inode*>(parent->private_node);
|
Inode* inode = reinterpret_cast<Inode*>(parent->private_node);
|
||||||
return inode->Remove(name);
|
return inode->Remove(name, NF4DIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user