1/*
2 * Copyright 2019, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
4 */
5#ifndef DIRECTORY_ENTRY_TABLE_H
6#define DIRECTORY_ENTRY_TABLE_H
7
8#include <util/OpenHashTable.h>
9
10#include "AllocationInfo.h"
11#include "DebugSupport.h"
12#include "Misc.h"
13#include "Node.h"
14
15// DirectoryEntryHash
16struct DirectoryEntryHash {
17	struct Key {
18		ino_t id;
19		const char* name;
20
21		Key(ino_t i, const char* n) : id(i), name(n) {}
22	};
23	typedef Key			KeyType;
24	typedef	Entry		ValueType;
25
26	size_t HashKey(KeyType key) const
27	{
28		return node_child_hash(key.id, key.name);
29	}
30
31	size_t Hash(ValueType* value) const
32	{
33		return HashKey(Key(value->GetParent()->GetID(), value->GetName()));
34	}
35
36	bool Compare(KeyType key, ValueType* value) const
37	{
38		return (value->GetParent()->GetID() == key.id
39			&& !strcmp(value->GetName(), key.name));
40	}
41
42	ValueType*& GetLink(ValueType* value) const
43	{
44		return value->HashLink();
45	}
46};
47
48// DirectoryEntryTable
49class DirectoryEntryTable {
50public:
51	DirectoryEntryTable();
52	~DirectoryEntryTable();
53
54	status_t InitCheck() const;
55
56	status_t AddEntry(Directory *node, Entry *child);
57	status_t AddEntry(ino_t, Entry *child);
58	status_t RemoveEntry(Directory *node, Entry *child);
59	status_t RemoveEntry(ino_t id, Entry *child);
60	status_t RemoveEntry(ino_t id, const char *name);
61	Entry *GetEntry(ino_t id, const char *name);
62
63	void GetAllocationInfo(AllocationInfo &info)
64	{
65		info.AddDirectoryEntryTableAllocation(0, fTable.TableSize(),
66			sizeof(void*), fTable.CountElements());
67	}
68
69protected:
70	BOpenHashTable<DirectoryEntryHash> fTable;
71	status_t fInitStatus;
72};
73
74// constructor
75DirectoryEntryTable::DirectoryEntryTable()
76{
77	fInitStatus = fTable.Init(1000);
78}
79
80// destructor
81DirectoryEntryTable::~DirectoryEntryTable()
82{
83}
84
85// InitCheck
86status_t
87DirectoryEntryTable::InitCheck() const
88{
89	RETURN_ERROR(fInitStatus);
90}
91
92// AddEntry
93status_t
94DirectoryEntryTable::AddEntry(Directory *node, Entry *child)
95{
96	status_t error = (node && child ? B_OK : B_BAD_VALUE);
97	if (error == B_OK)
98		error = AddEntry(node->GetID(), child);
99	return error;
100}
101
102// AddEntry
103status_t
104DirectoryEntryTable::AddEntry(ino_t id, Entry *child)
105{
106	status_t error = (child ? B_OK : B_BAD_VALUE);
107	if (error == B_OK) {
108		RemoveEntry(id, child);
109		SET_ERROR(error, fTable.Insert(child));
110	}
111	return error;
112}
113
114// RemoveEntry
115status_t
116DirectoryEntryTable::RemoveEntry(Directory *node, Entry *child)
117{
118	status_t error = (node && child ? B_OK : B_BAD_VALUE);
119	if (error == B_OK)
120		error = RemoveEntry(node->GetID(), child->GetName());
121	return error;
122}
123
124// RemoveEntry
125status_t
126DirectoryEntryTable::RemoveEntry(ino_t id, Entry *child)
127{
128	status_t error = (child ? B_OK : B_BAD_VALUE);
129	if (error == B_OK)
130		error = RemoveEntry(id, child->GetName());
131	return error;
132}
133
134// RemoveEntry
135status_t
136DirectoryEntryTable::RemoveEntry(ino_t id, const char *name)
137{
138	Entry* child = fTable.Lookup(DirectoryEntryHash::Key(id, name));
139	if (!child)
140		return B_NAME_NOT_FOUND;
141	return fTable.Remove(child) ? B_OK : B_ERROR;
142}
143
144// GetEntry
145Entry *
146DirectoryEntryTable::GetEntry(ino_t id, const char *name)
147{
148	Entry *child = fTable.Lookup(DirectoryEntryHash::Key(id, name));
149	return child;
150}
151
152#endif	// DIRECTORY_ENTRY_TABLE_H
153