From ef58ee846b9962044875d3c8bdd0ff7d4843b29f Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 19 Nov 2009 16:31:16 +0000 Subject: [PATCH] * Added method PackageDataReader::ReadDataToOutput(), which writes the read data to a DataOutput. * Implemented packagefs' io() hook and changed the read() hook implementation to use the file cache. It's now possible to mmap() files and thus execute programs. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34138 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../file_systems/packagefs/Directory.cpp | 7 ++ .../kernel/file_systems/packagefs/Directory.h | 1 + .../file_systems/packagefs/LeafNode.cpp | 9 +++ .../kernel/file_systems/packagefs/LeafNode.h | 1 + .../kernel/file_systems/packagefs/Node.h | 1 + .../file_systems/packagefs/PackageFile.cpp | 48 ++++++++++- .../file_systems/packagefs/PackageFile.h | 2 + .../packagefs/PackageLeafNode.cpp | 7 ++ .../file_systems/packagefs/PackageLeafNode.h | 3 + .../packagefs/kernel_interface.cpp | 22 ++++- src/bin/package/PackageDataReader.cpp | 81 ++++++++++++++++--- src/bin/package/PackageDataReader.h | 6 ++ 12 files changed, 168 insertions(+), 20 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp index 7759ae709e..cdcb55c35d 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp @@ -125,6 +125,13 @@ Directory::Read(off_t offset, void* buffer, size_t* bufferSize) } +status_t +Directory::Read(io_request* request) +{ + return B_IS_A_DIRECTORY; +} + + void Directory::AddChild(Node* node) { diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.h b/src/add-ons/kernel/file_systems/packagefs/Directory.h index 9f5e0bf8d8..2d643bc005 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.h +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.h @@ -46,6 +46,7 @@ public: virtual status_t Read(off_t offset, void* buffer, size_t* bufferSize); + virtual status_t Read(io_request* request); void AddChild(Node* node); void RemoveChild(Node* node); diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp index 06c3eba92f..6e90858d47 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp @@ -118,6 +118,15 @@ LeafNode::Read(off_t offset, void* buffer, size_t* bufferSize) } +status_t +LeafNode::Read(io_request* request) +{ + if (PackageLeafNode* packageNode = fPackageNodes.Head()) + return packageNode->Read(request); + return EBADF; +} + + const char* LeafNode::SymlinkPath() const { diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h index 1a8fad642c..64f563cca0 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h @@ -32,6 +32,7 @@ public: virtual status_t Read(off_t offset, void* buffer, size_t* bufferSize); + virtual status_t Read(io_request* request); const char* SymlinkPath() const; diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h index 673eea7705..6f72eb4962 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.h +++ b/src/add-ons/kernel/file_systems/packagefs/Node.h @@ -57,6 +57,7 @@ public: virtual status_t Read(off_t offset, void* buffer, size_t* bufferSize) = 0; + virtual status_t Read(io_request* request) = 0; protected: rw_lock fLock; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp index e32e46a0cb..23a80cf6a6 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp @@ -11,6 +11,7 @@ #include +#include "DataOutput.h" #include "DataReader.h" #include "PackageDataReader.h" @@ -22,6 +23,24 @@ // #pragma mark - DataAccessor +struct PackageFile::IORequestOutput : DataOutput { +public: + IORequestOutput(io_request* request) + : + fRequest(request) + { + } + + virtual status_t WriteData(const void* buffer, size_t size) + { + RETURN_ERROR(write_to_io_request(fRequest, buffer, size)); + } + +private: + io_request* fRequest; +}; + + struct PackageFile::DataAccessor { DataAccessor(PackageData* data) : @@ -73,17 +92,31 @@ struct PackageFile::DataAccessor { if (offset < 0 || (uint64)offset > fData->UncompressedSize()) return B_BAD_VALUE; - size_t toRead = std::min((uint64)*bufferSize, + *bufferSize = std::min((uint64)*bufferSize, + fData->UncompressedSize() - offset); + + return file_cache_read(fFileCache, NULL, offset, buffer, bufferSize); + } + + status_t ReadData(io_request* request) + { + off_t offset = io_request_offset(request); + size_t size = io_request_length(request); + + if (offset < 0 || (uint64)offset > fData->UncompressedSize()) + RETURN_ERROR(B_BAD_VALUE); + + size_t toRead = std::min((uint64)size, fData->UncompressedSize() - offset); if (toRead > 0) { + IORequestOutput output(request); MutexLocker locker(fLock); - status_t error = fReader->ReadData(offset, buffer, toRead); + status_t error = fReader->ReadDataToOutput(offset, toRead, &output); if (error != B_OK) RETURN_ERROR(error); } - *bufferSize = toRead; return B_OK; } @@ -164,3 +197,12 @@ PackageFile::Read(off_t offset, void* buffer, size_t* bufferSize) return B_BAD_VALUE; return fDataAccessor->ReadData(offset, buffer, bufferSize); } + + +status_t +PackageFile::Read(io_request* request) +{ + if (fDataAccessor == NULL) + return B_BAD_VALUE; + return fDataAccessor->ReadData(request); +} diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFile.h b/src/add-ons/kernel/file_systems/packagefs/PackageFile.h index 7fa0f67433..a6bf2d29b3 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFile.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFile.h @@ -24,8 +24,10 @@ public: virtual status_t Read(off_t offset, void* buffer, size_t* bufferSize); + virtual status_t Read(io_request* request); private: + struct IORequestOutput; struct DataAccessor; private: diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.cpp index f915b18b09..94a680432a 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.cpp @@ -31,3 +31,10 @@ PackageLeafNode::Read(off_t offset, void* buffer, size_t* bufferSize) { return EBADF; } + + +status_t +PackageLeafNode::Read(io_request* request) +{ + return EBADF; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.h b/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.h index 38ee6cf935..7b52fc6baa 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLeafNode.h @@ -8,6 +8,8 @@ #include "PackageNode.h" +#include + class PackageData; @@ -21,6 +23,7 @@ public: virtual status_t Read(off_t offset, void* buffer, size_t* bufferSize); + virtual status_t Read(io_request* request); public: SinglyLinkedListLink fListLink; diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp index 30369620ad..5cc0aec202 100644 --- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -249,13 +250,24 @@ packagefs_put_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter) // #pragma mark - Request I/O -#if 0 static status_t -packagefs_io(fs_volume* volume, fs_vnode* vnode, void* cookie, +packagefs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie, io_request* request) { + Volume* volume = (Volume*)fsVolume->private_volume; + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%lld), cookie: %p, request: %p\n", volume, + node, node->ID(), cookie, request); + TOUCH(volume); + + if (io_request_is_write(request)) + RETURN_ERROR(B_READ_ONLY_DEVICE); + + status_t error = node->Read(request); + notify_io_request(request, error); + return error; } -#endif // #pragma mark - Nodes @@ -517,6 +529,7 @@ packagefs_open_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie) Node* node = (Node*)fsNode->private_node; FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); + TOUCH(volume); if (!S_ISDIR(node->Mode())) return B_NOT_A_DIRECTORY; @@ -702,6 +715,7 @@ packagefs_open_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie) Node* node = (Node*)fsNode->private_node; FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID()); + TOUCH(volume); status_t error = check_access(node, R_OK); if (error != B_OK) @@ -1087,7 +1101,7 @@ fs_vnode_ops gPackageFSVnodeOps = { NULL, // read_pages, NULL, // write_pages, - NULL, // &packagefs_io, + &packagefs_io, NULL, // cancel_io() NULL, // get_file_map, diff --git a/src/bin/package/PackageDataReader.cpp b/src/bin/package/PackageDataReader.cpp index 8bd03e05a6..8274f4d7d1 100644 --- a/src/bin/package/PackageDataReader.cpp +++ b/src/bin/package/PackageDataReader.cpp @@ -14,6 +14,7 @@ #include #include "BufferCache.h" +#include "DataOutput.h" #include "PackageData.h" #include "ZlibDecompressor.h" @@ -25,6 +26,9 @@ static const size_t kMaxSaneZlibChunkSize = 10 * 1024 * 1024; // maximum number of entries in the zlib offset table buffer static const uint32 kMaxZlibOffsetTableBufferSize = 512; +static const size_t kUncompressedReaderBufferSize + = B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB; + // #pragma mark - PackageDataReader @@ -41,14 +45,24 @@ PackageDataReader::~PackageDataReader() } +status_t +PackageDataReader::ReadData(off_t offset, void* buffer, size_t size) +{ + BufferDataOutput output(buffer, size); + return ReadDataToOutput(offset, size, &output); +} + + // #pragma mark - UncompressedPackageDataReader class UncompressedPackageDataReader : public PackageDataReader { public: - UncompressedPackageDataReader(DataReader* dataReader) + UncompressedPackageDataReader(DataReader* dataReader, + BufferCache* bufferCache) : - PackageDataReader(dataReader) + PackageDataReader(dataReader), + fBufferCache(bufferCache) { } @@ -84,9 +98,49 @@ public: return fDataReader->ReadData(fOffset + offset, buffer, size); } + virtual status_t ReadDataToOutput(off_t offset, size_t size, + DataOutput* output) + { + if (size == 0) + return B_OK; + + if (offset < 0) + return B_BAD_VALUE; + + if ((uint64)offset > fSize || size > fSize - offset) + return B_BAD_VALUE; + + // get a temporary buffer + CachedBuffer* buffer = fBufferCache->GetBuffer( + kUncompressedReaderBufferSize); + if (buffer == NULL) + return B_NO_MEMORY; + CachedBufferPutter bufferPutter(fBufferCache, &buffer); + + while (size > 0) { + // read into the buffer + size_t toRead = std::min(size, buffer->Size()); + status_t error = fDataReader->ReadData(fOffset + offset, + buffer->Buffer(), toRead); + if (error != B_OK) + return error; + + // write to the output + error = output->WriteData(buffer->Buffer(), toRead); + if (error != B_OK) + return error; + + offset += toRead; + size -= toRead; + } + + return B_OK; + } + private: - uint64 fOffset; - uint64 fSize; + BufferCache* fBufferCache; + uint64 fOffset; + uint64 fSize; }; @@ -161,10 +215,9 @@ public: return fChunkSize; } - virtual status_t ReadData(off_t offset, void* _buffer, size_t size) + virtual status_t ReadDataToOutput(off_t offset, size_t size, + DataOutput* output) { - uint8* buffer = (uint8*)_buffer; - // check offset and size if (size == 0) return B_OK; @@ -183,7 +236,8 @@ public: == NULL) { return B_NO_MEMORY; } - CachedBufferPutter uncompressBuffer(fBufferCache, &fUncompressBuffer); + CachedBufferPutter uncompressBufferPutter(fBufferCache, + &fUncompressBuffer); if (newBuffer) fUncompressedChunk = -1; @@ -199,12 +253,13 @@ public: if (error != B_OK) return error; - // copy data to buffer + // write data to output size_t toCopy = std::min(size, (size_t)fChunkSize - inChunkOffset); - memcpy(buffer, (uint8*)fUncompressBuffer->Buffer() + inChunkOffset, - toCopy); + error = output->WriteData( + (uint8*)fUncompressBuffer->Buffer() + inChunkOffset, toCopy); + if (error != B_OK) + return error; - buffer += toCopy; size -= toCopy; chunkIndex++; @@ -372,7 +427,7 @@ PackageDataReaderFactory::CreatePackageDataReader(DataReader* dataReader, switch (data.Compression()) { case B_HPKG_COMPRESSION_NONE: reader = new(std::nothrow) UncompressedPackageDataReader( - dataReader); + dataReader, fBufferCache); break; case B_HPKG_COMPRESSION_ZLIB: reader = new(std::nothrow) ZlibPackageDataReader(dataReader, diff --git a/src/bin/package/PackageDataReader.h b/src/bin/package/PackageDataReader.h index 7f28f8995c..d1f8d8342d 100644 --- a/src/bin/package/PackageDataReader.h +++ b/src/bin/package/PackageDataReader.h @@ -10,6 +10,7 @@ class BufferCache; +class DataOutput; class PackageData; @@ -20,6 +21,11 @@ public: virtual status_t Init(const PackageData& data) = 0; + virtual status_t ReadData(off_t offset, void* buffer, + size_t size); + virtual status_t ReadDataToOutput(off_t offset, size_t size, + DataOutput* output) = 0; + virtual uint64 Size() const = 0; virtual size_t BlockSize() const = 0;