root/src/add-ons/kernel/file_systems/netfs/client/VirtualDir.cpp
// VirtualDir.cpp

#include "VirtualDir.h"

#include <string.h>

#include <AutoDeleter.h>

// constructor
VirtualDirEntry::VirtualDirEntry()
        : fName(),
          fNode(NULL)
{
}

// destructor
VirtualDirEntry::~VirtualDirEntry()
{
}

// SetTo
status_t
VirtualDirEntry::SetTo(const char* name, Node* node)
{
        if (!name || strlen(name) == 0 || !node)
                return B_BAD_VALUE;

        if (!fName.SetTo(name))
                return B_NO_MEMORY;
        fNode = node;

        return B_OK;
}

// GetName
const char*
VirtualDirEntry::GetName() const
{
        return fName.GetString();
}

// GetNode
Node*
VirtualDirEntry::GetNode() const
{
        return fNode;
}


// #pragma mark -

// constructor
VirtualDirIterator::VirtualDirIterator()
        : fDirectory(NULL),
          fCurrentEntry(NULL),
          fState(STATE_DOT)
{
}

// destructor
VirtualDirIterator::~VirtualDirIterator()
{
        SetDirectory(NULL);
}

// SetDirectory
void
VirtualDirIterator::SetDirectory(VirtualDir* directory, bool onlyChildren)
{
        // unset the old directory
        if (fDirectory)
                fDirectory->RemoveDirIterator(this);

        // set the new directory
        fDirectory = directory;
        if (fDirectory) {
                fDirectory->AddDirIterator(this);

                if (onlyChildren) {
                        fCurrentEntry = fDirectory->GetFirstEntry();
                        fState = STATE_OTHERS;
                } else {
                        fCurrentEntry = NULL;
                        fState = STATE_DOT;
                }
        }
}

// GetCurrentEntry
bool
VirtualDirIterator::GetCurrentEntry(const char** name, Node** node)
{
        if (!fDirectory)
                return false;
        switch (fState) {
                case STATE_DOT:
                        *name = ".";
                        *node = fDirectory;
                        return true;
                case STATE_DOT_DOT:
                        *name = "..";
                        *node = fDirectory->GetParent();
                        if (!*node)
                                *node = fDirectory;
                        return true;
                default:
                        if (!fCurrentEntry)
                                return false;
                        *name = fCurrentEntry->GetName();
                        *node = fCurrentEntry->GetNode();
                        return true;
        }
}

// GetCurrentEntry
VirtualDirEntry*
VirtualDirIterator::GetCurrentEntry() const
{
        return fCurrentEntry;
}

// NextEntry
void
VirtualDirIterator::NextEntry()
{
        if (!fDirectory)
                return;
        switch (fState) {
                case STATE_DOT:
                        fState = STATE_DOT_DOT;
                        break;
                case STATE_DOT_DOT:
                        fState = STATE_OTHERS;
                        fCurrentEntry = fDirectory->GetFirstEntry();
                        break;
                default:
                        if (fCurrentEntry)
                                fCurrentEntry = fDirectory->GetNextEntry(fCurrentEntry);
                        break;
        }
}

// Rewind
void
VirtualDirIterator::Rewind()
{
        fState = STATE_DOT;
        fCurrentEntry = NULL;
}


// #pragma mark -

// constructor
VirtualDir::VirtualDir(Volume* volume, vnode_id nodeID)
        : Node(volume, nodeID),
          fParent(NULL),
          fCreationTime(0),
          fEntries(),
          fEntryList(),
          fIterators()
{
}

// destructor
VirtualDir::~VirtualDir()
{
        while (VirtualDirEntry* entry = GetFirstEntry())
                RemoveEntry(entry->GetName());
}

// InitCheck
status_t
VirtualDir::InitCheck() const
{
        return fEntries.InitCheck();
}

// SetParent
void
VirtualDir::SetParent(VirtualDir* parent)
{
        fParent = parent;
}

// GetParent
VirtualDir*
VirtualDir::GetParent() const
{
        return fParent;
}

// GetCreationTime
time_t
VirtualDir::GetCreationTime() const
{
        return fCreationTime;
}

// AddEntry
status_t
VirtualDir::AddEntry(const char* name, Node* child)
{
        if (!name || !child || fEntries.ContainsKey(name))
                return B_BAD_VALUE;

        // create an entry
        VirtualDirEntry* entry = new(std::nothrow) VirtualDirEntry;
        if (!entry)
                return B_NO_MEMORY;
        ObjectDeleter<VirtualDirEntry> entryDeleter(entry);
        status_t error = entry->SetTo(name, child);
        if (error != B_OK)
                return error;

        // add the entry
        error = fEntries.Put(name, entry);
        if (error != B_OK)
                return error;
        fEntryList.Insert(entry);
        entryDeleter.Detach();

        // TODO: That's not so nice. Check whether better to move the fParent
        // property to Node.
        if (VirtualDir* childDir = dynamic_cast<VirtualDir*>(child))
                childDir->SetParent(this);

        return error;
}

// RemoveEntry
Node*
VirtualDir::RemoveEntry(const char* name)
{
        if (!name)
                return NULL;

        Node* child = NULL;
        VirtualDirEntry* entry = fEntries.Remove(name);
        if (entry) {
                child = entry->GetNode();
                // update the directory iterators pointing to the removed entry
                for (VirtualDirIterator* iterator = fIterators.First();
                         iterator;
                         iterator = fIterators.GetNext(iterator)) {
                        if (iterator->GetCurrentEntry() == entry)
                                iterator->NextEntry();
                }

                // remove the entry completely
                fEntryList.Remove(entry);
                delete entry;

                // TODO: See AddEntry().
                if (VirtualDir* childDir = dynamic_cast<VirtualDir*>(child))
                        childDir->SetParent(NULL);
        }
        return child;
}

// GetEntry
VirtualDirEntry*
VirtualDir::GetEntry(const char* name) const
{
        if (!name)
                return NULL;

        return fEntries.Get(name);
}

// GetChildNode
Node*
VirtualDir::GetChildNode(const char* name) const
{
        if (VirtualDirEntry* entry = GetEntry(name))
                return entry->GetNode();
        return NULL;
}

// GetFirstEntry
VirtualDirEntry*
VirtualDir::GetFirstEntry() const
{
        return fEntryList.First();
}

// GetNextEntry
VirtualDirEntry*
VirtualDir::GetNextEntry(VirtualDirEntry* entry) const
{
        if (!entry)
                return NULL;
        return fEntryList.GetNext(entry);
}

// AddDirIterator
void
VirtualDir::AddDirIterator(VirtualDirIterator* iterator)
{
        if (!iterator)
                return;

        fIterators.Insert(iterator);
}

// RemoveDirIterator
void
VirtualDir::RemoveDirIterator(VirtualDirIterator* iterator)
{
        if (!iterator)
                return;

        fIterators.Remove(iterator);
}