Implemented file reading (only slightly tested, but it should be enough
for our purposes [just copied some files in 1024 byte blocks to the Desktop]). git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4701 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -14,8 +14,156 @@
|
||||
|
||||
namespace FFS {
|
||||
|
||||
File::File(Volume &volume, int32 block)
|
||||
class Stream {
|
||||
public:
|
||||
Stream(int device, FileBlock &node);
|
||||
~Stream();
|
||||
|
||||
status_t InitCheck();
|
||||
ssize_t ReadAt(off_t offset, uint8 *buffer, size_t size);
|
||||
|
||||
private:
|
||||
int32 BlockOffset(off_t offset) const;
|
||||
int32 BlockIndex(off_t offset) const;
|
||||
int32 ExtensionBlockOffset(off_t offset) const;
|
||||
status_t ReadNextExtension();
|
||||
|
||||
int fDevice;
|
||||
FileBlock &fNode;
|
||||
FileBlock fBlock;
|
||||
int32 fExtensionBlockOffset;
|
||||
};
|
||||
|
||||
|
||||
Stream::Stream(int device, FileBlock &node)
|
||||
:
|
||||
fDevice(device),
|
||||
fNode(node)
|
||||
{
|
||||
void *buffer = malloc(fNode.BlockSize());
|
||||
if (buffer == NULL)
|
||||
return;
|
||||
|
||||
fExtensionBlockOffset = 0;
|
||||
fBlock.SetTo(buffer, fNode.BlockSize());
|
||||
}
|
||||
|
||||
|
||||
Stream::~Stream()
|
||||
{
|
||||
free(fBlock.BlockData());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Stream::InitCheck()
|
||||
{
|
||||
return fBlock.BlockData() != NULL ? B_OK : B_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
Stream::BlockOffset(off_t offset) const
|
||||
{
|
||||
return offset % fNode.BlockSize();
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
Stream::BlockIndex(off_t offset) const
|
||||
{
|
||||
return (offset % (fNode.BlockSize() * fNode.NumDataBlocks())) / fNode.BlockSize();
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
Stream::ExtensionBlockOffset(off_t offset) const
|
||||
{
|
||||
return offset / (fNode.BlockSize() * fNode.NumDataBlocks());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Stream::ReadNextExtension()
|
||||
{
|
||||
int32 next;
|
||||
if (fExtensionBlockOffset == 0)
|
||||
next = fNode.NextExtension();
|
||||
else
|
||||
next = fBlock.NextExtension();
|
||||
|
||||
if (read_pos(fDevice, next * fNode.BlockSize(), fBlock.BlockData(), fNode.BlockSize()) < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return fBlock.ValidateCheckSum();
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
Stream::ReadAt(off_t offset, uint8 *buffer, size_t size)
|
||||
{
|
||||
if (offset < 0)
|
||||
return B_BAD_VALUE;
|
||||
if (offset + size > fNode.Size())
|
||||
size = fNode.Size() - offset;
|
||||
|
||||
ssize_t bytesLeft = (ssize_t)size;
|
||||
|
||||
while (bytesLeft != 0) {
|
||||
int32 extensionBlock = ExtensionBlockOffset(offset);
|
||||
|
||||
// get the right extension block
|
||||
|
||||
if (extensionBlock < fExtensionBlockOffset)
|
||||
fExtensionBlockOffset = 1;
|
||||
|
||||
while (fExtensionBlockOffset < extensionBlock) {
|
||||
if (ReadNextExtension() != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
fExtensionBlockOffset++;
|
||||
}
|
||||
|
||||
// read the data block into memory
|
||||
|
||||
int32 block;
|
||||
if (extensionBlock == 0)
|
||||
block = fNode.DataBlock(BlockIndex(offset));
|
||||
else
|
||||
block = fBlock.DataBlock(BlockIndex(offset));
|
||||
|
||||
int32 blockOffset = BlockOffset(offset);
|
||||
int32 toRead = fNode.BlockSize() - blockOffset;
|
||||
if (toRead > bytesLeft)
|
||||
toRead = bytesLeft;
|
||||
|
||||
ssize_t bytesRead = read_pos(fDevice, block * fNode.BlockSize() + blockOffset,
|
||||
buffer, toRead);
|
||||
if (bytesRead < B_OK)
|
||||
return bytesRead;
|
||||
|
||||
bytesLeft -= bytesRead;
|
||||
buffer += bytesRead;
|
||||
offset += fNode.BlockSize() - blockOffset;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
File::File(Volume &volume, int32 block)
|
||||
:
|
||||
fVolume(volume)
|
||||
{
|
||||
void *data = malloc(volume.BlockSize());
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
if (read_pos(volume.Device(), block * volume.BlockSize(), data, volume.BlockSize()) == volume.BlockSize())
|
||||
fNode.SetTo(data, volume.BlockSize());
|
||||
}
|
||||
|
||||
|
||||
@@ -34,10 +182,41 @@ File::InitCheck()
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
File::Open(void **_cookie, int mode)
|
||||
{
|
||||
Stream *stream = new Stream(fVolume.Device(), fNode);
|
||||
if (stream == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
if (stream->InitCheck() != B_OK) {
|
||||
delete stream;
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
*_cookie = (void *)stream;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
File::Close(void *cookie)
|
||||
{
|
||||
Stream *stream = (Stream *)cookie;
|
||||
|
||||
delete stream;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
File::ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize)
|
||||
{
|
||||
return B_ERROR;
|
||||
Stream *stream = (Stream *)cookie;
|
||||
if (stream == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
return stream->ReadAt(pos, (uint8 *)buffer, bufferSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@ class File : public Node {
|
||||
|
||||
status_t InitCheck();
|
||||
|
||||
virtual status_t Open(void **_cookie, int mode);
|
||||
virtual status_t Close(void *cookie);
|
||||
|
||||
virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize);
|
||||
virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize);
|
||||
|
||||
@@ -28,6 +31,7 @@ class File : public Node {
|
||||
virtual off_t Size() const;
|
||||
|
||||
private:
|
||||
Volume &fVolume;
|
||||
FileBlock fNode;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user