nfs4: support hard links properly
The main purpose of this patch is to prevent VFS from removing a vnode to early what might have happened if the NFS client knew it had more than one name but then one of them was deleted. Moreover, all discovered and still valid names are stored what may be useful in proper file handle recovery when they are volatile. This patch fixes both #9558 and #9561.
This commit is contained in:
parent
efc29cc57a
commit
469f13fdfe
@ -308,19 +308,6 @@ DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot,
|
||||
} else {
|
||||
notify_entry_created(fInode->GetFileSystem()->DevId(),
|
||||
fInode->ID(), newCurrent->fName, newCurrent->fNode);
|
||||
|
||||
do {
|
||||
FileInfo fi;
|
||||
fi.fFileId = newCurrent->fNode;
|
||||
fi.fParent = fInode->fInfo.fHandle;
|
||||
status_t result = fi.CreateName(fInode->fInfo.fPath,
|
||||
newCurrent->fName);
|
||||
if (result != B_OK)
|
||||
break;
|
||||
|
||||
fInode->GetFileSystem()->InoIdMap()->AddEntry(fi,
|
||||
Inode::FileIdToInoT(newCurrent->fNode), true);
|
||||
} while (false);
|
||||
}
|
||||
} else
|
||||
oldSnapshot->fEntries.Remove(prev, oldCurrent);
|
||||
|
@ -13,80 +13,122 @@
|
||||
#include "Request.h"
|
||||
|
||||
|
||||
status_t
|
||||
FileInfo::ParsePath(RequestBuilder& req, uint32& count, const char* _path,
|
||||
bool getFileHandle)
|
||||
InodeName::InodeName(InodeNames* parent, const char* name)
|
||||
:
|
||||
fParent(parent),
|
||||
fName(strdup(name))
|
||||
{
|
||||
ASSERT(_path != NULL);
|
||||
if (fParent != NULL)
|
||||
fParent->AcquireReference();
|
||||
}
|
||||
|
||||
char* path = strdup(_path);
|
||||
if (path == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
char* pathStart = path;
|
||||
char* pathEnd;
|
||||
InodeName::~InodeName()
|
||||
{
|
||||
if (fParent != NULL)
|
||||
fParent->ReleaseReference();
|
||||
free(const_cast<char*>(fName));
|
||||
}
|
||||
|
||||
while (pathStart != NULL) {
|
||||
pathEnd = strchr(pathStart, '/');
|
||||
if (pathEnd != NULL)
|
||||
*pathEnd = '\0';
|
||||
|
||||
if (pathEnd != pathStart) {
|
||||
if (!strcmp(pathStart, "..")) {
|
||||
req.LookUpUp();
|
||||
count++;
|
||||
} else if (strcmp(pathStart, ".")) {
|
||||
req.LookUp(pathStart);
|
||||
if (getFileHandle)
|
||||
req.GetFH();
|
||||
count++;
|
||||
}
|
||||
}
|
||||
InodeNames::InodeNames()
|
||||
{
|
||||
mutex_init(&fLock, NULL);
|
||||
}
|
||||
|
||||
if (pathEnd != NULL && pathEnd[1] != '\0')
|
||||
pathStart = pathEnd + 1;
|
||||
else
|
||||
pathStart = NULL;
|
||||
}
|
||||
free(path);
|
||||
|
||||
return B_OK;
|
||||
InodeNames::~InodeNames()
|
||||
{
|
||||
while (!fNames.IsEmpty())
|
||||
delete fNames.RemoveHead();
|
||||
mutex_destroy(&fLock);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FileInfo::CreateName(const char* dirPath, const char* name)
|
||||
InodeNames::AddName(InodeNames* parent, const char* name)
|
||||
{
|
||||
ASSERT(name != NULL);
|
||||
MutexLocker _(fLock);
|
||||
|
||||
free(const_cast<char*>(fName));
|
||||
fName = strdup(name);
|
||||
if (fName == NULL)
|
||||
InodeName* current = fNames.Head();
|
||||
while (current != NULL) {
|
||||
if (current->fParent == parent && !strcmp(current->fName, name))
|
||||
return B_OK;
|
||||
current = fNames.GetNext(current);
|
||||
}
|
||||
|
||||
InodeName* newName = new InodeName(parent, name);
|
||||
if (newName == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
free(const_cast<char*>(fPath));
|
||||
fPath = NULL;
|
||||
if (dirPath != NULL) {
|
||||
char* path = reinterpret_cast<char*>(malloc(strlen(name) + 2
|
||||
+ strlen(dirPath)));
|
||||
if (path == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
strcpy(path, dirPath);
|
||||
strcat(path, "/");
|
||||
strcat(path, name);
|
||||
|
||||
fPath = path;
|
||||
} else
|
||||
fPath = strdup(name);
|
||||
|
||||
if (fPath == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fNames.Add(newName);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
InodeNames::RemoveName(InodeNames* parent, const char* name)
|
||||
{
|
||||
MutexLocker _(fLock);
|
||||
|
||||
InodeName* previous = NULL;
|
||||
InodeName* current = fNames.Head();
|
||||
while (current != NULL) {
|
||||
if (current->fParent == parent && !strcmp(current->fName, name)) {
|
||||
fNames.Remove(previous, current);
|
||||
delete current;
|
||||
break;
|
||||
}
|
||||
|
||||
previous = current;
|
||||
current = fNames.GetNext(current);
|
||||
}
|
||||
|
||||
return fNames.IsEmpty();
|
||||
}
|
||||
|
||||
|
||||
FileInfo::FileInfo()
|
||||
:
|
||||
fFileId(0),
|
||||
fNames(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
FileInfo::~FileInfo()
|
||||
{
|
||||
if (fNames != NULL)
|
||||
fNames->ReleaseReference();
|
||||
}
|
||||
|
||||
|
||||
FileInfo::FileInfo(const FileInfo& fi)
|
||||
:
|
||||
fFileId(fi.fFileId),
|
||||
fHandle(fi.fHandle),
|
||||
fNames(fi.fNames)
|
||||
{
|
||||
if (fNames != NULL)
|
||||
fNames->AcquireReference();
|
||||
}
|
||||
|
||||
|
||||
FileInfo&
|
||||
FileInfo::operator=(const FileInfo& fi)
|
||||
{
|
||||
fFileId = fi.fFileId;
|
||||
fHandle = fi.fHandle;
|
||||
|
||||
if (fNames != NULL)
|
||||
fNames->ReleaseReference();
|
||||
fNames = fi.fNames;
|
||||
if (fNames != NULL)
|
||||
fNames->AcquireReference();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FileInfo::UpdateFileHandles(FileSystem* fs)
|
||||
{
|
||||
@ -96,16 +138,41 @@ FileInfo::UpdateFileHandles(FileSystem* fs)
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
req.PutRootFH();
|
||||
req.GetFH();
|
||||
|
||||
uint32 lookupCount = 0;
|
||||
status_t result = ParsePath(req, lookupCount, fs->Path(), true);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
const char** path = fs->Path();
|
||||
if (path != NULL) {
|
||||
for (; path[lookupCount] != NULL; lookupCount++)
|
||||
req.LookUp(path[lookupCount]);
|
||||
}
|
||||
|
||||
result = ParsePath(req, lookupCount, fPath, true);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
uint32 i;
|
||||
InodeNames* names = fNames;
|
||||
for (i = 0; names != NULL; i++)
|
||||
names = names->fNames.Head()->fParent;
|
||||
|
||||
if (i > 0) {
|
||||
names = fNames;
|
||||
InodeNames** pathNames = new InodeNames*[i];
|
||||
if (pathNames == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
for (i = 0; names != NULL; i++) {
|
||||
pathNames[i] = names;
|
||||
names = names->fNames.Head()->fParent;
|
||||
}
|
||||
|
||||
for (; i > 0; i--) {
|
||||
if (!strcmp(pathNames[i - 1]->fNames.Head()->fName, ""))
|
||||
continue;
|
||||
|
||||
req.LookUp(pathNames[i - 1]->fNames.Head()->fName);
|
||||
lookupCount++;
|
||||
}
|
||||
delete[] pathNames;
|
||||
}
|
||||
|
||||
req.GetFH();
|
||||
|
||||
if (fs->IsAttrSupported(FATTR4_FILEID)) {
|
||||
AttrValue attr;
|
||||
@ -115,25 +182,20 @@ FileInfo::UpdateFileHandles(FileSystem* fs)
|
||||
req.Verify(&attr, 1);
|
||||
}
|
||||
|
||||
result = request.Send();
|
||||
status_t result = request.Send();
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
ReplyInterpreter& reply = request.Reply();
|
||||
|
||||
FileHandle parent;
|
||||
FileHandle child;
|
||||
|
||||
reply.PutRootFH();
|
||||
reply.GetFH(&child);
|
||||
parent = child;
|
||||
for (uint32 i = 0; i < lookupCount; i++) {
|
||||
for (uint32 i = 0; i < lookupCount; i++)
|
||||
reply.LookUp();
|
||||
parent = child;
|
||||
result = reply.GetFH(&child);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
FileHandle handle;
|
||||
result = reply.GetFH(&handle);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
if (fs->IsAttrSupported(FATTR4_FILEID)) {
|
||||
result = reply.Verify();
|
||||
@ -141,8 +203,8 @@ FileInfo::UpdateFileHandles(FileSystem* fs)
|
||||
return result;
|
||||
}
|
||||
|
||||
fHandle = child;
|
||||
fParent = parent;
|
||||
fHandle = handle;
|
||||
fNames->fHandle = handle;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -12,7 +12,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <lock.h>
|
||||
#include <SupportDefs.h>
|
||||
#include <util/KernelReferenceable.h>
|
||||
|
||||
|
||||
#define NFS4_FHSIZE 128
|
||||
@ -26,11 +28,34 @@ struct FileHandle {
|
||||
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;
|
||||
inline bool operator<(const FileHandle& handle) const;
|
||||
};
|
||||
|
||||
class InodeNames;
|
||||
|
||||
struct InodeName : public SinglyLinkedListLinkImpl<InodeName> {
|
||||
InodeName(InodeNames* parent, const char* name);
|
||||
~InodeName();
|
||||
|
||||
InodeNames* fParent;
|
||||
const char* fName;
|
||||
};
|
||||
|
||||
struct InodeNames : public KernelReferenceable {
|
||||
InodeNames();
|
||||
~InodeNames();
|
||||
|
||||
status_t AddName(InodeNames* parent, const char* name);
|
||||
bool RemoveName(InodeNames* parent,
|
||||
const char* name);
|
||||
|
||||
mutex fLock;
|
||||
SinglyLinkedList<InodeName> fNames;
|
||||
FileHandle fHandle;
|
||||
};
|
||||
|
||||
class FileSystem;
|
||||
class RequestBuilder;
|
||||
@ -42,23 +67,16 @@ struct FileInfo {
|
||||
uint64 fFileId;
|
||||
FileHandle fHandle;
|
||||
|
||||
FileHandle fParent;
|
||||
const char* fName;
|
||||
const char* fPath;
|
||||
InodeNames* fNames;
|
||||
|
||||
FileHandle fAttrDir;
|
||||
|
||||
inline FileInfo();
|
||||
inline ~FileInfo();
|
||||
inline FileInfo(const FileInfo& fi);
|
||||
inline FileInfo& operator=(const FileInfo& fi);
|
||||
FileInfo();
|
||||
~FileInfo();
|
||||
FileInfo(const FileInfo& fi);
|
||||
FileInfo& operator=(const FileInfo& fi);
|
||||
|
||||
status_t UpdateFileHandles(FileSystem* fs);
|
||||
|
||||
static status_t ParsePath(RequestBuilder& req, uint32& count,
|
||||
const char* _path, bool getFileHandle = false);
|
||||
|
||||
status_t CreateName(const char* dirPath, const char* name);
|
||||
};
|
||||
|
||||
struct FileSystemId {
|
||||
@ -97,11 +115,18 @@ FileHandle::operator=(const FileHandle& fh)
|
||||
|
||||
|
||||
inline bool
|
||||
FileHandle::operator!=(const FileHandle& handle) const
|
||||
FileHandle::operator==(const FileHandle& handle) const
|
||||
{
|
||||
if (fSize != handle.fSize)
|
||||
return true;
|
||||
return memcmp(fData, handle.fData, fSize) != 0;
|
||||
return false;
|
||||
return memcmp(fData, handle.fData, fSize) == 0;
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
FileHandle::operator!=(const FileHandle& handle) const
|
||||
{
|
||||
return !operator==(handle);
|
||||
}
|
||||
|
||||
|
||||
@ -123,53 +148,6 @@ FileHandle::operator<(const FileHandle& handle) const
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
FileInfo::FileInfo()
|
||||
:
|
||||
fFileId(0),
|
||||
fName(NULL),
|
||||
fPath(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
FileInfo::~FileInfo()
|
||||
{
|
||||
free(const_cast<char*>(fName));
|
||||
free(const_cast<char*>(fPath));
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
FileInfo::FileInfo(const FileInfo& fi)
|
||||
:
|
||||
fFileId(fi.fFileId),
|
||||
fHandle(fi.fHandle),
|
||||
fParent(fi.fParent),
|
||||
fName(strdup(fi.fName)),
|
||||
fPath(strdup(fi.fPath))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
inline FileInfo&
|
||||
FileInfo::operator=(const FileInfo& fi)
|
||||
{
|
||||
fFileId = fi.fFileId;
|
||||
fHandle = fi.fHandle;
|
||||
fParent = fi.fParent;
|
||||
|
||||
free(const_cast<char*>(fName));
|
||||
fName = strdup(fi.fName);
|
||||
|
||||
free(const_cast<char*>(fPath));
|
||||
fPath = strdup(fi.fPath);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
FileSystemId::operator==(const FileSystemId& fsid) const
|
||||
{
|
||||
|
@ -54,33 +54,74 @@ FileSystem::~FileSystem()
|
||||
mutex_destroy(&fOpenOwnerLock);
|
||||
mutex_destroy(&fCreateFileLock);
|
||||
|
||||
free(const_cast<char*>(fPath));
|
||||
if (fPath != NULL) {
|
||||
for (uint32 i = 0; fPath[i] != NULL; i++)
|
||||
free(const_cast<char*>(fPath[i]));
|
||||
}
|
||||
delete[] fPath;
|
||||
|
||||
delete fRoot;
|
||||
}
|
||||
|
||||
|
||||
static const char*
|
||||
GetPath(const char* root, const char* path)
|
||||
static InodeNames*
|
||||
GetInodeNames(const char** root, const char* _path)
|
||||
{
|
||||
ASSERT(path != NULL);
|
||||
ASSERT(_path != NULL);
|
||||
|
||||
int slash = 0;
|
||||
int i;
|
||||
for (i = 0; path[i] != '\0'; i++) {
|
||||
if (path[i] == '/')
|
||||
slash = i;
|
||||
char* path = strdup(_path);
|
||||
if (path == NULL)
|
||||
return NULL;
|
||||
MemoryDeleter _(path);
|
||||
|
||||
if (root == NULL)
|
||||
break;
|
||||
if (root != NULL) {
|
||||
for (i = 0; root[i] != NULL; i++) {
|
||||
char* pathEnd = strchr(path, '/');
|
||||
if (pathEnd == path) {
|
||||
path++;
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (path[i] != root[i] || root[i] == '\0')
|
||||
break;
|
||||
if (pathEnd == NULL) {
|
||||
path = NULL;
|
||||
break;
|
||||
} else
|
||||
path = pathEnd + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (path[i] == '\0')
|
||||
return NULL;
|
||||
InodeNames* names = NULL;
|
||||
if (path == NULL) {
|
||||
names = new InodeNames;
|
||||
if (names == NULL)
|
||||
return NULL;
|
||||
|
||||
return path + slash;
|
||||
names->AddName(NULL, "");
|
||||
return names;
|
||||
}
|
||||
|
||||
do {
|
||||
char* pathEnd = strchr(path, '/');
|
||||
if (pathEnd != NULL)
|
||||
*pathEnd = '\0';
|
||||
|
||||
InodeNames* name = new InodeNames;
|
||||
if (name == NULL) {
|
||||
delete names;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
name->AddName(names, path);
|
||||
names = name;
|
||||
if (pathEnd == NULL)
|
||||
break;
|
||||
|
||||
path = pathEnd + 1;
|
||||
} while (*path != '\0');
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
|
||||
@ -103,7 +144,7 @@ FileSystem::Mount(FileSystem** _fs, RPC::Server* serv, const char* fsPath,
|
||||
req.PutRootFH();
|
||||
|
||||
uint32 lookupCount = 0;
|
||||
status_t result = FileInfo::ParsePath(req, lookupCount, fsPath);
|
||||
status_t result = _ParsePath(req, lookupCount, fsPath);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
@ -156,30 +197,25 @@ FileSystem::Mount(FileSystem** _fs, RPC::Server* serv, const char* fsPath,
|
||||
FSLocations* locs
|
||||
= reinterpret_cast<FSLocations*>(values[3].fData.fLocations);
|
||||
|
||||
fs->fPath = strdup(locs->fRootPath);
|
||||
fs->fPath = locs->fRootPath;
|
||||
locs->fRootPath = NULL;
|
||||
} else
|
||||
fs->fPath = NULL;
|
||||
|
||||
FileInfo fi;
|
||||
const char* name;
|
||||
if (fsPath != NULL && fsPath[0] == '/')
|
||||
fsPath++;
|
||||
|
||||
fs->fServer = serv;
|
||||
fs->fDevId = id;
|
||||
fs->fFsId = *fsid;
|
||||
|
||||
fi.fHandle = fh;
|
||||
fi.fParent = fh;
|
||||
fi.fPath = strdup(GetPath(fs->fPath, fsPath));
|
||||
|
||||
if (fi.fPath != NULL) {
|
||||
name = strrchr(fi.fPath, '/');
|
||||
if (name != NULL) {
|
||||
name++;
|
||||
fi.fName = strdup(name);
|
||||
}
|
||||
fi.fNames = GetInodeNames(fs->fPath, fsPath);
|
||||
if (fi.fNames == NULL) {
|
||||
delete[] values;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
fi.fNames->fHandle = fh;
|
||||
|
||||
delete[] values;
|
||||
|
||||
@ -188,7 +224,7 @@ FileSystem::Mount(FileSystem** _fs, RPC::Server* serv, const char* fsPath,
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
name = strrchr(fsPath, '/');
|
||||
char* name = strrchr(fsPath, '/');
|
||||
if (name != NULL) {
|
||||
name++;
|
||||
reinterpret_cast<RootInode*>(inode)->SetName(name);
|
||||
@ -263,8 +299,14 @@ FileSystem::Migrate(const RPC::Server* serv)
|
||||
if (gRPCServerManager->Acquire(&fServer, &resolver,
|
||||
CreateNFS4Server) == B_OK) {
|
||||
|
||||
free(const_cast<char*>(fPath));
|
||||
fPath = strdup(locs->fLocations[i].fRootPath);
|
||||
if (fPath != NULL) {
|
||||
for (uint32 i = 0; fPath[i] != NULL; i++)
|
||||
free(const_cast<char*>(fPath[i]));
|
||||
}
|
||||
delete[] fPath;
|
||||
|
||||
fPath = locs->fLocations[i].fRootPath;
|
||||
locs->fLocations[i].fRootPath = NULL;
|
||||
|
||||
if (fPath == NULL) {
|
||||
gRPCServerManager->Release(fServer);
|
||||
@ -391,3 +433,41 @@ FileSystem::GetDelegation(const FileHandle& handle)
|
||||
return it.Current();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
FileSystem::_ParsePath(RequestBuilder& req, uint32& count, const char* _path)
|
||||
{
|
||||
ASSERT(_path != NULL);
|
||||
|
||||
char* path = strdup(_path);
|
||||
if (path == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
char* pathStart = path;
|
||||
char* pathEnd;
|
||||
|
||||
while (pathStart != NULL) {
|
||||
pathEnd = strchr(pathStart, '/');
|
||||
if (pathEnd != NULL)
|
||||
*pathEnd = '\0';
|
||||
|
||||
if (pathEnd != pathStart) {
|
||||
if (!strcmp(pathStart, "..")) {
|
||||
req.LookUpUp();
|
||||
count++;
|
||||
} else if (strcmp(pathStart, ".")) {
|
||||
req.LookUp(pathStart);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (pathEnd != NULL && pathEnd[1] != '\0')
|
||||
pathStart = pathEnd + 1;
|
||||
else
|
||||
pathStart = NULL;
|
||||
}
|
||||
free(path);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ public:
|
||||
inline RPC::Server* Server();
|
||||
inline NFS4Server* NFSServer();
|
||||
|
||||
inline const char* Path() const;
|
||||
inline const char** Path() const;
|
||||
inline const FileSystemId& FsId() const;
|
||||
|
||||
inline uint64 AllocFileId();
|
||||
@ -80,6 +80,9 @@ public:
|
||||
private:
|
||||
FileSystem(const MountConfiguration& config);
|
||||
|
||||
static status_t _ParsePath(RequestBuilder& req, uint32& count,
|
||||
const char* _path);
|
||||
|
||||
mutex fCreateFileLock;
|
||||
|
||||
mutex fDelegationLock;
|
||||
@ -99,7 +102,7 @@ private:
|
||||
bool fNamedAttrs;
|
||||
|
||||
FileSystemId fFsId;
|
||||
const char* fPath;
|
||||
const char** fPath;
|
||||
|
||||
RootInode* fRoot;
|
||||
|
||||
@ -158,7 +161,7 @@ FileSystem::NFSServer()
|
||||
}
|
||||
|
||||
|
||||
inline const char*
|
||||
inline const char**
|
||||
FileSystem::Path() const
|
||||
{
|
||||
ASSERT(fPath != NULL);
|
||||
|
@ -232,14 +232,7 @@ Inode::Link(Inode* dir, const char* name)
|
||||
return result;
|
||||
|
||||
fFileSystem->Root()->MakeInfoInvalid();
|
||||
|
||||
FileInfo fi = fInfo;
|
||||
fi.fParent = dir->fInfo.fHandle;
|
||||
result = fi.CreateName(fInfo.fPath, name);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
fFileSystem->InoIdMap()->AddEntry(fi, fInfo.fFileId);
|
||||
fInfo.fNames->AddName(dir->fInfo.fNames, name);
|
||||
|
||||
dir->fCache->Lock();
|
||||
if (dir->fCache->Valid()) {
|
||||
@ -875,19 +868,17 @@ Inode::ChildAdded(const char* name, uint64 fileID,
|
||||
FileInfo fi;
|
||||
fi.fFileId = fileID;
|
||||
fi.fHandle = fileHandle;
|
||||
fi.fParent = fInfo.fHandle;
|
||||
status_t result = fi.CreateName(fInfo.fPath, name);
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
return fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID));
|
||||
return fFileSystem->InoIdMap()->AddName(fi, fInfo.fNames, name,
|
||||
FileIdToInoT(fileID));
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
Inode::Name() const
|
||||
{
|
||||
return fInfo.fName;
|
||||
ASSERT(fInfo.fNames->fNames.Head() != NULL);
|
||||
return fInfo.fNames->fNames.Head()->fName;
|
||||
}
|
||||
|
||||
|
||||
|
81
src/add-ons/kernel/file_systems/nfs4/InodeIdMap.cpp
Normal file
81
src/add-ons/kernel/file_systems/nfs4/InodeIdMap.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2013 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Paweł Dziepak, pdziepak@quarnos.org
|
||||
*/
|
||||
|
||||
|
||||
#include "InodeIdMap.h"
|
||||
|
||||
|
||||
status_t
|
||||
InodeIdMap::AddName(FileInfo& fileInfo, InodeNames* parent,
|
||||
const char* name, ino_t id)
|
||||
{
|
||||
MutexLocker _(fLock);
|
||||
AVLTreeMap<ino_t, FileInfo>::Iterator iterator = fMap.Find(id);
|
||||
if (iterator.HasCurrent()) {
|
||||
if (fileInfo.fHandle == iterator.Current().fHandle) {
|
||||
return iterator.CurrentValuePointer()->fNames->AddName(parent,
|
||||
name);
|
||||
}
|
||||
}
|
||||
|
||||
fMap.Remove(id);
|
||||
fileInfo.fNames = new InodeNames;
|
||||
if (fileInfo.fNames == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
fileInfo.fNames->fHandle = fileInfo.fHandle;
|
||||
status_t result = fileInfo.fNames->AddName(parent, name);
|
||||
if (result != B_OK) {
|
||||
delete fileInfo.fNames;
|
||||
return result;
|
||||
}
|
||||
|
||||
return fMap.Insert(id, fileInfo);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
InodeIdMap::RemoveName(ino_t id, InodeNames* parent, const char* name)
|
||||
{
|
||||
ASSERT(name != NULL);
|
||||
|
||||
MutexLocker _(fLock);
|
||||
AVLTreeMap<ino_t, FileInfo>::Iterator iterator = fMap.Find(id);
|
||||
if (!iterator.HasCurrent())
|
||||
return true;
|
||||
|
||||
FileInfo* fileInfo = iterator.CurrentValuePointer();
|
||||
|
||||
return fileInfo->fNames->RemoveName(parent, name);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
InodeIdMap::RemoveEntry(ino_t id)
|
||||
{
|
||||
MutexLocker _(fLock);
|
||||
return fMap.Remove(id);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
InodeIdMap::GetFileInfo(FileInfo* fileInfo, ino_t id)
|
||||
{
|
||||
ASSERT(fileInfo != NULL);
|
||||
|
||||
MutexLocker _(fLock);
|
||||
AVLTreeMap<ino_t, FileInfo>::Iterator iterator = fMap.Find(id);
|
||||
if (!iterator.HasCurrent())
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
*fileInfo = iterator.Current();
|
||||
if (fileInfo->fNames->fNames.IsEmpty())
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 Haiku, Inc. All rights reserved.
|
||||
* Copyright 2012,2013 Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
@ -16,27 +16,24 @@
|
||||
|
||||
#include "FileInfo.h"
|
||||
|
||||
struct InodeIdMapEntry {
|
||||
FileInfo fFileInfo;
|
||||
bool fRemoved;
|
||||
};
|
||||
|
||||
class InodeIdMap {
|
||||
public:
|
||||
inline InodeIdMap();
|
||||
inline ~InodeIdMap();
|
||||
|
||||
inline status_t AddEntry(const FileInfo& fi,
|
||||
ino_t id, bool weak = false);
|
||||
inline status_t MarkRemoved(ino_t id);
|
||||
inline status_t RemoveEntry(ino_t id);
|
||||
inline status_t GetFileInfo(FileInfo* fi, ino_t id);
|
||||
|
||||
protected:
|
||||
inline bool _IsEntryRemoved(ino_t id);
|
||||
status_t AddName(FileInfo& fileInfo,
|
||||
InodeNames* parent,
|
||||
const char* name, ino_t id);
|
||||
bool RemoveName(ino_t id,
|
||||
InodeNames* parent,
|
||||
const char* name);
|
||||
status_t RemoveEntry(ino_t id);
|
||||
status_t GetFileInfo(FileInfo* fileInfo,
|
||||
ino_t id);
|
||||
|
||||
private:
|
||||
AVLTreeMap<ino_t, InodeIdMapEntry> fMap;
|
||||
AVLTreeMap<ino_t, FileInfo> fMap;
|
||||
mutex fLock;
|
||||
|
||||
};
|
||||
@ -56,71 +53,5 @@ InodeIdMap::~InodeIdMap()
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
InodeIdMap::AddEntry(const FileInfo& fi, ino_t id, bool weak)
|
||||
{
|
||||
InodeIdMapEntry entry;
|
||||
|
||||
MutexLocker _(fLock);
|
||||
if (!weak || _IsEntryRemoved(id))
|
||||
fMap.Remove(id);
|
||||
|
||||
entry.fFileInfo = fi;
|
||||
entry.fRemoved = false;
|
||||
|
||||
return fMap.Insert(id, entry);
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
InodeIdMap::MarkRemoved(ino_t id)
|
||||
{
|
||||
MutexLocker _(fLock);
|
||||
AVLTreeMap<ino_t, InodeIdMapEntry>::Iterator it = fMap.Find(id);
|
||||
if (!it.HasCurrent())
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
it.CurrentValuePointer()->fRemoved = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
InodeIdMap::RemoveEntry(ino_t id)
|
||||
{
|
||||
MutexLocker _(fLock);
|
||||
if (_IsEntryRemoved(id))
|
||||
return fMap.Remove(id);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
InodeIdMap::GetFileInfo(FileInfo* fi, ino_t id)
|
||||
{
|
||||
ASSERT(fi != NULL);
|
||||
|
||||
MutexLocker _(fLock);
|
||||
AVLTreeMap<ino_t, InodeIdMapEntry>::Iterator it = fMap.Find(id);
|
||||
if (!it.HasCurrent())
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
*fi = it.Current().fFileInfo;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// Caller must hold fLock
|
||||
inline bool
|
||||
InodeIdMap::_IsEntryRemoved(ino_t id)
|
||||
{
|
||||
AVLTreeMap<ino_t, InodeIdMapEntry>::Iterator it = fMap.Find(id);
|
||||
if (!it.HasCurrent())
|
||||
return true;
|
||||
|
||||
return it.Current().fRemoved;
|
||||
}
|
||||
|
||||
|
||||
#endif // INODEIDMAP_H
|
||||
|
||||
|
@ -36,13 +36,12 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state,
|
||||
if (result != B_OK)
|
||||
return result;
|
||||
|
||||
FileInfo fi;
|
||||
fi.fFileId = fileID;
|
||||
fi.fHandle = handle;
|
||||
fi.fParent = fInfo.fHandle;
|
||||
fi.CreateName(fInfo.fPath, name);
|
||||
FileInfo fileInfo;
|
||||
fileInfo.fFileId = fileID;
|
||||
fileInfo.fHandle = handle;
|
||||
|
||||
fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID));
|
||||
fFileSystem->InoIdMap()->AddName(fileInfo, fInfo.fNames, name,
|
||||
FileIdToInoT(fileID));
|
||||
|
||||
fCache->Lock();
|
||||
if (fCache->Valid()) {
|
||||
@ -56,7 +55,7 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state,
|
||||
fCache->Unlock();
|
||||
|
||||
state->fFileSystem = fFileSystem;
|
||||
state->fInfo = fi;
|
||||
state->fInfo = fileInfo;
|
||||
state->fMode = mode & O_RWMASK;
|
||||
|
||||
return B_OK;
|
||||
@ -253,8 +252,6 @@ Inode::OpenAttr(const char* _name, int mode, OpenAttrCookie* cookie,
|
||||
if (state == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
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) {
|
||||
|
@ -12,6 +12,7 @@ KernelAddon nfs4 :
|
||||
FileSystem.cpp
|
||||
IdMap.cpp
|
||||
Inode.cpp
|
||||
InodeIdMap.cpp
|
||||
InodeDir.cpp
|
||||
InodeRegular.cpp
|
||||
kernel_interface.cpp
|
||||
|
@ -125,10 +125,8 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
|
||||
Request request(serv, fFileSystem);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
if (parent)
|
||||
req.PutFH(fInfo.fParent);
|
||||
else
|
||||
req.PutFH(fInfo.fHandle);
|
||||
(void)parent; // TODO: add support for named attributes
|
||||
req.PutFH(fInfo.fHandle);
|
||||
|
||||
if (change != NULL) {
|
||||
Attribute dirAttr[] = { FATTR4_CHANGE };
|
||||
@ -562,16 +560,16 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
|
||||
// Since we are opening the file using a pair (parentFH, name) we
|
||||
// need to check for race conditions.
|
||||
if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
|
||||
req.PutFH(fInfo.fParent);
|
||||
req.LookUp(fInfo.fName);
|
||||
req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle);
|
||||
req.LookUp(fInfo.fNames->fNames.Head()->fName);
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_FILEID;
|
||||
attr.fFreePointer = false;
|
||||
attr.fData.fValue64 = fInfo.fFileId;
|
||||
req.Verify(&attr, 1);
|
||||
} else if (fFileSystem->ExpireType() == FH4_PERSISTENT) {
|
||||
req.PutFH(fInfo.fParent);
|
||||
req.LookUp(fInfo.fName);
|
||||
req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle);
|
||||
req.LookUp(fInfo.fNames->fNames.Head()->fName);
|
||||
AttrValue attr;
|
||||
attr.fAttribute = FATTR4_FILEHANDLE;
|
||||
attr.fFreePointer = true;
|
||||
@ -580,9 +578,10 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
|
||||
req.Verify(&attr, 1);
|
||||
}
|
||||
|
||||
req.PutFH(fInfo.fParent);
|
||||
req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle);
|
||||
req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID,
|
||||
OPEN4_NOCREATE, fFileSystem->OpenOwner(), fInfo.fName);
|
||||
OPEN4_NOCREATE, fFileSystem->OpenOwner(),
|
||||
fInfo.fNames->fNames.Head()->fName);
|
||||
req.GetFH();
|
||||
|
||||
result = request.Send();
|
||||
@ -796,10 +795,8 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode,
|
||||
Request request(serv, fFileSystem);
|
||||
RequestBuilder& req = request.Builder();
|
||||
|
||||
if (parent)
|
||||
req.PutFH(fInfo.fParent);
|
||||
else
|
||||
req.PutFH(fInfo.fHandle);
|
||||
(void)parent; // TODO: support named attributes
|
||||
req.PutFH(fInfo.fHandle);
|
||||
|
||||
uint32 i = 0;
|
||||
AttrValue cattr[1];
|
||||
|
@ -19,7 +19,12 @@
|
||||
|
||||
FSLocation::~FSLocation()
|
||||
{
|
||||
free(const_cast<char*>(fRootPath));
|
||||
if (fRootPath != NULL) {
|
||||
for (uint32 i = 0; fRootPath[i] != NULL; i++)
|
||||
free(const_cast<char*>(fRootPath[i]));
|
||||
}
|
||||
delete[] fRootPath;
|
||||
|
||||
for (uint32 i = 0; i < fCount; i++)
|
||||
free(const_cast<char*>(fLocations[i]));
|
||||
delete[] fLocations;
|
||||
@ -28,7 +33,12 @@ FSLocation::~FSLocation()
|
||||
|
||||
FSLocations::~FSLocations()
|
||||
{
|
||||
free(const_cast<char*>(fRootPath));
|
||||
if (fRootPath != NULL) {
|
||||
for (uint32 i = 0; fRootPath[i] != NULL; i++)
|
||||
free(const_cast<char*>(fRootPath[i]));
|
||||
}
|
||||
delete[] fRootPath;
|
||||
|
||||
delete[] fLocations;
|
||||
}
|
||||
|
||||
@ -528,27 +538,29 @@ ReplyInterpreter::Write(uint32* size)
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
ReplyInterpreter::_FlattenPathname(XDR::ReadStream& stream)
|
||||
const char**
|
||||
ReplyInterpreter::_GetPath(XDR::ReadStream& stream)
|
||||
{
|
||||
uint32 count = stream.GetUInt();
|
||||
char* pathname = NULL;
|
||||
uint32 size = 0;
|
||||
for (uint32 i = 0; i < count; i++) {
|
||||
const char* path = stream.GetString();
|
||||
size += strlen(path) + 1;
|
||||
if (pathname == NULL) {
|
||||
pathname = reinterpret_cast<char*>(malloc(strlen(path) + 1));
|
||||
pathname[0] = '\0';
|
||||
} else {
|
||||
*pathname++ = '/';
|
||||
pathname = reinterpret_cast<char*>(realloc(pathname, size));
|
||||
}
|
||||
strcat(pathname, path);
|
||||
free(const_cast<char*>(path));
|
||||
}
|
||||
char** path = new char*[count + 1];
|
||||
if (path == NULL)
|
||||
return NULL;
|
||||
|
||||
return pathname;
|
||||
uint32 i;
|
||||
for (i = 0; i < count; i++) {
|
||||
path[i] = stream.GetString();
|
||||
if (path[i] == NULL)
|
||||
goto out;
|
||||
}
|
||||
path[count] = NULL;
|
||||
|
||||
return const_cast<const char**>(path);
|
||||
|
||||
out:
|
||||
for (uint32 j = 0; j < i; j++)
|
||||
free(path[i]);
|
||||
delete[] path;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -662,11 +674,11 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs,
|
||||
values[current].fAttribute = FATTR4_FS_LOCATIONS;
|
||||
|
||||
FSLocations* locs = new FSLocations;
|
||||
locs->fRootPath = _FlattenPathname(stream);
|
||||
locs->fRootPath = _GetPath(stream);
|
||||
locs->fCount = stream.GetUInt();
|
||||
locs->fLocations = new FSLocation[locs->fCount];
|
||||
for (uint32 i = 0; i < locs->fCount; i++) {
|
||||
locs->fLocations[i].fRootPath = _FlattenPathname(stream);
|
||||
locs->fLocations[i].fRootPath = _GetPath(stream);
|
||||
locs->fLocations[i].fCount = stream.GetUInt();
|
||||
locs->fLocations[i].fLocations
|
||||
= new const char*[locs->fLocations[i].fCount];
|
||||
|
@ -17,7 +17,8 @@
|
||||
|
||||
|
||||
struct FSLocation {
|
||||
const char* fRootPath;
|
||||
const char** fRootPath;
|
||||
|
||||
const char** fLocations;
|
||||
uint32 fCount;
|
||||
|
||||
@ -25,7 +26,8 @@ struct FSLocation {
|
||||
};
|
||||
|
||||
struct FSLocations {
|
||||
const char* fRootPath;
|
||||
const char** fRootPath;
|
||||
|
||||
FSLocation* fLocations;
|
||||
uint32 fCount;
|
||||
|
||||
@ -108,7 +110,7 @@ public:
|
||||
private:
|
||||
void _ParseHeader();
|
||||
|
||||
static const char* _FlattenPathname(XDR::ReadStream& stream);
|
||||
static const char** _GetPath(XDR::ReadStream& stream);
|
||||
|
||||
status_t _DecodeAttrs(XDR::ReadStream& stream, AttrValue** attrs,
|
||||
uint32* count);
|
||||
|
@ -27,15 +27,27 @@ void
|
||||
VnodeToInode::Replace(Inode* newInode)
|
||||
{
|
||||
WriteLocker _(fLock);
|
||||
if (fInode != NULL && !IsRoot()) {
|
||||
fInode->GetFileSystem()->InoIdMap()->MarkRemoved(fID);
|
||||
if (fInode != NULL && !IsRoot())
|
||||
delete fInode;
|
||||
}
|
||||
|
||||
fInode = newInode;
|
||||
if (fInode != NULL) {
|
||||
ASSERT(fFileSystem == fInode->GetFileSystem());
|
||||
fInode->GetFileSystem()->InoIdMap()->AddEntry(fInode->fInfo, fID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
VnodeToInode::Unlink(InodeNames* parent, const char* name)
|
||||
{
|
||||
WriteLocker _(fLock);
|
||||
if (fInode != NULL && !IsRoot()) {
|
||||
bool removed = fInode->GetFileSystem()->InoIdMap()->RemoveName(fID,
|
||||
parent, name);
|
||||
if (removed) {
|
||||
delete fInode;
|
||||
fInode = NULL;
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
Inode* Get();
|
||||
void Replace(Inode* newInode);
|
||||
|
||||
inline void Remove();
|
||||
bool Unlink(InodeNames* parent, const char* name);
|
||||
inline void Clear();
|
||||
|
||||
inline ino_t ID() const;
|
||||
@ -72,7 +72,7 @@ VnodeToInode::VnodeToInode(ino_t id, FileSystem* fileSystem)
|
||||
inline
|
||||
VnodeToInode::~VnodeToInode()
|
||||
{
|
||||
Remove();
|
||||
Replace(NULL);
|
||||
if (fFileSystem != NULL && !IsRoot())
|
||||
fFileSystem->InoIdMap()->RemoveEntry(fID);
|
||||
rw_lock_destroy(&fLock);
|
||||
@ -93,13 +93,6 @@ VnodeToInode::Unlock()
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
VnodeToInode::Remove()
|
||||
{
|
||||
Replace(NULL);
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
VnodeToInode::Clear()
|
||||
{
|
||||
|
@ -321,23 +321,6 @@ nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id)
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_get_vnode_name(fs_volume* volume, fs_vnode* vnode, char* buffer,
|
||||
size_t bufferSize)
|
||||
{
|
||||
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
|
||||
TRACE("volume = %p, vnode = %" B_PRIi64, volume, vti->ID());
|
||||
|
||||
VnodeToInodeLocker _(vti);
|
||||
Inode* inode = vti->Get();
|
||||
if (inode == NULL)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
strncpy(buffer, inode->Name(), bufferSize);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
|
||||
{
|
||||
@ -606,11 +589,12 @@ nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name)
|
||||
if (result == B_OK) {
|
||||
result = get_vnode(volume, id, reinterpret_cast<void**>(&vti));
|
||||
ASSERT(result == B_OK);
|
||||
vti->Remove();
|
||||
put_vnode(volume, id);
|
||||
remove_vnode(volume, id);
|
||||
|
||||
if (vti->Unlink(inode->fInfo.fNames, name))
|
||||
remove_vnode(volume, id);
|
||||
|
||||
put_vnode(volume, id);
|
||||
put_vnode(volume, id);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
@ -654,9 +638,10 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName,
|
||||
if (result == B_OK) {
|
||||
result = get_vnode(volume, oldID, reinterpret_cast<void**>(&vti));
|
||||
ASSERT(result == B_OK);
|
||||
vti->Remove();
|
||||
if (vti->Unlink(toInode->fInfo.fNames, toName))
|
||||
remove_vnode(volume, oldID);
|
||||
|
||||
put_vnode(volume, oldID);
|
||||
remove_vnode(volume, oldID);
|
||||
put_vnode(volume, oldID);
|
||||
}
|
||||
}
|
||||
@ -670,8 +655,8 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName,
|
||||
}
|
||||
|
||||
unremove_vnode(volume, id);
|
||||
child->fInfo.fParent = toInode->fInfo.fHandle;
|
||||
child->fInfo.CreateName(toInode->fInfo.fPath, toName);
|
||||
child->fInfo.fNames->RemoveName(fromInode->fInfo.fNames, fromName);
|
||||
child->fInfo.fNames->AddName(toInode->fInfo.fNames, toName);
|
||||
put_vnode(volume, id);
|
||||
}
|
||||
|
||||
@ -998,11 +983,13 @@ nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name)
|
||||
|
||||
result = acquire_vnode(volume, id);
|
||||
if (result == B_OK) {
|
||||
ASSERT(get_vnode(volume, id, reinterpret_cast<void**>(&vti)) == B_OK);
|
||||
vti->Remove();
|
||||
put_vnode(volume, id);
|
||||
remove_vnode(volume, id);
|
||||
result = get_vnode(volume, id, reinterpret_cast<void**>(&vti));
|
||||
ASSERT(result == B_OK);
|
||||
|
||||
if (vti->Unlink(inode->fInfo.fNames, name))
|
||||
remove_vnode(volume, id);
|
||||
|
||||
put_vnode(volume, id);
|
||||
put_vnode(volume, id);
|
||||
}
|
||||
|
||||
@ -1444,7 +1431,7 @@ fs_volume_ops gNFSv4VolumeOps = {
|
||||
|
||||
fs_vnode_ops gNFSv4VnodeOps = {
|
||||
nfs4_lookup,
|
||||
nfs4_get_vnode_name,
|
||||
NULL, // get_vnode_name()
|
||||
nfs4_put_vnode,
|
||||
nfs4_remove_vnode,
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user