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