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