1// AttributeDirectory.cpp 2 3#include <new> 4 5#include <stdlib.h> 6#include <string.h> 7 8#include <AutoDeleter.h> 9#include <Node.h> 10 11#include "AttributeDirectory.h" 12 13// small data size 14static const int32 kSmallAttributeSize = 8; 15 16// constructor 17Attribute::Attribute(const char* name, const attr_info& info, 18 const void* data) 19 : fInfo(info) 20{ 21 char* nameBuffer = fDataAndName; 22 23 // copy data, if any 24 if (data) { 25 nameBuffer += info.size; 26 memcpy(fDataAndName, data, info.size); 27 28 // store a negative size to indicate we also have the data 29 fInfo.size = -info.size; 30 } 31 32 // copy the name 33 strcpy(nameBuffer, name); 34} 35 36// destructor 37Attribute::~Attribute() 38{ 39} 40 41// CreateAttribute 42status_t 43Attribute::CreateAttribute(const char* name, const attr_info& info, 44 const void* data, Attribute** attribute) 45{ 46 if (!name || !attribute) 47 return B_BAD_VALUE; 48 49 // compute the size 50 int32 nameLen = strlen(name); 51 int32 size = sizeof(Attribute) + nameLen; 52 if (data) 53 size += info.size; 54 55 void* buffer = malloc(size); 56 if (!buffer) 57 return B_NO_MEMORY; 58 59 *attribute = new(buffer) Attribute(name, info, data); 60 return B_OK; 61} 62 63// DeleteAttribute 64void 65Attribute::DeleteAttribute(Attribute* attribute) 66{ 67 if (attribute) { 68 attribute->~Attribute(); 69 free(attribute); 70 } 71} 72 73// GetName 74const char* 75Attribute::GetName() const 76{ 77 return (fInfo.size >= 0 ? fDataAndName : fDataAndName - fInfo.size); 78} 79 80// GetInfo 81void 82Attribute::GetInfo(attr_info* info) const 83{ 84 if (info) { 85 info->type = fInfo.type; 86 info->size = GetSize(); 87 } 88} 89 90// GetType 91uint32 92Attribute::GetType() const 93{ 94 return fInfo.type; 95} 96 97// GetSize 98off_t 99Attribute::GetSize() const 100{ 101 return (fInfo.size >= 0 ? fInfo.size : -fInfo.size); 102} 103 104// GetData 105const void* 106Attribute::GetData() const 107{ 108 return (fInfo.size >= 0 ? NULL : fDataAndName); 109} 110 111 112// #pragma mark - 113 114// constructor 115AttributeDirectory::AttributeDirectory() 116 : fAttributes(), 117 fStatus(ATTRIBUTE_DIRECTORY_NOT_LOADED) 118{ 119} 120 121// destructor 122AttributeDirectory::~AttributeDirectory() 123{ 124 ClearAttrDir(); 125} 126 127// GetAttrDirStatus 128uint32 129AttributeDirectory::GetAttrDirStatus() const 130{ 131 return fStatus; 132} 133 134// IsAttrDirValid 135bool 136AttributeDirectory::IsAttrDirValid() const 137{ 138 return (fStatus == ATTRIBUTE_DIRECTORY_VALID); 139} 140 141// LoadAttrDir 142status_t 143AttributeDirectory::LoadAttrDir() 144{ 145 // nothing to do, if already loaded 146 if (fStatus == ATTRIBUTE_DIRECTORY_VALID) 147 return B_OK; 148 149 // if we tried earlier and the attr dir was too big, we fail again 150 if (fStatus == ATTRIBUTE_DIRECTORY_TOO_BIG) 151 return B_ERROR; 152 153 // open the node 154 BNode node; 155 status_t error = OpenNode(node); 156 if (error != B_OK) 157 return error; 158 159 // iterate through the attribute directory 160 char name[B_ATTR_NAME_LENGTH]; 161 while (node.GetNextAttrName(name) == B_OK) { 162 // get the attribute data 163 attr_info info; 164 char data[kSmallAttributeSize]; 165 bool dataLoaded = false; 166 error = _LoadAttribute(node, name, info, data, dataLoaded); 167 if (error != B_OK) 168 break; 169 170 // create the attribute 171 error = AddAttribute(name, info, (dataLoaded ? data : NULL)); 172 } 173 174 if (error != B_OK) 175 ClearAttrDir(); 176// TODO: Enforce maximum attribute directory size. 177 178 return error; 179} 180 181// ClearAttrDir 182void 183AttributeDirectory::ClearAttrDir() 184{ 185 while (Attribute* attribute = GetFirstAttribute()) 186 RemoveAttribute(attribute); 187} 188 189// AddAttribute 190status_t 191AttributeDirectory::AddAttribute(const char* name, const attr_info& info, 192 const void* data) 193{ 194 if (!name || GetAttribute(name)) 195 return B_BAD_VALUE; 196 197 // create the attribute 198 Attribute* attribute; 199 status_t error = Attribute::CreateAttribute(name, info, data, &attribute); 200 if (error != B_OK) 201 return error; 202 203 // add the attribute 204 fAttributes.Insert(attribute); 205 206 return B_OK; 207} 208 209// RemoveAttribute 210bool 211AttributeDirectory::RemoveAttribute(const char* name) 212{ 213 if (!name) 214 return false; 215 216 for (SLList<Attribute>::Iterator it = fAttributes.GetIterator(); 217 it.HasNext();) { 218 Attribute* attribute = it.Next(); 219 if (strcmp(attribute->GetName(), name) == 0) { 220 it.Remove(); 221 Attribute::DeleteAttribute(attribute); 222 return true; 223 } 224 } 225 226 return false; 227} 228 229// RemoveAttribute 230void 231AttributeDirectory::RemoveAttribute(Attribute* attribute) 232{ 233 if (!attribute) 234 return; 235 236 fAttributes.Remove(attribute); 237 Attribute::DeleteAttribute(attribute); 238} 239 240// UpdateAttribute 241status_t 242AttributeDirectory::UpdateAttribute(const char* name, bool* removed, 243 attr_info* _info, const void** _data) 244{ 245 if (!name || !removed) 246 return B_BAD_VALUE; 247 248 // open the node 249 BNode node; 250 status_t error = OpenNode(node); 251 if (error != B_OK) { 252 ClearAttrDir(); 253 if (fStatus == ATTRIBUTE_DIRECTORY_VALID) 254 fStatus = ATTRIBUTE_DIRECTORY_NOT_LOADED; 255 return error; 256 } 257 258 // get the attribute data 259 attr_info info; 260 char data[kSmallAttributeSize]; 261 bool dataLoaded = false; 262 error = _LoadAttribute(node, name, info, 263 (fStatus == ATTRIBUTE_DIRECTORY_VALID ? data : NULL), dataLoaded); 264 if (error == B_OK) { 265 if (fStatus == ATTRIBUTE_DIRECTORY_VALID) { 266 // remove the attribute 267 Attribute* previous = NULL; 268 for (SLList<Attribute>::Iterator it = fAttributes.GetIterator(); 269 it.HasNext();) { 270 Attribute* attribute = it.Next(); 271 if (strcmp(attribute->GetName(), name) == 0) { 272 it.Remove(); 273 Attribute::DeleteAttribute(attribute); 274 break; 275 } 276 previous = attribute; 277 } 278 279// TODO: Enforce the maximum attr dir size. 280 // re-create the attribute 281 Attribute* attribute; 282 error = Attribute::CreateAttribute(name, info, data, 283 &attribute); 284 if (error == B_OK) { 285 // add the attribute 286 fAttributes.InsertAfter(previous, attribute); 287 288 // return the desired info 289 if (_info) 290 attribute->GetInfo(_info); 291 if (_data) 292 *_data = attribute->GetData(); 293 *removed = false; 294 } 295 } else if (error == B_OK) { 296 if (_info) 297 *_info = info; 298 if (_data) 299 *_data = NULL; 300 *removed = false; 301 } 302 } else { 303 *removed = true; 304 RemoveAttribute(name); 305 error = B_OK; 306 } 307 308 // clean up on error 309 if (error != B_OK) { 310 ClearAttrDir(); 311 if (fStatus == ATTRIBUTE_DIRECTORY_VALID) 312 fStatus = ATTRIBUTE_DIRECTORY_NOT_LOADED; 313 } 314 315 return error; 316} 317 318// GetAttribute 319Attribute* 320AttributeDirectory::GetAttribute(const char* name) const 321{ 322 if (!name) 323 return NULL; 324 325 for (SLList<Attribute>::ConstIterator it = fAttributes.GetIterator(); 326 it.HasNext();) { 327 Attribute* attribute = it.Next(); 328 if (strcmp(attribute->GetName(), name) == 0) 329 return attribute; 330 } 331 332 return NULL; 333} 334 335// GetFirstAttribute 336Attribute* 337AttributeDirectory::GetFirstAttribute() const 338{ 339 return fAttributes.GetFirst(); 340} 341 342// GetNextAttribute 343Attribute* 344AttributeDirectory::GetNextAttribute(Attribute* attribute) const 345{ 346 return (attribute ? fAttributes.GetNext(attribute) : NULL); 347} 348 349// _LoadAttribute 350status_t 351AttributeDirectory::_LoadAttribute(BNode& node, const char* name, 352 attr_info& info, void* data, bool& dataLoaded) 353{ 354 // stat the attribute 355 status_t error = node.GetAttrInfo(name, &info); 356 if (error != B_OK) 357 return error; 358 359 // if the data are small enough, read them 360 if (data && info.size <= kSmallAttributeSize) { 361 ssize_t bytesRead = node.ReadAttr(name, info.type, 0, data, 362 info.size); 363 dataLoaded = (bytesRead == info.size); 364 } 365 366 return B_OK; 367} 368 369