1/*
2 * Copyright 2013, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Ingo Weinhold, ingo_weinhold@gmx.de
7 */
8
9
10#include "VirtualDirectoryEntryList.h"
11
12#include <AutoLocker.h>
13#include <storage_support.h>
14
15#include "Model.h"
16#include "VirtualDirectoryManager.h"
17
18
19namespace BPrivate {
20
21//	#pragma mark - VirtualDirectoryEntryList
22
23
24VirtualDirectoryEntryList::VirtualDirectoryEntryList(Model* model)
25	:
26	EntryListBase(),
27	fDefinitionFileRef(),
28	fMergedDirectory(BMergedDirectory::B_ALWAYS_FIRST)
29{
30	VirtualDirectoryManager* manager = VirtualDirectoryManager::Instance();
31	if (manager == NULL) {
32		fStatus = B_NO_MEMORY;
33		return;
34	}
35
36	AutoLocker<VirtualDirectoryManager> managerLocker(manager);
37	BStringList directoryPaths;
38	fStatus = manager->ResolveDirectoryPaths(*model->NodeRef(),
39		*model->EntryRef(), directoryPaths, &fDefinitionFileRef);
40	if (fStatus != B_OK)
41		return;
42
43	fStatus = _InitMergedDirectory(directoryPaths);
44}
45
46
47VirtualDirectoryEntryList::VirtualDirectoryEntryList(
48	const node_ref& definitionFileRef, const BStringList& directoryPaths)
49	:
50	EntryListBase(),
51	fDefinitionFileRef(definitionFileRef),
52	fMergedDirectory(BMergedDirectory::B_ALWAYS_FIRST)
53{
54	fStatus = _InitMergedDirectory(directoryPaths);
55}
56
57
58VirtualDirectoryEntryList::~VirtualDirectoryEntryList()
59{
60}
61
62
63status_t
64VirtualDirectoryEntryList::InitCheck() const
65{
66	return EntryListBase::InitCheck();
67}
68
69
70status_t
71VirtualDirectoryEntryList::GetNextEntry(BEntry* entry, bool traverse)
72{
73	entry_ref ref;
74	status_t error = GetNextRef(&ref);
75	if (error != B_OK)
76		return error;
77
78	return entry->SetTo(&ref, traverse);
79}
80
81
82status_t
83VirtualDirectoryEntryList::GetNextRef(entry_ref* ref)
84{
85	BPrivate::Storage::LongDirEntry longEntry;
86	struct dirent* entry = longEntry.dirent();
87	int32 result = GetNextDirents(entry, sizeof(longEntry), 1);
88	if (result < 0)
89		return result;
90	if (result == 0)
91		return B_ENTRY_NOT_FOUND;
92
93	ref->device = entry->d_pdev;
94	ref->directory = entry->d_pino;
95	return ref->set_name(entry->d_name);
96}
97
98
99int32
100VirtualDirectoryEntryList::GetNextDirents(struct dirent* buffer, size_t length,
101	int32 count)
102{
103	if (count > 1)
104		count = 1;
105
106	int32 countRead = fMergedDirectory.GetNextDirents(buffer, length, count);
107	if (countRead != 1)
108		return countRead;
109
110	// deal with directories
111	entry_ref ref;
112	ref.device = buffer->d_pdev;
113	ref.directory = buffer->d_pino;
114	if (ref.set_name(buffer->d_name) == B_OK && BEntry(&ref).IsDirectory()) {
115		if (VirtualDirectoryManager* manager
116				= VirtualDirectoryManager::Instance()) {
117			AutoLocker<VirtualDirectoryManager> managerLocker(manager);
118			manager->TranslateDirectoryEntry(fDefinitionFileRef, buffer);
119		}
120	}
121
122	return countRead;
123}
124
125
126status_t
127VirtualDirectoryEntryList::Rewind()
128{
129	return fMergedDirectory.Rewind();
130}
131
132
133int32
134VirtualDirectoryEntryList::CountEntries()
135{
136	return 0;
137}
138
139
140status_t
141VirtualDirectoryEntryList::_InitMergedDirectory(
142	const BStringList& directoryPaths)
143{
144	status_t error = fMergedDirectory.Init();
145	if (error != B_OK)
146		return error;
147
148	int32 count = directoryPaths.CountStrings();
149	for (int32 i = 0; i < count; i++)
150		fMergedDirectory.AddDirectory(directoryPaths.StringAt(i));
151
152	return B_OK;
153}
154
155} // namespace BPrivate
156