1/*
2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "UnpackingAttributeCookie.h"
8
9#include <algorithm>
10#include <new>
11
12#include <package/hpkg/DataReader.h>
13#include <package/hpkg/PackageData.h>
14#include <package/hpkg/PackageDataReader.h>
15
16#include <AutoDeleter.h>
17
18#include "AttributeIndexer.h"
19#include "AutoPackageAttributes.h"
20#include "DebugSupport.h"
21#include "Package.h"
22#include "PackageNode.h"
23
24
25using BPackageKit::BHPKG::BDataReader;
26using BPackageKit::BHPKG::BBufferDataReader;
27using BPackageKit::BHPKG::BFDDataReader;
28
29
30static status_t
31read_package_data(const PackageData& data, BDataReader* reader, off_t offset,
32	void* buffer, size_t* bufferSize)
33{
34	// check the offset
35	if (offset < 0 || (uint64)offset > data.UncompressedSize())
36		return B_BAD_VALUE;
37
38	// clamp the size
39	size_t toRead = std::min((uint64)*bufferSize,
40		data.UncompressedSize() - offset);
41
42	// read
43	if (toRead > 0) {
44		status_t error = reader->ReadData(offset, buffer, toRead);
45		if (error != B_OK)
46			RETURN_ERROR(error);
47	}
48
49	*bufferSize = toRead;
50	return B_OK;
51}
52
53
54UnpackingAttributeCookie::UnpackingAttributeCookie(PackageNode* packageNode,
55	PackageNodeAttribute* attribute, int openMode)
56	:
57	fPackageNode(packageNode),
58	fPackage(packageNode->GetPackage()),
59	fAttribute(attribute),
60	fOpenMode(openMode)
61{
62	fPackageNode->AcquireReference();
63	fPackage->AcquireReference();
64}
65
66
67UnpackingAttributeCookie::~UnpackingAttributeCookie()
68{
69	fPackageNode->ReleaseReference();
70	fPackage->ReleaseReference();
71}
72
73
74/*static*/ status_t
75UnpackingAttributeCookie::Open(PackageNode* packageNode, const StringKey& name,
76	int openMode, AttributeCookie*& _cookie)
77{
78	if (packageNode == NULL)
79		return B_ENTRY_NOT_FOUND;
80
81	// get the attribute
82	PackageNodeAttribute* attribute = packageNode->FindAttribute(name);
83	if (attribute == NULL) {
84		// We don't know the attribute -- maybe it's an auto-generated one.
85		return AutoPackageAttributes::OpenCookie(packageNode->GetPackage(),
86			name, openMode, _cookie);
87	}
88
89	// allocate the cookie
90	UnpackingAttributeCookie* cookie = new(std::nothrow)
91		UnpackingAttributeCookie(packageNode, attribute, openMode);
92	if (cookie == NULL)
93		RETURN_ERROR(B_NO_MEMORY);
94
95	_cookie = cookie;
96	return B_OK;
97}
98
99
100status_t
101UnpackingAttributeCookie::ReadAttribute(off_t offset, void* buffer,
102	size_t* bufferSize)
103{
104	return ReadAttribute(fPackageNode, fAttribute, offset, buffer, bufferSize);
105}
106
107
108status_t
109UnpackingAttributeCookie::ReadAttributeStat(struct stat* st)
110{
111	st->st_size = fAttribute->Data().UncompressedSize();
112	st->st_type = fAttribute->Type();
113
114	return B_OK;
115}
116
117
118/*static*/ status_t
119UnpackingAttributeCookie::ReadAttribute(PackageNode* packageNode,
120	PackageNodeAttribute* attribute, off_t offset, void* buffer,
121	size_t* bufferSize)
122{
123	const PackageData& data = attribute->Data();
124	if (data.IsEncodedInline()) {
125		// inline data
126		BBufferDataReader dataReader(data.InlineData(),
127			data.UncompressedSize());
128		return read_package_data(data, &dataReader, offset, buffer, bufferSize);
129	}
130
131	// data not inline -- open the package and let it create a data reader for
132	// us
133	Package* package = packageNode->GetPackage();
134	int fd = package->Open();
135	if (fd < 0)
136		RETURN_ERROR(fd);
137	PackageCloser packageCloser(package);
138
139	BAbstractBufferedDataReader* reader;
140	status_t error = package->CreateDataReader(data, reader);
141	if (error != B_OK)
142		return error;
143	ObjectDeleter<BAbstractBufferedDataReader> readerDeleter(reader);
144
145	return read_package_data(data, reader, offset, buffer, bufferSize);
146}
147
148
149/*static*/ status_t
150UnpackingAttributeCookie::IndexAttribute(PackageNode* packageNode,
151	AttributeIndexer* indexer)
152{
153	if (packageNode == NULL)
154		return B_ENTRY_NOT_FOUND;
155
156	// get the attribute
157	PackageNodeAttribute* attribute = packageNode->FindAttribute(
158		indexer->IndexName());
159	if (attribute == NULL)
160		return B_ENTRY_NOT_FOUND;
161
162	// create the index cookie
163	void* data;
164	size_t toRead;
165	status_t error = indexer->CreateCookie(packageNode, attribute,
166		attribute->Type(), attribute->Data().UncompressedSize(), data, toRead);
167	if (error != B_OK)
168		return error;
169
170	// read the attribute
171	if (toRead > 0) {
172		// The package must be open or otherwise reading the attribute data
173		// may fail.
174		int fd = packageNode->GetPackage()->Open();
175		if (fd < 0) {
176			indexer->DeleteCookie();
177			return fd;
178		}
179		PackageCloser packageCloser(packageNode->GetPackage());
180
181		error = ReadAttribute(packageNode, attribute, 0, data, &toRead);
182		if (error != B_OK) {
183			indexer->DeleteCookie();
184			return error;
185		}
186	}
187
188	attribute->SetIndexCookie(indexer->Cookie());
189
190	return B_OK;
191}
192