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 "Package.h" 23 24 25 using namespace BPackageKit::BHPKG; 26 27 28 // #pragma mark - DataAccessor 29 30 31 struct PackageFile::IORequestOutput : BDataIO { 32 public: 33 IORequestOutput(io_request* request) 34 : 35 fRequest(request) 36 { 37 } 38 39 virtual ssize_t Write(const void* buffer, size_t size) 40 { 41 status_t error = write_to_io_request(fRequest, buffer, size); 42 RETURN_ERROR(error == B_OK ? (ssize_t)size : (ssize_t)error); 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 return file_cache_read(fFileCache, NULL, offset, buffer, bufferSize); 87 } 88 89 status_t ReadData(io_request* request) 90 { 91 off_t offset = io_request_offset(request); 92 size_t size = io_request_length(request); 93 94 if (offset < 0 || (uint64)offset > fData->UncompressedSize()) 95 RETURN_ERROR(B_BAD_VALUE); 96 97 size_t toRead = std::min((uint64)size, 98 fData->UncompressedSize() - offset); 99 100 if (toRead > 0) { 101 IORequestOutput output(request); 102 MutexLocker locker(fLock, false, fData->Version() == 1); 103 // V2 readers are reentrant 104 status_t error = fReader->ReadDataToOutput(offset, toRead, &output); 105 if (error != B_OK) 106 RETURN_ERROR(error); 107 } 108 109 return B_OK; 110 } 111 112 private: 113 mutex fLock; 114 Package* fPackage; 115 PackageData* fData; 116 BAbstractBufferedDataReader* fReader; 117 void* fFileCache; 118 }; 119 120 121 // #pragma mark - PackageFile 122 123 124 PackageFile::PackageFile(Package* package, mode_t mode, const PackageData& data) 125 : 126 PackageLeafNode(package, mode), 127 fData(data), 128 fDataAccessor(NULL) 129 { 130 } 131 132 133 PackageFile::~PackageFile() 134 { 135 } 136 137 138 status_t 139 PackageFile::VFSInit(dev_t deviceID, ino_t nodeID) 140 { 141 status_t error = PackageNode::VFSInit(deviceID, nodeID); 142 if (error != B_OK) 143 return error; 144 MethodDeleter<PackageNode> baseClassUninit(this, 145 &PackageNode::NonVirtualVFSUninit); 146 147 // open the package -- that's already done by PackageNode::VFSInit(), so it 148 // shouldn't fail here. We only need to do it again, since we need the FD. 149 int fd = fPackage->Open(); 150 if (fd < 0) 151 RETURN_ERROR(fd); 152 PackageCloser packageCloser(fPackage); 153 154 // create the data accessor 155 fDataAccessor = new(std::nothrow) DataAccessor(GetPackage(), &fData); 156 if (fDataAccessor == NULL) 157 RETURN_ERROR(B_NO_MEMORY); 158 159 error = fDataAccessor->Init(deviceID, nodeID, fd); 160 if (error != B_OK) { 161 delete fDataAccessor; 162 fDataAccessor = NULL; 163 return error; 164 } 165 166 baseClassUninit.Detach(); 167 return B_OK; 168 } 169 170 171 void 172 PackageFile::VFSUninit() 173 { 174 if (fDataAccessor != NULL) { 175 delete fDataAccessor; 176 fDataAccessor = NULL; 177 } 178 179 PackageNode::VFSUninit(); 180 } 181 182 183 off_t 184 PackageFile::FileSize() const 185 { 186 return fData.UncompressedSize(); 187 } 188 189 190 status_t 191 PackageFile::Read(off_t offset, void* buffer, size_t* bufferSize) 192 { 193 if (fDataAccessor == NULL) 194 return B_BAD_VALUE; 195 return fDataAccessor->ReadData(offset, buffer, bufferSize); 196 } 197 198 199 status_t 200 PackageFile::Read(io_request* request) 201 { 202 if (fDataAccessor == NULL) 203 return B_BAD_VALUE; 204 return fDataAccessor->ReadData(request); 205 } 206