#include <Debug.h>
#include <Entry.h>
#include <ObjectList.h>
#include <Path.h>
#include <new>
#include <string.h>
#include "EntryIterator.h"
TWalkerWrapper::TWalkerWrapper(BTrackerPrivate::TWalker* walker)
:
fWalker(walker),
fStatus(B_OK)
{
}
TWalkerWrapper::~TWalkerWrapper()
{
delete fWalker;
}
status_t
TWalkerWrapper::InitCheck() const
{
return fStatus;
}
status_t
TWalkerWrapper::GetNextEntry(BEntry* entry, bool traverse)
{
fStatus = fWalker->GetNextEntry(entry, traverse);
return fStatus;
}
status_t
TWalkerWrapper::GetNextRef(entry_ref* ref)
{
fStatus = fWalker->GetNextRef(ref);
return fStatus;
}
int32
TWalkerWrapper::GetNextDirents(struct dirent* buffer, size_t length,
int32 count)
{
int32 result = fWalker->GetNextDirents(buffer, length, count);
fStatus = result < B_OK ? result : (result ? B_OK : B_ENTRY_NOT_FOUND);
return result;
}
status_t
TWalkerWrapper::Rewind()
{
return fWalker->Rewind();
}
int32
TWalkerWrapper::CountEntries()
{
return fWalker->CountEntries();
}
EntryListBase::EntryListBase()
:
fStatus(B_OK)
{
}
status_t
EntryListBase::InitCheck() const
{
return fStatus;
}
dirent*
EntryListBase::Next(dirent* ent)
{
return (dirent*)((char*)ent + ent->d_reclen);
}
CachedEntryIterator::CachedEntryIterator(BEntryList* iterator,
int32 numEntries, bool sortInodes)
:
fIterator(iterator),
fEntryRefBuffer(NULL),
fCacheSize(numEntries),
fNumEntries(0),
fIndex(0),
fDirentBuffer(NULL),
fCurrentDirent(NULL),
fSortInodes(sortInodes),
fSortedList(NULL),
fEntryBuffer(NULL)
{
}
CachedEntryIterator::~CachedEntryIterator()
{
delete[] fEntryRefBuffer;
free(fDirentBuffer);
delete fSortedList;
delete[] fEntryBuffer;
}
status_t
CachedEntryIterator::GetNextEntry(BEntry* result, bool traverse)
{
ASSERT(fDirentBuffer == NULL);
ASSERT(fEntryRefBuffer == NULL);
if (fEntryBuffer == NULL) {
fEntryBuffer = new BEntry [fCacheSize];
ASSERT(fIndex == 0 && fNumEntries == 0);
}
if (fIndex >= fNumEntries) {
fStatus = B_OK;
for (fNumEntries = 0; fNumEntries < fCacheSize; fNumEntries++) {
fStatus = fIterator->GetNextEntry(&fEntryBuffer[fNumEntries],
traverse);
if (fStatus != B_OK)
break;
}
fIndex = 0;
}
*result = fEntryBuffer[fIndex++];
if (fIndex > fNumEntries) {
return fStatus;
}
return B_OK;
}
status_t
CachedEntryIterator::GetNextRef(entry_ref* ref)
{
ASSERT(fDirentBuffer == NULL);
ASSERT(fEntryBuffer == NULL);
if (fEntryRefBuffer == NULL) {
fEntryRefBuffer = new entry_ref[fCacheSize];
ASSERT(fIndex == 0 && fNumEntries == 0);
}
if (fIndex >= fNumEntries) {
fStatus = B_OK;
for (fNumEntries = 0; fNumEntries < fCacheSize; fNumEntries++) {
fStatus = fIterator->GetNextRef(&fEntryRefBuffer[fNumEntries]);
if (fStatus != B_OK)
break;
}
fIndex = 0;
}
*ref = fEntryRefBuffer[fIndex++];
if (fIndex > fNumEntries) {
return fStatus;
}
return B_OK;
}
int
CachedEntryIterator::_CompareInodes(const dirent* ent1, const dirent* ent2)
{
if (ent1->d_ino < ent2->d_ino)
return -1;
if (ent1->d_ino == ent2->d_ino)
return 0;
return 1;
}
int32
CachedEntryIterator::GetNextDirents(struct dirent* ent, size_t size,
int32 count)
{
ASSERT(fEntryRefBuffer == NULL);
if (fDirentBuffer == NULL) {
fDirentBuffer = (dirent*)malloc(kDirentBufferSize);
ASSERT(fIndex == 0 && fNumEntries == 0);
ASSERT(size > offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH);
}
if (count == 0)
return 0;
if (fIndex >= fNumEntries) {
fCurrentDirent = fDirentBuffer;
int32 bufferRemain = kDirentBufferSize;
for (fNumEntries = 0; fNumEntries < fCacheSize; ) {
int32 count = fIterator->GetNextDirents(fCurrentDirent,
bufferRemain, 1);
if (count <= 0)
break;
fNumEntries += count;
int32 currentDirentSize = fCurrentDirent->d_reclen;
bufferRemain -= currentDirentSize;
ASSERT(bufferRemain >= 0);
if ((size_t)bufferRemain
< (offsetof(struct dirent, d_name) + B_FILE_NAME_LENGTH)) {
break;
}
fCurrentDirent
= (dirent*)((char*)fCurrentDirent + currentDirentSize);
}
fCurrentDirent = fDirentBuffer;
if (fSortInodes) {
if (!fSortedList)
fSortedList = new BObjectList<dirent>(fCacheSize);
else
fSortedList->MakeEmpty();
for (int32 count = 0; count < fNumEntries; count++) {
fSortedList->AddItem(fCurrentDirent, 0);
fCurrentDirent = Next(fCurrentDirent);
}
fSortedList->SortItems(&_CompareInodes);
fCurrentDirent = fDirentBuffer;
}
fIndex = 0;
}
if (fIndex >= fNumEntries) {
return 0;
}
if (fSortInodes)
fCurrentDirent = fSortedList->ItemAt(fIndex);
fIndex++;
uint32 currentDirentSize = fCurrentDirent->d_reclen;
ASSERT(currentDirentSize <= size);
if (currentDirentSize > size)
return 0;
memcpy(ent, fCurrentDirent, currentDirentSize);
if (!fSortInodes)
fCurrentDirent = (dirent*)((char*)fCurrentDirent + currentDirentSize);
return 1;
}
status_t
CachedEntryIterator::Rewind()
{
fIndex = 0;
fNumEntries = 0;
fCurrentDirent = NULL;
fStatus = B_OK;
delete fSortedList;
fSortedList = NULL;
return fIterator->Rewind();
}
int32
CachedEntryIterator::CountEntries()
{
return fIterator->CountEntries();
}
void
CachedEntryIterator::SetTo(BEntryList* iterator)
{
fIndex = 0;
fNumEntries = 0;
fStatus = B_OK;
fIterator = iterator;
}
CachedDirectoryEntryList::CachedDirectoryEntryList(const BDirectory& directory)
:
CachedEntryIterator(0, 40, true),
fDirectory(directory)
{
fStatus = fDirectory.InitCheck();
SetTo(&fDirectory);
}
CachedDirectoryEntryList::~CachedDirectoryEntryList()
{
}
DirectoryEntryList::DirectoryEntryList(const BDirectory& directory)
:
fDirectory(directory)
{
fStatus = fDirectory.InitCheck();
}
status_t
DirectoryEntryList::GetNextEntry(BEntry* entry, bool traverse)
{
fStatus = fDirectory.GetNextEntry(entry, traverse);
return fStatus;
}
status_t
DirectoryEntryList::GetNextRef(entry_ref* ref)
{
fStatus = fDirectory.GetNextRef(ref);
return fStatus;
}
int32
DirectoryEntryList::GetNextDirents(struct dirent* buffer, size_t length,
int32 count)
{
fStatus = fDirectory.GetNextDirents(buffer, length, count);
return fStatus;
}
status_t
DirectoryEntryList::Rewind()
{
fStatus = fDirectory.Rewind();
return fStatus;
}
int32
DirectoryEntryList::CountEntries()
{
return fDirectory.CountEntries();
}
EntryIteratorList::EntryIteratorList()
:
fList(5),
fCurrentIndex(0)
{
}
EntryIteratorList::~EntryIteratorList()
{
int32 count = fList.CountItems();
for (;count; count--) {
BEntryList* entry = fList.RemoveItemAt(count - 1);
EntryListBase* fixedEntry = dynamic_cast<EntryListBase*>(entry);
if (fixedEntry != NULL)
delete fixedEntry;
else
delete entry;
}
}
void
EntryIteratorList::AddItem(BEntryList* walker)
{
fList.AddItem(walker);
}
status_t
EntryIteratorList::GetNextEntry(BEntry* entry, bool traverse)
{
while (true) {
if (fCurrentIndex >= fList.CountItems()) {
fStatus = B_ENTRY_NOT_FOUND;
break;
}
fStatus = fList.ItemAt(fCurrentIndex)->GetNextEntry(entry, traverse);
if (fStatus != B_ENTRY_NOT_FOUND)
break;
fCurrentIndex++;
}
return fStatus;
}
status_t
EntryIteratorList::GetNextRef(entry_ref* ref)
{
while (true) {
if (fCurrentIndex >= fList.CountItems()) {
fStatus = B_ENTRY_NOT_FOUND;
break;
}
fStatus = fList.ItemAt(fCurrentIndex)->GetNextRef(ref);
if (fStatus != B_ENTRY_NOT_FOUND)
break;
fCurrentIndex++;
}
return fStatus;
}
int32
EntryIteratorList::GetNextDirents(struct dirent* buffer, size_t length,
int32 count)
{
int32 result = 0;
while (true) {
if (fCurrentIndex >= fList.CountItems()) {
fStatus = B_ENTRY_NOT_FOUND;
break;
}
result = fList.ItemAt(fCurrentIndex)->GetNextDirents(buffer, length,
count);
if (result > 0) {
fStatus = B_OK;
break;
}
fCurrentIndex++;
}
return result;
}
status_t
EntryIteratorList::Rewind()
{
fCurrentIndex = 0;
int32 count = fList.CountItems();
for (int32 index = 0; index < count; index++)
fStatus = fList.ItemAt(index)->Rewind();
return fStatus;
}
int32
EntryIteratorList::CountEntries()
{
int32 result = 0;
int32 count = fList.CountItems();
for (int32 index = 0; index < count; index++)
result += fList.ItemAt(fCurrentIndex)->CountEntries();
return result;
}
CachedEntryIteratorList::CachedEntryIteratorList(bool sortInodes)
:
CachedEntryIterator(NULL, 10, sortInodes)
{
fStatus = B_OK;
SetTo(&fIteratorList);
}
void
CachedEntryIteratorList::AddItem(BEntryList* walker)
{
fIteratorList.AddItem(walker);
}