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