nfs4: Add basic emulation of named attributes
This commit is contained in:
@@ -62,22 +62,41 @@ Inode::OpenAttrDir(OpenDirCookie* cookie)
|
|||||||
status_t
|
status_t
|
||||||
Inode::LoadAttrDirHandle()
|
Inode::LoadAttrDirHandle()
|
||||||
{
|
{
|
||||||
if (!fFileSystem->NamedAttrs())
|
if (fInfo.fAttrDir.fSize != 0)
|
||||||
return B_UNSUPPORTED;
|
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)
|
if (result == B_UNSUPPORTED)
|
||||||
fFileSystem->SetNamedAttrs(false);
|
fFileSystem->SetNamedAttrs(false);
|
||||||
|
|
||||||
if (result != B_OK)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
fInfo.fAttrDir = handle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
fInfo.fAttrDir = handle;
|
||||||
return B_OK;
|
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
|
status_t
|
||||||
Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
|
Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
|
||||||
OpenDirCookie* cookie, uint64* _change, bool attribute)
|
OpenDirCookie* cookie, uint64* _change, bool attribute)
|
||||||
@@ -189,6 +233,9 @@ Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
|
|||||||
if (*fsid != fFileSystem->FsId())
|
if (*fsid != fFileSystem->FsId())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (strstr(dirents[i].fName, "-haiku-attrs") != NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
ino_t id;
|
ino_t id;
|
||||||
if (!attribute) {
|
if (!attribute) {
|
||||||
if (dirents[i].fAttrCount == 2)
|
if (dirents[i].fAttrCount == 2)
|
||||||
@@ -198,7 +245,19 @@ Inode::GetDirSnapshot(DirectoryCacheSnapshot** _snapshot,
|
|||||||
} else
|
} else
|
||||||
id = 0;
|
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 == NULL || entry->fName == NULL) {
|
||||||
if (entry->fName == NULL)
|
if (entry->fName == NULL)
|
||||||
delete entry;
|
delete entry;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <AutoDeleter.h>
|
||||||
#include <fs_cache.h>
|
#include <fs_cache.h>
|
||||||
#include <NodeMonitor.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
|
status_t
|
||||||
Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create,
|
Inode::OpenAttr(const char* _name, int mode, OpenAttrCookie* cookie,
|
||||||
int32 type)
|
bool create, int32 type)
|
||||||
{
|
{
|
||||||
(void)type;
|
(void)type;
|
||||||
|
|
||||||
@@ -202,6 +227,11 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create,
|
|||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
char* name = AttrToFileName(_name);
|
||||||
|
if (name == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
MemoryDeleter nameDeleter(name);
|
||||||
|
|
||||||
OpenDelegationData data;
|
OpenDelegationData data;
|
||||||
data.fType = OPEN_DELEGATE_NONE;
|
data.fType = OPEN_DELEGATE_NONE;
|
||||||
|
|
||||||
@@ -209,8 +239,9 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create,
|
|||||||
if (state == NULL)
|
if (state == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
state->fInfo.fName = name;
|
state->fInfo.fName = strdup(name);
|
||||||
state->fInfo.fParent = fInfo.fAttrDir;
|
state->fInfo.fParent = fInfo.fAttrDir;
|
||||||
|
state->fFileSystem = fFileSystem;
|
||||||
result = NFS4Inode::OpenAttr(state, name, mode, &data, create);
|
result = NFS4Inode::OpenAttr(state, name, mode, &data, create);
|
||||||
if (result != B_OK) {
|
if (result != B_OK) {
|
||||||
delete state;
|
delete state;
|
||||||
@@ -225,8 +256,7 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create,
|
|||||||
|
|
||||||
if (data.fType != OPEN_DELEGATE_NONE) {
|
if (data.fType != OPEN_DELEGATE_NONE) {
|
||||||
Delegation* delegation
|
Delegation* delegation
|
||||||
= new(std::nothrow) Delegation(data, this, fOpenState->fClientID,
|
= new(std::nothrow) Delegation(data, this, state->fClientID, true);
|
||||||
true);
|
|
||||||
if (delegation != NULL) {
|
if (delegation != NULL) {
|
||||||
delegation->fInfo = state->fInfo;
|
delegation->fInfo = state->fInfo;
|
||||||
delegation->fFileSystem = fFileSystem;
|
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;
|
struct stat st;
|
||||||
st.st_size = 0;
|
st.st_size = 0;
|
||||||
WriteStat(&st, B_STAT_SIZE, cookie);
|
WriteStat(&st, B_STAT_SIZE, cookie);
|
||||||
@@ -248,8 +278,11 @@ Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create,
|
|||||||
status_t
|
status_t
|
||||||
Inode::CloseAttr(OpenAttrCookie* cookie)
|
Inode::CloseAttr(OpenAttrCookie* cookie)
|
||||||
{
|
{
|
||||||
cookie->fOpenState->fDelegation->GiveUp();
|
if (cookie->fOpenState->fDelegation != NULL) {
|
||||||
fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation);
|
cookie->fOpenState->fDelegation->GiveUp();
|
||||||
|
fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation);
|
||||||
|
}
|
||||||
|
|
||||||
delete cookie->fOpenState->fDelegation;
|
delete cookie->fOpenState->fDelegation;
|
||||||
delete cookie->fOpenState;
|
delete cookie->fOpenState;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|||||||
@@ -107,17 +107,22 @@ NFS4Inode::Access(uint32* allowed)
|
|||||||
|
|
||||||
status_t
|
status_t
|
||||||
NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
|
NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
|
||||||
FileHandle* handle)
|
FileHandle* handle, bool parent)
|
||||||
{
|
{
|
||||||
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(fInfo.fHandle);
|
if (parent)
|
||||||
|
req.PutFH(fInfo.fParent);
|
||||||
|
else
|
||||||
|
req.PutFH(fInfo.fHandle);
|
||||||
|
|
||||||
Attribute dirAttr[] = { FATTR4_CHANGE };
|
if (change != NULL) {
|
||||||
req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
|
Attribute dirAttr[] = { FATTR4_CHANGE };
|
||||||
|
req.GetAttr(dirAttr, sizeof(dirAttr) / sizeof(Attribute));
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp(name, ".."))
|
if (!strcmp(name, ".."))
|
||||||
req.LookUpUp();
|
req.LookUpUp();
|
||||||
@@ -142,12 +147,14 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
|
|||||||
|
|
||||||
AttrValue* values;
|
AttrValue* values;
|
||||||
uint32 count;
|
uint32 count;
|
||||||
result = reply.GetAttr(&values, &count);
|
if (change != NULL) {
|
||||||
if (result != B_OK)
|
result = reply.GetAttr(&values, &count);
|
||||||
return result;
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
*change = values[0].fData.fValue64;
|
*change = values[0].fData.fValue64;
|
||||||
delete[] values;
|
delete[] values;
|
||||||
|
}
|
||||||
|
|
||||||
if (!strcmp(name, ".."))
|
if (!strcmp(name, ".."))
|
||||||
result = reply.LookUpUp();
|
result = reply.LookUpUp();
|
||||||
@@ -170,10 +177,13 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
|
|||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count < 2 || values[1].fAttribute != FATTR4_FILEID)
|
if (fileID != NULL) {
|
||||||
*fileID = fFileSystem->AllocFileId();
|
if (count < 2 || values[1].fAttribute != FATTR4_FILEID)
|
||||||
else
|
*fileID = fFileSystem->AllocFileId();
|
||||||
*fileID = values[1].fData.fValue64;
|
else
|
||||||
|
*fileID = values[1].fData.fValue64;
|
||||||
|
}
|
||||||
|
|
||||||
delete[] values;
|
delete[] values;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -536,11 +546,11 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
|
|||||||
|
|
||||||
ReplyInterpreter& reply = request.Reply();
|
ReplyInterpreter& reply = request.Reply();
|
||||||
|
|
||||||
|
sequence += IncrementSequence(reply.NFS4Error());
|
||||||
|
|
||||||
if (HandleErrors(reply.NFS4Error(), serv, NULL, state, &sequence))
|
if (HandleErrors(reply.NFS4Error(), serv, NULL, state, &sequence))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sequence += IncrementSequence(reply.NFS4Error());
|
|
||||||
|
|
||||||
// Verify if the file we want to open is the file this Inode
|
// Verify if the file we want to open is the file this Inode
|
||||||
// represents.
|
// represents.
|
||||||
if (fFileSystem->IsAttrSupported(FATTR4_FILEID) ||
|
if (fFileSystem->IsAttrSupported(FATTR4_FILEID) ||
|
||||||
@@ -617,11 +627,11 @@ NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode,
|
|||||||
|
|
||||||
ReplyInterpreter& reply = request.Reply();
|
ReplyInterpreter& reply = request.Reply();
|
||||||
|
|
||||||
if (HandleErrors(reply.NFS4Error(), serv, NULL, state))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
sequence += IncrementSequence(reply.NFS4Error());
|
sequence += IncrementSequence(reply.NFS4Error());
|
||||||
|
|
||||||
|
if (HandleErrors(reply.NFS4Error(), serv, NULL, state, &sequence))
|
||||||
|
continue;
|
||||||
|
|
||||||
reply.PutFH();
|
reply.PutFH();
|
||||||
result = reply.Open(state->fStateID, &state->fStateSeq, &confirm,
|
result = reply.Open(state->fStateID, &state->fStateSeq, &confirm,
|
||||||
delegation);
|
delegation);
|
||||||
@@ -639,7 +649,7 @@ NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode,
|
|||||||
state->fOpened = true;
|
state->fOpened = true;
|
||||||
|
|
||||||
if (confirm)
|
if (confirm)
|
||||||
result = ConfirmOpen(fInfo.fHandle, state, &sequence);
|
result = ConfirmOpen(state->fInfo.fHandle, state, &sequence);
|
||||||
|
|
||||||
fFileSystem->OpenOwnerSequenceUnlock(sequence);
|
fFileSystem->OpenOwnerSequenceUnlock(sequence);
|
||||||
return result;
|
return result;
|
||||||
@@ -714,14 +724,18 @@ NFS4Inode::WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position,
|
|||||||
|
|
||||||
status_t
|
status_t
|
||||||
NFS4Inode::CreateObject(const char* name, const char* path, int mode,
|
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 {
|
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(fInfo.fHandle);
|
if (parent)
|
||||||
|
req.PutFH(fInfo.fParent);
|
||||||
|
else
|
||||||
|
req.PutFH(fInfo.fHandle);
|
||||||
|
|
||||||
uint32 i = 0;
|
uint32 i = 0;
|
||||||
AttrValue cattr[1];
|
AttrValue cattr[1];
|
||||||
@@ -742,8 +756,11 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
req.GetFH();
|
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();
|
status_t result = request.Send();
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
@@ -764,18 +781,20 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode,
|
|||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
AttrValue* values;
|
if (fileID != NULL) {
|
||||||
uint32 count;
|
AttrValue* values;
|
||||||
result = reply.GetAttr(&values, &count);
|
uint32 count;
|
||||||
if (result != B_OK)
|
result = reply.GetAttr(&values, &count);
|
||||||
return result;
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
*fileID = fFileSystem->AllocFileId();
|
*fileID = fFileSystem->AllocFileId();
|
||||||
else
|
else
|
||||||
*fileID = values[0].fData.fValue64;
|
*fileID = values[0].fData.fValue64;
|
||||||
|
|
||||||
delete[] values;
|
delete[] values;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ protected:
|
|||||||
status_t CommitWrites();
|
status_t CommitWrites();
|
||||||
|
|
||||||
status_t LookUp(const char* name, uint64* change, uint64* fileID,
|
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,
|
status_t Link(Inode* dir, const char* name,
|
||||||
ChangeInfo* changeInfo);
|
ChangeInfo* changeInfo);
|
||||||
@@ -65,7 +65,8 @@ protected:
|
|||||||
|
|
||||||
status_t CreateObject(const char* name, const char* path,
|
status_t CreateObject(const char* name, const char* path,
|
||||||
int mode, FileType type, ChangeInfo* changeInfo,
|
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,
|
status_t RemoveObject(const char* name, FileType type,
|
||||||
ChangeInfo* changeInfo, uint64* fileID);
|
ChangeInfo* changeInfo, uint64* fileID);
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ OpenState::OpenState()
|
|||||||
|
|
||||||
OpenState::~OpenState()
|
OpenState::~OpenState()
|
||||||
{
|
{
|
||||||
fFileSystem->RemoveOpenFile(this);
|
if (fOpened)
|
||||||
|
fFileSystem->RemoveOpenFile(this);
|
||||||
Close();
|
Close();
|
||||||
|
|
||||||
mutex_destroy(&fLock);
|
mutex_destroy(&fLock);
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ FSLocations::~FSLocations()
|
|||||||
|
|
||||||
AttrValue::AttrValue()
|
AttrValue::AttrValue()
|
||||||
:
|
:
|
||||||
|
fAttribute(0),
|
||||||
fFreePointer(false)
|
fFreePointer(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user