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 mutex_init(&fLock, "file data accessor"); 66 } 67 68 ~DataAccessor() 69 { 70 file_cache_delete(fFileCache); 71 delete fReader; 72 mutex_destroy(&fLock); 73 } 74 75 status_t Init(dev_t deviceID, ino_t nodeID, int fd) 76 { 77 // create a reader for the data 78 status_t error = fPackage->CreateDataReader(*fData, fReader); 79 if (error != B_OK) 80 return error; 81 82 // create a file cache 83 fFileCache = file_cache_create(deviceID, nodeID, 84 fData->UncompressedSize()); 85 if (fFileCache == NULL) 86 RETURN_ERROR(B_NO_MEMORY); 87 88 return B_OK; 89 } 90 91 status_t ReadData(off_t offset, void* buffer, size_t* bufferSize) 92 { 93 return file_cache_read(fFileCache, NULL, offset, buffer, bufferSize); 94 } 95 96 status_t ReadData(io_request* request) 97 { 98 off_t offset = io_request_offset(request); 99 size_t size = io_request_length(request); 100 101 if (offset < 0 || (uint64)offset > fData->UncompressedSize()) 102 RETURN_ERROR(B_BAD_VALUE); 103 104 size_t toRead = std::min((uint64)size, 105 fData->UncompressedSize() - offset); 106 107 if (toRead > 0) { 108 IORequestOutput output(request); 109 MutexLocker locker(fLock, false, fData->Version() == 1); 110 // V2 readers are reentrant 111 status_t error = fReader->ReadDataToOutput(offset, toRead, &output); 112 if (error != B_OK) 113 RETURN_ERROR(error); 114 } 115 116 return B_OK; 117 } 118 119 private: 120 mutex fLock; 121 Package* fPackage; 122 PackageData* fData; 123 BAbstractBufferedDataReader* fReader; 124 void* fFileCache; 125 }; 126 127 128 // #pragma mark - PackageFile 129 130 131 PackageFile::PackageFile(Package* package, mode_t mode, const PackageData& data) 132 : 133 PackageLeafNode(package, mode), 134 fData(data), 135 fDataAccessor(NULL) 136 { 137 } 138 139 140 PackageFile::~PackageFile() 141 { 142 } 143 144 145 status_t 146 PackageFile::VFSInit(dev_t deviceID, ino_t nodeID) 147 { 148 status_t error = PackageNode::VFSInit(deviceID, nodeID); 149 if (error != B_OK) 150 return error; 151 MethodDeleter<PackageNode, void, &PackageNode::NonVirtualVFSUninit> 152 baseClassUninit(this); 153 154 // open the package -- that's already done by PackageNode::VFSInit(), so it 155 // shouldn't fail here. We only need to do it again, since we need the FD. 156 BReference<Package> package(GetPackage()); 157 int fd = package->Open(); 158 if (fd < 0) 159 RETURN_ERROR(fd); 160 PackageCloser packageCloser(package); 161 162 // create the data accessor 163 fDataAccessor = new(std::nothrow) DataAccessor(package, &fData); 164 if (fDataAccessor == NULL) 165 RETURN_ERROR(B_NO_MEMORY); 166 167 error = fDataAccessor->Init(deviceID, nodeID, fd); 168 if (error != B_OK) { 169 delete fDataAccessor; 170 fDataAccessor = NULL; 171 return error; 172 } 173 174 baseClassUninit.Detach(); 175 return B_OK; 176 } 177 178 179 void 180 PackageFile::VFSUninit() 181 { 182 if (fDataAccessor != NULL) { 183 delete fDataAccessor; 184 fDataAccessor = NULL; 185 } 186 187 PackageNode::VFSUninit(); 188 } 189 190 191 off_t 192 PackageFile::FileSize() const 193 { 194 return fData.UncompressedSize(); 195 } 196 197 198 status_t 199 PackageFile::Read(off_t offset, void* buffer, size_t* bufferSize) 200 { 201 if (fDataAccessor == NULL) 202 return B_BAD_VALUE; 203 return fDataAccessor->ReadData(offset, buffer, bufferSize); 204 } 205 206 207 status_t 208 PackageFile::Read(io_request* request) 209 { 210 if (fDataAccessor == NULL) 211 return B_BAD_VALUE; 212 return fDataAccessor->ReadData(request); 213 } 214