1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal in
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30of Be Incorporated in the United States and other countries. Other brand product
31names are registered trademarks or trademarks of their respective holders.
32All 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
47TWalkerWrapper::TWalkerWrapper(BTrackerPrivate::TWalker* walker)
48	:
49	fWalker(walker),
50	fStatus(B_OK)
51{
52}
53
54
55TWalkerWrapper::~TWalkerWrapper()
56{
57	delete fWalker;
58}
59
60
61status_t
62TWalkerWrapper::InitCheck() const
63{
64	return fStatus;
65}
66
67
68status_t
69TWalkerWrapper::GetNextEntry(BEntry* entry, bool traverse)
70{
71	fStatus = fWalker->GetNextEntry(entry, traverse);
72	return fStatus;
73}
74
75
76status_t
77TWalkerWrapper::GetNextRef(entry_ref* ref)
78{
79	fStatus = fWalker->GetNextRef(ref);
80	return fStatus;
81}
82
83
84int32
85TWalkerWrapper::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
94status_t
95TWalkerWrapper::Rewind()
96{
97	return fWalker->Rewind();
98}
99
100
101int32
102TWalkerWrapper::CountEntries()
103{
104	return fWalker->CountEntries();
105}
106
107
108//	#pragma mark -
109
110
111EntryListBase::EntryListBase()
112	:	fStatus(B_OK)
113{
114}
115
116
117status_t
118EntryListBase::InitCheck() const
119{
120	 return fStatus;
121}
122
123
124dirent*
125EntryListBase::Next(dirent* ent)
126{
127	return (dirent*)((char*)ent + ent->d_reclen);
128}
129
130
131//	#pragma mark -
132
133
134CachedEntryIterator::CachedEntryIterator(BEntryList* iterator,
135		int32 numEntries, 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
151CachedEntryIterator::~CachedEntryIterator()
152{
153	delete [] fEntryRefBuffer;
154	free(fDirentBuffer);
155	delete fSortedList;
156	delete [] fEntryBuffer;
157}
158
159
160status_t
161CachedEntryIterator::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
193status_t
194CachedEntryIterator::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
226CachedEntryIterator::_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
237int32
238CachedEntryIterator::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
269					< (sizeof(dirent) + B_FILE_NAME_LENGTH)) {
270				// cant fit a big entryRef in the buffer, just bail
271				// and start from scratch
272				break;
273			}
274
275			fCurrentDirent
276				= (dirent*)((char*)fCurrentDirent + currentDirentSize);
277		}
278		fCurrentDirent = fDirentBuffer;
279		if (fSortInodes) {
280			if (!fSortedList)
281				fSortedList = new BObjectList<dirent>(fCacheSize);
282			else
283				fSortedList->MakeEmpty();
284
285			for (int32 count = 0; count < fNumEntries; count++) {
286				fSortedList->AddItem(fCurrentDirent, 0);
287				fCurrentDirent = Next(fCurrentDirent);
288			}
289			fSortedList->SortItems(&_CompareInodes);
290			fCurrentDirent = fDirentBuffer;
291		}
292		fIndex = 0;
293	}
294	if (fIndex >= fNumEntries) {
295		// we are done, no more dirents left
296		return 0;
297	}
298
299	if (fSortInodes)
300		fCurrentDirent = fSortedList->ItemAt(fIndex);
301
302	fIndex++;
303	uint32 currentDirentSize = fCurrentDirent->d_reclen;
304	ASSERT(currentDirentSize <= size);
305	if (currentDirentSize > size)
306		return 0;
307
308	memcpy(ent, fCurrentDirent, currentDirentSize);
309
310	if (!fSortInodes)
311		fCurrentDirent = (dirent*)((char*)fCurrentDirent + currentDirentSize);
312
313	return 1;
314}
315
316
317status_t
318CachedEntryIterator::Rewind()
319{
320	fIndex = 0;
321	fNumEntries = 0;
322	fCurrentDirent = NULL;
323	fStatus = B_OK;
324
325	delete fSortedList;
326	fSortedList = NULL;
327
328	return fIterator->Rewind();
329}
330
331
332int32
333CachedEntryIterator::CountEntries()
334{
335	return fIterator->CountEntries();
336}
337
338
339void
340CachedEntryIterator::SetTo(BEntryList* iterator)
341{
342	fIndex = 0;
343	fNumEntries = 0;
344	fStatus = B_OK;
345	fIterator = iterator;
346}
347
348
349//	#pragma mark -
350
351
352CachedDirectoryEntryList::CachedDirectoryEntryList(const BDirectory &dir)
353	: CachedEntryIterator(0, 40, true),
354	fDir(dir)
355{
356	fStatus = fDir.InitCheck();
357	SetTo(&fDir);
358}
359
360
361CachedDirectoryEntryList::~CachedDirectoryEntryList()
362{
363}
364
365
366//	#pragma mark -
367
368
369DirectoryEntryList::DirectoryEntryList(const BDirectory &dir)
370	:
371	fDir(dir)
372{
373	fStatus = fDir.InitCheck();
374}
375
376
377status_t
378DirectoryEntryList::GetNextEntry(BEntry* entry, bool traverse)
379{
380	fStatus = fDir.GetNextEntry(entry, traverse);
381	return fStatus;
382}
383
384
385status_t
386DirectoryEntryList::GetNextRef(entry_ref* ref)
387{
388	fStatus = fDir.GetNextRef(ref);
389	return fStatus;
390}
391
392
393int32
394DirectoryEntryList::GetNextDirents(struct dirent* buffer, size_t length,
395	int32 count)
396{
397	fStatus = fDir.GetNextDirents(buffer, length, count);
398	return fStatus;
399}
400
401
402status_t
403DirectoryEntryList::Rewind()
404{
405	fStatus = fDir.Rewind();
406	return fStatus;
407}
408
409
410int32
411DirectoryEntryList::CountEntries()
412{
413	return fDir.CountEntries();
414}
415
416
417//	#pragma mark -
418
419
420EntryIteratorList::EntryIteratorList()
421	:
422	fList(5, true),
423	fCurrentIndex(0)
424{
425}
426
427
428EntryIteratorList::~EntryIteratorList()
429{
430	int32 count = fList.CountItems();
431	for (;count; count--) {
432		// workaround for BEntryList not having a proper destructor
433		BEntryList* entry = fList.RemoveItemAt(count - 1);
434		EntryListBase* fixedEntry = dynamic_cast<EntryListBase*>(entry);
435
436		if (fixedEntry)
437			delete fixedEntry;
438		else
439			delete entry;
440	}
441}
442
443
444void
445EntryIteratorList::AddItem(BEntryList* walker)
446{
447	fList.AddItem(walker);
448}
449
450
451status_t
452EntryIteratorList::GetNextEntry(BEntry* entry, bool traverse)
453{
454	while (true) {
455		if (fCurrentIndex >= fList.CountItems()) {
456			fStatus = B_ENTRY_NOT_FOUND;
457			break;
458		}
459
460		fStatus = fList.ItemAt(fCurrentIndex)->GetNextEntry(entry, traverse);
461		if (fStatus != B_ENTRY_NOT_FOUND)
462			break;
463
464		fCurrentIndex++;
465	}
466	return fStatus;
467}
468
469
470status_t
471EntryIteratorList::GetNextRef(entry_ref* ref)
472{
473	while (true) {
474		if (fCurrentIndex >= fList.CountItems()) {
475			fStatus = B_ENTRY_NOT_FOUND;
476			break;
477		}
478
479		fStatus = fList.ItemAt(fCurrentIndex)->GetNextRef(ref);
480		if (fStatus != B_ENTRY_NOT_FOUND)
481			break;
482
483		fCurrentIndex++;
484	}
485	return fStatus;
486}
487
488
489int32
490EntryIteratorList::GetNextDirents(struct dirent* buffer, size_t length,
491	int32 count)
492{
493	int32 result = 0;
494	while (true) {
495		if (fCurrentIndex >= fList.CountItems()) {
496			fStatus = B_ENTRY_NOT_FOUND;
497			break;
498		}
499
500		result = fList.ItemAt(fCurrentIndex)->GetNextDirents(buffer, length,
501			count);
502		if (result > 0) {
503			fStatus = B_OK;
504			break;
505		}
506
507		fCurrentIndex++;
508	}
509	return result;
510}
511
512
513status_t
514EntryIteratorList::Rewind()
515{
516	fCurrentIndex = 0;
517	int32 count = fList.CountItems();
518	for (int32 index = 0; index < count; index++)
519		fStatus = fList.ItemAt(index)->Rewind();
520
521	return fStatus;
522}
523
524
525int32
526EntryIteratorList::CountEntries()
527{
528	int32 result = 0;
529
530	int32 count = fList.CountItems();
531	for (int32 index = 0; index < count; index++)
532		result += fList.ItemAt(fCurrentIndex)->CountEntries();
533
534	return result;
535}
536
537
538//	#pragma mark -
539
540
541CachedEntryIteratorList::CachedEntryIteratorList(bool sortInodes)
542	: CachedEntryIterator(NULL, 10, sortInodes)
543{
544	fStatus = B_OK;
545	SetTo(&fIteratorList);
546}
547
548
549void
550CachedEntryIteratorList::AddItem(BEntryList* walker)
551{
552	fIteratorList.AddItem(walker);
553}
554