⛏️ index : haiku.git

/*
 * Copyright 2012 Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Paweł Dziepak, pdziepak@quarnos.org
 */


#include "FileInfo.h"

#include "FileSystem.h"
#include "Request.h"


/*! Print the handle.
	@pre The parent object is locked.
*/
void
FileHandle::Dump(void (*xprintf)(const char*, ...)) const
{
	for (int i = 0; i < fSize; ++i)
		xprintf("%d ", fData[i]);
	xprintf("\n");
}


InodeName::InodeName(InodeNames* parent, const char* name)
	:
	fParent(parent),
	fName(strdup(name))
{
	if (fParent != NULL)
		fParent->AcquireReference();
}


InodeName::~InodeName()
{
	if (fParent != NULL)
		fParent->ReleaseReference();
	free(const_cast<char*>(fName));
}


InodeNames::InodeNames()
{
	mutex_init(&fLock, NULL);
}


InodeNames::~InodeNames()
{
	while (!fNames.IsEmpty())
		delete fNames.RemoveHead();
	mutex_destroy(&fLock);
}


status_t
InodeNames::AddName(InodeNames* parent, const char* name)
{
	MutexLocker _(fLock);

	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;
	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();
}


void
InodeNames::Dump(void (*xprintf)(const char*, ...))
{
	MutexLocker locker;
	if (xprintf != kprintf)
		locker.SetTo(fLock, false);

	_DumpLocked(xprintf);

	return;
}


void
InodeNames::_DumpLocked(void (*xprintf)(const char*, ...)) const
{
	xprintf("InodeNames ");
	for (SinglyLinkedList<InodeName>::ConstIterator it = fNames.GetIterator();
		const InodeName* name = it.Next();) {
		if (name->fName != NULL)
			xprintf("%s ", name->fName);
	}
	xprintf("\n");

	return;
}


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)
{
	ASSERT(fs != NULL);

	Request request(fs->Server(), fs, geteuid(), getegid());
	RequestBuilder& req = request.Builder();

	req.PutRootFH();

	uint32 lookupCount = 0;
	const char** path = fs->Path();
	if (path != NULL) {
		for (; path[lookupCount] != NULL; lookupCount++)
			req.LookUp(path[lookupCount]);
	}

	uint32 i;
	InodeNames* names = fNames;
	for (i = 0; names != NULL; i++) {
		if (names->fNames.IsEmpty())
			return B_ENTRY_NOT_FOUND;

		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;
		attr.fAttribute = FATTR4_FILEID;
		attr.fFreePointer = false;
		attr.fData.fValue64 = fFileId;
		req.Verify(&attr, 1);
	}

	status_t result = request.Send();
	if (result != B_OK)
		return result;

	ReplyInterpreter& reply = request.Reply();

	reply.PutRootFH();
	for (uint32 i = 0; i < lookupCount; i++)
		reply.LookUp();

	FileHandle handle;
	result = reply.GetFH(&handle);
	if (result != B_OK)
		return result;

	if (fs->IsAttrSupported(FATTR4_FILEID)) {
		result = reply.Verify();
		if (result != B_OK)
			return result;
	}

	fHandle = handle;
	fNames->fHandle = handle;

	return B_OK;
}