xref: /haiku/src/add-ons/kernel/file_systems/ext2/HTreeEntryIterator.cpp (revision ce4e12ca3e341178e3df50ef67cf7c1d724e9559)
1919f9c41SJérôme Duval /*
2919f9c41SJérôme Duval  * Copyright 2010, Haiku Inc. All rights reserved.
3919f9c41SJérôme Duval  * This file may be used under the terms of the MIT License.
4919f9c41SJérôme Duval  *
5919f9c41SJérôme Duval  * Authors:
6919f9c41SJérôme Duval  *		Janito V. Ferreira Filho
7919f9c41SJérôme Duval  */
8919f9c41SJérôme Duval 
9919f9c41SJérôme Duval 
10919f9c41SJérôme Duval #include "HTreeEntryIterator.h"
11919f9c41SJérôme Duval 
12919f9c41SJérôme Duval #include <new>
13919f9c41SJérôme Duval 
14a1b0ec30SJérôme Duval #include "CachedBlock.h"
15*ce4e12caSJérôme Duval #include "CRCTable.h"
16919f9c41SJérôme Duval #include "HTree.h"
17919f9c41SJérôme Duval #include "Inode.h"
18919f9c41SJérôme Duval 
19919f9c41SJérôme Duval 
20919f9c41SJérôme Duval //#define TRACE_EXT2
21919f9c41SJérôme Duval #ifdef TRACE_EXT2
22919f9c41SJérôme Duval #	define TRACE(x...) dprintf("\33[34mext2:\33[0m " x)
23919f9c41SJérôme Duval #else
24919f9c41SJérôme Duval #	define TRACE(x...) ;
25919f9c41SJérôme Duval #endif
26919f9c41SJérôme Duval #define ERROR(x...) dprintf("\33[34mext2:\33[0m " x)
27919f9c41SJérôme Duval 
28919f9c41SJérôme Duval 
HTreeEntryIterator(off_t offset,Inode * directory)29919f9c41SJérôme Duval HTreeEntryIterator::HTreeEntryIterator(off_t offset, Inode* directory)
30919f9c41SJérôme Duval 	:
31919f9c41SJérôme Duval 	fDirectory(directory),
32a1b0ec30SJérôme Duval 	fVolume(directory->GetVolume()),
33a1b0ec30SJérôme Duval 	fHasCollision(false),
34*ce4e12caSJérôme Duval 	fLimit(0),
35*ce4e12caSJérôme Duval 	fCount(0),
36a1b0ec30SJérôme Duval 	fBlockSize(directory->GetVolume()->BlockSize()),
37919f9c41SJérôme Duval 	fParent(NULL),
38919f9c41SJérôme Duval 	fChild(NULL)
39919f9c41SJérôme Duval {
40a1b0ec30SJérôme Duval 	fInitStatus = fDirectory->FindBlock(offset, fBlockNum);
41a1b0ec30SJérôme Duval 
42a1b0ec30SJérôme Duval 	if (fInitStatus == B_OK) {
43a1b0ec30SJérôme Duval 		fFirstEntry = offset % fBlockSize / sizeof(HTreeEntry);
44a1b0ec30SJérôme Duval 		fCurrentEntry = fFirstEntry;
45a1b0ec30SJérôme Duval 	}
46a1b0ec30SJérôme Duval 
47a130bab3SJérôme Duval 	TRACE("HTreeEntryIterator::HTreeEntryIterator(): created %p, block %" B_PRIu64 ", "
48a130bab3SJérôme Duval 		"entry no. %u, parent: %p\n", this, fBlockNum, fCurrentEntry,
49a1b0ec30SJérôme Duval 		fParent);
50919f9c41SJérôme Duval }
51919f9c41SJérôme Duval 
52919f9c41SJérôme Duval 
HTreeEntryIterator(uint32 block,uint32 blockSize,Inode * directory,HTreeEntryIterator * parent,bool hasCollision)53919f9c41SJérôme Duval HTreeEntryIterator::HTreeEntryIterator(uint32 block, uint32 blockSize,
54919f9c41SJérôme Duval 	Inode* directory, HTreeEntryIterator* parent, bool hasCollision)
55919f9c41SJérôme Duval 	:
56919f9c41SJérôme Duval 	fDirectory(directory),
57a1b0ec30SJérôme Duval 	fVolume(directory->GetVolume()),
58a1b0ec30SJérôme Duval 	fHasCollision(hasCollision),
59*ce4e12caSJérôme Duval 	fLimit(0),
60*ce4e12caSJérôme Duval 	fCount(0),
61a1b0ec30SJérôme Duval 	fFirstEntry(1),
62a1b0ec30SJérôme Duval 	fCurrentEntry(1),
63a1b0ec30SJérôme Duval 	fBlockSize(blockSize),
64a1b0ec30SJérôme Duval 	fBlockNum(block),
65919f9c41SJérôme Duval 	fParent(parent),
66919f9c41SJérôme Duval 	fChild(NULL)
67919f9c41SJérôme Duval {
68a1b0ec30SJérôme Duval 	// fCurrentEntry is initialized to 1 to skip the fake directory entry
69a1b0ec30SJérôme Duval 	fInitStatus = B_OK;
70a1b0ec30SJérôme Duval 
71a130bab3SJérôme Duval 	TRACE("HTreeEntryIterator::HTreeEntryIterator(): created %p, block %"
72a130bab3SJérôme Duval 		B_PRIu32 ", parent: %p\n", this, block, fParent);
73919f9c41SJérôme Duval }
74919f9c41SJérôme Duval 
75919f9c41SJérôme Duval 
76919f9c41SJérôme Duval status_t
Init()77919f9c41SJérôme Duval HTreeEntryIterator::Init()
78919f9c41SJérôme Duval {
79a130bab3SJérôme Duval 	TRACE("HTreeEntryIterator::Init() first entry: %u\n",
80a130bab3SJérôme Duval 		fFirstEntry);
81919f9c41SJérôme Duval 
82a1b0ec30SJérôme Duval 	if (fInitStatus != B_OK)
83a1b0ec30SJérôme Duval 		return fInitStatus;
84919f9c41SJérôme Duval 
85a1b0ec30SJérôme Duval 	CachedBlock cached(fVolume);
86a1b0ec30SJérôme Duval 	const uint8* block = cached.SetTo(fBlockNum);
87a1b0ec30SJérôme Duval 	if (block == NULL) {
88a1b0ec30SJérôme Duval 		ERROR("Failed to read htree entry block.\n");
89919f9c41SJérôme Duval 		fCount = fLimit = 0;
90a1b0ec30SJérôme Duval 		return B_IO_ERROR;
91919f9c41SJérôme Duval 	}
92919f9c41SJérôme Duval 
93a1b0ec30SJérôme Duval 	HTreeCountLimit* countLimit = (HTreeCountLimit*)(
94a1b0ec30SJérôme Duval 		&((HTreeEntry*)block)[fFirstEntry]);
95a1b0ec30SJérôme Duval 
96a1b0ec30SJérôme Duval 	fCount = countLimit->Count();
97a1b0ec30SJérôme Duval 	fLimit = countLimit->Limit();
98919f9c41SJérôme Duval 
996bfb10d3SJérôme Duval 	if (fCount > fLimit) {
1006bfb10d3SJérôme Duval 		ERROR("HTreeEntryIterator::Init() bad fCount %u (fLimit %u)\n",
1016bfb10d3SJérôme Duval 			fCount, fLimit);
102919f9c41SJérôme Duval 		fCount = fLimit = 0;
103919f9c41SJérôme Duval 		return B_ERROR;
104919f9c41SJérôme Duval 	}
105919f9c41SJérôme Duval 
106*ce4e12caSJérôme Duval 	uint32 maxSize = fBlockSize;
107*ce4e12caSJérôme Duval 	if (fVolume->HasMetaGroupChecksumFeature())
108*ce4e12caSJérôme Duval 		maxSize -= sizeof(ext2_htree_tail);
109*ce4e12caSJérôme Duval 
110*ce4e12caSJérôme Duval 	if (fLimit != maxSize / sizeof(HTreeEntry) - fFirstEntry) {
111a130bab3SJérôme Duval 		ERROR("HTreeEntryIterator::Init() bad fLimit %u should be %" B_PRIu32
112a130bab3SJérôme Duval 			" at block %" B_PRIu64 "\n", fLimit,
113*ce4e12caSJérôme Duval 			(uint32)(maxSize / sizeof(HTreeEntry) - fFirstEntry), fBlockNum);
114919f9c41SJérôme Duval 		fCount = fLimit = 0;
115919f9c41SJérôme Duval 		return B_ERROR;
116919f9c41SJérôme Duval 	}
117919f9c41SJérôme Duval 
118a130bab3SJérôme Duval 	TRACE("HTreeEntryIterator::Init() count %u limit %u\n",
119a130bab3SJérôme Duval 		fCount, fLimit);
120919f9c41SJérôme Duval 
121919f9c41SJérôme Duval 	return B_OK;
122919f9c41SJérôme Duval }
123919f9c41SJérôme Duval 
124919f9c41SJérôme Duval 
~HTreeEntryIterator()125919f9c41SJérôme Duval HTreeEntryIterator::~HTreeEntryIterator()
126919f9c41SJérôme Duval {
127a1b0ec30SJérôme Duval 	TRACE("HTreeEntryIterator::~HTreeEntryIterator(): %p, parent: %p\n", this,
128a1b0ec30SJérôme Duval 		fParent);
129a1b0ec30SJérôme Duval 	delete fParent;
130a1b0ec30SJérôme Duval 	TRACE("HTreeEntryIterator::~HTreeEntryIterator(): Deleted the parent\n");
131919f9c41SJérôme Duval }
132919f9c41SJérôme Duval 
133919f9c41SJérôme Duval 
134919f9c41SJérôme Duval status_t
Lookup(uint32 hash,int indirections,DirectoryIterator ** directoryIterator,bool & detachRoot)135919f9c41SJérôme Duval HTreeEntryIterator::Lookup(uint32 hash, int indirections,
136a1b0ec30SJérôme Duval 	DirectoryIterator** directoryIterator, bool& detachRoot)
137919f9c41SJérôme Duval {
138a1b0ec30SJérôme Duval 	TRACE("HTreeEntryIterator::Lookup()\n");
139919f9c41SJérôme Duval 
140a1b0ec30SJérôme Duval 	if (fCount == 0)
141a1b0ec30SJérôme Duval 		return B_ENTRY_NOT_FOUND;
142919f9c41SJérôme Duval 
143a1b0ec30SJérôme Duval 	CachedBlock cached(fVolume);
144a1b0ec30SJérôme Duval 	const uint8* block = cached.SetTo(fBlockNum);
145a1b0ec30SJérôme Duval 	if (block == NULL) {
146a1b0ec30SJérôme Duval 		ERROR("Failed to read htree entry block.\n");
147919f9c41SJérôme Duval 		// Fallback to linear search
148919f9c41SJérôme Duval 		*directoryIterator = new(std::nothrow)
149919f9c41SJérôme Duval 			DirectoryIterator(fDirectory);
150919f9c41SJérôme Duval 
151919f9c41SJérôme Duval 		if (*directoryIterator == NULL)
152919f9c41SJérôme Duval 			return B_NO_MEMORY;
153919f9c41SJérôme Duval 
154919f9c41SJérôme Duval 		return B_OK;
155919f9c41SJérôme Duval 	}
156919f9c41SJérôme Duval 
157a1b0ec30SJérôme Duval 	HTreeEntry* start = (HTreeEntry*)block + fCurrentEntry + 1;
158a1b0ec30SJérôme Duval 	HTreeEntry* end = (HTreeEntry*)block + fCount + fFirstEntry - 1;
159a1b0ec30SJérôme Duval 	HTreeEntry* middle = start;
160a1b0ec30SJérôme Duval 
161a130bab3SJérôme Duval 	TRACE("HTreeEntryIterator::Lookup() current entry: %u\n",
162a130bab3SJérôme Duval 		fCurrentEntry);
163a1b0ec30SJérôme Duval 	TRACE("HTreeEntryIterator::Lookup() indirections: %d s:%p m:%p e:%p\n",
164a1b0ec30SJérôme Duval 		indirections, start, middle, end);
165a1b0ec30SJérôme Duval 
166a1b0ec30SJérôme Duval 	while (start <= end) {
167a1b0ec30SJérôme Duval 		middle = (HTreeEntry*)((end - start) / 2
168a1b0ec30SJérôme Duval 			+ start);
169a1b0ec30SJérôme Duval 
170a1b0ec30SJérôme Duval 		TRACE("HTreeEntryIterator::Lookup() indirections: %d s:%p m:%p e:%p\n",
171a1b0ec30SJérôme Duval 			indirections, start, middle, end);
172a1b0ec30SJérôme Duval 
173a130bab3SJérôme Duval 		TRACE("HTreeEntryIterator::Lookup() %" B_PRIx32 " %" B_PRIx32 "\n",
174a130bab3SJérôme Duval 			hash, middle->Hash());
175a1b0ec30SJérôme Duval 
176a1b0ec30SJérôme Duval 		if (hash >= middle->Hash())
177a1b0ec30SJérôme Duval 			start = middle + 1;
178919f9c41SJérôme Duval 		else
179a1b0ec30SJérôme Duval 			end = middle - 1;
180919f9c41SJérôme Duval 	}
181919f9c41SJérôme Duval 
182a1b0ec30SJérôme Duval 	--start;
183a1b0ec30SJérôme Duval 
184a1b0ec30SJérôme Duval 	fCurrentEntry = ((uint8*)start - block) / sizeof(HTreeEntry);
185919f9c41SJérôme Duval 
186919f9c41SJérôme Duval 	if (indirections == 0) {
187a1b0ec30SJérôme Duval 		TRACE("HTreeEntryIterator::Lookup(): Creating an indexed directory "
188a130bab3SJérôme Duval 			"iterator starting at block: %" B_PRIu32 ", hash: 0x%" B_PRIx32
189a130bab3SJérôme Duval 			"\n", start->Block(), start->Hash());
190919f9c41SJérôme Duval 		*directoryIterator = new(std::nothrow)
191a1b0ec30SJérôme Duval 			DirectoryIterator(fDirectory, start->Block() * fBlockSize, this);
192919f9c41SJérôme Duval 
193919f9c41SJérôme Duval 		if (*directoryIterator == NULL)
194919f9c41SJérôme Duval 			return B_NO_MEMORY;
195919f9c41SJérôme Duval 
196a1b0ec30SJérôme Duval 		detachRoot = true;
197919f9c41SJérôme Duval 		return B_OK;
198919f9c41SJérôme Duval 	}
199919f9c41SJérôme Duval 
200a1b0ec30SJérôme Duval 	TRACE("HTreeEntryIterator::Lookup(): Creating a HTree entry iterator "
201a130bab3SJérôme Duval 		"starting at block: %" B_PRIu32 ", hash: 0x%" B_PRIx32 "\n",
202a130bab3SJérôme Duval 		start->Block(), start->Hash());
20345af882dSJérôme Duval 	fsblock_t blockNum;
204a1b0ec30SJérôme Duval 	status_t status = fDirectory->FindBlock(start->Block() * fBlockSize,
205a1b0ec30SJérôme Duval 		blockNum);
206a1b0ec30SJérôme Duval 	if (status != B_OK)
207a1b0ec30SJérôme Duval 		return status;
208a1b0ec30SJérôme Duval 
209919f9c41SJérôme Duval 	delete fChild;
210919f9c41SJérôme Duval 
211a1b0ec30SJérôme Duval 	fChild = new(std::nothrow) HTreeEntryIterator(blockNum, fBlockSize,
212a1b0ec30SJérôme Duval 		fDirectory, this, (start->Hash() & 1) == 1);
213919f9c41SJérôme Duval 	if (fChild == NULL)
214919f9c41SJérôme Duval 		return B_NO_MEMORY;
215919f9c41SJérôme Duval 
216919f9c41SJérôme Duval 	status = fChild->Init();
217919f9c41SJérôme Duval 	if (status != B_OK)
218919f9c41SJérôme Duval 		return status;
219919f9c41SJérôme Duval 
220a1b0ec30SJérôme Duval 	return fChild->Lookup(hash, indirections - 1, directoryIterator,
221a1b0ec30SJérôme Duval 		detachRoot);
222919f9c41SJérôme Duval }
223919f9c41SJérôme Duval 
224919f9c41SJérôme Duval 
225919f9c41SJérôme Duval status_t
GetNext(uint32 & childBlock)226a1b0ec30SJérôme Duval HTreeEntryIterator::GetNext(uint32& childBlock)
227919f9c41SJérôme Duval {
228a1b0ec30SJérôme Duval 	fCurrentEntry++;
229a130bab3SJérôme Duval 	TRACE("HTreeEntryIterator::GetNext(): current entry: %u count: %u, "
230a130bab3SJérôme Duval 		"limit: %u\n", fCurrentEntry, fCount, fLimit);
231a1b0ec30SJérôme Duval 	bool endOfBlock = fCurrentEntry >= (fCount + fFirstEntry);
232919f9c41SJérôme Duval 
233a1b0ec30SJérôme Duval 	if (endOfBlock) {
234a1b0ec30SJérôme Duval 		TRACE("HTreeEntryIterator::GetNext(): end of entries in the block\n");
235a1b0ec30SJérôme Duval 		if (fParent == NULL) {
236a1b0ec30SJérôme Duval 			TRACE("HTreeEntryIterator::GetNext(): block was the root block\n");
237919f9c41SJérôme Duval 			return B_ENTRY_NOT_FOUND;
238a1b0ec30SJérôme Duval 		}
239919f9c41SJérôme Duval 
240a1b0ec30SJérôme Duval 		uint32 logicalBlock;
241a1b0ec30SJérôme Duval 		status_t status = fParent->GetNext(logicalBlock);
242919f9c41SJérôme Duval 		if (status != B_OK)
243919f9c41SJérôme Duval 			return status;
244919f9c41SJérôme Duval 
245a130bab3SJérôme Duval 		TRACE("HTreeEntryIterator::GetNext(): moving to next block: %" B_PRIx32
246a130bab3SJérôme Duval 			"\n", logicalBlock);
247a1b0ec30SJérôme Duval 
248a1b0ec30SJérôme Duval 		status = fDirectory->FindBlock(logicalBlock * fBlockSize, fBlockNum);
249a1b0ec30SJérôme Duval 		if (status != B_OK)
250a1b0ec30SJérôme Duval 			return status;
251a1b0ec30SJérôme Duval 
252a1b0ec30SJérôme Duval 		fFirstEntry = 1; // Skip fake directory entry
253a1b0ec30SJérôme Duval 		fCurrentEntry = 1;
254919f9c41SJérôme Duval 		status = Init();
255919f9c41SJérôme Duval 		if (status != B_OK)
256919f9c41SJérôme Duval 			return status;
257919f9c41SJérôme Duval 
258919f9c41SJérôme Duval 		fHasCollision = fParent->HasCollision();
259919f9c41SJérôme Duval 	}
260919f9c41SJérôme Duval 
261a1b0ec30SJérôme Duval 	CachedBlock cached(fVolume);
262a1b0ec30SJérôme Duval 	const uint8* block = cached.SetTo(fBlockNum);
263a1b0ec30SJérôme Duval 	if (block == NULL)
264a1b0ec30SJérôme Duval 		return B_IO_ERROR;
265a1b0ec30SJérôme Duval 
266a1b0ec30SJérôme Duval 	HTreeEntry* entry = &((HTreeEntry*)block)[fCurrentEntry];
267a1b0ec30SJérôme Duval 
268a1b0ec30SJérôme Duval 	if (!endOfBlock)
269a1b0ec30SJérôme Duval 		fHasCollision = (entry[fCurrentEntry].Hash() & 1) == 1;
270a1b0ec30SJérôme Duval 
271a130bab3SJérôme Duval 	TRACE("HTreeEntryIterator::GetNext(): next block: %" B_PRIu32 "\n",
272a1b0ec30SJérôme Duval 		entry->Block());
273a1b0ec30SJérôme Duval 
274a1b0ec30SJérôme Duval 	childBlock = entry->Block();
275a1b0ec30SJérôme Duval 
276a1b0ec30SJérôme Duval 	return B_OK;
277919f9c41SJérôme Duval }
278919f9c41SJérôme Duval 
279919f9c41SJérôme Duval 
280a1b0ec30SJérôme Duval uint32
BlocksNeededForNewEntry()281a1b0ec30SJérôme Duval HTreeEntryIterator::BlocksNeededForNewEntry()
282a1b0ec30SJérôme Duval {
283a130bab3SJérôme Duval 	TRACE("HTreeEntryIterator::BlocksNeededForNewEntry(): block num: %"
284a130bab3SJérôme Duval 		B_PRIu64 ", volume: %p\n", fBlockNum, fVolume);
285a1b0ec30SJérôme Duval 	CachedBlock cached(fVolume);
286a1b0ec30SJérôme Duval 
287a1b0ec30SJérôme Duval 	const uint8* blockData = cached.SetTo(fBlockNum);
288a1b0ec30SJérôme Duval 	const HTreeEntry* entries = (const HTreeEntry*)blockData;
289a1b0ec30SJérôme Duval 	const HTreeCountLimit* countLimit =
290a1b0ec30SJérôme Duval 		(const HTreeCountLimit*)&entries[fFirstEntry];
291a1b0ec30SJérôme Duval 
292a1b0ec30SJérôme Duval 	uint32 newBlocks = 0;
293a1b0ec30SJérôme Duval 	if (countLimit->IsFull()) {
294a1b0ec30SJérôme Duval 		newBlocks++;
295a1b0ec30SJérôme Duval 
296a1b0ec30SJérôme Duval 		if (fParent != NULL)
297a1b0ec30SJérôme Duval 			newBlocks += fParent->BlocksNeededForNewEntry();
298a1b0ec30SJérôme Duval 		else {
299a1b0ec30SJérôme Duval 			// Need a new level
300a1b0ec30SJérôme Duval 			HTreeRoot* root = (HTreeRoot*)entries;
301a1b0ec30SJérôme Duval 
302a1b0ec30SJérôme Duval 			if (root->indirection_levels == 1) {
303a1b0ec30SJérôme Duval 				// Maximum supported indirection levels reached
304a1b0ec30SJérôme Duval 				return B_DEVICE_FULL;
305a1b0ec30SJérôme Duval 			}
306a1b0ec30SJérôme Duval 
307a1b0ec30SJérôme Duval 			newBlocks++;
308a1b0ec30SJérôme Duval 		}
309a1b0ec30SJérôme Duval 	}
310a1b0ec30SJérôme Duval 
311a1b0ec30SJérôme Duval 	return newBlocks;
312a1b0ec30SJérôme Duval }
313a1b0ec30SJérôme Duval 
314a1b0ec30SJérôme Duval 
315a1b0ec30SJérôme Duval status_t
InsertEntry(Transaction & transaction,uint32 hash,off_t blockNum,off_t newBlocksPos,bool hasCollision)316a1b0ec30SJérôme Duval HTreeEntryIterator::InsertEntry(Transaction& transaction, uint32 hash,
3178d5a0a8fSJérôme Duval 	off_t blockNum, off_t newBlocksPos, bool hasCollision)
318a1b0ec30SJérôme Duval {
319a130bab3SJérôme Duval 	TRACE("HTreeEntryIterator::InsertEntry(): block num: %" B_PRIu64 "\n",
320a130bab3SJérôme Duval 		fBlockNum);
321a1b0ec30SJérôme Duval 	CachedBlock cached(fVolume);
322a1b0ec30SJérôme Duval 
323a1b0ec30SJérôme Duval 	uint8* blockData = cached.SetToWritable(transaction, fBlockNum);
324a1b0ec30SJérôme Duval 	if (blockData == NULL)
325a1b0ec30SJérôme Duval 		return B_IO_ERROR;
326a1b0ec30SJérôme Duval 
327a1b0ec30SJérôme Duval 	HTreeEntry* entries = (HTreeEntry*)blockData;
328a1b0ec30SJérôme Duval 
329a1b0ec30SJérôme Duval 	HTreeCountLimit* countLimit = (HTreeCountLimit*)&entries[fFirstEntry];
330a1b0ec30SJérôme Duval 	uint16 count = countLimit->Count();
331a1b0ec30SJérôme Duval 
332a1b0ec30SJérôme Duval 	if (count == countLimit->Limit()) {
333a1b0ec30SJérôme Duval 		TRACE("HTreeEntryIterator::InsertEntry(): Splitting the node\n");
334a1b0ec30SJérôme Duval 		panic("Splitting a HTree node required, but isn't yet fully "
335a1b0ec30SJérôme Duval 			"supported\n");
336a1b0ec30SJérôme Duval 
33745af882dSJérôme Duval 		fsblock_t physicalBlock;
338a1b0ec30SJérôme Duval 		status_t status = fDirectory->FindBlock(newBlocksPos, physicalBlock);
339a1b0ec30SJérôme Duval 		if (status != B_OK)
340a1b0ec30SJérôme Duval 			return status;
341a1b0ec30SJérôme Duval 
342a1b0ec30SJérôme Duval 		CachedBlock secondCached(fVolume);
343a1b0ec30SJérôme Duval 		uint8* secondBlockData = secondCached.SetToWritable(transaction,
344a1b0ec30SJérôme Duval 			physicalBlock);
345a1b0ec30SJérôme Duval 		if (secondBlockData == NULL)
346a1b0ec30SJérôme Duval 			return B_IO_ERROR;
347a1b0ec30SJérôme Duval 
348*ce4e12caSJérôme Duval 		uint32 maxSize = fBlockSize;
349*ce4e12caSJérôme Duval 		if (fVolume->HasMetaGroupChecksumFeature())
350*ce4e12caSJérôme Duval 			maxSize -= sizeof(ext2_dir_entry_tail);
351*ce4e12caSJérôme Duval 
352a1b0ec30SJérôme Duval 		HTreeFakeDirEntry* fakeEntry = (HTreeFakeDirEntry*)secondBlockData;
353a1b0ec30SJérôme Duval 		fakeEntry->inode_id = 0; // ?
354a1b0ec30SJérôme Duval 		fakeEntry->SetEntryLength(fBlockSize);
355a1b0ec30SJérôme Duval 		fakeEntry->name_length = 0;
356a1b0ec30SJérôme Duval 		fakeEntry->file_type = 0; // ?
357a1b0ec30SJérôme Duval 
358a1b0ec30SJérôme Duval 		HTreeEntry* secondBlockEntries = (HTreeEntry*)secondBlockData;
359a1b0ec30SJérôme Duval 		memmove(&entries[fFirstEntry + count / 2], &secondBlockEntries[1],
360a1b0ec30SJérôme Duval 			(count - count / 2) * sizeof(HTreeEntry));
361*ce4e12caSJérôme Duval 		_SetHTreeEntryChecksum(secondBlockData);
362a1b0ec30SJérôme Duval 	}
363a1b0ec30SJérôme Duval 
364a1b0ec30SJérôme Duval 	TRACE("HTreeEntryIterator::InsertEntry(): Inserting node. Count: %u, "
3658d5a0a8fSJérôme Duval 		"current entry: %u\n", count, fCurrentEntry);
366a1b0ec30SJérôme Duval 
367a1b0ec30SJérôme Duval 	if (count > 0) {
3688d5a0a8fSJérôme Duval 		TRACE("HTreeEntryIterator::InsertEntry(): memmove(%u, %u, %u)\n",
369a1b0ec30SJérôme Duval 			fCurrentEntry + 2, fCurrentEntry + 1, count + fFirstEntry
370a1b0ec30SJérôme Duval 				- fCurrentEntry - 1);
371a1b0ec30SJérôme Duval 		memmove(&entries[fCurrentEntry + 2], &entries[fCurrentEntry + 1],
372a1b0ec30SJérôme Duval 			(count + fFirstEntry - fCurrentEntry - 1) * sizeof(HTreeEntry));
373a1b0ec30SJérôme Duval 	}
374a1b0ec30SJérôme Duval 
375a1b0ec30SJérôme Duval 	uint32 oldHash = entries[fCurrentEntry].Hash();
376a1b0ec30SJérôme Duval 	entries[fCurrentEntry].SetHash(hasCollision ? oldHash | 1 : oldHash & ~1);
377a1b0ec30SJérôme Duval 	entries[fCurrentEntry + 1].SetHash((oldHash & 1) == 0 ? hash & ~1
378a1b0ec30SJérôme Duval 		: hash | 1);
379a1b0ec30SJérôme Duval 	entries[fCurrentEntry + 1].SetBlock(blockNum);
380a1b0ec30SJérôme Duval 
381a1b0ec30SJérôme Duval 	countLimit->SetCount(count + 1);
382919f9c41SJérôme Duval 
383*ce4e12caSJérôme Duval 	_SetHTreeEntryChecksum(blockData);
384*ce4e12caSJérôme Duval 
385919f9c41SJérôme Duval 	return B_OK;
386919f9c41SJérôme Duval }
387*ce4e12caSJérôme Duval 
388*ce4e12caSJérôme Duval 
389*ce4e12caSJérôme Duval ext2_htree_tail*
_HTreeEntryTail(uint8 * block) const390*ce4e12caSJérôme Duval HTreeEntryIterator::_HTreeEntryTail(uint8* block) const
391*ce4e12caSJérôme Duval {
392*ce4e12caSJérôme Duval 	HTreeEntry* entries = (HTreeEntry*)block;
393*ce4e12caSJérôme Duval 	HTreeCountLimit* countLimit = (HTreeCountLimit*)&entries[fFirstEntry];
394*ce4e12caSJérôme Duval 	uint16 limit = countLimit->Limit();
395*ce4e12caSJérôme Duval 	return (ext2_htree_tail*)(&entries[fFirstEntry + limit]);
396*ce4e12caSJérôme Duval }
397*ce4e12caSJérôme Duval 
398*ce4e12caSJérôme Duval 
399*ce4e12caSJérôme Duval uint32
_Checksum(uint8 * block) const400*ce4e12caSJérôme Duval HTreeEntryIterator::_Checksum(uint8* block) const
401*ce4e12caSJérôme Duval {
402*ce4e12caSJérôme Duval 	uint32 number = fDirectory->ID();
403*ce4e12caSJérôme Duval 	uint32 checksum = calculate_crc32c(fVolume->ChecksumSeed(),
404*ce4e12caSJérôme Duval 		(uint8*)&number, sizeof(number));
405*ce4e12caSJérôme Duval 	uint32 gen = fDirectory->Node().generation;
406*ce4e12caSJérôme Duval 	checksum = calculate_crc32c(checksum, (uint8*)&gen, sizeof(gen));
407*ce4e12caSJérôme Duval 	checksum = calculate_crc32c(checksum, block,
408*ce4e12caSJérôme Duval 		(fFirstEntry + fCount) * sizeof(HTreeEntry));
409*ce4e12caSJérôme Duval 	ext2_htree_tail dummy;
410*ce4e12caSJérôme Duval 	checksum = calculate_crc32c(checksum, (uint8*)&dummy, sizeof(dummy));
411*ce4e12caSJérôme Duval 	return checksum;
412*ce4e12caSJérôme Duval }
413*ce4e12caSJérôme Duval 
414*ce4e12caSJérôme Duval 
415*ce4e12caSJérôme Duval void
_SetHTreeEntryChecksum(uint8 * block)416*ce4e12caSJérôme Duval HTreeEntryIterator::_SetHTreeEntryChecksum(uint8* block)
417*ce4e12caSJérôme Duval {
418*ce4e12caSJérôme Duval 	if (fVolume->HasMetaGroupChecksumFeature()) {
419*ce4e12caSJérôme Duval 		ext2_htree_tail* tail = _HTreeEntryTail(block);
420*ce4e12caSJérôme Duval 		tail->reserved = 0xde00000c;
421*ce4e12caSJérôme Duval 		tail->checksum = _Checksum(block);
422*ce4e12caSJérôme Duval 	}
423*ce4e12caSJérôme Duval }
424*ce4e12caSJérôme Duval 
425