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