nfs4: Add basic support for extended attributes
This commit is contained in:
@@ -73,11 +73,12 @@ struct Cookie {
|
||||
status_t CancelAll();
|
||||
};
|
||||
|
||||
struct OpenFileCookie : public Cookie {
|
||||
struct OpenStateCookie : public Cookie {
|
||||
OpenState* fOpenState;
|
||||
|
||||
uint32 fMode;
|
||||
};
|
||||
|
||||
struct OpenFileCookie : public OpenStateCookie {
|
||||
LockInfo* fLocks;
|
||||
|
||||
void AddLock(LockInfo* lock);
|
||||
@@ -97,6 +98,8 @@ struct OpenDirCookie : public Cookie {
|
||||
~OpenDirCookie();
|
||||
};
|
||||
|
||||
struct OpenAttrCookie : public OpenStateCookie { };
|
||||
|
||||
|
||||
#endif // COOKIE_H
|
||||
|
||||
|
||||
@@ -14,11 +14,12 @@
|
||||
|
||||
|
||||
Delegation::Delegation(const OpenDelegationData& data, Inode* inode,
|
||||
uint64 clientID)
|
||||
uint64 clientID, bool attribute)
|
||||
:
|
||||
fClientID(clientID),
|
||||
fData(data),
|
||||
fInode(inode)
|
||||
fInode(inode),
|
||||
fAttribute(attribute)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -26,7 +27,7 @@ Delegation::Delegation(const OpenDelegationData& data, Inode* inode,
|
||||
status_t
|
||||
Delegation::GiveUp(bool truncate)
|
||||
{
|
||||
if (!truncate)
|
||||
if (!fAttribute && !truncate)
|
||||
fInode->SyncAndCommit(true);
|
||||
|
||||
ReturnDelegation();
|
||||
|
||||
@@ -21,7 +21,7 @@ class Delegation : public NFS4Object,
|
||||
public DoublyLinkedListLinkImpl<Delegation> {
|
||||
public:
|
||||
Delegation(const OpenDelegationData& data, Inode* inode,
|
||||
uint64 clientID);
|
||||
uint64 clientID, bool attr = false);
|
||||
|
||||
status_t GiveUp(bool truncate = false);
|
||||
|
||||
@@ -35,6 +35,7 @@ private:
|
||||
uint64 fClientID;
|
||||
OpenDelegationData fData;
|
||||
Inode* fInode;
|
||||
bool fAttribute;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ struct FileHandle {
|
||||
inline FileHandle(const FileHandle& fh);
|
||||
inline FileHandle& operator=(const FileHandle& fh);
|
||||
|
||||
|
||||
inline bool operator!=(const FileHandle& handle) const;
|
||||
inline bool operator>(const FileHandle& handle) const;
|
||||
inline bool operator<(const FileHandle& handle) const;
|
||||
};
|
||||
@@ -92,6 +94,15 @@ FileHandle::operator=(const FileHandle& fh)
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
FileHandle::operator!=(const FileHandle& handle) const
|
||||
{
|
||||
if (fSize != handle.fSize)
|
||||
return true;
|
||||
return memcmp(fData, handle.fData, fSize) != 0;
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
FileHandle::operator>(const FileHandle& handle) const
|
||||
{
|
||||
|
||||
@@ -262,68 +262,100 @@ Inode::Link(Inode* dir, const char* name)
|
||||
status_t
|
||||
Inode::Remove(const char* name, FileType type)
|
||||
{
|
||||
if (type == NF4NAMEDATTR) {
|
||||
status_t result = LoadAttrDirHandle();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
ChangeInfo changeInfo;
|
||||
uint64 fileID;
|
||||
status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
if (fCache->Lock() == B_OK) {
|
||||
DirectoryCache* cache = type != NF4NAMEDATTR ? fCache : fAttrCache;
|
||||
if (cache->Lock() == B_OK) {
|
||||
if (changeInfo.fAtomic
|
||||
&& fCache->ChangeInfo() == changeInfo.fBefore) {
|
||||
fCache->RemoveEntry(name);
|
||||
fCache->SetChangeInfo(changeInfo.fAfter);
|
||||
} else if (fCache->ChangeInfo() != changeInfo.fBefore)
|
||||
fCache->Trash();
|
||||
fCache->Unlock();
|
||||
cache->RemoveEntry(name);
|
||||
cache->SetChangeInfo(changeInfo.fAfter);
|
||||
} else if (cache->ChangeInfo() != changeInfo.fBefore)
|
||||
cache->Trash();
|
||||
cache->Unlock();
|
||||
}
|
||||
|
||||
fFileSystem->Root()->MakeInfoInvalid();
|
||||
|
||||
notify_entry_removed(fFileSystem->DevId(), ID(), name,
|
||||
FileIdToInoT(fileID));
|
||||
if (type == NF4NAMEDATTR) {
|
||||
notify_attribute_changed(fFileSystem->DevId(), ID(), name,
|
||||
B_ATTR_REMOVED);
|
||||
} else {
|
||||
notify_entry_removed(fFileSystem->DevId(), ID(), name,
|
||||
FileIdToInoT(fileID));
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName)
|
||||
Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName,
|
||||
bool attribute)
|
||||
{
|
||||
if (from->fFileSystem != to->fFileSystem)
|
||||
return B_DONT_DO_THAT;
|
||||
|
||||
if (attribute) {
|
||||
status_t result = from->LoadAttrDirHandle();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
result = to->LoadAttrDirHandle();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
ChangeInfo fromChange, toChange;
|
||||
uint64 fileID;
|
||||
status_t result = NFS4Inode::Rename(from, to, fromName, toName, &fromChange,
|
||||
&toChange, &fileID);
|
||||
&toChange, &fileID, attribute);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
from->fFileSystem->Root()->MakeInfoInvalid();
|
||||
|
||||
if (from->fCache->Lock() == B_OK) {
|
||||
DirectoryCache* cache = attribute ? from->fAttrCache : from->fCache;
|
||||
if (cache->Lock() == B_OK) {
|
||||
if (fromChange.fAtomic
|
||||
&& from->fCache->ChangeInfo() == fromChange.fBefore) {
|
||||
from->fCache->RemoveEntry(fromName);
|
||||
from->fCache->SetChangeInfo(fromChange.fAfter);
|
||||
} else if (from->fCache->ChangeInfo() != fromChange.fBefore)
|
||||
from->fCache->Trash();
|
||||
from->fCache->Unlock();
|
||||
&& cache->ChangeInfo() == fromChange.fBefore) {
|
||||
cache->RemoveEntry(fromName);
|
||||
cache->SetChangeInfo(fromChange.fAfter);
|
||||
} else if (cache->ChangeInfo() != fromChange.fBefore)
|
||||
cache->Trash();
|
||||
cache->Unlock();
|
||||
}
|
||||
|
||||
if (to->fCache->Lock() == B_OK) {
|
||||
cache = attribute ? to->fAttrCache : to->fCache;
|
||||
if (cache->Lock() == B_OK) {
|
||||
if (toChange.fAtomic
|
||||
&& to->fCache->ChangeInfo() == toChange.fBefore) {
|
||||
to->fCache->AddEntry(toName, fileID, true);
|
||||
to->fCache->SetChangeInfo(toChange.fAfter);
|
||||
&& cache->ChangeInfo() == toChange.fBefore) {
|
||||
cache->AddEntry(toName, fileID, true);
|
||||
cache->SetChangeInfo(toChange.fAfter);
|
||||
} else if (to->fCache->ChangeInfo() != toChange.fBefore)
|
||||
to->fCache->Trash();
|
||||
to->fCache->Unlock();
|
||||
cache->Trash();
|
||||
cache->Unlock();
|
||||
}
|
||||
|
||||
notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName,
|
||||
to->ID(), toName, FileIdToInoT(fileID));
|
||||
if (attribute) {
|
||||
notify_attribute_changed(from->fFileSystem->DevId(), from->ID(),
|
||||
fromName, B_ATTR_REMOVED);
|
||||
notify_attribute_changed(to->fFileSystem->DevId(), to->ID(), toName,
|
||||
B_ATTR_CREATED);
|
||||
} else {
|
||||
notify_entry_moved(from->fFileSystem->DevId(), from->ID(), fromName,
|
||||
to->ID(), toName, FileIdToInoT(fileID));
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -404,8 +436,11 @@ Inode::Access(int mode)
|
||||
|
||||
|
||||
status_t
|
||||
Inode::Stat(struct stat* st)
|
||||
Inode::Stat(struct stat* st, OpenAttrCookie* attr)
|
||||
{
|
||||
if (attr != NULL)
|
||||
return GetStat(st, attr);
|
||||
|
||||
status_t result = fMetaCache.GetStat(st);
|
||||
if (result != B_OK) {
|
||||
struct stat temp;
|
||||
@@ -421,11 +456,11 @@ Inode::Stat(struct stat* st)
|
||||
|
||||
|
||||
status_t
|
||||
Inode::GetStat(struct stat* st)
|
||||
Inode::GetStat(struct stat* st, OpenAttrCookie* attr)
|
||||
{
|
||||
AttrValue* values;
|
||||
uint32 count;
|
||||
status_t result = NFS4Inode::GetStat(&values, &count);
|
||||
status_t result = NFS4Inode::GetStat(&values, &count, attr);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
@@ -504,7 +539,7 @@ Inode::GetStat(struct stat* st)
|
||||
|
||||
|
||||
status_t
|
||||
Inode::WriteStat(const struct stat* st, uint32 mask)
|
||||
Inode::WriteStat(const struct stat* st, uint32 mask, OpenAttrCookie* cookie)
|
||||
{
|
||||
status_t result;
|
||||
AttrValue attr[6];
|
||||
@@ -554,15 +589,18 @@ Inode::WriteStat(const struct stat* st, uint32 mask)
|
||||
i++;
|
||||
}
|
||||
|
||||
MutexLocker stateLocker(fStateLock);
|
||||
result = NFS4Inode::WriteStat(fOpenState, attr, i);
|
||||
stateLocker.Unlock();
|
||||
if (cookie == NULL) {
|
||||
MutexLocker stateLocker(fStateLock);
|
||||
result = NFS4Inode::WriteStat(fOpenState, attr, i);
|
||||
stateLocker.Unlock();
|
||||
|
||||
fMetaCache.InvalidateStat();
|
||||
if ((mask & B_STAT_MODE) != 0 || (mask & B_STAT_UID) != 0
|
||||
|| (mask & B_STAT_GID) != 0) {
|
||||
fMetaCache.InvalidateAccess();
|
||||
}
|
||||
fMetaCache.InvalidateStat();
|
||||
if ((mask & B_STAT_MODE) != 0 || (mask & B_STAT_UID) != 0
|
||||
|| (mask & B_STAT_GID) != 0) {
|
||||
fMetaCache.InvalidateAccess();
|
||||
}
|
||||
} else
|
||||
result = NFS4Inode::WriteStat(cookie->fOpenState, attr, i);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -57,24 +57,33 @@ public:
|
||||
status_t Link(Inode* dir, const char* name);
|
||||
status_t Remove(const char* name, FileType type);
|
||||
static status_t Rename(Inode* from, Inode* to,
|
||||
const char* fromName, const char* toName);
|
||||
const char* fromName, const char* toName,
|
||||
bool attribute = false);
|
||||
|
||||
status_t Stat(struct stat* st);
|
||||
status_t WriteStat(const struct stat* st, uint32 mask);
|
||||
status_t Stat(struct stat* st,
|
||||
OpenAttrCookie* attr = NULL);
|
||||
status_t WriteStat(const struct stat* st, uint32 mask,
|
||||
OpenAttrCookie* attr = NULL);
|
||||
|
||||
status_t Create(const char* name, int mode, int perms,
|
||||
OpenFileCookie* cookie,
|
||||
OpenDelegationData* data, ino_t* id);
|
||||
status_t Open(int mode, OpenFileCookie* cookie);
|
||||
status_t Close(OpenFileCookie* cookie);
|
||||
|
||||
status_t OpenAttr(const char* name, int mode,
|
||||
OpenAttrCookie* cookie, bool create,
|
||||
int32 type = 0);
|
||||
status_t CloseAttr(OpenAttrCookie* cookie);
|
||||
|
||||
status_t Read(OpenFileCookie* cookie, off_t pos,
|
||||
void* buffer, size_t* length);
|
||||
status_t Write(OpenFileCookie* cookie, off_t pos,
|
||||
const void* buffer, size_t *_length);
|
||||
|
||||
status_t ReadDirect(OpenFileCookie* cookie, off_t pos,
|
||||
status_t ReadDirect(OpenStateCookie* cookie, off_t pos,
|
||||
void* buffer, size_t* length, bool* eof);
|
||||
status_t WriteDirect(OpenFileCookie* cookie, off_t pos,
|
||||
status_t WriteDirect(OpenStateCookie* cookie, off_t pos,
|
||||
const void* buffer, size_t *_length);
|
||||
|
||||
status_t CreateDir(const char* name, int mode);
|
||||
@@ -96,6 +105,8 @@ public:
|
||||
_snapshot, OpenDirCookie* cookie,
|
||||
uint64* _change, bool attribute);
|
||||
|
||||
status_t LoadAttrDirHandle();
|
||||
|
||||
protected:
|
||||
Inode();
|
||||
|
||||
@@ -115,7 +126,8 @@ protected:
|
||||
status_t ChildAdded(const char* name, uint64 fileID,
|
||||
const FileHandle& fileHandle);
|
||||
|
||||
status_t GetStat(struct stat* st);
|
||||
status_t GetStat(struct stat* st,
|
||||
OpenAttrCookie* attr = NULL);
|
||||
|
||||
static inline status_t CheckLockType(short ltype, uint32 mode);
|
||||
|
||||
|
||||
@@ -55,6 +55,13 @@ Inode::OpenAttrDir(OpenDirCookie* cookie)
|
||||
cookie->fEOF = false;
|
||||
cookie->fAttrDir = true;
|
||||
|
||||
return LoadAttrDirHandle();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::LoadAttrDirHandle()
|
||||
{
|
||||
if (fInfo.fAttrDir.fSize == 0) {
|
||||
FileHandle handle;
|
||||
|
||||
@@ -65,7 +72,7 @@ Inode::OpenAttrDir(OpenDirCookie* cookie)
|
||||
fInfo.fAttrDir = handle;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -193,7 +193,72 @@ Inode::Close(OpenFileCookie* cookie)
|
||||
|
||||
|
||||
status_t
|
||||
Inode::ReadDirect(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length,
|
||||
Inode::OpenAttr(const char* name, int mode, OpenAttrCookie* cookie, bool create,
|
||||
int32 type)
|
||||
{
|
||||
(void)type;
|
||||
|
||||
status_t result = LoadAttrDirHandle();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
OpenDelegationData data;
|
||||
data.fType = OPEN_DELEGATE_NONE;
|
||||
|
||||
OpenState* state = new OpenState;
|
||||
if (state == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
state->fInfo.fName = name;
|
||||
state->fInfo.fParent = fInfo.fAttrDir;
|
||||
result = NFS4Inode::OpenAttr(state, name, mode, &data, create);
|
||||
if (result != B_OK) {
|
||||
delete state;
|
||||
return result;
|
||||
}
|
||||
|
||||
fFileSystem->AddOpenFile(state);
|
||||
|
||||
cookie->fOpenState = state;
|
||||
cookie->fFileSystem = fFileSystem;
|
||||
cookie->fMode = mode;
|
||||
|
||||
if (data.fType != OPEN_DELEGATE_NONE) {
|
||||
Delegation* delegation
|
||||
= new(std::nothrow) Delegation(data, this, fOpenState->fClientID,
|
||||
true);
|
||||
if (delegation != NULL) {
|
||||
delegation->fInfo = state->fInfo;
|
||||
delegation->fFileSystem = fFileSystem;
|
||||
state->fDelegation = delegation;
|
||||
fFileSystem->AddDelegation(delegation);
|
||||
}
|
||||
}
|
||||
|
||||
if ((mode & O_TRUNC) == O_TRUNC) {
|
||||
struct stat st;
|
||||
st.st_size = 0;
|
||||
WriteStat(&st, B_STAT_SIZE, cookie);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::CloseAttr(OpenAttrCookie* cookie)
|
||||
{
|
||||
cookie->fOpenState->fDelegation->GiveUp();
|
||||
fFileSystem->RemoveDelegation(cookie->fOpenState->fDelegation);
|
||||
delete cookie->fOpenState->fDelegation;
|
||||
delete cookie->fOpenState;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::ReadDirect(OpenStateCookie* cookie, off_t pos, void* buffer, size_t* _length,
|
||||
bool* eof)
|
||||
{
|
||||
*eof = false;
|
||||
@@ -203,9 +268,10 @@ Inode::ReadDirect(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _leng
|
||||
*_length = min_c(ioSize, *_length);
|
||||
|
||||
status_t result;
|
||||
OpenState* state = cookie != NULL ? cookie->fOpenState : fOpenState;
|
||||
while (size < *_length && !*eof) {
|
||||
uint32 len = *_length - size;
|
||||
result = ReadFile(cookie, fOpenState, pos + size, &len,
|
||||
result = ReadFile(cookie, state, pos + size, &len,
|
||||
reinterpret_cast<char*>(buffer) + size, eof);
|
||||
if (result != B_OK) {
|
||||
if (size == 0)
|
||||
@@ -234,7 +300,7 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
|
||||
|
||||
|
||||
status_t
|
||||
Inode::WriteDirect(OpenFileCookie* cookie, off_t pos, const void* _buffer,
|
||||
Inode::WriteDirect(OpenStateCookie* cookie, off_t pos, const void* _buffer,
|
||||
size_t *_length)
|
||||
{
|
||||
uint32 size = 0;
|
||||
@@ -243,12 +309,20 @@ Inode::WriteDirect(OpenFileCookie* cookie, off_t pos, const void* _buffer,
|
||||
uint32 ioSize = fFileSystem->Root()->IOSize();
|
||||
*_length = min_c(ioSize, *_length);
|
||||
|
||||
fWriteDirty = true;
|
||||
bool attribute = false;
|
||||
OpenState* state = fOpenState;
|
||||
if (cookie != NULL) {
|
||||
attribute = cookie->fOpenState->fInfo.fHandle != fInfo.fHandle;
|
||||
state = cookie->fOpenState;
|
||||
}
|
||||
|
||||
if (!attribute)
|
||||
fWriteDirty = true;
|
||||
|
||||
while (size < *_length) {
|
||||
uint32 len = *_length - size;
|
||||
status_t result = WriteFile(cookie, fOpenState, pos + size, &len,
|
||||
buffer + size);
|
||||
status_t result = WriteFile(cookie, state, pos + size,
|
||||
&len, buffer + size, attribute);
|
||||
if (result != B_OK) {
|
||||
if (size == 0)
|
||||
return result;
|
||||
|
||||
@@ -83,7 +83,10 @@ MetadataCache::GetAccess(uid_t uid, uint32* allowed)
|
||||
if (!it.HasCurrent())
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
if (it.Current().fExpire < time(NULL)) {
|
||||
if (!fForceValid)
|
||||
it.Current().fForceValid = false;
|
||||
|
||||
if (!it.Current().fForceValid && it.Current().fExpire < time(NULL)) {
|
||||
it.Remove();
|
||||
return B_ERROR;
|
||||
}
|
||||
@@ -105,6 +108,7 @@ MetadataCache::SetAccess(uid_t uid, uint32 allowed)
|
||||
AccessEntry entry;
|
||||
entry.fAllowed = allowed;
|
||||
entry.fExpire = time(NULL) + kExpirationTime;
|
||||
entry.fForceValid = fForceValid;
|
||||
fAccessCache.Insert(uid, entry);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ class Inode;
|
||||
|
||||
struct AccessEntry {
|
||||
time_t fExpire;
|
||||
bool fForceValid;
|
||||
|
||||
uint32 fAllowed;
|
||||
};
|
||||
|
||||
|
||||
@@ -245,14 +245,17 @@ NFS4Inode::ReadLink(void* buffer, size_t* length)
|
||||
|
||||
|
||||
status_t
|
||||
NFS4Inode::GetStat(AttrValue** values, uint32* count)
|
||||
NFS4Inode::GetStat(AttrValue** values, uint32* count, OpenAttrCookie* cookie)
|
||||
{
|
||||
do {
|
||||
RPC::Server* serv = fFileSystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fInfo.fHandle);
|
||||
if (cookie != NULL)
|
||||
req.PutFH(cookie->fOpenState->fInfo.fHandle);
|
||||
else
|
||||
req.PutFH(fInfo.fHandle);
|
||||
|
||||
Attribute attr[] = { FATTR4_SIZE, FATTR4_MODE, FATTR4_NUMLINKS,
|
||||
FATTR4_OWNER, FATTR4_OWNER_GROUP,
|
||||
@@ -260,7 +263,7 @@ NFS4Inode::GetStat(AttrValue** values, uint32* count)
|
||||
FATTR4_TIME_METADATA, FATTR4_TIME_MODIFY };
|
||||
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
||||
|
||||
status_t result = request.Send();
|
||||
status_t result = request.Send(cookie);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
@@ -284,7 +287,7 @@ NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount)
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fInfo.fHandle);
|
||||
req.PutFH(state->fInfo.fHandle);
|
||||
if (state != NULL)
|
||||
req.SetAttr(state->fStateID, state->fStateSeq, attrs, attrCount);
|
||||
else
|
||||
@@ -313,21 +316,29 @@ NFS4Inode::WriteStat(OpenState* state, AttrValue* attrs, uint32 attrCount)
|
||||
status_t
|
||||
NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName,
|
||||
const char* toName, ChangeInfo* fromChange, ChangeInfo* toChange,
|
||||
uint64* fileID)
|
||||
uint64* fileID, bool attribute)
|
||||
{
|
||||
do {
|
||||
RPC::Server* serv = from->fFileSystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(from->fInfo.fHandle);
|
||||
if (attribute)
|
||||
req.PutFH(from->fInfo.fAttrDir);
|
||||
else
|
||||
req.PutFH(from->fInfo.fHandle);
|
||||
req.SaveFH();
|
||||
req.PutFH(to->fInfo.fHandle);
|
||||
if (attribute)
|
||||
req.PutFH(to->fInfo.fAttrDir);
|
||||
else
|
||||
req.PutFH(to->fInfo.fHandle);
|
||||
req.Rename(fromName, toName);
|
||||
|
||||
Attribute attr[] = { FATTR4_FILEID };
|
||||
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
||||
req.LookUp(toName);
|
||||
if (!attribute) {
|
||||
req.LookUp(toName);
|
||||
Attribute attr[] = { FATTR4_FILEID };
|
||||
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
|
||||
}
|
||||
|
||||
status_t result = request.Send();
|
||||
if (result != B_OK)
|
||||
@@ -358,22 +369,24 @@ NFS4Inode::Rename(Inode* from, Inode* to, const char* fromName,
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
result = reply.LookUp();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
if (!attribute) {
|
||||
result = reply.LookUp();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
AttrValue* values;
|
||||
uint32 count;
|
||||
result = reply.GetAttr(&values, &count);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
AttrValue* values;
|
||||
uint32 count;
|
||||
result = reply.GetAttr(&values, &count);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
if (count == 0)
|
||||
*fileID = from->fFileSystem->AllocFileId();
|
||||
else
|
||||
*fileID = values[0].fData.fValue64;
|
||||
if (count == 0)
|
||||
*fileID = from->fFileSystem->AllocFileId();
|
||||
else
|
||||
*fileID = values[0].fData.fValue64;
|
||||
|
||||
delete[] values;
|
||||
delete[] values;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
} while (true);
|
||||
@@ -581,7 +594,61 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
|
||||
|
||||
|
||||
status_t
|
||||
NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position,
|
||||
NFS4Inode::OpenAttr(OpenState* state, const char* name, int mode,
|
||||
OpenDelegationData* delegation, bool create)
|
||||
{
|
||||
bool confirm;
|
||||
status_t result;
|
||||
uint32 sequence = fFileSystem->OpenOwnerSequenceLock();
|
||||
do {
|
||||
state->fClientID = fFileSystem->NFSServer()->ClientId();
|
||||
|
||||
RPC::Server* serv = fFileSystem->Server();
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fInfo.fAttrDir);
|
||||
req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID,
|
||||
create ? OPEN4_CREATE : OPEN4_NOCREATE, fFileSystem->OpenOwner(),
|
||||
name);
|
||||
req.GetFH();
|
||||
|
||||
result = request.Send();
|
||||
if (result != B_OK) {
|
||||
fFileSystem->OpenOwnerSequenceUnlock(false);
|
||||
return result;
|
||||
}
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
if (HandleErrors(reply.NFS4Error(), serv, NULL, state))
|
||||
continue;
|
||||
|
||||
fFileSystem->OpenOwnerSequenceUnlock();
|
||||
|
||||
reply.PutFH();
|
||||
result = reply.Open(state->fStateID, &state->fStateSeq, &confirm,
|
||||
delegation);
|
||||
|
||||
reply.GetFH(&state->fInfo.fHandle);
|
||||
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
state->fOpened = true;
|
||||
|
||||
if (confirm)
|
||||
return ConfirmOpen(fInfo.fHandle, state);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
NFS4Inode::ReadFile(OpenStateCookie* cookie, OpenState* state, uint64 position,
|
||||
uint32* length, void* buffer, bool* eof)
|
||||
{
|
||||
do {
|
||||
@@ -589,7 +656,7 @@ NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position,
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fInfo.fHandle);
|
||||
req.PutFH(state->fInfo.fHandle);
|
||||
req.Read(state->fStateID, state->fStateSeq, position, *length);
|
||||
|
||||
status_t result = request.Send(cookie);
|
||||
@@ -612,8 +679,8 @@ NFS4Inode::ReadFile(OpenFileCookie* cookie, OpenState* state, uint64 position,
|
||||
|
||||
|
||||
status_t
|
||||
NFS4Inode::WriteFile(OpenFileCookie* cookie, OpenState* state, uint64 position,
|
||||
uint32* length, const void* buffer)
|
||||
NFS4Inode::WriteFile(OpenStateCookie* cookie, OpenState* state, uint64 position,
|
||||
uint32* length, const void* buffer, bool commit)
|
||||
{
|
||||
|
||||
do {
|
||||
@@ -621,9 +688,10 @@ NFS4Inode::WriteFile(OpenFileCookie* cookie, OpenState* state, uint64 position,
|
||||
Request request(serv);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutFH(fInfo.fHandle);
|
||||
req.PutFH(state->fInfo.fHandle);
|
||||
|
||||
req.Write(state->fStateID, state->fStateSeq, buffer, position, *length);
|
||||
req.Write(state->fStateID, state->fStateSeq, buffer, position, *length,
|
||||
commit);
|
||||
|
||||
status_t result = request.Send(cookie);
|
||||
if (result != B_OK)
|
||||
@@ -757,8 +825,10 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo,
|
||||
|
||||
req.PutFH(fInfo.fHandle);
|
||||
|
||||
Attribute idAttr[] = { FATTR4_FILEID };
|
||||
req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute));
|
||||
if (type != NF4NAMEDATTR) {
|
||||
Attribute idAttr[] = { FATTR4_FILEID };
|
||||
req.GetAttr(idAttr, sizeof(idAttr) / sizeof(Attribute));
|
||||
}
|
||||
|
||||
req.Remove(name);
|
||||
|
||||
@@ -790,17 +860,19 @@ NFS4Inode::RemoveObject(const char* name, FileType type, ChangeInfo* changeInfo,
|
||||
|
||||
reply.PutFH();
|
||||
|
||||
AttrValue* values;
|
||||
uint32 count;
|
||||
result = reply.GetAttr(&values, &count);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
if (type != NF4NAMEDATTR) {
|
||||
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;
|
||||
delete[] values;
|
||||
if (count == 0)
|
||||
*fileID = fFileSystem->AllocFileId();
|
||||
else
|
||||
*fileID = values[0].fData.fValue64;
|
||||
delete[] values;
|
||||
}
|
||||
|
||||
return reply.Remove(&changeInfo->fBefore, &changeInfo->fAfter,
|
||||
changeInfo->fAtomic);
|
||||
|
||||
@@ -38,9 +38,11 @@ protected:
|
||||
|
||||
static status_t Rename(Inode* from, Inode* to, const char* fromName,
|
||||
const char* toName, ChangeInfo* fromChange,
|
||||
ChangeInfo* toChange, uint64* fileID);
|
||||
ChangeInfo* toChange, uint64* fileID,
|
||||
bool attribute = false);
|
||||
|
||||
status_t GetStat(AttrValue** values, uint32* count);
|
||||
status_t GetStat(AttrValue** values, uint32* count,
|
||||
OpenAttrCookie* attr = NULL);
|
||||
status_t WriteStat(OpenState* state, AttrValue* attrs,
|
||||
uint32 attrCount);
|
||||
|
||||
@@ -51,12 +53,15 @@ protected:
|
||||
status_t OpenFile(OpenState* state, int mode,
|
||||
OpenDelegationData* delegation);
|
||||
|
||||
status_t ReadFile(OpenFileCookie* cookie, OpenState* state,
|
||||
status_t OpenAttr(OpenState* state, const char* name, int mode,
|
||||
OpenDelegationData* delegation, bool create);
|
||||
|
||||
status_t ReadFile(OpenStateCookie* cookie, OpenState* state,
|
||||
uint64 position, uint32* length, void* buffer,
|
||||
bool* eof);
|
||||
status_t WriteFile(OpenFileCookie* cookie, OpenState* state,
|
||||
status_t WriteFile(OpenStateCookie* cookie, OpenState* state,
|
||||
uint64 position, uint32* length,
|
||||
const void* buffer);
|
||||
const void* buffer, bool commit = false);
|
||||
|
||||
status_t CreateObject(const char* name, const char* path,
|
||||
int mode, FileType type, ChangeInfo* changeInfo,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
bool
|
||||
NFS4Object::HandleErrors(uint32 nfs4Error, RPC::Server* serv,
|
||||
OpenFileCookie* cookie, OpenState* state)
|
||||
OpenStateCookie* cookie, OpenState* state)
|
||||
{
|
||||
uint32 leaseTime;
|
||||
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
#include "RPCServer.h"
|
||||
|
||||
|
||||
class OpenFileCookie;
|
||||
class OpenStateCookie;
|
||||
class OpenState;
|
||||
|
||||
class NFS4Object {
|
||||
public:
|
||||
bool HandleErrors(uint32 nfs4Error, RPC::Server* serv,
|
||||
OpenFileCookie* cookie = NULL, OpenState* state = NULL);
|
||||
OpenStateCookie* cookie = NULL, OpenState* state = NULL);
|
||||
|
||||
status_t ConfirmOpen(const FileHandle& fileHandle, OpenState* state);
|
||||
|
||||
|
||||
@@ -788,7 +788,7 @@ RequestBuilder::Verify(AttrValue* attr, uint32 count)
|
||||
|
||||
status_t
|
||||
RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer,
|
||||
uint64 pos, uint32 len)
|
||||
uint64 pos, uint32 len, bool stable)
|
||||
{
|
||||
if (fProcedure != ProcCompound)
|
||||
return B_BAD_VALUE;
|
||||
@@ -801,7 +801,7 @@ RequestBuilder::Write(const uint32* id, uint32 stateSeq, const void* buffer,
|
||||
fRequest->Stream().AddUInt(id[1]);
|
||||
fRequest->Stream().AddUInt(id[2]);
|
||||
fRequest->Stream().AddUHyper(pos);
|
||||
fRequest->Stream().AddInt(UNSTABLE4);
|
||||
fRequest->Stream().AddInt(stable ? FILE_SYNC4 : UNSTABLE4);
|
||||
fRequest->Stream().AddOpaque(buffer, len);
|
||||
|
||||
fOpCount++;
|
||||
@@ -862,6 +862,12 @@ void
|
||||
RequestBuilder::_EncodeAttrs(XDR::WriteStream& stream, AttrValue* attr,
|
||||
uint32 count)
|
||||
{
|
||||
if (count == 0) {
|
||||
stream.AddUInt(0);
|
||||
stream.AddOpaque(NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
Attribute* attrs =
|
||||
reinterpret_cast<Attribute*>(malloc(sizeof(Attribute) * count));
|
||||
for (uint32 i = 0; i < count; i++)
|
||||
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
status_t Verify(AttrValue* attr, uint32 count);
|
||||
status_t Write(const uint32* id, uint32 stateSeq,
|
||||
const void* buffer, uint64 pos,
|
||||
uint32 len);
|
||||
uint32 len, bool stable = false);
|
||||
status_t ReleaseLockOwner(OpenState* state,
|
||||
LockOwner* owner);
|
||||
|
||||
|
||||
@@ -636,7 +636,7 @@ nfs4_open_attr_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie)
|
||||
static status_t
|
||||
nfs4_close_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie)
|
||||
{
|
||||
return nfs4_close_attr_dir(volume, vnode, cookie);
|
||||
return nfs4_close_dir(volume, vnode, cookie);
|
||||
}
|
||||
|
||||
|
||||
@@ -658,7 +658,125 @@ nfs4_read_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie,
|
||||
static status_t
|
||||
nfs4_rewind_attr_dir(fs_volume* volume, fs_vnode* vnode, void* cookie)
|
||||
{
|
||||
return nfs4_rewind_attr_dir(volume, vnode, cookie);
|
||||
return nfs4_rewind_dir(volume, vnode, cookie);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_create_attr(fs_volume* volume, fs_vnode* vnode, const char* name,
|
||||
uint32 type, int openMode, void** _cookie)
|
||||
{
|
||||
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
|
||||
|
||||
OpenAttrCookie* cookie = new OpenAttrCookie;
|
||||
if (cookie == NULL)
|
||||
return B_NO_MEMORY;
|
||||
*_cookie = cookie;
|
||||
|
||||
status_t result = inode->OpenAttr(name, openMode, cookie, true, type);
|
||||
if (result != B_OK)
|
||||
delete cookie;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_open_attr(fs_volume* volume, fs_vnode* vnode, const char* name,
|
||||
int openMode, void** _cookie)
|
||||
{
|
||||
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
|
||||
|
||||
OpenAttrCookie* cookie = new OpenAttrCookie;
|
||||
if (cookie == NULL)
|
||||
return B_NO_MEMORY;
|
||||
*_cookie = cookie;
|
||||
|
||||
status_t result = inode->OpenAttr(name, openMode, cookie, false);
|
||||
if (result != B_OK)
|
||||
delete cookie;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_close_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie)
|
||||
{
|
||||
Cookie* cookie = reinterpret_cast<Cookie*>(_cookie);
|
||||
return cookie->CancelAll();
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_free_attr_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie)
|
||||
{
|
||||
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
|
||||
|
||||
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
|
||||
inode->CloseAttr(cookie);
|
||||
delete cookie;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_read_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
|
||||
void* buffer, size_t* length)
|
||||
{
|
||||
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
|
||||
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
|
||||
bool eof;
|
||||
return inode->ReadDirect(cookie, pos, buffer, length, &eof);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_write_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
|
||||
const void* buffer, size_t* length)
|
||||
{
|
||||
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
|
||||
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
|
||||
return inode->WriteDirect(cookie, pos, buffer, length);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_read_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie,
|
||||
struct stat* stat)
|
||||
{
|
||||
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
|
||||
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
|
||||
return inode->Stat(stat, cookie);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_write_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie,
|
||||
const struct stat* stat, int statMask)
|
||||
{
|
||||
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
|
||||
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
|
||||
return inode->WriteStat(stat, statMask, cookie);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_rename_attr(fs_volume* volume, fs_vnode* fromVnode, const char* fromName,
|
||||
fs_vnode* toVnode, const char* toName)
|
||||
{
|
||||
Inode* fromInode = reinterpret_cast<Inode*>(fromVnode->private_node);
|
||||
Inode* toInode = reinterpret_cast<Inode*>(toVnode->private_node);
|
||||
return Inode::Rename(fromInode, toInode, fromName, toName, true);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_remove_attr(fs_volume* volume, fs_vnode* vnode, const char* name)
|
||||
{
|
||||
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
|
||||
return inode->Remove(name, NF4NAMEDATTR);
|
||||
}
|
||||
|
||||
|
||||
@@ -832,17 +950,17 @@ fs_vnode_ops gNFSv4VnodeOps = {
|
||||
nfs4_rewind_attr_dir,
|
||||
|
||||
/* attribute operations */
|
||||
NULL, // create_attr
|
||||
NULL, // open_attr
|
||||
NULL, // close_attr
|
||||
NULL, // free_attr_cookie
|
||||
NULL, // read_attr
|
||||
NULL, // write_attr
|
||||
nfs4_create_attr,
|
||||
nfs4_open_attr,
|
||||
nfs4_close_attr,
|
||||
nfs4_free_attr_cookie,
|
||||
nfs4_read_attr,
|
||||
nfs4_write_attr,
|
||||
|
||||
NULL, // read_attr_stat
|
||||
NULL, // write_attr_stat
|
||||
NULL, // rename_attr
|
||||
NULL, // remove_attr
|
||||
nfs4_read_attr_stat,
|
||||
nfs4_write_attr_stat,
|
||||
nfs4_rename_attr,
|
||||
nfs4_remove_attr,
|
||||
|
||||
/* support for node and FS layers */
|
||||
NULL, // create_special_node
|
||||
|
||||
Reference in New Issue
Block a user