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