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