extent.c revision 2d328bb76d2d63bdfdba923b54c28bd686bd8fec
1/*
2 * extent.c --- routines to implement extents support
3 *
4 * Copyright (C) 2007 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12#include <stdio.h>
13#include <string.h>
14#if HAVE_UNISTD_H
15#include <unistd.h>
16#endif
17#if HAVE_ERRNO_H
18#include <errno.h>
19#endif
20#if HAVE_SYS_STAT_H
21#include <sys/stat.h>
22#endif
23#if HAVE_SYS_TYPES_H
24#include <sys/types.h>
25#endif
26
27#include "ext2_fs.h"
28#include "ext2fsP.h"
29#include "e2image.h"
30#include "ss/ss.h"
31
32/*
33 * Definitions to be dropped in lib/ext2fs/ext2fs.h
34 */
35
36/*
37 * Private definitions
38 */
39
40struct extent_path {
41	char		*buf;
42	int		entries;
43	int		max_entries;
44	int		left;
45	int		visit_num;
46	int		flags;
47	blk64_t		end_blk;
48	void		*curr;
49};
50
51
52struct ext2_extent_handle {
53	errcode_t		magic;
54	ext2_filsys		fs;
55	ext2_ino_t 		ino;
56	struct ext2_inode	*inode;
57	int			type;
58	int			level;
59	int			max_depth;
60	struct extent_path	*path;
61};
62
63struct ext2_extent_path {
64	errcode_t		magic;
65	int			leaf_height;
66	blk64_t			lblk;
67};
68
69/*
70 *  Useful Debugging stuff
71 */
72
73#ifdef DEBUG
74static void dbg_show_header(struct ext3_extent_header *eh)
75{
76	printf("header: magic=%x entries=%u max=%u depth=%u generation=%u\n",
77	       eh->eh_magic, eh->eh_entries, eh->eh_max, eh->eh_depth,
78	       eh->eh_generation);
79}
80
81static void dbg_show_index(struct ext3_extent_idx *ix)
82{
83	printf("index: block=%u leaf=%u leaf_hi=%u unused=%u\n",
84	       ix->ei_block, ix->ei_leaf, ix->ei_leaf_hi, ix->ei_unused);
85}
86
87static void dbg_show_extent(struct ext3_extent *ex)
88{
89	printf("extent: block=%u-%u len=%u start=%u start_hi=%u\n",
90	       ex->ee_block, ex->ee_block + ex->ee_len - 1,
91	       ex->ee_len, ex->ee_start, ex->ee_start_hi);
92}
93
94static void dbg_print_extent(char *desc, struct ext2fs_extent *extent)
95{
96	if (desc)
97		printf("%s: ", desc);
98	printf("extent: lblk %llu--%llu, len %lu, pblk %llu, flags: ",
99	       extent->e_lblk, extent->e_lblk + extent->e_len - 1,
100	       extent->e_len, extent->e_pblk);
101	if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF)
102		fputs("LEAF ", stdout);
103	if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
104		fputs("UNINIT ", stdout);
105	if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
106		fputs("2ND_VISIT ", stdout);
107	if (!extent->e_flags)
108		fputs("(none)", stdout);
109	fputc('\n', stdout);
110
111}
112
113#define dbg_printf(fmt, args...) printf(fmt, ## args)
114#else
115#define dbg_show_header(eh) do { } while (0)
116#define dbg_show_index(ix) do { } while (0)
117#define dbg_show_extent(ex) do { } while (0)
118#define dbg_print_extent(desc, ex) do { } while (0)
119#define dbg_printf(fmt, args...) do { } while (0)
120#endif
121
122/*
123 * Verify the extent header as being sane
124 */
125errcode_t ext2fs_extent_header_verify(void *ptr, int size)
126{
127	int eh_max, entry_size;
128	struct ext3_extent_header *eh = ptr;
129
130	dbg_show_header(eh);
131	if (ext2fs_le16_to_cpu(eh->eh_magic) != EXT3_EXT_MAGIC)
132		return EXT2_ET_EXTENT_HEADER_BAD;
133	if (ext2fs_le16_to_cpu(eh->eh_entries) > ext2fs_le16_to_cpu(eh->eh_max))
134		return EXT2_ET_EXTENT_HEADER_BAD;
135	if (eh->eh_depth == 0)
136		entry_size = sizeof(struct ext3_extent);
137	else
138		entry_size = sizeof(struct ext3_extent_idx);
139
140	eh_max = (size - sizeof(*eh)) / entry_size;
141	/* Allow two extent-sized items at the end of the block, for
142	 * ext4_extent_tail with checksum in the future. */
143	if ((ext2fs_le16_to_cpu(eh->eh_max) > eh_max) ||
144	    (ext2fs_le16_to_cpu(eh->eh_max) < (eh_max - 2)))
145		return EXT2_ET_EXTENT_HEADER_BAD;
146
147	return 0;
148}
149
150
151/*
152 * Begin functions to handle an inode's extent information
153 */
154extern void ext2fs_extent_free(ext2_extent_handle_t handle)
155{
156	int			i;
157
158	if (!handle)
159		return;
160
161	if (handle->inode)
162		ext2fs_free_mem(&handle->inode);
163	if (handle->path) {
164		for (i=1; i < handle->max_depth; i++) {
165			if (handle->path[i].buf)
166				ext2fs_free_mem(&handle->path[i].buf);
167		}
168		ext2fs_free_mem(&handle->path);
169	}
170	ext2fs_free_mem(&handle);
171}
172
173extern errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino,
174				    ext2_extent_handle_t *ret_handle)
175{
176	struct ext2_extent_handle	*handle;
177	errcode_t			retval;
178	int				isize = EXT2_INODE_SIZE(fs->super);
179	struct ext3_extent_header	*eh;
180
181	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
182
183	if ((ino == 0) || (ino > fs->super->s_inodes_count))
184		return EXT2_ET_BAD_INODE_NUM;
185
186	retval = ext2fs_get_mem(sizeof(struct ext2_extent_handle), &handle);
187	if (retval)
188		return retval;
189	memset(handle, 0, sizeof(struct ext2_extent_handle));
190
191	retval = ext2fs_get_mem(isize, &handle->inode);
192	if (retval)
193		goto errout;
194
195	handle->ino = ino;
196	handle->fs = fs;
197
198	retval = ext2fs_read_inode_full(fs, ino, handle->inode, isize);
199	if (retval)
200		goto errout;
201
202	if (!(handle->inode->i_flags & EXT4_EXTENTS_FL))
203		return EXT2_ET_INODE_NOT_EXTENT;
204
205	eh = (struct ext3_extent_header *) &handle->inode->i_block[0];
206
207	retval = ext2fs_extent_header_verify(eh, sizeof(handle->inode->i_block));
208	if (retval)
209		return (retval);
210
211	handle->max_depth = ext2fs_le16_to_cpu(eh->eh_depth);
212	handle->type = ext2fs_le16_to_cpu(eh->eh_magic);
213
214	retval = ext2fs_get_mem(((handle->max_depth+1) *
215				 sizeof(struct extent_path)),
216				&handle->path);
217	memset(handle->path, 0,
218	       (handle->max_depth+1) * sizeof(struct extent_path));
219	handle->path[0].buf = (char *) handle->inode->i_block;
220
221	handle->path[0].left = handle->path[0].entries =
222		ext2fs_le16_to_cpu(eh->eh_entries);
223	handle->path[0].max_entries = ext2fs_le16_to_cpu(eh->eh_max);
224	handle->path[0].curr = 0;
225	handle->path[0].end_blk =
226		((((__u64) handle->inode->i_size_high << 32) +
227		  handle->inode->i_size + (fs->blocksize - 1))
228		 >> EXT2_BLOCK_SIZE_BITS(fs->super));
229	handle->path[0].visit_num = 1;
230	handle->level = 0;
231	handle->magic = EXT2_ET_MAGIC_EXTENT_HANDLE;
232
233	*ret_handle = handle;
234	return 0;
235
236errout:
237	ext2fs_extent_free(handle);
238	return retval;
239}
240
241/*
242 * This function is responsible for (optionally) moving through the
243 * extent tree and then returning the current extent
244 */
245errcode_t ext2fs_extent_get(ext2_extent_handle_t handle,
246			    int flags, struct ext2fs_extent *extent)
247{
248	struct extent_path	*path, *newpath;
249	struct ext3_extent_header	*eh;
250	struct ext3_extent_idx		*ix = 0;
251	struct ext3_extent		*ex;
252	errcode_t			retval;
253	blk_t				blk;
254	blk64_t				end_blk;
255	int				orig_op, op;
256
257	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
258
259	if (!handle->path)
260		return EXT2_ET_NO_CURRENT_NODE;
261
262	orig_op = op = flags & EXT2_EXTENT_MOVE_MASK;
263
264retry:
265	path = handle->path + handle->level;
266	if ((orig_op == EXT2_EXTENT_NEXT) ||
267	    (orig_op == EXT2_EXTENT_NEXT_LEAF)) {
268		if (handle->level < handle->max_depth) {
269			/* interior node */
270			if (path->visit_num == 0) {
271				path->visit_num++;
272				op = EXT2_EXTENT_DOWN;
273			} else if (path->left > 0)
274				op = EXT2_EXTENT_NEXT_SIB;
275			else if (handle->level > 0)
276				op = EXT2_EXTENT_UP;
277			else
278				return EXT2_ET_EXTENT_NO_NEXT;
279		} else {
280			/* leaf node */
281			if (path->left > 0)
282				op = EXT2_EXTENT_NEXT_SIB;
283			else if (handle->level > 0)
284				op = EXT2_EXTENT_UP;
285			else
286				return EXT2_ET_EXTENT_NO_NEXT;
287		}
288		if (op != EXT2_EXTENT_NEXT_SIB) {
289			dbg_printf("<<<< OP = %s\n",
290			       (op == EXT2_EXTENT_DOWN) ? "down" :
291			       ((op == EXT2_EXTENT_UP) ? "up" : "unknown"));
292		}
293	}
294
295	if ((orig_op == EXT2_EXTENT_PREV) ||
296	    (orig_op == EXT2_EXTENT_PREV_LEAF)) {
297		if (handle->level < handle->max_depth) {
298			/* interior node */
299			if (path->visit_num > 0 ) {
300				/* path->visit_num = 0; */
301				op = EXT2_EXTENT_DOWN_AND_LAST;
302			} else if (path->left < path->entries-1)
303				op = EXT2_EXTENT_PREV_SIB;
304			else if (handle->level > 0)
305				op = EXT2_EXTENT_UP;
306			else
307				return EXT2_ET_EXTENT_NO_PREV;
308		} else {
309			/* leaf node */
310			if (path->left < path->entries-1)
311				op = EXT2_EXTENT_PREV_SIB;
312			else if (handle->level > 0)
313				op = EXT2_EXTENT_UP;
314			else
315				return EXT2_ET_EXTENT_NO_PREV;
316		}
317		if (op != EXT2_EXTENT_PREV_SIB) {
318			dbg_printf("<<<< OP = %s\n",
319			       (op == EXT2_EXTENT_DOWN_AND_LAST) ? "down/last" :
320			       ((op == EXT2_EXTENT_UP) ? "up" : "unknown"));
321		}
322	}
323
324	if (orig_op == EXT2_EXTENT_LAST_LEAF) {
325		if ((handle->level < handle->max_depth) &&
326		    (path->left == 0))
327			op = EXT2_EXTENT_DOWN;
328		else
329			op = EXT2_EXTENT_LAST_SIB;
330		dbg_printf("<<<< OP = %s\n",
331			   (op == EXT2_EXTENT_DOWN) ? "down" : "last_sib");
332	}
333
334	switch (op) {
335	case EXT2_EXTENT_CURRENT:
336		ix = path->curr;
337		break;
338	case EXT2_EXTENT_ROOT:
339		handle->level = 0;
340		path = handle->path + handle->level;
341	case EXT2_EXTENT_FIRST_SIB:
342		path->left = path->entries;
343		path->curr = 0;
344	case EXT2_EXTENT_NEXT_SIB:
345		if (path->left <= 0)
346			return EXT2_ET_EXTENT_NO_NEXT;
347		if (path->curr) {
348			ix = path->curr;
349			ix++;
350		} else {
351			eh = (struct ext3_extent_header *) path->buf;
352			ix = EXT_FIRST_INDEX(eh);
353		}
354		path->left--;
355		path->curr = ix;
356		path->visit_num = 0;
357		break;
358	case EXT2_EXTENT_PREV_SIB:
359		if (!path->curr ||
360		    path->left+1 >= path->entries)
361			return EXT2_ET_EXTENT_NO_PREV;
362		ix = path->curr;
363		ix--;
364		path->curr = ix;
365		path->left++;
366		if (handle->level < handle->max_depth)
367			path->visit_num = 1;
368		break;
369	case EXT2_EXTENT_LAST_SIB:
370		eh = (struct ext3_extent_header *) path->buf;
371		path->curr = EXT_LAST_EXTENT(eh);
372		ix = path->curr;
373		path->left = 0;
374		path->visit_num = 0;
375		break;
376	case EXT2_EXTENT_UP:
377		if (handle->level <= 0)
378			return EXT2_ET_EXTENT_NO_UP;
379		handle->level--;
380		path--;
381		ix = path->curr;
382		if ((orig_op == EXT2_EXTENT_PREV) ||
383		    (orig_op == EXT2_EXTENT_PREV_LEAF))
384			path->visit_num = 0;
385		break;
386	case EXT2_EXTENT_DOWN:
387	case EXT2_EXTENT_DOWN_AND_LAST:
388		if (!path->curr ||(handle->level >= handle->max_depth))
389			return EXT2_ET_EXTENT_NO_DOWN;
390
391		ix = path->curr;
392		newpath = path + 1;
393		if (!newpath->buf) {
394			retval = ext2fs_get_mem(handle->fs->blocksize,
395						&newpath->buf);
396			if (retval)
397				return retval;
398		}
399		blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
400			((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
401		if ((handle->fs->flags & EXT2_FLAG_IMAGE_FILE) &&
402		    (handle->fs->io != handle->fs->image_io))
403			memset(newpath->buf, 0, handle->fs->blocksize);
404		else {
405			retval = io_channel_read_blk(handle->fs->io,
406						     blk, 1, newpath->buf);
407			if (retval)
408				return retval;
409		}
410		handle->level++;
411
412		eh = (struct ext3_extent_header *) newpath->buf;
413
414		retval = ext2fs_extent_header_verify(eh, handle->fs->blocksize);
415		if (retval)
416			return retval;
417
418		newpath->left = newpath->entries =
419			ext2fs_le16_to_cpu(eh->eh_entries);
420		newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max);
421
422		if (path->left > 0) {
423			ix++;
424			newpath->end_blk = ext2fs_le32_to_cpu(ix->ei_block);
425		} else
426			newpath->end_blk = path->end_blk;
427
428		path = newpath;
429		if (op == EXT2_EXTENT_DOWN) {
430			ix = EXT_FIRST_INDEX((struct ext3_extent_header *) eh);
431			path->curr = ix;
432			path->left = path->entries - 1;
433			path->visit_num = 0;
434		} else {
435			ix = EXT_LAST_INDEX((struct ext3_extent_header *) eh);
436			path->curr = ix;
437			path->left = 0;
438			if (handle->level < handle->max_depth)
439				path->visit_num = 1;
440		}
441
442		dbg_printf("Down to level %d/%d, end_blk=%llu\n",
443			   handle->level, handle->max_depth,
444			   path->end_blk);
445
446		break;
447	default:
448		return EXT2_ET_OP_NOT_SUPPORTED;
449	}
450
451	if (!ix)
452		return EXT2_ET_NO_CURRENT_NODE;
453
454	extent->e_flags = 0;
455	dbg_printf("(Left %d)\n", path->left);
456
457	if (handle->level == handle->max_depth) {
458		ex = (struct ext3_extent *) ix;
459
460		extent->e_pblk = ext2fs_le32_to_cpu(ex->ee_start) +
461			((__u64) ext2fs_le16_to_cpu(ex->ee_start_hi) << 32);
462		extent->e_lblk = ext2fs_le32_to_cpu(ex->ee_block);
463		extent->e_len = ext2fs_le16_to_cpu(ex->ee_len);
464		extent->e_flags = EXT2_EXTENT_FLAGS_LEAF;
465		if (extent->e_len > EXT_INIT_MAX_LEN) {
466			extent->e_len -= EXT_INIT_MAX_LEN;
467			extent->e_flags = EXT2_EXTENT_FLAGS_UNINIT;
468		}
469	} else {
470		extent->e_pblk = ext2fs_le32_to_cpu(ix->ei_leaf) +
471			((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
472		extent->e_lblk = ext2fs_le32_to_cpu(ix->ei_block);
473		if (path->left > 0) {
474			ix++;
475			end_blk = ext2fs_le32_to_cpu(ix->ei_block);
476		} else
477			end_blk = path->end_blk;
478
479		extent->e_len = end_blk - extent->e_lblk;
480	}
481	if (path->visit_num)
482		extent->e_flags |= EXT2_EXTENT_FLAGS_SECOND_VISIT;
483
484	if (((orig_op == EXT2_EXTENT_NEXT_LEAF) ||
485	     (orig_op == EXT2_EXTENT_PREV_LEAF)) &&
486	    (handle->level != handle->max_depth))
487		goto retry;
488
489	if ((orig_op == EXT2_EXTENT_LAST_LEAF) &&
490	    ((handle->level != handle->max_depth) ||
491	     (path->left != 0)))
492		goto retry;
493
494	return 0;
495}
496
497static errcode_t update_path(ext2_extent_handle_t handle)
498{
499	blk64_t				blk;
500	errcode_t			retval;
501	struct ext3_extent_idx		*ix;
502
503	if (handle->level == 0) {
504		retval = ext2fs_write_inode_full(handle->fs, handle->ino,
505			   handle->inode, EXT2_INODE_SIZE(handle->fs->super));
506	} else {
507		ix = handle->path[handle->level - 1].curr;
508		blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
509			((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
510
511		retval = io_channel_write_blk(handle->fs->io,
512				      blk, 1, handle->path[handle->level].buf);
513	}
514	return retval;
515}
516
517#if 0
518errcode_t ext2fs_extent_save_path(ext2_extent_handle_t handle,
519				  ext2_extent_path_t *ret_path)
520{
521	ext2_extent_path_t	save_path;
522	struct ext2fs_extent	extent;
523	struct ext2_extent_info	info;
524	errcode_t		retval;
525
526	retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
527	if (retval)
528		return retval;
529
530	retval = ext2fs_extent_get_info(handle, &info);
531	if (retval)
532		return retval;
533
534	retval = ext2fs_get_mem(sizeof(struct ext2_extent_path), &save_path);
535	if (retval)
536		return retval;
537	memset(save_path, 0, sizeof(struct ext2_extent_path));
538
539	save_path->magic = EXT2_ET_MAGIC_EXTENT_PATH;
540	save_path->leaf_height = info.max_depth - info.curr_level - 1;
541	save_path->lblk = extent.e_lblk;
542
543	*ret_path = save_path;
544	return 0;
545}
546
547errcode_t ext2fs_extent_free_path(ext2_extent_path_t path)
548{
549	EXT2_CHECK_MAGIC(path, EXT2_ET_MAGIC_EXTENT_PATH);
550
551	ext2fs_free_mem(&path);
552	return 0;
553}
554#endif
555
556static errcode_t extent_goto(ext2_extent_handle_t handle,
557			     int leaf_level, blk64_t blk)
558{
559	struct ext2fs_extent	extent;
560	errcode_t		retval;
561
562	retval = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent);
563	if (retval)
564		return retval;
565
566	dbg_print_extent("root", &extent);
567	while (1) {
568		if (handle->level - leaf_level == handle->max_depth) {
569			if ((blk >= extent.e_lblk) &&
570			    (blk < extent.e_lblk + extent.e_len))
571				return 0;
572			if (blk < extent.e_lblk)
573				return EXT2_ET_EXTENT_NOT_FOUND;
574			retval = ext2fs_extent_get(handle,
575						   EXT2_EXTENT_NEXT_SIB,
576						   &extent);
577			if (retval == EXT2_ET_EXTENT_NO_NEXT)
578				return EXT2_ET_EXTENT_NOT_FOUND;
579			if (retval)
580				return retval;
581			continue;
582		}
583
584		retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_SIB,
585					   &extent);
586		if (retval == EXT2_ET_EXTENT_NO_NEXT)
587			goto go_down;
588		if (retval)
589			return retval;
590
591		dbg_print_extent("next", &extent);
592		if (blk == extent.e_lblk)
593			goto go_down;
594		if (blk > extent.e_lblk)
595			continue;
596
597		retval = ext2fs_extent_get(handle, EXT2_EXTENT_PREV_SIB,
598					   &extent);
599		if (retval)
600			return retval;
601
602		dbg_print_extent("prev", &extent);
603
604	go_down:
605		retval = ext2fs_extent_get(handle, EXT2_EXTENT_DOWN,
606					   &extent);
607		if (retval)
608			return retval;
609
610		dbg_print_extent("down", &extent);
611	}
612}
613
614errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
615			     blk64_t blk)
616{
617	return extent_goto(handle, 0, blk);
618}
619
620errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle,
621				int flags EXT2FS_ATTR((unused)),
622				struct ext2fs_extent *extent)
623{
624	struct extent_path		*path;
625	struct ext3_extent_idx		*ix;
626	struct ext3_extent		*ex;
627
628	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
629
630	if (!(handle->fs->flags & EXT2_FLAG_RW))
631		return EXT2_ET_RO_FILSYS;
632
633	if (!handle->path)
634		return EXT2_ET_NO_CURRENT_NODE;
635
636	path = handle->path + handle->level;
637	if (!path->curr)
638		return EXT2_ET_NO_CURRENT_NODE;
639
640	if (handle->level == handle->max_depth) {
641		ex = path->curr;
642
643		ex->ee_block = ext2fs_cpu_to_le32(extent->e_lblk);
644		ex->ee_start = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF);
645		ex->ee_start_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32);
646		ex->ee_len = ext2fs_cpu_to_le16(extent->e_len);
647	} else {
648		ix = path->curr;
649
650		ix->ei_leaf = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF);
651		ix->ei_leaf_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32);
652		ix->ei_block = ext2fs_cpu_to_le32(extent->e_lblk);
653		ix->ei_unused = 0;
654	}
655	update_path(handle);
656	return 0;
657}
658
659errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags,
660				      struct ext2fs_extent *extent)
661{
662	struct extent_path		*path;
663	struct ext3_extent_idx		*ix;
664	struct ext3_extent_header	*eh;
665	errcode_t			retval;
666
667	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
668
669	if (!(handle->fs->flags & EXT2_FLAG_RW))
670		return EXT2_ET_RO_FILSYS;
671
672	if (!handle->path)
673		return EXT2_ET_NO_CURRENT_NODE;
674
675	path = handle->path + handle->level;
676
677	if (path->entries >= path->max_entries)
678		return EXT2_ET_CANT_INSERT_EXTENT;
679
680	eh = (struct ext3_extent_header *) path->buf;
681	if (path->curr) {
682		ix = path->curr;
683		if (flags & EXT2_EXTENT_INSERT_AFTER) {
684			ix++;
685			path->left--;
686		}
687	} else
688		ix = EXT_FIRST_INDEX(eh);
689
690	path->curr = ix;
691
692	if (path->left > 0)
693		memmove(ix + 1, ix,
694			(path->left+1) * sizeof(struct ext3_extent_idx));
695	path->left++;
696	path->entries++;
697
698	eh = (struct ext3_extent_header *) path->buf;
699	eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
700
701	retval = ext2fs_extent_replace(handle, 0, extent);
702	if (retval)
703		goto errout;
704
705	retval = update_path(handle);
706	if (retval)
707		goto errout;
708
709	return 0;
710
711errout:
712	ext2fs_extent_delete(handle, 0);
713	return retval;
714}
715
716errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle,
717			       int flags EXT2FS_ATTR((unused)))
718{
719	struct extent_path		*path;
720	char 				*cp;
721	struct ext3_extent_header	*eh;
722	errcode_t			retval;
723
724	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
725
726	if (!(handle->fs->flags & EXT2_FLAG_RW))
727		return EXT2_ET_RO_FILSYS;
728
729	if (!handle->path)
730		return EXT2_ET_NO_CURRENT_NODE;
731
732	path = handle->path + handle->level;
733	if (!path->curr)
734		return EXT2_ET_NO_CURRENT_NODE;
735
736	cp = path->curr;
737
738	if (path->left) {
739		memmove(cp, cp + sizeof(struct ext3_extent_idx),
740			path->left * sizeof(struct ext3_extent_idx));
741		path->left--;
742	} else {
743		struct ext3_extent_idx	*ix = path->curr;
744		ix--;
745		path->curr = ix;
746	}
747	path->entries--;
748	if (path->entries == 0)
749		path->curr = 0;
750
751	eh = (struct ext3_extent_header *) path->buf;
752	eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
753
754	retval = update_path(handle);
755
756	return retval;
757}
758
759errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle,
760				 struct ext2_extent_info *info)
761{
762	struct extent_path		*path;
763
764	EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
765
766	memset(info, 0, sizeof(struct ext2_extent_info));
767
768	path = handle->path + handle->level;
769	if (path) {
770		if (path->curr)
771			info->curr_entry = ((char *) path->curr - path->buf) /
772				sizeof(struct ext3_extent_idx);
773		else
774			info->curr_entry = 0;
775		info->num_entries = path->entries;
776		info->max_entries = path->max_entries;
777		info->bytes_avail = (path->max_entries - path->entries) *
778			sizeof(struct ext3_extent);
779	}
780
781	info->curr_level = handle->level;
782	info->max_depth = handle->max_depth;
783	info->max_lblk = ((__u64) 1 << 32) - 1;
784	info->max_pblk = ((__u64) 1 << 48) - 1;
785	info->max_len = (1UL << 15);
786	info->max_uninit_len = (1UL << 15) - 1;
787
788	return 0;
789}
790
791#ifdef DEBUG
792
793#include "debugfs.h"
794
795/*
796 * Hook in new commands into debugfs
797 */
798const char *debug_prog_name = "tst_extents";
799extern ss_request_table extent_cmds;
800ss_request_table *extra_cmds = &extent_cmds;
801
802ext2_ino_t	current_ino = 0;
803ext2_extent_handle_t current_handle;
804
805void do_inode(int argc, char *argv[])
806{
807	ext2_ino_t	inode;
808	int		i;
809	struct ext3_extent_header *eh;
810	errcode_t retval;
811
812	if (check_fs_open(argv[0]))
813		return;
814
815	if (argc == 1) {
816		if (current_ino)
817			printf("Current inode is %d\n", current_ino);
818		else
819			printf("No current inode\n");
820		return;
821	}
822
823	if (common_inode_args_process(argc, argv, &inode, 0)) {
824		return;
825	}
826
827	current_ino = 0;
828
829	retval = ext2fs_extent_open(current_fs, inode, &current_handle);
830	if (retval) {
831		com_err(argv[1], retval, "while opening extent handle");
832		return;
833	}
834
835	current_ino = inode;
836
837	printf("Loaded inode %d\n", current_ino);
838
839	return;
840}
841
842void generic_goto_node(char *cmd_name, int op)
843{
844	struct ext2fs_extent	extent;
845	errcode_t		retval;
846
847	if (check_fs_open(cmd_name))
848		return;
849
850	if (!current_handle) {
851		com_err(cmd_name, 0, "Extent handle not open");
852		return;
853	}
854
855	retval = ext2fs_extent_get(current_handle, op, &extent);
856	if (retval) {
857		com_err(cmd_name, retval, 0);
858		return;
859	}
860	dbg_print_extent(0, &extent);
861}
862
863void do_current_node(int argc, char *argv[])
864{
865	generic_goto_node(argv[0], EXT2_EXTENT_CURRENT);
866}
867
868void do_root_node(int argc, char *argv[])
869{
870	generic_goto_node(argv[0], EXT2_EXTENT_ROOT);
871}
872
873void do_last_leaf(int argc, char *argv[])
874{
875	generic_goto_node(argv[0], EXT2_EXTENT_LAST_LEAF);
876}
877
878void do_first_sib(int argc, char *argv[])
879{
880	generic_goto_node(argv[0], EXT2_EXTENT_FIRST_SIB);
881}
882
883void do_last_sib(int argc, char *argv[])
884{
885	generic_goto_node(argv[0], EXT2_EXTENT_LAST_SIB);
886}
887
888void do_next_sib(int argc, char *argv[])
889{
890	generic_goto_node(argv[0], EXT2_EXTENT_NEXT_SIB);
891}
892
893void do_prev_sib(int argc, char *argv[])
894{
895	generic_goto_node(argv[0], EXT2_EXTENT_PREV_SIB);
896}
897
898void do_next_leaf(int argc, char *argv[])
899{
900	generic_goto_node(argv[0], EXT2_EXTENT_NEXT_LEAF);
901}
902
903void do_prev_leaf(int argc, char *argv[])
904{
905	generic_goto_node(argv[0], EXT2_EXTENT_PREV_LEAF);
906}
907
908void do_next(int argc, char *argv[])
909{
910	generic_goto_node(argv[0], EXT2_EXTENT_NEXT);
911}
912
913void do_prev(int argc, char *argv[])
914{
915	generic_goto_node(argv[0], EXT2_EXTENT_PREV);
916}
917
918void do_up(int argc, char *argv[])
919{
920	generic_goto_node(argv[0], EXT2_EXTENT_UP);
921}
922
923void do_down(int argc, char *argv[])
924{
925	generic_goto_node(argv[0], EXT2_EXTENT_DOWN);
926}
927
928void do_delete_node(int argc, char *argv[])
929{
930	errcode_t	retval;
931	int		err;
932
933	if (check_fs_read_write(argv[0]))
934		return;
935
936	retval = ext2fs_extent_delete(current_handle, 0);
937	if (retval) {
938		com_err(argv[0], retval, 0);
939		return;
940	}
941	do_current_node(argc, argv);
942}
943
944void do_replace_node(int argc, char *argv[])
945{
946	errcode_t	retval;
947	struct ext2fs_extent extent;
948	int err;
949
950	if (check_fs_read_write(argv[0]))
951		return;
952
953	if (argc != 4) {
954		fprintf(stderr, "usage: %s <lblk> <len> <pblk>\n", argv[0]);
955		return;
956	}
957
958	extent.e_lblk = parse_ulong(argv[1], argv[0],
959				    "logical block", &err);
960	if (err)
961		return;
962
963	extent.e_len = parse_ulong(argv[2], argv[0],
964				    "logical block", &err);
965	if (err)
966		return;
967
968	extent.e_pblk = parse_ulong(argv[3], argv[0],
969				    "logical block", &err);
970	if (err)
971		return;
972
973	retval = ext2fs_extent_replace(current_handle, 0, &extent);
974	if (retval) {
975		com_err(argv[0], retval, 0);
976		return;
977	}
978	do_current_node(argc, argv);
979}
980
981void do_insert_node(int argc, char *argv[])
982{
983	errcode_t	retval;
984	struct ext2fs_extent extent;
985	char *cmd;
986	int err;
987	int flags = 0;
988
989	if (check_fs_read_write(argv[0]))
990		return;
991
992	cmd = argv[0];
993
994	if (argc > 2 && !strcmp(argv[1], "--after")) {
995		argc--;
996		argv++;
997		flags |= EXT2_EXTENT_INSERT_AFTER;
998	}
999
1000	if (argc != 4) {
1001		fprintf(stderr, "usage: %s <lblk> <len> <pblk>\n", cmd);
1002		return;
1003	}
1004
1005	extent.e_lblk = parse_ulong(argv[1], cmd,
1006				    "logical block", &err);
1007	if (err)
1008		return;
1009
1010	extent.e_len = parse_ulong(argv[2], cmd,
1011				    "length", &err);
1012	if (err)
1013		return;
1014
1015	extent.e_pblk = parse_ulong(argv[3], cmd,
1016				    "pysical block", &err);
1017	if (err)
1018		return;
1019
1020	retval = ext2fs_extent_insert(current_handle, flags, &extent);
1021	if (retval) {
1022		com_err(cmd, retval, 0);
1023		return;
1024	}
1025	do_current_node(argc, argv);
1026}
1027
1028void do_print_all(int argc, char **argv)
1029{
1030	struct ext2fs_extent	extent;
1031	errcode_t		retval;
1032	errcode_t		end_err = EXT2_ET_EXTENT_NO_NEXT;
1033	int			op = EXT2_EXTENT_NEXT;
1034	int			first_op = EXT2_EXTENT_ROOT;
1035
1036
1037	if (check_fs_open(argv[0]))
1038		return;
1039
1040	if (!current_handle) {
1041		com_err(argv[0], 0, "Extent handle not open");
1042		return;
1043	}
1044
1045	if (argc > 2) {
1046	print_usage:
1047		fprintf(stderr,
1048			"Usage: %s [--leaf-only|--reverse|--reverse-leaf]\n",
1049			argv[0]);
1050		return;
1051	}
1052
1053	if (argc == 2) {
1054		if (!strcmp(argv[1], "--leaf-only"))
1055			op = EXT2_EXTENT_NEXT_LEAF;
1056		else if (!strcmp(argv[1], "--reverse")) {
1057			op = EXT2_EXTENT_PREV;
1058			first_op = EXT2_EXTENT_LAST_LEAF;
1059			end_err = EXT2_ET_EXTENT_NO_PREV;
1060		} else if (!strcmp(argv[1], "--reverse-leaf")) {
1061			op = EXT2_EXTENT_PREV_LEAF;
1062			first_op = EXT2_EXTENT_LAST_LEAF;
1063			end_err = EXT2_ET_EXTENT_NO_PREV;
1064		} else
1065			  goto print_usage;
1066	}
1067
1068	retval = ext2fs_extent_get(current_handle, first_op, &extent);
1069	if (retval) {
1070		com_err(argv[0], retval, 0);
1071		return;
1072	}
1073	dbg_print_extent(0, &extent);
1074
1075	while (1) {
1076		retval = ext2fs_extent_get(current_handle, op, &extent);
1077		if (retval == end_err)
1078			break;
1079
1080		if (retval) {
1081			com_err(argv[0], retval, 0);
1082			return;
1083		}
1084		dbg_print_extent(0, &extent);
1085	}
1086}
1087
1088void do_info(int argc, char **argv)
1089{
1090	struct ext2_extent_info	info;
1091	errcode_t		retval;
1092
1093	if (check_fs_open(argv[0]))
1094		return;
1095
1096	if (!current_handle) {
1097		com_err(argv[0], 0, "Extent handle not open");
1098		return;
1099	}
1100
1101	retval = ext2fs_extent_get_info(current_handle, &info);
1102	if (retval) {
1103		com_err(argv[0], retval, 0);
1104		return;
1105	}
1106
1107	printf("Current handle location: %d/%d (max: %d, bytes %d), level %d/%d\n",
1108	       info.curr_entry, info.num_entries, info.max_entries,
1109	       info.bytes_avail, info.curr_level, info.max_depth);
1110	printf("\tmax lblk: %llu, max pblk: %llu\n", info.max_lblk,
1111	       info.max_pblk);
1112	printf("\tmax_len: %u, max_uninit_len: %u\n", info.max_len,
1113	       info.max_uninit_len);
1114}
1115
1116void do_goto_block(int argc, char **argv)
1117{
1118	struct ext2fs_extent	extent;
1119	errcode_t		retval;
1120	int			op = EXT2_EXTENT_NEXT_LEAF;
1121	blk_t			blk;
1122
1123	if (check_fs_open(argv[0]))
1124		return;
1125
1126	if (!current_handle) {
1127		com_err(argv[0], 0, "Extent handle not open");
1128		return;
1129	}
1130
1131	if (argc != 2) {
1132		fprintf(stderr, "%s block\n", argv[0]);
1133		return;
1134	}
1135
1136	if (strtoblk(argv[0], argv[1], &blk))
1137		return;
1138
1139	retval = ext2fs_extent_goto(current_handle, (blk64_t) blk);
1140	if (retval) {
1141		com_err(argv[0], retval, "while trying to go to block %lu",
1142			blk);
1143		return;
1144	}
1145
1146	generic_goto_node(argv[0], EXT2_EXTENT_CURRENT);
1147}
1148#endif
1149
1150