xref: /haiku/src/add-ons/kernel/file_systems/ext2/DataStream.cpp (revision 45af882d0698d575ec1b4883a8ebff276c9519d8)
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 Duval DataStream::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 Duval DataStream::~DataStream()
51a1b0ec30SJérôme Duval {
52a1b0ec30SJérôme Duval }
53a1b0ec30SJérôme Duval 
54a1b0ec30SJérôme Duval 
55a1b0ec30SJérôme Duval status_t
56*45af882dSJérôme Duval DataStream::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
1699637baaeSJérôme Duval 		dprintf("ext2: block outside datastream!\n");
1709637baaeSJérôme Duval 		return B_ERROR;
1719637baaeSJérôme Duval 	}
1729637baaeSJérôme Duval 
1739637baaeSJérôme Duval 	TRACE("inode %Ld: FindBlock(offset %lld): %lld %ld\n", ID(), offset, block,
1749637baaeSJérôme Duval 		_count != NULL ? *_count : 1);
1759637baaeSJérôme Duval 	return B_OK;
1769637baaeSJérôme Duval }
1779637baaeSJérôme Duval 
1789637baaeSJérôme Duval 
1799637baaeSJérôme Duval status_t
180d8772e0cSJérôme Duval DataStream::Enlarge(Transaction& transaction, off_t& numBlocks)
181a1b0ec30SJérôme Duval {
182d8772e0cSJérôme Duval 	TRACE("DataStream::Enlarge(): current size: %llu, target size: %llu\n",
183a1b0ec30SJérôme Duval 		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 
199d8772e0cSJérôme Duval 		TRACE("DataStream::Enlarge(): current size: %llu, target size: %llu\n",
200a1b0ec30SJérôme Duval 			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 
206d8772e0cSJérôme Duval 	TRACE("DataStream::Enlarge(): indirect current size: %llu, target size: %llu\n",
207d8772e0cSJérôme Duval 		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 
217d8772e0cSJérôme Duval 		TRACE("DataStream::Enlarge(): current size: %llu, target size: %llu\n",
218a1b0ec30SJérôme Duval 			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 
224d8772e0cSJérôme Duval 	TRACE("DataStream::Enlarge(): indirect2 current size: %llu, target size: %llu\n",
225d8772e0cSJérôme Duval 		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 
235d8772e0cSJérôme Duval 		TRACE("DataStream::Enlarge(): current size: %llu, target size: %llu\n",
236a1b0ec30SJérôme Duval 			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 
242d8772e0cSJérôme Duval 	TRACE("DataStream::Enlarge(): indirect3 current size: %llu, target size: %llu\n",
243d8772e0cSJérôme Duval 		fNumBlocks, targetBlocks);
244d8772e0cSJérôme Duval 
245a1b0ec30SJérôme Duval 	TRACE("DataStream::Enlarge(): allocated: %lu, waiting: %lu\n", fAllocated,
246a1b0ec30SJérôme Duval 		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 Duval status_t
253d8772e0cSJérôme Duval DataStream::Shrink(Transaction& transaction, off_t& numBlocks)
254a1b0ec30SJérôme Duval {
255d8772e0cSJérôme Duval 	TRACE("DataStream::Shrink(): current size: %llu, target size: %llu\n",
256a1b0ec30SJérôme Duval 		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 Duval uint32
330d8772e0cSJérôme Duval DataStream::_BlocksNeeded(off_t numBlocks)
331a1b0ec30SJérôme Duval {
332d8772e0cSJérôme Duval 	TRACE("DataStream::BlocksNeeded(): num blocks %llu\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 
366d8772e0cSJérôme Duval 	TRACE("DataStream::BlocksNeeded(): %llu\n", blocksNeeded);
367a1b0ec30SJérôme Duval 	return blocksNeeded;
368a1b0ec30SJérôme Duval }
369a1b0ec30SJérôme Duval 
370a1b0ec30SJérôme Duval 
371a1b0ec30SJérôme Duval status_t
372d8772e0cSJérôme Duval DataStream::_GetBlock(Transaction& transaction, uint32& blockNum)
373a1b0ec30SJérôme Duval {
374d8772e0cSJérôme Duval 	TRACE("DataStream::_GetBlock(): allocated: %lu, pos: %llu, waiting: %lu\n",
375a1b0ec30SJérôme Duval 		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();
380a1b0ec30SJé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 		}
387a1b0ec30SJérôme Duval 
388a1b0ec30SJérôme Duval 		fWaiting -= fAllocated;
389de66992bSJérôme Duval 
390d8772e0cSJérôme Duval 		TRACE("DataStream::_GetBlock(): newAllocated: %lu, newpos: %llu,"
391de66992bSJérôme Duval 			"newwaiting: %lu\n", fAllocated, fAllocatedPos, fWaiting);
392a1b0ec30SJérôme Duval 	}
393a1b0ec30SJérôme Duval 
394a1b0ec30SJérôme Duval 	fAllocated--;
395d8772e0cSJérôme Duval 	blockNum = (uint32)fAllocatedPos++;
396a1b0ec30SJérôme Duval 
397a1b0ec30SJérôme Duval 	return B_OK;
398a1b0ec30SJérôme Duval }
399a1b0ec30SJérôme Duval 
400a1b0ec30SJérôme Duval 
401a1b0ec30SJérôme Duval status_t
402a1b0ec30SJérôme Duval DataStream::_PrepareBlock(Transaction& transaction, uint32* pos,
403a1b0ec30SJérôme Duval 	uint32& blockNum, bool& clear)
404a1b0ec30SJérôme Duval {
405a1b0ec30SJérôme Duval 	blockNum = B_LENDIAN_TO_HOST_INT32(*pos);
406a1b0ec30SJérôme Duval 	clear = false;
407a1b0ec30SJérôme Duval 
408a1b0ec30SJérôme Duval 	if (blockNum == 0) {
409a1b0ec30SJérôme Duval 		status_t status = _GetBlock(transaction, blockNum);
410d8772e0cSJérôme Duval 		if (status != B_OK) {
411d8772e0cSJérôme Duval 			ERROR("DataStream::_PrepareBlock() _GetBlock() failed blockNum %ld\n", blockNum);
412a1b0ec30SJérôme Duval 			return status;
413d8772e0cSJérôme Duval 		}
414a1b0ec30SJérôme Duval 
415a1b0ec30SJérôme Duval 		*pos = B_HOST_TO_LENDIAN_INT32(blockNum);
416a1b0ec30SJérôme Duval 		clear = true;
417a1b0ec30SJérôme Duval 	}
418a1b0ec30SJérôme Duval 
419a1b0ec30SJérôme Duval 	return B_OK;
420a1b0ec30SJérôme Duval }
421a1b0ec30SJérôme Duval 
422a1b0ec30SJérôme Duval 
423a1b0ec30SJérôme Duval status_t
424d8772e0cSJérôme Duval DataStream::_AddBlocks(Transaction& transaction, uint32* block, off_t _count)
425a1b0ec30SJérôme Duval {
426d8772e0cSJérôme Duval 	off_t count = _count;
427d8772e0cSJérôme Duval 	TRACE("DataStream::_AddBlocks(): count: %llu\n", count);
428a1b0ec30SJérôme Duval 
429a1b0ec30SJérôme Duval 	while (count > 0) {
430a1b0ec30SJérôme Duval 		uint32 blockNum;
431a1b0ec30SJérôme Duval 		status_t status = _GetBlock(transaction, blockNum);
432a1b0ec30SJérôme Duval 		if (status != B_OK)
433a1b0ec30SJérôme Duval 			return status;
434a1b0ec30SJérôme Duval 
435a1b0ec30SJérôme Duval 		*(block++) = B_HOST_TO_LENDIAN_INT32(blockNum);
436a1b0ec30SJérôme Duval 		--count;
437a1b0ec30SJérôme Duval 	}
438a1b0ec30SJérôme Duval 
439a1b0ec30SJérôme Duval 	fNumBlocks += _count;
440a1b0ec30SJérôme Duval 
441a1b0ec30SJérôme Duval 	return B_OK;
442a1b0ec30SJérôme Duval }
443a1b0ec30SJérôme Duval 
444a1b0ec30SJérôme Duval 
445a1b0ec30SJérôme Duval status_t
446d8772e0cSJérôme Duval DataStream::_AddBlocks(Transaction& transaction, uint32* block, off_t start,
447d8772e0cSJérôme Duval 	off_t end, int recursion)
448a1b0ec30SJérôme Duval {
449d8772e0cSJérôme Duval 	TRACE("DataStream::_AddBlocks(): start: %llu, end %llu, recursion: %d\n",
450a1b0ec30SJérôme Duval 		start, end, recursion);
451a1b0ec30SJérôme Duval 
452a1b0ec30SJérôme Duval 	bool clear;
453a1b0ec30SJérôme Duval 	uint32 blockNum;
454a1b0ec30SJérôme Duval 	status_t status = _PrepareBlock(transaction, block, blockNum, clear);
455a1b0ec30SJérôme Duval 	if (status != B_OK)
456a1b0ec30SJérôme Duval 		return status;
457a1b0ec30SJérôme Duval 
458a1b0ec30SJérôme Duval 	CachedBlock cached(fVolume);
459a1b0ec30SJérôme Duval 	uint32* childBlock = (uint32*)cached.SetToWritable(transaction, blockNum,
460a1b0ec30SJérôme Duval 		clear);
461a1b0ec30SJérôme Duval 	if (childBlock == NULL)
462a1b0ec30SJérôme Duval 		return B_IO_ERROR;
463a1b0ec30SJérôme Duval 
464a1b0ec30SJérôme Duval 	if (recursion == 0)
465a1b0ec30SJérôme Duval 		return _AddBlocks(transaction, &childBlock[start], end - start);
466a1b0ec30SJérôme Duval 
467a1b0ec30SJérôme Duval 	uint32 elementWidth;
468a1b0ec30SJérôme Duval 	if (recursion == 1)
469a1b0ec30SJérôme Duval 		elementWidth = kIndirectsPerBlock;
470a1b0ec30SJérôme Duval 	else if (recursion == 2)
471a1b0ec30SJérôme Duval 		elementWidth = kIndirectsPerBlock2;
472a1b0ec30SJérôme Duval 	else {
473de66992bSJérôme Duval 		panic("Undefined recursion level\n");
474a1b0ec30SJérôme Duval 		elementWidth = 0;
475a1b0ec30SJérôme Duval 	}
476a1b0ec30SJérôme Duval 
477a1b0ec30SJérôme Duval 	uint32 elementPos = start / elementWidth;
478a1b0ec30SJérôme Duval 	uint32 endPos = end / elementWidth;
479a1b0ec30SJérôme Duval 
480a1b0ec30SJérôme Duval 	TRACE("DataStream::_AddBlocks(): element pos: %lu, end pos: %lu\n",
481a1b0ec30SJérôme Duval 		elementPos, endPos);
482a1b0ec30SJérôme Duval 
483a1b0ec30SJérôme Duval 	recursion--;
484a1b0ec30SJérôme Duval 
485a1b0ec30SJérôme Duval 	if (elementPos == endPos) {
486a1b0ec30SJérôme Duval 		return _AddBlocks(transaction, &childBlock[elementPos],
487a1b0ec30SJérôme Duval 			start % elementWidth, end % elementWidth, recursion);
488a1b0ec30SJérôme Duval 	}
489a1b0ec30SJérôme Duval 
490a1b0ec30SJérôme Duval 	if (start % elementWidth != 0) {
491a1b0ec30SJérôme Duval 		status = _AddBlocks(transaction, &childBlock[elementPos],
492a1b0ec30SJérôme Duval 			start % elementWidth, elementWidth, recursion);
493d8772e0cSJérôme Duval 		if (status != B_OK) {
494d8772e0cSJérôme Duval 			ERROR("DataStream::_AddBlocks() _AddBlocks() start failed\n");
495a1b0ec30SJérôme Duval 			return status;
496d8772e0cSJérôme Duval 		}
497a1b0ec30SJérôme Duval 
498a1b0ec30SJérôme Duval 		elementPos++;
499a1b0ec30SJérôme Duval 	}
500a1b0ec30SJérôme Duval 
501a1b0ec30SJérôme Duval 	while (elementPos < endPos) {
502a1b0ec30SJérôme Duval 		status = _AddBlocks(transaction, &childBlock[elementPos], 0,
503a1b0ec30SJérôme Duval 			elementWidth, recursion);
504d8772e0cSJérôme Duval 		if (status != B_OK) {
505d8772e0cSJérôme Duval 			ERROR("DataStream::_AddBlocks() _AddBlocks() mid failed\n");
506a1b0ec30SJérôme Duval 			return status;
507d8772e0cSJérôme Duval 		}
508a1b0ec30SJérôme Duval 
509a1b0ec30SJérôme Duval 		elementPos++;
510a1b0ec30SJérôme Duval 	}
511a1b0ec30SJérôme Duval 
512a1b0ec30SJérôme Duval 	if (end % elementWidth != 0) {
513a1b0ec30SJérôme Duval 		status = _AddBlocks(transaction, &childBlock[elementPos], 0,
514a1b0ec30SJérôme Duval 			end % elementWidth, recursion);
515d8772e0cSJérôme Duval 		if (status != B_OK) {
516d8772e0cSJérôme Duval 			ERROR("DataStream::_AddBlocks() _AddBlocks() end failed\n");
517a1b0ec30SJérôme Duval 			return status;
518a1b0ec30SJérôme Duval 		}
519d8772e0cSJérôme Duval 	}
520a1b0ec30SJérôme Duval 
521a1b0ec30SJérôme Duval 	return B_OK;
522a1b0ec30SJérôme Duval }
523a1b0ec30SJérôme Duval 
524a1b0ec30SJérôme Duval 
525a1b0ec30SJérôme Duval status_t
526a1b0ec30SJérôme Duval DataStream::_AddForDirectBlocks(Transaction& transaction, uint32 numBlocks)
527a1b0ec30SJérôme Duval {
528d8772e0cSJérôme Duval 	TRACE("DataStream::_AddForDirectBlocks(): current size: %llu, target size: "
529a1b0ec30SJérôme Duval 		"%lu\n", fNumBlocks, numBlocks);
530a1b0ec30SJérôme Duval 	uint32* direct = &fStream->direct[fNumBlocks];
531a1b0ec30SJérôme Duval 	uint32 end = numBlocks > kMaxDirect ? kMaxDirect : numBlocks;
532a1b0ec30SJérôme Duval 
533a1b0ec30SJérôme Duval 	return _AddBlocks(transaction, direct, end - fNumBlocks);
534a1b0ec30SJérôme Duval }
535a1b0ec30SJérôme Duval 
536a1b0ec30SJérôme Duval 
537a1b0ec30SJérôme Duval status_t
538a1b0ec30SJérôme Duval DataStream::_AddForIndirectBlock(Transaction& transaction, uint32 numBlocks)
539a1b0ec30SJérôme Duval {
540d8772e0cSJérôme Duval 	TRACE("DataStream::_AddForIndirectBlocks(): current size: %llu, target "
541a1b0ec30SJérôme Duval 		"size: %lu\n", fNumBlocks, numBlocks);
542a1b0ec30SJérôme Duval 	uint32 *indirect = &fStream->indirect;
543a1b0ec30SJérôme Duval 	uint32 start = fNumBlocks - kMaxDirect;
544a1b0ec30SJérôme Duval 	uint32 end = numBlocks - kMaxDirect;
545a1b0ec30SJérôme Duval 
546a1b0ec30SJérôme Duval 	if (end > kIndirectsPerBlock)
547a1b0ec30SJérôme Duval 		end = kIndirectsPerBlock;
548a1b0ec30SJérôme Duval 
549a1b0ec30SJérôme Duval 	return _AddBlocks(transaction, indirect, start, end, 0);
550a1b0ec30SJérôme Duval }
551a1b0ec30SJérôme Duval 
552a1b0ec30SJérôme Duval 
553a1b0ec30SJérôme Duval status_t
554a1b0ec30SJérôme Duval DataStream::_AddForDoubleIndirectBlock(Transaction& transaction,
555a1b0ec30SJérôme Duval 	uint32 numBlocks)
556a1b0ec30SJérôme Duval {
557d8772e0cSJérôme Duval 	TRACE("DataStream::_AddForDoubleIndirectBlock(): current size: %llu, "
558a1b0ec30SJérôme Duval 		"target size: %lu\n", fNumBlocks, numBlocks);
559a1b0ec30SJérôme Duval 	uint32 *doubleIndirect = &fStream->double_indirect;
560a1b0ec30SJérôme Duval 	uint32 start = fNumBlocks - kMaxIndirect;
561a1b0ec30SJérôme Duval 	uint32 end = numBlocks - kMaxIndirect;
562a1b0ec30SJérôme Duval 
563a1b0ec30SJérôme Duval 	if (end > kIndirectsPerBlock2)
564a1b0ec30SJérôme Duval 		end = kIndirectsPerBlock2;
565a1b0ec30SJérôme Duval 
566a1b0ec30SJérôme Duval 	return _AddBlocks(transaction, doubleIndirect, start, end, 1);
567a1b0ec30SJérôme Duval }
568a1b0ec30SJérôme Duval 
569a1b0ec30SJérôme Duval 
570a1b0ec30SJérôme Duval status_t
571a1b0ec30SJérôme Duval DataStream::_AddForTripleIndirectBlock(Transaction& transaction,
572a1b0ec30SJérôme Duval 	uint32 numBlocks)
573a1b0ec30SJérôme Duval {
574d8772e0cSJérôme Duval 	TRACE("DataStream::_AddForTripleIndirectBlock(): current size: %llu, "
575a1b0ec30SJérôme Duval 		"target size: %lu\n", fNumBlocks, numBlocks);
576a1b0ec30SJérôme Duval 	uint32 *tripleIndirect = &fStream->triple_indirect;
577a1b0ec30SJérôme Duval 	uint32 start = fNumBlocks - kMaxDoubleIndirect;
578a1b0ec30SJérôme Duval 	uint32 end = numBlocks - kMaxDoubleIndirect;
579a1b0ec30SJérôme Duval 
580a1b0ec30SJérôme Duval 	return _AddBlocks(transaction, tripleIndirect, start, end, 2);
581a1b0ec30SJérôme Duval }
582a1b0ec30SJérôme Duval 
583a1b0ec30SJérôme Duval 
584a1b0ec30SJérôme Duval status_t
585a1b0ec30SJérôme Duval DataStream::_PerformFree(Transaction& transaction)
586a1b0ec30SJérôme Duval {
587a1b0ec30SJérôme Duval 	TRACE("DataStream::_PerformFree(): start: %lu, count: %lu\n", fFreeStart,
588a1b0ec30SJérôme Duval 		fFreeCount);
589a1b0ec30SJérôme Duval 	status_t status;
590a1b0ec30SJérôme Duval 
591a1b0ec30SJérôme Duval 	if (fFreeCount == 0)
592a1b0ec30SJérôme Duval 		status = B_OK;
593a1b0ec30SJérôme Duval 	else
594a1b0ec30SJérôme Duval 		status = fVolume->FreeBlocks(transaction, fFreeStart, fFreeCount);
595a1b0ec30SJérôme Duval 
596a1b0ec30SJérôme Duval 	fFreeStart = 0;
597a1b0ec30SJérôme Duval 	fFreeCount = 0;
598a1b0ec30SJérôme Duval 
599a1b0ec30SJérôme Duval 	return status;
600a1b0ec30SJérôme Duval }
601a1b0ec30SJérôme Duval 
602a1b0ec30SJérôme Duval 
603a1b0ec30SJérôme Duval status_t
604a1b0ec30SJérôme Duval DataStream::_MarkBlockForRemoval(Transaction& transaction, uint32* block)
605a1b0ec30SJérôme Duval {
606d8772e0cSJérôme Duval 
607a1b0ec30SJérôme Duval 	TRACE("DataStream::_MarkBlockForRemoval(*(%p) = %lu): free start: %lu, "
608d8772e0cSJérôme Duval 		"free count: %lu\n", block, B_LENDIAN_TO_HOST_INT32(*block),
609d8772e0cSJérôme Duval 		fFreeStart, fFreeCount);
610a1b0ec30SJérôme Duval 	uint32 blockNum = B_LENDIAN_TO_HOST_INT32(*block);
611a1b0ec30SJérôme Duval 	*block = 0;
612a1b0ec30SJérôme Duval 
613a1b0ec30SJérôme Duval 	if (blockNum != fFreeStart + fFreeCount) {
614a1b0ec30SJérôme Duval 		if (fFreeCount != 0) {
615a1b0ec30SJérôme Duval 			status_t status = fVolume->FreeBlocks(transaction, fFreeStart,
616a1b0ec30SJérôme Duval 				fFreeCount);
617a1b0ec30SJérôme Duval 			if (status != B_OK)
618a1b0ec30SJérôme Duval 				return status;
619a1b0ec30SJérôme Duval 		}
620a1b0ec30SJérôme Duval 
621a1b0ec30SJérôme Duval 		fFreeStart = blockNum;
622a1b0ec30SJérôme Duval 		fFreeCount = 0;
623a1b0ec30SJérôme Duval 	}
624a1b0ec30SJérôme Duval 
625a1b0ec30SJérôme Duval 	fFreeCount++;
626a1b0ec30SJérôme Duval 
627a1b0ec30SJérôme Duval 	return B_OK;
628a1b0ec30SJérôme Duval }
629a1b0ec30SJérôme Duval 
630a1b0ec30SJérôme Duval 
631a1b0ec30SJérôme Duval status_t
632a1b0ec30SJérôme Duval DataStream::_FreeBlocks(Transaction& transaction, uint32* block, uint32 _count)
633a1b0ec30SJérôme Duval {
634a1b0ec30SJérôme Duval 	uint32 count = _count;
635a1b0ec30SJérôme Duval 	TRACE("DataStream::_FreeBlocks(%p, %lu)\n", block, count);
636a1b0ec30SJérôme Duval 
637a1b0ec30SJérôme Duval 	while (count > 0) {
638a1b0ec30SJérôme Duval 		status_t status = _MarkBlockForRemoval(transaction, block);
639a1b0ec30SJérôme Duval 		if (status != B_OK)
640a1b0ec30SJérôme Duval 			return status;
641a1b0ec30SJérôme Duval 
642a1b0ec30SJérôme Duval 		block++;
643a1b0ec30SJérôme Duval 		count--;
644a1b0ec30SJérôme Duval 	}
645a1b0ec30SJérôme Duval 
646a1b0ec30SJérôme Duval 	fRemovedBlocks += _count;
647a1b0ec30SJérôme Duval 
648a1b0ec30SJérôme Duval 	return B_OK;
649a1b0ec30SJérôme Duval }
650a1b0ec30SJérôme Duval 
651a1b0ec30SJérôme Duval 
652a1b0ec30SJérôme Duval status_t
653d8772e0cSJérôme Duval DataStream::_FreeBlocks(Transaction& transaction, uint32* block, off_t start,
654d8772e0cSJérôme Duval 	off_t end, bool freeParent, int recursion)
655a1b0ec30SJérôme Duval {
656a1b0ec30SJérôme Duval 	// TODO: Designed specifically for shrinking. Perhaps make it more general?
657d8772e0cSJérôme Duval 	TRACE("DataStream::_FreeBlocks(%p, %llu, %llu, %c, %d)\n",
658a1b0ec30SJérôme Duval 		block, start, end, freeParent ? 't' : 'f', recursion);
659a1b0ec30SJérôme Duval 
660a1b0ec30SJérôme Duval 	uint32 blockNum = B_LENDIAN_TO_HOST_INT32(*block);
661a1b0ec30SJérôme Duval 
662a1b0ec30SJérôme Duval 	if (freeParent) {
663a1b0ec30SJérôme Duval 		status_t status = _MarkBlockForRemoval(transaction, block);
664a1b0ec30SJérôme Duval 		if (status != B_OK)
665a1b0ec30SJérôme Duval 			return status;
666a1b0ec30SJérôme Duval 	}
667a1b0ec30SJérôme Duval 
668a1b0ec30SJérôme Duval 	CachedBlock cached(fVolume);
669a1b0ec30SJérôme Duval 	uint32* childBlock = (uint32*)cached.SetToWritable(transaction, blockNum);
670a1b0ec30SJérôme Duval 	if (childBlock == NULL)
671a1b0ec30SJérôme Duval 		return B_IO_ERROR;
672a1b0ec30SJérôme Duval 
673a1b0ec30SJérôme Duval 	if (recursion == 0)
674a1b0ec30SJérôme Duval 		return _FreeBlocks(transaction, &childBlock[start], end - start);
675a1b0ec30SJérôme Duval 
676a1b0ec30SJérôme Duval 	uint32 elementWidth;
677a1b0ec30SJérôme Duval 	if (recursion == 1)
678a1b0ec30SJérôme Duval 		elementWidth = kIndirectsPerBlock;
679a1b0ec30SJérôme Duval 	else if (recursion == 2)
680a1b0ec30SJérôme Duval 		elementWidth = kIndirectsPerBlock2;
681a1b0ec30SJérôme Duval 	else {
682a1b0ec30SJérôme Duval 		panic("Undefinied recursion level\n");
683a1b0ec30SJérôme Duval 		elementWidth = 0;
684a1b0ec30SJérôme Duval 	}
685a1b0ec30SJérôme Duval 
686a1b0ec30SJérôme Duval 	uint32 elementPos = start / elementWidth;
687a1b0ec30SJérôme Duval 	uint32 endPos = end / elementWidth;
688a1b0ec30SJérôme Duval 
689a1b0ec30SJérôme Duval 	recursion--;
690a1b0ec30SJérôme Duval 
691a1b0ec30SJérôme Duval 	if (elementPos == endPos) {
692a1b0ec30SJérôme Duval 		bool free = freeParent || start % elementWidth == 0;
693a1b0ec30SJérôme Duval 		return _FreeBlocks(transaction, &childBlock[elementPos],
694a1b0ec30SJérôme Duval 			start % elementWidth, end % elementWidth, free, recursion);
695a1b0ec30SJérôme Duval 	}
696a1b0ec30SJérôme Duval 
697a1b0ec30SJérôme Duval 	status_t status = B_OK;
698a1b0ec30SJérôme Duval 
699a1b0ec30SJérôme Duval 	if (start % elementWidth != 0) {
700a1b0ec30SJérôme Duval 		status = _FreeBlocks(transaction, &childBlock[elementPos],
701a1b0ec30SJérôme Duval 			start % elementWidth, elementWidth, false, recursion);
702a1b0ec30SJérôme Duval 		if (status != B_OK)
703a1b0ec30SJérôme Duval 			return status;
704a1b0ec30SJérôme Duval 
705a1b0ec30SJérôme Duval 		elementPos++;
706a1b0ec30SJérôme Duval 	}
707a1b0ec30SJérôme Duval 
708a1b0ec30SJérôme Duval 	while (elementPos < endPos) {
709a1b0ec30SJérôme Duval 		status = _FreeBlocks(transaction, &childBlock[elementPos], 0,
710a1b0ec30SJérôme Duval 			elementWidth, true, recursion);
711a1b0ec30SJérôme Duval 		if (status != B_OK)
712a1b0ec30SJérôme Duval 			return status;
713a1b0ec30SJérôme Duval 
714a1b0ec30SJérôme Duval 		elementPos++;
715a1b0ec30SJérôme Duval 	}
716a1b0ec30SJérôme Duval 
717a1b0ec30SJérôme Duval 	if (end % elementWidth != 0) {
718a1b0ec30SJérôme Duval 		status = _FreeBlocks(transaction, &childBlock[elementPos], 0,
719a1b0ec30SJérôme Duval 			end % elementWidth, true, recursion);
720a1b0ec30SJérôme Duval 	}
721a1b0ec30SJérôme Duval 
722a1b0ec30SJérôme Duval 	return status;
723a1b0ec30SJérôme Duval }
724a1b0ec30SJérôme Duval 
725a1b0ec30SJérôme Duval 
726a1b0ec30SJérôme Duval status_t
727a1b0ec30SJérôme Duval DataStream::_RemoveFromDirectBlocks(Transaction& transaction, uint32 numBlocks)
728a1b0ec30SJérôme Duval {
729d8772e0cSJérôme Duval 	TRACE("DataStream::_RemoveFromDirectBlocks(): current size: %llu, "
730a1b0ec30SJérôme Duval 		"target size: %lu\n", fNumBlocks, numBlocks);
731a1b0ec30SJérôme Duval 	uint32* direct = &fStream->direct[numBlocks];
732d8772e0cSJérôme Duval 	off_t end = fNumBlocks > kMaxDirect ? kMaxDirect : fNumBlocks;
733a1b0ec30SJérôme Duval 
734a1b0ec30SJérôme Duval 	return _FreeBlocks(transaction, direct, end - numBlocks);
735a1b0ec30SJérôme Duval }
736a1b0ec30SJérôme Duval 
737a1b0ec30SJérôme Duval 
738a1b0ec30SJérôme Duval status_t
739a1b0ec30SJérôme Duval DataStream::_RemoveFromIndirectBlock(Transaction& transaction, uint32 numBlocks)
740a1b0ec30SJérôme Duval {
741d8772e0cSJérôme Duval 	TRACE("DataStream::_RemoveFromIndirectBlock(): current size: %llu, "
742a1b0ec30SJérôme Duval 		"target size: %lu\n", fNumBlocks, numBlocks);
743a1b0ec30SJérôme Duval 	uint32* indirect = &fStream->indirect;
744d8772e0cSJérôme Duval 	off_t start = numBlocks <= kMaxDirect ? 0 : numBlocks - kMaxDirect;
745d8772e0cSJérôme Duval 	off_t end = fNumBlocks - kMaxDirect;
746a1b0ec30SJérôme Duval 
747a1b0ec30SJérôme Duval 	if (end > kIndirectsPerBlock)
748a1b0ec30SJérôme Duval 		end = kIndirectsPerBlock;
749a1b0ec30SJérôme Duval 
750a1b0ec30SJérôme Duval 	bool freeAll = start == 0;
751a1b0ec30SJérôme Duval 
752a1b0ec30SJérôme Duval 	return _FreeBlocks(transaction, indirect, start, end, freeAll, 0);
753a1b0ec30SJérôme Duval }
754a1b0ec30SJérôme Duval 
755a1b0ec30SJérôme Duval 
756a1b0ec30SJérôme Duval status_t
757a1b0ec30SJérôme Duval DataStream::_RemoveFromDoubleIndirectBlock(Transaction& transaction,
758a1b0ec30SJérôme Duval 	uint32 numBlocks)
759a1b0ec30SJérôme Duval {
760d8772e0cSJérôme Duval 	TRACE("DataStream::_RemoveFromDoubleIndirectBlock(): current size: %llu, "
761a1b0ec30SJérôme Duval 		"target size: %lu\n", fNumBlocks, numBlocks);
762a1b0ec30SJérôme Duval 	uint32* doubleIndirect = &fStream->double_indirect;
763d8772e0cSJérôme Duval 	off_t start = numBlocks <= kMaxIndirect ? 0 : numBlocks - kMaxIndirect;
764d8772e0cSJérôme Duval 	off_t end = fNumBlocks - kMaxIndirect;
765a1b0ec30SJérôme Duval 
766a1b0ec30SJérôme Duval 	if (end > kIndirectsPerBlock2)
767a1b0ec30SJérôme Duval 		end = kIndirectsPerBlock2;
768a1b0ec30SJérôme Duval 
769a1b0ec30SJérôme Duval 	bool freeAll = start == 0;
770a1b0ec30SJérôme Duval 
771a1b0ec30SJérôme Duval 	return _FreeBlocks(transaction, doubleIndirect, start, end, freeAll, 1);
772a1b0ec30SJérôme Duval }
773a1b0ec30SJérôme Duval 
774a1b0ec30SJérôme Duval 
775a1b0ec30SJérôme Duval status_t
776a1b0ec30SJérôme Duval DataStream::_RemoveFromTripleIndirectBlock(Transaction& transaction,
777a1b0ec30SJérôme Duval 	uint32 numBlocks)
778a1b0ec30SJérôme Duval {
779d8772e0cSJérôme Duval 	TRACE("DataStream::_RemoveFromTripleIndirectBlock(): current size: %llu, "
780a1b0ec30SJérôme Duval 		"target size: %lu\n", fNumBlocks, numBlocks);
781a1b0ec30SJérôme Duval 	uint32* tripleIndirect = &fStream->triple_indirect;
782d8772e0cSJérôme Duval 	off_t start = numBlocks <= kMaxDoubleIndirect ? 0
783a1b0ec30SJérôme Duval 		: numBlocks - kMaxDoubleIndirect;
784d8772e0cSJérôme Duval 	off_t end = fNumBlocks - kMaxDoubleIndirect;
785a1b0ec30SJérôme Duval 
786a1b0ec30SJérôme Duval 	bool freeAll = start == 0;
787a1b0ec30SJérôme Duval 
788a1b0ec30SJérôme Duval 	return _FreeBlocks(transaction, tripleIndirect, start, end, freeAll, 2);
789a1b0ec30SJérôme Duval }
790