HaikuDepot: notify work status from main window
[haiku.git] / src / kits / storage / MergedDirectory.cpp
blob90519ed3e84fb03c746acbe7dcc9510b60ac8505
1 /*
2 * Copyright 2013, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Ingo Weinhold <ingo_weinhold@gmx.de>
7 */
10 #include <MergedDirectory.h>
12 #include <string.h>
14 #include <new>
15 #include <set>
16 #include <string>
18 #include <Directory.h>
19 #include <Entry.h>
21 #include <AutoDeleter.h>
23 #include "storage_support.h"
26 struct BMergedDirectory::EntryNameSet : std::set<std::string> {
30 BMergedDirectory::BMergedDirectory(BPolicy policy)
32 BEntryList(),
33 fDirectories(10, true),
34 fPolicy(policy),
35 fDirectoryIndex(0),
36 fVisitedEntries(NULL)
41 BMergedDirectory::~BMergedDirectory()
43 delete fVisitedEntries;
47 status_t
48 BMergedDirectory::Init()
50 delete fVisitedEntries;
51 fDirectories.MakeEmpty(true);
53 fVisitedEntries = new(std::nothrow) EntryNameSet;
54 return fVisitedEntries != NULL ? B_OK : B_NO_MEMORY;
58 BMergedDirectory::BPolicy
59 BMergedDirectory::Policy() const
61 return fPolicy;
65 void
66 BMergedDirectory::SetPolicy(BPolicy policy)
68 fPolicy = policy;
72 status_t
73 BMergedDirectory::AddDirectory(BDirectory* directory)
75 return fDirectories.AddItem(directory) ? B_OK : B_NO_MEMORY;
79 status_t
80 BMergedDirectory::AddDirectory(const char* path)
82 BDirectory* directory = new(std::nothrow) BDirectory(path);
83 if (directory == NULL)
84 return B_NO_MEMORY;
85 ObjectDeleter<BDirectory> directoryDeleter(directory);
87 if (directory->InitCheck() != B_OK)
88 return directory->InitCheck();
90 status_t error = AddDirectory(directory);
91 if (error != B_OK)
92 return error;
93 directoryDeleter.Detach();
95 return B_OK;
99 status_t
100 BMergedDirectory::GetNextEntry(BEntry* entry, bool traverse)
102 entry_ref ref;
103 status_t error = GetNextRef(&ref);
104 if (error != B_OK)
105 return error;
107 return entry->SetTo(&ref, traverse);
111 status_t
112 BMergedDirectory::GetNextRef(entry_ref* ref)
114 BPrivate::Storage::LongDirEntry entry;
115 int32 result = GetNextDirents(&entry, sizeof(entry), 1);
116 if (result < 0)
117 return result;
118 if (result == 0)
119 return B_ENTRY_NOT_FOUND;
121 ref->device = entry.d_pdev;
122 ref->directory = entry.d_pino;
123 return ref->set_name(entry.d_name);
127 int32
128 BMergedDirectory::GetNextDirents(struct dirent* direntBuffer, size_t bufferSize,
129 int32 maxEntries)
131 if (maxEntries <= 0)
132 return B_BAD_VALUE;
134 while (fDirectoryIndex < fDirectories.CountItems()) {
135 int32 count = fDirectories.ItemAt(fDirectoryIndex)->GetNextDirents(
136 direntBuffer, bufferSize, 1);
137 if (count < 0)
138 return count;
139 if (count == 0) {
140 fDirectoryIndex++;
141 continue;
144 if (strcmp(direntBuffer->d_name, ".") == 0
145 || strcmp(direntBuffer->d_name, "..") == 0) {
146 continue;
149 switch (fPolicy) {
150 case B_ALLOW_DUPLICATES:
151 return count;
153 case B_ALWAYS_FIRST:
154 case B_COMPARE:
155 if (fVisitedEntries != NULL
156 && fVisitedEntries->find(direntBuffer->d_name)
157 != fVisitedEntries->end()) {
158 continue;
161 if (fVisitedEntries != NULL) {
162 try {
163 fVisitedEntries->insert(direntBuffer->d_name);
164 } catch (std::bad_alloc&) {
165 return B_NO_MEMORY;
169 if (fPolicy == B_COMPARE)
170 _FindBestEntry(direntBuffer);
171 return 1;
175 return 0;
179 status_t
180 BMergedDirectory::Rewind()
182 for (int32 i = 0; BDirectory* directory = fDirectories.ItemAt(i); i++)
183 directory->Rewind();
185 if (fVisitedEntries != NULL)
186 fVisitedEntries->clear();
188 fDirectoryIndex = 0;
189 return B_OK;
193 int32
194 BMergedDirectory::CountEntries()
196 int32 count = 0;
197 char buffer[sizeof(dirent) + B_FILE_NAME_LENGTH];
198 while (GetNextDirents((dirent*)&buffer, sizeof(buffer), 1) == 1)
199 count++;
200 return count;
204 bool
205 BMergedDirectory::ShallPreferFirstEntry(const entry_ref& entry1, int32 index1,
206 const entry_ref& entry2, int32 index2)
208 // That's basically B_ALWAYS_FIRST semantics. A derived class will implement
209 // the desired semantics.
210 return true;
214 void
215 BMergedDirectory::_FindBestEntry(dirent* direntBuffer)
217 entry_ref bestEntry(direntBuffer->d_pdev, direntBuffer->d_pino,
218 direntBuffer->d_name);
219 if (bestEntry.name == NULL)
220 return;
221 int32 bestIndex = fDirectoryIndex;
223 int32 directoryCount = fDirectories.CountItems();
224 for (int32 i = fDirectoryIndex + 1; i < directoryCount; i++) {
225 BEntry entry(fDirectories.ItemAt(i), bestEntry.name);
226 struct stat st;
227 entry_ref ref;
228 if (entry.GetStat(&st) == B_OK && entry.GetRef(&ref) == B_OK
229 && !ShallPreferFirstEntry(bestEntry, bestIndex, ref, i)) {
230 direntBuffer->d_pdev = ref.device;
231 direntBuffer->d_pino = ref.directory;
232 direntBuffer->d_dev = st.st_dev;
233 direntBuffer->d_ino = st.st_ino;
234 bestEntry.device = ref.device;
235 bestEntry.directory = ref.directory;
236 bestIndex = i;