xref: /haiku/src/kits/tracker/EntryIterator.cpp (revision 83b1a68c52ba3e0e8796282759f694b7fdddf06d)
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 != NULL);
172 	ASSERT(fEntryRefBuffer != NULL);
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& directory)
366 	:
367 	CachedEntryIterator(0, 40, true),
368 	fDirectory(directory)
369 {
370 	fStatus = fDirectory.InitCheck();
371 	SetTo(&fDirectory);
372 }
373 
374 
375 CachedDirectoryEntryList::~CachedDirectoryEntryList()
376 {
377 }
378 
379 
380 //	#pragma mark - DirectoryEntryList
381 
382 
383 DirectoryEntryList::DirectoryEntryList(const BDirectory& directory)
384 	:
385 	fDirectory(directory)
386 {
387 	fStatus = fDirectory.InitCheck();
388 }
389 
390 
391 status_t
392 DirectoryEntryList::GetNextEntry(BEntry* entry, bool traverse)
393 {
394 	fStatus = fDirectory.GetNextEntry(entry, traverse);
395 	return fStatus;
396 }
397 
398 
399 status_t
400 DirectoryEntryList::GetNextRef(entry_ref* ref)
401 {
402 	fStatus = fDirectory.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 = fDirectory.GetNextDirents(buffer, length, count);
412 	return fStatus;
413 }
414 
415 
416 status_t
417 DirectoryEntryList::Rewind()
418 {
419 	fStatus = fDirectory.Rewind();
420 	return fStatus;
421 }
422 
423 
424 int32
425 DirectoryEntryList::CountEntries()
426 {
427 	return fDirectory.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 		if (fixedEntry != NULL)
450 			delete fixedEntry;
451 		else
452 			delete entry;
453 	}
454 }
455 
456 
457 void
458 EntryIteratorList::AddItem(BEntryList* walker)
459 {
460 	fList.AddItem(walker);
461 }
462 
463 
464 status_t
465 EntryIteratorList::GetNextEntry(BEntry* entry, bool traverse)
466 {
467 	while (true) {
468 		if (fCurrentIndex >= fList.CountItems()) {
469 			fStatus = B_ENTRY_NOT_FOUND;
470 			break;
471 		}
472 
473 		fStatus = fList.ItemAt(fCurrentIndex)->GetNextEntry(entry, traverse);
474 		if (fStatus != B_ENTRY_NOT_FOUND)
475 			break;
476 
477 		fCurrentIndex++;
478 	}
479 	return fStatus;
480 }
481 
482 
483 status_t
484 EntryIteratorList::GetNextRef(entry_ref* ref)
485 {
486 	while (true) {
487 		if (fCurrentIndex >= fList.CountItems()) {
488 			fStatus = B_ENTRY_NOT_FOUND;
489 			break;
490 		}
491 
492 		fStatus = fList.ItemAt(fCurrentIndex)->GetNextRef(ref);
493 		if (fStatus != B_ENTRY_NOT_FOUND)
494 			break;
495 
496 		fCurrentIndex++;
497 	}
498 	return fStatus;
499 }
500 
501 
502 int32
503 EntryIteratorList::GetNextDirents(struct dirent* buffer, size_t length,
504 	int32 count)
505 {
506 	int32 result = 0;
507 	while (true) {
508 		if (fCurrentIndex >= fList.CountItems()) {
509 			fStatus = B_ENTRY_NOT_FOUND;
510 			break;
511 		}
512 
513 		result = fList.ItemAt(fCurrentIndex)->GetNextDirents(buffer, length,
514 			count);
515 		if (result > 0) {
516 			fStatus = B_OK;
517 			break;
518 		}
519 
520 		fCurrentIndex++;
521 	}
522 	return result;
523 }
524 
525 
526 status_t
527 EntryIteratorList::Rewind()
528 {
529 	fCurrentIndex = 0;
530 	int32 count = fList.CountItems();
531 	for (int32 index = 0; index < count; index++)
532 		fStatus = fList.ItemAt(index)->Rewind();
533 
534 	return fStatus;
535 }
536 
537 
538 int32
539 EntryIteratorList::CountEntries()
540 {
541 	int32 result = 0;
542 
543 	int32 count = fList.CountItems();
544 	for (int32 index = 0; index < count; index++)
545 		result += fList.ItemAt(fCurrentIndex)->CountEntries();
546 
547 	return result;
548 }
549 
550 
551 //	#pragma mark - CachedEntryIteratorList
552 
553 
554 CachedEntryIteratorList::CachedEntryIteratorList(bool sortInodes)
555 	:
556 	CachedEntryIterator(NULL, 10, sortInodes)
557 {
558 	fStatus = B_OK;
559 	SetTo(&fIteratorList);
560 }
561 
562 
563 void
564 CachedEntryIteratorList::AddItem(BEntryList* walker)
565 {
566 	fIteratorList.AddItem(walker);
567 }
568