491 lines
10 KiB
C++
491 lines
10 KiB
C++
/*
|
|||
|
|
Open Tracker License
|
||
|
|
|
||
|
|
Terms and Conditions
|
||
|
|
|
||
|
|
Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
|
||
|
|
|
||
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||
|
|
this software and associated documentation files (the "Software"), to deal in
|
||
|
|
the Software without restriction, including without limitation the rights to
|
||
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||
|
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||
|
|
so, subject to the following conditions:
|
||
|
|
|
||
|
|
The above copyright notice and this permission notice applies to all licensees
|
||
|
|
and shall be included in all copies or substantial portions of the Software.
|
||
|
|
|
||
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
|
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
|
|
||
|
|
Except as contained in this notice, the name of Be Incorporated shall not be
|
||
|
|
used in advertising or otherwise to promote the sale, use or other dealings in
|
||
|
|
this Software without prior written authorization from Be Incorporated.
|
||
|
|
|
||
|
|
Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||
|
|
of Be Incorporated in the United States and other countries. Other brand product
|
||
|
|
names are registered trademarks or trademarks of their respective holders.
|
||
|
|
All rights reserved.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <Debug.h>
|
||
|
|
#include <Entry.h>
|
||
|
|
#include <Path.h>
|
||
|
|
|
||
|
|
#include <new>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#include "EntryIterator.h"
|
||
|
|
#include "NodeWalker.h"
|
||
|
|
#include "ObjectList.h"
|
||
|
|
|
||
|
|
TWalkerWrapper::TWalkerWrapper(WALKER_NS::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 < 0 ? 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 + sizeof(dirent));
|
||
|
|
}
|
||
|
|
|
||
|
|
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);
|
||
|
|
ASSERT(!fEntryRefBuffer);
|
||
|
|
|
||
|
|
if (!fEntryBuffer) {
|
||
|
|
fEntryBuffer = new BEntry [fCacheSize];
|
||
|
|
ASSERT(fIndex == 0 && fNumEntries == 0);
|
||
|
|
}
|
||
|
|
if (fIndex >= fNumEntries) {
|
||
|
|
// fill up the buffer or stop if error; keep error around
|
||
|
|
// and return it when appropriate
|
||
|
|
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)
|
||
|
|
// we are at the end of the cache we loaded up, time to return
|
||
|
|
// an error, if we had one
|
||
|
|
return fStatus;
|
||
|
|
|
||
|
|
return B_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
status_t
|
||
|
|
CachedEntryIterator::GetNextRef(entry_ref *ref)
|
||
|
|
{
|
||
|
|
ASSERT(!fDirentBuffer);
|
||
|
|
ASSERT(!fEntryBuffer);
|
||
|
|
|
||
|
|
if (!fEntryRefBuffer) {
|
||
|
|
fEntryRefBuffer = new entry_ref[fCacheSize];
|
||
|
|
ASSERT(fIndex == 0 && fNumEntries == 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (fIndex >= fNumEntries) {
|
||
|
|
// fill up the buffer or stop if error; keep error around
|
||
|
|
// and return it when appropriate
|
||
|
|
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)
|
||
|
|
// we are at the end of the cache we loaded up, time to return
|
||
|
|
// an error, if we had one
|
||
|
|
return fStatus;
|
||
|
|
|
||
|
|
return B_OK;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
static int
|
||
|
|
CompareInode(const dirent *ent1, const dirent *ent2)
|
||
|
|
{
|
||
|
|
if (ent1->d_ino < ent2->d_ino)
|
||
|
|
return -1;
|
||
|
|
else if (ent1->d_ino == ent2->d_ino)
|
||
|
|
return 0;
|
||
|
|
else
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32
|
||
|
|
CachedEntryIterator::GetNextDirents(struct dirent *ent, size_t size,
|
||
|
|
int32 count)
|
||
|
|
{
|
||
|
|
ASSERT(!fEntryRefBuffer);
|
||
|
|
if (!fDirentBuffer) {
|
||
|
|
fDirentBuffer = (dirent *)malloc(kDirentBufferSize);
|
||
|
|
ASSERT(fIndex == 0 && fNumEntries == 0);
|
||
|
|
ASSERT(size > sizeof(dirent) + B_FILE_NAME_LENGTH);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!count)
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
if (fIndex >= fNumEntries) {
|
||
|
|
// we are out of stock, cache em up
|
||
|
|
fCurrentDirent = fDirentBuffer;
|
||
|
|
uint32 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 + (ssize_t)sizeof(dirent);
|
||
|
|
bufferRemain -= currentDirentSize;
|
||
|
|
if (bufferRemain < (sizeof(dirent) + B_FILE_NAME_LENGTH))
|
||
|
|
// cant fit a big entryRef in the buffer, just bail
|
||
|
|
// and start from scratch
|
||
|
|
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(CompareInode);
|
||
|
|
fCurrentDirent = fDirentBuffer;
|
||
|
|
}
|
||
|
|
fIndex = 0;
|
||
|
|
}
|
||
|
|
if (fIndex >= fNumEntries)
|
||
|
|
// we are done, no more dirents left
|
||
|
|
return 0;
|
||
|
|
|
||
|
|
if (fSortInodes)
|
||
|
|
fCurrentDirent = fSortedList->ItemAt(fIndex);
|
||
|
|
|
||
|
|
fIndex++;
|
||
|
|
uint32 currentDirentSize = fCurrentDirent->d_reclen + sizeof(dirent);
|
||
|
|
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 &dir)
|
||
|
|
: CachedEntryIterator(0, 40, true),
|
||
|
|
fDir(dir)
|
||
|
|
{
|
||
|
|
fStatus = fDir.InitCheck();
|
||
|
|
SetTo(&fDir);
|
||
|
|
}
|
||
|
|
|
||
|
|
CachedDirectoryEntryList::~CachedDirectoryEntryList()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
DirectoryEntryList::DirectoryEntryList(const BDirectory &dir)
|
||
|
|
: fDir(dir)
|
||
|
|
{
|
||
|
|
fStatus = fDir.InitCheck();
|
||
|
|
}
|
||
|
|
|
||
|
|
status_t
|
||
|
|
DirectoryEntryList::GetNextEntry(BEntry *entry, bool traverse)
|
||
|
|
{
|
||
|
|
fStatus = fDir.GetNextEntry(entry, traverse);
|
||
|
|
return fStatus;
|
||
|
|
}
|
||
|
|
|
||
|
|
status_t
|
||
|
|
DirectoryEntryList::GetNextRef(entry_ref *ref)
|
||
|
|
{
|
||
|
|
fStatus = fDir.GetNextRef(ref);
|
||
|
|
return fStatus;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32
|
||
|
|
DirectoryEntryList::GetNextDirents(struct dirent *buffer, size_t length,
|
||
|
|
int32 count)
|
||
|
|
{
|
||
|
|
fStatus = fDir.GetNextDirents(buffer, length, count);
|
||
|
|
return fStatus;
|
||
|
|
}
|
||
|
|
|
||
|
|
status_t
|
||
|
|
DirectoryEntryList::Rewind()
|
||
|
|
{
|
||
|
|
fStatus = fDir.Rewind();
|
||
|
|
return fStatus;
|
||
|
|
}
|
||
|
|
|
||
|
|
int32
|
||
|
|
DirectoryEntryList::CountEntries()
|
||
|
|
{
|
||
|
|
return fDir.CountEntries();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
EntryIteratorList::EntryIteratorList()
|
||
|
|
: fList(5, true),
|
||
|
|
fCurrentIndex(0)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
EntryIteratorList::~EntryIteratorList()
|
||
|
|
{
|
||
|
|
int32 count = fList.CountItems();
|
||
|
|
for (;count; count--) {
|
||
|
|
// workaround for BEntryList not having a proper destructor
|
||
|
|
BEntryList *entry = fList.RemoveItemAt(count - 1);
|
||
|
|
EntryListBase *fixedEntry = dynamic_cast<EntryListBase *>(entry);
|
||
|
|
|
||
|
|
if (fixedEntry)
|
||
|
|
delete fixedEntry;
|
||
|
|
else
|
||
|
|
delete entry;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
void
|
||
|
|
EntryIteratorList::AddItem(BEntryList *walker)
|
||
|
|
{
|
||
|
|
fList.AddItem(walker);
|
||
|
|
}
|
||
|
|
|
||
|
|
status_t
|
||
|
|
EntryIteratorList::GetNextEntry(BEntry *entry, bool traverse)
|
||
|
|
{
|
||
|
|
for (;;) {
|
||
|
|
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)
|
||
|
|
{
|
||
|
|
for (;;) {
|
||
|
|
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;
|
||
|
|
for (;;) {
|
||
|
|
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()
|
||
|
|
: CachedEntryIterator(0, 10, true)
|
||
|
|
{
|
||
|
|
fStatus = B_OK;
|
||
|
|
SetTo(&fIteratorList);
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
CachedEntryIteratorList::AddItem(BEntryList *walker)
|
||
|
|
{
|
||
|
|
fIteratorList.AddItem(walker);
|
||
|
|
}
|
||
|
|
|