xref: /haiku/src/kits/tracker/EntryIterator.cpp (revision 02b72520b683730ce13b30416576ded451fb2843)
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 
36 #include <Debug.h>
37 #include <Entry.h>
38 #include <ObjectList.h>
39 #include <Path.h>
40 
41 #include <new>
42 #include <string.h>
43 
44 #include "EntryIterator.h"
45 
46 
47 //	#pragma mark - TWalkerWrapper
48 
49 
50 TWalkerWrapper::TWalkerWrapper(BTrackerPrivate::TWalker* walker)
51 	:
52 	fWalker(walker),
53 	fStatus(B_OK)
54 {
55 }
56 
57 
58 TWalkerWrapper::~TWalkerWrapper()
59 {
60 	delete fWalker;
61 }
62 
63 
64 status_t
65 TWalkerWrapper::InitCheck() const
66 {
67 	return fStatus;
68 }
69 
70 
71 status_t
72 TWalkerWrapper::GetNextEntry(BEntry* entry, bool traverse)
73 {
74 	fStatus = fWalker->GetNextEntry(entry, traverse);
75 
76 	return fStatus;
77 }
78 
79 
80 status_t
81 TWalkerWrapper::GetNextRef(entry_ref* ref)
82 {
83 	fStatus = fWalker->GetNextRef(ref);
84 
85 	return fStatus;
86 }
87 
88 
89 int32
90 TWalkerWrapper::GetNextDirents(struct dirent* buffer, size_t length,
91 	int32 count)
92 {
93 	int32 result = fWalker->GetNextDirents(buffer, length, count);
94 	fStatus = result < B_OK ? result : (result ? B_OK : B_ENTRY_NOT_FOUND);
95 
96 	return result;
97 }
98 
99 
100 status_t
101 TWalkerWrapper::Rewind()
102 {
103 	return fWalker->Rewind();
104 }
105 
106 
107 int32
108 TWalkerWrapper::CountEntries()
109 {
110 	return fWalker->CountEntries();
111 }
112 
113 
114 //	#pragma mark - EntryListBase
115 
116 
117 EntryListBase::EntryListBase()
118 	:
119 	fStatus(B_OK)
120 {
121 }
122 
123 
124 status_t
125 EntryListBase::InitCheck() const
126 {
127 	 return fStatus;
128 }
129 
130 
131 dirent*
132 EntryListBase::Next(dirent* ent)
133 {
134 	return (dirent*)((char*)ent + ent->d_reclen);
135 }
136 
137 
138 //	#pragma mark - CachedEntryIterator
139 
140 
141 CachedEntryIterator::CachedEntryIterator(BEntryList* iterator,
142 	int32 numEntries, bool sortInodes)
143 	:
144 	fIterator(iterator),
145 	fEntryRefBuffer(NULL),
146 	fCacheSize(numEntries),
147 	fNumEntries(0),
148 	fIndex(0),
149 	fDirentBuffer(NULL),
150 	fCurrentDirent(NULL),
151 	fSortInodes(sortInodes),
152 	fSortedList(NULL),
153 	fEntryBuffer(NULL)
154 {
155 }
156 
157 
158 CachedEntryIterator::~CachedEntryIterator()
159 {
160 	delete[] fEntryRefBuffer;
161 	free(fDirentBuffer);
162 	delete fSortedList;
163 	delete[] fEntryBuffer;
164 }
165 
166 
167 status_t
168 CachedEntryIterator::GetNextEntry(BEntry* result, bool traverse)
169 {
170 	ASSERT(fDirentBuffer != NULL);
171 	ASSERT(fEntryRefBuffer != NULL);
172 
173 	if (fEntryBuffer == NULL) {
174 		fEntryBuffer = new BEntry [fCacheSize];
175 		ASSERT(fIndex == 0 && fNumEntries == 0);
176 	}
177 
178 	if (fIndex >= fNumEntries) {
179 		// fill up the buffer or stop if error; keep error around
180 		// and return it when appropriate
181 		fStatus = B_OK;
182 		for (fNumEntries = 0; fNumEntries < fCacheSize; fNumEntries++) {
183 			fStatus = fIterator->GetNextEntry(&fEntryBuffer[fNumEntries],
184 				traverse);
185 			if (fStatus != B_OK)
186 				break;
187 		}
188 		fIndex = 0;
189 	}
190 
191 	*result = fEntryBuffer[fIndex++];
192 	if (fIndex > fNumEntries) {
193 		// we are at the end of the cache we loaded up, time to return
194 		// an error, if we had one
195 		return fStatus;
196 	}
197 
198 	return B_OK;
199 }
200 
201 
202 status_t
203 CachedEntryIterator::GetNextRef(entry_ref* ref)
204 {
205 	ASSERT(fDirentBuffer == NULL);
206 	ASSERT(fEntryBuffer == NULL);
207 
208 	if (fEntryRefBuffer == NULL) {
209 		fEntryRefBuffer = new entry_ref[fCacheSize];
210 		ASSERT(fIndex == 0 && fNumEntries == 0);
211 	}
212 
213 	if (fIndex >= fNumEntries) {
214 		// fill up the buffer or stop if error; keep error around
215 		// and return it when appropriate
216 		fStatus = B_OK;
217 		for (fNumEntries = 0; fNumEntries < fCacheSize; fNumEntries++) {
218 			fStatus = fIterator->GetNextRef(&fEntryRefBuffer[fNumEntries]);
219 			if (fStatus != B_OK)
220 				break;
221 		}
222 		fIndex = 0;
223 	}
224 
225 	*ref = fEntryRefBuffer[fIndex++];
226 	if (fIndex > fNumEntries) {
227 		// we are at the end of the cache we loaded up, time to return
228 		// an error, if we had one
229 		return fStatus;
230 	}
231 
232 	return B_OK;
233 }
234 
235 
236 /*static*/ int
237 CachedEntryIterator::_CompareInodes(const dirent* ent1, const dirent* ent2)
238 {
239 	if (ent1->d_ino < ent2->d_ino)
240 		return -1;
241 
242 	if (ent1->d_ino == ent2->d_ino)
243 		return 0;
244 
245 	return 1;
246 }
247 
248 
249 int32
250 CachedEntryIterator::GetNextDirents(struct dirent* ent, size_t size,
251 	int32 count)
252 {
253 	ASSERT(fEntryRefBuffer == NULL);
254 	if (fDirentBuffer == NULL) {
255 		fDirentBuffer = (dirent*)malloc(kDirentBufferSize);
256 		ASSERT(fIndex == 0 && fNumEntries == 0);
257 		ASSERT(size > sizeof(dirent) + B_FILE_NAME_LENGTH);
258 	}
259 
260 	if (count == 0)
261 		return 0;
262 
263 	if (fIndex >= fNumEntries) {
264 		// we are out of stock, cache em up
265 		fCurrentDirent = fDirentBuffer;
266 		int32 bufferRemain = kDirentBufferSize;
267 		for (fNumEntries = 0; fNumEntries < fCacheSize; ) {
268 			int32 count = fIterator->GetNextDirents(fCurrentDirent,
269 				bufferRemain, 1);
270 
271 			if (count <= 0)
272 				break;
273 
274 			fNumEntries += count;
275 
276 			int32 currentDirentSize = fCurrentDirent->d_reclen;
277 			bufferRemain -= currentDirentSize;
278 			ASSERT(bufferRemain >= 0);
279 
280 			if ((size_t)bufferRemain
281 					< (sizeof(dirent) + B_FILE_NAME_LENGTH)) {
282 				// cant fit a big entryRef in the buffer, just bail
283 				// and start from scratch
284 				break;
285 			}
286 
287 			fCurrentDirent
288 				= (dirent*)((char*)fCurrentDirent + currentDirentSize);
289 		}
290 		fCurrentDirent = fDirentBuffer;
291 		if (fSortInodes) {
292 			if (!fSortedList)
293 				fSortedList = new BObjectList<dirent>(fCacheSize);
294 			else
295 				fSortedList->MakeEmpty();
296 
297 			for (int32 count = 0; count < fNumEntries; count++) {
298 				fSortedList->AddItem(fCurrentDirent, 0);
299 				fCurrentDirent = Next(fCurrentDirent);
300 			}
301 			fSortedList->SortItems(&_CompareInodes);
302 			fCurrentDirent = fDirentBuffer;
303 		}
304 		fIndex = 0;
305 	}
306 	if (fIndex >= fNumEntries) {
307 		// we are done, no more dirents left
308 		return 0;
309 	}
310 
311 	if (fSortInodes)
312 		fCurrentDirent = fSortedList->ItemAt(fIndex);
313 
314 	fIndex++;
315 	uint32 currentDirentSize = fCurrentDirent->d_reclen;
316 	ASSERT(currentDirentSize <= size);
317 	if (currentDirentSize > size)
318 		return 0;
319 
320 	memcpy(ent, fCurrentDirent, currentDirentSize);
321 
322 	if (!fSortInodes)
323 		fCurrentDirent = (dirent*)((char*)fCurrentDirent + currentDirentSize);
324 
325 	return 1;
326 }
327 
328 
329 status_t
330 CachedEntryIterator::Rewind()
331 {
332 	fIndex = 0;
333 	fNumEntries = 0;
334 	fCurrentDirent = NULL;
335 	fStatus = B_OK;
336 
337 	delete fSortedList;
338 	fSortedList = NULL;
339 
340 	return fIterator->Rewind();
341 }
342 
343 
344 int32
345 CachedEntryIterator::CountEntries()
346 {
347 	return fIterator->CountEntries();
348 }
349 
350 
351 void
352 CachedEntryIterator::SetTo(BEntryList* iterator)
353 {
354 	fIndex = 0;
355 	fNumEntries = 0;
356 	fStatus = B_OK;
357 	fIterator = iterator;
358 }
359 
360 
361 //	#pragma mark - CachedDirectoryEntryList
362 
363 
364 CachedDirectoryEntryList::CachedDirectoryEntryList(const BDirectory& directory)
365 	:
366 	CachedEntryIterator(0, 40, true),
367 	fDirectory(directory)
368 {
369 	fStatus = fDirectory.InitCheck();
370 	SetTo(&fDirectory);
371 }
372 
373 
374 CachedDirectoryEntryList::~CachedDirectoryEntryList()
375 {
376 }
377 
378 
379 //	#pragma mark - DirectoryEntryList
380 
381 
382 DirectoryEntryList::DirectoryEntryList(const BDirectory& directory)
383 	:
384 	fDirectory(directory)
385 {
386 	fStatus = fDirectory.InitCheck();
387 }
388 
389 
390 status_t
391 DirectoryEntryList::GetNextEntry(BEntry* entry, bool traverse)
392 {
393 	fStatus = fDirectory.GetNextEntry(entry, traverse);
394 	return fStatus;
395 }
396 
397 
398 status_t
399 DirectoryEntryList::GetNextRef(entry_ref* ref)
400 {
401 	fStatus = fDirectory.GetNextRef(ref);
402 	return fStatus;
403 }
404 
405 
406 int32
407 DirectoryEntryList::GetNextDirents(struct dirent* buffer, size_t length,
408 	int32 count)
409 {
410 	fStatus = fDirectory.GetNextDirents(buffer, length, count);
411 	return fStatus;
412 }
413 
414 
415 status_t
416 DirectoryEntryList::Rewind()
417 {
418 	fStatus = fDirectory.Rewind();
419 	return fStatus;
420 }
421 
422 
423 int32
424 DirectoryEntryList::CountEntries()
425 {
426 	return fDirectory.CountEntries();
427 }
428 
429 
430 //	#pragma mark - EntryIteratorList
431 
432 
433 EntryIteratorList::EntryIteratorList()
434 	:
435 	fList(5, true),
436 	fCurrentIndex(0)
437 {
438 }
439 
440 
441 EntryIteratorList::~EntryIteratorList()
442 {
443 	int32 count = fList.CountItems();
444 	for (;count; count--) {
445 		// workaround for BEntryList not having a proper destructor
446 		BEntryList* entry = fList.RemoveItemAt(count - 1);
447 		EntryListBase* fixedEntry = dynamic_cast<EntryListBase*>(entry);
448 		if (fixedEntry != NULL)
449 			delete fixedEntry;
450 		else
451 			delete entry;
452 	}
453 }
454 
455 
456 void
457 EntryIteratorList::AddItem(BEntryList* walker)
458 {
459 	fList.AddItem(walker);
460 }
461 
462 
463 status_t
464 EntryIteratorList::GetNextEntry(BEntry* entry, bool traverse)
465 {
466 	while (true) {
467 		if (fCurrentIndex >= fList.CountItems()) {
468 			fStatus = B_ENTRY_NOT_FOUND;
469 			break;
470 		}
471 
472 		fStatus = fList.ItemAt(fCurrentIndex)->GetNextEntry(entry, traverse);
473 		if (fStatus != B_ENTRY_NOT_FOUND)
474 			break;
475 
476 		fCurrentIndex++;
477 	}
478 	return fStatus;
479 }
480 
481 
482 status_t
483 EntryIteratorList::GetNextRef(entry_ref* ref)
484 {
485 	while (true) {
486 		if (fCurrentIndex >= fList.CountItems()) {
487 			fStatus = B_ENTRY_NOT_FOUND;
488 			break;
489 		}
490 
491 		fStatus = fList.ItemAt(fCurrentIndex)->GetNextRef(ref);
492 		if (fStatus != B_ENTRY_NOT_FOUND)
493 			break;
494 
495 		fCurrentIndex++;
496 	}
497 	return fStatus;
498 }
499 
500 
501 int32
502 EntryIteratorList::GetNextDirents(struct dirent* buffer, size_t length,
503 	int32 count)
504 {
505 	int32 result = 0;
506 	while (true) {
507 		if (fCurrentIndex >= fList.CountItems()) {
508 			fStatus = B_ENTRY_NOT_FOUND;
509 			break;
510 		}
511 
512 		result = fList.ItemAt(fCurrentIndex)->GetNextDirents(buffer, length,
513 			count);
514 		if (result > 0) {
515 			fStatus = B_OK;
516 			break;
517 		}
518 
519 		fCurrentIndex++;
520 	}
521 	return result;
522 }
523 
524 
525 status_t
526 EntryIteratorList::Rewind()
527 {
528 	fCurrentIndex = 0;
529 	int32 count = fList.CountItems();
530 	for (int32 index = 0; index < count; index++)
531 		fStatus = fList.ItemAt(index)->Rewind();
532 
533 	return fStatus;
534 }
535 
536 
537 int32
538 EntryIteratorList::CountEntries()
539 {
540 	int32 result = 0;
541 
542 	int32 count = fList.CountItems();
543 	for (int32 index = 0; index < count; index++)
544 		result += fList.ItemAt(fCurrentIndex)->CountEntries();
545 
546 	return result;
547 }
548 
549 
550 //	#pragma mark - CachedEntryIteratorList
551 
552 
553 CachedEntryIteratorList::CachedEntryIteratorList(bool sortInodes)
554 	:
555 	CachedEntryIterator(NULL, 10, sortInodes)
556 {
557 	fStatus = B_OK;
558 	SetTo(&fIteratorList);
559 }
560 
561 
562 void
563 CachedEntryIteratorList::AddItem(BEntryList* walker)
564 {
565 	fIteratorList.AddItem(walker);
566 }
567