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
DataStream(Volume * volume,ext2_data_stream * stream,off_t size)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
~DataStream()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
FindBlock(off_t offset,fsblock_t & block,uint32 * _count)5645af882dSJé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
169*ce4e12caSJé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
1799637baaeSJérôme Duval status_t
Enlarge(Transaction & transaction,off_t & numBlocks)180d8772e0cSJérôme Duval DataStream::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 Duval status_t
Shrink(Transaction & transaction,off_t & numBlocks)253d8772e0cSJérôme Duval DataStream::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 Duval uint32
_BlocksNeeded(off_t numBlocks)330d8772e0cSJérôme Duval DataStream::_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 Duval status_t
_GetBlock(Transaction & transaction,uint32 & blockNum)372d8772e0cSJérôme Duval DataStream::_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();
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 }
387*ce4e12caSJérôme Duval if (fAllocatedPos > UINT_MAX)
388*ce4e12caSJé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 Duval status_t
_PrepareBlock(Transaction & transaction,uint32 * pos,uint32 & blockNum,bool & clear)405a1b0ec30SJérôme Duval DataStream::_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 Duval status_t
_AddBlocks(Transaction & transaction,uint32 * block,off_t _count)428d8772e0cSJérôme Duval DataStream::_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 (status != B_OK)
437a1b0ec30SJérôme Duval return status;
438a1b0ec30SJérôme Duval
439a1b0ec30SJérôme Duval *(block++) = B_HOST_TO_LENDIAN_INT32(blockNum);
440a1b0ec30SJérôme Duval --count;
441a1b0ec30SJérôme Duval }
442a1b0ec30SJérôme Duval
443a1b0ec30SJérôme Duval fNumBlocks += _count;
444a1b0ec30SJérôme Duval
445a1b0ec30SJérôme Duval return B_OK;
446a1b0ec30SJérôme Duval }
447a1b0ec30SJérôme Duval
448a1b0ec30SJérôme Duval
449a1b0ec30SJérôme Duval status_t
_AddBlocks(Transaction & transaction,uint32 * block,off_t start,off_t end,int recursion)450d8772e0cSJérôme Duval DataStream::_AddBlocks(Transaction& transaction, uint32* block, off_t start,
451d8772e0cSJérôme Duval off_t end, int recursion)
452a1b0ec30SJérôme Duval {
453a130bab3SJérôme Duval TRACE("DataStream::_AddBlocks(): start: %" B_PRIdOFF ", end %" B_PRIdOFF
454a130bab3SJérôme Duval ", recursion: %d\n", start, end, recursion);
455a1b0ec30SJérôme Duval
456a1b0ec30SJérôme Duval bool clear;
457a1b0ec30SJérôme Duval uint32 blockNum;
458a1b0ec30SJérôme Duval status_t status = _PrepareBlock(transaction, block, blockNum, clear);
459a1b0ec30SJérôme Duval if (status != B_OK)
460a1b0ec30SJérôme Duval return status;
461a1b0ec30SJérôme Duval
462a1b0ec30SJérôme Duval CachedBlock cached(fVolume);
463a1b0ec30SJérôme Duval uint32* childBlock = (uint32*)cached.SetToWritable(transaction, blockNum,
464a1b0ec30SJérôme Duval clear);
465a1b0ec30SJérôme Duval if (childBlock == NULL)
466a1b0ec30SJérôme Duval return B_IO_ERROR;
467a1b0ec30SJérôme Duval
468a1b0ec30SJérôme Duval if (recursion == 0)
469a1b0ec30SJérôme Duval return _AddBlocks(transaction, &childBlock[start], end - start);
470a1b0ec30SJérôme Duval
471a1b0ec30SJérôme Duval uint32 elementWidth;
472a1b0ec30SJérôme Duval if (recursion == 1)
473a1b0ec30SJérôme Duval elementWidth = kIndirectsPerBlock;
474a1b0ec30SJérôme Duval else if (recursion == 2)
475a1b0ec30SJérôme Duval elementWidth = kIndirectsPerBlock2;
476a1b0ec30SJérôme Duval else {
477de66992bSJérôme Duval panic("Undefined recursion level\n");
478a1b0ec30SJérôme Duval elementWidth = 0;
479a1b0ec30SJérôme Duval }
480a1b0ec30SJérôme Duval
481a1b0ec30SJérôme Duval uint32 elementPos = start / elementWidth;
482a1b0ec30SJérôme Duval uint32 endPos = end / elementWidth;
483a1b0ec30SJérôme Duval
484a130bab3SJérôme Duval TRACE("DataStream::_AddBlocks(): element pos: %" B_PRIu32 ", end pos: %"
485a130bab3SJérôme Duval B_PRIu32 "\n", elementPos, endPos);
486a1b0ec30SJérôme Duval
487a1b0ec30SJérôme Duval recursion--;
488a1b0ec30SJérôme Duval
489a1b0ec30SJérôme Duval if (elementPos == endPos) {
490a1b0ec30SJérôme Duval return _AddBlocks(transaction, &childBlock[elementPos],
491a1b0ec30SJérôme Duval start % elementWidth, end % elementWidth, recursion);
492a1b0ec30SJérôme Duval }
493a1b0ec30SJérôme Duval
494a1b0ec30SJérôme Duval if (start % elementWidth != 0) {
495a1b0ec30SJérôme Duval status = _AddBlocks(transaction, &childBlock[elementPos],
496a1b0ec30SJérôme Duval start % elementWidth, elementWidth, recursion);
497d8772e0cSJérôme Duval if (status != B_OK) {
498d8772e0cSJérôme Duval ERROR("DataStream::_AddBlocks() _AddBlocks() start failed\n");
499a1b0ec30SJérôme Duval return status;
500d8772e0cSJérôme Duval }
501a1b0ec30SJérôme Duval
502a1b0ec30SJérôme Duval elementPos++;
503a1b0ec30SJérôme Duval }
504a1b0ec30SJérôme Duval
505a1b0ec30SJérôme Duval while (elementPos < endPos) {
506a1b0ec30SJérôme Duval status = _AddBlocks(transaction, &childBlock[elementPos], 0,
507a1b0ec30SJérôme Duval elementWidth, recursion);
508d8772e0cSJérôme Duval if (status != B_OK) {
509d8772e0cSJérôme Duval ERROR("DataStream::_AddBlocks() _AddBlocks() mid failed\n");
510a1b0ec30SJérôme Duval return status;
511d8772e0cSJérôme Duval }
512a1b0ec30SJérôme Duval
513a1b0ec30SJérôme Duval elementPos++;
514a1b0ec30SJérôme Duval }
515a1b0ec30SJérôme Duval
516a1b0ec30SJérôme Duval if (end % elementWidth != 0) {
517a1b0ec30SJérôme Duval status = _AddBlocks(transaction, &childBlock[elementPos], 0,
518a1b0ec30SJérôme Duval end % elementWidth, recursion);
519d8772e0cSJérôme Duval if (status != B_OK) {
520d8772e0cSJérôme Duval ERROR("DataStream::_AddBlocks() _AddBlocks() end failed\n");
521a1b0ec30SJérôme Duval return status;
522a1b0ec30SJérôme Duval }
523d8772e0cSJérôme Duval }
524a1b0ec30SJérôme Duval
525a1b0ec30SJérôme Duval return B_OK;
526a1b0ec30SJérôme Duval }
527a1b0ec30SJérôme Duval
528a1b0ec30SJérôme Duval
529a1b0ec30SJérôme Duval status_t
_AddForDirectBlocks(Transaction & transaction,uint32 numBlocks)530a1b0ec30SJérôme Duval DataStream::_AddForDirectBlocks(Transaction& transaction, uint32 numBlocks)
531a1b0ec30SJérôme Duval {
532a130bab3SJérôme Duval TRACE("DataStream::_AddForDirectBlocks(): current size: %" B_PRIdOFF
533a130bab3SJérôme Duval ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks);
534a1b0ec30SJérôme Duval uint32* direct = &fStream->direct[fNumBlocks];
535a1b0ec30SJérôme Duval uint32 end = numBlocks > kMaxDirect ? kMaxDirect : numBlocks;
536a1b0ec30SJérôme Duval
537a1b0ec30SJérôme Duval return _AddBlocks(transaction, direct, end - fNumBlocks);
538a1b0ec30SJérôme Duval }
539a1b0ec30SJérôme Duval
540a1b0ec30SJérôme Duval
541a1b0ec30SJérôme Duval status_t
_AddForIndirectBlock(Transaction & transaction,uint32 numBlocks)542a1b0ec30SJérôme Duval DataStream::_AddForIndirectBlock(Transaction& transaction, uint32 numBlocks)
543a1b0ec30SJérôme Duval {
544a130bab3SJérôme Duval TRACE("DataStream::_AddForIndirectBlocks(): current size: %" B_PRIdOFF
545a130bab3SJérôme Duval ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks);
546a1b0ec30SJérôme Duval uint32 *indirect = &fStream->indirect;
547a1b0ec30SJérôme Duval uint32 start = fNumBlocks - kMaxDirect;
548a1b0ec30SJérôme Duval uint32 end = numBlocks - kMaxDirect;
549a1b0ec30SJérôme Duval
550a1b0ec30SJérôme Duval if (end > kIndirectsPerBlock)
551a1b0ec30SJérôme Duval end = kIndirectsPerBlock;
552a1b0ec30SJérôme Duval
553a1b0ec30SJérôme Duval return _AddBlocks(transaction, indirect, start, end, 0);
554a1b0ec30SJérôme Duval }
555a1b0ec30SJérôme Duval
556a1b0ec30SJérôme Duval
557a1b0ec30SJérôme Duval status_t
_AddForDoubleIndirectBlock(Transaction & transaction,uint32 numBlocks)558a1b0ec30SJérôme Duval DataStream::_AddForDoubleIndirectBlock(Transaction& transaction,
559a1b0ec30SJérôme Duval uint32 numBlocks)
560a1b0ec30SJérôme Duval {
561a130bab3SJérôme Duval TRACE("DataStream::_AddForDoubleIndirectBlock(): current size: %" B_PRIdOFF
562a130bab3SJérôme Duval ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks);
563a1b0ec30SJérôme Duval uint32 *doubleIndirect = &fStream->double_indirect;
564a1b0ec30SJérôme Duval uint32 start = fNumBlocks - kMaxIndirect;
565a1b0ec30SJérôme Duval uint32 end = numBlocks - kMaxIndirect;
566a1b0ec30SJérôme Duval
567a1b0ec30SJérôme Duval if (end > kIndirectsPerBlock2)
568a1b0ec30SJérôme Duval end = kIndirectsPerBlock2;
569a1b0ec30SJérôme Duval
570a1b0ec30SJérôme Duval return _AddBlocks(transaction, doubleIndirect, start, end, 1);
571a1b0ec30SJérôme Duval }
572a1b0ec30SJérôme Duval
573a1b0ec30SJérôme Duval
574a1b0ec30SJérôme Duval status_t
_AddForTripleIndirectBlock(Transaction & transaction,uint32 numBlocks)575a1b0ec30SJérôme Duval DataStream::_AddForTripleIndirectBlock(Transaction& transaction,
576a1b0ec30SJérôme Duval uint32 numBlocks)
577a1b0ec30SJérôme Duval {
578a130bab3SJérôme Duval TRACE("DataStream::_AddForTripleIndirectBlock(): current size: %" B_PRIdOFF
579a130bab3SJérôme Duval ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks);
580a1b0ec30SJérôme Duval uint32 *tripleIndirect = &fStream->triple_indirect;
581a1b0ec30SJérôme Duval uint32 start = fNumBlocks - kMaxDoubleIndirect;
582a1b0ec30SJérôme Duval uint32 end = numBlocks - kMaxDoubleIndirect;
583a1b0ec30SJérôme Duval
584a1b0ec30SJérôme Duval return _AddBlocks(transaction, tripleIndirect, start, end, 2);
585a1b0ec30SJérôme Duval }
586a1b0ec30SJérôme Duval
587a1b0ec30SJérôme Duval
588a1b0ec30SJérôme Duval status_t
_PerformFree(Transaction & transaction)589a1b0ec30SJérôme Duval DataStream::_PerformFree(Transaction& transaction)
590a1b0ec30SJérôme Duval {
591a130bab3SJérôme Duval TRACE("DataStream::_PerformFree(): start: %" B_PRIu32 ", count: %" B_PRIu32
592a130bab3SJérôme Duval "\n", fFreeStart, fFreeCount);
593a1b0ec30SJérôme Duval status_t status;
594a1b0ec30SJérôme Duval
595a1b0ec30SJérôme Duval if (fFreeCount == 0)
596a1b0ec30SJérôme Duval status = B_OK;
597a1b0ec30SJérôme Duval else
598a1b0ec30SJérôme Duval status = fVolume->FreeBlocks(transaction, fFreeStart, fFreeCount);
599a1b0ec30SJérôme Duval
600a1b0ec30SJérôme Duval fFreeStart = 0;
601a1b0ec30SJérôme Duval fFreeCount = 0;
602a1b0ec30SJérôme Duval
603a1b0ec30SJérôme Duval return status;
604a1b0ec30SJérôme Duval }
605a1b0ec30SJérôme Duval
606a1b0ec30SJérôme Duval
607a1b0ec30SJérôme Duval status_t
_MarkBlockForRemoval(Transaction & transaction,uint32 * block)608a1b0ec30SJérôme Duval DataStream::_MarkBlockForRemoval(Transaction& transaction, uint32* block)
609a1b0ec30SJérôme Duval {
610d8772e0cSJérôme Duval
611a130bab3SJérôme Duval TRACE("DataStream::_MarkBlockForRemoval(*(%p) = %" B_PRIu32
612a130bab3SJérôme Duval "): free start: %" B_PRIu32 ", free count: %" B_PRIu32 "\n", block,
613a130bab3SJérôme Duval B_LENDIAN_TO_HOST_INT32(*block), fFreeStart, fFreeCount);
614a1b0ec30SJérôme Duval uint32 blockNum = B_LENDIAN_TO_HOST_INT32(*block);
615a1b0ec30SJérôme Duval *block = 0;
616a1b0ec30SJérôme Duval
617a1b0ec30SJérôme Duval if (blockNum != fFreeStart + fFreeCount) {
618a1b0ec30SJérôme Duval if (fFreeCount != 0) {
619a1b0ec30SJérôme Duval status_t status = fVolume->FreeBlocks(transaction, fFreeStart,
620a1b0ec30SJérôme Duval fFreeCount);
621a1b0ec30SJérôme Duval if (status != B_OK)
622a1b0ec30SJérôme Duval return status;
623a1b0ec30SJérôme Duval }
624a1b0ec30SJérôme Duval
625a1b0ec30SJérôme Duval fFreeStart = blockNum;
626a1b0ec30SJérôme Duval fFreeCount = 0;
627a1b0ec30SJérôme Duval }
628a1b0ec30SJérôme Duval
629a1b0ec30SJérôme Duval fFreeCount++;
630a1b0ec30SJérôme Duval
631a1b0ec30SJérôme Duval return B_OK;
632a1b0ec30SJérôme Duval }
633a1b0ec30SJérôme Duval
634a1b0ec30SJérôme Duval
635a1b0ec30SJérôme Duval status_t
_FreeBlocks(Transaction & transaction,uint32 * block,uint32 _count)636a1b0ec30SJérôme Duval DataStream::_FreeBlocks(Transaction& transaction, uint32* block, uint32 _count)
637a1b0ec30SJérôme Duval {
638a1b0ec30SJérôme Duval uint32 count = _count;
639a130bab3SJérôme Duval TRACE("DataStream::_FreeBlocks(%p, %" B_PRIu32 ")\n", block, count);
640a1b0ec30SJérôme Duval
641a1b0ec30SJérôme Duval while (count > 0) {
642a1b0ec30SJérôme Duval status_t status = _MarkBlockForRemoval(transaction, block);
643a1b0ec30SJérôme Duval if (status != B_OK)
644a1b0ec30SJérôme Duval return status;
645a1b0ec30SJérôme Duval
646a1b0ec30SJérôme Duval block++;
647a1b0ec30SJérôme Duval count--;
648a1b0ec30SJérôme Duval }
649a1b0ec30SJérôme Duval
650a1b0ec30SJérôme Duval fRemovedBlocks += _count;
651a1b0ec30SJérôme Duval
652a1b0ec30SJérôme Duval return B_OK;
653a1b0ec30SJérôme Duval }
654a1b0ec30SJérôme Duval
655a1b0ec30SJérôme Duval
656a1b0ec30SJérôme Duval status_t
_FreeBlocks(Transaction & transaction,uint32 * block,off_t start,off_t end,bool freeParent,int recursion)657d8772e0cSJérôme Duval DataStream::_FreeBlocks(Transaction& transaction, uint32* block, off_t start,
658d8772e0cSJérôme Duval off_t end, bool freeParent, int recursion)
659a1b0ec30SJérôme Duval {
660a1b0ec30SJérôme Duval // TODO: Designed specifically for shrinking. Perhaps make it more general?
661a130bab3SJérôme Duval TRACE("DataStream::_FreeBlocks(%p, %" B_PRIdOFF ", %" B_PRIdOFF
662a130bab3SJérôme Duval ", %c, %d)\n", block, start, end, freeParent ? 't' : 'f', recursion);
663a1b0ec30SJérôme Duval
664a1b0ec30SJérôme Duval uint32 blockNum = B_LENDIAN_TO_HOST_INT32(*block);
665a1b0ec30SJérôme Duval
666a1b0ec30SJérôme Duval if (freeParent) {
667a1b0ec30SJérôme Duval status_t status = _MarkBlockForRemoval(transaction, block);
668a1b0ec30SJérôme Duval if (status != B_OK)
669a1b0ec30SJérôme Duval return status;
670a1b0ec30SJérôme Duval }
671a1b0ec30SJérôme Duval
672a1b0ec30SJérôme Duval CachedBlock cached(fVolume);
673a1b0ec30SJérôme Duval uint32* childBlock = (uint32*)cached.SetToWritable(transaction, blockNum);
674a1b0ec30SJérôme Duval if (childBlock == NULL)
675a1b0ec30SJérôme Duval return B_IO_ERROR;
676a1b0ec30SJérôme Duval
677a1b0ec30SJérôme Duval if (recursion == 0)
678a1b0ec30SJérôme Duval return _FreeBlocks(transaction, &childBlock[start], end - start);
679a1b0ec30SJérôme Duval
680a1b0ec30SJérôme Duval uint32 elementWidth;
681a1b0ec30SJérôme Duval if (recursion == 1)
682a1b0ec30SJérôme Duval elementWidth = kIndirectsPerBlock;
683a1b0ec30SJérôme Duval else if (recursion == 2)
684a1b0ec30SJérôme Duval elementWidth = kIndirectsPerBlock2;
685a1b0ec30SJérôme Duval else {
686a1b0ec30SJérôme Duval panic("Undefinied recursion level\n");
687a1b0ec30SJérôme Duval elementWidth = 0;
688a1b0ec30SJérôme Duval }
689a1b0ec30SJérôme Duval
690a1b0ec30SJérôme Duval uint32 elementPos = start / elementWidth;
691a1b0ec30SJérôme Duval uint32 endPos = end / elementWidth;
692a1b0ec30SJérôme Duval
693a1b0ec30SJérôme Duval recursion--;
694a1b0ec30SJérôme Duval
695a1b0ec30SJérôme Duval if (elementPos == endPos) {
696a1b0ec30SJérôme Duval bool free = freeParent || start % elementWidth == 0;
697a1b0ec30SJérôme Duval return _FreeBlocks(transaction, &childBlock[elementPos],
698a1b0ec30SJérôme Duval start % elementWidth, end % elementWidth, free, recursion);
699a1b0ec30SJérôme Duval }
700a1b0ec30SJérôme Duval
701a1b0ec30SJérôme Duval status_t status = B_OK;
702a1b0ec30SJérôme Duval
703a1b0ec30SJérôme Duval if (start % elementWidth != 0) {
704a1b0ec30SJérôme Duval status = _FreeBlocks(transaction, &childBlock[elementPos],
705a1b0ec30SJérôme Duval start % elementWidth, elementWidth, false, recursion);
706a1b0ec30SJérôme Duval if (status != B_OK)
707a1b0ec30SJérôme Duval return status;
708a1b0ec30SJérôme Duval
709a1b0ec30SJérôme Duval elementPos++;
710a1b0ec30SJérôme Duval }
711a1b0ec30SJérôme Duval
712a1b0ec30SJérôme Duval while (elementPos < endPos) {
713a1b0ec30SJérôme Duval status = _FreeBlocks(transaction, &childBlock[elementPos], 0,
714a1b0ec30SJérôme Duval elementWidth, true, recursion);
715a1b0ec30SJérôme Duval if (status != B_OK)
716a1b0ec30SJérôme Duval return status;
717a1b0ec30SJérôme Duval
718a1b0ec30SJérôme Duval elementPos++;
719a1b0ec30SJérôme Duval }
720a1b0ec30SJérôme Duval
721a1b0ec30SJérôme Duval if (end % elementWidth != 0) {
722a1b0ec30SJérôme Duval status = _FreeBlocks(transaction, &childBlock[elementPos], 0,
723a1b0ec30SJérôme Duval end % elementWidth, true, recursion);
724a1b0ec30SJérôme Duval }
725a1b0ec30SJérôme Duval
726a1b0ec30SJérôme Duval return status;
727a1b0ec30SJérôme Duval }
728a1b0ec30SJérôme Duval
729a1b0ec30SJérôme Duval
730a1b0ec30SJérôme Duval status_t
_RemoveFromDirectBlocks(Transaction & transaction,uint32 numBlocks)731a1b0ec30SJérôme Duval DataStream::_RemoveFromDirectBlocks(Transaction& transaction, uint32 numBlocks)
732a1b0ec30SJérôme Duval {
733a130bab3SJérôme Duval TRACE("DataStream::_RemoveFromDirectBlocks(): current size: %" B_PRIdOFF
734a130bab3SJérôme Duval ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks);
735a1b0ec30SJérôme Duval uint32* direct = &fStream->direct[numBlocks];
736d8772e0cSJérôme Duval off_t end = fNumBlocks > kMaxDirect ? kMaxDirect : fNumBlocks;
737a1b0ec30SJérôme Duval
738a1b0ec30SJérôme Duval return _FreeBlocks(transaction, direct, end - numBlocks);
739a1b0ec30SJérôme Duval }
740a1b0ec30SJérôme Duval
741a1b0ec30SJérôme Duval
742a1b0ec30SJérôme Duval status_t
_RemoveFromIndirectBlock(Transaction & transaction,uint32 numBlocks)743a1b0ec30SJérôme Duval DataStream::_RemoveFromIndirectBlock(Transaction& transaction, uint32 numBlocks)
744a1b0ec30SJérôme Duval {
745a130bab3SJérôme Duval TRACE("DataStream::_RemoveFromIndirectBlock(): current size: %" B_PRIdOFF
746a130bab3SJérôme Duval ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks);
747a1b0ec30SJérôme Duval uint32* indirect = &fStream->indirect;
748d8772e0cSJérôme Duval off_t start = numBlocks <= kMaxDirect ? 0 : numBlocks - kMaxDirect;
749d8772e0cSJérôme Duval off_t end = fNumBlocks - kMaxDirect;
750a1b0ec30SJérôme Duval
751a1b0ec30SJérôme Duval if (end > kIndirectsPerBlock)
752a1b0ec30SJérôme Duval end = kIndirectsPerBlock;
753a1b0ec30SJérôme Duval
754a1b0ec30SJérôme Duval bool freeAll = start == 0;
755a1b0ec30SJérôme Duval
756a1b0ec30SJérôme Duval return _FreeBlocks(transaction, indirect, start, end, freeAll, 0);
757a1b0ec30SJérôme Duval }
758a1b0ec30SJérôme Duval
759a1b0ec30SJérôme Duval
760a1b0ec30SJérôme Duval status_t
_RemoveFromDoubleIndirectBlock(Transaction & transaction,uint32 numBlocks)761a1b0ec30SJérôme Duval DataStream::_RemoveFromDoubleIndirectBlock(Transaction& transaction,
762a1b0ec30SJérôme Duval uint32 numBlocks)
763a1b0ec30SJérôme Duval {
764a130bab3SJérôme Duval TRACE("DataStream::_RemoveFromDoubleIndirectBlock(): current size: %" B_PRIdOFF
765a130bab3SJérôme Duval ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks);
766a1b0ec30SJérôme Duval uint32* doubleIndirect = &fStream->double_indirect;
767d8772e0cSJérôme Duval off_t start = numBlocks <= kMaxIndirect ? 0 : numBlocks - kMaxIndirect;
768d8772e0cSJérôme Duval off_t end = fNumBlocks - kMaxIndirect;
769a1b0ec30SJérôme Duval
770a1b0ec30SJérôme Duval if (end > kIndirectsPerBlock2)
771a1b0ec30SJérôme Duval end = kIndirectsPerBlock2;
772a1b0ec30SJérôme Duval
773a1b0ec30SJérôme Duval bool freeAll = start == 0;
774a1b0ec30SJérôme Duval
775a1b0ec30SJérôme Duval return _FreeBlocks(transaction, doubleIndirect, start, end, freeAll, 1);
776a1b0ec30SJérôme Duval }
777a1b0ec30SJérôme Duval
778a1b0ec30SJérôme Duval
779a1b0ec30SJérôme Duval status_t
_RemoveFromTripleIndirectBlock(Transaction & transaction,uint32 numBlocks)780a1b0ec30SJérôme Duval DataStream::_RemoveFromTripleIndirectBlock(Transaction& transaction,
781a1b0ec30SJérôme Duval uint32 numBlocks)
782a1b0ec30SJérôme Duval {
783a130bab3SJérôme Duval TRACE("DataStream::_RemoveFromTripleIndirectBlock(): current size: %" B_PRIdOFF
784a130bab3SJérôme Duval ", target size: %" B_PRIu32 "\n", fNumBlocks, numBlocks);
785a1b0ec30SJérôme Duval uint32* tripleIndirect = &fStream->triple_indirect;
786d8772e0cSJérôme Duval off_t start = numBlocks <= kMaxDoubleIndirect ? 0
787a1b0ec30SJérôme Duval : numBlocks - kMaxDoubleIndirect;
788d8772e0cSJérôme Duval off_t end = fNumBlocks - kMaxDoubleIndirect;
789a1b0ec30SJérôme Duval
790a1b0ec30SJérôme Duval bool freeAll = start == 0;
791a1b0ec30SJérôme Duval
792a1b0ec30SJérôme Duval return _FreeBlocks(transaction, tripleIndirect, start, end, freeAll, 2);
793a1b0ec30SJérôme Duval }
794