1// VirtualDir.cpp
2
3#include "VirtualDir.h"
4
5#include <string.h>
6
7#include <AutoDeleter.h>
8
9// constructor
10VirtualDirEntry::VirtualDirEntry()
11	: fName(),
12	  fNode(NULL)
13{
14}
15
16// destructor
17VirtualDirEntry::~VirtualDirEntry()
18{
19}
20
21// SetTo
22status_t
23VirtualDirEntry::SetTo(const char* name, Node* node)
24{
25	if (!name || strlen(name) == 0 || !node)
26		return B_BAD_VALUE;
27
28	if (!fName.SetTo(name))
29		return B_NO_MEMORY;
30	fNode = node;
31
32	return B_OK;
33}
34
35// GetName
36const char*
37VirtualDirEntry::GetName() const
38{
39	return fName.GetString();
40}
41
42// GetNode
43Node*
44VirtualDirEntry::GetNode() const
45{
46	return fNode;
47}
48
49
50// #pragma mark -
51
52// constructor
53VirtualDirIterator::VirtualDirIterator()
54	: fDirectory(NULL),
55	  fCurrentEntry(NULL),
56	  fState(STATE_DOT)
57{
58}
59
60// destructor
61VirtualDirIterator::~VirtualDirIterator()
62{
63	SetDirectory(NULL);
64}
65
66// SetDirectory
67void
68VirtualDirIterator::SetDirectory(VirtualDir* directory, bool onlyChildren)
69{
70	// unset the old directory
71	if (fDirectory)
72		fDirectory->RemoveDirIterator(this);
73
74	// set the new directory
75	fDirectory = directory;
76	if (fDirectory) {
77		fDirectory->AddDirIterator(this);
78
79		if (onlyChildren) {
80			fCurrentEntry = fDirectory->GetFirstEntry();
81			fState = STATE_OTHERS;
82		} else {
83			fCurrentEntry = NULL;
84			fState = STATE_DOT;
85		}
86	}
87}
88
89// GetCurrentEntry
90bool
91VirtualDirIterator::GetCurrentEntry(const char** name, Node** node)
92{
93	if (!fDirectory)
94		return false;
95	switch (fState) {
96		case STATE_DOT:
97			*name = ".";
98			*node = fDirectory;
99			return true;
100		case STATE_DOT_DOT:
101			*name = "..";
102			*node = fDirectory->GetParent();
103			if (!*node)
104				*node = fDirectory;
105			return true;
106		default:
107			if (!fCurrentEntry)
108				return false;
109			*name = fCurrentEntry->GetName();
110			*node = fCurrentEntry->GetNode();
111			return true;
112	}
113}
114
115// GetCurrentEntry
116VirtualDirEntry*
117VirtualDirIterator::GetCurrentEntry() const
118{
119	return fCurrentEntry;
120}
121
122// NextEntry
123void
124VirtualDirIterator::NextEntry()
125{
126	if (!fDirectory)
127		return;
128	switch (fState) {
129		case STATE_DOT:
130			fState = STATE_DOT_DOT;
131			break;
132		case STATE_DOT_DOT:
133			fState = STATE_OTHERS;
134			fCurrentEntry = fDirectory->GetFirstEntry();
135			break;
136		default:
137			if (fCurrentEntry)
138				fCurrentEntry = fDirectory->GetNextEntry(fCurrentEntry);
139			break;
140	}
141}
142
143// Rewind
144void
145VirtualDirIterator::Rewind()
146{
147	fState = STATE_DOT;
148	fCurrentEntry = NULL;
149}
150
151
152// #pragma mark -
153
154// constructor
155VirtualDir::VirtualDir(Volume* volume, vnode_id nodeID)
156	: Node(volume, nodeID),
157	  fParent(NULL),
158	  fCreationTime(0),
159	  fEntries(),
160	  fEntryList(),
161	  fIterators()
162{
163}
164
165// destructor
166VirtualDir::~VirtualDir()
167{
168	while (VirtualDirEntry* entry = GetFirstEntry())
169		RemoveEntry(entry->GetName());
170}
171
172// InitCheck
173status_t
174VirtualDir::InitCheck() const
175{
176	return fEntries.InitCheck();
177}
178
179// SetParent
180void
181VirtualDir::SetParent(VirtualDir* parent)
182{
183	fParent = parent;
184}
185
186// GetParent
187VirtualDir*
188VirtualDir::GetParent() const
189{
190	return fParent;
191}
192
193// GetCreationTime
194time_t
195VirtualDir::GetCreationTime() const
196{
197	return fCreationTime;
198}
199
200// AddEntry
201status_t
202VirtualDir::AddEntry(const char* name, Node* child)
203{
204	if (!name || !child || fEntries.ContainsKey(name))
205		return B_BAD_VALUE;
206
207	// create an entry
208	VirtualDirEntry* entry = new(std::nothrow) VirtualDirEntry;
209	if (!entry)
210		return B_NO_MEMORY;
211	ObjectDeleter<VirtualDirEntry> entryDeleter(entry);
212	status_t error = entry->SetTo(name, child);
213	if (error != B_OK)
214		return error;
215
216	// add the entry
217	error = fEntries.Put(name, entry);
218	if (error != B_OK)
219		return error;
220	fEntryList.Insert(entry);
221	entryDeleter.Detach();
222
223	// TODO: That's not so nice. Check whether better to move the fParent
224	// property to Node.
225	if (VirtualDir* childDir = dynamic_cast<VirtualDir*>(child))
226		childDir->SetParent(this);
227
228	return error;
229}
230
231// RemoveEntry
232Node*
233VirtualDir::RemoveEntry(const char* name)
234{
235	if (!name)
236		return NULL;
237
238	Node* child = NULL;
239	VirtualDirEntry* entry = fEntries.Remove(name);
240	if (entry) {
241		child = entry->GetNode();
242		// update the directory iterators pointing to the removed entry
243		for (VirtualDirIterator* iterator = fIterators.First();
244			 iterator;
245			 iterator = fIterators.GetNext(iterator)) {
246			if (iterator->GetCurrentEntry() == entry)
247				iterator->NextEntry();
248		}
249
250		// remove the entry completely
251		fEntryList.Remove(entry);
252		delete entry;
253
254		// TODO: See AddEntry().
255		if (VirtualDir* childDir = dynamic_cast<VirtualDir*>(child))
256			childDir->SetParent(NULL);
257	}
258	return child;
259}
260
261// GetEntry
262VirtualDirEntry*
263VirtualDir::GetEntry(const char* name) const
264{
265	if (!name)
266		return NULL;
267
268	return fEntries.Get(name);
269}
270
271// GetChildNode
272Node*
273VirtualDir::GetChildNode(const char* name) const
274{
275	if (VirtualDirEntry* entry = GetEntry(name))
276		return entry->GetNode();
277	return NULL;
278}
279
280// GetFirstEntry
281VirtualDirEntry*
282VirtualDir::GetFirstEntry() const
283{
284	return fEntryList.First();
285}
286
287// GetNextEntry
288VirtualDirEntry*
289VirtualDir::GetNextEntry(VirtualDirEntry* entry) const
290{
291	if (!entry)
292		return NULL;
293	return fEntryList.GetNext(entry);
294}
295
296// AddDirIterator
297void
298VirtualDir::AddDirIterator(VirtualDirIterator* iterator)
299{
300	if (!iterator)
301		return;
302
303	fIterators.Insert(iterator);
304}
305
306// RemoveDirIterator
307void
308VirtualDir::RemoveDirIterator(VirtualDirIterator* iterator)
309{
310	if (!iterator)
311		return;
312
313	fIterators.Remove(iterator);
314}
315