1 /* 2 * Copyright 2009-2014, 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 14 #include <DataIO.h> 15 #include <package/hpkg/DataReader.h> 16 #include <package/hpkg/PackageDataReader.h> 17 18 #include <AutoDeleter.h> 19 #include <util/AutoLock.h> 20 21 #include "DebugSupport.h" 22 #include "ClassCache.h" 23 #include "Package.h" 24 25 26 using namespace BPackageKit::BHPKG; 27 28 29 // #pragma mark - class cache 30 31 32 CLASS_CACHE(PackageFile); 33 34 35 // #pragma mark - DataAccessor 36 37 38 struct PackageFile::IORequestOutput : BDataIO { 39 public: 40 IORequestOutput(io_request* request) 41 : 42 fRequest(request) 43 { 44 } 45 46 virtual ssize_t Write(const void* buffer, size_t size) 47 { 48 status_t error = write_to_io_request(fRequest, buffer, size); 49 RETURN_ERROR(error == B_OK ? (ssize_t)size : (ssize_t)error); 50 } 51 52 private: 53 io_request* fRequest; 54 }; 55 56 57 struct PackageFile::DataAccessor { 58 DataAccessor(Package* package, PackageData* data) 59 : 60 fPackage(package), 61 fData(data), 62 fReader(NULL), 63 fFileCache(NULL) 64 { 65 } 66 67 ~DataAccessor() 68 { 69 file_cache_delete(fFileCache); 70 delete fReader; 71 } 72 73 status_t Init(dev_t deviceID, ino_t nodeID, int fd) 74 { 75 // create a reader for the data 76 status_t error = fPackage->CreateDataReader(*fData, fReader); 77 if (error != B_OK) 78 return error; 79 80 // create a file cache 81 fFileCache = file_cache_create(deviceID, nodeID, 82 fData->UncompressedSize()); 83 if (fFileCache == NULL) 84 RETURN_ERROR(B_NO_MEMORY); 85 86 return B_OK; 87 } 88 89 status_t ReadData(off_t offset, void* buffer, size_t* bufferSize) 90 { 91 return file_cache_read(fFileCache, NULL, offset, buffer, bufferSize); 92 } 93 94 status_t ReadData(io_request* request) 95 { 96 off_t offset = io_request_offset(request); 97 size_t size = io_request_length(request); 98 99 if (offset < 0 || (uint64)offset > fData->UncompressedSize()) 100 RETURN_ERROR(B_BAD_VALUE); 101 102 size_t toRead = std::min((uint64)size, 103 fData->UncompressedSize() - offset); 104 105 if (toRead > 0) { 106 IORequestOutput output(request); 107 status_t error = fReader->ReadDataToOutput(offset, toRead, &output); 108 if (error != B_OK) 109 RETURN_ERROR(error); 110 } 111 112 return B_OK; 113 } 114 115 private: 116 Package* fPackage; 117 PackageData* fData; 118 BAbstractBufferedDataReader* fReader; 119 void* fFileCache; 120 }; 121 122 123 // #pragma mark - PackageFile 124 125 126 PackageFile::PackageFile(Package* package, mode_t mode, const PackageData& data) 127 : 128 PackageLeafNode(package, mode), 129 fData(data), 130 fDataAccessor(NULL) 131 { 132 } 133 134 135 PackageFile::~PackageFile() 136 { 137 } 138 139 140 status_t 141 PackageFile::VFSInit(dev_t deviceID, ino_t nodeID) 142 { 143 status_t error = PackageNode::VFSInit(deviceID, nodeID); 144 if (error != B_OK) 145 return error; 146 MethodDeleter<PackageNode, void, &PackageNode::NonVirtualVFSUninit> 147 baseClassUninit(this); 148 149 // open the package -- that's already done by PackageNode::VFSInit(), so it 150 // shouldn't fail here. We only need to do it again, since we need the FD. 151 BReference<Package> package(GetPackage()); 152 int fd = package->Open(); 153 if (fd < 0) 154 RETURN_ERROR(fd); 155 PackageCloser packageCloser(package); 156 157 // create the data accessor 158 fDataAccessor = new(std::nothrow) DataAccessor(package, &fData); 159 if (fDataAccessor == NULL) 160 RETURN_ERROR(B_NO_MEMORY); 161 162 error = fDataAccessor->Init(deviceID, nodeID, fd); 163 if (error != B_OK) { 164 delete fDataAccessor; 165 fDataAccessor = NULL; 166 return error; 167 } 168 169 baseClassUninit.Detach(); 170 return B_OK; 171 } 172 173 174 void 175 PackageFile::VFSUninit() 176 { 177 if (fDataAccessor != NULL) { 178 delete fDataAccessor; 179 fDataAccessor = NULL; 180 } 181 182 PackageNode::VFSUninit(); 183 } 184 185 186 off_t 187 PackageFile::FileSize() const 188 { 189 return fData.UncompressedSize(); 190 } 191 192 193 status_t 194 PackageFile::Read(off_t offset, void* buffer, size_t* bufferSize) 195 { 196 if (fDataAccessor == NULL) 197 return B_BAD_VALUE; 198 return fDataAccessor->ReadData(offset, buffer, bufferSize); 199 } 200 201 202 status_t 203 PackageFile::Read(io_request* request) 204 { 205 if (fDataAccessor == NULL) 206 return B_BAD_VALUE; 207 return fDataAccessor->ReadData(request); 208 } 209