* 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:
Ingo Weinhold 2009-11-19 16:31:16 +00:00
parent 8af6418b5c
commit ef58ee846b
12 changed files with 168 additions and 20 deletions

View File

@ -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)
{

View File

@ -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);

View File

@ -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
{

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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:

View File

@ -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;
}

View File

@ -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;

View File

@ -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,

View File

@ -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,

View File

@ -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;