#include <new>
#include <string.h>
#include <sys/stat.h>
#include <Directory.h>
#include <fs_info.h>
#include <HashMap.h>
#include "Directory.h"
#include "FDManager.h"
#include "Entry.h"
#include "Node.h"
#include "Volume.h"
struct Volume::NodeMap : HashMap<HashKey64<ino_t>, Node*> {
};
struct Volume::EntryKey {
EntryKey() {}
EntryKey(ino_t directoryID, const char* name)
: directoryID(directoryID),
name(name)
{
}
EntryKey(Entry* entry)
: directoryID(entry->GetDirectoryID()),
name(entry->GetName())
{
}
EntryKey(const EntryKey& other)
: directoryID(other.directoryID),
name(other.name)
{
}
uint32 GetHashCode() const
{
uint32 hash = (uint32)directoryID;
hash = 31 * hash + (uint32)(directoryID >> 32);
hash = 31 * hash + string_hash(name);
return hash;
}
EntryKey& operator=(const EntryKey& other)
{
directoryID = other.directoryID;
name = other.name;
return *this;
}
bool operator==(const EntryKey& other) const
{
if (directoryID != other.directoryID)
return false;
if (name)
return (other.name && strcmp(name, other.name) == 0);
return !other.name;
}
bool operator!=(const EntryKey& other) const
{
return !(*this == other);
}
ino_t directoryID;
const char* name;
};
struct Volume::EntryMap : HashMap<EntryKey, Entry*> {
};
Volume::Volume(dev_t id)
: fID(id),
fRootDir(NULL),
fFSFlags(0),
fNodes(NULL),
fEntries(NULL)
{
}
Volume::~Volume()
{
if (fEntries) {
for (EntryMap::Iterator it = fEntries->GetIterator(); it.HasNext();) {
Entry* entry = it.Next().value;
delete entry;
}
delete fEntries;
}
if (fNodes) {
if (fRootDir)
RemoveNode(fRootDir);
for (NodeMap::Iterator it = fNodes->GetIterator(); it.HasNext();) {
Node* node = it.Next().value;
delete node;
}
delete fNodes;
}
delete fRootDir;
}
status_t
Volume::Init()
{
fNodes = new(std::nothrow) NodeMap;
if (!fNodes)
return B_NO_MEMORY;
if (fNodes->InitCheck() != B_OK)
return fNodes->InitCheck();
fEntries = new(std::nothrow) EntryMap;
if (!fEntries)
return B_NO_MEMORY;
if (fEntries->InitCheck() != B_OK)
return fEntries->InitCheck();
fs_info info;
status_t error = fs_stat_dev(fID, &info);
if (error != B_OK)
return error;
fFSFlags = info.flags;
node_ref rootRef;
rootRef.device = fID;
rootRef.node = info.root;
BDirectory rootDir;
error = FDManager::SetDirectory(&rootDir, &rootRef);
if (error != B_OK)
return error;
struct stat st;
error = rootDir.GetStat(&st);
if (error != B_OK)
return error;
fRootDir = new(std::nothrow) Directory(this, st);
if (!fRootDir)
return B_NO_MEMORY;
return B_OK;
}
dev_t
Volume::GetID() const
{
return fID;
}
Directory*
Volume::GetRootDirectory() const
{
return fRootDir;
}
ino_t
Volume::GetRootID() const
{
return fRootDir->GetID();
}
bool
Volume::KnowsQuery() const
{
return (fFSFlags & B_FS_HAS_QUERY);
}
status_t
Volume::AddNode(Node* node)
{
if (!node || node->GetVolume() != this || GetNode(node->GetID()))
return B_BAD_VALUE;
return fNodes->Put(node->GetID(), node);
}
bool
Volume::RemoveNode(Node* node)
{
if (node && GetNode(node->GetID()) == node) {
fNodes->Remove(node->GetID());
return true;
}
return false;
}
Node*
Volume::GetNode(ino_t nodeID)
{
return fNodes->Get(nodeID);
}
Node*
Volume::GetFirstNode() const
{
NodeMap::Iterator it = fNodes->GetIterator();
if (it.HasNext())
return it.Next().value;
return NULL;
}
status_t
Volume::AddEntry(Entry* entry)
{
if (!entry || entry->GetVolume() != this
|| GetEntry(entry->GetDirectoryID(), entry->GetName())) {
return B_BAD_VALUE;
}
return fEntries->Put(EntryKey(entry), entry);
}
bool
Volume::RemoveEntry(Entry* entry)
{
if (entry && GetEntry(entry->GetDirectoryID(), entry->GetName()) == entry) {
fEntries->Remove(EntryKey(entry));
return true;
}
return false;
}
Entry*
Volume::GetEntry(ino_t dirID, const char* name)
{
return fEntries->Get(EntryKey(dirID, name));
}
Entry*
Volume::GetFirstEntry() const
{
EntryMap::Iterator it = fEntries->GetIterator();
if (it.HasNext())
return it.Next().value;
return NULL;
}