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
Attribute(const char * name,const attr_info & info,const void * data)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
~Attribute()37 Attribute::~Attribute()
38 {
39 }
40
41 // CreateAttribute
42 status_t
CreateAttribute(const char * name,const attr_info & info,const void * data,Attribute ** attribute)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
DeleteAttribute(Attribute * attribute)65 Attribute::DeleteAttribute(Attribute* attribute)
66 {
67 if (attribute) {
68 attribute->~Attribute();
69 free(attribute);
70 }
71 }
72
73 // GetName
74 const char*
GetName() const75 Attribute::GetName() const
76 {
77 return (fInfo.size >= 0 ? fDataAndName : fDataAndName - fInfo.size);
78 }
79
80 // GetInfo
81 void
GetInfo(attr_info * info) const82 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
GetType() const92 Attribute::GetType() const
93 {
94 return fInfo.type;
95 }
96
97 // GetSize
98 off_t
GetSize() const99 Attribute::GetSize() const
100 {
101 return (fInfo.size >= 0 ? fInfo.size : -fInfo.size);
102 }
103
104 // GetData
105 const void*
GetData() const106 Attribute::GetData() const
107 {
108 return (fInfo.size >= 0 ? NULL : fDataAndName);
109 }
110
111
112 // #pragma mark -
113
114 // constructor
AttributeDirectory()115 AttributeDirectory::AttributeDirectory()
116 : fAttributes(),
117 fStatus(ATTRIBUTE_DIRECTORY_NOT_LOADED)
118 {
119 }
120
121 // destructor
~AttributeDirectory()122 AttributeDirectory::~AttributeDirectory()
123 {
124 ClearAttrDir();
125 }
126
127 // GetAttrDirStatus
128 uint32
GetAttrDirStatus() const129 AttributeDirectory::GetAttrDirStatus() const
130 {
131 return fStatus;
132 }
133
134 // IsAttrDirValid
135 bool
IsAttrDirValid() const136 AttributeDirectory::IsAttrDirValid() const
137 {
138 return (fStatus == ATTRIBUTE_DIRECTORY_VALID);
139 }
140
141 // LoadAttrDir
142 status_t
LoadAttrDir()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
ClearAttrDir()183 AttributeDirectory::ClearAttrDir()
184 {
185 while (Attribute* attribute = GetFirstAttribute())
186 RemoveAttribute(attribute);
187 }
188
189 // AddAttribute
190 status_t
AddAttribute(const char * name,const attr_info & info,const void * data)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
RemoveAttribute(const char * name)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
RemoveAttribute(Attribute * attribute)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
UpdateAttribute(const char * name,bool * removed,attr_info * _info,const void ** _data)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*
GetAttribute(const char * name) const320 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 NULL;
333 }
334
335 // GetFirstAttribute
336 Attribute*
GetFirstAttribute() const337 AttributeDirectory::GetFirstAttribute() const
338 {
339 return fAttributes.GetFirst();
340 }
341
342 // GetNextAttribute
343 Attribute*
GetNextAttribute(Attribute * attribute) const344 AttributeDirectory::GetNextAttribute(Attribute* attribute) const
345 {
346 return (attribute ? fAttributes.GetNext(attribute) : NULL);
347 }
348
349 // _LoadAttribute
350 status_t
_LoadAttribute(BNode & node,const char * name,attr_info & info,void * data,bool & dataLoaded)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