* 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:
parent
8af6418b5c
commit
ef58ee846b
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <fs_cache.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#include "PackageNode.h"
|
||||
|
||||
#include <io_requests.h>
|
||||
|
||||
|
||||
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<PackageLeafNode> fListLink;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <fs_info.h>
|
||||
#include <fs_interface.h>
|
||||
#include <KernelExport.h>
|
||||
#include <io_requests.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
@ -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,
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <haiku_package.h>
|
||||
|
||||
#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,
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user