xref: /haiku/src/add-ons/kernel/file_systems/ntfs/libntfs/index.c (revision a1163de83ea633463a79de234b8742ee106531b2)
1 /**
2  * index.c - NTFS index handling.  Originated from the Linux-NTFS project.
3  *
4  * Copyright (c) 2004-2005 Anton Altaparmakov
5  * Copyright (c) 2004-2005 Richard Russon
6  * Copyright (c) 2005-2006 Yura Pakhuchiy
7  * Copyright (c) 2005-2008 Szabolcs Szakacsits
8  *
9  * This program/include file is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as published
11  * by the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program/include file is distributed in the hope that it will be
15  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program (in the main directory of the NTFS-3G
21  * distribution in the file COPYING); if not, write to the Free Software
22  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32 #ifdef HAVE_STRING_H
33 #include <string.h>
34 #endif
35 #ifdef HAVE_ERRNO_H
36 #include <errno.h>
37 #endif
38 
39 #include "attrib.h"
40 #include "collate.h"
41 #include "debug.h"
42 #include "index.h"
43 #include "mst.h"
44 #include "dir.h"
45 #include "logging.h"
46 #include "bitmap.h"
47 #include "misc.h"
48 
49 /**
50  * ntfs_index_entry_mark_dirty - mark an index entry dirty
51  * @ictx:	ntfs index context describing the index entry
52  *
53  * Mark the index entry described by the index entry context @ictx dirty.
54  *
55  * If the index entry is in the index root attribute, simply mark the inode
56  * containing the index root attribute dirty.  This ensures the mftrecord, and
57  * hence the index root attribute, will be written out to disk later.
58  *
59  * If the index entry is in an index block belonging to the index allocation
60  * attribute, set ib_dirty to TRUE, thus index block will be updated during
61  * ntfs_index_ctx_put.
62  */
63 void ntfs_index_entry_mark_dirty(ntfs_index_context *ictx)
64 {
65 	if (ictx->is_in_root)
66 		ntfs_inode_mark_dirty(ictx->actx->ntfs_ino);
67 	else
68 		ictx->ib_dirty = TRUE;
69 }
70 
71 static s64 ntfs_ib_vcn_to_pos(ntfs_index_context *icx, VCN vcn)
72 {
73 	return vcn << icx->vcn_size_bits;
74 }
75 
76 static VCN ntfs_ib_pos_to_vcn(ntfs_index_context *icx, s64 pos)
77 {
78 	return pos >> icx->vcn_size_bits;
79 }
80 
81 static int ntfs_ib_write(ntfs_index_context *icx, INDEX_BLOCK *ib)
82 {
83 	s64 ret, vcn = sle64_to_cpu(ib->index_block_vcn);
84 
85 	ntfs_log_trace("vcn: %lld\n", (long long)vcn);
86 
87 	ret = ntfs_attr_mst_pwrite(icx->ia_na, ntfs_ib_vcn_to_pos(icx, vcn),
88 				   1, icx->block_size, ib);
89 	if (ret != 1) {
90 		ntfs_log_perror("Failed to write index block %lld, inode %llu",
91 			(long long)vcn, (unsigned long long)icx->ni->mft_no);
92 		return STATUS_ERROR;
93 	}
94 
95 	return STATUS_OK;
96 }
97 
98 static int ntfs_icx_ib_write(ntfs_index_context *icx)
99 {
100 		if (ntfs_ib_write(icx, icx->ib))
101 			return STATUS_ERROR;
102 
103 		icx->ib_dirty = FALSE;
104 
105 		return STATUS_OK;
106 }
107 
108 /**
109  * ntfs_index_ctx_get - allocate and initialize a new index context
110  * @ni:		ntfs inode with which to initialize the context
111  * @name:	name of the which context describes
112  * @name_len:	length of the index name
113  *
114  * Allocate a new index context, initialize it with @ni and return it.
115  * Return NULL if allocation failed.
116  */
117 ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *ni,
118 				       ntfschar *name, u32 name_len)
119 {
120 	ntfs_index_context *icx;
121 
122 	ntfs_log_trace("Entering\n");
123 
124 	if (!ni) {
125 		errno = EINVAL;
126 		return NULL;
127 	}
128 	if (ni->nr_extents == -1)
129 		ni = ni->base_ni;
130 	icx = ntfs_calloc(sizeof(ntfs_index_context));
131 	if (icx)
132 		*icx = (ntfs_index_context) {
133 			.ni = ni,
134 			.name = name,
135 			.name_len = name_len,
136 		};
137 	return icx;
138 }
139 
140 static void ntfs_index_ctx_free(ntfs_index_context *icx)
141 {
142 	ntfs_log_trace("Entering\n");
143 
144 	if (!icx->entry)
145 		return;
146 
147 	if (icx->actx)
148 		ntfs_attr_put_search_ctx(icx->actx);
149 
150 	if (!icx->is_in_root) {
151 		if (icx->ib_dirty) {
152 			/* FIXME: Error handling!!! */
153 			ntfs_ib_write(icx, icx->ib);
154 		}
155 		free(icx->ib);
156 	}
157 
158 	ntfs_attr_close(icx->ia_na);
159 }
160 
161 /**
162  * ntfs_index_ctx_put - release an index context
163  * @icx:	index context to free
164  *
165  * Release the index context @icx, releasing all associated resources.
166  */
167 void ntfs_index_ctx_put(ntfs_index_context *icx)
168 {
169 	ntfs_index_ctx_free(icx);
170 	free(icx);
171 }
172 
173 /**
174  * ntfs_index_ctx_reinit - reinitialize an index context
175  * @icx:	index context to reinitialize
176  *
177  * Reinitialize the index context @icx so it can be used for ntfs_index_lookup.
178  */
179 void ntfs_index_ctx_reinit(ntfs_index_context *icx)
180 {
181 	ntfs_log_trace("Entering\n");
182 
183 	ntfs_index_ctx_free(icx);
184 
185 	*icx = (ntfs_index_context) {
186 		.ni = icx->ni,
187 		.name = icx->name,
188 		.name_len = icx->name_len,
189 	};
190 }
191 
192 static VCN *ntfs_ie_get_vcn_addr(INDEX_ENTRY *ie)
193 {
194 	return (VCN *)((u8 *)ie + le16_to_cpu(ie->length) - sizeof(VCN));
195 }
196 
197 /**
198  *  Get the subnode vcn to which the index entry refers.
199  */
200 VCN ntfs_ie_get_vcn(INDEX_ENTRY *ie)
201 {
202 	return sle64_to_cpup(ntfs_ie_get_vcn_addr(ie));
203 }
204 
205 static INDEX_ENTRY *ntfs_ie_get_first(INDEX_HEADER *ih)
206 {
207 	return (INDEX_ENTRY *)((u8 *)ih + le32_to_cpu(ih->entries_offset));
208 }
209 
210 static INDEX_ENTRY *ntfs_ie_get_next(INDEX_ENTRY *ie)
211 {
212 	return (INDEX_ENTRY *)((char *)ie + le16_to_cpu(ie->length));
213 }
214 
215 static u8 *ntfs_ie_get_end(INDEX_HEADER *ih)
216 {
217 	/* FIXME: check if it isn't overflowing the index block size */
218 	return (u8 *)ih + le32_to_cpu(ih->index_length);
219 }
220 
221 static int ntfs_ie_end(INDEX_ENTRY *ie)
222 {
223 	return ie->ie_flags & INDEX_ENTRY_END || !ie->length;
224 }
225 
226 /**
227  *  Find the last entry in the index block
228  */
229 static INDEX_ENTRY *ntfs_ie_get_last(INDEX_ENTRY *ie, char *ies_end)
230 {
231 	ntfs_log_trace("Entering\n");
232 
233 	while ((char *)ie < ies_end && !ntfs_ie_end(ie))
234 		ie = ntfs_ie_get_next(ie);
235 
236 	return ie;
237 }
238 
239 static INDEX_ENTRY *ntfs_ie_get_by_pos(INDEX_HEADER *ih, int pos)
240 {
241 	INDEX_ENTRY *ie;
242 
243 	ntfs_log_trace("pos: %d\n", pos);
244 
245 	ie = ntfs_ie_get_first(ih);
246 
247 	while (pos-- > 0)
248 		ie = ntfs_ie_get_next(ie);
249 
250 	return ie;
251 }
252 
253 static INDEX_ENTRY *ntfs_ie_prev(INDEX_HEADER *ih, INDEX_ENTRY *ie)
254 {
255 	INDEX_ENTRY *ie_prev = NULL;
256 	INDEX_ENTRY *tmp;
257 
258 	ntfs_log_trace("Entering\n");
259 
260 	tmp = ntfs_ie_get_first(ih);
261 
262 	while (tmp != ie) {
263 		ie_prev = tmp;
264 		tmp = ntfs_ie_get_next(tmp);
265 	}
266 
267 	return ie_prev;
268 }
269 
270 char *ntfs_ie_filename_get(INDEX_ENTRY *ie)
271 {
272 	FILE_NAME_ATTR *fn;
273 
274 	fn = (FILE_NAME_ATTR *)&ie->key;
275 	return ntfs_attr_name_get(fn->file_name, fn->file_name_length);
276 }
277 
278 void ntfs_ie_filename_dump(INDEX_ENTRY *ie)
279 {
280 	char *s;
281 
282 	s = ntfs_ie_filename_get(ie);
283 	ntfs_log_debug("'%s' ", s);
284 	ntfs_attr_name_free(&s);
285 }
286 
287 void ntfs_ih_filename_dump(INDEX_HEADER *ih)
288 {
289 	INDEX_ENTRY *ie;
290 
291 	ntfs_log_trace("Entering\n");
292 
293 	ie = ntfs_ie_get_first(ih);
294 	while (!ntfs_ie_end(ie)) {
295 		ntfs_ie_filename_dump(ie);
296 		ie = ntfs_ie_get_next(ie);
297 	}
298 }
299 
300 static int ntfs_ih_numof_entries(INDEX_HEADER *ih)
301 {
302 	int n;
303 	INDEX_ENTRY *ie;
304 	u8 *end;
305 
306 	ntfs_log_trace("Entering\n");
307 
308 	end = ntfs_ie_get_end(ih);
309 	ie = ntfs_ie_get_first(ih);
310 	for (n = 0; !ntfs_ie_end(ie) && (u8 *)ie < end; n++)
311 		ie = ntfs_ie_get_next(ie);
312 	return n;
313 }
314 
315 static int ntfs_ih_one_entry(INDEX_HEADER *ih)
316 {
317 	return (ntfs_ih_numof_entries(ih) == 1);
318 }
319 
320 static int ntfs_ih_zero_entry(INDEX_HEADER *ih)
321 {
322 	return (ntfs_ih_numof_entries(ih) == 0);
323 }
324 
325 static void ntfs_ie_delete(INDEX_HEADER *ih, INDEX_ENTRY *ie)
326 {
327 	u32 new_size;
328 
329 	ntfs_log_trace("Entering\n");
330 
331 	new_size = le32_to_cpu(ih->index_length) - le16_to_cpu(ie->length);
332 	ih->index_length = cpu_to_le32(new_size);
333 	memmove(ie, (u8 *)ie + le16_to_cpu(ie->length),
334 		new_size - ((u8 *)ie - (u8 *)ih));
335 }
336 
337 static void ntfs_ie_set_vcn(INDEX_ENTRY *ie, VCN vcn)
338 {
339 	*ntfs_ie_get_vcn_addr(ie) = cpu_to_le64(vcn);
340 }
341 
342 /**
343  *  Insert @ie index entry at @pos entry. Used @ih values should be ok already.
344  */
345 static void ntfs_ie_insert(INDEX_HEADER *ih, INDEX_ENTRY *ie, INDEX_ENTRY *pos)
346 {
347 	int ie_size = le16_to_cpu(ie->length);
348 
349 	ntfs_log_trace("Entering\n");
350 
351 	ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) + ie_size);
352 	memmove((u8 *)pos + ie_size, pos,
353 		le32_to_cpu(ih->index_length) - ((u8 *)pos - (u8 *)ih) - ie_size);
354 	memcpy(pos, ie, ie_size);
355 }
356 
357 static INDEX_ENTRY *ntfs_ie_dup(INDEX_ENTRY *ie)
358 {
359 	INDEX_ENTRY *dup;
360 
361 	ntfs_log_trace("Entering\n");
362 
363 	dup = ntfs_malloc(le16_to_cpu(ie->length));
364 	if (dup)
365 		memcpy(dup, ie, le16_to_cpu(ie->length));
366 
367 	return dup;
368 }
369 
370 static INDEX_ENTRY *ntfs_ie_dup_novcn(INDEX_ENTRY *ie)
371 {
372 	INDEX_ENTRY *dup;
373 	int size = le16_to_cpu(ie->length);
374 
375 	ntfs_log_trace("Entering\n");
376 
377 	if (ie->ie_flags & INDEX_ENTRY_NODE)
378 		size -= sizeof(VCN);
379 
380 	dup = ntfs_malloc(size);
381 	if (dup) {
382 		memcpy(dup, ie, size);
383 		dup->ie_flags &= ~INDEX_ENTRY_NODE;
384 		dup->length = cpu_to_le16(size);
385 	}
386 	return dup;
387 }
388 
389 static int ntfs_ia_check(ntfs_index_context *icx, INDEX_BLOCK *ib, VCN vcn)
390 {
391 	u32 ib_size = (unsigned)le32_to_cpu(ib->index.allocated_size) + 0x18;
392 
393 	ntfs_log_trace("Entering\n");
394 
395 	if (!ntfs_is_indx_record(ib->magic)) {
396 
397 		ntfs_log_error("Corrupt index block signature: vcn %lld inode "
398 			       "%llu\n", (long long)vcn,
399 			       (unsigned long long)icx->ni->mft_no);
400 		return -1;
401 	}
402 
403 	if (sle64_to_cpu(ib->index_block_vcn) != vcn) {
404 
405 		ntfs_log_error("Corrupt index block: VCN (%lld) is different "
406 			       "from expected VCN (%lld) in inode %llu\n",
407 			       (long long)sle64_to_cpu(ib->index_block_vcn),
408 			       (long long)vcn,
409 			       (unsigned long long)icx->ni->mft_no);
410 		return -1;
411 	}
412 
413 	if (ib_size != icx->block_size) {
414 
415 		ntfs_log_error("Corrupt index block : VCN (%lld) of inode %llu "
416 			       "has a size (%u) differing from the index "
417 			       "specified size (%u)\n", (long long)vcn,
418 			       (unsigned long long)icx->ni->mft_no, ib_size,
419 			       icx->block_size);
420 		return -1;
421 	}
422 	return 0;
423 }
424 
425 static INDEX_ROOT *ntfs_ir_lookup(ntfs_inode *ni, ntfschar *name,
426 				  u32 name_len, ntfs_attr_search_ctx **ctx)
427 {
428 	ATTR_RECORD *a;
429 	INDEX_ROOT *ir = NULL;
430 
431 	ntfs_log_trace("Entering\n");
432 
433 	*ctx = ntfs_attr_get_search_ctx(ni, NULL);
434 	if (!*ctx)
435 		return NULL;
436 
437 	if (ntfs_attr_lookup(AT_INDEX_ROOT, name, name_len, CASE_SENSITIVE,
438 			     0, NULL, 0, *ctx)) {
439 		ntfs_log_perror("Failed to lookup $INDEX_ROOT");
440 		goto err_out;
441 	}
442 
443 	a = (*ctx)->attr;
444 	if (a->non_resident) {
445 		errno = EINVAL;
446 		ntfs_log_perror("Non-resident $INDEX_ROOT detected");
447 		goto err_out;
448 	}
449 
450 	ir = (INDEX_ROOT *)((char *)a + le16_to_cpu(a->value_offset));
451 err_out:
452 	if (!ir) {
453 		ntfs_attr_put_search_ctx(*ctx);
454 		*ctx = NULL;
455 	}
456 	return ir;
457 }
458 
459 static INDEX_ROOT *ntfs_ir_lookup2(ntfs_inode *ni, ntfschar *name, u32 len)
460 {
461 	ntfs_attr_search_ctx *ctx;
462 	INDEX_ROOT *ir;
463 
464 	ir = ntfs_ir_lookup(ni, name, len, &ctx);
465 	if (ir)
466 		ntfs_attr_put_search_ctx(ctx);
467 	return ir;
468 }
469 
470 /**
471  * Find a key in the index block.
472  *
473  * Return values:
474  *   STATUS_OK with errno set to ESUCCESS if we know for sure that the
475  *             entry exists and @ie_out points to this entry.
476  *   STATUS_NOT_FOUND with errno set to ENOENT if we know for sure the
477  *                    entry doesn't exist and @ie_out is the insertion point.
478  *   STATUS_KEEP_SEARCHING if we can't answer the above question and
479  *                         @vcn will contain the node index block.
480  *   STATUS_ERROR with errno set if on unexpected error during lookup.
481  */
482 static int ntfs_ie_lookup(const void *key, const int key_len,
483 			  ntfs_index_context *icx, INDEX_HEADER *ih,
484 			  VCN *vcn, INDEX_ENTRY **ie_out)
485 {
486 	INDEX_ENTRY *ie;
487 	u8 *index_end;
488 	int rc, item = 0;
489 
490 	ntfs_log_trace("Entering\n");
491 
492 	index_end = ntfs_ie_get_end(ih);
493 
494 	/*
495 	 * Loop until we exceed valid memory (corruption case) or until we
496 	 * reach the last entry.
497 	 */
498 	for (ie = ntfs_ie_get_first(ih); ; ie = ntfs_ie_get_next(ie)) {
499 		/* Bounds checks. */
500 		if ((u8 *)ie + sizeof(INDEX_ENTRY_HEADER) > index_end ||
501 		    (u8 *)ie + le16_to_cpu(ie->length) > index_end) {
502 			errno = ERANGE;
503 			ntfs_log_error("Index entry out of bounds in inode "
504 				       "%llu.\n",
505 				       (unsigned long long)icx->ni->mft_no);
506 			return STATUS_ERROR;
507 		}
508 		/*
509 		 * The last entry cannot contain a key.  It can however contain
510 		 * a pointer to a child node in the B+tree so we just break out.
511 		 */
512 		if (ntfs_ie_end(ie))
513 			break;
514 		/*
515 		 * Not a perfect match, need to do full blown collation so we
516 		 * know which way in the B+tree we have to go.
517 		 */
518 		rc = ntfs_collate(icx->ni->vol, icx->cr, key, key_len, &ie->key,
519 				  le16_to_cpu(ie->key_length));
520 		if (rc == NTFS_COLLATION_ERROR) {
521 			ntfs_log_error("Collation error. Perhaps a filename "
522 				       "contains invalid characters?\n");
523 			errno = ERANGE;
524 			return STATUS_ERROR;
525 		}
526 		/*
527 		 * If @key collates before the key of the current entry, there
528 		 * is definitely no such key in this index but we might need to
529 		 * descend into the B+tree so we just break out of the loop.
530 		 */
531 		if (rc == -1)
532 			break;
533 
534 		if (!rc) {
535 			*ie_out = ie;
536 			errno = 0;
537 			icx->parent_pos[icx->pindex] = item;
538 			return STATUS_OK;
539 		}
540 
541 		item++;
542 	}
543 	/*
544 	 * We have finished with this index block without success. Check for the
545 	 * presence of a child node and if not present return with errno ENOENT,
546 	 * otherwise we will keep searching in another index block.
547 	 */
548 	if (!(ie->ie_flags & INDEX_ENTRY_NODE)) {
549 		ntfs_log_debug("Index entry wasn't found.\n");
550 		*ie_out = ie;
551 		errno = ENOENT;
552 		return STATUS_NOT_FOUND;
553 	}
554 
555 	/* Get the starting vcn of the index_block holding the child node. */
556 	*vcn = ntfs_ie_get_vcn(ie);
557 	if (*vcn < 0) {
558 		errno = EINVAL;
559 		ntfs_log_perror("Negative vcn in inode %llu\n",
560 			       	(unsigned long long)icx->ni->mft_no);
561 		return STATUS_ERROR;
562 	}
563 
564 	ntfs_log_trace("Parent entry number %d\n", item);
565 	icx->parent_pos[icx->pindex] = item;
566 
567 	return STATUS_KEEP_SEARCHING;
568 }
569 
570 static ntfs_attr *ntfs_ia_open(ntfs_index_context *icx, ntfs_inode *ni)
571 {
572 	ntfs_attr *na;
573 
574 	na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len);
575 	if (!na) {
576 		ntfs_log_perror("Failed to open index allocation of inode "
577 				"%llu", (unsigned long long)ni->mft_no);
578 		return NULL;
579 	}
580 
581 	return na;
582 }
583 
584 static int ntfs_ib_read(ntfs_index_context *icx, VCN vcn, INDEX_BLOCK *dst)
585 {
586 	s64 pos, ret;
587 
588 	ntfs_log_trace("vcn: %lld\n", (long long)vcn);
589 
590 	pos = ntfs_ib_vcn_to_pos(icx, vcn);
591 
592 	ret = ntfs_attr_mst_pread(icx->ia_na, pos, 1, icx->block_size, (u8 *)dst);
593 	if (ret != 1) {
594 		if (ret == -1)
595 			ntfs_log_perror("Failed to read index block");
596 		else
597 			ntfs_log_error("Failed to read full index block at "
598 				       "%lld\n", (long long)pos);
599 		return -1;
600 	}
601 
602 	if (ntfs_ia_check(icx, dst, vcn))
603 		return -1;
604 
605 	return 0;
606 }
607 
608 static int ntfs_icx_parent_inc(ntfs_index_context *icx)
609 {
610 	icx->pindex++;
611 	if (icx->pindex >= MAX_PARENT_VCN) {
612 		errno = EOPNOTSUPP;
613 		ntfs_log_perror("Index is over %d level deep", MAX_PARENT_VCN);
614 		return STATUS_ERROR;
615 	}
616 	return STATUS_OK;
617 }
618 
619 static int ntfs_icx_parent_dec(ntfs_index_context *icx)
620 {
621 	icx->pindex--;
622 	if (icx->pindex < 0) {
623 		errno = EINVAL;
624 		ntfs_log_perror("Corrupt index pointer (%d)", icx->pindex);
625 		return STATUS_ERROR;
626 	}
627 	return STATUS_OK;
628 }
629 
630 /**
631  * ntfs_index_lookup - find a key in an index and return its index entry
632  * @key:	[IN] key for which to search in the index
633  * @key_len:	[IN] length of @key in bytes
634  * @icx:	[IN/OUT] context describing the index and the returned entry
635  *
636  * Before calling ntfs_index_lookup(), @icx must have been obtained from a
637  * call to ntfs_index_ctx_get().
638  *
639  * Look for the @key in the index specified by the index lookup context @icx.
640  * ntfs_index_lookup() walks the contents of the index looking for the @key.
641  *
642  * If the @key is found in the index, 0 is returned and @icx is setup to
643  * describe the index entry containing the matching @key.  @icx->entry is the
644  * index entry and @icx->data and @icx->data_len are the index entry data and
645  * its length in bytes, respectively.
646  *
647  * If the @key is not found in the index, -1 is returned, errno = ENOENT and
648  * @icx is setup to describe the index entry whose key collates immediately
649  * after the search @key, i.e. this is the position in the index at which
650  * an index entry with a key of @key would need to be inserted.
651  *
652  * If an error occurs return -1, set errno to error code and @icx is left
653  * untouched.
654  *
655  * When finished with the entry and its data, call ntfs_index_ctx_put() to free
656  * the context and other associated resources.
657  *
658  * If the index entry was modified, call ntfs_index_entry_mark_dirty() before
659  * the call to ntfs_index_ctx_put() to ensure that the changes are written
660  * to disk.
661  */
662 int ntfs_index_lookup(const void *key, const int key_len, ntfs_index_context *icx)
663 {
664 	VCN old_vcn, vcn;
665 	ntfs_inode *ni = icx->ni;
666 	INDEX_ROOT *ir;
667 	INDEX_ENTRY *ie;
668 	INDEX_BLOCK *ib = NULL;
669 	int ret, err = 0;
670 
671 	ntfs_log_trace("Entering\n");
672 
673 	if (!key || key_len <= 0) {
674 		errno = EINVAL;
675 		ntfs_log_perror("key: %p  key_len: %d", key, key_len);
676 		return -1;
677 	}
678 
679 	ir = ntfs_ir_lookup(ni, icx->name, icx->name_len, &icx->actx);
680 	if (!ir) {
681 		if (errno == ENOENT)
682 			errno = EIO;
683 		return -1;
684 	}
685 
686 	icx->block_size = le32_to_cpu(ir->index_block_size);
687 	if (icx->block_size < NTFS_BLOCK_SIZE) {
688 		errno = EINVAL;
689 		ntfs_log_perror("Index block size (%d) is smaller than the "
690 				"sector size (%d)", icx->block_size, NTFS_BLOCK_SIZE);
691 		goto err_out;
692 	}
693 
694 	if (ni->vol->cluster_size <= icx->block_size)
695 		icx->vcn_size_bits = ni->vol->cluster_size_bits;
696 	else
697 		icx->vcn_size_bits = ni->vol->sector_size_bits;
698 
699 	icx->cr = ir->collation_rule;
700 	if (!ntfs_is_collation_rule_supported(icx->cr)) {
701 		err = errno = EOPNOTSUPP;
702 		ntfs_log_perror("Unknown collation rule 0x%x",
703 				(unsigned)le32_to_cpu(icx->cr));
704 		goto err_out;
705 	}
706 
707 	old_vcn = VCN_INDEX_ROOT_PARENT;
708 	/*
709 	 * FIXME: check for both ir and ib that the first index entry is
710 	 * within the index block.
711 	 */
712 	ret = ntfs_ie_lookup(key, key_len, icx, &ir->index, &vcn, &ie);
713 	if (ret == STATUS_ERROR) {
714 		err = errno;
715 		goto err_out;
716 	}
717 
718 	icx->ir = ir;
719 
720 	if (ret != STATUS_KEEP_SEARCHING) {
721 		/* STATUS_OK or STATUS_NOT_FOUND */
722 		err = errno;
723 		icx->is_in_root = TRUE;
724 		icx->parent_vcn[icx->pindex] = old_vcn;
725 		goto done;
726 	}
727 
728 	/* Child node present, descend into it. */
729 
730 	icx->ia_na = ntfs_ia_open(icx, ni);
731 	if (!icx->ia_na)
732 		goto err_out;
733 
734 	ib = ntfs_malloc(icx->block_size);
735 	if (!ib) {
736 		err = errno;
737 		goto err_out;
738 	}
739 
740 descend_into_child_node:
741 
742 	icx->parent_vcn[icx->pindex] = old_vcn;
743 	if (ntfs_icx_parent_inc(icx)) {
744 		err = errno;
745 		goto err_out;
746 	}
747 	old_vcn = vcn;
748 
749 	ntfs_log_debug("Descend into node with VCN %lld\n", (long long)vcn);
750 
751 	if (ntfs_ib_read(icx, vcn, ib))
752 		goto err_out;
753 
754 	ret = ntfs_ie_lookup(key, key_len, icx, &ib->index, &vcn, &ie);
755 	if (ret != STATUS_KEEP_SEARCHING) {
756 		err = errno;
757 		if (ret == STATUS_ERROR)
758 			goto err_out;
759 
760 		/* STATUS_OK or STATUS_NOT_FOUND */
761 		icx->is_in_root = FALSE;
762 		icx->ib = ib;
763 		icx->parent_vcn[icx->pindex] = vcn;
764 		goto done;
765 	}
766 
767 	if ((ib->index.ih_flags & NODE_MASK) == LEAF_NODE) {
768 		ntfs_log_error("Index entry with child node found in a leaf "
769 			       "node in inode 0x%llx.\n",
770 			       (unsigned long long)ni->mft_no);
771 		goto err_out;
772 	}
773 
774 	goto descend_into_child_node;
775 err_out:
776 	free(ib);
777 	if (!err)
778 		err = EIO;
779 	errno = err;
780 	return -1;
781 done:
782 	icx->entry = ie;
783 	icx->data = (u8 *)ie + offsetof(INDEX_ENTRY, key);
784 	icx->data_len = le16_to_cpu(ie->key_length);
785 	ntfs_log_trace("Done.\n");
786 	if (err) {
787 		errno = err;
788 		return -1;
789 	}
790 	return 0;
791 
792 }
793 
794 static INDEX_BLOCK *ntfs_ib_alloc(VCN ib_vcn, u32 ib_size,
795 				  INDEX_HEADER_FLAGS node_type)
796 {
797 	INDEX_BLOCK *ib;
798 	int ih_size = sizeof(INDEX_HEADER);
799 
800 	ntfs_log_trace("ib_vcn: %lld ib_size: %u\n", (long long)ib_vcn, ib_size);
801 
802 	ib = ntfs_calloc(ib_size);
803 	if (!ib)
804 		return NULL;
805 
806 	ib->magic = magic_INDX;
807 	ib->usa_ofs = cpu_to_le16(sizeof(INDEX_BLOCK));
808 	ib->usa_count = cpu_to_le16(ib_size / NTFS_BLOCK_SIZE + 1);
809 	/* Set USN to 1 */
810 	*(u16 *)((char *)ib + le16_to_cpu(ib->usa_ofs)) = cpu_to_le16(1);
811 	ib->lsn = cpu_to_le64(0);
812 
813 	ib->index_block_vcn = cpu_to_sle64(ib_vcn);
814 
815 	ib->index.entries_offset = cpu_to_le32((ih_size +
816 			le16_to_cpu(ib->usa_count) * 2 + 7) & ~7);
817 	ib->index.index_length = 0;
818 	ib->index.allocated_size = cpu_to_le32(ib_size -
819 					       (sizeof(INDEX_BLOCK) - ih_size));
820 	ib->index.ih_flags = node_type;
821 
822 	return ib;
823 }
824 
825 /**
826  *  Find the median by going through all the entries
827  */
828 static INDEX_ENTRY *ntfs_ie_get_median(INDEX_HEADER *ih)
829 {
830 	INDEX_ENTRY *ie, *ie_start;
831 	u8 *ie_end;
832 	int i = 0, median;
833 
834 	ntfs_log_trace("Entering\n");
835 
836 	ie = ie_start = ntfs_ie_get_first(ih);
837 	ie_end   = (u8 *)ntfs_ie_get_end(ih);
838 
839 	while ((u8 *)ie < ie_end && !ntfs_ie_end(ie)) {
840 		ie = ntfs_ie_get_next(ie);
841 		i++;
842 	}
843 	/*
844 	 * NOTE: this could be also the entry at the half of the index block.
845 	 */
846 	median = i / 2 - 1;
847 
848 	ntfs_log_trace("Entries: %d  median: %d\n", i, median);
849 
850 	for (i = 0, ie = ie_start; i <= median; i++)
851 		ie = ntfs_ie_get_next(ie);
852 
853 	return ie;
854 }
855 
856 static s64 ntfs_ibm_vcn_to_pos(ntfs_index_context *icx, VCN vcn)
857 {
858 	return ntfs_ib_vcn_to_pos(icx, vcn) / icx->block_size;
859 }
860 
861 static s64 ntfs_ibm_pos_to_vcn(ntfs_index_context *icx, s64 pos)
862 {
863 	return ntfs_ib_pos_to_vcn(icx, pos * icx->block_size);
864 }
865 
866 static int ntfs_ibm_add(ntfs_index_context *icx)
867 {
868 	u8 bmp[8];
869 
870 	ntfs_log_trace("Entering\n");
871 
872 	if (ntfs_attr_exist(icx->ni, AT_BITMAP, icx->name, icx->name_len))
873 		return STATUS_OK;
874 	/*
875 	 * AT_BITMAP must be at least 8 bytes.
876 	 */
877 	memset(bmp, 0, sizeof(bmp));
878 	if (ntfs_attr_add(icx->ni, AT_BITMAP, icx->name, icx->name_len,
879 			  bmp, sizeof(bmp))) {
880 		ntfs_log_perror("Failed to add AT_BITMAP");
881 		return STATUS_ERROR;
882 	}
883 
884 	return STATUS_OK;
885 }
886 
887 static int ntfs_ibm_modify(ntfs_index_context *icx, VCN vcn, int set)
888 {
889 	u8 byte;
890 	s64 pos = ntfs_ibm_vcn_to_pos(icx, vcn);
891 	u32 bpos = pos / 8;
892 	u32 bit = 1 << (pos % 8);
893 	ntfs_attr *na;
894 	int ret = STATUS_ERROR;
895 
896 	ntfs_log_trace("%s vcn: %lld\n", set ? "set" : "clear", (long long)vcn);
897 
898 	na = ntfs_attr_open(icx->ni, AT_BITMAP,  icx->name, icx->name_len);
899 	if (!na) {
900 		ntfs_log_perror("Failed to open $BITMAP attribute");
901 		return -1;
902 	}
903 
904 	if (set) {
905 		if (na->data_size < bpos + 1) {
906 			if (ntfs_attr_truncate(na, (na->data_size + 8) & ~7)) {
907 				ntfs_log_perror("Failed to truncate AT_BITMAP");
908 				goto err_na;
909 			}
910 		}
911 	}
912 
913 	if (ntfs_attr_pread(na, bpos, 1, &byte) != 1) {
914 		ntfs_log_perror("Failed to read $BITMAP");
915 		goto err_na;
916 	}
917 
918 	if (set)
919 		byte |= bit;
920 	else
921 		byte &= ~bit;
922 
923 	if (ntfs_attr_pwrite(na, bpos, 1, &byte) != 1) {
924 		ntfs_log_perror("Failed to write $Bitmap");
925 		goto err_na;
926 	}
927 
928 	ret = STATUS_OK;
929 err_na:
930 	ntfs_attr_close(na);
931 	return ret;
932 }
933 
934 
935 static int ntfs_ibm_set(ntfs_index_context *icx, VCN vcn)
936 {
937 	return ntfs_ibm_modify(icx, vcn, 1);
938 }
939 
940 static int ntfs_ibm_clear(ntfs_index_context *icx, VCN vcn)
941 {
942 	return ntfs_ibm_modify(icx, vcn, 0);
943 }
944 
945 static VCN ntfs_ibm_get_free(ntfs_index_context *icx)
946 {
947 	u8 *bm;
948 	int bit;
949 	s64 vcn, byte, size;
950 
951 	ntfs_log_trace("Entering\n");
952 
953 	bm = ntfs_attr_readall(icx->ni, AT_BITMAP,  icx->name, icx->name_len,
954 			       &size);
955 	if (!bm)
956 		return (VCN)-1;
957 
958 	for (byte = 0; byte < size; byte++) {
959 
960 		if (bm[byte] == 255)
961 			continue;
962 
963 		for (bit = 0; bit < 8; bit++) {
964 			if (!(bm[byte] & (1 << bit))) {
965 				vcn = ntfs_ibm_pos_to_vcn(icx, byte * 8 + bit);
966 				goto out;
967 			}
968 		}
969 	}
970 
971 	vcn = ntfs_ibm_pos_to_vcn(icx, size * 8);
972 out:
973 	ntfs_log_trace("allocated vcn: %lld\n", (long long)vcn);
974 
975 	if (ntfs_ibm_set(icx, vcn))
976 		vcn = (VCN)-1;
977 
978 	free(bm);
979 	return vcn;
980 }
981 
982 static INDEX_BLOCK *ntfs_ir_to_ib(INDEX_ROOT *ir, VCN ib_vcn)
983 {
984 	INDEX_BLOCK *ib;
985 	INDEX_ENTRY *ie_last;
986 	char *ies_start, *ies_end;
987 	int i;
988 
989 	ntfs_log_trace("Entering\n");
990 
991 	ib = ntfs_ib_alloc(ib_vcn, le32_to_cpu(ir->index_block_size), LEAF_NODE);
992 	if (!ib)
993 		return NULL;
994 
995 	ies_start = (char *)ntfs_ie_get_first(&ir->index);
996 	ies_end   = (char *)ntfs_ie_get_end(&ir->index);
997 	ie_last   = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end);
998 	/*
999 	 * Copy all entries, including the termination entry
1000 	 * as well, which can never have any data.
1001 	 */
1002 	i = (char *)ie_last - ies_start + le16_to_cpu(ie_last->length);
1003 	memcpy(ntfs_ie_get_first(&ib->index), ies_start, i);
1004 
1005 	ib->index.ih_flags = ir->index.ih_flags;
1006 	ib->index.index_length = cpu_to_le32(i +
1007 			le32_to_cpu(ib->index.entries_offset));
1008 	return ib;
1009 }
1010 
1011 static void ntfs_ir_nill(INDEX_ROOT *ir)
1012 {
1013 	INDEX_ENTRY *ie_last;
1014 	char *ies_start, *ies_end;
1015 
1016 	ntfs_log_trace("Entering\n");
1017 	/*
1018 	 * TODO: This function could be much simpler.
1019 	 */
1020 	ies_start = (char *)ntfs_ie_get_first(&ir->index);
1021 	ies_end   = (char *)ntfs_ie_get_end(&ir->index);
1022 	ie_last   = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end);
1023 	/*
1024 	 * Move the index root termination entry forward
1025 	 */
1026 	if ((char *)ie_last > ies_start) {
1027 		memmove(ies_start, (char *)ie_last, le16_to_cpu(ie_last->length));
1028 		ie_last = (INDEX_ENTRY *)ies_start;
1029 	}
1030 }
1031 
1032 static int ntfs_ib_copy_tail(ntfs_index_context *icx, INDEX_BLOCK *src,
1033 			     INDEX_ENTRY *median, VCN new_vcn)
1034 {
1035 	u8 *ies_end;
1036 	INDEX_ENTRY *ie_head;		/* first entry after the median */
1037 	int tail_size, ret;
1038 	INDEX_BLOCK *dst;
1039 
1040 	ntfs_log_trace("Entering\n");
1041 
1042 	dst = ntfs_ib_alloc(new_vcn, icx->block_size,
1043 			    src->index.ih_flags & NODE_MASK);
1044 	if (!dst)
1045 		return STATUS_ERROR;
1046 
1047 	ie_head = ntfs_ie_get_next(median);
1048 
1049 	ies_end = (u8 *)ntfs_ie_get_end(&src->index);
1050 	tail_size = ies_end - (u8 *)ie_head;
1051 	memcpy(ntfs_ie_get_first(&dst->index), ie_head, tail_size);
1052 
1053 	dst->index.index_length = cpu_to_le32(tail_size +
1054 					      le32_to_cpu(dst->index.entries_offset));
1055 	ret = ntfs_ib_write(icx, dst);
1056 
1057 	free(dst);
1058 	return ret;
1059 }
1060 
1061 static int ntfs_ib_cut_tail(ntfs_index_context *icx, INDEX_BLOCK *ib,
1062 			    INDEX_ENTRY *ie)
1063 {
1064 	char *ies_start, *ies_end;
1065 	INDEX_ENTRY *ie_last;
1066 
1067 	ntfs_log_trace("Entering\n");
1068 
1069 	ies_start = (char *)ntfs_ie_get_first(&ib->index);
1070 	ies_end   = (char *)ntfs_ie_get_end(&ib->index);
1071 
1072 	ie_last   = ntfs_ie_get_last((INDEX_ENTRY *)ies_start, ies_end);
1073 	if (ie_last->ie_flags & INDEX_ENTRY_NODE)
1074 		ntfs_ie_set_vcn(ie_last, ntfs_ie_get_vcn(ie));
1075 
1076 	memcpy(ie, ie_last, le16_to_cpu(ie_last->length));
1077 
1078 	ib->index.index_length = cpu_to_le32(((char *)ie - ies_start) +
1079 		le16_to_cpu(ie->length) + le32_to_cpu(ib->index.entries_offset));
1080 
1081 	if (ntfs_ib_write(icx, ib))
1082 		return STATUS_ERROR;
1083 
1084 	return STATUS_OK;
1085 }
1086 
1087 static int ntfs_ia_add(ntfs_index_context *icx)
1088 {
1089 	ntfs_log_trace("Entering\n");
1090 
1091 	if (ntfs_ibm_add(icx))
1092 		return -1;
1093 
1094 	if (!ntfs_attr_exist(icx->ni, AT_INDEX_ALLOCATION, icx->name, icx->name_len)) {
1095 
1096 		if (ntfs_attr_add(icx->ni, AT_INDEX_ALLOCATION, icx->name,
1097 				  icx->name_len, NULL, 0)) {
1098 			ntfs_log_perror("Failed to add AT_INDEX_ALLOCATION");
1099 			return -1;
1100 		}
1101 	}
1102 
1103 	icx->ia_na = ntfs_ia_open(icx, icx->ni);
1104 	if (!icx->ia_na)
1105 		return -1;
1106 
1107 	return 0;
1108 }
1109 
1110 static int ntfs_ir_reparent(ntfs_index_context *icx)
1111 {
1112 	ntfs_attr_search_ctx *ctx = NULL;
1113 	INDEX_ROOT *ir;
1114 	INDEX_ENTRY *ie;
1115 	INDEX_BLOCK *ib = NULL;
1116 	VCN new_ib_vcn;
1117 	int ret = STATUS_ERROR;
1118 
1119 	ntfs_log_trace("Entering\n");
1120 
1121 	ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
1122 	if (!ir)
1123 		goto out;
1124 
1125 	if ((ir->index.ih_flags & NODE_MASK) == SMALL_INDEX)
1126 		if (ntfs_ia_add(icx))
1127 			goto out;
1128 
1129 	new_ib_vcn = ntfs_ibm_get_free(icx);
1130 	if (new_ib_vcn == -1)
1131 		goto out;
1132 
1133 	ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
1134 	if (!ir)
1135 		goto clear_bmp;
1136 
1137 	ib = ntfs_ir_to_ib(ir, new_ib_vcn);
1138 	if (ib == NULL) {
1139 		ntfs_log_perror("Failed to move index root to index block");
1140 		goto clear_bmp;
1141 	}
1142 
1143 	if (ntfs_ib_write(icx, ib))
1144 		goto clear_bmp;
1145 
1146 	ir = ntfs_ir_lookup(icx->ni, icx->name, icx->name_len, &ctx);
1147 	if (!ir)
1148 		goto clear_bmp;
1149 
1150 	ntfs_ir_nill(ir);
1151 
1152 	ie = ntfs_ie_get_first(&ir->index);
1153 	ie->ie_flags |= INDEX_ENTRY_NODE;
1154 	ie->length = cpu_to_le16(sizeof(INDEX_ENTRY_HEADER) + sizeof(VCN));
1155 
1156 	ir->index.ih_flags = LARGE_INDEX;
1157 	ir->index.index_length = cpu_to_le32(le32_to_cpu(ir->index.entries_offset)
1158 					     + le16_to_cpu(ie->length));
1159 	ir->index.allocated_size = ir->index.index_length;
1160 
1161 	if (ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr,
1162 			sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER) +
1163 			le32_to_cpu(ir->index.allocated_size)))
1164 		/* FIXME: revert index root */
1165 		goto clear_bmp;
1166 	/*
1167 	 *  FIXME: do it earlier if we have enough space in IR (should always),
1168 	 *  so in error case we wouldn't lose the IB.
1169 	 */
1170 	ntfs_ie_set_vcn(ie, new_ib_vcn);
1171 
1172 	ret = STATUS_OK;
1173 err_out:
1174 	free(ib);
1175 	ntfs_attr_put_search_ctx(ctx);
1176 out:
1177 	return ret;
1178 clear_bmp:
1179 	ntfs_ibm_clear(icx, new_ib_vcn);
1180 	goto err_out;
1181 }
1182 
1183 /**
1184  * ntfs_ir_truncate - Truncate index root attribute
1185  *
1186  * Returns STATUS_OK, STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT or STATUS_ERROR.
1187  */
1188 static int ntfs_ir_truncate(ntfs_index_context *icx, int data_size)
1189 {
1190 	ntfs_attr *na;
1191 	int ret;
1192 
1193 	ntfs_log_trace("Entering\n");
1194 
1195 	na = ntfs_attr_open(icx->ni, AT_INDEX_ROOT, icx->name, icx->name_len);
1196 	if (!na) {
1197 		ntfs_log_perror("Failed to open INDEX_ROOT");
1198 		return STATUS_ERROR;
1199 	}
1200 	/*
1201 	 *  INDEX_ROOT must be resident and its entries can be moved to
1202 	 *  INDEX_BLOCK, so ENOSPC isn't a real error.
1203 	 */
1204 	ret = ntfs_attr_truncate(na, data_size + offsetof(INDEX_ROOT, index));
1205 	if (ret == STATUS_OK) {
1206 
1207 		icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
1208 		if (!icx->ir)
1209 			return STATUS_ERROR;
1210 
1211 		icx->ir->index.allocated_size = cpu_to_le32(data_size);
1212 
1213 	} else if (ret == STATUS_ERROR)
1214 		ntfs_log_perror("Failed to truncate INDEX_ROOT");
1215 
1216 	ntfs_attr_close(na);
1217 	return ret;
1218 }
1219 
1220 /**
1221  * ntfs_ir_make_space - Make more space for the index root attribute
1222  *
1223  * On success return STATUS_OK or STATUS_KEEP_SEARCHING.
1224  * On error return STATUS_ERROR.
1225  */
1226 static int ntfs_ir_make_space(ntfs_index_context *icx, int data_size)
1227 {
1228 	int ret;
1229 
1230 	ntfs_log_trace("Entering\n");
1231 
1232 	ret = ntfs_ir_truncate(icx, data_size);
1233 	if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) {
1234 
1235 		ret = ntfs_ir_reparent(icx);
1236 		if (ret == STATUS_OK)
1237 			ret = STATUS_KEEP_SEARCHING;
1238 		else
1239 			ntfs_log_perror("Failed to nodify INDEX_ROOT");
1240 	}
1241 
1242 	return ret;
1243 }
1244 
1245 /*
1246  * NOTE: 'ie' must be a copy of a real index entry.
1247  */
1248 static int ntfs_ie_add_vcn(INDEX_ENTRY **ie)
1249 {
1250 	INDEX_ENTRY *p, *old = *ie;
1251 
1252 	old->length = cpu_to_le16(le16_to_cpu(old->length) + sizeof(VCN));
1253 	p = realloc(old, le16_to_cpu(old->length));
1254 	if (!p)
1255 		return STATUS_ERROR;
1256 
1257 	p->ie_flags |= INDEX_ENTRY_NODE;
1258 	*ie = p;
1259 
1260 	return STATUS_OK;
1261 }
1262 
1263 static int ntfs_ih_insert(INDEX_HEADER *ih, INDEX_ENTRY *orig_ie, VCN new_vcn,
1264 			  int pos)
1265 {
1266 	INDEX_ENTRY *ie_node, *ie;
1267 	int ret = STATUS_ERROR;
1268 	VCN old_vcn;
1269 
1270 	ntfs_log_trace("Entering\n");
1271 
1272 	ie = ntfs_ie_dup(orig_ie);
1273 	if (!ie)
1274 		return STATUS_ERROR;
1275 
1276 	if (!(ie->ie_flags & INDEX_ENTRY_NODE))
1277 		if (ntfs_ie_add_vcn(&ie))
1278 			goto out;
1279 
1280 	ie_node = ntfs_ie_get_by_pos(ih, pos);
1281 	old_vcn = ntfs_ie_get_vcn(ie_node);
1282 	ntfs_ie_set_vcn(ie_node, new_vcn);
1283 
1284 	ntfs_ie_insert(ih, ie, ie_node);
1285 	ntfs_ie_set_vcn(ie_node, old_vcn);
1286 	ret = STATUS_OK;
1287 out:
1288 	free(ie);
1289 
1290 	return ret;
1291 }
1292 
1293 static VCN ntfs_icx_parent_vcn(ntfs_index_context *icx)
1294 {
1295 	return icx->parent_vcn[icx->pindex];
1296 }
1297 
1298 static VCN ntfs_icx_parent_pos(ntfs_index_context *icx)
1299 {
1300 	return icx->parent_pos[icx->pindex];
1301 }
1302 
1303 
1304 static int ntfs_ir_insert_median(ntfs_index_context *icx, INDEX_ENTRY *median,
1305 				 VCN new_vcn)
1306 {
1307 	u32 new_size;
1308 	int ret;
1309 
1310 	ntfs_log_trace("Entering\n");
1311 
1312 	icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
1313 	if (!icx->ir)
1314 		return STATUS_ERROR;
1315 
1316 	new_size = le32_to_cpu(icx->ir->index.index_length) +
1317 			le16_to_cpu(median->length);
1318 	if (!(median->ie_flags & INDEX_ENTRY_NODE))
1319 		new_size += sizeof(VCN);
1320 
1321 	ret = ntfs_ir_make_space(icx, new_size);
1322 	if (ret != STATUS_OK)
1323 		return ret;
1324 
1325 	icx->ir = ntfs_ir_lookup2(icx->ni, icx->name, icx->name_len);
1326 	if (!icx->ir)
1327 		return STATUS_ERROR;
1328 
1329 	return ntfs_ih_insert(&icx->ir->index, median, new_vcn,
1330 			      ntfs_icx_parent_pos(icx));
1331 }
1332 
1333 static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib);
1334 
1335 /**
1336  * On success return STATUS_OK or STATUS_KEEP_SEARCHING.
1337  * On error return STATUS_ERROR.
1338  */
1339 static int ntfs_ib_insert(ntfs_index_context *icx, INDEX_ENTRY *ie, VCN new_vcn)
1340 {
1341 	INDEX_BLOCK *ib;
1342 	u32 idx_size, allocated_size;
1343 	int err = STATUS_ERROR;
1344 	VCN old_vcn;
1345 
1346 	ntfs_log_trace("Entering\n");
1347 
1348 	ib = ntfs_malloc(icx->block_size);
1349 	if (!ib)
1350 		return -1;
1351 
1352 	old_vcn = ntfs_icx_parent_vcn(icx);
1353 
1354 	if (ntfs_ib_read(icx, old_vcn, ib))
1355 		goto err_out;
1356 
1357 	idx_size       = le32_to_cpu(ib->index.index_length);
1358 	allocated_size = le32_to_cpu(ib->index.allocated_size);
1359 	/* FIXME: sizeof(VCN) should be included only if ie has no VCN */
1360 	if (idx_size + le16_to_cpu(ie->length) + sizeof(VCN) > allocated_size) {
1361 		err = ntfs_ib_split(icx, ib);
1362 		if (err == STATUS_OK)
1363 			err = STATUS_KEEP_SEARCHING;
1364 		goto err_out;
1365 	}
1366 
1367 	if (ntfs_ih_insert(&ib->index, ie, new_vcn, ntfs_icx_parent_pos(icx)))
1368 		goto err_out;
1369 
1370 	if (ntfs_ib_write(icx, ib))
1371 		goto err_out;
1372 
1373 	err = STATUS_OK;
1374 err_out:
1375 	free(ib);
1376 	return err;
1377 }
1378 
1379 /**
1380  * ntfs_ib_split - Split an index block
1381  *
1382  * On success return STATUS_OK or STATUS_KEEP_SEARCHING.
1383  * On error return is STATUS_ERROR.
1384  */
1385 static int ntfs_ib_split(ntfs_index_context *icx, INDEX_BLOCK *ib)
1386 {
1387 	INDEX_ENTRY *median;
1388 	VCN new_vcn;
1389 	int ret;
1390 
1391 	ntfs_log_trace("Entering\n");
1392 
1393 	if (ntfs_icx_parent_dec(icx))
1394 		return STATUS_ERROR;
1395 
1396 	median  = ntfs_ie_get_median(&ib->index);
1397 	new_vcn = ntfs_ibm_get_free(icx);
1398 	if (new_vcn == -1)
1399 		return STATUS_ERROR;
1400 
1401 	if (ntfs_ib_copy_tail(icx, ib, median, new_vcn)) {
1402 		ntfs_ibm_clear(icx, new_vcn);
1403 		return STATUS_ERROR;
1404 	}
1405 
1406 	if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT)
1407 		ret = ntfs_ir_insert_median(icx, median, new_vcn);
1408 	else
1409 		ret = ntfs_ib_insert(icx, median, new_vcn);
1410 
1411 	if (ret != STATUS_OK) {
1412 		ntfs_ibm_clear(icx, new_vcn);
1413 		return ret;
1414 	}
1415 
1416 	ret = ntfs_ib_cut_tail(icx, ib, median);
1417 
1418 	return ret;
1419 }
1420 
1421 
1422 static int ntfs_ie_add(ntfs_index_context *icx, INDEX_ENTRY *ie)
1423 {
1424 	INDEX_HEADER *ih;
1425 	int allocated_size, new_size;
1426 	int ret = STATUS_ERROR;
1427 
1428 #ifdef DEBUG
1429 	char *fn;
1430 	fn = ntfs_ie_filename_get(ie);
1431 	ntfs_log_trace("file: '%s'\n", fn);
1432 	ntfs_attr_name_free(&fn);
1433 #endif
1434 
1435 	while (1) {
1436 
1437 		if (!ntfs_index_lookup(&ie->key, le16_to_cpu(ie->key_length), icx)) {
1438 			errno = EEXIST;
1439 			ntfs_log_perror("Index already have such entry");
1440 			goto err_out;
1441 		}
1442 		if (errno != ENOENT) {
1443 			ntfs_log_perror("Failed to find place for new entry");
1444 			goto err_out;
1445 		}
1446 
1447 		if (icx->is_in_root)
1448 			ih = &icx->ir->index;
1449 		else
1450 			ih = &icx->ib->index;
1451 
1452 		allocated_size = le32_to_cpu(ih->allocated_size);
1453 		new_size = le32_to_cpu(ih->index_length) + le16_to_cpu(ie->length);
1454 
1455 		if (new_size <= allocated_size)
1456 			break;
1457 
1458 		ntfs_log_trace("index block sizes: allocated: %d  needed: %d\n",
1459 			       allocated_size, new_size);
1460 
1461 		if (icx->is_in_root) {
1462 			if (ntfs_ir_make_space(icx, new_size) == STATUS_ERROR)
1463 				goto err_out;
1464 		} else {
1465 			if (ntfs_ib_split(icx, icx->ib) == STATUS_ERROR)
1466 				goto err_out;
1467 		}
1468 
1469 		ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
1470 		ntfs_index_ctx_reinit(icx);
1471 	}
1472 
1473 	ntfs_ie_insert(ih, ie, icx->entry);
1474 	ntfs_index_entry_mark_dirty(icx);
1475 
1476 	ret = STATUS_OK;
1477 err_out:
1478 	ntfs_log_trace("%s\n", ret ? "Failed" : "Done");
1479 	return ret;
1480 }
1481 
1482 /**
1483  * ntfs_index_add_filename - add filename to directory index
1484  * @ni:		ntfs inode describing directory to which index add filename
1485  * @fn:		FILE_NAME attribute to add
1486  * @mref:	reference of the inode which @fn describes
1487  *
1488  * Return 0 on success or -1 on error with errno set to the error code.
1489  */
1490 int ntfs_index_add_filename(ntfs_inode *ni, FILE_NAME_ATTR *fn, MFT_REF mref)
1491 {
1492 	INDEX_ENTRY *ie;
1493 	ntfs_index_context *icx;
1494 	int fn_size, ie_size, err, ret = -1;
1495 
1496 	ntfs_log_trace("Entering\n");
1497 
1498 	if (!ni || !fn) {
1499 		ntfs_log_error("Invalid arguments.\n");
1500 		errno = EINVAL;
1501 		return -1;
1502 	}
1503 
1504 	fn_size = (fn->file_name_length * sizeof(ntfschar)) +
1505 			sizeof(FILE_NAME_ATTR);
1506 	ie_size = (sizeof(INDEX_ENTRY_HEADER) + fn_size + 7) & ~7;
1507 
1508 	ie = ntfs_calloc(ie_size);
1509 	if (!ie)
1510 		return -1;
1511 
1512 	ie->indexed_file = cpu_to_le64(mref);
1513 	ie->length 	 = cpu_to_le16(ie_size);
1514 	ie->key_length 	 = cpu_to_le16(fn_size);
1515 	memcpy(&ie->key, fn, fn_size);
1516 
1517 	icx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4);
1518 	if (!icx)
1519 		goto out;
1520 
1521 	ret = ntfs_ie_add(icx, ie);
1522 	err = errno;
1523 	ntfs_index_ctx_put(icx);
1524 	errno = err;
1525 out:
1526 	free(ie);
1527 	return ret;
1528 }
1529 
1530 static int ntfs_ih_takeout(ntfs_index_context *icx, INDEX_HEADER *ih,
1531 			   INDEX_ENTRY *ie, INDEX_BLOCK *ib)
1532 {
1533 	INDEX_ENTRY *ie_roam;
1534 	int ret = STATUS_ERROR;
1535 
1536 	ntfs_log_trace("Entering\n");
1537 
1538 	ie_roam = ntfs_ie_dup_novcn(ie);
1539 	if (!ie_roam)
1540 		return STATUS_ERROR;
1541 
1542 	ntfs_ie_delete(ih, ie);
1543 
1544 	if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT)
1545 		ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
1546 	else
1547 		if (ntfs_ib_write(icx, ib))
1548 			goto out;
1549 
1550 	ntfs_index_ctx_reinit(icx);
1551 
1552 	ret = ntfs_ie_add(icx, ie_roam);
1553 out:
1554 	free(ie_roam);
1555 	return ret;
1556 }
1557 
1558 /**
1559  *  Used if an empty index block to be deleted has END entry as the parent
1560  *  in the INDEX_ROOT which is the only one there.
1561  */
1562 static void ntfs_ir_leafify(ntfs_index_context *icx, INDEX_HEADER *ih)
1563 {
1564 	INDEX_ENTRY *ie;
1565 
1566 	ntfs_log_trace("Entering\n");
1567 
1568 	ie = ntfs_ie_get_first(ih);
1569 	ie->ie_flags &= ~INDEX_ENTRY_NODE;
1570 	ie->length = cpu_to_le16(le16_to_cpu(ie->length) - sizeof(VCN));
1571 
1572 	ih->index_length = cpu_to_le32(le32_to_cpu(ih->index_length) - sizeof(VCN));
1573 	ih->ih_flags &= ~LARGE_INDEX;
1574 
1575 	/* Not fatal error */
1576 	ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length));
1577 }
1578 
1579 /**
1580  *  Used if an empty index block to be deleted has END entry as the parent
1581  *  in the INDEX_ROOT which is not the only one there.
1582  */
1583 static int ntfs_ih_reparent_end(ntfs_index_context *icx, INDEX_HEADER *ih,
1584 				INDEX_BLOCK *ib)
1585 {
1586 	INDEX_ENTRY *ie, *ie_prev;
1587 
1588 	ntfs_log_trace("Entering\n");
1589 
1590 	ie = ntfs_ie_get_by_pos(ih, ntfs_icx_parent_pos(icx));
1591 	ie_prev = ntfs_ie_prev(ih, ie);
1592 
1593 	ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(ie_prev));
1594 
1595 	return ntfs_ih_takeout(icx, ih, ie_prev, ib);
1596 }
1597 
1598 static int ntfs_index_rm_leaf(ntfs_index_context *icx)
1599 {
1600 	INDEX_BLOCK *ib = NULL;
1601 	INDEX_HEADER *parent_ih;
1602 	INDEX_ENTRY *ie;
1603 	int ret = STATUS_ERROR;
1604 
1605 	ntfs_log_trace("pindex: %d\n", icx->pindex);
1606 
1607 	if (ntfs_icx_parent_dec(icx))
1608 		return STATUS_ERROR;
1609 
1610 	if (ntfs_ibm_clear(icx, icx->parent_vcn[icx->pindex + 1]))
1611 		return STATUS_ERROR;
1612 
1613 	if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT)
1614 		parent_ih = &icx->ir->index;
1615 	else {
1616 		ib = ntfs_malloc(icx->block_size);
1617 		if (!ib)
1618 			return STATUS_ERROR;
1619 
1620 		if (ntfs_ib_read(icx, ntfs_icx_parent_vcn(icx), ib))
1621 			goto out;
1622 
1623 		parent_ih = &ib->index;
1624 	}
1625 
1626 	ie = ntfs_ie_get_by_pos(parent_ih, ntfs_icx_parent_pos(icx));
1627 	if (!ntfs_ie_end(ie)) {
1628 		ret = ntfs_ih_takeout(icx, parent_ih, ie, ib);
1629 		goto out;
1630 	}
1631 
1632 	if (ntfs_ih_zero_entry(parent_ih)) {
1633 
1634 		if (ntfs_icx_parent_vcn(icx) == VCN_INDEX_ROOT_PARENT) {
1635 			ntfs_ir_leafify(icx, parent_ih);
1636 			goto ok;
1637 		}
1638 
1639 		ret = ntfs_index_rm_leaf(icx);
1640 		goto out;
1641 	}
1642 
1643 	if (ntfs_ih_reparent_end(icx, parent_ih, ib))
1644 		goto out;
1645 ok:
1646 	ret = STATUS_OK;
1647 out:
1648 	free(ib);
1649 	return ret;
1650 }
1651 
1652 static int ntfs_index_rm_node(ntfs_index_context *icx)
1653 {
1654 	int entry_pos, pindex;
1655 	VCN vcn;
1656 	INDEX_BLOCK *ib = NULL;
1657 	INDEX_ENTRY *ie_succ, *ie, *entry = icx->entry;
1658 	INDEX_HEADER *ih;
1659 	u32 new_size;
1660 	int delta, ret = STATUS_ERROR;
1661 
1662 	ntfs_log_trace("Entering\n");
1663 
1664 	if (!icx->ia_na) {
1665 		icx->ia_na = ntfs_ia_open(icx, icx->ni);
1666 		if (!icx->ia_na)
1667 			return STATUS_ERROR;
1668 	}
1669 
1670 	ib = ntfs_malloc(icx->block_size);
1671 	if (!ib)
1672 		return STATUS_ERROR;
1673 
1674 	ie_succ = ntfs_ie_get_next(icx->entry);
1675 	entry_pos = icx->parent_pos[icx->pindex]++;
1676 	pindex = icx->pindex;
1677 descend:
1678 	vcn = ntfs_ie_get_vcn(ie_succ);
1679 	if (ntfs_ib_read(icx, vcn, ib))
1680 		goto out;
1681 
1682 	ie_succ = ntfs_ie_get_first(&ib->index);
1683 
1684 	if (ntfs_icx_parent_inc(icx))
1685 		goto out;
1686 
1687 	icx->parent_vcn[icx->pindex] = vcn;
1688 	icx->parent_pos[icx->pindex] = 0;
1689 
1690 	if ((ib->index.ih_flags & NODE_MASK) == INDEX_NODE)
1691 		goto descend;
1692 
1693 	if (ntfs_ih_zero_entry(&ib->index)) {
1694 		errno = EIO;
1695 		ntfs_log_perror("Empty index block");
1696 		goto out;
1697 	}
1698 
1699 	ie = ntfs_ie_dup(ie_succ);
1700 	if (!ie)
1701 		goto out;
1702 
1703 	if (ntfs_ie_add_vcn(&ie))
1704 		goto out2;
1705 
1706 	ntfs_ie_set_vcn(ie, ntfs_ie_get_vcn(icx->entry));
1707 
1708 	if (icx->is_in_root)
1709 		ih = &icx->ir->index;
1710 	else
1711 		ih = &icx->ib->index;
1712 
1713 	delta = le16_to_cpu(ie->length) - le16_to_cpu(icx->entry->length);
1714 	new_size = le32_to_cpu(ih->index_length) + delta;
1715 	if (delta > 0) {
1716 		if (icx->is_in_root) {
1717 			ret = ntfs_ir_make_space(icx, new_size);
1718 			if (ret != STATUS_OK)
1719 				goto out2;
1720 
1721 			ih = &icx->ir->index;
1722 			entry = ntfs_ie_get_by_pos(ih, entry_pos);
1723 
1724 		} else if (new_size > le32_to_cpu(ih->allocated_size)) {
1725 			icx->pindex = pindex;
1726 			ret = ntfs_ib_split(icx, icx->ib);
1727 			if (ret == STATUS_OK)
1728 				ret = STATUS_KEEP_SEARCHING;
1729 			goto out2;
1730 		}
1731 	}
1732 
1733 	ntfs_ie_delete(ih, entry);
1734 	ntfs_ie_insert(ih, ie, entry);
1735 
1736 	if (icx->is_in_root) {
1737 		if (ntfs_ir_truncate(icx, new_size))
1738 			goto out2;
1739 	} else
1740 		if (ntfs_icx_ib_write(icx))
1741 			goto out2;
1742 
1743 	ntfs_ie_delete(&ib->index, ie_succ);
1744 
1745 	if (ntfs_ih_zero_entry(&ib->index)) {
1746 		if (ntfs_index_rm_leaf(icx))
1747 			goto out2;
1748 	} else
1749 		if (ntfs_ib_write(icx, ib))
1750 			goto out2;
1751 
1752 	ret = STATUS_OK;
1753 out2:
1754 	free(ie);
1755 out:
1756 	free(ib);
1757 	return ret;
1758 }
1759 
1760 /**
1761  * ntfs_index_rm - remove entry from the index
1762  * @icx:	index context describing entry to delete
1763  *
1764  * Delete entry described by @icx from the index. Index context is always
1765  * reinitialized after use of this function, so it can be used for index
1766  * lookup once again.
1767  *
1768  * Return 0 on success or -1 on error with errno set to the error code.
1769  */
1770 static int ntfs_index_rm(ntfs_index_context *icx)
1771 {
1772 	INDEX_HEADER *ih;
1773 	int err, ret = STATUS_OK;
1774 
1775 	ntfs_log_trace("Entering\n");
1776 
1777 	if (!icx || (!icx->ib && !icx->ir) || ntfs_ie_end(icx->entry)) {
1778 		ntfs_log_error("Invalid arguments.\n");
1779 		errno = EINVAL;
1780 		goto err_out;
1781 	}
1782 	if (icx->is_in_root)
1783 		ih = &icx->ir->index;
1784 	else
1785 		ih = &icx->ib->index;
1786 
1787 	if (icx->entry->ie_flags & INDEX_ENTRY_NODE) {
1788 
1789 		ret = ntfs_index_rm_node(icx);
1790 
1791 	} else if (icx->is_in_root || !ntfs_ih_one_entry(ih)) {
1792 
1793 		ntfs_ie_delete(ih, icx->entry);
1794 
1795 		if (icx->is_in_root) {
1796 			err = ntfs_ir_truncate(icx, le32_to_cpu(ih->index_length));
1797 			if (err != STATUS_OK)
1798 				goto err_out;
1799 		} else
1800 			if (ntfs_icx_ib_write(icx))
1801 				goto err_out;
1802 	} else {
1803 		if (ntfs_index_rm_leaf(icx))
1804 			goto err_out;
1805 	}
1806 out:
1807 	return ret;
1808 err_out:
1809 	ret = STATUS_ERROR;
1810 	goto out;
1811 }
1812 
1813 int ntfs_index_remove(ntfs_inode *ni, const void *key, const int keylen)
1814 {
1815 	int ret = STATUS_ERROR;
1816 	ntfs_index_context *icx;
1817 
1818 	icx = ntfs_index_ctx_get(ni, NTFS_INDEX_I30, 4);
1819 	if (!icx)
1820 		return -1;
1821 
1822 	while (1) {
1823 
1824 		if (ntfs_index_lookup(key, keylen, icx))
1825 			goto err_out;
1826 
1827 		if (((FILE_NAME_ATTR *)icx->data)->file_attributes &
1828 				FILE_ATTR_REPARSE_POINT) {
1829 			errno = EOPNOTSUPP;
1830 			goto err_out;
1831 		}
1832 
1833 		ret = ntfs_index_rm(icx);
1834 		if (ret == STATUS_ERROR)
1835 			goto err_out;
1836 		else if (ret == STATUS_OK)
1837 			break;
1838 
1839 		ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
1840 		ntfs_index_ctx_reinit(icx);
1841 	}
1842 
1843 	ntfs_inode_mark_dirty(icx->actx->ntfs_ino);
1844 out:
1845 	ntfs_index_ctx_put(icx);
1846 	return ret;
1847 err_out:
1848 	ret = STATUS_ERROR;
1849 	ntfs_log_perror("Delete failed");
1850 	goto out;
1851 }
1852 
1853 /**
1854  * ntfs_index_root_get - read the index root of an attribute
1855  * @ni:		open ntfs inode in which the ntfs attribute resides
1856  * @attr:	attribute for which we want its index root
1857  *
1858  * This function will read the related index root an ntfs attribute.
1859  *
1860  * On success a buffer is allocated with the content of the index root
1861  * and which needs to be freed when it's not needed anymore.
1862  *
1863  * On error NULL is returned with errno set to the error code.
1864  */
1865 INDEX_ROOT *ntfs_index_root_get(ntfs_inode *ni, ATTR_RECORD *attr)
1866 {
1867 	ntfs_attr_search_ctx *ctx;
1868 	ntfschar *name;
1869 	INDEX_ROOT *root = NULL;
1870 
1871 	name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset));
1872 
1873 	if (!ntfs_ir_lookup(ni, name, attr->name_length, &ctx))
1874 		return NULL;
1875 
1876 	root = ntfs_malloc(sizeof(INDEX_ROOT));
1877 	if (!root)
1878 		goto out;
1879 
1880 	*root = *((INDEX_ROOT *)((u8 *)ctx->attr +
1881 				le16_to_cpu(ctx->attr->value_offset)));
1882 out:
1883 	ntfs_attr_put_search_ctx(ctx);
1884 	return root;
1885 }
1886 
1887 
1888