xref: /haiku/src/add-ons/kernel/file_systems/netfs/client/ShareAttrDir.cpp (revision 83b1a68c52ba3e0e8796282759f694b7fdddf06d)
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 NULL;
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