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 26 using BPackageKit::BHPKG::BBufferDataReader; 27 using BPackageKit::BHPKG::BFDDataReader; 28 29 30 static status_t 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 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 67 UnpackingAttributeCookie::~UnpackingAttributeCookie() 68 { 69 fPackageNode->ReleaseReference(); 70 fPackage->ReleaseReference(); 71 } 72 73 74 /*static*/ status_t 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 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 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 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 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