1/*
2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "UnpackingAttributeDirectoryCookie.h"
8
9#include "DebugSupport.h"
10#include "PackageNode.h"
11#include "Utils.h"
12
13
14UnpackingAttributeDirectoryCookie::UnpackingAttributeDirectoryCookie(
15	PackageNode* packageNode)
16	:
17	fPackageNode(packageNode),
18	fAttribute(NULL),
19	fState(AUTO_PACKAGE_ATTRIBUTE_ENUM_FIRST)
20{
21	if (fPackageNode != NULL) {
22		fPackageNode->AcquireReference();
23		fAttribute = fPackageNode->Attributes().Head();
24	}
25}
26
27
28UnpackingAttributeDirectoryCookie::~UnpackingAttributeDirectoryCookie()
29{
30	if (fPackageNode != NULL)
31		fPackageNode->ReleaseReference();
32}
33
34
35/*static*/ status_t
36UnpackingAttributeDirectoryCookie::Open(PackageNode* packageNode,
37	AttributeDirectoryCookie*& _cookie)
38{
39	UnpackingAttributeDirectoryCookie* cookie = new(std::nothrow)
40		UnpackingAttributeDirectoryCookie(packageNode);
41	if (cookie == NULL)
42		return B_NO_MEMORY;
43
44	_cookie = cookie;
45	return B_OK;
46}
47
48
49status_t
50UnpackingAttributeDirectoryCookie::Read(dev_t volumeID, ino_t nodeID,
51	struct dirent* buffer, size_t bufferSize, uint32* _count)
52{
53	uint32 maxCount = *_count;
54	uint32 count = 0;
55
56	dirent* previousEntry = NULL;
57
58	while (fState < AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT || fAttribute != NULL) {
59		// don't read more entries than requested
60		if (count >= maxCount)
61			break;
62
63		// align the buffer for subsequent entries
64		if (count > 0) {
65			addr_t offset = (addr_t)buffer % 8;
66			if (offset > 0) {
67				offset = 8 - offset;
68				if (bufferSize <= offset)
69					break;
70
71				previousEntry->d_reclen += offset;
72				buffer = (dirent*)((addr_t)buffer + offset);
73				bufferSize -= offset;
74			}
75		}
76
77		// get the attribute name
78		const char* name;
79		if (fState < AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT) {
80			name = AutoPackageAttributes::NameForAttribute(
81				(AutoPackageAttribute)fState);
82		} else
83			name = fAttribute->Name();
84
85		// fill in the entry name -- checks whether the entry fits into the
86		// buffer
87		if (!set_dirent_name(buffer, bufferSize, name, strlen(name))) {
88			if (count == 0)
89				RETURN_ERROR(B_BUFFER_OVERFLOW);
90			break;
91		}
92
93		// fill in the other data
94		buffer->d_dev = volumeID;
95		buffer->d_ino = nodeID;
96
97		count++;
98		previousEntry = buffer;
99		bufferSize -= buffer->d_reclen;
100		buffer = (dirent*)((addr_t)buffer + buffer->d_reclen);
101
102		if (fState < AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT)
103			fState++;
104		else
105			fAttribute = fPackageNode->Attributes().GetNext(fAttribute);
106	}
107
108	*_count = count;
109	return B_OK;
110}
111
112
113status_t
114UnpackingAttributeDirectoryCookie::Rewind()
115{
116	if (fPackageNode != NULL)
117		fAttribute = fPackageNode->Attributes().Head();
118
119	fState = AUTO_PACKAGE_ATTRIBUTE_ENUM_FIRST;
120
121	return B_OK;
122}
123