1a1b0ec30SJérôme Duval/*
2a1b0ec30SJérôme Duval * Copyright 2001-2010, Haiku Inc. All rights reserved.
3a1b0ec30SJérôme Duval * This file may be used under the terms of the MIT License.
4a1b0ec30SJérôme Duval *
5a1b0ec30SJérôme Duval * Authors:
6a1b0ec30SJérôme Duval *		Janito V. Ferreira Filho
7a1b0ec30SJérôme Duval */
8a1b0ec30SJérôme Duval
9a1b0ec30SJérôme Duval
10a1b0ec30SJérôme Duval#include "DataStream.h"
11a1b0ec30SJérôme Duval
12a1b0ec30SJérôme Duval#include "CachedBlock.h"
13a1b0ec30SJérôme Duval#include "Volume.h"
14a1b0ec30SJérôme Duval
15a1b0ec30SJérôme Duval
16a1b0ec30SJérôme Duval//#define TRACE_EXT2
17a1b0ec30SJérôme Duval#ifdef TRACE_EXT2
18a1b0ec30SJérôme Duval#	define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
19a1b0ec30SJérôme Duval#else
20a1b0ec30SJérôme Duval#	define TRACE(x...) ;
21a1b0ec30SJérôme Duval#endif
22d8772e0cSJérôme Duval#define ERROR(x...)	dprintf("\33[34mext2:\33[0m " x)
23a1b0ec30SJérôme Duval
24a1b0ec30SJérôme Duval
25a1b0ec30SJérôme DuvalDataStream::DataStream(Volume* volume, ext2_data_stream* stream,
26a1b0ec30SJérôme Duval	off_t size)
27a1b0ec30SJérôme Duval	:
28a1b0ec30SJérôme Duval	kBlockSize(volume->BlockSize()),
29de66992bSJérôme Duval	kIndirectsPerBlock(kBlockSize / sizeof(uint32)),
30a1b0ec30SJérôme Duval	kIndirectsPerBlock2(kIndirectsPerBlock * kIndirectsPerBlock),
31a1b0ec30SJérôme Duval	kIndirectsPerBlock3(kIndirectsPerBlock2 * kIndirectsPerBlock),
32a1b0ec30SJérôme Duval	kMaxDirect(EXT2_DIRECT_BLOCKS),
33a1b0ec30SJérôme Duval	kMaxIndirect(kMaxDirect + kIndirectsPerBlock),
34a1b0ec30SJérôme Duval	kMaxDoubleIndirect(kMaxIndirect + kIndirectsPerBlock2),
35a1b0ec30SJérôme Duval	fVolume(volume),
36a1b0ec30SJérôme Duval	fStream(stream),
37a1b0ec30SJérôme Duval	fFirstBlock(volume->FirstDataBlock()),
38a1b0ec30SJérôme Duval	fAllocated(0),
39a1b0ec30SJérôme Duval	fAllocatedPos(fFirstBlock),
40a1b0ec30SJérôme Duval	fWaiting(0),
41a1b0ec30SJérôme Duval	fFreeStart(0),
42a1b0ec30SJérôme Duval	fFreeCount(0),
439637baaeSJérôme Duval	fRemovedBlocks(0),
449637baaeSJérôme Duval	fSize(size)
45a1b0ec30SJérôme Duval{
469637baaeSJérôme Duval	fNumBlocks = size == 0 ? 0 : ((size - 1) >> fVolume->BlockShift()) + 1;
47a1b0ec30SJérôme Duval}
48a1b0ec30SJérôme Duval
49a1b0ec30SJérôme Duval
50a1b0ec30SJérôme DuvalDataStream::~DataStream()
51a1b0ec30SJérôme Duval{
52a1b0ec30SJérôme Duval}
53a1b0ec30SJérôme Duval
54a1b0ec30SJérôme Duval
559637baaeSJérôme Duvalstatus_t
5645af882dSJérôme DuvalDataStream::FindBlock(off_t offset, fsblock_t& block, uint32 *_count)
579637baaeSJérôme Duval{
589637baaeSJérôme Duval	uint32 index = offset >> fVolume->BlockShift();
599637baaeSJérôme Duval
609637baaeSJérôme Duval	if (offset >= fSize) {
619637baaeSJérôme Duval		TRACE("FindBlock: offset larger than inode size\n");
629637baaeSJérôme Duval		return B_ENTRY_NOT_FOUND;
639637baaeSJérôme Duval	}
649637baaeSJérôme Duval
659637baaeSJérôme Duval	// TODO: we could return the size of the sparse range, as this might be more
669637baaeSJérôme Duval	// than just a block
679637baaeSJérôme Duval
689637baaeSJérôme Duval	if (index < EXT2_DIRECT_BLOCKS) {
699637baaeSJérôme Duval		// direct blocks
709637baaeSJérôme Duval		block = B_LENDIAN_TO_HOST_INT32(fStream->direct[index]);
719637baaeSJérôme Duval		ASSERT(block != 0);
729637baaeSJérôme Duval		if (_count) {
739637baaeSJérôme Duval			*_count = 1;
749637baaeSJérôme Duval			uint32 nextBlock = block;
759637baaeSJérôme Duval			while (++index < EXT2_DIRECT_BLOCKS
769637baaeSJérôme Duval				&& fStream->direct[index] == ++nextBlock)
779637baaeSJérôme Duval				(*_count)++;
789637baaeSJérôme Duval		}
799637baaeSJérôme Duval	} else if ((index -= EXT2_DIRECT_BLOCKS) < kIndirectsPerBlock) {
809637baaeSJérôme Duval		// indirect blocks
819637baaeSJérôme Duval		CachedBlock cached(fVolume);
829637baaeSJérôme Duval		uint32* indirectBlocks = (uint32*)cached.SetTo(B_LENDIAN_TO_HOST_INT32(
839637baaeSJérôme Duval			fStream->indirect));
849637baaeSJérôme Duval		if (indirectBlocks == NULL)
859637baaeSJérôme Duval			return B_IO_ERROR;
869637baaeSJérôme Duval
879637baaeSJérôme Duval		block = B_LENDIAN_TO_HOST_INT32(indirectBlocks[index]);
889637baaeSJérôme Duval		ASSERT(block != 0);
899637baaeSJérôme Duval		if (_count) {
909637baaeSJérôme Duval			*_count = 1;
919637baaeSJérôme Duval			uint32 nextBlock = block;
929637baaeSJérôme Duval			while (++index < kIndirectsPerBlock
939637baaeSJérôme Duval				&& indirectBlocks[index] == ++nextBlock)
949637baaeSJérôme Duval				(*_count)++;
959637baaeSJérôme Duval		}
969637baaeSJérôme Duval	} else if ((index -= kIndirectsPerBlock) < kIndirectsPerBlock2) {
979637baaeSJérôme Duval		// double indirect blocks
989637baaeSJérôme Duval		CachedBlock cached(fVolume);
999637baaeSJérôme Duval		uint32* indirectBlocks = (uint32*)cached.SetTo(B_LENDIAN_TO_HOST_INT32(
1009637baaeSJérôme Duval			fStream->double_indirect));
1019637baaeSJérôme Duval		if (indirectBlocks == NULL)
1029637baaeSJérôme Duval			return B_IO_ERROR;
1039637baaeSJérôme Duval
1049637baaeSJérôme Duval		uint32 indirectIndex = B_LENDIAN_TO_HOST_INT32(indirectBlocks[index
1059637baaeSJérôme Duval			/ kIndirectsPerBlock]);
1069637baaeSJérôme Duval		if (indirectIndex == 0) {
1079637baaeSJérôme Duval			// a sparse indirect block
1089637baaeSJérôme Duval			block = 0;
1099637baaeSJérôme Duval		} else {
1109637baaeSJérôme Duval			indirectBlocks = (uint32*)cached.SetTo(indirectIndex);
1119637baaeSJérôme Duval			if (indirectBlocks == NULL)
1129637baaeSJérôme Duval				return B_IO_ERROR;
1139637baaeSJérôme Duval
1149637baaeSJérôme Duval			block = B_LENDIAN_TO_HOST_INT32(
1159637baaeSJérôme Duval				indirectBlocks[index & (kIndirectsPerBlock - 1)]);
1169637baaeSJérôme Duval			if (_count) {
1179637baaeSJérôme Duval				*_count = 1;
1189637baaeSJérôme Duval				uint32 nextBlock = block;
1199637baaeSJérôme Duval				while (((++index & (kIndirectsPerBlock - 1)) != 0)
1209637baaeSJérôme Duval					&& indirectBlocks[index & (kIndirectsPerBlock - 1)]
1219637baaeSJérôme Duval						== ++nextBlock)
1229637baaeSJérôme Duval					(*_count)++;
1239637baaeSJérôme Duval			}
1249637baaeSJérôme Duval		}
1259637baaeSJérôme Duval		ASSERT(block != 0);
1269637baaeSJérôme Duval	} else if ((index -= kIndirectsPerBlock2) < kIndirectsPerBlock3) {
1279637baaeSJérôme Duval		// triple indirect blocks
1289637baaeSJérôme Duval		CachedBlock cached(fVolume);
1299637baaeSJérôme Duval		uint32* indirectBlocks = (uint32*)cached.SetTo(B_LENDIAN_TO_HOST_INT32(
1309637baaeSJérôme Duval			fStream->triple_indirect));
1319637baaeSJérôme Duval		if (indirectBlocks == NULL)
1329637baaeSJérôme Duval			return B_IO_ERROR;
1339637baaeSJérôme Duval
1349637baaeSJérôme Duval		uint32 indirectIndex = B_LENDIAN_TO_HOST_INT32(indirectBlocks[index
1359637baaeSJérôme Duval			/ kIndirectsPerBlock2]);
1369637baaeSJérôme Duval		if (indirectIndex == 0) {
1379637baaeSJérôme Duval			// a sparse indirect block
1389637baaeSJérôme Duval			block = 0;
1399637baaeSJérôme Duval		} else {
1409637baaeSJérôme Duval			indirectBlocks = (uint32*)cached.SetTo(indirectIndex);
1419637baaeSJérôme Duval			if (indirectBlocks == NULL)
1429637baaeSJérôme Duval				return B_IO_ERROR;
1439637baaeSJérôme Duval
1449637baaeSJérôme Duval			indirectIndex = B_LENDIAN_TO_HOST_INT32(
1459637baaeSJérôme Duval				indirectBlocks[(index / kIndirectsPerBlock) & (kIndirectsPerBlock - 1)]);
1469637baaeSJérôme Duval			if (indirectIndex == 0) {
1479637baaeSJérôme Duval				// a sparse indirect block
1489637baaeSJérôme Duval				block = 0;
1499637baaeSJérôme Duval			} else {
1509637baaeSJérôme Duval				indirectBlocks = (uint32*)cached.SetTo(indirectIndex);
1519637baaeSJérôme Duval				if (indirectBlocks == NULL)
1529637baaeSJérôme Duval					return B_IO_ERROR;
1539637baaeSJérôme Duval
1549637baaeSJérôme Duval				block = B_LENDIAN_TO_HOST_INT32(
1559637baaeSJérôme Duval					indirectBlocks[index & (kIndirectsPerBlock - 1)]);
1569637baaeSJérôme Duval				if (_count) {
1579637baaeSJérôme Duval					*_count = 1;
1589637baaeSJérôme Duval					uint32 nextBlock = block;
1599637baaeSJérôme Duval					while (((++index & (kIndirectsPerBlock - 1)) != 0)
1609637baaeSJérôme Duval						&& indirectBlocks[index & (kIndirectsPerBlock - 1)]
1619637baaeSJérôme Duval							== ++nextBlock)
1629637baaeSJérôme Duval						(*_count)++;
1639637baaeSJérôme Duval				}
1649637baaeSJérôme Duval			}
1659637baaeSJérôme Duval		}
1669637baaeSJérôme Duval		ASSERT(block != 0);
1679637baaeSJérôme Duval	} else {
1689637baaeSJérôme Duval		// Outside of the possible data stream
169ce4e12caSJérôme Duval		ERROR("ext2: block outside datastream!\n");
1709637baaeSJérôme Duval		return B_ERROR;
1719637baaeSJérôme Duval	}
1729637baaeSJérôme Duval
173a130bab3SJérôme Duval	TRACE("FindBlock(offset %" B_PRIdOFF "): %" B_PRIu64" %" B_PRIu32 "\n", offset,
174a130bab3SJérôme Duval		block, _count != NULL ? *_count : 1);
1759637baaeSJérôme Duval	return B_OK;
1769637baaeSJérôme Duval}
1779637baaeSJérôme Duval
1789637baaeSJérôme Duval
179a1b0ec30SJérôme Duvalstatus_t
180d8772e0cSJérôme DuvalDataStream::Enlarge(Transaction& transaction, off_t& numBlocks)
181a1b0ec30SJérôme Duval{
182a130bab3SJérôme Duval	TRACE("DataStream::Enlarge(): current size: %" B_PRIdOFF ", target size: %"
183a130bab3SJérôme Duval		B_PRIdOFF "\n", fNumBlocks, numBlocks);
184a1b0ec30SJérôme Duval
185d8772e0cSJérôme Duval	off_t targetBlocks = numBlocks;
186a1b0ec30SJérôme Duval	fWaiting = _BlocksNeeded(numBlocks);
187a1b0ec30SJérôme Duval	numBlocks = fWaiting;
188a1b0ec30SJérôme Duval
189a1b0ec30SJérôme Duval	status_t status;
190a1b0ec30SJérôme Duval
191a1b0ec30SJérôme Duval	if (fNumBlocks <= kMaxDirect) {
192a1b0ec30SJérôme Duval		status = _AddForDirectBlocks(transaction, targetBlocks);
193a1b0ec30SJérôme Duval
194d8772e0cSJérôme Duval		if (status != B_OK) {
195d8772e0cSJérôme Duval			ERROR("DataStream::Enlarge(): _AddForDirectBlocks() failed\n");
196a1b0ec30SJérôme Duval			return status;
197d8772e0cSJérôme Duval		}
198a1b0ec30SJérôme Duval
199a130bab3SJérôme Duval		TRACE("DataStream::Enlarge(): current size: %" B_PRIdOFF
200a130bab3SJérôme Duval			", target size: %" B_PRIdOFF "\n", fNumBlocks, targetBlocks);
201a1b0ec30SJérôme Duval
202a1b0ec30SJérôme Duval		if (fNumBlocks == targetBlocks)
203a1b0ec30SJérôme Duval			return B_OK;
204a1b0ec30SJérôme Duval	}
205a1b0ec30SJérôme Duval
206a130bab3SJérôme Duval	TRACE("DataStream::Enlarge(): indirect current size: %" B_PRIdOFF
207a130bab3SJérôme Duval		", target size: %" B_PRIdOFF "\n", fNumBlocks, targetBlocks);
208d8772e0cSJérôme Duval
209a1b0ec30SJérôme Duval	if (fNumBlocks <= kMaxIndirect) {
210a1b0ec30SJérôme Duval		status = _AddForIndirectBlock(transaction, targetBlocks);
211a1b0ec30SJérôme Duval
212d8772e0cSJérôme Duval		if (status != B_OK) {
213d8772e0cSJérôme Duval			ERROR("DataStream::Enlarge(): _AddForIndirectBlock() failed\n");
214a1b0ec30SJérôme Duval			return status;
215d8772e0cSJérôme Duval		}
216a1b0ec30SJérôme Duval
217a130bab3SJérôme Duval		TRACE("DataStream::Enlarge(): current size: %" B_PRIdOFF
218a130bab3SJérôme Duval			", target size: %" B_PRIdOFF "\n", fNumBlocks, targetBlocks);
219a1b0ec30SJérôme Duval
220a1b0ec30SJérôme Duval		if (fNumBlocks == targetBlocks)
221a1b0ec30SJérôme Duval			return B_OK;
222a1b0ec30SJérôme Duval	}
223a1b0ec30SJérôme Duval
224a130bab3SJérôme Duval	TRACE("DataStream::Enlarge(): indirect2 current size: %" B_PRIdOFF
225a130bab3SJérôme Duval		", target size: %" B_PRIdOFF "\n", fNumBlocks, targetBlocks);
226d8772e0cSJérôme Duval
227a1b0ec30SJérôme Duval	if (fNumBlocks <= kMaxDoubleIndirect) {
228a1b0ec30SJérôme Duval		status = _AddForDoubleIndirectBlock(transaction, targetBlocks);
229a1b0ec30SJérôme Duval
230d8772e0cSJérôme Duval		if (status != B_OK) {
231d8772e0cSJérôme Duval			ERROR("DataStream::Enlarge(): _AddForDoubleIndirectBlock() failed\n");
232a1b0ec30SJérôme Duval			return status;
233d8772e0cSJérôme Duval		}
234a1b0ec30SJérôme Duval
235a130bab3SJérôme Duval		TRACE("DataStream::Enlarge(): current size: %" B_PRIdOFF
236a130bab3SJérôme Duval			", target size: %" B_PRIdOFF "\n", fNumBlocks, targetBlocks);
237a1b0ec30SJérôme Duval
238a1b0ec30SJérôme Duval		if (fNumBlocks == targetBlocks)
239a1b0ec30SJérôme Duval			return B_OK;
240a1b0ec30SJérôme Duval	}
241a1b0ec30SJérôme Duval
242a130bab3SJérôme Duval	TRACE("DataStream::Enlarge(): indirect3 current size: %" B_PRIdOFF
243a130bab3SJérôme Duval		", target size: %" B_PRIdOFF "\n", fNumBlocks, targetBlocks);
244d8772e0cSJérôme Duval
245a130bab3SJérôme Duval	TRACE("DataStream::Enlarge(): allocated: %" B_PRIu32 ", waiting: %"
246a130bab3SJérôme Duval		B_PRIu32 "\n", fAllocated, fWaiting);
247a1b0ec30SJérôme Duval
248a1b0ec30SJérôme Duval	return _AddForTripleIndirectBlock(transaction, targetBlocks);
249a1b0ec30SJérôme Duval}
250a1b0ec30SJérôme Duval
251a1b0ec30SJérôme Duval
252a1b0ec30SJérôme Duvalstatus_t
253d8772e0cSJérôme DuvalDataStream::Shrink(Transaction& transaction, off_t& numBlocks)
254a1b0ec30SJérôme Duval{
255a130bab3SJérôme Duval	TRACE("DataStream::Shrink(): current size: %" B_PRIdOFF ", target size: %"
256a130bab3SJérôme Duval		B_PRIdOFF "\n", fNumBlocks, numBlocks);
257a1b0ec30SJérôme Duval
258a1b0ec30SJérôme Duval	fFreeStart = 0;
259a1b0ec30SJérôme Duval	fFreeCount = 0;
260a1b0ec30SJérôme Duval	fRemovedBlocks = 0;
261a1b0ec30SJérôme Duval
262d8772e0cSJérôme Duval	off_t oldNumBlocks = fNumBlocks;
263d8772e0cSJérôme Duval	off_t blocksToRemove = fNumBlocks - numBlocks;
264a1b0ec30SJérôme Duval
265a1b0ec30SJérôme Duval	status_t status;
266a1b0ec30SJérôme Duval
267a1b0ec30SJérôme Duval	if (numBlocks < kMaxDirect) {
268a1b0ec30SJérôme Duval		status = _RemoveFromDirectBlocks(transaction, numBlocks);
269a1b0ec30SJérôme Duval
270d8772e0cSJérôme Duval		if (status != B_OK) {
271d8772e0cSJérôme Duval			ERROR("DataStream::Shrink(): _RemoveFromDirectBlocks() failed\n");
272a1b0ec30SJérôme Duval			return status;
273d8772e0cSJérôme Duval		}
274a1b0ec30SJérôme Duval
275a1b0ec30SJérôme Duval		if (fRemovedBlocks == blocksToRemove) {
276a1b0ec30SJérôme Duval			fNumBlocks -= fRemovedBlocks;
277a1b0ec30SJérôme Duval			numBlocks = _BlocksNeeded(oldNumBlocks);
278a1b0ec30SJérôme Duval
279a1b0ec30SJérôme Duval			return _PerformFree(transaction);
280a1b0ec30SJérôme Duval		}
281a1b0ec30SJérôme Duval	}
282a1b0ec30SJérôme Duval
283a1b0ec30SJérôme Duval	if (numBlocks < kMaxIndirect) {
284a1b0ec30SJérôme Duval		status = _RemoveFromIndirectBlock(transaction, numBlocks);
285a1b0ec30SJérôme Duval
286d8772e0cSJérôme Duval		if (status != B_OK) {
287d8772e0cSJérôme Duval			ERROR("DataStream::Shrink(): _RemoveFromIndirectBlock() failed\n");
288a1b0ec30SJérôme Duval			return status;
289d8772e0cSJérôme Duval		}
290a1b0ec30SJérôme Duval
291a1b0ec30SJérôme Duval		if (fRemovedBlocks == blocksToRemove) {
292a1b0ec30SJérôme Duval			fNumBlocks -= fRemovedBlocks;
293a1b0ec30SJérôme Duval			numBlocks = _BlocksNeeded(oldNumBlocks);
294a1b0ec30SJérôme Duval
295a1b0ec30SJérôme Duval			return _PerformFree(transaction);
296a1b0ec30SJérôme Duval		}
297a1b0ec30SJérôme Duval	}
298a1b0ec30SJérôme Duval
299a1b0ec30SJérôme Duval	if (numBlocks < kMaxDoubleIndirect) {
300a1b0ec30SJérôme Duval		status = _RemoveFromDoubleIndirectBlock(transaction, numBlocks);
301a1b0ec30SJérôme Duval
302d8772e0cSJérôme Duval		if (status != B_OK) {
303d8772e0cSJérôme Duval			ERROR("DataStream::Shrink(): _RemoveFromDoubleIndirectBlock() failed\n");
304a1b0ec30SJérôme Duval			return status;
305d8772e0cSJérôme Duval		}
306a1b0ec30SJérôme Duval
307a1b0ec30SJérôme Duval		if (fRemovedBlocks == blocksToRemove) {
308a1b0ec30SJérôme Duval			fNumBlocks -= fRemovedBlocks;
309a1b0ec30SJérôme Duval			numBlocks = _BlocksNeeded(oldNumBlocks);
310a1b0ec30SJérôme Duval
311a1b0ec30SJérôme Duval			return _PerformFree(transaction);
312a1b0ec30SJérôme Duval		}
313a1b0ec30SJérôme Duval	}
314a1b0ec30SJérôme Duval
315a1b0ec30SJérôme Duval	status = _RemoveFromTripleIndirectBlock(transaction, numBlocks);
316a1b0ec30SJérôme Duval
317d8772e0cSJérôme Duval	if (status != B_OK) {
318d8772e0cSJérôme Duval		ERROR("DataStream::Shrink(): _RemoveFromTripleIndirectBlock() failed\n");
319a1b0ec30SJérôme Duval		return status;
320d8772e0cSJérôme Duval	}
321a1b0ec30SJérôme Duval
322a1b0ec30SJérôme Duval	fNumBlocks -= fRemovedBlocks;
323a1b0ec30SJérôme Duval	numBlocks = _BlocksNeeded(oldNumBlocks);
324a1b0ec30SJérôme Duval
325a1b0ec30SJérôme Duval	return _PerformFree(transaction);
326a1b0ec30SJérôme Duval}
327a1b0ec30SJérôme Duval
328a1b0ec30SJérôme Duval
329a1b0ec30SJérôme Duvaluint32
330d8772e0cSJérôme DuvalDataStream::_BlocksNeeded(off_t numBlocks)
331a1b0ec30SJérôme Duval{
332a130bab3SJérôme Duval	TRACE("DataStream::BlocksNeeded(): num blocks %" B_PRIdOFF "\n", numBlocks);
333d8772e0cSJérôme Duval	off_t blocksNeeded = 0;
334a1b0ec30SJérôme Duval
335a1b0ec30SJérôme Duval	if (numBlocks > fNumBlocks) {
336a1b0ec30SJérôme Duval		blocksNeeded += numBlocks - fNumBlocks;
337a1b0ec30SJérôme Duval
338a1b0ec30SJérôme Duval		if (numBlocks > kMaxDirect) {
339a1b0ec30SJérôme Duval			if (fNumBlocks <= kMaxDirect)
340a1b0ec30SJérôme Duval				blocksNeeded += 1;
341a1b0ec30SJérôme Duval
342a1b0ec30SJérôme Duval			if (numBlocks > kMaxIndirect) {
343a1b0ec30SJérôme Duval				if (fNumBlocks <= kMaxIndirect) {
344a1b0ec30SJérôme Duval					blocksNeeded += 2 + (numBlocks - kMaxIndirect - 1)
345a1b0ec30SJérôme Duval						/ kIndirectsPerBlock;
346a1b0ec30SJérôme Duval				} else {
347de66992bSJérôme Duval					blocksNeeded += (numBlocks - kMaxIndirect - 1)
348de66992bSJérôme Duval						/ kIndirectsPerBlock - (fNumBlocks
349de66992bSJérôme Duval							- kMaxIndirect - 1) / kIndirectsPerBlock;
350a1b0ec30SJérôme Duval				}
351a1b0ec30SJérôme Duval
352a1b0ec30SJérôme Duval				if (numBlocks > kMaxDoubleIndirect) {
353a1b0ec30SJérôme Duval					if (fNumBlocks <= kMaxDoubleIndirect) {
354a1b0ec30SJérôme Duval						blocksNeeded += 2 + (numBlocks - kMaxDoubleIndirect - 1)
355a1b0ec30SJérôme Duval							/ kIndirectsPerBlock2;
356a1b0ec30SJérôme Duval					} else {
357de66992bSJérôme Duval						blocksNeeded += (numBlocks - kMaxDoubleIndirect - 1)
358de66992bSJérôme Duval							/ kIndirectsPerBlock - (fNumBlocks
359de66992bSJérôme Duval								- kMaxDoubleIndirect - 1) / kIndirectsPerBlock;
360a1b0ec30SJérôme Duval					}
361a1b0ec30SJérôme Duval				}
362a1b0ec30SJérôme Duval			}
363a1b0ec30SJérôme Duval		}
364a1b0ec30SJérôme Duval	}
365a1b0ec30SJérôme Duval
366a130bab3SJérôme Duval	TRACE("DataStream::BlocksNeeded(): %" B_PRIdOFF "\n", blocksNeeded);
367a1b0ec30SJérôme Duval	return blocksNeeded;
368a1b0ec30SJérôme Duval}
369a1b0ec30SJérôme Duval
370a1b0ec30SJérôme Duval
371a1b0ec30SJérôme Duvalstatus_t
372d8772e0cSJérôme DuvalDataStream::_GetBlock(Transaction& transaction, uint32& blockNum)
373a1b0ec30SJérôme Duval{
374a130bab3SJérôme Duval	TRACE("DataStream::_GetBlock(): allocated: %" B_PRIu32 ", pos: %" B_PRIu64
375a130bab3SJérôme Duval		", waiting: %" B_PRIu32 "\n", fAllocated, fAllocatedPos, fWaiting);
376a1b0ec30SJérôme Duval
377a1b0ec30SJérôme Duval	if (fAllocated == 0) {
378a1b0ec30SJérôme Duval		uint32 blockGroup = (fAllocatedPos - fFirstBlock)
379a1b0ec30SJérôme Duval			/ fVolume->BlocksPerGroup();
38045af882dSJérôme Duval
381a1b0ec30SJérôme Duval		status_t status = fVolume->AllocateBlocks(transaction, 1, fWaiting,
382a1b0ec30SJérôme Duval			blockGroup, fAllocatedPos, fAllocated);
383d8772e0cSJérôme Duval		if (status != B_OK) {
384d8772e0cSJérôme Duval			ERROR("DataStream::_GetBlock(): AllocateBlocks() failed()\n");
385a1b0ec30SJérôme Duval			return status;
386d8772e0cSJérôme Duval		}
387ce4e12caSJérôme Duval		if (fAllocatedPos > UINT_MAX)
388ce4e12caSJérôme Duval			return B_FILE_TOO_LARGE;
389a1b0ec30SJérôme Duval
390a1b0ec30SJérôme Duval		fWaiting -= fAllocated;
391de66992bSJérôme Duval
392a130bab3SJérôme Duval		TRACE("DataStream::_GetBlock(): newAllocated: %" B_PRIu32 ", newpos: %"
393a130bab3SJérôme Duval			B_PRIu64 ", newwaiting: %" B_PRIu32 "\n", fAllocated,
394a130bab3SJérôme Duval			fAllocatedPos, fWaiting);
395a1b0ec30SJérôme Duval	}
396a1b0ec30SJérôme Duval
397a1b0ec30SJérôme Duval	fAllocated--;
398d8772e0cSJérôme Duval	blockNum = (uint32)fAllocatedPos++;
399a1b0ec30SJérôme Duval
400a1b0ec30SJérôme Duval	return B_OK;
401a1b0ec30SJérôme Duval}
402a1b0ec30SJérôme Duval
403a1b0ec30SJérôme Duval
404a1b0ec30SJérôme Duvalstatus_t
405a1b0ec30SJérôme DuvalDataStream::_PrepareBlock(Transaction& transaction, uint32* pos,
406a1b0ec30SJérôme Duval	uint32& blockNum, bool& clear)
407a1b0ec30SJérôme Duval{
408a1b0ec30SJérôme Duval	blockNum = B_LENDIAN_TO_HOST_INT32(*pos);
409a1b0ec30SJérôme Duval	clear = false;
410a1b0ec30SJérôme Duval
411a1b0ec30SJérôme Duval	if (blockNum == 0) {
412a1b0ec30SJérôme Duval		status_t status = _GetBlock(transaction, blockNum);
413d8772e0cSJérôme Duval		if (status != B_OK) {
414a130bab3SJérôme Duval			ERROR("DataStream::_PrepareBlock() _GetBlock() failed blockNum %"
415a130bab3SJérôme Duval				B_PRIu32 "\n", blockNum);
416a1b0ec30SJérôme Duval			return status;
417d8772e0cSJérôme Duval		}
418a1b0ec30SJérôme Duval
419a1b0ec30SJérôme Duval		*pos = B_HOST_TO_LENDIAN_INT32(blockNum);
420a1b0ec30SJérôme Duval		clear = true;
421a1b0ec30SJérôme Duval	}
422a1b0ec30SJérôme Duval
423a1b0ec30SJérôme Duval	return B_OK;
424a1b0ec30SJérôme Duval}
425a1b0ec30SJérôme Duval
426a1b0ec30SJérôme Duval
427a1b0ec30SJérôme Duvalstatus_t
428d8772e0cSJérôme DuvalDataStream::_AddBlocks(Transaction& transaction, uint32* block, off_t _count)
429a1b0ec30SJérôme Duval{
430d8772e0cSJérôme Duval	off_t count = _count;
431a130bab3SJérôme Duval	TRACE("DataStream::_AddBlocks(): count: %" B_PRIdOFF "\n", count);
432a1b0ec30SJérôme Duval
433a1b0ec30SJérôme Duval	while (count > 0) {
434a1b0ec30SJérôme Duval		uint32 blockNum;
435a1b0ec30SJérôme Duval		status_t status = _GetBlock(transaction, blockNum);
436a1b0ec30SJérôme Duval		if