Somehow forgot to actually include the Stream class in the last commit...
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4640 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
aec0abfd56
commit
50ab1fac08
364
src/kernel/boot/loader/file_systems/bfs/Stream.cpp
Normal file
364
src/kernel/boot/loader/file_systems/bfs/Stream.cpp
Normal file
@ -0,0 +1,364 @@
|
||||
/* Stream - inode stream access functions
|
||||
**
|
||||
** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
** Distributed under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Stream.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
using namespace BFS;
|
||||
|
||||
|
||||
class CachedBlock {
|
||||
public:
|
||||
CachedBlock(Volume &volume);
|
||||
CachedBlock(Volume &volume, block_run run);
|
||||
~CachedBlock();
|
||||
|
||||
uint8 *SetTo(block_run run);
|
||||
uint8 *SetTo(off_t offset);
|
||||
|
||||
void Unset();
|
||||
|
||||
uint8 *Block() const { return fBlock; }
|
||||
off_t BlockNumber() const { return fBlockNumber; }
|
||||
uint32 BlockSize() const { return fVolume.BlockSize(); }
|
||||
uint32 BlockShift() const { return fVolume.BlockShift(); }
|
||||
|
||||
private:
|
||||
Volume &fVolume;
|
||||
off_t fBlockNumber;
|
||||
uint8 *fBlock;
|
||||
};
|
||||
|
||||
|
||||
CachedBlock::CachedBlock(Volume &volume)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlockNumber(-1LL),
|
||||
fBlock(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CachedBlock::CachedBlock(Volume &volume, block_run run)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlockNumber(-1LL)
|
||||
{
|
||||
SetTo(run);
|
||||
}
|
||||
|
||||
|
||||
CachedBlock::~CachedBlock()
|
||||
{
|
||||
free(fBlock);
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
CachedBlock::Unset()
|
||||
{
|
||||
fBlockNumber = -1;
|
||||
}
|
||||
|
||||
|
||||
inline uint8 *
|
||||
CachedBlock::SetTo(off_t block)
|
||||
{
|
||||
if (block == fBlockNumber)
|
||||
return fBlock;
|
||||
if (fBlock == NULL) {
|
||||
fBlock = (uint8 *)malloc(BlockSize());
|
||||
if (fBlock == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fBlockNumber = block;
|
||||
if (read_pos(fVolume.Device(), block << BlockShift(), fBlock, BlockSize()) < (ssize_t)BlockSize())
|
||||
return NULL;
|
||||
|
||||
return fBlock;
|
||||
}
|
||||
|
||||
|
||||
inline uint8 *
|
||||
CachedBlock::SetTo(block_run run)
|
||||
{
|
||||
return SetTo(fVolume.ToBlock(run));
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
Stream::Stream(Volume &volume, block_run run)
|
||||
:
|
||||
fVolume(volume)
|
||||
{
|
||||
if (read_pos(volume.Device(), volume.ToOffset(run), this, sizeof(bfs_inode)) != sizeof(bfs_inode))
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Stream::~Stream()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Stream::InitCheck()
|
||||
{
|
||||
return bfs_inode::InitCheck(&fVolume);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Stream::FindBlockRun(off_t pos, block_run &run, off_t &offset)
|
||||
{
|
||||
// find matching block run
|
||||
|
||||
if (data.MaxDirectRange() > 0 && pos >= data.MaxDirectRange()) {
|
||||
if (data.MaxDoubleIndirectRange() > 0 && pos >= data.MaxIndirectRange()) {
|
||||
// access to double indirect blocks
|
||||
|
||||
CachedBlock cached(fVolume);
|
||||
|
||||
off_t start = pos - data.MaxIndirectRange();
|
||||
int32 indirectSize = (1L << (INDIRECT_BLOCKS_SHIFT + cached.BlockShift()))
|
||||
* (fVolume.BlockSize() / sizeof(block_run));
|
||||
int32 directSize = NUM_ARRAY_BLOCKS << cached.BlockShift();
|
||||
int32 index = start / indirectSize;
|
||||
int32 runsPerBlock = cached.BlockSize() / sizeof(block_run);
|
||||
|
||||
block_run *indirect = (block_run *)cached.SetTo(
|
||||
fVolume.ToBlock(data.double_indirect) + index / runsPerBlock);
|
||||
if (indirect == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
//printf("\tstart = %Ld, indirectSize = %ld, directSize = %ld, index = %ld\n",start,indirectSize,directSize,index);
|
||||
//printf("\tlook for indirect block at %ld,%d\n",indirect[index].allocation_group,indirect[index].start);
|
||||
|
||||
int32 current = (start % indirectSize) / directSize;
|
||||
|
||||
indirect = (block_run *)cached.SetTo(
|
||||
fVolume.ToBlock(indirect[index % runsPerBlock]) + current / runsPerBlock);
|
||||
if (indirect == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
run = indirect[current % runsPerBlock];
|
||||
offset = data.MaxIndirectRange() + (index * indirectSize) + (current * directSize);
|
||||
//printf("\tfCurrent = %ld, fRunFileOffset = %Ld, fRunBlockEnd = %Ld, fRun = %ld,%d\n",fCurrent,fRunFileOffset,fRunBlockEnd,fRun.allocation_group,fRun.start);
|
||||
} else {
|
||||
// access to indirect blocks
|
||||
|
||||
int32 runsPerBlock = fVolume.BlockSize() / sizeof(block_run);
|
||||
off_t runBlockEnd = data.MaxDirectRange();
|
||||
|
||||
CachedBlock cached(fVolume);
|
||||
off_t block = fVolume.ToBlock(data.indirect);
|
||||
|
||||
for (int32 i = 0;i < data.indirect.Length();i++) {
|
||||
block_run *indirect = (block_run *)cached.SetTo(block + i);
|
||||
if (indirect == NULL)
|
||||
return B_IO_ERROR;
|
||||
|
||||
int32 current = -1;
|
||||
while (++current < runsPerBlock) {
|
||||
if (indirect[current].IsZero())
|
||||
break;
|
||||
|
||||
runBlockEnd += indirect[current].Length() << cached.BlockShift();
|
||||
if (runBlockEnd > pos) {
|
||||
run = indirect[current];
|
||||
offset = runBlockEnd - (run.Length() << cached.BlockShift());
|
||||
//printf("reading from indirect block: %ld,%d\n",fRun.allocation_group,fRun.start);
|
||||
//printf("### indirect-run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset);
|
||||
return fVolume.ValidateBlockRun(run);
|
||||
}
|
||||
}
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
} else {
|
||||
// access from direct blocks
|
||||
|
||||
off_t runBlockEnd = 0LL;
|
||||
int32 current = -1;
|
||||
|
||||
while (++current < NUM_DIRECT_BLOCKS) {
|
||||
if (data.direct[current].IsZero())
|
||||
break;
|
||||
|
||||
runBlockEnd += data.direct[current].Length() << fVolume.BlockShift();
|
||||
if (runBlockEnd > pos) {
|
||||
run = data.direct[current];
|
||||
offset = runBlockEnd - (run.Length() << fVolume.BlockShift());
|
||||
//printf("### run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset);
|
||||
return fVolume.ValidateBlockRun(run);
|
||||
}
|
||||
}
|
||||
//PRINT(("FindBlockRun() failed in direct range: size = %Ld, pos = %Ld\n",data.size,pos));
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
return fVolume.ValidateBlockRun(run);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Stream::ReadAt(off_t pos, uint8 *buffer, size_t *_length)
|
||||
{
|
||||
// set/check boundaries for pos/length
|
||||
|
||||
if (pos < 0)
|
||||
return B_BAD_VALUE;
|
||||
if (pos >= data.Size()) {
|
||||
*_length = 0;
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
size_t length = *_length;
|
||||
|
||||
if (pos + length > data.Size())
|
||||
length = data.Size() - pos;
|
||||
|
||||
block_run run;
|
||||
off_t offset;
|
||||
if (FindBlockRun(pos, run, offset) < B_OK) {
|
||||
*_length = 0;
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
uint32 bytesRead = 0;
|
||||
uint32 blockSize = fVolume.BlockSize();
|
||||
uint32 blockShift = fVolume.BlockShift();
|
||||
uint8 *block;
|
||||
|
||||
// the first block_run we read could not be aligned to the block_size boundary
|
||||
// (read partial block at the beginning)
|
||||
|
||||
// pos % block_size == (pos - offset) % block_size, offset % block_size == 0
|
||||
if (pos % blockSize != 0) {
|
||||
run.start += (pos - offset) / blockSize;
|
||||
run.length -= (pos - offset) / blockSize;
|
||||
|
||||
CachedBlock cached(fVolume, run);
|
||||
if ((block = cached.Block()) == NULL) {
|
||||
*_length = 0;
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
bytesRead = blockSize - (pos % blockSize);
|
||||
if (length < bytesRead)
|
||||
bytesRead = length;
|
||||
|
||||
memcpy(buffer, block + (pos % blockSize), bytesRead);
|
||||
pos += bytesRead;
|
||||
|
||||
length -= bytesRead;
|
||||
if (length == 0) {
|
||||
*_length = bytesRead;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
if (FindBlockRun(pos, run, offset) < B_OK) {
|
||||
*_length = bytesRead;
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
// the first block_run is already filled in at this point
|
||||
// read the following complete blocks using cached_read(),
|
||||
// the last partial block is read using the generic Cache class
|
||||
|
||||
bool partial = false;
|
||||
|
||||
while (length > 0) {
|
||||
// offset is the offset to the current pos in the block_run
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + ((pos - offset) >> blockShift));
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - ((pos - offset) >> blockShift));
|
||||
|
||||
if (uint32(run.Length() << blockShift) > length) {
|
||||
if (length < blockSize) {
|
||||
CachedBlock cached(fVolume, run);
|
||||
if ((block = cached.Block()) == NULL) {
|
||||
*_length = bytesRead;
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
memcpy(buffer + bytesRead, block, length);
|
||||
bytesRead += length;
|
||||
break;
|
||||
}
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(length >> blockShift);
|
||||
partial = true;
|
||||
}
|
||||
|
||||
if (read_pos(fVolume.Device(), fVolume.ToOffset(run), buffer + bytesRead, run.Length() << fVolume.BlockShift()) < B_OK) {
|
||||
*_length = bytesRead;
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
int32 bytes = run.Length() << blockShift;
|
||||
length -= bytes;
|
||||
bytesRead += bytes;
|
||||
if (length == 0)
|
||||
break;
|
||||
|
||||
pos += bytes;
|
||||
|
||||
if (partial) {
|
||||
// if the last block was read only partially, point block_run
|
||||
// to the remaining part
|
||||
run.start += run.length;
|
||||
run.length = 1;
|
||||
offset = pos;
|
||||
} else if (FindBlockRun(pos, run, offset) < B_OK) {
|
||||
*_length = bytesRead;
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
*_length = bytesRead;
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
bfs_inode::InitCheck(Volume *volume)
|
||||
{
|
||||
if (Flags() & INODE_NOT_READY) {
|
||||
// the other fields may not yet contain valid values
|
||||
return B_BUSY;
|
||||
}
|
||||
|
||||
if (Magic1() != INODE_MAGIC1
|
||||
|| !(Flags() & INODE_IN_USE)
|
||||
|| inode_num.Length() != 1
|
||||
// matches inode size?
|
||||
|| (uint32)InodeSize() != volume->InodeSize()
|
||||
// parent resides on disk?
|
||||
|| parent.AllocationGroup() > int32(volume->AllocationGroups())
|
||||
|| parent.AllocationGroup() < 0
|
||||
|| parent.Start() > (1L << volume->AllocationGroupShift())
|
||||
|| parent.Length() != 1
|
||||
// attributes, too?
|
||||
|| attributes.AllocationGroup() > int32(volume->AllocationGroups())
|
||||
|| attributes.AllocationGroup() < 0
|
||||
|| attributes.Start() > (1L << volume->AllocationGroupShift()))
|
||||
return B_BAD_DATA;
|
||||
|
||||
// ToDo: Add some tests to check the integrity of the other stuff here,
|
||||
// especially for the data_stream!
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
31
src/kernel/boot/loader/file_systems/bfs/Stream.h
Normal file
31
src/kernel/boot/loader/file_systems/bfs/Stream.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* Stream - inode stream access functions
|
||||
**
|
||||
** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
|
||||
** Distributed under the terms of the OpenBeOS License.
|
||||
*/
|
||||
#ifndef STREAM_H
|
||||
#define STREAM_H
|
||||
|
||||
|
||||
#include "Volume.h"
|
||||
|
||||
namespace BFS {
|
||||
|
||||
class Stream : public bfs_inode {
|
||||
public:
|
||||
Stream(Volume &volume, block_run run);
|
||||
~Stream();
|
||||
|
||||
status_t InitCheck();
|
||||
Volume &GetVolume() { return fVolume; }
|
||||
|
||||
status_t FindBlockRun(off_t pos, block_run &run, off_t &offset);
|
||||
status_t ReadAt(off_t pos, uint8 *buffer, size_t *length);
|
||||
|
||||
private:
|
||||
Volume &fVolume;
|
||||
};
|
||||
|
||||
} // namespace BFS
|
||||
|
||||
#endif /* STREAM_H */
|
Loading…
Reference in New Issue
Block a user