// ShareAttrDir.cpp
#include <new>
#include <stdlib.h>
#include <string.h>
#include <Node.h>
#include "AttrDirInfo.h"
#include "AutoDeleter.h"
#include "ShareAttrDir.h"
// compare_attributes
//
// NULL is considered the maximum
static
int
compare_attributes(const Attribute* a, const Attribute* b)
{
if (a == b)
return 0;
if (!a)
return 1;
if (!b)
return -1;
return strcmp(a->GetName(), b->GetName());
}
// compare_attributes
static
int
compare_attributes(const void* _a, const void* _b)
{
return compare_attributes(*(const Attribute**)_a, *(const Attribute**)_b);
}
// compare_iterators
static
int
compare_iterators(const ShareAttrDirIterator* a, const ShareAttrDirIterator* b)
{
return compare_attributes(a->GetCurrentAttribute(),
b->GetCurrentAttribute());
}
// compare_iterators
static
int
compare_iterators(const void* _a, const void* _b)
{
return compare_iterators(*(const ShareAttrDirIterator**)_a,
*(const ShareAttrDirIterator**)_b);
}
// constructor
Attribute::Attribute(const char* name, const attr_info& info,
const void* data)
: fInfo(info)
{
char* nameBuffer = fDataAndName;
// copy data, if any
if (data) {
nameBuffer += info.size;
memcpy(fDataAndName, data, info.size);
// store a negative size to indicate we also have the data
fInfo.size = -info.size;
}
// copy the name
strcpy(nameBuffer, name);
}
// destructor
Attribute::~Attribute()
{
}
// CreateAttribute
status_t
Attribute::CreateAttribute(const char* name, const attr_info& info,
const void* data, Attribute** attribute)
{
if (!name || !attribute)
return B_BAD_VALUE;
// compute the size
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;
}
// DeleteAttribute
void
Attribute::DeleteAttribute(Attribute* attribute)
{
if (attribute) {
attribute->~Attribute();
free(attribute);
}
}
// GetName
const char*
Attribute::GetName() const
{
return (fInfo.size >= 0 ? fDataAndName : fDataAndName - fInfo.size);
}
// GetInfo
void
Attribute::GetInfo(attr_info* info) const
{
if (info) {
info->type = fInfo.type;
info->size = GetSize();
}
}
// GetType
uint32
Attribute::GetType() const
{
return fInfo.type;
}
// GetSize
off_t
Attribute::GetSize() const
{
return (fInfo.size >= 0 ? fInfo.size : -fInfo.size);
}
// GetData
const void*
Attribute::GetData() const
{
return (fInfo.size >= 0 ? NULL : fDataAndName);
}
// #pragma mark -
// constructor
ShareAttrDir::ShareAttrDir()
: fAttributes(),
fRevision(-1),
fUpToDate(false)
{
}
// destructor
ShareAttrDir::~ShareAttrDir()
{
ClearAttrDir();
}
// Init
status_t
ShareAttrDir::Init(const AttrDirInfo& dirInfo)
{
if (!dirInfo.isValid)
return B_BAD_VALUE;
// get the attributes
Attribute** attributes = NULL;
int32 count = 0;
status_t error = _GetAttributes(dirInfo, attributes, count);
if (error != B_OK)
return error;
ArrayDeleter<Attribute*> _(attributes);
// add the attributes
for (int32 i = 0; i < count; i++)
fAttributes.Insert(attributes[i]);
fRevision = dirInfo.revision;
fUpToDate = true;
return B_OK;
}
// Update
status_t
ShareAttrDir::Update(const AttrDirInfo& dirInfo,
DoublyLinkedList<ShareAttrDirIterator>* iterators)
{
if (!dirInfo.isValid)
return B_BAD_VALUE;
if (fRevision >= dirInfo.revision)
return B_OK;
// allocate an array for the old attributes
int32 oldCount = fAttributes.Size();
Attribute** oldAttributes = new(std::nothrow) Attribute*[oldCount];
if (!oldAttributes)
return B_NO_MEMORY;
ArrayDeleter<Attribute*> _(oldAttributes);
// get the new attributes
Attribute** newAttributes = NULL;
int32 newCount = 0;
status_t error = _GetAttributes(dirInfo, newAttributes, newCount);
if (error != B_OK)
return error;
ArrayDeleter<Attribute*> _2(newAttributes);
// sort the iterators
int32 iteratorCount = (iterators ? iterators->Count() : 0);
if (iteratorCount > 0) {
// allocate an array
ShareAttrDirIterator** _iterators
= new(std::nothrow) ShareAttrDirIterator*[iteratorCount];
if (!_iterators)
return B_NO_MEMORY;
ArrayDeleter<ShareAttrDirIterator*> _3(_iterators);
// move the iterators
for (int32 i = 0; i < iteratorCount; i++) {
ShareAttrDirIterator* iterator = iterators->First();
_iterators[i] = iterator;
iterators->Remove(iterator);
}
// sort them
qsort(_iterators, iteratorCount, sizeof(ShareAttrDirIterator*),
compare_iterators);
// move them back into the list
for (int32 i = 0; i < iteratorCount; i++)
iterators->Insert(_iterators[i]);
}
// remove the old attributes
for (int32 i = 0; i < oldCount; i++) {
Attribute* attribute = fAttributes.GetFirst();
oldAttributes[i] = attribute;
fAttributes.Remove(attribute);
}
// add the new attributes
int32 oldIndex = 0;
int32 newIndex = 0;
ShareAttrDirIterator* iterator = (iterators ? iterators->First() : NULL);
while (oldIndex < oldCount || newIndex < newCount) {
Attribute* oldAttr = (oldCount > 0 ? oldAttributes[oldIndex] : NULL);
Attribute* newAttr = (newCount > 0 ? newAttributes[newIndex] : NULL);
int cmp = compare_attributes(oldAttr, newAttr);
if (cmp < 0) {
// oldAttr is obsolete: move all iterators pointing to it to the
// next new attribute
while (iterator && iterator->GetCurrentAttribute() == oldAttr) {
iterator->SetCurrentAttribute(newAttr);
iterator = iterators->GetNext(iterator);
}
oldIndex++;
} else if (cmp > 0) {
// newAttr is new
fAttributes.Insert(newAttr);
newIndex++;
} else {
// oldAttr == newAttr
fAttributes.Insert(newAttr);
oldIndex++;
newIndex++;
// move the attributes pointing to this attribute
while (iterator && iterator->GetCurrentAttribute() == oldAttr) {
iterator->SetCurrentAttribute(newAttr);
iterator = iterators->GetNext(iterator);
}
}
}
// delete the old attributes
for (int32 i = 0; i < oldCount; i++)
Attribute::DeleteAttribute(oldAttributes[i]);
fRevision = dirInfo.revision;
fUpToDate = true;
return B_OK;
}
// SetRevision
void
ShareAttrDir::SetRevision(int64 revision)
{
fRevision = revision;
}
// GetRevision
int64
ShareAttrDir::GetRevision() const
{
return fRevision;
}
// SetUpToDate
void
ShareAttrDir::SetUpToDate(bool upToDate)
{
fUpToDate = upToDate;
}
// IsUpToDate
bool
ShareAttrDir::IsUpToDate() const
{
return fUpToDate;
}
// ClearAttrDir
void
ShareAttrDir::ClearAttrDir()
{
while (Attribute* attribute = GetFirstAttribute())
RemoveAttribute(attribute);
}
// AddAttribute
status_t
ShareAttrDir::AddAttribute(const char* name, const attr_info& info,
const void* data)
{
if (!name || GetAttribute(name))
return B_BAD_VALUE;
// create the attribute
Attribute* attribute;
status_t error = Attribute::CreateAttribute(name, info, data, &attribute);
if (error != B_OK)
return error;
// add the attribute
fAttributes.Insert(attribute);
return B_OK;
}
// RemoveAttribute
bool
ShareAttrDir::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;
}
// RemoveAttribute
void
ShareAttrDir::RemoveAttribute(Attribute* attribute)
{
if (!attribute)
return;
fAttributes.Remove(attribute);
Attribute::DeleteAttribute(attribute);
}
// GetAttribute
Attribute*
ShareAttrDir::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;
}
// GetFirstAttribute
Attribute*
ShareAttrDir::GetFirstAttribute() const
{
return fAttributes.GetFirst();
}
// GetNextAttribute
Attribute*
ShareAttrDir::GetNextAttribute(Attribute* attribute) const
{
return (attribute ? fAttributes.GetNext(attribute) : NULL);
}
// _GetAttributes
status_t
ShareAttrDir::_GetAttributes(const AttrDirInfo& dirInfo,
Attribute**& _attributes, int32& _count)
{
if (!dirInfo.isValid)
return B_BAD_VALUE;
int32 count = dirInfo.attributeInfos.CountElements();
const AttributeInfo* attrInfos = dirInfo.attributeInfos.GetElements();
// allocate an attribute array
Attribute** attributes = NULL;
if (count > 0) {
attributes = new(std::nothrow) Attribute*[count];
if (!attributes)
return B_NO_MEMORY;
memset(attributes, 0, sizeof(Attribute*) * count);
}
status_t error = B_OK;
for (int32 i = 0; i < count; i++) {
const AttributeInfo& attrInfo = attrInfos[i];
// create the attribute
const void* data = attrInfo.data.GetData();
if (data && attrInfo.data.GetSize() != attrInfo.info.size)
data = NULL;
error = Attribute::CreateAttribute(attrInfo.name.GetString(),
attrInfo.info, data, attributes + i);
if (error != B_OK)
break;
}
// cleanup on error
if (error != B_OK) {
for (int32 i = 0; i < count; i++) {
if (Attribute* attribute = attributes[i])
Attribute::DeleteAttribute(attribute);
}
delete[] attributes;
return error;
}
// sort the attribute array
if (count > 0)
qsort(attributes, count, sizeof(Attribute*), compare_attributes);
_attributes = attributes;
_count = count;
return B_OK;
}
↑ V595 The 'iterators' pointer was utilized before it was verified against nullptr. Check lines: 243, 256.