⛏️ index : haiku.git

/*
 * Copyright 2009-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */


#include "UnpackingDirectory.h"

#include "ClassCache.h"
#include "DebugSupport.h"
#include "EmptyAttributeDirectoryCookie.h"
#include "UnpackingAttributeCookie.h"
#include "UnpackingAttributeDirectoryCookie.h"
#include "Utils.h"


// #pragma mark - UnpackingDirectory


CLASS_CACHE(UnpackingDirectory);


UnpackingDirectory::UnpackingDirectory(ino_t id)
	:
	Directory(id)
{
}


UnpackingDirectory::~UnpackingDirectory()
{
}


status_t
UnpackingDirectory::VFSInit(dev_t deviceID)
{
	status_t error = NodeInitVFS(deviceID, fID, fPackageDirectories.Head());
	if (error == B_OK)
		Directory::VFSInit(deviceID);

	return error;
}


void
UnpackingDirectory::VFSUninit()
{
	NodeUninitVFS(fPackageDirectories.Head(), fFlags);
	Directory::VFSUninit();
}


mode_t
UnpackingDirectory::Mode() const
{
	if (PackageDirectory* packageDirectory = fPackageDirectories.Head())
		return packageDirectory->Mode();
	return S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
}


uid_t
UnpackingDirectory::UserID() const
{
	if (PackageDirectory* packageDirectory = fPackageDirectories.Head())
		return packageDirectory->UserID();
	return 0;
}


gid_t
UnpackingDirectory::GroupID() const
{
	if (PackageDirectory* packageDirectory = fPackageDirectories.Head())
		return packageDirectory->GroupID();
	return 0;
}


timespec
UnpackingDirectory::ModifiedTime() const
{
	if (PackageDirectory* packageDirectory = fPackageDirectories.Head())
		return packageDirectory->ModifiedTime();

	timespec time = { 0, 0 };
	return time;
}


off_t
UnpackingDirectory::FileSize() const
{
	return 0;
}


Node*
UnpackingDirectory::GetNode()
{
	return this;
}


status_t
UnpackingDirectory::AddPackageNode(PackageNode* packageNode, dev_t deviceID)
{
	if (!S_ISDIR(packageNode->Mode()))
		return B_NOT_A_DIRECTORY;

	PackageDirectory* packageDirectory
		= dynamic_cast<PackageDirectory*>(packageNode);

	PackageDirectory* other = fPackageDirectories.Head();
	bool overridesHead = other == NULL
		|| packageDirectory->HasPrecedenceOver(other);

	if (overridesHead) {
		fPackageDirectories.InsertBefore(other, packageDirectory);
		NodeReinitVFS(deviceID, fID, packageDirectory, other, fFlags);
	} else
		fPackageDirectories.Add(packageDirectory);

	return B_OK;
}


void
UnpackingDirectory::RemovePackageNode(PackageNode* packageNode, dev_t deviceID)
{
	bool isNewest = packageNode == fPackageDirectories.Head();
	fPackageDirectories.Remove(dynamic_cast<PackageDirectory*>(packageNode));

	// when removing the newest node, we need to find the next node (the list
	// is not sorted)
	PackageDirectory* newestNode = fPackageDirectories.Head();
	if (isNewest && newestNode != NULL) {
		PackageDirectoryList::Iterator it = fPackageDirectories.GetIterator();
		it.Next();
			// skip the first one
		while (PackageDirectory* otherNode = it.Next()) {
			if (otherNode->HasPrecedenceOver(newestNode))
				newestNode = otherNode;
		}

		fPackageDirectories.Remove(newestNode);
		fPackageDirectories.InsertBefore(fPackageDirectories.Head(), newestNode);
		NodeReinitVFS(deviceID, fID, newestNode, packageNode, fFlags);
	}
}


PackageNode*
UnpackingDirectory::GetPackageNode()
{
	return fPackageDirectories.Head();
}


bool
UnpackingDirectory::IsOnlyPackageNode(PackageNode* node) const
{
	return node == fPackageDirectories.Head()
		&& node == fPackageDirectories.Tail();
}


bool
UnpackingDirectory::WillBeFirstPackageNode(PackageNode* packageNode) const
{
	PackageDirectory* packageDirectory
		= dynamic_cast<PackageDirectory*>(packageNode);
	if (packageDirectory == NULL)
		return false;

	PackageDirectory* other = fPackageDirectories.Head();
	return other == NULL || packageDirectory->HasPrecedenceOver(other);
}


void
UnpackingDirectory::PrepareForRemoval()
{
	fPackageDirectories.MakeEmpty();
}


status_t
UnpackingDirectory::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
{
	if (HasVFSInitError())
		return B_ERROR;

	return UnpackingAttributeDirectoryCookie::Open(fPackageDirectories.Head(),
		_cookie);
}


status_t
UnpackingDirectory::OpenAttribute(const StringKey& name, int openMode,
	AttributeCookie*& _cookie)
{
	if (HasVFSInitError())
		return B_ERROR;

	return UnpackingAttributeCookie::Open(fPackageDirectories.Head(), name,
		openMode, _cookie);
}


status_t
UnpackingDirectory::IndexAttribute(AttributeIndexer* indexer)
{
	return UnpackingAttributeCookie::IndexAttribute(fPackageDirectories.Head(),
		indexer);
}


void*
UnpackingDirectory::IndexCookieForAttribute(const StringKey& name) const
{
	if (PackageDirectory* packageDirectory = fPackageDirectories.Head())
		return packageDirectory->IndexCookieForAttribute(name);
	return NULL;
}


// #pragma mark - RootDirectory


void*
RootDirectory::operator new(size_t size)
{
	return malloc(size);
}


void
RootDirectory::operator delete(void* object)
{
	free(object);
}


RootDirectory::RootDirectory(ino_t id, const timespec& modifiedTime)
	:
	UnpackingDirectory(id),
	fModifiedTime(modifiedTime)
{
}


status_t
RootDirectory::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
{
	if (HasVFSInitError())
		return B_ERROR;

	_cookie = new(std::nothrow) EmptyAttributeDirectoryCookie;
	if (_cookie == nullptr)
		return B_NO_MEMORY;
	return B_OK;
}


timespec
RootDirectory::ModifiedTime() const
{
	return fModifiedTime;
}