nfs4: Add basic emulation of named attributes

This commit is contained in:
Pawel Dziepak
2012-08-15 04:11:25 +02:00
parent ff4d16ded4
commit 70472e11d3
6 changed files with 169 additions and 55 deletions
@@ -62,22 +62,41 @@ Inode::OpenAttrDir(OpenDirCookie* cookie)
status_t
Inode::LoadAttrDirHandle()
{
if (!fFileSystem->NamedAttrs())
return B_UNSUPPORTED;
if (fInfo.fAttrDir.fSize != 0)
return B_OK;
if (fInfo.fAttrDir.fSize == 0) {
FileHandle handle;
FileHandle handle;
status_t result;
if (!fFileSystem->NamedAttrs()) {
char* attrDir
= reinterpret_cast<char*>(malloc(strlen(fInfo.fName) + 32));
if (attrDir == NULL)
return B_NO_MEMORY;
strcpy(attrDir, ".");
strcat(attrDir, fInfo.fName);
strcat(attrDir, "-haiku-attrs");
status_t result = NFS4Inode::OpenAttrDir(&handle);
result = NFS4Inode::LookUp(attrDir, NULL, NULL, &handle, true);
if (result == B_ENTRY_NOT_FOUND) {
ChangeInfo change;
struct stat st;
Stat(&st);
st.st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
result = NFS4Inode::CreateObject(attrDir, NULL, st.st_mode, NF4DIR,
&change, NULL, &handle, true);
}
free(attrDir);
} else {
result = NFS4Inode::OpenAttrDir(&handle);
if (result == B_UNSUPPORTED)
fFileSystem->SetNamedAttrs(false);
if (result != B_OK)
return result;
fInfo.fAttrDir = handle;
}
if (result != B_OK)
return result;
fInfo.fAttrDir = handle;
return B_OK;
}
@@ -156,6 +175,31 @@ Inode::ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
}
static char*
FileToAttrName(const char* path)
{
char* name = strdup(path);
if (name == NULL)
return NULL;
char* current = strpbrk(name, "#$");
while (current != NULL) {
switch (*current) {
case '#':
*current = '/';
break;
case '$':
*current = ':';
break;
}
current = strpbrk(name, "#$");
}
return name;
}
status_t
Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
OpenDirCookie* cookie, uint64* _change, bool attribute)
@@ -189,6 +233,9 @@ Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
if (*fsid != fFileSystem->FsId())
continue;
if (strstr(dirents[i].fName, "-haiku-attrs") != NULL)
continue;
ino_t id;
if (!attribute) {
if (dirents[i].fAttrCount == 2)
@@ -198,7 +245,19 @@ Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
} else
id = 0;
NameCacheEntry* entry = new NameCacheEntry(dirents[i].fName, id);
const char* name = dirents[i].fName;
if (attribute)
name = FileToAttrName(name);
if (name == NULL) {
delete snapshot;
delete[] dirents;
return B_NO_MEMORY;
}
NameCacheEntry* entry = new NameCacheEntry(name, id);
if (attribute)
free(const_cast<char*>(name));
if (entry == NULL || entry->fName == NULL) {
if (entry->fName == NULL)
delete entry;
@@ -11,6 +11,7 @@
#include <string.h>
#include <AutoDeleter.h>
#include <fs_cache.h>
#include <NodeMonitor.h>
@@ -192,9 +193,33 @@ Inode::Close(OpenFileCookie* cookie)
}
static char*
AttrToFileName(const char* path)
{
char* name = strdup(path);
if (name == NULL)
return NULL;
char* current = strpbrk(name, "/:");
while (current != NULL) {
switch (*current) {
case '/':
*current = '#';
break;
case ':':
*current = '$';
break;
}
current = strpbrk(name, "/:");
}
return name;
}
status_t
Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create,
int32 type)
Inode::OpenAttr(const char* _name, int mode, OpenAttrCookie* cookie,
bool create, int32 type)
{
(void)type;
@@ -202,6 +227,11 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create,
if (result != B_OK)
return result;
char* name = AttrToFileName(_name);
if (name == NULL)
return B_NO_MEMORY;
MemoryDeleter nameDeleter(name);
OpenDelegationData data;
data.fType = OPEN_DELEGATE_NONE;
@@ -209,8 +239,9 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create,
if (state == NULL)
return B_NO_MEMORY;
state->fInfo.fName = name;
state->fInfo.fName = strdup(name);
state->fInfo.fParent = fInfo.fAttrDir;
state->fFileSystem = fFileSystem;
result = NFS4Inode::OpenAttr(state, name, mode, &data, create);
if (result != B_OK) {
delete state;
@@ -225,8 +256,7 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create,
if (data.fType != OPEN_DELEGATE_NONE) {
Delegation* delegation
= new(std::nothrow) Delegation(data, this, fOpenState->fClientID,
true);
= new(std::nothrow) Delegation(data, this, state->fClientID, true);
if (delegation != NULL) {
delegation->fInfo = state->fInfo;
delegation->fFileSystem = fFileSystem;
@@ -235,7 +265,7 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create,
}
}
if ((mode & O_TRUNC) == O_TRUNC) {
if (create || (mode & O_TRUNC) == O_TRUNC) {
struct stat st;
st.st_size = 0;
WriteStat(&st, B_STAT_SIZE, cookie);
@@ -248,8 +278,11 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create,
status_t
Inode::CloseAttr(OpenAttrCookie* cookie)
{
cookie->fOpenState->fDelegation->GiveUp();
fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation);
if (cookie->fOpenState->fDelegation != NULL) {
cookie->fOpenState->fDelegation->GiveUp();
fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation);
}
delete cookie->fOpenState->fDelegation;
delete cookie->fOpenState;
return B_OK;
@@ -107,17 +107,22 @@ NFS4Inode::Access(uint32* allowed)
status_t
NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
FileHandle* handle)
FileHandle* handle, bool parent)
{
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
if (parent)
req.PutFH(fInfo.fParent);
else
req.PutFH(fInfo.fHandle);
Attribute dirAttr[] = { FATTR4_CHANGE };
req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
if (change != NULL) {
Attribute dirAttr[] = { FATTR4_CHANGE };
req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
}
if (!strcmp(name, ".."))
req.LookUpUp();
@@ -142,12 +147,14 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count);
if (result != B_OK)
return result;
if (change != NULL) {
result = reply.GetAttr(&values, &count);
if (result != B_OK)
return result;
*change = values[0].fData.fValue64;
delete[] values;
*change = values[0].fData.fValue64;
delete[] values;
}
if (!strcmp(name, ".."))
result = reply.LookUpUp();
@@ -170,10 +177,13 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
return B_ENTRY_NOT_FOUND;
}
if (count < 2 || values[1].fAttribute != FATTR4_FILEID)
*fileID = fFileSystem->AllocFileId();
else
*fileID = values[1].fData.fValue64;
if (fileID != NULL) {
if (count < 2 || values[1].fAttribute != FATTR4_FILEID)
*fileID = fFileSystem->AllocFileId();
else
*fileID = values[1].fData.fValue64;
}
delete[] values;
return B_OK;
@@ -536,11 +546,11 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
ReplyInterpreter& reply = request.Reply();
sequence += IncrementSequence(reply.NFS4Error());
if (HandleErrors(reply.NFS4Error(), serv, NULL, state, &sequence))
continue;
sequence += IncrementSequence(reply.NFS4Error());
// Verify if the file we want to open is the file this Inode
// represents.
if (fFileSystem->IsAttrSupported(FATTR4_FILEID) ||
@@ -617,11 +627,11 @@ NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode,
ReplyInterpreter& reply = request.Reply();
if (HandleErrors(reply.NFS4Error(), serv, NULL, state))
continue;
sequence += IncrementSequence(reply.NFS4Error());
if (HandleErrors(reply.NFS4Error(), serv, NULL, state, &sequence))
continue;
reply.PutFH();
result = reply.Open(state->fStateID, &state->fStateSeq, &confirm,
delegation);
@@ -639,7 +649,7 @@ NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode,
state->fOpened = true;
if (confirm)
result = ConfirmOpen(fInfo.fHandle, state, &sequence);
result = ConfirmOpen(state->fInfo.fHandle, state, &sequence);
fFileSystem->OpenOwnerSequenceUnlock(sequence);
return result;
@@ -714,14 +724,18 @@ NFS4Inode::WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position,
status_t
NFS4Inode::CreateObject(const char* name, const char* path, int mode,
FileType type, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle)
FileType type, ChangeInfo* changeInfo, uint64* fileID, FileHandle* handle,
bool parent)
{
do {
RPC::Server* serv = fFileSystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fInfo.fHandle);
if (parent)
req.PutFH(fInfo.fParent);
else
req.PutFH(fInfo.fHandle);
uint32 i = 0;
AttrValue cattr[1];
@@ -742,8 +756,11 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode,
}
req.GetFH();
Attribute attr[] = { FATTR4_FILEID };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
if (fileID != NULL) {
Attribute attr[] = { FATTR4_FILEID };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
}
status_t result = request.Send();
if (result != B_OK)
@@ -764,18 +781,20 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode,
if (result != B_OK)
return result;
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count);
if (result != B_OK)
return result;
if (fileID != NULL) {
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count);
if (result != B_OK)
return result;
if (count == 0)
*fileID = fFileSystem->AllocFileId();
else
*fileID = values[0].fData.fValue64;
if (count == 0)
*fileID = fFileSystem->AllocFileId();
else
*fileID = values[0].fData.fValue64;
delete[] values;
delete[] values;
}
return B_OK;
} while (true);
@@ -31,7 +31,7 @@ protected:
status_t CommitWrites();
status_t LookUp(const char* name, uint64* change, uint64* fileID,
FileHandle* handle);
FileHandle* handle, bool parent = false);
status_t Link(Inode* dir, const char* name,
ChangeInfo* changeInfo);
@@ -65,7 +65,8 @@ protected:
status_t CreateObject(const char* name, const char* path,
int mode, FileType type, ChangeInfo* changeInfo,
uint64* fileID, FileHandle* handle);
uint64* fileID, FileHandle* handle,
bool parent = false);
status_t RemoveObject(const char* name, FileType type,
ChangeInfo* changeInfo, uint64* fileID);
@@ -32,7 +32,8 @@ OpenState::OpenState()
OpenState::~OpenState()
{
fFileSystem->RemoveOpenFile(this);
if (fOpened)
fFileSystem->RemoveOpenFile(this);
Close();
mutex_destroy(&fLock);
@@ -34,6 +34,7 @@ FSLocations::~FSLocations()
AttrValue::AttrValue()
:
fAttribute(0),
fFreePointer(false)
{
}