⛏️ index : haiku.git

/*
 * Copyright 2008-2010, Axel DΓΆrfler, axeld@pinc-software.de.
 * Copyright 2011, JΓ©rΓ΄me Duval, korli@users.berlios.de.
 * Copyright 2014 Haiku, Inc. All rights reserved.
 *
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *		Axel DΓΆrfler, axeld@pinc-software.de
 *		JΓ©rΓ΄me Duval, korli@users.berlios.de
 *		John Scipione, jscipione@gmail.com
 */
#ifndef VOLUME_H
#define VOLUME_H


#include <lock.h>
#include <string.h>

#include <StorageDefs.h>
#include <util/SplayTree.h>

#include "exfat.h"


struct node_key {
	cluster_t cluster;
	uint32 offset;
};

struct node {
	struct node_key key;
	ino_t ino;
	ino_t parent;
	SplayTreeLink<struct node> nodeTreeLink;
	SplayTreeLink<struct node> inoTreeLink;
};


struct NodeTreeDefinition {
	typedef struct node_key KeyType;
	typedef	struct node NodeType;

	static KeyType GetKey(const NodeType* node)
	{
		return node->key;
	}

	static SplayTreeLink<NodeType>* GetLink(NodeType* node)
	{
		return &node->nodeTreeLink;
	}

	static int Compare(KeyType key, const NodeType* node)
	{
		if (key.cluster == node->key.cluster) {
			if (key.offset == node->key.offset)
				return 0;
			return key.offset < node->key.offset ? -1 : 1;
		}
		return key.cluster < node->key.cluster ? -1 : 1;
	}
};

struct InoTreeDefinition {
	typedef ino_t KeyType;
	typedef	struct node NodeType;

	static KeyType GetKey(const NodeType* node)
	{
		return node->ino;
	}

	static SplayTreeLink<NodeType>* GetLink(NodeType* node)
	{
		return &node->inoTreeLink;
	}

	static int Compare(KeyType key, const NodeType* node)
	{
		if (key != node->ino)
			return key < node->ino ? -1 : 1;
		return 0;
	}
};


typedef SplayTree<NodeTreeDefinition> NodeTree;
typedef SplayTree<InoTreeDefinition> InoTree;
class Inode;
struct InodesInoTreeDefinition;
typedef IteratableSplayTree<InodesInoTreeDefinition> InodesInoTree;
struct InodesClusterTreeDefinition;
typedef IteratableSplayTree<InodesClusterTreeDefinition> InodesClusterTree;


enum volume_flags {
	VOLUME_READ_ONLY	= 0x0001
};


class Volume {
public:
								Volume(fs_volume* volume);
								~Volume();

			status_t			Mount(const char* device, uint32 flags);
			status_t			Unmount();

			bool				IsValidSuperBlock();
			bool				IsReadOnly() const
								{ return (fFlags & VOLUME_READ_ONLY) != 0; }

			Inode*				RootNode() const { return fRootNode; }
			int					Device() const { return fDevice; }

			dev_t				ID() const
								{ return fFSVolume ? fFSVolume->id : -1; }
			fs_volume*			FSVolume() const { return fFSVolume; }
			const char*			Name() const;
			void				SetName(const char* name)
								{ strlcpy(fName, name, sizeof(fName)); }
			
			uint32				BlockSize() const { return fBlockSize; }
			uint32				EntriesPerBlock() const
								{ return fEntriesPerBlock; }
			uint32				EntriesPerCluster()
								{ return fEntriesPerBlock
									<< SuperBlock().BlocksPerClusterShift(); }
			size_t				ClusterSize() { return fBlockSize 
									<< SuperBlock().BlocksPerClusterShift(); }
			exfat_super_block&	SuperBlock() { return fSuperBlock; }

			status_t			LoadSuperBlock();

			// cache access
			void*				BlockCache() { return fBlockCache; }

	static	status_t			Identify(int fd, exfat_super_block* superBlock);

			status_t			ClusterToBlock(cluster_t cluster,
									fsblock_t &block);
			Inode *				FindInode(ino_t id);
			Inode *				FindInode(cluster_t cluster);
			cluster_t			NextCluster(cluster_t cluster);
			ino_t				GetIno(cluster_t cluster, uint32 offset,
									ino_t parent);
			struct node_key*	GetNode(ino_t ino, ino_t &parent);
private:
			ino_t				_NextID() { return fNextId++; }

			mutex				fLock;
			fs_volume*			fFSVolume;
			int					fDevice;
			exfat_super_block	fSuperBlock;
			char				fName[B_FILE_NAME_LENGTH];

			uint16				fFlags;
			uint32				fBlockSize;
			uint32				fEntriesPerBlock;
			Inode*				fRootNode;
			ino_t				fNextId;

			void*				fBlockCache;
			InodesInoTree*		fInodesInoTree;
			InodesClusterTree*	fInodesClusterTree;
			NodeTree			fNodeTree;
			InoTree				fInoTree;
};

#endif	// VOLUME_H