1/* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7#include "PackageFile.h" 8 9#include <algorithm> 10#include <new> 11 12#include <fs_cache.h> 13#include <util/AutoLock.h> 14 15#include <package/hpkg/DataOutput.h> 16#include <package/hpkg/DataReader.h> 17#include <package/hpkg/PackageDataReader.h> 18 19#include "DebugSupport.h" 20#include "GlobalFactory.h" 21#include "Package.h" 22 23 24using namespace BPackageKit::BHPKG; 25 26 27// #pragma mark - DataAccessor 28 29 30struct PackageFile::IORequestOutput : BDataOutput { 31public: 32 IORequestOutput(io_request* request) 33 : 34 fRequest(request) 35 { 36 } 37 38 virtual status_t WriteData(const void* buffer, size_t size) 39 { 40 RETURN_ERROR(write_to_io_request(fRequest, buffer, size)); 41 } 42 43private: 44 io_request* fRequest; 45}; 46 47 48struct PackageFile::DataAccessor { 49 DataAccessor(BPackageData* data) 50 : 51 fData(data), 52 fDataReader(NULL), 53 fReader(NULL), 54 fFileCache(NULL) 55 { 56 mutex_init(&fLock, "file data accessor"); 57 } 58 59 ~DataAccessor() 60 { 61 file_cache_delete(fFileCache); 62 delete fReader; 63 delete fDataReader; 64 mutex_destroy(&fLock); 65 } 66 67 status_t Init(dev_t deviceID, ino_t nodeID, int fd) 68 { 69 // create a BDataReader for the compressed data 70 if (fData->IsEncodedInline()) { 71 fDataReader = new(std::nothrow) BBufferDataReader( 72 fData->InlineData(), fData->CompressedSize()); 73 } else 74 fDataReader = new(std::nothrow) BFDDataReader(fd); 75 76 if (fDataReader == NULL) 77 RETURN_ERROR(B_NO_MEMORY); 78 79 // create a BPackageDataReader 80 status_t error = GlobalFactory::Default()->CreatePackageDataReader( 81 fDataReader, *fData, fReader); 82 if (error != B_OK) 83 RETURN_ERROR(error); 84 85 // create a file cache 86 fFileCache = file_cache_create(deviceID, nodeID, 87 fData->UncompressedSize()); 88 if (fFileCache == NULL) 89 RETURN_ERROR(B_NO_MEMORY); 90 91 return B_OK; 92 } 93 94 status_t ReadData(off_t offset, void* buffer, size_t* bufferSize) 95 { 96 if (offset < 0 || (uint64)offset > fData->UncompressedSize()) 97 return B_BAD_VALUE; 98 99 *bufferSize = std::min((uint64)*bufferSize, 100 fData->UncompressedSize() - offset); 101 102 return file_cache_read(fFileCache, NULL, offset, buffer, bufferSize); 103 } 104 105 status_t ReadData(io_request* request) 106 { 107 off_t offset = io_request_offset(request); 108 size_t size = io_request_length(request); 109 110 if (offset < 0 || (uint64)offset > fData->UncompressedSize()) 111 RETURN_ERROR(B_BAD_VALUE); 112 113 size_t toRead = std::min((uint64)size, 114 fData->UncompressedSize() - offset); 115 116 if (toRead > 0) { 117 IORequestOutput output(request); 118 MutexLocker locker(fLock); 119 status_t error = fReader->ReadDataToOutput(offset, toRead, &output); 120 if (error != B_OK) 121 RETURN_ERROR(error); 122 } 123 124 return B_OK; 125 } 126 127private: 128 mutex fLock; 129 BPackageData* fData; 130 BDataReader* fDataReader; 131 BPackageDataReader* fReader; 132 void* fFileCache; 133}; 134 135 136// #pragma mark - PackageFile 137 138 139PackageFile::PackageFile(Package* package, mode_t mode, const BPackageData& data) 140 : 141 PackageLeafNode(package, mode), 142 fData(data), 143 fDataAccessor(NULL) 144{ 145} 146 147 148PackageFile::~PackageFile() 149{ 150} 151 152 153status_t 154PackageFile::VFSInit(dev_t deviceID, ino_t nodeID) 155{ 156 // open the package 157 int fd = fPackage->Open(); 158 if (fd < 0) 159 RETURN_ERROR(fd); 160 PackageCloser packageCloser(fPackage); 161 162 // create the data accessor 163 fDataAccessor = new(std::nothrow) DataAccessor(&fData); 164 if (fDataAccessor == NULL) 165 RETURN_ERROR(B_NO_MEMORY); 166 167 status_t error = fDataAccessor->Init(deviceID, nodeID, fd); 168 if (error != B_OK) { 169 delete fDataAccessor; 170 fDataAccessor = NULL; 171 return error; 172 } 173 174 packageCloser.Detach(); 175 return B_OK; 176} 177 178 179void 180PackageFile::VFSUninit() 181{ 182 if (fDataAccessor != NULL) { 183 fPackage->Close(); 184 delete fDataAccessor; 185 fDataAccessor = NULL; 186 } 187} 188 189 190off_t 191PackageFile::FileSize() const 192{ 193 return fData.UncompressedSize(); 194} 195 196 197status_t 198PackageFile::Read(off_t offset, void* buffer, size_t* bufferSize) 199{ 200 if (fDataAccessor == NULL) 201 return B_BAD_VALUE; 202 return fDataAccessor->ReadData(offset, buffer, bufferSize); 203} 204 205 206status_t 207PackageFile::Read(io_request* request) 208{ 209 if (fDataAccessor == NULL) 210 return B_BAD_VALUE; 211 return fDataAccessor->ReadData(request); 212} 213