xref: /haiku/src/add-ons/kernel/file_systems/netfs/server/AttributeDirectory.cpp (revision 97901ec593ec4dd50ac115c1c35a6d72f6e489a5)
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