xref: /haiku/src/kits/tracker/EntryIterator.cpp (revision a30a4a41f948ebb03b95dab065a27a584ac0c97a)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 
35 #include <Debug.h>
36 #include <Entry.h>
37 #include <Path.h>
38 
39 #include <new>
40 #include <string.h>
41 
42 #include "EntryIterator.h"
43 #include "NodeWalker.h"
44 #include "ObjectList.h"
45 
46 
47 TWalkerWrapper::TWalkerWrapper(BTrackerPrivate::TWalker* walker)
48 	:
49 	fWalker(walker),
50 	fStatus(B_OK)
51 {
52 }
53 
54 
55 TWalkerWrapper::~TWalkerWrapper()
56 {
57 	delete fWalker;
58 }
59 
60 
61 status_t
62 TWalkerWrapper::InitCheck() const
63 {
64 	return fStatus;
65 }
66 
67 
68 status_t
69 TWalkerWrapper::GetNextEntry(BEntry* entry, bool traverse)
70 {
71 	fStatus = fWalker->GetNextEntry(entry, traverse);
72 	return fStatus;
73 }
74 
75 
76 status_t
77 TWalkerWrapper::GetNextRef(entry_ref* ref)
78 {
79 	fStatus = fWalker->GetNextRef(ref);
80 	return fStatus;
81 }
82 
83 
84 int32
85 TWalkerWrapper::GetNextDirents(struct dirent* buffer, size_t length,
86 	int32 count)
87 {
88 	int32 result = fWalker->GetNextDirents(buffer, length, count);
89 	fStatus = result < B_OK ? result : (result ? B_OK : B_ENTRY_NOT_FOUND);
90 	return result;
91 }
92 
93 
94 status_t
95 TWalkerWrapper::Rewind()
96 {
97 	return fWalker->Rewind();
98 }
99 
100 
101 int32
102 TWalkerWrapper::CountEntries()
103 {
104 	return fWalker->CountEntries();
105 }
106 
107 
108 //	#pragma mark -
109 
110 
111 EntryListBase::EntryListBase()
112 	:	fStatus(B_OK)
113 {
114 }
115 
116 
117 status_t
118 EntryListBase::InitCheck() const
119 {
120 	 return fStatus;
121 }
122 
123 
124 dirent*
125 EntryListBase::Next(dirent* ent)
126 {
127 	return (dirent*)((char*)ent + ent->d_reclen);
128 }
129 
130 
131 //	#pragma mark -
132 
133 
134 CachedEntryIterator::CachedEntryIterator(BEntryList* iterator,
135 		int32 numEntries, bool sortInodes)
136 	:
137 	fIterator(iterator),
138 	fEntryRefBuffer(NULL),
139 	fCacheSize(numEntries),
140 	fNumEntries(0),
141 	fIndex(0),
142 	fDirentBuffer(NULL),
143 	fCurrentDirent(NULL),
144 	fSortInodes(sortInodes),
145 	fSortedList(NULL),
146 	fEntryBuffer(NULL)
147 {
148 }
149 
150 
151 CachedEntryIterator::~CachedEntryIterator()
152 {
153 	delete[] fEntryRefBuffer;
154 	free(fDirentBuffer);
155 	delete fSortedList;
156 	delete[] fEntryBuffer;
157 }
158 
159 
160 status_t
161 CachedEntryIterator::GetNextEntry(BEntry* result, bool traverse)
162 {
163 	ASSERT(!fDirentBuffer);
164 	ASSERT(!fEntryRefBuffer);
165 
166 	if (!fEntryBuffer) {
167 		fEntryBuffer = new BEntry [fCacheSize];
168 		ASSERT(fIndex == 0 && fNumEntries == 0);
169 	}
170 	if (fIndex >= fNumEntries) {
171 		// fill up the buffer or stop if error; keep error around
172 		// and return it when appropriate
173 		fStatus = B_OK;
174 		for (fNumEntries = 0; fNumEntries < fCacheSize; fNumEntries++) {
175 			fStatus = fIterator->GetNextEntry(&fEntryBuffer[fNumEntries],
176 				traverse);
177 			if (fStatus != B_OK)
178 				break;
179 		}
180 		fIndex = 0;
181 	}
182 	*result = fEntryBuffer[fIndex++];
183 	if (fIndex > fNumEntries) {
184 		// we are at the end of the cache we loaded up, time to return
185 		// an error, if we had one
186 		return fStatus;
187 	}
188 
189 	return B_OK;
190 }
191 
192 
193 status_t
194 CachedEntryIterator::GetNextRef(entry_ref* ref)
195 {
196 	ASSERT(!fDirentBuffer);
197 	ASSERT(!fEntryBuffer);
198 
199 	if (!fEntryRefBuffer) {
200 		fEntryRefBuffer = new entry_ref[fCacheSize];
201 		ASSERT(fIndex == 0 && fNumEntries == 0);
202 	}
203 
204 	if (fIndex >= fNumEntries) {
205 		// fill up the buffer or stop if error; keep error around
206 		// and return it when appropriate
207 		fStatus = B_OK;
208 		for (fNumEntries = 0; fNumEntries < fCacheSize; fNumEntries++) {
209 			fStatus = fIterator->GetNextRef(&fEntryRefBuffer[fNumEntries]);
210 			if (fStatus != B_OK)
211 				break;
212 		}
213 		fIndex = 0;
214 	}
215 	*ref = fEntryRefBuffer[fIndex++];
216 	if (fIndex > fNumEntries)
217 		// we are at the end of the cache we loaded up, time to return
218 		// an error, if we had one
219 		return fStatus;
220 
221 	return B_OK;
222 }
223 
224 
225 /*static*/ int
226 CachedEntryIterator::_CompareInodes(const dirent* ent1, const dirent* ent2)
227 {
228 	if (ent1->d_ino < ent2->d_ino)
229 		return -1;
230 	if (ent1->d_ino == ent2->d_ino)
231 		return 0;
232 
233 	return 1;
234 }
235 
236 
237 int32
238 CachedEntryIterator::GetNextDirents(struct dirent* ent, size_t size,
239 	int32 count)
240 {
241 	ASSERT(!fEntryRefBuffer);
242 	if (!fDirentBuffer) {
243 		fDirentBuffer = (dirent*)malloc(kDirentBufferSize);
244 		ASSERT(fIndex == 0 && fNumEntries == 0);
245 		ASSERT(size > sizeof(dirent) + B_FILE_NAME_LENGTH);
246 	}
247 
248 	if (!count)
249 		return 0;
250 
251 	if (fIndex >= fNumEntries) {
252 		// we are out of stock, cache em up
253 		fCurrentDirent = fDirentBuffer;
254 		int32 bufferRemain = kDirentBufferSize;
255 		for (fNumEntries = 0; fNumEntries < fCacheSize; ) {
256 			int32 count = fIterator->GetNextDirents(fCurrentDirent,
257 				bufferRemain, 1);
258 
259 			if (count <= 0)
260 				break;
261 
262 			fNumEntries += count;
263 
264 			int32 currentDirentSize = fCurrentDirent->d_reclen;
265 			bufferRemain -= currentDirentSize;
266 			ASSERT(bufferRemain >= 0);
267 
268 			if ((size_t)bufferRemain
269 					< (sizeof(dirent) + B_FILE_NAME_LENGTH)) {
270 				// cant fit a big entryRef in the buffer, just bail
271 				// and start from scratch
272 				break;
273 			}
274 
275 			fCurrentDirent
276 				= (dirent*)((char*)fCurrentDirent + currentDirentSize);
277 		}
278 		fCurrentDirent = fDirentBuffer;
279 		if (fSortInodes) {
280 			if (!fSortedList)
281 				fSortedList = new BObjectList<dirent>(fCacheSize);
282 			else
283 				fSortedList->MakeEmpty();
284 
285 			for (int32 count = 0; count < fNumEntries; count++) {
286 				fSortedList->AddItem(fCurrentDirent, 0);
287 				fCurrentDirent = Next(fCurrentDirent);
288 			}
289 			fSortedList->SortItems(&_CompareInodes);
290 			fCurrentDirent = fDirentBuffer;
291 		}
292 		fIndex = 0;
293 	}
294 	if (fIndex >= fNumEntries) {
295 		// we are done, no more dirents left
296 		return 0;
297 	}
298 
299 	if (fSortInodes)
300 		fCurrentDirent = fSortedList->ItemAt(fIndex);
301 
302 	fIndex++;
303 	uint32 currentDirentSize = fCurrentDirent->d_reclen;
304 	ASSERT(currentDirentSize <= size);
305 	if (currentDirentSize > size)
306 		return 0;
307 
308 	memcpy(ent, fCurrentDirent, currentDirentSize);
309 
310 	if (!fSortInodes)
311 		fCurrentDirent = (dirent*)((char*)fCurrentDirent + currentDirentSize);
312 
313 	return 1;
314 }
315 
316 
317 status_t
318 CachedEntryIterator::Rewind()
319 {
320 	fIndex = 0;
321 	fNumEntries = 0;
322 	fCurrentDirent = NULL;
323 	fStatus = B_OK;
324 
325 	delete fSortedList;
326 	fSortedList = NULL;
327 
328 	return fIterator->Rewind();
329 }
330 
331 
332 int32
333 CachedEntryIterator::CountEntries()
334 {
335 	return fIterator->CountEntries();
336 }
337 
338 
339 void
340 CachedEntryIterator::SetTo(BEntryList* iterator)
341 {
342 	fIndex = 0;
343 	fNumEntries = 0;
344 	fStatus = B_OK;
345 	fIterator = iterator;
346 }
347 
348 
349 //	#pragma mark -
350 
351 
352 CachedDirectoryEntryList::CachedDirectoryEntryList(const BDirectory &dir)
353 	: CachedEntryIterator(0, 40, true),
354 	fDir(dir)
355 {
356 	fStatus = fDir.InitCheck();
357 	SetTo(&fDir);
358 }
359 
360 
361 CachedDirectoryEntryList::~CachedDirectoryEntryList()
362 {
363 }
364 
365 
366 //	#pragma mark -
367 
368 
369 DirectoryEntryList::DirectoryEntryList(const BDirectory &dir)
370 	:
371 	fDir(dir)
372 {
373 	fStatus = fDir.InitCheck();
374 }
375 
376 
377 status_t
378 DirectoryEntryList::GetNextEntry(BEntry* entry, bool traverse)
379 {
380 	fStatus = fDir.GetNextEntry(entry, traverse);
381 	return fStatus;
382 }
383 
384 
385 status_t
386 DirectoryEntryList::GetNextRef(entry_ref* ref)
387 {
388 	fStatus = fDir.GetNextRef(ref);
389 	return fStatus;
390 }
391 
392 
393 int32
394 DirectoryEntryList::GetNextDirents(struct dirent* buffer, size_t length,
395 	int32 count)
396 {
397 	fStatus = fDir.GetNextDirents(buffer, length, count);
398 	return fStatus;
399 }
400 
401 
402 status_t
403 DirectoryEntryList::Rewind()
404 {
405 	fStatus = fDir.Rewind();
406 	return fStatus;
407 }
408 
409 
410 int32
411 DirectoryEntryList::CountEntries()
412 {
413 	return fDir.CountEntries();
414 }
415 
416 
417 //	#pragma mark -
418 
419 
420 EntryIteratorList::EntryIteratorList()
421 	:
422 	fList(5, true),
423 	fCurrentIndex(0)
424 {
425 }
426 
427 
428 EntryIteratorList::~EntryIteratorList()
429 {
430 	int32 count = fList.CountItems();
431 	for (;count; count--) {
432 		// workaround for BEntryList not having a proper destructor
433 		BEntryList* entry = fList.RemoveItemAt(count - 1);
434 		EntryListBase* fixedEntry = dynamic_cast<EntryListBase*>(entry);
435 
436 		if (fixedEntry)
437 			delete fixedEntry;
438 		else
439 			delete entry;
440 	}
441 }
442 
443 
444 void
445 EntryIteratorList::AddItem(BEntryList* walker)
446 {
447 	fList.AddItem(walker);
448 }
449 
450 
451 status_t
452 EntryIteratorList::GetNextEntry(BEntry* entry, bool traverse)
453 {
454 	while (true) {
455 		if (fCurrentIndex >= fList.CountItems()) {
456 			fStatus = B_ENTRY_NOT_FOUND;
457 			break;
458 		}
459 
460 		fStatus = fList.ItemAt(fCurrentIndex)->GetNextEntry(entry, traverse);
461 		if (fStatus != B_ENTRY_NOT_FOUND)
462 			break;
463 
464 		fCurrentIndex++;
465 	}
466 	return fStatus;
467 }
468 
469 
470 status_t
471 EntryIteratorList::GetNextRef(entry_ref* ref)
472 {
473 	while (true) {
474 		if (fCurrentIndex >= fList.CountItems()) {
475 			fStatus = B_ENTRY_NOT_FOUND;
476 			break;
477 		}
478 
479 		fStatus = fList.ItemAt(fCurrentIndex)->GetNextRef(ref);
480 		if (fStatus != B_ENTRY_NOT_FOUND)
481 			break;
482 
483 		fCurrentIndex++;
484 	}
485 	return fStatus;
486 }
487 
488 
489 int32
490 EntryIteratorList::GetNextDirents(struct dirent* buffer, size_t length,
491 	int32 count)
492 {
493 	int32 result = 0;
494 	while (true) {
495 		if (fCurrentIndex >= fList.CountItems()) {
496 			fStatus = B_ENTRY_NOT_FOUND;
497 			break;
498 		}
499 
500 		result = fList.ItemAt(fCurrentIndex)->GetNextDirents(buffer, length,
501 			count);
502 		if (result > 0) {
503 			fStatus = B_OK;
504 			break;
505 		}
506 
507 		fCurrentIndex++;
508 	}
509 	return result;
510 }
511 
512 
513 status_t
514 EntryIteratorList::Rewind()
515 {
516 	fCurrentIndex = 0;
517 	int32 count = fList.CountItems();
518 	for (int32 index = 0; index < count; index++)
519 		fStatus = fList.ItemAt(index)->Rewind();
520 
521 	return fStatus;
522 }
523 
524 
525 int32
526 EntryIteratorList::CountEntries()
527 {
528 	int32 result = 0;
529 
530 	int32 count = fList.CountItems();
531 	for (int32 index = 0; index < count; index++)
532 		result += fList.ItemAt(fCurrentIndex)->CountEntries();
533 
534 	return result;
535 }
536 
537 
538 //	#pragma mark -
539 
540 
541 CachedEntryIteratorList::CachedEntryIteratorList(bool sortInodes)
542 	: CachedEntryIterator(NULL, 10, sortInodes)
543 {
544 	fStatus = B_OK;
545 	SetTo(&fIteratorList);
546 }
547 
548 
549 void
550 CachedEntryIteratorList::AddItem(BEntryList* walker)
551 {
552 	fIteratorList.AddItem(walker);
553 }
554