⛏️ index : haiku.git

/*
 * Copyright 2009-2014, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */
#ifndef VOLUME_H
#define VOLUME_H


#include <fs_interface.h>

#include <condition_variable.h>
#include <lock.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h>
#include <util/KMessage.h>

#include <packagefs.h>

#include "Index.h"
#include "Node.h"
#include "NodeListener.h"
#include "Package.h"
#include "PackageLinksListener.h"
#include "PackagesDirectory.h"
#include "PackageSettings.h"
#include "Query.h"


class Directory;
class PackageFSRoot;
class PackagesDirectory;
class UnpackingNode;

typedef IndexHashTable::Iterator IndexDirIterator;


typedef PackageFSMountType MountType;


class Volume : public DoublyLinkedListLinkImpl<Volume>,
	private PackageLinksListener {
public:
								Volume(fs_volume* fsVolume);
								~Volume();

	inline	bool				ReadLock() const;
	inline	void				ReadUnlock() const;
	inline	bool				WriteLock();
	inline	void				WriteUnlock();
	inline	bool				IsWriteLocked() const;

			fs_volume*			FSVolume() const	{ return fFSVolume; }
			dev_t				ID() const			{ return fFSVolume->id; }
			Directory*			RootDirectory() const { return fRootDirectory; }

			::MountType			MountType() const	{ return fMountType; }

			void				SetPackageFSRoot(::PackageFSRoot* root)
									{ fPackageFSRoot = root; }
			::PackageFSRoot*	PackageFSRoot() const
									{ return fPackageFSRoot; }

			dev_t				MountPointDeviceID() const
									{ return fMountPoint.deviceID; }
			ino_t				MountPointNodeID() const
									{ return fMountPoint.nodeID; }

			status_t			Mount(const char* parameterString);
			void				Unmount();

			Node*				FindNode(ino_t nodeID) const
									{ return fNodes.Lookup(nodeID); }

			status_t			IOCtl(Node* node, uint32 operation,
									void* buffer, size_t size);

			// node listeners -- volume must be write-locked
			void				AddNodeListener(NodeListener* listener,
									Node* node);
			void				RemoveNodeListener(NodeListener* listener);

			// query support -- volume must be write-locked
			void				AddQuery(Query* query);
			void				RemoveQuery(Query* query);
			void				UpdateLiveQueries(Node* node,
									const char* attribute, int32 type,
									const void* oldKey, size_t oldLength,
									const void* newKey, size_t newLength);

			Index*				FindIndex(const StringKey& name) const
									{ return fIndices.Lookup(name); }
			IndexDirIterator	GetIndexDirIterator() const
									{ return fIndices.GetIterator(); }

			// VFS wrappers
			status_t			GetVNode(ino_t nodeID, Node*& _node);
			status_t			PutVNode(ino_t nodeID);
			status_t			RemoveVNode(ino_t nodeID);
			status_t			PublishVNode(Node* node);

private:
	// PackageLinksListener
	virtual	void				PackageLinkNodeAdded(Node* node);
	virtual	void				PackageLinkNodeRemoved(Node* node);
	virtual	void				PackageLinkNodeChanged(Node* node,
									uint32 statFields,
									const OldNodeAttributes& oldAttributes);

private:
			struct ShineThroughDirectory;
			struct ActivationChangeRequest;

private:
			status_t			_LoadOldPackagesStates(
									const char* packagesState);

			status_t			_AddInitialPackages();
			status_t			_AddInitialPackagesFromActivationFile(
									PackagesDirectory* packagesDirectory);
			status_t			_AddInitialPackagesFromDirectory();
			status_t			_LoadAndAddInitialPackage(
									PackagesDirectory* packagesDirectory,
									const char* name);

	inline	void				_AddPackage(Package* package);
	inline	void				_RemovePackage(Package* package);
			void				_RemoveAllPackages();
	inline	Package*			_FindPackage(const char* fileName) const;

			status_t			_AddPackageContent(Package* package,
									bool notify);
			void				_RemovePackageContent(Package* package,
									PackageNode* endNode, bool notify);

			status_t			_AddPackageContentRootNode(Package* package,
									PackageNode* node, bool notify);
			void				_RemovePackageContentRootNode(Package* package,
									PackageNode* packageNode,
									PackageNode* endPackageNode, bool notify);

			status_t			_AddPackageNode(Directory* directory,
									PackageNode* packageNode, bool notify,
									Node*& _node);
			void				_RemovePackageNode(Directory* directory,
									PackageNode* packageNode, Node* node,
									bool notify);

			status_t			_CreateUnpackingNode(mode_t mode,
									Directory* parent, const String& name,
									UnpackingNode*& _node);
									// does *not* return a reference
			void				_RemoveNode(Node* node);
			void				_RemoveNodeAndVNode(Node* node);
									// caller must hold a reference

			status_t			_LoadPackage(
									PackagesDirectory* packagesDirectory,
									const char* name, Package*& _package);

			status_t			_ChangeActivation(
									ActivationChangeRequest& request);

			status_t			_InitMountType(const char* mountType);
			status_t			_CreateShineThroughDirectory(Directory* parent,
									const char* name, Directory*& _directory);
			status_t			_CreateShineThroughDirectories(
									const char* shineThroughSetting);
			status_t			_PublishShineThroughDirectories();

			status_t			_AddPackageLinksDirectory();
			void				_RemovePackageLinksDirectory();
			void				_AddPackageLinksNode(Node* node);
			void				_RemovePackageLinksNode(Node* node);

	inline	Volume*				_SystemVolumeIfNotSelf() const;

			void				_NotifyNodeAdded(Node* node);
			void				_NotifyNodeRemoved(Node* node);
			void				_NotifyNodeChanged(Node* node,
									uint32 statFields,
									const OldNodeAttributes& oldAttributes);

private:
	mutable	rw_lock				fLock;
			fs_volume*			fFSVolume;
			Directory*			fRootDirectory;
			::PackageFSRoot*	fPackageFSRoot;
			::MountType			fMountType;
			PackagesDirectory*	fPackagesDirectory;
			PackagesDirectoryList fPackagesDirectories;
			PackagesDirectoryHashTable fPackagesDirectoriesByNodeRef;
			PackageSettings		fPackageSettings;

			struct {
				dev_t			deviceID;
				ino_t			nodeID;
			} fMountPoint;

			NodeIDHashTable		fNodes;
			NodeListenerHashTable fNodeListeners;
			PackageFileNameHashTable fPackages;
			QueryList			fQueries;
			IndexHashTable		fIndices;

			ino_t				fNextNodeID;
};


bool
Volume::ReadLock() const
{
	return rw_lock_read_lock(&fLock) == B_OK;
}


void
Volume::ReadUnlock() const
{
	rw_lock_read_unlock(&fLock);
}


bool
Volume::WriteLock()
{
	return rw_lock_write_lock(&fLock) == B_OK;
}


void
Volume::WriteUnlock()
{
	rw_lock_write_unlock(&fLock);
}


bool
Volume::IsWriteLocked() const
{
	return find_thread(NULL) == fLock.holder;
}


typedef AutoLocker<const Volume, AutoLockerReadLocking<const Volume> >
	VolumeReadLocker;
typedef AutoLocker<Volume, AutoLockerWriteLocking<Volume> > VolumeWriteLocker;


#endif	// VOLUME_H