#include <new>
#include <stdlib.h>
#include <string.h>
#include <AutoDeleter.h>
#include <Node.h>
#include "AttributeDirectory.h"
static const int32 kSmallAttributeSize = 8;
Attribute::Attribute(const char* name, const attr_info& info,
const void* data)
: fInfo(info)
{
char* nameBuffer = fDataAndName;
if (data) {
nameBuffer += info.size;
memcpy(fDataAndName, data, info.size);
fInfo.size = -info.size;
}
strcpy(nameBuffer, name);
}
Attribute::~Attribute()
{
}
status_t
Attribute::CreateAttribute(const char* name, const attr_info& info,
const void* data, Attribute** attribute)
{
if (!name || !attribute)
return B_BAD_VALUE;
int32 nameLen = strlen(name);
int32 size = sizeof(Attribute) + nameLen;
if (data)
size += info.size;
void* buffer = malloc(size);
if (!buffer)
return B_NO_MEMORY;
*attribute = new(buffer) Attribute(name, info, data);
return B_OK;
}
void
Attribute::DeleteAttribute(Attribute* attribute)
{
if (attribute) {
attribute->~Attribute();
free(attribute);
}
}
const char*
Attribute::GetName() const
{
return (fInfo.size >= 0 ? fDataAndName : fDataAndName - fInfo.size);
}
void
Attribute::GetInfo(attr_info* info) const
{
if (info) {
info->type = fInfo.type;
info->size = GetSize();
}
}
uint32
Attribute::GetType() const
{
return fInfo.type;
}
off_t
Attribute::GetSize() const
{
return (fInfo.size >= 0 ? fInfo.size : -fInfo.size);
}
const void*
Attribute::GetData() const
{
return (fInfo.size >= 0 ? NULL : fDataAndName);
}
AttributeDirectory::AttributeDirectory()
: fAttributes(),
fStatus(ATTRIBUTE_DIRECTORY_NOT_LOADED)
{
}
AttributeDirectory::~AttributeDirectory()
{
ClearAttrDir();
}
uint32
AttributeDirectory::GetAttrDirStatus() const
{
return fStatus;
}
bool
AttributeDirectory::IsAttrDirValid() const
{
return (fStatus == ATTRIBUTE_DIRECTORY_VALID);
}
status_t
AttributeDirectory::LoadAttrDir()
{
if (fStatus == ATTRIBUTE_DIRECTORY_VALID)
return B_OK;
if (fStatus == ATTRIBUTE_DIRECTORY_TOO_BIG)
return B_ERROR;
BNode node;
status_t error = OpenNode(node);
if (error != B_OK)
return error;
char name[B_ATTR_NAME_LENGTH];
while (node.GetNextAttrName(name) == B_OK) {
attr_info info;
char data[kSmallAttributeSize];
bool dataLoaded = false;
error = _LoadAttribute(node, name, info, data, dataLoaded);
if (error != B_OK)
break;
error = AddAttribute(name, info, (dataLoaded ? data : NULL));
}
if (error != B_OK)
ClearAttrDir();
return error;
}
void
AttributeDirectory::ClearAttrDir()
{
while (Attribute* attribute = GetFirstAttribute())
RemoveAttribute(attribute);
}
status_t
AttributeDirectory::AddAttribute(const char* name, const attr_info& info,
const void* data)
{
if (!name || GetAttribute(name))
return B_BAD_VALUE;
Attribute* attribute;
status_t error = Attribute::CreateAttribute(name, info, data, &attribute);
if (error != B_OK)
return error;
fAttributes.Insert(attribute);
return B_OK;
}
bool
AttributeDirectory::RemoveAttribute(const char* name)
{
if (!name)
return false;
for (SLList<Attribute>::Iterator it = fAttributes.GetIterator();
it.HasNext();) {
Attribute* attribute = it.Next();
if (strcmp(attribute->GetName(), name) == 0) {
it.Remove();
Attribute::DeleteAttribute(attribute);
return true;
}
}
return false;
}
void
AttributeDirectory::RemoveAttribute(Attribute* attribute)
{
if (!attribute)
return;
fAttributes.Remove(attribute);
Attribute::DeleteAttribute(attribute);
}
status_t
AttributeDirectory::UpdateAttribute(const char* name, bool* removed,
attr_info* _info, const void** _data)
{
if (!name || !removed)
return B_BAD_VALUE;
BNode node;
status_t error = OpenNode(node);
if (error != B_OK) {
ClearAttrDir();
if (fStatus == ATTRIBUTE_DIRECTORY_VALID)
fStatus = ATTRIBUTE_DIRECTORY_NOT_LOADED;
return error;
}
attr_info info;
char data[kSmallAttributeSize];
bool dataLoaded = false;
error = _LoadAttribute(node, name, info,
(fStatus == ATTRIBUTE_DIRECTORY_VALID ? data : NULL), dataLoaded);
if (error == B_OK) {
if (fStatus == ATTRIBUTE_DIRECTORY_VALID) {
Attribute* previous = NULL;
for (SLList<Attribute>::Iterator it = fAttributes.GetIterator();
it.HasNext();) {
Attribute* attribute = it.Next();
if (strcmp(attribute->GetName(), name) == 0) {
it.Remove();
Attribute::DeleteAttribute(attribute);
break;
}
previous = attribute;
}
Attribute* attribute;
error = Attribute::CreateAttribute(name, info, data,
&attribute);
if (error == B_OK) {
fAttributes.InsertAfter(previous, attribute);
if (_info)
attribute->GetInfo(_info);
if (_data)
*_data = attribute->GetData();
*removed = false;
}
} else if (error == B_OK) {
if (_info)
*_info = info;
if (_data)
*_data = NULL;
*removed = false;
}
} else {
*removed = true;
RemoveAttribute(name);
error = B_OK;
}
if (error != B_OK) {
ClearAttrDir();
if (fStatus == ATTRIBUTE_DIRECTORY_VALID)
fStatus = ATTRIBUTE_DIRECTORY_NOT_LOADED;
}
return error;
}
Attribute*
AttributeDirectory::GetAttribute(const char* name) const
{
if (!name)
return NULL;
for (SLList<Attribute>::ConstIterator it = fAttributes.GetIterator();
it.HasNext();) {
Attribute* attribute = it.Next();
if (strcmp(attribute->GetName(), name) == 0)
return attribute;
}
return NULL;
}
Attribute*
AttributeDirectory::GetFirstAttribute() const
{
return fAttributes.GetFirst();
}
Attribute*
AttributeDirectory::GetNextAttribute(Attribute* attribute) const
{
return (attribute ? fAttributes.GetNext(attribute) : NULL);
}
status_t
AttributeDirectory::_LoadAttribute(BNode& node, const char* name,
attr_info& info, void* data, bool& dataLoaded)
{
status_t error = node.GetAttrInfo(name, &info);
if (error != B_OK)
return error;
if (data && info.size <= kSmallAttributeSize) {
ssize_t bytesRead = node.ReadAttr(name, info.type, 0, data,
info.size);
dataLoaded = (bytesRead == info.size);
}
return B_OK;
}