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 17 static 18 int 19 compare_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 32 static 33 int 34 compare_attributes(const void* _a, const void* _b) 35 { 36 return compare_attributes(*(const Attribute**)_a, *(const Attribute**)_b); 37 } 38 39 // compare_iterators 40 static 41 int 42 compare_iterators(const ShareAttrDirIterator* a, const ShareAttrDirIterator* b) 43 { 44 return compare_attributes(a->GetCurrentAttribute(), 45 b->GetCurrentAttribute()); 46 } 47 48 // compare_iterators 49 static 50 int 51 compare_iterators(const void* _a, const void* _b) 52 { 53 return compare_iterators(*(const ShareAttrDirIterator**)_a, 54 *(const ShareAttrDirIterator**)_b); 55 } 56 57 // constructor 58 Attribute::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 78 Attribute::~Attribute() 79 { 80 } 81 82 // CreateAttribute 83 status_t 84 Attribute::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 105 void 106 Attribute::DeleteAttribute(Attribute* attribute) 107 { 108 if (attribute) { 109 attribute->~Attribute(); 110 free(attribute); 111 } 112 } 113 114 // GetName 115 const char* 116 Attribute::GetName() const 117 { 118 return (fInfo.size >= 0 ? fDataAndName : fDataAndName - fInfo.size); 119 } 120 121 // GetInfo 122 void 123 Attribute::GetInfo(attr_info* info) const 124 { 125 if (info) { 126 info->type = fInfo.type; 127 info->size = GetSize(); 128 } 129 } 130 131 // GetType 132 uint32 133 Attribute::GetType() const 134 { 135 return fInfo.type; 136 } 137 138 // GetSize 139 off_t 140 Attribute::GetSize() const 141 { 142 return (fInfo.size >= 0 ? fInfo.size : -fInfo.size); 143 } 144 145 // GetData 146 const void* 147 Attribute::GetData() const 148 { 149 return (fInfo.size >= 0 ? NULL : fDataAndName); 150 } 151 152 153 // #pragma mark - 154 155 // constructor 156 ShareAttrDir::ShareAttrDir() 157 : fAttributes(), 158 fRevision(-1), 159 fUpToDate(false) 160 { 161 } 162 163 // destructor 164 ShareAttrDir::~ShareAttrDir() 165 { 166 ClearAttrDir(); 167 } 168 169 // Init 170 status_t 171 ShareAttrDir::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 195 status_t 196 ShareAttrDir::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 298 void 299 ShareAttrDir::SetRevision(int64 revision) 300 { 301 fRevision = revision; 302 } 303 304 // GetRevision 305 int64 306 ShareAttrDir::GetRevision() const 307 { 308 return fRevision; 309 } 310 311 // SetUpToDate 312 void 313 ShareAttrDir::SetUpToDate(bool upToDate) 314 { 315 fUpToDate = upToDate; 316 } 317 318 // IsUpToDate 319 bool 320 ShareAttrDir::IsUpToDate() const 321 { 322 return fUpToDate; 323 } 324 325 // ClearAttrDir 326 void 327 ShareAttrDir::ClearAttrDir() 328 { 329 while (Attribute* attribute = GetFirstAttribute()) 330 RemoveAttribute(attribute); 331 } 332 333 // AddAttribute 334 status_t 335 ShareAttrDir::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 354 bool 355 ShareAttrDir::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 374 void 375 ShareAttrDir::RemoveAttribute(Attribute* attribute) 376 { 377 if (!attribute) 378 return; 379 380 fAttributes.Remove(attribute); 381 Attribute::DeleteAttribute(attribute); 382 } 383 384 // GetAttribute 385 Attribute* 386 ShareAttrDir::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 false; 399 } 400 401 // GetFirstAttribute 402 Attribute* 403 ShareAttrDir::GetFirstAttribute() const 404 { 405 return fAttributes.GetFirst(); 406 } 407 408 // GetNextAttribute 409 Attribute* 410 ShareAttrDir::GetNextAttribute(Attribute* attribute) const 411 { 412 return (attribute ? fAttributes.GetNext(attribute) : NULL); 413 } 414 415 // _GetAttributes 416 status_t 417 ShareAttrDir::_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