1// ShareAttrDir.cpp 2 3#include <new> 4 5#include <stdlib.h> 6#include <string.h> 7 8#include <Node.h> 9 10#include "AttrDirInfo.h" 11#include "AutoDeleter.h" 12#include "ShareAttrDir.h" 13 14// compare_attributes 15// 16// NULL is considered the maximum 17static 18int 19compare_attributes(const Attribute* a, const Attribute* b) 20{ 21 if (a == b) 22 return 0; 23 if (!a) 24 return 1; 25 if (!b) 26 return -1; 27 28 return strcmp(a->GetName(), b->GetName()); 29} 30 31// compare_attributes 32static 33int 34compare_attributes(const void* _a, const void* _b) 35{ 36 return compare_attributes(*(const Attribute**)_a, *(const Attribute**)_b); 37} 38 39// compare_iterators 40static 41int 42compare_iterators(const ShareAttrDirIterator* a, const ShareAttrDirIterator* b) 43{ 44 return compare_attributes(a->GetCurrentAttribute(), 45 b->GetCurrentAttribute()); 46} 47 48// compare_iterators 49static 50int 51compare_iterators(const void* _a, const void* _b) 52{ 53 return compare_iterators(*(const ShareAttrDirIterator**)_a, 54 *(const ShareAttrDirIterator**)_b); 55} 56 57// constructor 58Attribute::Attribute(const char* name, const attr_info& info, 59 const void* data) 60 : fInfo(info) 61{ 62 char* nameBuffer = fDataAndName; 63 64 // copy data, if any 65 if (data) { 66 nameBuffer += info.size; 67 memcpy(fDataAndName, data, info.size); 68 69 // store a negative size to indicate we also have the data 70 fInfo.size = -info.size; 71 } 72 73 // copy the name 74 strcpy(nameBuffer, name); 75} 76 77// destructor 78Attribute::~Attribute() 79{ 80} 81 82// CreateAttribute 83status_t 84Attribute::CreateAttribute(const char* name, const attr_info& info, 85 const void* data, Attribute** attribute) 86{ 87 if (!name || !attribute) 88 return B_BAD_VALUE; 89 90 // compute the size 91 int32 nameLen = strlen(name); 92 int32 size = sizeof(Attribute) + nameLen; 93 if (data) 94 size += info.size; 95 96 void* buffer = malloc(size); 97 if (!buffer) 98 return B_NO_MEMORY; 99 100 *attribute = new(buffer) Attribute(name, info, data); 101 return B_OK; 102} 103 104// DeleteAttribute 105void 106Attribute::DeleteAttribute(Attribute* attribute) 107{ 108 if (attribute) { 109 attribute->~Attribute(); 110 free(attribute); 111 } 112} 113 114// GetName 115const char* 116Attribute::GetName() const 117{ 118 return (fInfo.size >= 0 ? fDataAndName : fDataAndName - fInfo.size); 119} 120 121// GetInfo 122void 123Attribute::GetInfo(attr_info* info) const 124{ 125 if (info) { 126 info->type = fInfo.type; 127 info->size = GetSize(); 128 } 129} 130 131// GetType 132uint32 133Attribute::GetType() const 134{ 135 return fInfo.type; 136} 137 138// GetSize 139off_t 140Attribute::GetSize() const 141{ 142 return (fInfo.size >= 0 ? fInfo.size : -fInfo.size); 143} 144 145// GetData 146const void* 147Attribute::GetData() const 148{ 149 return (fInfo.size >= 0 ? NULL : fDataAndName); 150} 151 152 153// #pragma mark - 154 155// constructor 156ShareAttrDir::ShareAttrDir() 157 : fAttributes(), 158 fRevision(-1), 159 fUpToDate(false) 160{ 161} 162 163// destructor 164ShareAttrDir::~ShareAttrDir() 165{ 166 ClearAttrDir(); 167} 168 169// Init 170status_t 171ShareAttrDir::Init(const AttrDirInfo& dirInfo) 172{ 173 if (!dirInfo.isValid) 174 return B_BAD_VALUE; 175 176 // get the attributes 177 Attribute** attributes = NULL; 178 int32 count = 0; 179 status_t error = _GetAttributes(dirInfo, attributes, count); 180 if (error != B_OK) 181 return error; 182 ArrayDeleter<Attribute*> _(attributes); 183 184 // add the attributes 185 for (int32 i = 0; i < count; i++) 186 fAttributes.Insert(attributes[i]); 187 188 fRevision = dirInfo.revision; 189 fUpToDate = true; 190 191 return B_OK; 192} 193 194// Update 195status_t 196ShareAttrDir::Update(const AttrDirInfo& dirInfo, 197 DoublyLinkedList<ShareAttrDirIterator>* iterators) 198{ 199 if (!dirInfo.isValid) 200 return B_BAD_VALUE; 201 202 if (fRevision >= dirInfo.revision) 203 return B_OK; 204 205 // allocate an array for the old attributes 206 int32 oldCount = fAttributes.Size(); 207 Attribute** oldAttributes = new(std::nothrow) Attribute*[oldCount]; 208 if (!oldAttributes) 209 return B_NO_MEMORY; 210 ArrayDeleter<Attribute*> _(oldAttributes); 211 212 // get the new attributes 213 Attribute** newAttributes = NULL; 214 int32 newCount = 0; 215 status_t error = _GetAttributes(dirInfo, newAttributes, newCount); 216 if (error != B_OK) 217 return error; 218 ArrayDeleter<Attribute*> _2(newAttributes); 219 220 // sort the iterators 221 int32 iteratorCount = (iterators ? iterators->Count() : 0); 222 if (iteratorCount > 0) { 223 // allocate an array 224 ShareAttrDirIterator** _iterators 225 = new(std::nothrow) ShareAttrDirIterator*[iteratorCount]; 226 if (!_iterators) 227 return B_NO_MEMORY; 228 ArrayDeleter<ShareAttrDirIterator*> _3(_iterators); 229 230 // move the iterators 231 for (int32 i = 0; i < iteratorCount; i++) { 232 ShareAttrDirIterator* iterator = iterators->First(); 233 _iterators[i] = iterator; 234 iterators->Remove(iterator); 235 } 236 237 // sort them 238 qsort(_iterators, iteratorCount, sizeof(ShareAttrDirIterator*), 239 compare_iterators); 240 241 // move them back into the list 242 for (int32 i = 0; i < iteratorCount; i++) 243 iterators->Insert(_iterators[i]); 244 } 245 246 // remove the old attributes 247 for (int32 i = 0; i < oldCount; i++) { 248 Attribute* attribute = fAttributes.GetFirst(); 249 oldAttributes[i] = attribute; 250 fAttributes.Remove(attribute); 251 } 252 253 // add the new attributes 254 int32 oldIndex = 0; 255 int32 newIndex = 0; 256 ShareAttrDirIterator* iterator = (iterators ? iterators->First() : NULL); 257 while (oldIndex < oldCount || newIndex < newCount) { 258 Attribute* oldAttr = (oldCount > 0 ? oldAttributes[oldIndex] : NULL); 259 Attribute* newAttr = (newCount > 0 ? newAttributes[newIndex] : NULL); 260 int cmp = compare_attributes(oldAttr, newAttr); 261 if (cmp < 0) { 262 // oldAttr is obsolete: move all iterators pointing to it to the 263 // next new attribute 264 while (iterator && iterator->GetCurrentAttribute() == oldAttr) { 265 iterator->SetCurrentAttribute(newAttr); 266 iterator = iterators->GetNext(iterator); 267 } 268 oldIndex++; 269 } else if (cmp > 0) { 270 // newAttr is new 271 fAttributes.Insert(newAttr); 272 newIndex++; 273 } else { 274 // oldAttr == newAttr 275 fAttributes.Insert(newAttr); 276 oldIndex++; 277 newIndex++; 278 279 // move the attributes pointing to this attribute 280 while (iterator && iterator->GetCurrentAttribute() == oldAttr) { 281 iterator->SetCurrentAttribute(newAttr); 282 iterator = iterators->GetNext(iterator); 283 } 284 } 285 } 286 287 // delete the old attributes 288 for (int32 i = 0; i < oldCount; i++) 289 Attribute::DeleteAttribute(oldAttributes[i]); 290 291 fRevision = dirInfo.revision; 292 fUpToDate = true; 293 294 return B_OK; 295} 296 297// SetRevision 298void 299ShareAttrDir::SetRevision(int64 revision) 300{ 301 fRevision = revision; 302} 303 304// GetRevision 305int64 306ShareAttrDir::GetRevision() const 307{ 308 return fRevision; 309} 310 311// SetUpToDate 312void 313ShareAttrDir::SetUpToDate(bool upToDate) 314{ 315 fUpToDate = upToDate; 316} 317 318// IsUpToDate 319bool 320ShareAttrDir::IsUpToDate() const 321{ 322 return fUpToDate; 323} 324 325// ClearAttrDir 326void 327ShareAttrDir::ClearAttrDir() 328{ 329 while (Attribute* attribute = GetFirstAttribute()) 330 RemoveAttribute(attribute); 331} 332 333// AddAttribute 334status_t 335ShareAttrDir::AddAttribute(const char* name, const attr_info& info, 336 const void* data) 337{ 338 if (!name || GetAttribute(name)) 339 return B_BAD_VALUE; 340 341 // create the attribute 342 Attribute* attribute; 343 status_t error = Attribute::CreateAttribute(name, info, data, &attribute); 344 if (error != B_OK) 345 return error; 346 347 // add the attribute 348 fAttributes.Insert(attribute); 349 350 return B_OK; 351} 352 353// RemoveAttribute 354bool 355ShareAttrDir::RemoveAttribute(const char* name) 356{ 357 if (!name) 358 return false; 359 360 for (SLList<Attribute>::Iterator it = fAttributes.GetIterator(); 361 it.HasNext();) { 362 Attribute* attribute = it.Next(); 363 if (strcmp(attribute->GetName(), name) == 0) { 364 it.Remove(); 365 Attribute::DeleteAttribute(attribute); 366 return true; 367 } 368 } 369 370 return false; 371} 372 373// RemoveAttribute 374void 375ShareAttrDir::RemoveAttribute(Attribute* attribute) 376{ 377 if (!attribute) 378 return; 379 380 fAttributes.Remove(attribute); 381 Attribute::DeleteAttribute(attribute); 382} 383 384// GetAttribute 385Attribute* 386ShareAttrDir::GetAttribute(const char* name) const 387{ 388 if (!name) 389 return NULL; 390 391 for (SLList<Attribute>::ConstIterator it = fAttributes.GetIterator(); 392 it.HasNext();) { 393 Attribute* attribute = it.Next(); 394 if (strcmp(attribute->GetName(), name) == 0) 395 return attribute; 396 } 397 398 return NULL; 399} 400 401// GetFirstAttribute 402Attribute* 403ShareAttrDir::GetFirstAttribute() const 404{ 405 return fAttributes.GetFirst(); 406} 407 408// GetNextAttribute 409Attribute* 410ShareAttrDir::GetNextAttribute(Attribute* attribute) const 411{ 412 return (attribute ? fAttributes.GetNext(attribute) : NULL); 413} 414 415// _GetAttributes 416status_t 417ShareAttrDir::_GetAttributes(const AttrDirInfo& dirInfo, 418 Attribute**& _attributes, int32& _count) 419{ 420 if (!dirInfo.isValid) 421 return B_BAD_VALUE; 422 423 int32 count = dirInfo.attributeInfos.CountElements(); 424 const AttributeInfo* attrInfos = dirInfo.attributeInfos.GetElements(); 425 426 // allocate an attribute array 427 Attribute** attributes = NULL; 428 if (count > 0) { 429 attributes = new(std::nothrow) Attribute*[count]; 430 if (!attributes) 431 return B_NO_MEMORY; 432 memset(attributes, 0, sizeof(Attribute*) * count); 433 } 434 435 status_t error = B_OK; 436 for (int32 i = 0; i < count; i++) { 437 const AttributeInfo& attrInfo = attrInfos[i]; 438 439 // create the attribute 440 const void* data = attrInfo.data.GetData(); 441 if (data && attrInfo.data.GetSize() != attrInfo.info.size) 442 data = NULL; 443 error = Attribute::CreateAttribute(attrInfo.name.GetString(), 444 attrInfo.info, data, attributes + i); 445 if (error != B_OK) 446 break; 447 } 448 449 // cleanup on error 450 if (error != B_OK) { 451 for (int32 i = 0; i < count; i++) { 452 if (Attribute* attribute = attributes[i]) 453 Attribute::DeleteAttribute(attribute); 454 } 455 delete[] attributes; 456 457 return error; 458 } 459 460 // sort the attribute array 461 if (count > 0) 462 qsort(attributes, count, sizeof(Attribute*), compare_attributes); 463 464 _attributes = attributes; 465 _count = count; 466 return B_OK; 467} 468 469