nfs4: Add basic emulation of named attributes
This commit is contained in:
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user