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