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 "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 : BDataIO { 33 public: 34 IORequestOutput(io_request* request) 35 : 36 fRequest(request) 37 { 38 } 39 40 virtual ssize_t Write(const void* buffer, size_t size) 41 { 42 status_t error = write_to_io_request(fRequest, buffer, size); 43 RETURN_ERROR(error == B_OK ? (ssize_t)size : (ssize_t)error); 44 } 45 46 private: 47 io_request* fRequest; 48 }; 49 50 51 struct PackageFile::DataAccessor { 52 DataAccessor(Package* package, PackageData* data) 53 : 54 fPackage(package), 55 fData(data), 56 fReader(NULL), 57 fFileCache(NULL) 58 { 59 mutex_init(&fLock, "file data accessor"); 60 } 61 62 ~DataAccessor() 63 { 64 file_cache_delete(fFileCache); 65 delete fReader; 66 mutex_destroy(&fLock); 67 } 68 69 status_t Init(dev_t deviceID, ino_t nodeID, int fd) 70 { 71 // create a reader for the data 72 status_t error = fPackage->CreateDataReader(*fData, fReader); 73 if (error != B_OK) 74 return error; 75 76 // create a file cache 77 fFileCache = file_cache_create(deviceID, nodeID, 78 fData->UncompressedSize()); 79 if (fFileCache == NULL) 80 RETURN_ERROR(B_NO_MEMORY); 81 82 return B_OK; 83 } 84 85 status_t ReadData(off_t offset, void* buffer, size_t* bufferSize) 86 { 87 if (offset < 0 || (uint64)offset > fData->UncompressedSize()) 88 return B_BAD_VALUE; 89 90 *bufferSize = std::min((uint64)*bufferSize, 91 fData->UncompressedSize() - offset); 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> baseClassUninit(this, 152 &PackageNode::NonVirtualVFSUninit); 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 int fd = fPackage->Open(); 157 if (fd < 0) 158 RETURN_ERROR(fd); 159 PackageCloser packageCloser(fPackage); 160 161 // create the data accessor 162 fDataAccessor = new(std::nothrow) DataAccessor(GetPackage(), &fData); 163 if (fDataAccessor == NULL) 164 RETURN_ERROR(B_NO_MEMORY); 165 166 error = fDataAccessor->Init(deviceID, nodeID, fd); 167 if (error != B_OK) { 168 delete fDataAccessor; 169 fDataAccessor = NULL; 170 return error; 171 } 172 173 baseClassUninit.Detach(); 174 return B_OK; 175 } 176 177 178 void 179 PackageFile::VFSUninit() 180 { 181 if (fDataAccessor != NULL) { 182 delete fDataAccessor; 183 fDataAccessor = NULL; 184 } 185 186 PackageNode::VFSUninit(); 187 } 188 189 190 off_t 191 PackageFile::FileSize() const 192 { 193 return fData.UncompressedSize(); 194 } 195 196 197 status_t 198 PackageFile::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 206 status_t 207 PackageFile::Read(io_request* request) 208 { 209 if (fDataAccessor == NULL) 210 return B_BAD_VALUE; 211 return fDataAccessor->ReadData(request); 212 } 213