xref: /haiku/src/kits/tracker/EntryIterator.cpp (revision 2222d0559df303a9846a2fad53741f8b20b14d7c)
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(WALKER_NS::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, int32 numEntries,
135 		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 < (sizeof(dirent) + B_FILE_NAME_LENGTH)) {
269 				// cant fit a big entryRef in the buffer, just bail
270 				// and start from scratch
271 				break;
272 			}
273 
274 			fCurrentDirent
275 				= (dirent *)((char *)fCurrentDirent + currentDirentSize);
276 		}
277 		fCurrentDirent = fDirentBuffer;
278 		if (fSortInodes) {
279 			if (!fSortedList)
280 				fSortedList = new BObjectList<dirent>(fCacheSize);
281 			else
282 				fSortedList->MakeEmpty();
283 
284 			for (int32 count = 0; count < fNumEntries; count++) {
285 				fSortedList->AddItem(fCurrentDirent, 0);
286 				fCurrentDirent = Next(fCurrentDirent);
287 			}
288 			fSortedList->SortItems(&_CompareInodes);
289 			fCurrentDirent = fDirentBuffer;
290 		}
291 		fIndex = 0;
292 	}
293 	if (fIndex >= fNumEntries) {
294 		// we are done, no more dirents left
295 		return 0;
296 	}
297 
298 	if (fSortInodes)
299 		fCurrentDirent = fSortedList->ItemAt(fIndex);
300 
301 	fIndex++;
302 	uint32 currentDirentSize = fCurrentDirent->d_reclen;
303 	ASSERT(currentDirentSize <= size);
304 	if (currentDirentSize > size)
305 		return 0;
306 
307 	memcpy(ent, fCurrentDirent, currentDirentSize);
308 
309 	if (!fSortInodes)
310 		fCurrentDirent = (dirent *)((char *)fCurrentDirent + currentDirentSize);
311 
312 	return 1;
313 }
314 
315 
316 status_t
317 CachedEntryIterator::Rewind()
318 {
319 	fIndex = 0;
320 	fNumEntries = 0;
321 	fCurrentDirent = NULL;
322 	fStatus = B_OK;
323 
324 	delete fSortedList;
325 	fSortedList = NULL;
326 
327 	return fIterator->Rewind();
328 }
329 
330 
331 int32
332 CachedEntryIterator::CountEntries()
333 {
334 	return fIterator->CountEntries();
335 }
336 
337 
338 void
339 CachedEntryIterator::SetTo(BEntryList *iterator)
340 {
341 	fIndex = 0;
342 	fNumEntries = 0;
343 	fStatus = B_OK;
344 	fIterator = iterator;
345 }
346 
347 
348 //	#pragma mark -
349 
350 
351 CachedDirectoryEntryList::CachedDirectoryEntryList(const BDirectory &dir)
352 	: CachedEntryIterator(0, 40, true),
353 	fDir(dir)
354 {
355 	fStatus = fDir.InitCheck();
356 	SetTo(&fDir);
357 }
358 
359 
360 CachedDirectoryEntryList::~CachedDirectoryEntryList()
361 {
362 }
363 
364 
365 //	#pragma mark -
366 
367 
368 DirectoryEntryList::DirectoryEntryList(const BDirectory &dir)
369 	:
370 	fDir(dir)
371 {
372 	fStatus = fDir.InitCheck();
373 }
374 
375 
376 status_t
377 DirectoryEntryList::GetNextEntry(BEntry *entry, bool traverse)
378 {
379 	fStatus = fDir.GetNextEntry(entry, traverse);
380 	return fStatus;
381 }
382 
383 
384 status_t
385 DirectoryEntryList::GetNextRef(entry_ref *ref)
386 {
387 	fStatus = fDir.GetNextRef(ref);
388 	return fStatus;
389 }
390 
391 
392 int32
393 DirectoryEntryList::GetNextDirents(struct dirent *buffer, size_t length,
394 	int32 count)
395 {
396 	fStatus = fDir.GetNextDirents(buffer, length, count);
397 	return fStatus;
398 }
399 
400 
401 status_t
402 DirectoryEntryList::Rewind()
403 {
404 	fStatus = fDir.Rewind();
405 	return fStatus;
406 }
407 
408 
409 int32
410 DirectoryEntryList::CountEntries()
411 {
412 	return fDir.CountEntries();
413 }
414 
415 
416 //	#pragma mark -
417 
418 
419 EntryIteratorList::EntryIteratorList()
420 	:
421 	fList(5, true),
422 	fCurrentIndex(0)
423 {
424 }
425 
426 
427 EntryIteratorList::~EntryIteratorList()
428 {
429 	int32 count = fList.CountItems();
430 	for (;count; count--) {
431 		// workaround for BEntryList not having a proper destructor
432 		BEntryList *entry = fList.RemoveItemAt(count - 1);
433 		EntryListBase *fixedEntry = dynamic_cast<EntryListBase *>(entry);
434 
435 		if (fixedEntry)
436 			delete fixedEntry;
437 		else
438 			delete entry;
439 	}
440 }
441 
442 
443 void
444 EntryIteratorList::AddItem(BEntryList *walker)
445 {
446 	fList.AddItem(walker);
447 }
448 
449 
450 status_t
451 EntryIteratorList::GetNextEntry(BEntry *entry, bool traverse)
452 {
453 	while (true) {
454 		if (fCurrentIndex >= fList.CountItems()) {
455 			fStatus = B_ENTRY_NOT_FOUND;
456 			break;
457 		}
458 
459 		fStatus = fList.ItemAt(fCurrentIndex)->GetNextEntry(entry, traverse);
460 		if (fStatus != B_ENTRY_NOT_FOUND)
461 			break;
462 
463 		fCurrentIndex++;
464 	}
465 	return fStatus;
466 }
467 
468 
469 status_t
470 EntryIteratorList::GetNextRef(entry_ref *ref)
471 {
472 	while (true) {
473 		if (fCurrentIndex >= fList.CountItems()) {
474 			fStatus = B_ENTRY_NOT_FOUND;
475 			break;
476 		}
477 
478 		fStatus = fList.ItemAt(fCurrentIndex)->GetNextRef(ref);
479 		if (fStatus != B_ENTRY_NOT_FOUND)
480 			break;
481 
482 		fCurrentIndex++;
483 	}
484 	return fStatus;
485 }
486 
487 
488 int32
489 EntryIteratorList::GetNextDirents(struct dirent *buffer, size_t length,
490 	int32 count)
491 {
492 	int32 result = 0;
493 	while (true) {
494 		if (fCurrentIndex >= fList.CountItems()) {
495 			fStatus = B_ENTRY_NOT_FOUND;
496 			break;
497 		}
498 
499 		result = fList.ItemAt(fCurrentIndex)->GetNextDirents(buffer, length,
500 			count);
501 		if (result > 0) {
502 			fStatus = B_OK;
503 			break;
504 		}
505 
506 		fCurrentIndex++;
507 	}
508 	return result;
509 }
510 
511 
512 status_t
513 EntryIteratorList::Rewind()
514 {
515 	fCurrentIndex = 0;
516 	int32 count = fList.CountItems();
517 	for (int32 index = 0; index < count; index++)
518 		fStatus = fList.ItemAt(index)->Rewind();
519 
520 	return fStatus;
521 }
522 
523 
524 int32
525 EntryIteratorList::CountEntries()
526 {
527 	int32 result = 0;
528 
529 	int32 count = fList.CountItems();
530 	for (int32 index = 0; index < count; index++)
531 		result += fList.ItemAt(fCurrentIndex)->CountEntries();
532 
533 	return result;
534 }
535 
536 
537 //	#pragma mark -
538 
539 
540 CachedEntryIteratorList::CachedEntryIteratorList(bool sortInodes)
541 	: CachedEntryIterator(NULL, 10, sortInodes)
542 {
543 	fStatus = B_OK;
544 	SetTo(&fIteratorList);
545 }
546 
547 
548 void
549 CachedEntryIteratorList::AddItem(BEntryList *walker)
550 {
551 	fIteratorList.AddItem(walker);
552 }
553 
554