xref: /haiku/src/add-ons/kernel/file_systems/packagefs/nodes/UnpackingAttributeCookie.cpp (revision d1a0bc4fb57c1381d3b92dd985900d168a5ab0ec)
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 
25 using BPackageKit::BHPKG::BDataReader;
26 using BPackageKit::BHPKG::BBufferDataReader;
27 using BPackageKit::BHPKG::BFDDataReader;
28 
29 
30 static status_t
read_package_data(const PackageData & data,BDataReader * reader,off_t offset,void * buffer,size_t * bufferSize)31 read_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 
UnpackingAttributeCookie(PackageNode * packageNode,PackageNodeAttribute * attribute,int openMode)54 UnpackingAttributeCookie::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 
~UnpackingAttributeCookie()67 UnpackingAttributeCookie::~UnpackingAttributeCookie()
68 {
69 	fPackageNode->ReleaseReference();
70 	fPackage->ReleaseReference();
71 }
72 
73 
74 /*static*/ status_t
Open(PackageNode * packageNode,const StringKey & name,int openMode,AttributeCookie * & _cookie)75 UnpackingAttributeCookie::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 
100 status_t
ReadAttribute(off_t offset,void * buffer,size_t * bufferSize)101 UnpackingAttributeCookie::ReadAttribute(off_t offset, void* buffer,
102 	size_t* bufferSize)
103 {
104 	return ReadAttribute(fPackageNode, fAttribute, offset, buffer, bufferSize);
105 }
106 
107 
108 status_t
ReadAttributeStat(struct stat * st)109 UnpackingAttributeCookie::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
ReadAttribute(PackageNode * packageNode,PackageNodeAttribute * attribute,off_t offset,void * buffer,size_t * bufferSize)119 UnpackingAttributeCookie::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
IndexAttribute(PackageNode * packageNode,AttributeIndexer * indexer)150 UnpackingAttributeCookie::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