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