// ShareAttrDir.cpp #include #include #include #include #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 _(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* 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 _(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 _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 _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::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::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; }