Whamcloud - gitweb
eb096d6ab5b139eee4095de85b8aa8cc6a573c1d
[tools/e2fsprogs.git] / lib / ext2fs / extent.c
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 Library
8  * General Public License, version 2.
9  * %End-Header%
10  */
11
12 #include "config.h"
13 #include <stdio.h>
14 #include <string.h>
15 #if HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif
18 #if HAVE_ERRNO_H
19 #include <errno.h>
20 #endif
21 #if HAVE_SYS_STAT_H
22 #include <sys/stat.h>
23 #endif
24 #if HAVE_SYS_TYPES_H
25 #include <sys/types.h>
26 #endif
27
28 #include "ext2_fs.h"
29 #include "ext2fsP.h"
30 #include "e2image.h"
31
32 /*
33  * Definitions to be dropped in lib/ext2fs/ext2fs.h
34  */
35
36 /*
37  * Private definitions
38  */
39
40 struct 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
52 struct ext2_extent_handle {
53         errcode_t               magic;
54         ext2_filsys             fs;
55         ext2_ino_t              ino;
56         struct ext2_inode       *inode;
57         struct ext2_inode       inodebuf;
58         int                     type;
59         int                     level;
60         int                     max_depth;
61         struct extent_path      *path;
62 };
63
64 struct ext2_extent_path {
65         errcode_t               magic;
66         int                     leaf_height;
67         blk64_t                 lblk;
68 };
69
70 /*
71  *  Useful Debugging stuff
72  */
73
74 #ifdef DEBUG
75 static void dbg_show_header(struct ext3_extent_header *eh)
76 {
77         printf("header: magic=%x entries=%u max=%u depth=%u generation=%u\n",
78                         ext2fs_le16_to_cpu(eh->eh_magic),
79                         ext2fs_le16_to_cpu(eh->eh_entries),
80                         ext2fs_le16_to_cpu(eh->eh_max),
81                         ext2fs_le16_to_cpu(eh->eh_depth),
82                         ext2fs_le32_to_cpu(eh->eh_generation));
83 }
84
85 static void dbg_show_index(struct ext3_extent_idx *ix)
86 {
87         printf("index: block=%u leaf=%u leaf_hi=%u unused=%u\n",
88                         ext2fs_le32_to_cpu(ix->ei_block),
89                         ext2fs_le32_to_cpu(ix->ei_leaf),
90                         ext2fs_le16_to_cpu(ix->ei_leaf_hi),
91                         ext2fs_le16_to_cpu(ix->ei_unused));
92 }
93
94 static void dbg_show_extent(struct ext3_extent *ex)
95 {
96         printf("extent: block=%u-%u len=%u start=%u start_hi=%u\n",
97                         ext2fs_le32_to_cpu(ex->ee_block),
98                         ext2fs_le32_to_cpu(ex->ee_block) +
99                         ext2fs_le16_to_cpu(ex->ee_len) - 1,
100                         ext2fs_le16_to_cpu(ex->ee_len),
101                         ext2fs_le32_to_cpu(ex->ee_start),
102                         ext2fs_le16_to_cpu(ex->ee_start_hi));
103 }
104
105 static void dbg_print_extent(char *desc, struct ext2fs_extent *extent)
106 {
107         if (desc)
108                 printf("%s: ", desc);
109         printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ",
110                extent->e_lblk, extent->e_lblk + extent->e_len - 1,
111                extent->e_len, extent->e_pblk);
112         if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF)
113                 fputs("LEAF ", stdout);
114         if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
115                 fputs("UNINIT ", stdout);
116         if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
117                 fputs("2ND_VISIT ", stdout);
118         if (!extent->e_flags)
119                 fputs("(none)", stdout);
120         fputc('\n', stdout);
121
122 }
123
124 #else
125 #define dbg_show_header(eh) do { } while (0)
126 #define dbg_show_index(ix) do { } while (0)
127 #define dbg_show_extent(ex) do { } while (0)
128 #define dbg_print_extent(desc, ex) do { } while (0)
129 #endif
130
131 /*
132  * Verify the extent header as being sane
133  */
134 errcode_t ext2fs_extent_header_verify(void *ptr, int size)
135 {
136         int eh_max, entry_size;
137         struct ext3_extent_header *eh = ptr;
138
139         dbg_show_header(eh);
140         if (ext2fs_le16_to_cpu(eh->eh_magic) != EXT3_EXT_MAGIC)
141                 return EXT2_ET_EXTENT_HEADER_BAD;
142         if (ext2fs_le16_to_cpu(eh->eh_entries) > ext2fs_le16_to_cpu(eh->eh_max))
143                 return EXT2_ET_EXTENT_HEADER_BAD;
144         if (eh->eh_depth == 0)
145                 entry_size = sizeof(struct ext3_extent);
146         else
147                 entry_size = sizeof(struct ext3_extent_idx);
148
149         eh_max = (size - sizeof(*eh)) / entry_size;
150         /* Allow two extent-sized items at the end of the block, for
151          * ext4_extent_tail with checksum in the future. */
152         if ((ext2fs_le16_to_cpu(eh->eh_max) > eh_max) ||
153             (ext2fs_le16_to_cpu(eh->eh_max) < (eh_max - 2)))
154                 return EXT2_ET_EXTENT_HEADER_BAD;
155
156         return 0;
157 }
158
159
160 /*
161  * Begin functions to handle an inode's extent information
162  */
163 extern void ext2fs_extent_free(ext2_extent_handle_t handle)
164 {
165         int                     i;
166
167         if (!handle)
168                 return;
169
170         if (handle->path) {
171                 for (i=1; i <= handle->max_depth; i++) {
172                         if (handle->path[i].buf)
173                                 ext2fs_free_mem(&handle->path[i].buf);
174                 }
175                 ext2fs_free_mem(&handle->path);
176         }
177         ext2fs_free_mem(&handle);
178 }
179
180 extern errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino,
181                                     ext2_extent_handle_t *ret_handle)
182 {
183         return ext2fs_extent_open2(fs, ino, NULL, ret_handle);
184 }
185
186 extern errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
187                                     struct ext2_inode *inode,
188                                     ext2_extent_handle_t *ret_handle)
189 {
190         struct ext2_extent_handle       *handle;
191         errcode_t                       retval;
192         int                             i;
193         struct ext3_extent_header       *eh;
194
195         EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
196
197         if (!inode)
198                 if ((ino == 0) || (ino > fs->super->s_inodes_count))
199                         return EXT2_ET_BAD_INODE_NUM;
200
201         retval = ext2fs_get_mem(sizeof(struct ext2_extent_handle), &handle);
202         if (retval)
203                 return retval;
204         memset(handle, 0, sizeof(struct ext2_extent_handle));
205
206         handle->ino = ino;
207         handle->fs = fs;
208
209         if (inode) {
210                 handle->inode = inode;
211         } else {
212                 handle->inode = &handle->inodebuf;
213                 retval = ext2fs_read_inode(fs, ino, handle->inode);
214                 if (retval)
215                         goto errout;
216         }
217
218         eh = (struct ext3_extent_header *) &handle->inode->i_block[0];
219
220         for (i=0; i < EXT2_N_BLOCKS; i++)
221                 if (handle->inode->i_block[i])
222                         break;
223         if (i >= EXT2_N_BLOCKS) {
224                 eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
225                 eh->eh_depth = 0;
226                 eh->eh_entries = 0;
227                 i = (sizeof(handle->inode->i_block) - sizeof(*eh)) /
228                         sizeof(struct ext3_extent);
229                 eh->eh_max = ext2fs_cpu_to_le16(i);
230                 handle->inode->i_flags |= EXT4_EXTENTS_FL;
231         }
232
233         if (!(handle->inode->i_flags & EXT4_EXTENTS_FL)) {
234                 retval = EXT2_ET_INODE_NOT_EXTENT;
235                 goto errout;
236         }
237
238         retval = ext2fs_extent_header_verify(eh, sizeof(handle->inode->i_block));
239         if (retval)
240                 goto errout;
241
242         handle->max_depth = ext2fs_le16_to_cpu(eh->eh_depth);
243         handle->type = ext2fs_le16_to_cpu(eh->eh_magic);
244
245         retval = ext2fs_get_mem(((handle->max_depth+1) *
246                                  sizeof(struct extent_path)),
247                                 &handle->path);
248         memset(handle->path, 0,
249                (handle->max_depth+1) * sizeof(struct extent_path));
250         handle->path[0].buf = (char *) handle->inode->i_block;
251
252         handle->path[0].left = handle->path[0].entries =
253                 ext2fs_le16_to_cpu(eh->eh_entries);
254         handle->path[0].max_entries = ext2fs_le16_to_cpu(eh->eh_max);
255         handle->path[0].curr = 0;
256         handle->path[0].end_blk =
257                 (EXT2_I_SIZE(handle->inode) + fs->blocksize - 1) >>
258                  EXT2_BLOCK_SIZE_BITS(fs->super);
259         handle->path[0].visit_num = 1;
260         handle->level = 0;
261         handle->magic = EXT2_ET_MAGIC_EXTENT_HANDLE;
262
263         *ret_handle = handle;
264         return 0;
265
266 errout:
267         ext2fs_extent_free(handle);
268         return retval;
269 }
270
271 /*
272  * This function is responsible for (optionally) moving through the
273  * extent tree and then returning the current extent
274  */
275 errcode_t ext2fs_extent_get(ext2_extent_handle_t handle,
276                             int flags, struct ext2fs_extent *extent)
277 {
278         struct extent_path      *path, *newpath;
279         struct ext3_extent_header       *eh;
280         struct ext3_extent_idx          *ix = 0;
281         struct ext3_extent              *ex;
282         errcode_t                       retval;
283         blk64_t                         blk;
284         blk64_t                         end_blk;
285         int                             orig_op, op;
286
287         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
288
289         if (!handle->path)
290                 return EXT2_ET_NO_CURRENT_NODE;
291
292         orig_op = op = flags & EXT2_EXTENT_MOVE_MASK;
293
294 retry:
295         path = handle->path + handle->level;
296         if ((orig_op == EXT2_EXTENT_NEXT) ||
297             (orig_op == EXT2_EXTENT_NEXT_LEAF)) {
298                 if (handle->level < handle->max_depth) {
299                         /* interior node */
300                         if (path->visit_num == 0) {
301                                 path->visit_num++;
302                                 op = EXT2_EXTENT_DOWN;
303                         } else if (path->left > 0)
304                                 op = EXT2_EXTENT_NEXT_SIB;
305                         else if (handle->level > 0)
306                                 op = EXT2_EXTENT_UP;
307                         else
308                                 return EXT2_ET_EXTENT_NO_NEXT;
309                 } else {
310                         /* leaf node */
311                         if (path->left > 0)
312                                 op = EXT2_EXTENT_NEXT_SIB;
313                         else if (handle->level > 0)
314                                 op = EXT2_EXTENT_UP;
315                         else
316                                 return EXT2_ET_EXTENT_NO_NEXT;
317                 }
318                 if (op != EXT2_EXTENT_NEXT_SIB) {
319 #ifdef DEBUG_GET_EXTENT
320                         printf("<<<< OP = %s\n",
321                                (op == EXT2_EXTENT_DOWN) ? "down" :
322                                ((op == EXT2_EXTENT_UP) ? "up" : "unknown"));
323 #endif
324                 }
325         }
326
327         if ((orig_op == EXT2_EXTENT_PREV) ||
328             (orig_op == EXT2_EXTENT_PREV_LEAF)) {
329                 if (handle->level < handle->max_depth) {
330                         /* interior node */
331                         if (path->visit_num > 0 ) {
332                                 /* path->visit_num = 0; */
333                                 op = EXT2_EXTENT_DOWN_AND_LAST;
334                         } else if (path->left < path->entries-1)
335                                 op = EXT2_EXTENT_PREV_SIB;
336                         else if (handle->level > 0)
337                                 op = EXT2_EXTENT_UP;
338                         else
339                                 return EXT2_ET_EXTENT_NO_PREV;
340                 } else {
341                         /* leaf node */
342                         if (path->left < path->entries-1)
343                                 op = EXT2_EXTENT_PREV_SIB;
344                         else if (handle->level > 0)
345                                 op = EXT2_EXTENT_UP;
346                         else
347                                 return EXT2_ET_EXTENT_NO_PREV;
348                 }
349                 if (op != EXT2_EXTENT_PREV_SIB) {
350 #ifdef DEBUG_GET_EXTENT
351                         printf("<<<< OP = %s\n",
352                                (op == EXT2_EXTENT_DOWN_AND_LAST) ? "down/last" :
353                                ((op == EXT2_EXTENT_UP) ? "up" : "unknown"));
354 #endif
355                 }
356         }
357
358         if (orig_op == EXT2_EXTENT_LAST_LEAF) {
359                 if ((handle->level < handle->max_depth) &&
360                     (path->left == 0))
361                         op = EXT2_EXTENT_DOWN;
362                 else
363                         op = EXT2_EXTENT_LAST_SIB;
364 #ifdef DEBUG_GET_EXTENT
365                 printf("<<<< OP = %s\n",
366                            (op == EXT2_EXTENT_DOWN) ? "down" : "last_sib");
367 #endif
368         }
369
370         switch (op) {
371         case EXT2_EXTENT_CURRENT:
372                 ix = path->curr;
373                 break;
374         case EXT2_EXTENT_ROOT:
375                 handle->level = 0;
376                 path = handle->path + handle->level;
377                 /* fallthrough */
378         case EXT2_EXTENT_FIRST_SIB:
379                 path->left = path->entries;
380                 path->curr = 0;
381                 /* fallthrough */
382         case EXT2_EXTENT_NEXT_SIB:
383                 if (path->left <= 0)
384                         return EXT2_ET_EXTENT_NO_NEXT;
385                 if (path->curr) {
386                         ix = path->curr;
387                         ix++;
388                 } else {
389                         eh = (struct ext3_extent_header *) path->buf;
390                         ix = EXT_FIRST_INDEX(eh);
391                 }
392                 path->left--;
393                 path->curr = ix;
394                 path->visit_num = 0;
395                 break;
396         case EXT2_EXTENT_PREV_SIB:
397                 if (!path->curr ||
398                     path->left+1 >= path->entries)
399                         return EXT2_ET_EXTENT_NO_PREV;
400                 ix = path->curr;
401                 ix--;
402                 path->curr = ix;
403                 path->left++;
404                 if (handle->level < handle->max_depth)
405                         path->visit_num = 1;
406                 break;
407         case EXT2_EXTENT_LAST_SIB:
408                 eh = (struct ext3_extent_header *) path->buf;
409                 path->curr = EXT_LAST_EXTENT(eh);
410                 ix = path->curr;
411                 path->left = 0;
412                 path->visit_num = 0;
413                 break;
414         case EXT2_EXTENT_UP:
415                 if (handle->level <= 0)
416                         return EXT2_ET_EXTENT_NO_UP;
417                 handle->level--;
418                 path--;
419                 ix = path->curr;
420                 if ((orig_op == EXT2_EXTENT_PREV) ||
421                     (orig_op == EXT2_EXTENT_PREV_LEAF))
422                         path->visit_num = 0;
423                 break;
424         case EXT2_EXTENT_DOWN:
425         case EXT2_EXTENT_DOWN_AND_LAST:
426                 if (!path->curr ||(handle->level >= handle->max_depth))
427                         return EXT2_ET_EXTENT_NO_DOWN;
428
429                 ix = path->curr;
430                 newpath = path + 1;
431                 if (!newpath->buf) {
432                         retval = ext2fs_get_mem(handle->fs->blocksize,
433                                                 &newpath->buf);
434                         if (retval)
435                                 return retval;
436                 }
437                 blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
438                         ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
439                 if ((handle->fs->flags & EXT2_FLAG_IMAGE_FILE) &&
440                     (handle->fs->io != handle->fs->image_io))
441                         memset(newpath->buf, 0, handle->fs->blocksize);
442                 else {
443                         retval = io_channel_read_blk64(handle->fs->io,
444                                                      blk, 1, newpath->buf);
445                         if (retval)
446                                 return retval;
447                 }
448                 handle->level++;
449
450                 eh = (struct ext3_extent_header *) newpath->buf;
451
452                 retval = ext2fs_extent_header_verify(eh, handle->fs->blocksize);
453                 if (retval) {
454                         handle->level--;
455                         return retval;
456                 }
457
458                 newpath->left = newpath->entries =
459                         ext2fs_le16_to_cpu(eh->eh_entries);
460                 newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max);
461
462                 if (path->left > 0) {
463                         ix++;
464                         newpath->end_blk = ext2fs_le32_to_cpu(ix->ei_block);
465                 } else
466                         newpath->end_blk = path->end_blk;
467
468                 path = newpath;
469                 if (op == EXT2_EXTENT_DOWN) {
470                         ix = EXT_FIRST_INDEX((struct ext3_extent_header *) eh);
471                         path->curr = ix;
472                         path->left = path->entries - 1;
473                         path->visit_num = 0;
474                 } else {
475                         ix = EXT_LAST_INDEX((struct ext3_extent_header *) eh);
476                         path->curr = ix;
477                         path->left = 0;
478                         if (handle->level < handle->max_depth)
479                                 path->visit_num = 1;
480                 }
481 #ifdef DEBUG_GET_EXTENT
482                 printf("Down to level %d/%d, end_blk=%llu\n",
483                            handle->level, handle->max_depth,
484                            path->end_blk);
485 #endif
486                 break;
487         default:
488                 return EXT2_ET_OP_NOT_SUPPORTED;
489         }
490
491         if (!ix)
492                 return EXT2_ET_NO_CURRENT_NODE;
493
494         extent->e_flags = 0;
495 #ifdef DEBUG_GET_EXTENT
496         printf("(Left %d)\n", path->left);
497 #endif
498
499         if (handle->level == handle->max_depth) {
500                 ex = (struct ext3_extent *) ix;
501
502                 extent->e_pblk = ext2fs_le32_to_cpu(ex->ee_start) +
503                         ((__u64) ext2fs_le16_to_cpu(ex->ee_start_hi) << 32);
504                 extent->e_lblk = ext2fs_le32_to_cpu(ex->ee_block);
505                 extent->e_len = ext2fs_le16_to_cpu(ex->ee_len);
506                 extent->e_flags |= EXT2_EXTENT_FLAGS_LEAF;
507                 if (extent->e_len > EXT_INIT_MAX_LEN) {
508                         extent->e_len -= EXT_INIT_MAX_LEN;
509                         extent->e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
510                 }
511         } else {
512                 extent->e_pblk = ext2fs_le32_to_cpu(ix->ei_leaf) +
513                         ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
514                 extent->e_lblk = ext2fs_le32_to_cpu(ix->ei_block);
515                 if (path->left > 0) {
516                         ix++;
517                         end_blk = ext2fs_le32_to_cpu(ix->ei_block);
518                 } else
519                         end_blk = path->end_blk;
520
521                 extent->e_len = end_blk - extent->e_lblk;
522         }
523         if (path->visit_num)
524                 extent->e_flags |= EXT2_EXTENT_FLAGS_SECOND_VISIT;
525
526         if (((orig_op == EXT2_EXTENT_NEXT_LEAF) ||
527              (orig_op == EXT2_EXTENT_PREV_LEAF)) &&
528             (handle->level != handle->max_depth))
529                 goto retry;
530
531         if ((orig_op == EXT2_EXTENT_LAST_LEAF) &&
532             ((handle->level != handle->max_depth) ||
533              (path->left != 0)))
534                 goto retry;
535
536         return 0;
537 }
538
539 static errcode_t update_path(ext2_extent_handle_t handle)
540 {
541         blk64_t                         blk;
542         errcode_t                       retval;
543         struct ext3_extent_idx          *ix;
544
545         if (handle->level == 0) {
546                 retval = ext2fs_write_inode(handle->fs, handle->ino,
547                                             handle->inode);
548         } else {
549                 ix = handle->path[handle->level - 1].curr;
550                 blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
551                         ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
552
553                 retval = io_channel_write_blk64(handle->fs->io,
554                                       blk, 1, handle->path[handle->level].buf);
555         }
556         return retval;
557 }
558
559 #if 0
560 errcode_t ext2fs_extent_save_path(ext2_extent_handle_t handle,
561                                   ext2_extent_path_t *ret_path)
562 {
563         ext2_extent_path_t      save_path;
564         struct ext2fs_extent    extent;
565         struct ext2_extent_info info;
566         errcode_t               retval;
567
568         retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
569         if (retval)
570                 return retval;
571
572         retval = ext2fs_extent_get_info(handle, &info);
573         if (retval)
574                 return retval;
575
576         retval = ext2fs_get_mem(sizeof(struct ext2_extent_path), &save_path);
577         if (retval)
578                 return retval;
579         memset(save_path, 0, sizeof(struct ext2_extent_path));
580
581         save_path->magic = EXT2_ET_MAGIC_EXTENT_PATH;
582         save_path->leaf_height = info.max_depth - info.curr_level - 1;
583         save_path->lblk = extent.e_lblk;
584
585         *ret_path = save_path;
586         return 0;
587 }
588
589 errcode_t ext2fs_extent_free_path(ext2_extent_path_t path)
590 {
591         EXT2_CHECK_MAGIC(path, EXT2_ET_MAGIC_EXTENT_PATH);
592
593         ext2fs_free_mem(&path);
594         return 0;
595 }
596 #endif
597
598 /*
599  * Go to the node at leaf_level which contains logical block blk.
600  *
601  * leaf_level is height from the leaf node level, i.e.
602  * leaf_level 0 is at leaf node, leaf_level 1 is 1 above etc.
603  *
604  * If "blk" has no mapping (hole) then handle is left at last
605  * extent before blk.
606  */
607 static errcode_t extent_goto(ext2_extent_handle_t handle,
608                              int leaf_level, blk64_t blk)
609 {
610         struct ext2fs_extent    extent;
611         errcode_t               retval;
612
613         retval = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent);
614         if (retval) {
615                 if (retval == EXT2_ET_EXTENT_NO_NEXT)
616                         retval = EXT2_ET_EXTENT_NOT_FOUND;
617                 return retval;
618         }
619
620         if (leaf_level > handle->max_depth) {
621 #ifdef DEBUG
622                 printf("leaf level %d greater than tree depth %d\n",
623                         leaf_level, handle->max_depth);
624 #endif
625                 return EXT2_ET_OP_NOT_SUPPORTED;
626         }
627
628 #ifdef DEBUG
629         printf("goto extent ino %u, level %d, %llu\n", handle->ino,
630                leaf_level, blk);
631 #endif
632
633 #ifdef DEBUG_GOTO_EXTENTS
634         dbg_print_extent("root", &extent);
635 #endif
636         while (1) {
637                 if (handle->max_depth - handle->level == leaf_level) {
638                         /* block is in this &extent */
639                         if ((blk >= extent.e_lblk) &&
640                             (blk < extent.e_lblk + extent.e_len))
641                                 return 0;
642                         if (blk < extent.e_lblk) {
643                                 retval = ext2fs_extent_get(handle,
644                                                            EXT2_EXTENT_PREV_SIB,
645                                                            &extent);
646                                 return EXT2_ET_EXTENT_NOT_FOUND;
647                         }
648                         retval = ext2fs_extent_get(handle,
649                                                    EXT2_EXTENT_NEXT_SIB,
650                                                    &extent);
651                         if (retval == EXT2_ET_EXTENT_NO_NEXT)
652                                 return EXT2_ET_EXTENT_NOT_FOUND;
653                         if (retval)
654                                 return retval;
655                         continue;
656                 }
657
658                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_SIB,
659                                            &extent);
660                 if (retval == EXT2_ET_EXTENT_NO_NEXT)
661                         goto go_down;
662                 if (retval)
663                         return retval;
664
665 #ifdef DEBUG_GOTO_EXTENTS
666                 dbg_print_extent("next", &extent);
667 #endif
668                 if (blk == extent.e_lblk)
669                         goto go_down;
670                 if (blk > extent.e_lblk)
671                         continue;
672
673                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_PREV_SIB,
674                                            &extent);
675                 if (retval)
676                         return retval;
677
678 #ifdef DEBUG_GOTO_EXTENTS
679                 dbg_print_extent("prev", &extent);
680 #endif
681
682         go_down:
683                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_DOWN,
684                                            &extent);
685                 if (retval)
686                         return retval;
687
688 #ifdef DEBUG_GOTO_EXTENTS
689                 dbg_print_extent("down", &extent);
690 #endif
691         }
692 }
693
694 errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
695                              blk64_t blk)
696 {
697         return extent_goto(handle, 0, blk);
698 }
699
700 /*
701  * Traverse back up to root fixing parents of current node as needed.
702  *
703  * If we changed start of first entry in a node, fix parent index start
704  * and so on.
705  *
706  * Safe to call for any position in node; if not at the first entry,
707  * will  simply return.
708  */
709 static errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle)
710 {
711         int                             retval = 0;
712         blk64_t                         start;
713         struct extent_path              *path;
714         struct ext2fs_extent            extent;
715
716         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
717
718         if (!(handle->fs->flags & EXT2_FLAG_RW))
719                 return EXT2_ET_RO_FILSYS;
720
721         if (!handle->path)
722                 return EXT2_ET_NO_CURRENT_NODE;
723
724         path = handle->path + handle->level;
725         if (!path->curr)
726                 return EXT2_ET_NO_CURRENT_NODE;
727
728         retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
729         if (retval)
730                 goto done;
731
732         /* modified node's start block */
733         start = extent.e_lblk;
734
735         /* traverse up until index not first, or startblk matches, or top */
736         while (handle->level > 0 &&
737                (path->left == path->entries - 1)) {
738                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent);
739                 if (retval)
740                         goto done;
741                 if (extent.e_lblk == start)
742                         break;
743                 path = handle->path + handle->level;
744                 extent.e_len += (extent.e_lblk - start);
745                 extent.e_lblk = start;
746                 retval = ext2fs_extent_replace(handle, 0, &extent);
747                 if (retval)
748                         goto done;
749                 update_path(handle);
750         }
751
752         /* put handle back to where we started */
753         retval = ext2fs_extent_goto(handle, start);
754 done:
755         return retval;
756 }
757
758 errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle,
759                                 int flags EXT2FS_ATTR((unused)),
760                                 struct ext2fs_extent *extent)
761 {
762         struct extent_path              *path;
763         struct ext3_extent_idx          *ix;
764         struct ext3_extent              *ex;
765
766         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
767
768         if (!(handle->fs->flags & EXT2_FLAG_RW))
769                 return EXT2_ET_RO_FILSYS;
770
771         if (!handle->path)
772                 return EXT2_ET_NO_CURRENT_NODE;
773
774         path = handle->path + handle->level;
775         if (!path->curr)
776                 return EXT2_ET_NO_CURRENT_NODE;
777
778 #ifdef DEBUG
779         printf("extent replace: %u ", handle->ino);
780         dbg_print_extent(0, extent);
781 #endif
782
783         if (handle->level == handle->max_depth) {
784                 ex = path->curr;
785
786                 ex->ee_block = ext2fs_cpu_to_le32(extent->e_lblk);
787                 ex->ee_start = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF);
788                 ex->ee_start_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32);
789                 if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) {
790                         if (extent->e_len > EXT_UNINIT_MAX_LEN)
791                                 return EXT2_ET_EXTENT_INVALID_LENGTH;
792                         ex->ee_len = ext2fs_cpu_to_le16(extent->e_len +
793                                                         EXT_INIT_MAX_LEN);
794                 } else {
795                         if (extent->e_len > EXT_INIT_MAX_LEN)
796                                 return EXT2_ET_EXTENT_INVALID_LENGTH;
797                         ex->ee_len = ext2fs_cpu_to_le16(extent->e_len);
798                 }
799         } else {
800                 ix = path->curr;
801
802                 ix->ei_leaf = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF);
803                 ix->ei_leaf_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32);
804                 ix->ei_block = ext2fs_cpu_to_le32(extent->e_lblk);
805                 ix->ei_unused = 0;
806         }
807         update_path(handle);
808         return 0;
809 }
810
811 /*
812  * allocate a new block, move half the current node to it, and update parent
813  *
814  * handle will be left pointing at original record.
815  */
816 static errcode_t extent_node_split(ext2_extent_handle_t handle)
817 {
818         errcode_t                       retval = 0;
819         blk64_t                         new_node_pblk;
820         blk64_t                         new_node_start;
821         blk64_t                         orig_lblk;
822         blk64_t                         goal_blk = 0;
823         int                             orig_height;
824         char                            *block_buf = NULL;
825         struct ext2fs_extent            extent;
826         struct extent_path              *path, *newpath = 0;
827         struct ext3_extent_header       *eh, *neweh;
828         int                             tocopy;
829         int                             new_root = 0;
830         struct ext2_extent_info         info;
831
832         /* basic sanity */
833         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
834
835         if (!(handle->fs->flags & EXT2_FLAG_RW))
836                 return EXT2_ET_RO_FILSYS;
837
838         if (!handle->path)
839                 return EXT2_ET_NO_CURRENT_NODE;
840
841 #ifdef DEBUG
842         printf("splitting node at level %d\n", handle->level);
843 #endif
844         retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
845         if (retval)
846                 goto done;
847
848         retval = ext2fs_extent_get_info(handle, &info);
849         if (retval)
850                 goto done;
851
852         /* save the position we were originally splitting... */
853         orig_height = info.max_depth - info.curr_level;
854         orig_lblk = extent.e_lblk;
855
856         /* Is there room in the parent for a new entry? */
857         if (handle->level &&
858                         (handle->path[handle->level - 1].entries >=
859                          handle->path[handle->level - 1].max_entries)) {
860
861 #ifdef DEBUG
862                 printf("parent level %d full; splitting it too\n",
863                                                         handle->level - 1);
864 #endif
865                 /* split the parent */
866                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent);
867                 if (retval)
868                         goto done;
869                 goal_blk = extent.e_pblk;
870
871                 retval = extent_node_split(handle);
872                 if (retval)
873                         goto done;
874
875                 /* get handle back to our original split position */
876                 retval = extent_goto(handle, orig_height, orig_lblk);
877                 if (retval)
878                         goto done;
879         }
880
881         /* At this point, parent should have room for this split */
882         path = handle->path + handle->level;
883         if (!path->curr)
884                 return EXT2_ET_NO_CURRENT_NODE;
885
886         /* extent header of the current node we'll split */
887         eh = (struct ext3_extent_header *)path->buf;
888
889         /* splitting root level means moving them all out */
890         if (handle->level == 0) {
891                 new_root = 1;
892                 tocopy = ext2fs_le16_to_cpu(eh->eh_entries);
893                 retval = ext2fs_get_mem(((handle->max_depth+2) *
894                                          sizeof(struct extent_path)),
895                                         &newpath);
896                 if (retval)
897                         goto done;
898                 memset(newpath, 0,
899                        ((handle->max_depth+2) * sizeof(struct extent_path)));
900         } else {
901                 tocopy = ext2fs_le16_to_cpu(eh->eh_entries) / 2;
902         }
903
904 #ifdef DEBUG
905         printf("will copy out %d of %d entries at level %d\n",
906                                 tocopy, ext2fs_le16_to_cpu(eh->eh_entries),
907                                 handle->level);
908 #endif
909
910         if (!tocopy) {
911 #ifdef DEBUG
912                 printf("Nothing to copy to new block!\n");
913 #endif
914                 retval = EXT2_ET_CANT_SPLIT_EXTENT;
915                 goto done;
916         }
917
918         /* first we need a new block, or can do nothing. */
919         block_buf = malloc(handle->fs->blocksize);
920         if (!block_buf) {
921                 retval = ENOMEM;
922                 goto done;
923         }
924
925         if (!goal_blk) {
926                 dgrp_t  group = ext2fs_group_of_ino(handle->fs, handle->ino);
927                 __u8    log_flex = handle->fs->super->s_log_groups_per_flex;
928
929                 if (log_flex)
930                         group = group & ~((1 << (log_flex)) - 1);
931                 goal_blk = (group * handle->fs->super->s_blocks_per_group) +
932                         handle->fs->super->s_first_data_block;
933         }
934         retval = ext2fs_alloc_block2(handle->fs, goal_blk, block_buf,
935                                     &new_node_pblk);
936         if (retval)
937                 goto done;
938
939 #ifdef DEBUG
940         printf("will copy to new node at block %lu\n",
941                (unsigned long) new_node_pblk);
942 #endif
943
944         /* Copy data into new block buffer */
945         /* First the header for the new block... */
946         neweh = (struct ext3_extent_header *) block_buf;
947         memcpy(neweh, eh, sizeof(struct ext3_extent_header));
948         neweh->eh_entries = ext2fs_cpu_to_le16(tocopy);
949         neweh->eh_max = ext2fs_cpu_to_le16((handle->fs->blocksize -
950                          sizeof(struct ext3_extent_header)) /
951                                 sizeof(struct ext3_extent));
952
953         /* then the entries for the new block... */
954         memcpy(EXT_FIRST_INDEX(neweh),
955                 EXT_FIRST_INDEX(eh) +
956                         (ext2fs_le16_to_cpu(eh->eh_entries) - tocopy),
957                 sizeof(struct ext3_extent_idx) * tocopy);
958
959         new_node_start = ext2fs_le32_to_cpu(EXT_FIRST_INDEX(neweh)->ei_block);
960
961         /* ...and write the new node block out to disk. */
962         retval = io_channel_write_blk64(handle->fs->io, new_node_pblk, 1,
963                                         block_buf);
964
965         if (retval)
966                 goto done;
967
968         /* OK! we've created the new node; now adjust the tree */
969
970         /* current path now has fewer active entries, we copied some out */
971         if (handle->level == 0) {
972                 memcpy(newpath, path,
973                        sizeof(struct extent_path) * (handle->max_depth+1));
974                 handle->path = newpath;
975                 newpath = path;
976                 path = handle->path;
977                 path->entries = 1;
978                 path->left = path->max_entries - 1;
979                 handle->max_depth++;
980                 eh->eh_depth = ext2fs_cpu_to_le16(handle->max_depth);
981         } else {
982                 path->entries -= tocopy;
983                 path->left -= tocopy;
984         }
985
986         eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
987         /* this writes out the node, incl. the modified header */
988         retval = update_path(handle);
989         if (retval)
990                 goto done;
991
992         /* now go up and insert/replace index for new node we created */
993         if (new_root) {
994                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_FIRST_SIB, &extent);
995                 if (retval)
996                         goto done;
997
998                 extent.e_lblk = new_node_start;
999                 extent.e_pblk = new_node_pblk;
1000                 extent.e_len = handle->path[0].end_blk - extent.e_lblk;
1001                 retval = ext2fs_extent_replace(handle, 0, &extent);
1002                 if (retval)
1003                         goto done;
1004         } else {
1005                 __u32 new_node_length;
1006
1007                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent);
1008                 /* will insert after this one; it's length is shorter now */
1009                 new_node_length = new_node_start - extent.e_lblk;
1010                 extent.e_len -= new_node_length;
1011                 retval = ext2fs_extent_replace(handle, 0, &extent);
1012                 if (retval)
1013                         goto done;
1014
1015                 /* now set up the new extent and insert it */
1016                 extent.e_lblk = new_node_start;
1017                 extent.e_pblk = new_node_pblk;
1018                 extent.e_len = new_node_length;
1019                 retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER, &extent);
1020                 if (retval)
1021                         goto done;
1022         }
1023
1024         /* get handle back to our original position */
1025         retval = extent_goto(handle, orig_height, orig_lblk);
1026         if (retval)
1027                 goto done;
1028
1029         /* new node hooked in, so update inode block count (do this here?) */
1030         handle->inode->i_blocks += handle->fs->blocksize / 512;
1031         retval = ext2fs_write_inode(handle->fs, handle->ino,
1032                                     handle->inode);
1033         if (retval)
1034                 goto done;
1035
1036 done:
1037         if (newpath)
1038                 ext2fs_free_mem(&newpath);
1039         free(block_buf);
1040
1041         return retval;
1042 }
1043
1044 errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags,
1045                                       struct ext2fs_extent *extent)
1046 {
1047         struct extent_path              *path;
1048         struct ext3_extent_idx          *ix;
1049         struct ext3_extent_header       *eh;
1050         errcode_t                       retval;
1051
1052         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
1053
1054         if (!(handle->fs->flags & EXT2_FLAG_RW))
1055                 return EXT2_ET_RO_FILSYS;
1056
1057         if (!handle->path)
1058                 return EXT2_ET_NO_CURRENT_NODE;
1059
1060 #ifdef DEBUG
1061         printf("extent insert: %u ", handle->ino);
1062         dbg_print_extent(0, extent);
1063 #endif
1064
1065         path = handle->path + handle->level;
1066
1067         if (path->entries >= path->max_entries) {
1068                 if (flags & EXT2_EXTENT_INSERT_NOSPLIT) {
1069                         return EXT2_ET_CANT_INSERT_EXTENT;
1070                 } else {
1071 #ifdef DEBUG
1072                         printf("node full (level %d) - splitting\n",
1073                                    handle->level);
1074 #endif
1075                         retval = extent_node_split(handle);
1076                         if (retval)
1077                                 return retval;
1078                         path = handle->path + handle->level;
1079                 }
1080         }
1081
1082         eh = (struct ext3_extent_header *) path->buf;
1083         if (path->curr) {
1084                 ix = path->curr;
1085                 if (flags & EXT2_EXTENT_INSERT_AFTER) {
1086                         ix++;
1087                         path->left--;
1088                 }
1089         } else
1090                 ix = EXT_FIRST_INDEX(eh);
1091
1092         path->curr = ix;
1093
1094         if (path->left >= 0)
1095                 memmove(ix + 1, ix,
1096                         (path->left+1) * sizeof(struct ext3_extent_idx));
1097         path->left++;
1098         path->entries++;
1099
1100         eh = (struct ext3_extent_header *) path->buf;
1101         eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
1102
1103         retval = ext2fs_extent_replace(handle, 0, extent);
1104         if (retval)
1105                 goto errout;
1106
1107         retval = update_path(handle);
1108         if (retval)
1109                 goto errout;
1110
1111         return 0;
1112
1113 errout:
1114         ext2fs_extent_delete(handle, 0);
1115         return retval;
1116 }
1117
1118 /*
1119  * Sets the physical block for a logical file block in the extent tree.
1120  *
1121  * May: map unmapped, unmap mapped, or remap mapped blocks.
1122  *
1123  * Mapping an unmapped block adds a single-block extent.
1124  *
1125  * Unmapping first or last block modifies extent in-place
1126  *  - But may need to fix parent's starts too in first-block case
1127  *
1128  * Mapping any unmapped block requires adding a (single-block) extent
1129  * and inserting into proper point in tree.
1130  *
1131  * Modifying (unmapping or remapping) a block in the middle
1132  * of an extent requires splitting the extent.
1133  *  - Remapping case requires new single-block extent.
1134  *
1135  * Remapping first or last block adds an extent.
1136  *
1137  * We really need extent adding to be smart about merging.
1138  */
1139
1140 errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
1141                                  blk64_t logical, blk64_t physical, int flags)
1142 {
1143         errcode_t               ec, retval = 0;
1144         int                     mapped = 1; /* logical is mapped? */
1145         int                     orig_height;
1146         int                     extent_uninit = 0;
1147         int                     prev_uninit = 0;
1148         int                     next_uninit = 0;
1149         int                     new_uninit = 0;
1150         int                     max_len = EXT_INIT_MAX_LEN;
1151         int                     has_prev, has_next;
1152         blk64_t                 orig_lblk;
1153         struct extent_path      *path;
1154         struct ext2fs_extent    extent, next_extent, prev_extent;
1155         struct ext2fs_extent    newextent;
1156         struct ext2_extent_info info;
1157
1158         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
1159
1160 #ifdef DEBUG
1161         printf("set_bmap ino %u log %lld phys %lld flags %d\n",
1162                handle->ino, logical, physical, flags);
1163 #endif
1164
1165         if (!(handle->fs->flags & EXT2_FLAG_RW))
1166                 return EXT2_ET_RO_FILSYS;
1167
1168         if (!handle->path)
1169                 return EXT2_ET_NO_CURRENT_NODE;
1170
1171         path = handle->path + handle->level;
1172
1173         if (flags & EXT2_EXTENT_SET_BMAP_UNINIT) {
1174                 new_uninit = 1;
1175                 max_len = EXT_UNINIT_MAX_LEN;
1176         }
1177
1178         /* if (re)mapping, set up new extent to insert */
1179         if (physical) {
1180                 newextent.e_len = 1;
1181                 newextent.e_pblk = physical;
1182                 newextent.e_lblk = logical;
1183                 newextent.e_flags = EXT2_EXTENT_FLAGS_LEAF;
1184                 if (new_uninit)
1185                         newextent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
1186         }
1187
1188         /* special case if the extent tree is completely empty */
1189         if ((handle->max_depth == 0) && (path->entries == 0)) {
1190                 retval = ext2fs_extent_insert(handle, 0, &newextent);
1191                 return retval;
1192         }
1193
1194         /* save our original location in the extent tree */
1195         if ((retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
1196                                         &extent))) {
1197                 if (retval != EXT2_ET_NO_CURRENT_NODE)
1198                         return retval;
1199                 memset(&extent, 0, sizeof(extent));
1200         }
1201         if ((retval = ext2fs_extent_get_info(handle, &info)))
1202                 return retval;
1203         orig_height = info.max_depth - info.curr_level;
1204         orig_lblk = extent.e_lblk;
1205
1206         /* go to the logical spot we want to (re/un)map */
1207         retval = ext2fs_extent_goto(handle, logical);
1208         if (retval) {
1209                 if (retval == EXT2_ET_EXTENT_NOT_FOUND) {
1210                         retval = 0;
1211                         mapped = 0;
1212                         if (!physical) {
1213 #ifdef DEBUG
1214                                 printf("block %llu already unmapped\n",
1215                                         logical);
1216 #endif
1217                                 goto done;
1218                         }
1219                 } else
1220                         goto done;
1221         }
1222
1223         /*
1224          * This may be the extent *before* the requested logical,
1225          * if it's currently unmapped.
1226          *
1227          * Get the previous and next leaf extents, if they are present.
1228          */
1229         retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
1230         if (retval)
1231                 goto done;
1232         if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
1233                 extent_uninit = 1;
1234         retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, &next_extent);
1235         if (retval) {
1236                 has_next = 0;
1237                 if (retval != EXT2_ET_EXTENT_NO_NEXT)
1238                         goto done;
1239         } else {
1240                 dbg_print_extent("set_bmap: next_extent",
1241                                  &next_extent);
1242                 has_next = 1;
1243                 if (next_extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
1244                         next_uninit = 1;
1245         }
1246         retval = ext2fs_extent_goto(handle, logical);
1247         if (retval && retval != EXT2_ET_EXTENT_NOT_FOUND)
1248                 goto done;
1249         retval = ext2fs_extent_get(handle, EXT2_EXTENT_PREV_LEAF, &prev_extent);
1250         if (retval) {
1251                 has_prev = 0;
1252                 if (retval != EXT2_ET_EXTENT_NO_PREV)
1253                         goto done;
1254         } else {
1255                 has_prev = 1;
1256                 dbg_print_extent("set_bmap: prev_extent",
1257                                  &prev_extent);
1258                 if (prev_extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
1259                         prev_uninit = 1;
1260         }
1261         retval = ext2fs_extent_goto(handle, logical);
1262         if (retval && retval != EXT2_ET_EXTENT_NOT_FOUND)
1263                 goto done;
1264
1265         /* check if already pointing to the requested physical */
1266         if (mapped && (new_uninit == extent_uninit) &&
1267             (extent.e_pblk + (logical - extent.e_lblk) == physical)) {
1268 #ifdef DEBUG
1269                 printf("physical block (at %llu) unchanged\n", logical);
1270 #endif
1271                 goto done;
1272         }
1273
1274         if (!mapped) {
1275 #ifdef DEBUG
1276                 printf("mapping unmapped logical block %llu\n", logical);
1277 #endif
1278                 if ((logical == extent.e_lblk + extent.e_len) &&
1279                     (physical == extent.e_pblk + extent.e_len) &&
1280                     (new_uninit == extent_uninit) &&
1281                     ((int) extent.e_len < max_len-1)) {
1282                         extent.e_len++;
1283                         retval = ext2fs_extent_replace(handle, 0, &extent);
1284                 } else if ((logical == extent.e_lblk - 1) &&
1285                            (physical == extent.e_pblk - 1) &&
1286                            (new_uninit == extent_uninit) &&
1287                            ((int) extent.e_len < max_len - 1)) {
1288                         extent.e_len++;
1289                         extent.e_lblk--;
1290                         extent.e_pblk--;
1291                         retval = ext2fs_extent_replace(handle, 0, &extent);
1292                 } else if (has_next &&
1293                            (logical == next_extent.e_lblk - 1) &&
1294                            (physical == next_extent.e_pblk - 1) &&
1295                            (new_uninit == next_uninit) &&
1296                            ((int) next_extent.e_len < max_len - 1)) {
1297                         retval = ext2fs_extent_get(handle,
1298                                                    EXT2_EXTENT_NEXT_LEAF,
1299                                                    &next_extent);
1300                         if (retval)
1301                                 goto done;
1302                         next_extent.e_len++;
1303                         next_extent.e_lblk--;
1304                         next_extent.e_pblk--;
1305                         retval = ext2fs_extent_replace(handle, 0, &next_extent);
1306                 } else if (logical < extent.e_lblk)
1307                         retval = ext2fs_extent_insert(handle, 0, &newextent);
1308                 else
1309                         retval = ext2fs_extent_insert(handle,
1310                                       EXT2_EXTENT_INSERT_AFTER, &newextent);
1311                 if (retval)
1312                         goto done;
1313                 retval = ext2fs_extent_fix_parents(handle);
1314                 if (retval)
1315                         goto done;
1316         } else if ((logical == extent.e_lblk) && (extent.e_len == 1))  {
1317 #ifdef DEBUG
1318                 printf("(re/un)mapping only block in extent\n");
1319 #endif
1320                 if (physical) {
1321                         retval = ext2fs_extent_replace(handle, 0, &newextent);
1322                 } else {
1323                         retval = ext2fs_extent_delete(handle, 0);
1324                         if (retval)
1325                                 goto done;
1326                         ec = ext2fs_extent_fix_parents(handle);
1327                         if (ec != EXT2_ET_NO_CURRENT_NODE)
1328                                 retval = ec;
1329                 }
1330
1331                 if (retval)
1332                         goto done;
1333         } else if (logical == extent.e_lblk + extent.e_len - 1)  {
1334 #ifdef DEBUG
1335                 printf("(re/un)mapping last block in extent\n");
1336 #endif
1337                 if (physical) {
1338                         if (has_next &&
1339                             (logical == (next_extent.e_lblk - 1)) &&
1340                             (physical == (next_extent.e_pblk - 1)) &&
1341                             (new_uninit == next_uninit) &&
1342                             ((int) next_extent.e_len < max_len - 1)) {
1343                                 retval = ext2fs_extent_get(handle,
1344                                         EXT2_EXTENT_NEXT_LEAF, &next_extent);
1345                                 if (retval)
1346                                         goto done;
1347                                 next_extent.e_len++;
1348                                 next_extent.e_lblk--;
1349                                 next_extent.e_pblk--;
1350                                 retval = ext2fs_extent_replace(handle, 0,
1351                                                                &next_extent);
1352                                 if (retval)
1353                                         goto done;
1354                         } else
1355                                 retval = ext2fs_extent_insert(handle,
1356                                       EXT2_EXTENT_INSERT_AFTER, &newextent);
1357                         if (retval)
1358                                 goto done;
1359                         /* Now pointing at inserted extent; move back to prev */
1360                         retval = ext2fs_extent_get(handle,
1361                                                    EXT2_EXTENT_PREV_LEAF,
1362                                                    &extent);
1363                         if (retval)
1364                                 goto done;
1365                 }
1366                 extent.e_len--;
1367                 retval = ext2fs_extent_replace(handle, 0, &extent);
1368                 if (retval)
1369                         goto done;
1370         } else if (logical == extent.e_lblk) {
1371 #ifdef DEBUG
1372                 printf("(re/un)mapping first block in extent\n");
1373 #endif
1374                 if (physical) {
1375                         if (has_prev &&
1376                             (logical == (prev_extent.e_lblk +
1377                                          prev_extent.e_len)) &&
1378                             (physical == (prev_extent.e_pblk +
1379                                           prev_extent.e_len)) &&
1380                             (new_uninit == prev_uninit) &&
1381                             ((int) prev_extent.e_len < max_len-1)) {
1382                                 retval = ext2fs_extent_get(handle, 
1383                                         EXT2_EXTENT_PREV_LEAF, &prev_extent);
1384                                 if (retval)
1385                                         goto done;
1386                                 prev_extent.e_len++;
1387                                 retval = ext2fs_extent_replace(handle, 0,
1388                                                                &prev_extent);
1389                         } else
1390                                 retval = ext2fs_extent_insert(handle,
1391                                                               0, &newextent);
1392                         if (retval)
1393                                 goto done;
1394                         retval = ext2fs_extent_get(handle,
1395                                                    EXT2_EXTENT_NEXT_LEAF,
1396                                                    &extent);
1397                         if (retval)
1398                                 goto done;
1399                 }
1400                 extent.e_pblk++;
1401                 extent.e_lblk++;
1402                 extent.e_len--;
1403                 retval = ext2fs_extent_replace(handle, 0, &extent);
1404                 if (retval)
1405                         goto done;
1406         } else {
1407                 __u32   orig_length;
1408
1409 #ifdef DEBUG
1410                 printf("(re/un)mapping in middle of extent\n");
1411 #endif
1412                 /* need to split this extent; later */
1413
1414                 orig_length = extent.e_len;
1415
1416                 /* shorten pre-split extent */
1417                 extent.e_len = (logical - extent.e_lblk);
1418                 retval = ext2fs_extent_replace(handle, 0, &extent);
1419                 if (retval)
1420                         goto done;
1421                 /* insert our new extent, if any */
1422                 if (physical) {
1423                         /* insert new extent after current */
1424                         retval = ext2fs_extent_insert(handle,
1425                                         EXT2_EXTENT_INSERT_AFTER, &newextent);
1426                         if (retval)
1427                                 goto done;
1428                 }
1429                 /* add post-split extent */
1430                 extent.e_pblk += extent.e_len + 1;
1431                 extent.e_lblk += extent.e_len + 1;
1432                 extent.e_len = orig_length - extent.e_len - 1;
1433                 retval = ext2fs_extent_insert(handle,
1434                                 EXT2_EXTENT_INSERT_AFTER, &extent);
1435                 if (retval)
1436                         goto done;
1437         }
1438
1439 done:
1440         /* get handle back to its position */
1441         if (orig_height > handle->max_depth)
1442                 orig_height = handle->max_depth; /* In case we shortened the tree */
1443         extent_goto(handle, orig_height, orig_lblk);
1444         return retval;
1445 }
1446
1447 errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, int flags)
1448 {
1449         struct extent_path              *path;
1450         char                            *cp;
1451         struct ext3_extent_header       *eh;
1452         errcode_t                       retval = 0;
1453
1454         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
1455
1456         if (!(handle->fs->flags & EXT2_FLAG_RW))
1457                 return EXT2_ET_RO_FILSYS;
1458
1459         if (!handle->path)
1460                 return EXT2_ET_NO_CURRENT_NODE;
1461
1462 #ifdef DEBUG
1463         {
1464                 struct ext2fs_extent    extent;
1465
1466                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
1467                                            &extent);
1468                 if (retval == 0) {
1469                         printf("extent delete %u ", handle->ino);
1470                         dbg_print_extent(0, &extent);
1471                 }
1472         }
1473 #endif
1474
1475         path = handle->path + handle->level;
1476         if (!path->curr)
1477                 return EXT2_ET_NO_CURRENT_NODE;
1478
1479         cp = path->curr;
1480
1481         if (path->left) {
1482                 memmove(cp, cp + sizeof(struct ext3_extent_idx),
1483                         path->left * sizeof(struct ext3_extent_idx));
1484                 path->left--;
1485         } else {
1486                 struct ext3_extent_idx  *ix = path->curr;
1487                 ix--;
1488                 path->curr = ix;
1489         }
1490         if (--path->entries == 0)
1491                 path->curr = 0;
1492
1493         /* if non-root node has no entries left, remove it & parent ptr to it */
1494         if (path->entries == 0 && handle->level) {
1495                 if (!(flags & EXT2_EXTENT_DELETE_KEEP_EMPTY)) {
1496                         struct ext2fs_extent    extent;
1497
1498                         retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP,
1499                                                                 &extent);
1500                         if (retval)
1501                                 return retval;
1502
1503                         retval = ext2fs_extent_delete(handle, flags);
1504                         handle->inode->i_blocks -= handle->fs->blocksize / 512;
1505                         retval = ext2fs_write_inode(handle->fs, handle->ino,
1506                                                     handle->inode);
1507                         ext2fs_block_alloc_stats2(handle->fs,
1508                                                   extent.e_pblk, -1);
1509                 }
1510         } else {
1511                 eh = (struct ext3_extent_header *) path->buf;
1512                 eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
1513                 if ((path->entries == 0) && (handle->level == 0))
1514                         eh->eh_depth = handle->max_depth = 0;
1515                 retval = update_path(handle);
1516         }
1517         return retval;
1518 }
1519
1520 errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle,
1521                                  struct ext2_extent_info *info)
1522 {
1523         struct extent_path              *path;
1524
1525         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
1526
1527         memset(info, 0, sizeof(struct ext2_extent_info));
1528
1529         path = handle->path + handle->level;
1530         if (path) {
1531                 if (path->curr)
1532                         info->curr_entry = ((char *) path->curr - path->buf) /
1533                                 sizeof(struct ext3_extent_idx);
1534                 else
1535                         info->curr_entry = 0;
1536                 info->num_entries = path->entries;
1537                 info->max_entries = path->max_entries;
1538                 info->bytes_avail = (path->max_entries - path->entries) *
1539                         sizeof(struct ext3_extent);
1540         }
1541
1542         info->curr_level = handle->level;
1543         info->max_depth = handle->max_depth;
1544         info->max_lblk = ((__u64) 1 << 32) - 1;
1545         info->max_pblk = ((__u64) 1 << 48) - 1;
1546         info->max_len = (1UL << 15);
1547         info->max_uninit_len = (1UL << 15) - 1;
1548
1549         return 0;
1550 }
1551
1552 #ifdef DEBUG
1553
1554 #include "ss/ss.h"
1555
1556 #include "debugfs.h"
1557
1558 /*
1559  * Hook in new commands into debugfs
1560  */
1561 const char *debug_prog_name = "tst_extents";
1562 extern ss_request_table extent_cmds;
1563 ss_request_table *extra_cmds = &extent_cmds;
1564
1565 ext2_ino_t      current_ino = 0;
1566 ext2_extent_handle_t current_handle;
1567
1568 int common_extent_args_process(int argc, char *argv[], int min_argc,
1569                                int max_argc, const char *cmd,
1570                                const char *usage, int flags)
1571 {
1572         if (common_args_process(argc, argv, min_argc, max_argc, cmd,
1573                                 usage, flags))
1574                 return 1;
1575
1576         if (!current_handle) {
1577                 com_err(cmd, 0, "Extent handle not open");
1578                 return 1;
1579         }
1580         return 0;
1581 }
1582
1583 void do_inode(int argc, char *argv[])
1584 {
1585         ext2_ino_t      inode;
1586         int             i;
1587         struct ext3_extent_header *eh;
1588         errcode_t retval;
1589
1590         if (check_fs_open(argv[0]))
1591                 return;
1592
1593         if (argc == 1) {
1594                 if (current_ino)
1595                         printf("Current inode is %d\n", current_ino);
1596                 else
1597                         printf("No current inode\n");
1598                 return;
1599         }
1600
1601         if (common_inode_args_process(argc, argv, &inode, 0)) {
1602                 return;
1603         }
1604
1605         current_ino = 0;
1606
1607         retval = ext2fs_extent_open(current_fs, inode, &current_handle);
1608         if (retval) {
1609                 com_err(argv[1], retval, "while opening extent handle");
1610                 return;
1611         }
1612
1613         current_ino = inode;
1614
1615         printf("Loaded inode %d\n", current_ino);
1616
1617         return;
1618 }
1619
1620 void generic_goto_node(char *cmd_name, int op)
1621 {
1622         struct ext2fs_extent    extent;
1623         errcode_t               retval;
1624
1625         if (check_fs_open(cmd_name))
1626                 return;
1627
1628         if (!current_handle) {
1629                 com_err(cmd_name, 0, "Extent handle not open");
1630                 return;
1631         }
1632
1633         retval = ext2fs_extent_get(current_handle, op, &extent);
1634         if (retval) {
1635                 com_err(cmd_name, retval, 0);
1636                 return;
1637         }
1638         dbg_print_extent(0, &extent);
1639 }
1640
1641 void do_current_node(int argc, char *argv[])
1642 {
1643         generic_goto_node(argv[0], EXT2_EXTENT_CURRENT);
1644 }
1645
1646 void do_root_node(int argc, char *argv[])
1647 {
1648         generic_goto_node(argv[0], EXT2_EXTENT_ROOT);
1649 }
1650
1651 void do_last_leaf(int argc, char *argv[])
1652 {
1653         generic_goto_node(argv[0], EXT2_EXTENT_LAST_LEAF);
1654 }
1655
1656 void do_first_sib(int argc, char *argv[])
1657 {
1658         generic_goto_node(argv[0], EXT2_EXTENT_FIRST_SIB);
1659 }
1660
1661 void do_last_sib(int argc, char *argv[])
1662 {
1663         generic_goto_node(argv[0], EXT2_EXTENT_LAST_SIB);
1664 }
1665
1666 void do_next_sib(int argc, char *argv[])
1667 {
1668         generic_goto_node(argv[0], EXT2_EXTENT_NEXT_SIB);
1669 }
1670
1671 void do_prev_sib(int argc, char *argv[])
1672 {
1673         generic_goto_node(argv[0], EXT2_EXTENT_PREV_SIB);
1674 }
1675
1676 void do_next_leaf(int argc, char *argv[])
1677 {
1678         generic_goto_node(argv[0], EXT2_EXTENT_NEXT_LEAF);
1679 }
1680
1681 void do_prev_leaf(int argc, char *argv[])
1682 {
1683         generic_goto_node(argv[0], EXT2_EXTENT_PREV_LEAF);
1684 }
1685
1686 void do_next(int argc, char *argv[])
1687 {
1688         generic_goto_node(argv[0], EXT2_EXTENT_NEXT);
1689 }
1690
1691 void do_prev(int argc, char *argv[])
1692 {
1693         generic_goto_node(argv[0], EXT2_EXTENT_PREV);
1694 }
1695
1696 void do_up(int argc, char *argv[])
1697 {
1698         generic_goto_node(argv[0], EXT2_EXTENT_UP);
1699 }
1700
1701 void do_down(int argc, char *argv[])
1702 {
1703         generic_goto_node(argv[0], EXT2_EXTENT_DOWN);
1704 }
1705
1706 void do_delete_node(int argc, char *argv[])
1707 {
1708         errcode_t       retval;
1709         int             err;
1710
1711         if (common_extent_args_process(argc, argv, 1, 1, "delete_node",
1712                                        "", CHECK_FS_RW | CHECK_FS_BITMAPS))
1713                 return;
1714
1715         retval = ext2fs_extent_delete(current_handle, 0);
1716         if (retval) {
1717                 com_err(argv[0], retval, 0);
1718                 return;
1719         }
1720         if (current_handle->path && current_handle->path[0].curr)
1721                 do_current_node(argc, argv);
1722 }
1723
1724 void do_replace_node(int argc, char *argv[])
1725 {
1726         const char      *usage = "[--uninit] <lblk> <len> <pblk>";
1727         errcode_t       retval;
1728         struct ext2fs_extent extent;
1729         int err;
1730
1731         if (common_extent_args_process(argc, argv, 3, 5, "replace_node",
1732                                        usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
1733                 return;
1734
1735         extent.e_flags = 0;
1736
1737         if (!strcmp(argv[1], "--uninit")) {
1738                 argc--;
1739                 argv++;
1740                 extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
1741         }
1742
1743         if (argc != 4) {
1744                 fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
1745                 return;
1746         }
1747
1748         extent.e_lblk = parse_ulong(argv[1], argv[0], "logical block", &err);
1749         if (err)
1750                 return;
1751
1752         extent.e_len = parse_ulong(argv[2], argv[0], "logical block", &err);
1753         if (err)
1754                 return;
1755
1756         extent.e_pblk = parse_ulong(argv[3], argv[0], "logical block", &err);
1757         if (err)
1758                 return;
1759
1760         retval = ext2fs_extent_replace(current_handle, 0, &extent);
1761         if (retval) {
1762                 com_err(argv[0], retval, 0);
1763                 return;
1764         }
1765         do_current_node(argc, argv);
1766 }
1767
1768 void do_split_node(int argc, char *argv[])
1769 {
1770         errcode_t       retval;
1771         struct ext2fs_extent extent;
1772         int err;
1773
1774         if (common_extent_args_process(argc, argv, 1, 1, "split_node",
1775                                        "", CHECK_FS_RW | CHECK_FS_BITMAPS))
1776                 return;
1777
1778         retval = extent_node_split(current_handle);
1779         if (retval) {
1780                 com_err(argv[0], retval, 0);
1781                 return;
1782         }
1783         do_current_node(argc, argv);
1784 }
1785
1786 void do_insert_node(int argc, char *argv[])
1787 {
1788         const char      *usage = "[--after] [--uninit] <lblk> <len> <pblk>";
1789         errcode_t       retval;
1790         struct ext2fs_extent extent;
1791         char *cmd;
1792         int err;
1793         int flags = 0;
1794
1795         if (common_extent_args_process(argc, argv, 3, 6, "insert_node",
1796                                        usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
1797                 return;
1798
1799         cmd = argv[0];
1800
1801         extent.e_flags = 0;
1802
1803         while (argc > 2) {
1804                 if (!strcmp(argv[1], "--after")) {
1805                         argc--;
1806                         argv++;
1807                         flags |= EXT2_EXTENT_INSERT_AFTER;
1808                         continue;
1809                 }
1810                 if (!strcmp(argv[1], "--uninit")) {
1811                         argc--;
1812                         argv++;
1813                         extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
1814                         continue;
1815                 }
1816                 break;
1817         }
1818
1819         if (argc != 4) {
1820                 fprintf(stderr, "usage: %s %s\n", cmd, usage);
1821                 return;
1822         }
1823
1824         extent.e_lblk = parse_ulong(argv[1], cmd,
1825                                     "logical block", &err);
1826         if (err)
1827                 return;
1828
1829         extent.e_len = parse_ulong(argv[2], cmd,
1830                                     "length", &err);
1831         if (err)
1832                 return;
1833
1834         extent.e_pblk = parse_ulong(argv[3], cmd,
1835                                     "pysical block", &err);
1836         if (err)
1837                 return;
1838
1839         retval = ext2fs_extent_insert(current_handle, flags, &extent);
1840         if (retval) {
1841                 com_err(cmd, retval, 0);
1842                 return;
1843         }
1844         do_current_node(argc, argv);
1845 }
1846
1847 void do_set_bmap(int argc, char **argv)
1848 {
1849         const char      *usage = "[--uninit] <lblk> <pblk>";
1850         errcode_t       retval;
1851         blk_t           logical;
1852         blk_t           physical;
1853         char            *cmd = argv[0];
1854         int             flags = 0;
1855         int             err;
1856
1857         if (common_extent_args_process(argc, argv, 3, 5, "set_bmap",
1858                                        usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
1859                 return;
1860
1861         if (argc > 2 && !strcmp(argv[1], "--uninit")) {
1862                 argc--;
1863                 argv++;
1864                 flags |= EXT2_EXTENT_SET_BMAP_UNINIT;
1865         }
1866
1867         if (argc != 3) {
1868                 fprintf(stderr, "Usage: %s %s\n", cmd, usage);
1869                 return;
1870         }
1871
1872         logical = parse_ulong(argv[1], cmd,
1873                                     "logical block", &err);
1874         if (err)
1875                 return;
1876
1877         physical = parse_ulong(argv[2], cmd,
1878                                     "physical block", &err);
1879         if (err)
1880                 return;
1881
1882         retval = ext2fs_extent_set_bmap(current_handle, logical,
1883                                         (blk64_t) physical, flags);
1884         if (retval) {
1885                 com_err(cmd, retval, 0);
1886                 return;
1887         }
1888         if (current_handle->path && current_handle->path[0].curr)
1889                 do_current_node(argc, argv);
1890 }
1891
1892 void do_print_all(int argc, char **argv)
1893 {
1894         const char      *usage = "[--leaf-only|--reverse|--reverse-leaf]";
1895         struct ext2fs_extent    extent;
1896         errcode_t               retval;
1897         errcode_t               end_err = EXT2_ET_EXTENT_NO_NEXT;
1898         int                     op = EXT2_EXTENT_NEXT;
1899         int                     first_op = EXT2_EXTENT_ROOT;
1900
1901
1902         if (common_extent_args_process(argc, argv, 1, 2, "print_all",
1903                                        usage, 0))
1904                 return;
1905
1906         if (argc == 2) {
1907                 if (!strcmp(argv[1], "--leaf-only"))
1908                         op = EXT2_EXTENT_NEXT_LEAF;
1909                 else if (!strcmp(argv[1], "--reverse")) {
1910                         op = EXT2_EXTENT_PREV;
1911                         first_op = EXT2_EXTENT_LAST_LEAF;
1912                         end_err = EXT2_ET_EXTENT_NO_PREV;
1913                 } else if (!strcmp(argv[1], "--reverse-leaf")) {
1914                         op = EXT2_EXTENT_PREV_LEAF;
1915                         first_op = EXT2_EXTENT_LAST_LEAF;
1916                         end_err = EXT2_ET_EXTENT_NO_PREV;
1917                 } else {
1918                         fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
1919                         return;
1920                 }
1921         }
1922
1923         retval = ext2fs_extent_get(current_handle, first_op, &extent);
1924         if (retval) {
1925                 com_err(argv[0], retval, 0);
1926                 return;
1927         }
1928         dbg_print_extent(0, &extent);
1929
1930         while (1) {
1931                 retval = ext2fs_extent_get(current_handle, op, &extent);
1932                 if (retval == end_err)
1933                         break;
1934
1935                 if (retval) {
1936                         com_err(argv[0], retval, 0);
1937                         return;
1938                 }
1939                 dbg_print_extent(0, &extent);
1940         }
1941 }
1942
1943 void do_info(int argc, char **argv)
1944 {
1945         struct ext2fs_extent    extent;
1946         struct ext2_extent_info info;
1947         errcode_t               retval;
1948
1949         if (common_extent_args_process(argc, argv, 1, 1, "info", "", 0))
1950                 return;
1951
1952         retval = ext2fs_extent_get_info(current_handle, &info);
1953         if (retval) {
1954                 com_err(argv[0], retval, 0);
1955                 return;
1956         }
1957
1958         retval = ext2fs_extent_get(current_handle,
1959                                    EXT2_EXTENT_CURRENT, &extent);
1960         if (retval) {
1961                 com_err(argv[0], retval, 0);
1962                 return;
1963         }
1964
1965         dbg_print_extent(0, &extent);
1966
1967         printf("Current handle location: %d/%d (max: %d, bytes %d), level %d/%d\n",
1968                info.curr_entry, info.num_entries, info.max_entries,
1969                info.bytes_avail, info.curr_level, info.max_depth);
1970         printf("\tmax lblk: %llu, max pblk: %llu\n", info.max_lblk,
1971                info.max_pblk);
1972         printf("\tmax_len: %u, max_uninit_len: %u\n", info.max_len,
1973                info.max_uninit_len);
1974 }
1975
1976 void do_goto_block(int argc, char **argv)
1977 {
1978         struct ext2fs_extent    extent;
1979         errcode_t               retval;
1980         int                     op = EXT2_EXTENT_NEXT_LEAF;
1981         blk64_t                 blk;
1982         int                     level = 0, err;
1983
1984         if (common_extent_args_process(argc, argv, 2, 3, "goto_block",
1985                                        "block [level]", 0))
1986                 return;
1987
1988         if (strtoblk(argv[0], argv[1], &blk))
1989                 return;
1990
1991         if (argc == 3) {
1992                 level = parse_ulong(argv[2], argv[0], "level", &err);
1993                 if (err)
1994                         return;
1995         }
1996
1997         retval = extent_goto(current_handle, level, (blk64_t) blk);
1998
1999         if (retval) {
2000                 com_err(argv[0], retval,
2001                         "while trying to go to block %llu, level %d",
2002                         (unsigned long long) blk, level);
2003                 return;
2004         }
2005
2006         generic_goto_node(argv[0], EXT2_EXTENT_CURRENT);
2007 }
2008 #endif
2009