* 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
This commit is contained in:
@@ -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
|
void
|
||||||
Directory::AddChild(Node* node)
|
Directory::AddChild(Node* node)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public:
|
|||||||
|
|
||||||
virtual status_t Read(off_t offset, void* buffer,
|
virtual status_t Read(off_t offset, void* buffer,
|
||||||
size_t* bufferSize);
|
size_t* bufferSize);
|
||||||
|
virtual status_t Read(io_request* request);
|
||||||
|
|
||||||
void AddChild(Node* node);
|
void AddChild(Node* node);
|
||||||
void RemoveChild(Node* node);
|
void RemoveChild(Node* node);
|
||||||
|
|||||||
@@ -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*
|
const char*
|
||||||
LeafNode::SymlinkPath() const
|
LeafNode::SymlinkPath() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ public:
|
|||||||
|
|
||||||
virtual status_t Read(off_t offset, void* buffer,
|
virtual status_t Read(off_t offset, void* buffer,
|
||||||
size_t* bufferSize);
|
size_t* bufferSize);
|
||||||
|
virtual status_t Read(io_request* request);
|
||||||
|
|
||||||
const char* SymlinkPath() const;
|
const char* SymlinkPath() const;
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ public:
|
|||||||
|
|
||||||
virtual status_t Read(off_t offset, void* buffer,
|
virtual status_t Read(off_t offset, void* buffer,
|
||||||
size_t* bufferSize) = 0;
|
size_t* bufferSize) = 0;
|
||||||
|
virtual status_t Read(io_request* request) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
rw_lock fLock;
|
rw_lock fLock;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <fs_cache.h>
|
#include <fs_cache.h>
|
||||||
|
|
||||||
|
#include "DataOutput.h"
|
||||||
#include "DataReader.h"
|
#include "DataReader.h"
|
||||||
#include "PackageDataReader.h"
|
#include "PackageDataReader.h"
|
||||||
|
|
||||||
@@ -22,6 +23,24 @@
|
|||||||
// #pragma mark - DataAccessor
|
// #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 {
|
struct PackageFile::DataAccessor {
|
||||||
DataAccessor(PackageData* data)
|
DataAccessor(PackageData* data)
|
||||||
:
|
:
|
||||||
@@ -73,17 +92,31 @@ struct PackageFile::DataAccessor {
|
|||||||
if (offset < 0 || (uint64)offset > fData->UncompressedSize())
|
if (offset < 0 || (uint64)offset > fData->UncompressedSize())
|
||||||
return B_BAD_VALUE;
|
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);
|
fData->UncompressedSize() - offset);
|
||||||
|
|
||||||
if (toRead > 0) {
|
if (toRead > 0) {
|
||||||
|
IORequestOutput output(request);
|
||||||
MutexLocker locker(fLock);
|
MutexLocker locker(fLock);
|
||||||
status_t error = fReader->ReadData(offset, buffer, toRead);
|
status_t error = fReader->ReadDataToOutput(offset, toRead, &output);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
*bufferSize = toRead;
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,3 +197,12 @@ PackageFile::Read(off_t offset, void* buffer, size_t* bufferSize)
|
|||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
return fDataAccessor->ReadData(offset, buffer, bufferSize);
|
return fDataAccessor->ReadData(offset, buffer, bufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
PackageFile::Read(io_request* request)
|
||||||
|
{
|
||||||
|
if (fDataAccessor == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
return fDataAccessor->ReadData(request);
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,8 +24,10 @@ public:
|
|||||||
|
|
||||||
virtual status_t Read(off_t offset, void* buffer,
|
virtual status_t Read(off_t offset, void* buffer,
|
||||||
size_t* bufferSize);
|
size_t* bufferSize);
|
||||||
|
virtual status_t Read(io_request* request);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct IORequestOutput;
|
||||||
struct DataAccessor;
|
struct DataAccessor;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -31,3 +31,10 @@ PackageLeafNode::Read(off_t offset, void* buffer, size_t* bufferSize)
|
|||||||
{
|
{
|
||||||
return EBADF;
|
return EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
PackageLeafNode::Read(io_request* request)
|
||||||
|
{
|
||||||
|
return EBADF;
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "PackageNode.h"
|
#include "PackageNode.h"
|
||||||
|
|
||||||
|
#include <io_requests.h>
|
||||||
|
|
||||||
|
|
||||||
class PackageData;
|
class PackageData;
|
||||||
|
|
||||||
@@ -21,6 +23,7 @@ public:
|
|||||||
|
|
||||||
virtual status_t Read(off_t offset, void* buffer,
|
virtual status_t Read(off_t offset, void* buffer,
|
||||||
size_t* bufferSize);
|
size_t* bufferSize);
|
||||||
|
virtual status_t Read(io_request* request);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SinglyLinkedListLink<PackageLeafNode> fListLink;
|
SinglyLinkedListLink<PackageLeafNode> fListLink;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <fs_info.h>
|
#include <fs_info.h>
|
||||||
#include <fs_interface.h>
|
#include <fs_interface.h>
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
#include <io_requests.h>
|
||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
@@ -249,13 +250,24 @@ packagefs_put_vnode(fs_volume* fsVolume, fs_vnode* fsNode, bool reenter)
|
|||||||
// #pragma mark - Request I/O
|
// #pragma mark - Request I/O
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static status_t
|
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)
|
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
|
// #pragma mark - Nodes
|
||||||
@@ -517,6 +529,7 @@ packagefs_open_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie)
|
|||||||
Node* node = (Node*)fsNode->private_node;
|
Node* node = (Node*)fsNode->private_node;
|
||||||
|
|
||||||
FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID());
|
FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID());
|
||||||
|
TOUCH(volume);
|
||||||
|
|
||||||
if (!S_ISDIR(node->Mode()))
|
if (!S_ISDIR(node->Mode()))
|
||||||
return B_NOT_A_DIRECTORY;
|
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;
|
Node* node = (Node*)fsNode->private_node;
|
||||||
|
|
||||||
FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID());
|
FUNCTION("volume: %p, node: %p (%lld)\n", volume, node, node->ID());
|
||||||
|
TOUCH(volume);
|
||||||
|
|
||||||
status_t error = check_access(node, R_OK);
|
status_t error = check_access(node, R_OK);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
@@ -1087,7 +1101,7 @@ fs_vnode_ops gPackageFSVnodeOps = {
|
|||||||
NULL, // read_pages,
|
NULL, // read_pages,
|
||||||
NULL, // write_pages,
|
NULL, // write_pages,
|
||||||
|
|
||||||
NULL, // &packagefs_io,
|
&packagefs_io,
|
||||||
NULL, // cancel_io()
|
NULL, // cancel_io()
|
||||||
|
|
||||||
NULL, // get_file_map,
|
NULL, // get_file_map,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <haiku_package.h>
|
#include <haiku_package.h>
|
||||||
|
|
||||||
#include "BufferCache.h"
|
#include "BufferCache.h"
|
||||||
|
#include "DataOutput.h"
|
||||||
#include "PackageData.h"
|
#include "PackageData.h"
|
||||||
#include "ZlibDecompressor.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
|
// maximum number of entries in the zlib offset table buffer
|
||||||
static const uint32 kMaxZlibOffsetTableBufferSize = 512;
|
static const uint32 kMaxZlibOffsetTableBufferSize = 512;
|
||||||
|
|
||||||
|
static const size_t kUncompressedReaderBufferSize
|
||||||
|
= B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB;
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - PackageDataReader
|
// #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
|
// #pragma mark - UncompressedPackageDataReader
|
||||||
|
|
||||||
|
|
||||||
class UncompressedPackageDataReader : public PackageDataReader {
|
class UncompressedPackageDataReader : public PackageDataReader {
|
||||||
public:
|
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);
|
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:
|
private:
|
||||||
uint64 fOffset;
|
BufferCache* fBufferCache;
|
||||||
uint64 fSize;
|
uint64 fOffset;
|
||||||
|
uint64 fSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -161,10 +215,9 @@ public:
|
|||||||
return fChunkSize;
|
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
|
// check offset and size
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -183,7 +236,8 @@ public:
|
|||||||
== NULL) {
|
== NULL) {
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
CachedBufferPutter uncompressBuffer(fBufferCache, &fUncompressBuffer);
|
CachedBufferPutter uncompressBufferPutter(fBufferCache,
|
||||||
|
&fUncompressBuffer);
|
||||||
|
|
||||||
if (newBuffer)
|
if (newBuffer)
|
||||||
fUncompressedChunk = -1;
|
fUncompressedChunk = -1;
|
||||||
@@ -199,12 +253,13 @@ public:
|
|||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
// copy data to buffer
|
// write data to output
|
||||||
size_t toCopy = std::min(size, (size_t)fChunkSize - inChunkOffset);
|
size_t toCopy = std::min(size, (size_t)fChunkSize - inChunkOffset);
|
||||||
memcpy(buffer, (uint8*)fUncompressBuffer->Buffer() + inChunkOffset,
|
error = output->WriteData(
|
||||||
toCopy);
|
(uint8*)fUncompressBuffer->Buffer() + inChunkOffset, toCopy);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
buffer += toCopy;
|
|
||||||
size -= toCopy;
|
size -= toCopy;
|
||||||
|
|
||||||
chunkIndex++;
|
chunkIndex++;
|
||||||
@@ -372,7 +427,7 @@ PackageDataReaderFactory::CreatePackageDataReader(DataReader* dataReader,
|
|||||||
switch (data.Compression()) {
|
switch (data.Compression()) {
|
||||||
case B_HPKG_COMPRESSION_NONE:
|
case B_HPKG_COMPRESSION_NONE:
|
||||||
reader = new(std::nothrow) UncompressedPackageDataReader(
|
reader = new(std::nothrow) UncompressedPackageDataReader(
|
||||||
dataReader);
|
dataReader, fBufferCache);
|
||||||
break;
|
break;
|
||||||
case B_HPKG_COMPRESSION_ZLIB:
|
case B_HPKG_COMPRESSION_ZLIB:
|
||||||
reader = new(std::nothrow) ZlibPackageDataReader(dataReader,
|
reader = new(std::nothrow) ZlibPackageDataReader(dataReader,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
|
|
||||||
class BufferCache;
|
class BufferCache;
|
||||||
|
class DataOutput;
|
||||||
class PackageData;
|
class PackageData;
|
||||||
|
|
||||||
|
|
||||||
@@ -20,6 +21,11 @@ public:
|
|||||||
|
|
||||||
virtual status_t Init(const PackageData& data) = 0;
|
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 uint64 Size() const = 0;
|
||||||
virtual size_t BlockSize() const = 0;
|
virtual size_t BlockSize() const = 0;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user