From 50ab1fac082fdc4fed2d69e3b6e7371c5941003a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 12 Sep 2003 02:29:01 +0000 Subject: [PATCH] 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 --- .../boot/loader/file_systems/bfs/Stream.cpp | 364 ++++++++++++++++++ .../boot/loader/file_systems/bfs/Stream.h | 31 ++ 2 files changed, 395 insertions(+) create mode 100644 src/kernel/boot/loader/file_systems/bfs/Stream.cpp create mode 100644 src/kernel/boot/loader/file_systems/bfs/Stream.h diff --git a/src/kernel/boot/loader/file_systems/bfs/Stream.cpp b/src/kernel/boot/loader/file_systems/bfs/Stream.cpp new file mode 100644 index 0000000000..a754847c67 --- /dev/null +++ b/src/kernel/boot/loader/file_systems/bfs/Stream.cpp @@ -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 +#include +#include + + +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; +} + diff --git a/src/kernel/boot/loader/file_systems/bfs/Stream.h b/src/kernel/boot/loader/file_systems/bfs/Stream.h new file mode 100644 index 0000000000..99930bd207 --- /dev/null +++ b/src/kernel/boot/loader/file_systems/bfs/Stream.h @@ -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 */