#include <Debug.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <SupportDefs.h>
#include "NodeWalker.h"
namespace BTrackerPrivate {
TWalker::~TWalker()
{
}
status_t
TWalker::GetNextEntry(BEntry*, bool )
{
TRESPASS();
return B_ERROR;
}
status_t
TWalker::GetNextRef(entry_ref*)
{
TRESPASS();
return B_ERROR;
}
int32
TWalker::GetNextDirents(struct dirent*, size_t, int32)
{
TRESPASS();
return 0;
}
status_t
TWalker::Rewind()
{
TRESPASS();
return B_ERROR;
}
int32
TWalker::CountEntries()
{
TRESPASS();
return -1;
}
TNodeWalker::TNodeWalker(bool includeTopDirectory)
:
fDirs(20),
fTopIndex(-1),
fTopDir(NULL),
fIncludeTopDir(includeTopDirectory),
fOriginalIncludeTopDir(includeTopDirectory),
fJustFile(NULL),
fOriginalJustFile(NULL)
{
}
TNodeWalker::TNodeWalker(const char* path, bool includeTopDirectory)
:
fDirs(20),
fTopIndex(-1),
fTopDir(NULL),
fIncludeTopDir(includeTopDirectory),
fOriginalIncludeTopDir(includeTopDirectory),
fJustFile(NULL),
fOriginalDirCopy(path),
fOriginalJustFile(NULL)
{
if (fOriginalDirCopy.InitCheck() != B_OK) {
fJustFile = new BEntry(path);
if (fJustFile->InitCheck() != B_OK) {
delete fJustFile;
fJustFile = NULL;
}
fOriginalJustFile = fJustFile;
} else {
fTopDir = new BDirectory(fOriginalDirCopy);
fTopIndex++;
fDirs.AddItem(fTopDir);
}
}
TNodeWalker::TNodeWalker(const entry_ref* ref, bool includeTopDirectory)
:
fDirs(20),
fTopIndex(-1),
fTopDir(NULL),
fIncludeTopDir(includeTopDirectory),
fOriginalIncludeTopDir(includeTopDirectory),
fJustFile(NULL),
fOriginalDirCopy(ref),
fOriginalJustFile(NULL)
{
if (fOriginalDirCopy.InitCheck() != B_OK) {
fJustFile = new BEntry(ref);
if (fJustFile->InitCheck() != B_OK) {
delete fJustFile;
fJustFile = NULL;
}
fOriginalJustFile = fJustFile;
} else {
fTopDir = new BDirectory(fOriginalDirCopy);
fTopIndex++;
fDirs.AddItem(fTopDir);
}
}
TNodeWalker::TNodeWalker(const BDirectory* dir, bool includeTopDirectory)
:
fDirs(20),
fTopIndex(-1),
fTopDir(NULL),
fIncludeTopDir(includeTopDirectory),
fOriginalIncludeTopDir(includeTopDirectory),
fJustFile(NULL),
fOriginalDirCopy(*dir),
fOriginalJustFile(NULL)
{
fTopDir = new BDirectory(*dir);
fTopIndex++;
fDirs.AddItem(fTopDir);
}
TNodeWalker::TNodeWalker()
:
fDirs(20),
fTopIndex(-1),
fTopDir(NULL),
fIncludeTopDir(false),
fOriginalIncludeTopDir(false),
fJustFile(NULL),
fOriginalJustFile(NULL)
{
}
TNodeWalker::TNodeWalker(const char* path)
:
fDirs(20),
fTopIndex(-1),
fTopDir(NULL),
fIncludeTopDir(false),
fOriginalIncludeTopDir(false),
fJustFile(NULL),
fOriginalDirCopy(path),
fOriginalJustFile(NULL)
{
if (fOriginalDirCopy.InitCheck() != B_OK) {
fJustFile = new BEntry(path);
if (fJustFile->InitCheck() != B_OK) {
delete fJustFile;
fJustFile = NULL;
}
fOriginalJustFile = fJustFile;
} else {
fTopDir = new BDirectory(fOriginalDirCopy);
fTopIndex++;
fDirs.AddItem(fTopDir);
}
}
TNodeWalker::TNodeWalker(const entry_ref* ref)
:
fDirs(20),
fTopIndex(-1),
fTopDir(NULL),
fIncludeTopDir(false),
fOriginalIncludeTopDir(false),
fJustFile(NULL),
fOriginalDirCopy(ref),
fOriginalJustFile(NULL)
{
if (fOriginalDirCopy.InitCheck() != B_OK) {
fJustFile = new BEntry(ref);
if (fJustFile->InitCheck() != B_OK) {
delete fJustFile;
fJustFile = NULL;
}
fOriginalJustFile = fJustFile;
} else {
fTopDir = new BDirectory(fOriginalDirCopy);
fTopIndex++;
fDirs.AddItem(fTopDir);
}
}
TNodeWalker::TNodeWalker(const BDirectory* dir)
:
fDirs(20),
fTopIndex(-1),
fTopDir(NULL),
fIncludeTopDir(false),
fOriginalIncludeTopDir(false),
fJustFile(NULL),
fOriginalDirCopy(*dir),
fOriginalJustFile(NULL)
{
fTopDir = new BDirectory(*dir);
fTopIndex++;
fDirs.AddItem(fTopDir);
}
TNodeWalker::~TNodeWalker()
{
delete fOriginalJustFile;
for (;;) {
BDirectory* directory = fDirs.RemoveItemAt(fTopIndex--);
if (directory == NULL)
break;
delete directory;
}
}
status_t
TNodeWalker::PopDirCommon()
{
ASSERT(fTopIndex >= 0);
fDirs.RemoveItemAt(fTopIndex);
fTopIndex--;
delete fTopDir;
fTopDir = NULL;
if (fTopIndex == -1) {
return B_ENTRY_NOT_FOUND;
}
fTopDir = fDirs.ItemAt(fTopIndex);
return B_OK;
}
void
TNodeWalker::PushDirCommon(const entry_ref* ref)
{
fTopDir = new BDirectory(ref);
fTopIndex++;
fDirs.AddItem(fTopDir);
}
status_t
TNodeWalker::GetNextEntry(BEntry* entry, bool traverse)
{
if (fJustFile != NULL) {
*entry = *fJustFile;
fJustFile = 0;
return B_OK;
}
if (fTopDir == NULL) {
return B_ENTRY_NOT_FOUND;
}
if (fIncludeTopDir) {
fIncludeTopDir = false;
return fTopDir->GetEntry(entry);
}
status_t result = fTopDir->GetNextEntry(entry, traverse);
if (result != B_OK) {
result = PopDirCommon();
if (result != B_OK)
return result;
return GetNextEntry(entry, traverse);
}
entry_ref ref;
result = entry->GetRef(&ref);
if (result == B_OK && fTopDir->Contains(ref.name, B_DIRECTORY_NODE))
PushDirCommon(&ref);
return result;
}
status_t
TNodeWalker::GetNextRef(entry_ref* ref)
{
if (fJustFile != NULL) {
fJustFile->GetRef(ref);
fJustFile = 0;
return B_OK;
}
if (fTopDir == NULL) {
return B_ENTRY_NOT_FOUND;
}
if (fIncludeTopDir) {
fIncludeTopDir = false;
BEntry entry;
status_t err = fTopDir->GetEntry(&entry);
if (err == B_OK)
err = entry.GetRef(ref);
return err;
}
status_t err = fTopDir->GetNextRef(ref);
if (err != B_OK) {
err = PopDirCommon();
if (err != B_OK)
return err;
return GetNextRef(ref);
}
if (fTopDir->Contains(ref->name, B_DIRECTORY_NODE))
PushDirCommon(ref);
return B_OK;
}
static int32
build_dirent(const BEntry* source, struct dirent* ent,
size_t size, int32 count)
{
if (source == NULL)
return 0;
entry_ref ref;
source->GetRef(&ref);
size_t recordLength = offsetof(struct dirent, d_name) + strlen(ref.name) + 1;
if (recordLength > size || count <= 0) {
return 0;
}
ent->d_reclen = static_cast<ushort>(recordLength);
strcpy(ent->d_name, ref.name);
ent->d_dev = ref.device;
ent->d_ino = ref.directory;
BEntry parent;
source->GetParent(&parent);
if (parent.InitCheck() == B_OK) {
entry_ref parentRef;
parent.GetRef(&parentRef);
ent->d_pdev = parentRef.device;
ent->d_pino = parentRef.directory;
} else {
ent->d_pdev = 0;
ent->d_pino = 0;
}
return 1;
}
int32
TNodeWalker::GetNextDirents(struct dirent* ent, size_t size, int32 count)
{
if (fJustFile != NULL) {
if (count == 0)
return 0;
int32 result = build_dirent(fJustFile, ent, size, count);
fJustFile = 0;
return result;
}
if (fTopDir == NULL) {
return 0;
}
if (fIncludeTopDir) {
fIncludeTopDir = false;
BEntry entry;
if (fTopDir->GetEntry(&entry) < B_OK)
return 0;
return build_dirent(fJustFile, ent, size, count);
}
int32 nextDirent = fTopDir->GetNextDirents(ent, size, count);
if (nextDirent == 0) {
status_t result = PopDirCommon();
if (result != B_OK)
return 0;
return GetNextDirents(ent, size, count);
}
for (int32 i = 0; i < nextDirent; i++) {
if (fTopDir->Contains(ent->d_name, B_DIRECTORY_NODE)) {
entry_ref ref(ent->d_dev, ent->d_ino, ent->d_name);
PushDirCommon(&ref);
}
ent = (dirent*)((char*)ent + ent->d_reclen);
}
return nextDirent;
}
status_t
TNodeWalker::Rewind()
{
if (fOriginalJustFile != NULL) {
fJustFile = fOriginalJustFile;
return B_OK;
}
for (;;) {
BDirectory* directory = fDirs.RemoveItemAt(fTopIndex--);
if (directory == NULL)
break;
delete directory;
}
fTopDir = new BDirectory(fOriginalDirCopy);
fTopIndex = 0;
fIncludeTopDir = fOriginalIncludeTopDir;
fDirs.AddItem(fTopDir);
return fTopDir->Rewind();
}
int32
TNodeWalker::CountEntries()
{
TRESPASS();
return -1;
}
TVolWalker::TVolWalker(bool knowsAttributes, bool writable,
bool includeTopDirectory)
:
TNodeWalker(includeTopDirectory),
fKnowsAttr(knowsAttributes),
fWritable(writable)
{
NextVolume();
}
TVolWalker::~TVolWalker()
{
}
status_t
TVolWalker::NextVolume()
{
ASSERT(fTopIndex == -1);
ASSERT(fTopDir == NULL);
status_t result;
do {
result = fVolRoster.GetNextVolume(&fVol);
if (result != B_OK)
break;
} while ((fKnowsAttr && !fVol.KnowsAttr())
|| (fWritable && fVol.IsReadOnly()));
if (result == B_OK) {
fTopDir = new BDirectory();
result = fVol.GetRootDirectory(fTopDir);
fIncludeTopDir = fOriginalIncludeTopDir;
fTopIndex = 0;
fDirs.AddItem(fTopDir);
}
return result;
}
status_t
TVolWalker::GetNextEntry(BEntry* entry, bool traverse)
{
if (fTopDir == NULL)
return B_ENTRY_NOT_FOUND;
status_t result = _inherited::GetNextEntry(entry, traverse);
while (result != B_OK) {
result = NextVolume();
if (result != B_OK)
break;
result = GetNextEntry(entry, traverse);
}
return result;
}
status_t
TVolWalker::GetNextRef(entry_ref* ref)
{
if (fTopDir == NULL)
return B_ENTRY_NOT_FOUND;
status_t result = _inherited::GetNextRef(ref);
while (result != B_OK) {
result = NextVolume();
if (result != B_OK)
break;
result = GetNextRef(ref);
}
return result;
}
int32
TVolWalker::GetNextDirents(struct dirent* ent, size_t size, int32 count)
{
if (fTopDir == NULL)
return B_ENTRY_NOT_FOUND;
status_t result = _inherited::GetNextDirents(ent, size, count);
while (result != B_OK) {
result = NextVolume();
if (result != B_OK)
break;
result = GetNextDirents(ent, size, count);
}
return result;
}
status_t
TVolWalker::Rewind()
{
fVolRoster.Rewind();
return NextVolume();
}
TQueryWalker::TQueryWalker(const char* predicate)
:
TWalker(),
fTime(0)
{
fPredicate = strdup(predicate);
NextVolume();
}
TQueryWalker::~TQueryWalker()
{
free((char*)fPredicate);
fPredicate = NULL;
}
status_t
TQueryWalker::GetNextEntry(BEntry* entry, bool traverse)
{
status_t result;
do {
result = fQuery.GetNextEntry(entry, traverse);
if (result == B_ENTRY_NOT_FOUND) {
if (NextVolume() != B_OK)
break;
}
} while (result == B_ENTRY_NOT_FOUND);
return result;
}
status_t
TQueryWalker::GetNextRef(entry_ref* ref)
{
status_t result;
for (;;) {
result = fQuery.GetNextRef(ref);
if (result != B_ENTRY_NOT_FOUND)
break;
result = NextVolume();
if (result != B_OK)
break;
}
return result;
}
int32
TQueryWalker::GetNextDirents(struct dirent* ent, size_t size, int32 count)
{
int32 result;
for (;;) {
result = fQuery.GetNextDirents(ent, size, count);
if (result != 0)
return result;
if (NextVolume() != B_OK)
return 0;
}
return result;
}
status_t
TQueryWalker::NextVolume()
{
status_t result;
do {
result = fVolRoster.GetNextVolume(&fVol);
if (result != B_OK)
break;
} while (!fVol.KnowsQuery());
if (result == B_OK) {
result = fQuery.Clear();
result = fQuery.SetVolume(&fVol);
result = fQuery.SetPredicate(fPredicate);
result = fQuery.Fetch();
}
return result;
}
int32
TQueryWalker::CountEntries()
{
TRESPASS();
return -1;
}
status_t
TQueryWalker::Rewind()
{
fVolRoster.Rewind();
return NextVolume();
}
}