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 14 static const int32 kSmallAttributeSize = 8; 15 16 // constructor 17 Attribute::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 37 Attribute::~Attribute() 38 { 39 } 40 41 // CreateAttribute 42 status_t 43 Attribute::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 64 void 65 Attribute::DeleteAttribute(Attribute* attribute) 66 { 67 if (attribute) { 68 attribute->~Attribute(); 69 free(attribute); 70 } 71 } 72 73 // GetName 74 const char* 75 Attribute::GetName() const 76 { 77 return (fInfo.size >= 0 ? fDataAndName : fDataAndName - fInfo.size); 78 } 79 80 // GetInfo 81 void 82 Attribute::GetInfo(attr_info* info) const 83 { 84 if (info) { 85 info->type = fInfo.type; 86 info->size = GetSize(); 87 } 88 } 89 90 // GetType 91 uint32 92 Attribute::GetType() const 93 { 94 return fInfo.type; 95 } 96 97 // GetSize 98 off_t 99 Attribute::GetSize() const 100 { 101 return (fInfo.size >= 0 ? fInfo.size : -fInfo.size); 102 } 103 104 // GetData 105 const void* 106 Attribute::GetData() const 107 { 108 return (fInfo.size >= 0 ? NULL : fDataAndName); 109 } 110 111 112 // #pragma mark - 113 114 // constructor 115 AttributeDirectory::AttributeDirectory() 116 : fAttributes(), 117 fStatus(ATTRIBUTE_DIRECTORY_NOT_LOADED) 118 { 119 } 120 121 // destructor 122 AttributeDirectory::~AttributeDirectory() 123 { 124 ClearAttrDir(); 125 } 126 127 // GetAttrDirStatus 128 uint32 129 AttributeDirectory::GetAttrDirStatus() const 130 { 131 return fStatus; 132 } 133 134 // IsAttrDirValid 135 bool 136 AttributeDirectory::IsAttrDirValid() const 137 { 138 return (fStatus == ATTRIBUTE_DIRECTORY_VALID); 139 } 140 141 // LoadAttrDir 142 status_t 143 AttributeDirectory::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 182 void 183 AttributeDirectory::ClearAttrDir() 184 { 185 while (Attribute* attribute = GetFirstAttribute()) 186 RemoveAttribute(attribute); 187 } 188 189 // AddAttribute 190 status_t 191 AttributeDirectory::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 210 bool 211 AttributeDirectory::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 230 void 231 AttributeDirectory::RemoveAttribute(Attribute* attribute) 232 { 233 if (!attribute) 234 return; 235 236 fAttributes.Remove(attribute); 237 Attribute::DeleteAttribute(attribute); 238 } 239 240 // UpdateAttribute 241 status_t 242 AttributeDirectory::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 319 Attribute* 320 AttributeDirectory::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 false; 333 } 334 335 // GetFirstAttribute 336 Attribute* 337 AttributeDirectory::GetFirstAttribute() const 338 { 339 return fAttributes.GetFirst(); 340 } 341 342 // GetNextAttribute 343 Attribute* 344 AttributeDirectory::GetNextAttribute(Attribute* attribute) const 345 { 346 return (attribute ? fAttributes.GetNext(attribute) : NULL); 347 } 348 349 // _LoadAttribute 350 status_t 351 AttributeDirectory::_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