xref: /haiku/src/system/boot/loader/file_systems/bfs/Stream.cpp (revision 9618c0dc63767f7752c2f6b2e097552362d24ab5)
15af32e75SAxel Dörfler /* Stream - inode stream access functions
25af32e75SAxel Dörfler **
35af32e75SAxel Dörfler ** Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
45af32e75SAxel Dörfler ** Distributed under the terms of the OpenBeOS License.
55af32e75SAxel Dörfler */
65af32e75SAxel Dörfler 
75af32e75SAxel Dörfler 
85af32e75SAxel Dörfler #include "Stream.h"
95af32e75SAxel Dörfler #include "Directory.h"
105af32e75SAxel Dörfler #include "File.h"
115af32e75SAxel Dörfler #include "Link.h"
125af32e75SAxel Dörfler 
135af32e75SAxel Dörfler #include <util/kernel_cpp.h>
145af32e75SAxel Dörfler 
155af32e75SAxel Dörfler #include <stdlib.h>
165af32e75SAxel Dörfler #include <unistd.h>
175af32e75SAxel Dörfler #include <string.h>
185af32e75SAxel Dörfler 
195af32e75SAxel Dörfler 
205af32e75SAxel Dörfler using namespace BFS;
215af32e75SAxel Dörfler 
225af32e75SAxel Dörfler 
235af32e75SAxel Dörfler class CachedBlock {
245af32e75SAxel Dörfler 	public:
255af32e75SAxel Dörfler 		CachedBlock(Volume &volume);
265af32e75SAxel Dörfler 		CachedBlock(Volume &volume, block_run run);
275af32e75SAxel Dörfler 		~CachedBlock();
285af32e75SAxel Dörfler 
295af32e75SAxel Dörfler 		uint8 *SetTo(block_run run);
305af32e75SAxel Dörfler 		uint8 *SetTo(off_t offset);
315af32e75SAxel Dörfler 
325af32e75SAxel Dörfler 		void Unset();
335af32e75SAxel Dörfler 
345af32e75SAxel Dörfler 		uint8 *Block() const { return fBlock; }
355af32e75SAxel Dörfler 		off_t BlockNumber() const { return fBlockNumber; }
365af32e75SAxel Dörfler 		uint32 BlockSize() const { return fVolume.BlockSize(); }
375af32e75SAxel Dörfler 		uint32 BlockShift() const { return fVolume.BlockShift(); }
385af32e75SAxel Dörfler 
395af32e75SAxel Dörfler 	private:
405af32e75SAxel Dörfler 		Volume	&fVolume;
415af32e75SAxel Dörfler 		off_t	fBlockNumber;
425af32e75SAxel Dörfler 		uint8	*fBlock;
435af32e75SAxel Dörfler };
445af32e75SAxel Dörfler 
455af32e75SAxel Dörfler 
465af32e75SAxel Dörfler CachedBlock::CachedBlock(Volume &volume)
475af32e75SAxel Dörfler 	:
485af32e75SAxel Dörfler 	fVolume(volume),
495af32e75SAxel Dörfler 	fBlockNumber(-1LL),
505af32e75SAxel Dörfler 	fBlock(NULL)
515af32e75SAxel Dörfler {
525af32e75SAxel Dörfler }
535af32e75SAxel Dörfler 
545af32e75SAxel Dörfler 
555af32e75SAxel Dörfler CachedBlock::CachedBlock(Volume &volume, block_run run)
565af32e75SAxel Dörfler 	:
575af32e75SAxel Dörfler 	fVolume(volume),
585af32e75SAxel Dörfler 	fBlockNumber(-1LL),
595af32e75SAxel Dörfler 	fBlock(NULL)
605af32e75SAxel Dörfler {
615af32e75SAxel Dörfler 	SetTo(run);
625af32e75SAxel Dörfler }
635af32e75SAxel Dörfler 
645af32e75SAxel Dörfler 
655af32e75SAxel Dörfler CachedBlock::~CachedBlock()
665af32e75SAxel Dörfler {
675af32e75SAxel Dörfler 	free(fBlock);
685af32e75SAxel Dörfler }
695af32e75SAxel Dörfler 
705af32e75SAxel Dörfler 
715af32e75SAxel Dörfler inline void
725af32e75SAxel Dörfler CachedBlock::Unset()
735af32e75SAxel Dörfler {
745af32e75SAxel Dörfler 	fBlockNumber = -1;
755af32e75SAxel Dörfler }
765af32e75SAxel Dörfler 
775af32e75SAxel Dörfler 
785af32e75SAxel Dörfler inline uint8 *
795af32e75SAxel Dörfler CachedBlock::SetTo(off_t block)
805af32e75SAxel Dörfler {
815af32e75SAxel Dörfler 	if (block == fBlockNumber)
825af32e75SAxel Dörfler 		return fBlock;
835af32e75SAxel Dörfler 	if (fBlock == NULL) {
845af32e75SAxel Dörfler 		fBlock = (uint8 *)malloc(BlockSize());
855af32e75SAxel Dörfler 		if (fBlock == NULL)
865af32e75SAxel Dörfler 			return NULL;
875af32e75SAxel Dörfler 	}
885af32e75SAxel Dörfler 
895af32e75SAxel Dörfler 	fBlockNumber = block;
905af32e75SAxel Dörfler 	if (read_pos(fVolume.Device(), block << BlockShift(), fBlock, BlockSize()) < (ssize_t)BlockSize())
915af32e75SAxel Dörfler 		return NULL;
925af32e75SAxel Dörfler 
935af32e75SAxel Dörfler 	return fBlock;
945af32e75SAxel Dörfler }
955af32e75SAxel Dörfler 
965af32e75SAxel Dörfler 
975af32e75SAxel Dörfler inline uint8 *
985af32e75SAxel Dörfler CachedBlock::SetTo(block_run run)
995af32e75SAxel Dörfler {
1005af32e75SAxel Dörfler 	return SetTo(fVolume.ToBlock(run));
1015af32e75SAxel Dörfler }
1025af32e75SAxel Dörfler 
1035af32e75SAxel Dörfler 
1045af32e75SAxel Dörfler //	#pragma mark -
1055af32e75SAxel Dörfler 
1065af32e75SAxel Dörfler 
1075af32e75SAxel Dörfler Stream::Stream(Volume &volume, block_run run)
1085af32e75SAxel Dörfler 	:
1090dc4d1e5SIngo Weinhold 	fVolume(volume)
1105af32e75SAxel Dörfler {
1110dc4d1e5SIngo Weinhold 	if (read_pos(volume.Device(), volume.ToOffset(run), this, sizeof(bfs_inode)) != sizeof(bfs_inode))
1120dc4d1e5SIngo Weinhold 		return;
1135af32e75SAxel Dörfler }
1145af32e75SAxel Dörfler 
1155af32e75SAxel Dörfler 
1165af32e75SAxel Dörfler Stream::Stream(Volume &volume, off_t id)
1175af32e75SAxel Dörfler 	:
1180dc4d1e5SIngo Weinhold 	fVolume(volume)
1195af32e75SAxel Dörfler {
1200dc4d1e5SIngo Weinhold 	if (read_pos(volume.Device(), volume.ToOffset(id), this, sizeof(bfs_inode)) != sizeof(bfs_inode))
1210dc4d1e5SIngo Weinhold 		return;
1225af32e75SAxel Dörfler }
1235af32e75SAxel Dörfler 
1245af32e75SAxel Dörfler 
1255af32e75SAxel Dörfler Stream::~Stream()
1265af32e75SAxel Dörfler {
1275af32e75SAxel Dörfler }
1285af32e75SAxel Dörfler 
1295af32e75SAxel Dörfler 
1305af32e75SAxel Dörfler status_t
1315af32e75SAxel Dörfler Stream::InitCheck()
1325af32e75SAxel Dörfler {
1330dc4d1e5SIngo Weinhold 	return bfs_inode::InitCheck(&fVolume);
1345af32e75SAxel Dörfler }
1355af32e75SAxel Dörfler 
1365af32e75SAxel Dörfler 
1375af32e75SAxel Dörfler status_t
1385af32e75SAxel Dörfler Stream::GetNextSmallData(const small_data **_smallData) const
1395af32e75SAxel Dörfler {
140*9618c0dcSIngo Weinhold 	// TODO: Stream derives from bfs_inode and we read only sizeof(bfs_inode)
141*9618c0dcSIngo Weinhold 	// bytes from disk, i.e. the small data region is not in memory.
142*9618c0dcSIngo Weinhold 	panic("Stream::GetNextSmallData(): small data region is not loaded!");
143*9618c0dcSIngo Weinhold 
1445af32e75SAxel Dörfler 	const small_data *smallData = *_smallData;
1455af32e75SAxel Dörfler 
1465af32e75SAxel Dörfler 	// begin from the start?
1475af32e75SAxel Dörfler 	if (smallData == NULL)
1480dc4d1e5SIngo Weinhold 		smallData = small_data_start;
1495af32e75SAxel Dörfler 	else
1505af32e75SAxel Dörfler 		smallData = smallData->Next();
1515af32e75SAxel Dörfler 
1525af32e75SAxel Dörfler 	// is already last item?
1530dc4d1e5SIngo Weinhold 	if (smallData->IsLast(this))
1545af32e75SAxel Dörfler 		return B_ENTRY_NOT_FOUND;
1555af32e75SAxel Dörfler 
1565af32e75SAxel Dörfler 	*_smallData = smallData;
1575af32e75SAxel Dörfler 
1585af32e75SAxel Dörfler 	return B_OK;
1595af32e75SAxel Dörfler }
1605af32e75SAxel Dörfler 
1615af32e75SAxel Dörfler 
1625af32e75SAxel Dörfler status_t
1635af32e75SAxel Dörfler Stream::GetName(char *name, size_t size) const
1645af32e75SAxel Dörfler {
1655af32e75SAxel Dörfler 	const small_data *smallData = NULL;
1665af32e75SAxel Dörfler 	while (GetNextSmallData(&smallData) == B_OK) {
1675af32e75SAxel Dörfler 		if (*smallData->Name() == FILE_NAME_NAME
1685af32e75SAxel Dörfler 			&& smallData->NameSize() == FILE_NAME_NAME_LENGTH) {
1695af32e75SAxel Dörfler 			strlcpy(name, (const char *)smallData->Data(), size);
1705af32e75SAxel Dörfler 			return B_OK;
1715af32e75SAxel Dörfler 		}
1725af32e75SAxel Dörfler 	}
1735af32e75SAxel Dörfler 	return B_ERROR;
1745af32e75SAxel Dörfler }
1755af32e75SAxel Dörfler 
1765af32e75SAxel Dörfler 
1775af32e75SAxel Dörfler status_t
1785af32e75SAxel Dörfler Stream::ReadLink(char *buffer, size_t bufferSize)
1795af32e75SAxel Dörfler {
1805af32e75SAxel Dörfler 	// link in the stream
1815af32e75SAxel Dörfler 
1820dc4d1e5SIngo Weinhold 	if (Flags() & INODE_LONG_SYMLINK)
1835af32e75SAxel Dörfler 		return ReadAt(0, (uint8 *)buffer, &bufferSize);
1845af32e75SAxel Dörfler 
1855af32e75SAxel Dörfler 	// link in the inode
1865af32e75SAxel Dörfler 
1870dc4d1e5SIngo Weinhold 	strlcpy(buffer, short_symlink, bufferSize);
1885af32e75SAxel Dörfler 	return B_OK;
1895af32e75SAxel Dörfler }
1905af32e75SAxel Dörfler 
1915af32e75SAxel Dörfler 
1925af32e75SAxel Dörfler status_t
1935af32e75SAxel Dörfler Stream::FindBlockRun(off_t pos, block_run &run, off_t &offset)
1945af32e75SAxel Dörfler {
1955af32e75SAxel Dörfler 	// find matching block run
1965af32e75SAxel Dörfler 
1970dc4d1e5SIngo Weinhold 	if (data.MaxDirectRange() > 0 && pos >= data.MaxDirectRange()) {
1980dc4d1e5SIngo Weinhold 		if (data.MaxDoubleIndirectRange() > 0 && pos >= data.MaxIndirectRange()) {
1995af32e75SAxel Dörfler 			// access to double indirect blocks
2005af32e75SAxel Dörfler 
2015af32e75SAxel Dörfler 			CachedBlock cached(fVolume);
2025af32e75SAxel Dörfler 
2030dc4d1e5SIngo Weinhold 			off_t start = pos - data.MaxIndirectRange();
2040dc4d1e5SIngo Weinhold 			int32 indirectSize = (1L << (INDIRECT_BLOCKS_SHIFT + cached.BlockShift()))
2055af32e75SAxel Dörfler 				* (fVolume.BlockSize() / sizeof(block_run));
2065af32e75SAxel Dörfler 			int32 directSize = NUM_ARRAY_BLOCKS << cached.BlockShift();
2075af32e75SAxel Dörfler 			int32 index = start / indirectSize;
2085af32e75SAxel Dörfler 			int32 runsPerBlock = cached.BlockSize() / sizeof(block_run);
2095af32e75SAxel Dörfler 
2105af32e75SAxel Dörfler 			block_run *indirect = (block_run *)cached.SetTo(
2110dc4d1e5SIngo Weinhold 					fVolume.ToBlock(data.double_indirect) + index / runsPerBlock);
2125af32e75SAxel Dörfler 			if (indirect == NULL)
2135af32e75SAxel Dörfler 				return B_ERROR;
2145af32e75SAxel Dörfler 
2155af32e75SAxel Dörfler 			//printf("\tstart = %Ld, indirectSize = %ld, directSize = %ld, index = %ld\n",start,indirectSize,directSize,index);
2165af32e75SAxel Dörfler 			//printf("\tlook for indirect block at %ld,%d\n",indirect[index].allocation_group,indirect[index].start);
2175af32e75SAxel Dörfler 
2185af32e75SAxel Dörfler 			int32 current = (start % indirectSize) / directSize;
2195af32e75SAxel Dörfler 
2205af32e75SAxel Dörfler 			indirect = (block_run *)cached.SetTo(
2215af32e75SAxel Dörfler 					fVolume.ToBlock(indirect[index % runsPerBlock]) + current / runsPerBlock);
2225af32e75SAxel Dörfler 			if (indirect == NULL)
2235af32e75SAxel Dörfler 				return B_ERROR;
2245af32e75SAxel Dörfler 
2255af32e75SAxel Dörfler 			run = indirect[current % runsPerBlock];
2260dc4d1e5SIngo Weinhold 			offset = data.MaxIndirectRange() + (index * indirectSize) + (current * directSize);
2275af32e75SAxel Dörfler 			//printf("\tfCurrent = %ld, fRunFileOffset = %Ld, fRunBlockEnd = %Ld, fRun = %ld,%d\n",fCurrent,fRunFileOffset,fRunBlockEnd,fRun.allocation_group,fRun.start);
2285af32e75SAxel Dörfler 		} else {
2295af32e75SAxel Dörfler 			// access to indirect blocks
2305af32e75SAxel Dörfler 
2315af32e75SAxel Dörfler 			int32 runsPerBlock = fVolume.BlockSize() / sizeof(block_run);
2320dc4d1e5SIngo Weinhold 			off_t runBlockEnd = data.MaxDirectRange();
2335af32e75SAxel Dörfler 
2345af32e75SAxel Dörfler 			CachedBlock cached(fVolume);
2350dc4d1e5SIngo Weinhold 			off_t block = fVolume.ToBlock(data.indirect);
2365af32e75SAxel Dörfler 
2370dc4d1e5SIngo Weinhold 			for (int32 i = 0;i < data.indirect.Length();i++) {
2385af32e75SAxel Dörfler 				block_run *indirect = (block_run *)cached.SetTo(block + i);
2395af32e75SAxel Dörfler 				if (indirect == NULL)
2405af32e75SAxel Dörfler 					return B_IO_ERROR;
2415af32e75SAxel Dörfler 
2425af32e75SAxel Dörfler 				int32 current = -1;
2435af32e75SAxel Dörfler 				while (++current < runsPerBlock) {
2445af32e75SAxel Dörfler 					if (indirect[current].IsZero())
2455af32e75SAxel Dörfler 						break;
2465af32e75SAxel Dörfler 
2475af32e75SAxel Dörfler 					runBlockEnd += indirect[current].Length() << cached.BlockShift();
2485af32e75SAxel Dörfler 					if (runBlockEnd > pos) {
2495af32e75SAxel Dörfler 						run = indirect[current];
2505af32e75SAxel Dörfler 						offset = runBlockEnd - (run.Length() << cached.BlockShift());
2515af32e75SAxel Dörfler 						//printf("reading from indirect block: %ld,%d\n",fRun.allocation_group,fRun.start);
2525af32e75SAxel Dörfler 						//printf("### indirect-run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset);
2535af32e75SAxel Dörfler 						return fVolume.ValidateBlockRun(run);
2545af32e75SAxel Dörfler 					}
2555af32e75SAxel Dörfler 				}
2565af32e75SAxel Dörfler 			}
2575af32e75SAxel Dörfler 			return B_ERROR;
2585af32e75SAxel Dörfler 		}
2595af32e75SAxel Dörfler 	} else {
2605af32e75SAxel Dörfler 		// access from direct blocks
2615af32e75SAxel Dörfler 
2625af32e75SAxel Dörfler 		off_t runBlockEnd = 0LL;
2635af32e75SAxel Dörfler 		int32 current = -1;
2645af32e75SAxel Dörfler 
2655af32e75SAxel Dörfler 		while (++current < NUM_DIRECT_BLOCKS) {
2660dc4d1e5SIngo Weinhold 			if (data.direct[current].IsZero())
2675af32e75SAxel Dörfler 				break;
2685af32e75SAxel Dörfler 
2690dc4d1e5SIngo Weinhold 			runBlockEnd += data.direct[current].Length() << fVolume.BlockShift();
2705af32e75SAxel Dörfler 			if (runBlockEnd > pos) {
2710dc4d1e5SIngo Weinhold 				run = data.direct[current];
2725af32e75SAxel Dörfler 				offset = runBlockEnd - (run.Length() << fVolume.BlockShift());
2735af32e75SAxel Dörfler 				//printf("### run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.length,fRunFileOffset);
2745af32e75SAxel Dörfler 				return fVolume.ValidateBlockRun(run);
2755af32e75SAxel Dörfler 			}
2765af32e75SAxel Dörfler 		}
2775af32e75SAxel Dörfler 		//PRINT(("FindBlockRun() failed in direct range: size = %Ld, pos = %Ld\n",data.size,pos));
2785af32e75SAxel Dörfler 		return B_ENTRY_NOT_FOUND;
2795af32e75SAxel Dörfler 	}
2805af32e75SAxel Dörfler 	return fVolume.ValidateBlockRun(run);
2815af32e75SAxel Dörfler }
2825af32e75SAxel Dörfler 
2835af32e75SAxel Dörfler 
2845af32e75SAxel Dörfler status_t
2855af32e75SAxel Dörfler Stream::ReadAt(off_t pos, uint8 *buffer, size_t *_length)
2865af32e75SAxel Dörfler {
2875af32e75SAxel Dörfler 	// set/check boundaries for pos/length
2885af32e75SAxel Dörfler 
2895af32e75SAxel Dörfler 	if (pos < 0)
2905af32e75SAxel Dörfler 		return B_BAD_VALUE;
2910dc4d1e5SIngo Weinhold 	if (pos >= data.Size()) {
2925af32e75SAxel Dörfler 		*_length = 0;
2935af32e75SAxel Dörfler 		return B_NO_ERROR;
2945af32e75SAxel Dörfler 	}
2955af32e75SAxel Dörfler 
2965af32e75SAxel Dörfler 	size_t length = *_length;
2975af32e75SAxel Dörfler 
2980dc4d1e5SIngo Weinhold 	if (pos + length > data.Size())
2990dc4d1e5SIngo Weinhold 		length = data.Size() - pos;
3005af32e75SAxel Dörfler 
3015af32e75SAxel Dörfler 	block_run run;
3025af32e75SAxel Dörfler 	off_t offset;
3035af32e75SAxel Dörfler 	if (FindBlockRun(pos, run, offset) < B_OK) {
3045af32e75SAxel Dörfler 		*_length = 0;
3055af32e75SAxel Dörfler 		return B_BAD_VALUE;
3065af32e75SAxel Dörfler 	}
3075af32e75SAxel Dörfler 
3085af32e75SAxel Dörfler 	uint32 bytesRead = 0;
3095af32e75SAxel Dörfler 	uint32 blockSize = fVolume.BlockSize();
3105af32e75SAxel Dörfler 	uint32 blockShift = fVolume.BlockShift();
3115af32e75SAxel Dörfler 	uint8 *block;
3125af32e75SAxel Dörfler 
3135af32e75SAxel Dörfler 	// the first block_run we read could not be aligned to the block_size boundary
3145af32e75SAxel Dörfler 	// (read partial block at the beginning)
3155af32e75SAxel Dörfler 
3165af32e75SAxel Dörfler 	// pos % block_size == (pos - offset) % block_size, offset % block_size == 0
3175af32e75SAxel Dörfler 	if (pos % blockSize != 0) {
3185af32e75SAxel Dörfler 		run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + ((pos - offset) >> blockShift));
3195af32e75SAxel Dörfler 		run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - ((pos - offset) >> blockShift));
3205af32e75SAxel Dörfler 
3215af32e75SAxel Dörfler 		CachedBlock cached(fVolume, run);
3225af32e75SAxel Dörfler 		if ((block = cached.Block()) == NULL) {
3235af32e75SAxel Dörfler 			*_length = 0;
3245af32e75SAxel Dörfler 			return B_BAD_VALUE;
3255af32e75SAxel Dörfler 		}
3265af32e75SAxel Dörfler 
3275af32e75SAxel Dörfler 		bytesRead = blockSize - (pos % blockSize);
3285af32e75SAxel Dörfler 		if (length < bytesRead)
3295af32e75SAxel Dörfler 			bytesRead = length;
3305af32e75SAxel Dörfler 
3315af32e75SAxel Dörfler 		memcpy(buffer, block + (pos % blockSize), bytesRead);
3325af32e75SAxel Dörfler 		pos += bytesRead;
3335af32e75SAxel Dörfler 
3345af32e75SAxel Dörfler 		length -= bytesRead;
3355af32e75SAxel Dörfler 		if (length == 0) {
3365af32e75SAxel Dörfler 			*_length = bytesRead;
3375af32e75SAxel Dörfler 			return B_OK;
3385af32e75SAxel Dörfler 		}
3395af32e75SAxel Dörfler 
3405af32e75SAxel Dörfler 		if (FindBlockRun(pos, run, offset) < B_OK) {
3415af32e75SAxel Dörfler 			*_length = bytesRead;
3425af32e75SAxel Dörfler 			return B_BAD_VALUE;
3435af32e75SAxel Dörfler 		}
3445af32e75SAxel Dörfler 	}
3455af32e75SAxel Dörfler 
3465af32e75SAxel Dörfler 	// the first block_run is already filled in at this point
3475af32e75SAxel Dörfler 	// read the following complete blocks using cached_read(),
3485af32e75SAxel Dörfler 	// the last partial block is read using the generic Cache class
3495af32e75SAxel Dörfler 
3505af32e75SAxel Dörfler 	bool partial = false;
3515af32e75SAxel Dörfler 
3525af32e75SAxel Dörfler 	while (length > 0) {
3535af32e75SAxel Dörfler 		// offset is the offset to the current pos in the block_run
3545af32e75SAxel Dörfler 		run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + ((pos - offset) >> blockShift));
3555af32e75SAxel Dörfler 		run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - ((pos - offset) >> blockShift));
3565af32e75SAxel Dörfler 
3575af32e75SAxel Dörfler 		if (uint32(run.Length() << blockShift) > length) {
3585af32e75SAxel Dörfler 			if (length < blockSize) {
3595af32e75SAxel Dörfler 				CachedBlock cached(fVolume, run);
3605af32e75SAxel Dörfler 				if ((block = cached.Block()) == NULL) {
3615af32e75SAxel Dörfler 					*_length = bytesRead;
3625af32e75SAxel Dörfler 					return B_BAD_VALUE;
3635af32e75SAxel Dörfler 				}
3645af32e75SAxel Dörfler 				memcpy(buffer + bytesRead, block, length);
3655af32e75SAxel Dörfler 				bytesRead += length;
3665af32e75SAxel Dörfler 				break;
3675af32e75SAxel Dörfler 			}
3685af32e75SAxel Dörfler 			run.length = HOST_ENDIAN_TO_BFS_INT16(length >> blockShift);
3695af32e75SAxel Dörfler 			partial = true;
3705af32e75SAxel Dörfler 		}
3715af32e75SAxel Dörfler 
3725af32e75SAxel Dörfler 		if (read_pos(fVolume.Device(), fVolume.ToOffset(run), buffer + bytesRead, run.Length() << fVolume.BlockShift()) < B_OK) {
3735af32e75SAxel Dörfler 			*_length = bytesRead;
3745af32e75SAxel Dörfler 			return B_BAD_VALUE;
3755af32e75SAxel Dörfler 		}
3765af32e75SAxel Dörfler 
3775af32e75SAxel Dörfler 		int32 bytes = run.Length() << blockShift;
3785af32e75SAxel Dörfler 		length -= bytes;
3795af32e75SAxel Dörfler 		bytesRead += bytes;
3805af32e75SAxel Dörfler 		if (length == 0)
3815af32e75SAxel Dörfler 			break;
3825af32e75SAxel Dörfler 
3835af32e75SAxel Dörfler 		pos += bytes;
3845af32e75SAxel Dörfler 
3855af32e75SAxel Dörfler 		if (partial) {
3865af32e75SAxel Dörfler 			// if the last block was read only partially, point block_run
3875af32e75SAxel Dörfler 			// to the remaining part
3885af32e75SAxel Dörfler 			run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + run.Length());
3895af32e75SAxel Dörfler 			run.length = 1;
3905af32e75SAxel Dörfler 			offset = pos;
3915af32e75SAxel Dörfler 		} else if (FindBlockRun(pos, run, offset) < B_OK) {
3925af32e75SAxel Dörfler 			*_length = bytesRead;
3935af32e75SAxel Dörfler 			return B_BAD_VALUE;
3945af32e75SAxel Dörfler 		}
3955af32e75SAxel Dörfler 	}
3965af32e75SAxel Dörfler 
3975af32e75SAxel Dörfler 	*_length = bytesRead;
3985af32e75SAxel Dörfler 	return B_NO_ERROR;
3995af32e75SAxel Dörfler }
4005af32e75SAxel Dörfler 
4015af32e75SAxel Dörfler 
4025af32e75SAxel Dörfler Node *
4030dc4d1e5SIngo Weinhold Stream::NodeFactory(Volume &volume, off_t id)
4045af32e75SAxel Dörfler {
4055af32e75SAxel Dörfler 	Stream stream(volume, id);
4065af32e75SAxel Dörfler 	if (stream.InitCheck() != B_OK)
4075af32e75SAxel Dörfler 		return NULL;
4085af32e75SAxel Dörfler 
4095af32e75SAxel Dörfler 	if (stream.IsContainer())
4100dc4d1e5SIngo Weinhold 		return new(nothrow) Directory(stream);
4115af32e75SAxel Dörfler 
4125af32e75SAxel Dörfler 	if (stream.IsSymlink())
41382029bdaSMarcus Overhagen 		return new(nothrow) Link(stream);
4145af32e75SAxel Dörfler 
41582029bdaSMarcus Overhagen 	return new(nothrow) File(stream);
4165af32e75SAxel Dörfler }
4175af32e75SAxel Dörfler 
4185af32e75SAxel Dörfler 
4195af32e75SAxel Dörfler //	#pragma mark -
4205af32e75SAxel Dörfler 
4215af32e75SAxel Dörfler 
4225af32e75SAxel Dörfler status_t
4235af32e75SAxel Dörfler bfs_inode::InitCheck(Volume *volume)
4245af32e75SAxel Dörfler {
4255af32e75SAxel Dörfler 	if (Flags() & INODE_NOT_READY) {
4265af32e75SAxel Dörfler 		// the other fields may not yet contain valid values
4275af32e75SAxel Dörfler 		return B_BUSY;
4285af32e75SAxel Dörfler 	}
4295af32e75SAxel Dörfler 
4305af32e75SAxel Dörfler 	if (Magic1() != INODE_MAGIC1
4315af32e75SAxel Dörfler 		|| !(Flags() & INODE_IN_USE)
4325af32e75SAxel Dörfler 		|| inode_num.Length() != 1
4335af32e75SAxel Dörfler 		// matches inode size?
4345af32e75SAxel Dörfler 		|| (uint32)InodeSize() != volume->InodeSize()
4355af32e75SAxel Dörfler 		// parent resides on disk?
4365af32e75SAxel Dörfler 		|| parent.AllocationGroup() > int32(volume->AllocationGroups())
4375af32e75SAxel Dörfler 		|| parent.AllocationGroup() < 0
4385af32e75SAxel Dörfler 		|| parent.Start() > (1L << volume->AllocationGroupShift())
4395af32e75SAxel Dörfler 		|| parent.Length() != 1
4405af32e75SAxel Dörfler 		// attributes, too?
4415af32e75SAxel Dörfler 		|| attributes.AllocationGroup() > int32(volume->AllocationGroups())
4425af32e75SAxel Dörfler 		|| attributes.AllocationGroup() < 0
4435af32e75SAxel Dörfler 		|| attributes.Start() > (1L << volume->AllocationGroupShift()))
4445af32e75SAxel Dörfler 		return B_BAD_DATA;
4455af32e75SAxel Dörfler 
4465af32e75SAxel Dörfler 	// ToDo: Add some tests to check the integrity of the other stuff here,
4475af32e75SAxel Dörfler 	// especially for the data_stream!
4485af32e75SAxel Dörfler 
4495af32e75SAxel Dörfler 	return B_OK;
4505af32e75SAxel Dörfler }
4515af32e75SAxel Dörfler 
452