Whamcloud - gitweb
libext2fs: try to roll back when splitting an extent fails
[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 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 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 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 errcode_t ext2fs_extent_goto2(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 ext2fs_extent_goto2(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 errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle)
710 {
711         int                             retval = 0;
712         int                             orig_height;
713         blk64_t                         start;
714         struct extent_path              *path;
715         struct ext2fs_extent            extent;
716         struct ext2_extent_info         info;
717
718         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
719
720         if (!(handle->fs->flags & EXT2_FLAG_RW))
721                 return EXT2_ET_RO_FILSYS;
722
723         if (!handle->path)
724                 return EXT2_ET_NO_CURRENT_NODE;
725
726         path = handle->path + handle->level;
727         if (!path->curr)
728                 return EXT2_ET_NO_CURRENT_NODE;
729
730         retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
731         if (retval)
732                 goto done;
733
734         /* modified node's start block */
735         start = extent.e_lblk;
736
737         if ((retval = ext2fs_extent_get_info(handle, &info)))
738                 return retval;
739         orig_height = info.max_depth - info.curr_level;
740
741         /* traverse up until index not first, or startblk matches, or top */
742         while (handle->level > 0 &&
743                (path->left == path->entries - 1)) {
744                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent);
745                 if (retval)
746                         goto done;
747                 if (extent.e_lblk == start)
748                         break;
749                 path = handle->path + handle->level;
750                 extent.e_len += (extent.e_lblk - start);
751                 extent.e_lblk = start;
752                 retval = ext2fs_extent_replace(handle, 0, &extent);
753                 if (retval)
754                         goto done;
755                 update_path(handle);
756         }
757
758         /* put handle back to where we started */
759         retval = ext2fs_extent_goto2(handle, orig_height, start);
760 done:
761         return retval;
762 }
763
764 errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle,
765                                 int flags EXT2FS_ATTR((unused)),
766                                 struct ext2fs_extent *extent)
767 {
768         struct extent_path              *path;
769         struct ext3_extent_idx          *ix;
770         struct ext3_extent              *ex;
771
772         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
773
774         if (!(handle->fs->flags & EXT2_FLAG_RW))
775                 return EXT2_ET_RO_FILSYS;
776
777         if (!handle->path)
778                 return EXT2_ET_NO_CURRENT_NODE;
779
780         path = handle->path + handle->level;
781         if (!path->curr)
782                 return EXT2_ET_NO_CURRENT_NODE;
783
784 #ifdef DEBUG
785         printf("extent replace: %u ", handle->ino);
786         dbg_print_extent(0, extent);
787 #endif
788
789         if (handle->level == handle->max_depth) {
790                 ex = path->curr;
791
792                 ex->ee_block = ext2fs_cpu_to_le32(extent->e_lblk);
793                 ex->ee_start = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF);
794                 ex->ee_start_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32);
795                 if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) {
796                         if (extent->e_len > EXT_UNINIT_MAX_LEN)
797                                 return EXT2_ET_EXTENT_INVALID_LENGTH;
798                         ex->ee_len = ext2fs_cpu_to_le16(extent->e_len +
799                                                         EXT_INIT_MAX_LEN);
800                 } else {
801                         if (extent->e_len > EXT_INIT_MAX_LEN)
802                                 return EXT2_ET_EXTENT_INVALID_LENGTH;
803                         ex->ee_len = ext2fs_cpu_to_le16(extent->e_len);
804                 }
805         } else {
806                 ix = path->curr;
807
808                 ix->ei_leaf = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF);
809                 ix->ei_leaf_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32);
810                 ix->ei_block = ext2fs_cpu_to_le32(extent->e_lblk);
811                 ix->ei_unused = 0;
812         }
813         update_path(handle);
814         return 0;
815 }
816
817 /*
818  * allocate a new block, move half the current node to it, and update parent
819  *
820  * handle will be left pointing at original record.
821  */
822 errcode_t ext2fs_extent_node_split(ext2_extent_handle_t handle)
823 {
824         errcode_t                       retval = 0;
825         blk64_t                         new_node_pblk;
826         blk64_t                         new_node_start;
827         blk64_t                         orig_lblk;
828         blk64_t                         goal_blk = 0;
829         int                             orig_height;
830         char                            *block_buf = NULL;
831         struct ext2fs_extent            extent;
832         struct extent_path              *path, *newpath = 0;
833         struct ext3_extent_header       *eh, *neweh;
834         int                             tocopy;
835         int                             new_root = 0;
836         struct ext2_extent_info         info;
837
838         /* basic sanity */
839         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
840
841         if (!(handle->fs->flags & EXT2_FLAG_RW))
842                 return EXT2_ET_RO_FILSYS;
843
844         if (!handle->path)
845                 return EXT2_ET_NO_CURRENT_NODE;
846
847 #ifdef DEBUG
848         printf("splitting node at level %d\n", handle->level);
849 #endif
850         retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
851         if (retval)
852                 goto done;
853
854         retval = ext2fs_extent_get_info(handle, &info);
855         if (retval)
856                 goto done;
857
858         /* save the position we were originally splitting... */
859         orig_height = info.max_depth - info.curr_level;
860         orig_lblk = extent.e_lblk;
861
862         /* Is there room in the parent for a new entry? */
863         if (handle->level &&
864                         (handle->path[handle->level - 1].entries >=
865                          handle->path[handle->level - 1].max_entries)) {
866
867 #ifdef DEBUG
868                 printf("parent level %d full; splitting it too\n",
869                                                         handle->level - 1);
870 #endif
871                 /* split the parent */
872                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent);
873                 if (retval)
874                         goto done;
875                 goal_blk = extent.e_pblk;
876
877                 retval = ext2fs_extent_node_split(handle);
878                 if (retval)
879                         goto done;
880
881                 /* get handle back to our original split position */
882                 retval = ext2fs_extent_goto2(handle, orig_height, orig_lblk);
883                 if (retval)
884                         goto done;
885         }
886
887         /* At this point, parent should have room for this split */
888         path = handle->path + handle->level;
889         if (!path->curr)
890                 return EXT2_ET_NO_CURRENT_NODE;
891
892         /* extent header of the current node we'll split */
893         eh = (struct ext3_extent_header *)path->buf;
894
895         /* splitting root level means moving them all out */
896         if (handle->level == 0) {
897                 new_root = 1;
898                 tocopy = ext2fs_le16_to_cpu(eh->eh_entries);
899                 retval = ext2fs_get_mem(((handle->max_depth+2) *
900                                          sizeof(struct extent_path)),
901                                         &newpath);
902                 if (retval)
903                         goto done;
904                 memset(newpath, 0,
905                        ((handle->max_depth+2) * sizeof(struct extent_path)));
906         } else {
907                 tocopy = ext2fs_le16_to_cpu(eh->eh_entries) / 2;
908         }
909
910 #ifdef DEBUG
911         printf("will copy out %d of %d entries at level %d\n",
912                                 tocopy, ext2fs_le16_to_cpu(eh->eh_entries),
913                                 handle->level);
914 #endif
915
916         if (!tocopy) {
917 #ifdef DEBUG
918                 printf("Nothing to copy to new block!\n");
919 #endif
920                 retval = EXT2_ET_CANT_SPLIT_EXTENT;
921                 goto done;
922         }
923
924         /* first we need a new block, or can do nothing. */
925         block_buf = malloc(handle->fs->blocksize);
926         if (!block_buf) {
927                 retval = ENOMEM;
928                 goto done;
929         }
930
931         if (!goal_blk) {
932                 dgrp_t  group = ext2fs_group_of_ino(handle->fs, handle->ino);
933                 __u8    log_flex = handle->fs->super->s_log_groups_per_flex;
934
935                 if (log_flex)
936                         group = group & ~((1 << (log_flex)) - 1);
937                 goal_blk = ext2fs_group_first_block2(handle->fs, group);
938         }
939         retval = ext2fs_alloc_block2(handle->fs, goal_blk, block_buf,
940                                     &new_node_pblk);
941         if (retval)
942                 goto done;
943
944 #ifdef DEBUG
945         printf("will copy to new node at block %lu\n",
946                (unsigned long) new_node_pblk);
947 #endif
948
949         /* Copy data into new block buffer */
950         /* First the header for the new block... */
951         neweh = (struct ext3_extent_header *) block_buf;
952         memcpy(neweh, eh, sizeof(struct ext3_extent_header));
953         neweh->eh_entries = ext2fs_cpu_to_le16(tocopy);
954         neweh->eh_max = ext2fs_cpu_to_le16((handle->fs->blocksize -
955                          sizeof(struct ext3_extent_header)) /
956                                 sizeof(struct ext3_extent));
957
958         /* then the entries for the new block... */
959         memcpy(EXT_FIRST_INDEX(neweh),
960                 EXT_FIRST_INDEX(eh) +
961                         (ext2fs_le16_to_cpu(eh->eh_entries) - tocopy),
962                 sizeof(struct ext3_extent_idx) * tocopy);
963
964         new_node_start = ext2fs_le32_to_cpu(EXT_FIRST_INDEX(neweh)->ei_block);
965
966         /* ...and write the new node block out to disk. */
967         retval = io_channel_write_blk64(handle->fs->io, new_node_pblk, 1,
968                                         block_buf);
969
970         if (retval)
971                 goto done;
972
973         /* OK! we've created the new node; now adjust the tree */
974
975         /* current path now has fewer active entries, we copied some out */
976         if (handle->level == 0) {
977                 memcpy(newpath, path,
978                        sizeof(struct extent_path) * (handle->max_depth+1));
979                 handle->path = newpath;
980                 newpath = path;
981                 path = handle->path;
982                 path->entries = 1;
983                 path->left = path->max_entries - 1;
984                 handle->max_depth++;
985                 eh->eh_depth = ext2fs_cpu_to_le16(handle->max_depth);
986         } else {
987                 path->entries -= tocopy;
988                 path->left -= tocopy;
989         }
990
991         eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
992         /* this writes out the node, incl. the modified header */
993         retval = update_path(handle);
994         if (retval)
995                 goto done;
996
997         /* now go up and insert/replace index for new node we created */
998         if (new_root) {
999                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_FIRST_SIB, &extent);
1000                 if (retval)
1001                         goto done;
1002
1003                 extent.e_lblk = new_node_start;
1004                 extent.e_pblk = new_node_pblk;
1005                 extent.e_len = handle->path[0].end_blk - extent.e_lblk;
1006                 retval = ext2fs_extent_replace(handle, 0, &extent);
1007                 if (retval)
1008                         goto done;
1009         } else {
1010                 __u32 new_node_length;
1011
1012                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent);
1013                 /* will insert after this one; it's length is shorter now */
1014                 new_node_length = new_node_start - extent.e_lblk;
1015                 extent.e_len -= new_node_length;
1016                 retval = ext2fs_extent_replace(handle, 0, &extent);
1017                 if (retval)
1018                         goto done;
1019
1020                 /* now set up the new extent and insert it */
1021                 extent.e_lblk = new_node_start;
1022                 extent.e_pblk = new_node_pblk;
1023                 extent.e_len = new_node_length;
1024                 retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER, &extent);
1025                 if (retval)
1026                         goto done;
1027         }
1028
1029         /* get handle back to our original position */
1030         retval = ext2fs_extent_goto2(handle, orig_height, orig_lblk);
1031         if (retval)
1032                 goto done;
1033
1034         /* new node hooked in, so update inode block count (do this here?) */
1035         handle->inode->i_blocks += (handle->fs->blocksize *
1036                                     EXT2FS_CLUSTER_RATIO(handle->fs)) / 512;
1037         retval = ext2fs_write_inode(handle->fs, handle->ino,
1038                                     handle->inode);
1039         if (retval)
1040                 goto done;
1041
1042 done:
1043         if (newpath)
1044                 ext2fs_free_mem(&newpath);
1045         free(block_buf);
1046
1047         return retval;
1048 }
1049
1050 errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags,
1051                                       struct ext2fs_extent *extent)
1052 {
1053         struct extent_path              *path;
1054         struct ext3_extent_idx          *ix;
1055         struct ext3_extent_header       *eh;
1056         errcode_t                       retval;
1057
1058         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
1059
1060         if (!(handle->fs->flags & EXT2_FLAG_RW))
1061                 return EXT2_ET_RO_FILSYS;
1062
1063         if (!handle->path)
1064                 return EXT2_ET_NO_CURRENT_NODE;
1065
1066 #ifdef DEBUG
1067         printf("extent insert: %u ", handle->ino);
1068         dbg_print_extent(0, extent);
1069 #endif
1070
1071         path = handle->path + handle->level;
1072
1073         if (path->entries >= path->max_entries) {
1074                 if (flags & EXT2_EXTENT_INSERT_NOSPLIT) {
1075                         return EXT2_ET_CANT_INSERT_EXTENT;
1076                 } else {
1077 #ifdef DEBUG
1078                         printf("node full (level %d) - splitting\n",
1079                                    handle->level);
1080 #endif
1081                         retval = ext2fs_extent_node_split(handle);
1082                         if (retval)
1083                                 return retval;
1084                         path = handle->path + handle->level;
1085                 }
1086         }
1087
1088         eh = (struct ext3_extent_header *) path->buf;
1089         if (path->curr) {
1090                 ix = path->curr;
1091                 if (flags & EXT2_EXTENT_INSERT_AFTER) {
1092                         ix++;
1093                         path->left--;
1094                 }
1095         } else {
1096                 ix = EXT_FIRST_INDEX(eh);
1097                 path->left = -1;
1098         }
1099
1100         path->curr = ix;
1101
1102         if (path->left >= 0)
1103                 memmove(ix + 1, ix,
1104                         (path->left+1) * sizeof(struct ext3_extent_idx));
1105         path->left++;
1106         path->entries++;
1107
1108         eh = (struct ext3_extent_header *) path->buf;
1109         eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
1110
1111         retval = ext2fs_extent_replace(handle, 0, extent);
1112         if (retval)
1113                 goto errout;
1114
1115         retval = update_path(handle);
1116         if (retval)
1117                 goto errout;
1118
1119         return 0;
1120
1121 errout:
1122         ext2fs_extent_delete(handle, 0);
1123         return retval;
1124 }
1125
1126 /*
1127  * Sets the physical block for a logical file block in the extent tree.
1128  *
1129  * May: map unmapped, unmap mapped, or remap mapped blocks.
1130  *
1131  * Mapping an unmapped block adds a single-block extent.
1132  *
1133  * Unmapping first or last block modifies extent in-place
1134  *  - But may need to fix parent's starts too in first-block case
1135  *
1136  * Mapping any unmapped block requires adding a (single-block) extent
1137  * and inserting into proper point in tree.
1138  *
1139  * Modifying (unmapping or remapping) a block in the middle
1140  * of an extent requires splitting the extent.
1141  *  - Remapping case requires new single-block extent.
1142  *
1143  * Remapping first or last block adds an extent.
1144  *
1145  * We really need extent adding to be smart about merging.
1146  */
1147
1148 errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
1149                                  blk64_t logical, blk64_t physical, int flags)
1150 {
1151         errcode_t               ec, retval = 0;
1152         int                     mapped = 1; /* logical is mapped? */
1153         int                     orig_height;
1154         int                     extent_uninit = 0;
1155         int                     prev_uninit = 0;
1156         int                     next_uninit = 0;
1157         int                     new_uninit = 0;
1158         int                     max_len = EXT_INIT_MAX_LEN;
1159         int                     has_prev, has_next;
1160         blk64_t                 orig_lblk;
1161         struct extent_path      *path;
1162         struct ext2fs_extent    extent, next_extent, prev_extent;
1163         struct ext2fs_extent    newextent;
1164         struct ext2_extent_info info;
1165
1166         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
1167
1168 #ifdef DEBUG
1169         printf("set_bmap ino %u log %lld phys %lld flags %d\n",
1170                handle->ino, logical, physical, flags);
1171 #endif
1172
1173         if (!(handle->fs->flags & EXT2_FLAG_RW))
1174                 return EXT2_ET_RO_FILSYS;
1175
1176         if (!handle->path)
1177                 return EXT2_ET_NO_CURRENT_NODE;
1178
1179         path = handle->path + handle->level;
1180
1181         if (flags & EXT2_EXTENT_SET_BMAP_UNINIT) {
1182                 new_uninit = 1;
1183                 max_len = EXT_UNINIT_MAX_LEN;
1184         }
1185
1186         /* if (re)mapping, set up new extent to insert */
1187         if (physical) {
1188                 newextent.e_len = 1;
1189                 newextent.e_pblk = physical;
1190                 newextent.e_lblk = logical;
1191                 newextent.e_flags = EXT2_EXTENT_FLAGS_LEAF;
1192                 if (new_uninit)
1193                         newextent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
1194         }
1195
1196         /* special case if the extent tree is completely empty */
1197         if ((handle->max_depth == 0) && (path->entries == 0)) {
1198                 retval = ext2fs_extent_insert(handle, 0, &newextent);
1199                 return retval;
1200         }
1201
1202         /* save our original location in the extent tree */
1203         if ((retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
1204                                         &extent))) {
1205                 if (retval != EXT2_ET_NO_CURRENT_NODE)
1206                         return retval;
1207                 memset(&extent, 0, sizeof(extent));
1208         }
1209         if ((retval = ext2fs_extent_get_info(handle, &info)))
1210                 return retval;
1211         orig_height = info.max_depth - info.curr_level;
1212         orig_lblk = extent.e_lblk;
1213
1214         /* go to the logical spot we want to (re/un)map */
1215         retval = ext2fs_extent_goto(handle, logical);
1216         if (retval) {
1217                 if (retval == EXT2_ET_EXTENT_NOT_FOUND) {
1218                         retval = 0;
1219                         mapped = 0;
1220                         if (!physical) {
1221 #ifdef DEBUG
1222                                 printf("block %llu already unmapped\n",
1223                                         logical);
1224 #endif
1225                                 goto done;
1226                         }
1227                 } else
1228                         goto done;
1229         }
1230
1231         /*
1232          * This may be the extent *before* the requested logical,
1233          * if it's currently unmapped.
1234          *
1235          * Get the previous and next leaf extents, if they are present.
1236          */
1237         retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
1238         if (retval)
1239                 goto done;
1240         if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
1241                 extent_uninit = 1;
1242         retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, &next_extent);
1243         if (retval) {
1244                 has_next = 0;
1245                 if (retval != EXT2_ET_EXTENT_NO_NEXT)
1246                         goto done;
1247         } else {
1248                 dbg_print_extent("set_bmap: next_extent",
1249                                  &next_extent);
1250                 has_next = 1;
1251                 if (next_extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
1252                         next_uninit = 1;
1253         }
1254         retval = ext2fs_extent_goto(handle, logical);
1255         if (retval && retval != EXT2_ET_EXTENT_NOT_FOUND)
1256                 goto done;
1257         retval = ext2fs_extent_get(handle, EXT2_EXTENT_PREV_LEAF, &prev_extent);
1258         if (retval) {
1259                 has_prev = 0;
1260                 if (retval != EXT2_ET_EXTENT_NO_PREV)
1261                         goto done;
1262         } else {
1263                 has_prev = 1;
1264                 dbg_print_extent("set_bmap: prev_extent",
1265                                  &prev_extent);
1266                 if (prev_extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
1267                         prev_uninit = 1;
1268         }
1269         retval = ext2fs_extent_goto(handle, logical);
1270         if (retval && retval != EXT2_ET_EXTENT_NOT_FOUND)
1271                 goto done;
1272
1273         /* check if already pointing to the requested physical */
1274         if (mapped && (new_uninit == extent_uninit) &&
1275             (extent.e_pblk + (logical - extent.e_lblk) == physical)) {
1276 #ifdef DEBUG
1277                 printf("physical block (at %llu) unchanged\n", logical);
1278 #endif
1279                 goto done;
1280         }
1281
1282         if (!mapped) {
1283 #ifdef DEBUG
1284                 printf("mapping unmapped logical block %llu\n", logical);
1285 #endif
1286                 if ((logical == extent.e_lblk + extent.e_len) &&
1287                     (physical == extent.e_pblk + extent.e_len) &&
1288                     (new_uninit == extent_uninit) &&
1289                     ((int) extent.e_len < max_len-1)) {
1290                         extent.e_len++;
1291                         retval = ext2fs_extent_replace(handle, 0, &extent);
1292                 } else if ((logical == extent.e_lblk - 1) &&
1293                            (physical == extent.e_pblk - 1) &&
1294                            (new_uninit == extent_uninit) &&
1295                            ((int) extent.e_len < max_len - 1)) {
1296                         extent.e_len++;
1297                         extent.e_lblk--;
1298                         extent.e_pblk--;
1299                         retval = ext2fs_extent_replace(handle, 0, &extent);
1300                 } else if (has_next &&
1301                            (logical == next_extent.e_lblk - 1) &&
1302                            (physical == next_extent.e_pblk - 1) &&
1303                            (new_uninit == next_uninit) &&
1304                            ((int) next_extent.e_len < max_len - 1)) {
1305                         retval = ext2fs_extent_get(handle,
1306                                                    EXT2_EXTENT_NEXT_LEAF,
1307                                                    &next_extent);
1308                         if (retval)
1309                                 goto done;
1310                         next_extent.e_len++;
1311                         next_extent.e_lblk--;
1312                         next_extent.e_pblk--;
1313                         retval = ext2fs_extent_replace(handle, 0, &next_extent);
1314                 } else if (logical < extent.e_lblk)
1315                         retval = ext2fs_extent_insert(handle, 0, &newextent);
1316                 else
1317                         retval = ext2fs_extent_insert(handle,
1318                                       EXT2_EXTENT_INSERT_AFTER, &newextent);
1319                 if (retval)
1320                         goto done;
1321                 retval = ext2fs_extent_fix_parents(handle);
1322                 if (retval)
1323                         goto done;
1324         } else if ((logical == extent.e_lblk) && (extent.e_len == 1))  {
1325 #ifdef DEBUG
1326                 printf("(re/un)mapping only block in extent\n");
1327 #endif
1328                 if (physical) {
1329                         retval = ext2fs_extent_replace(handle, 0, &newextent);
1330                 } else {
1331                         retval = ext2fs_extent_delete(handle, 0);
1332                         if (retval)
1333                                 goto done;
1334                         ec = ext2fs_extent_fix_parents(handle);
1335                         if (ec != EXT2_ET_NO_CURRENT_NODE)
1336                                 retval = ec;
1337                 }
1338
1339                 if (retval)
1340                         goto done;
1341         } else if (logical == extent.e_lblk + extent.e_len - 1)  {
1342 #ifdef DEBUG
1343                 printf("(re/un)mapping last block in extent\n");
1344 #endif
1345                 if (physical) {
1346                         if (has_next &&
1347                             (logical == (next_extent.e_lblk - 1)) &&
1348                             (physical == (next_extent.e_pblk - 1)) &&
1349                             (new_uninit == next_uninit) &&
1350                             ((int) next_extent.e_len < max_len - 1)) {
1351                                 retval = ext2fs_extent_get(handle,
1352                                         EXT2_EXTENT_NEXT_LEAF, &next_extent);
1353                                 if (retval)
1354                                         goto done;
1355                                 next_extent.e_len++;
1356                                 next_extent.e_lblk--;
1357                                 next_extent.e_pblk--;
1358                                 retval = ext2fs_extent_replace(handle, 0,
1359                                                                &next_extent);
1360                                 if (retval)
1361                                         goto done;
1362                                 retval = ext2fs_extent_fix_parents(handle);
1363                                 if (retval)
1364                                         goto done;
1365                         } else
1366                                 retval = ext2fs_extent_insert(handle,
1367                                       EXT2_EXTENT_INSERT_AFTER, &newextent);
1368                         if (retval)
1369                                 goto done;
1370                         /* Now pointing at inserted extent; move back to prev */
1371                         retval = ext2fs_extent_get(handle,
1372                                                    EXT2_EXTENT_PREV_LEAF,
1373                                                    &extent);
1374                         if (retval)
1375                                 goto done;
1376                 }
1377                 extent.e_len--;
1378                 retval = ext2fs_extent_replace(handle, 0, &extent);
1379                 if (retval)
1380                         goto done;
1381         } else if (logical == extent.e_lblk) {
1382 #ifdef DEBUG
1383                 printf("(re/un)mapping first block in extent\n");
1384 #endif
1385                 if (physical) {
1386                         if (has_prev &&
1387                             (logical == (prev_extent.e_lblk +
1388                                          prev_extent.e_len)) &&
1389                             (physical == (prev_extent.e_pblk +
1390                                           prev_extent.e_len)) &&
1391                             (new_uninit == prev_uninit) &&
1392                             ((int) prev_extent.e_len < max_len-1)) {
1393                                 retval = ext2fs_extent_get(handle, 
1394                                         EXT2_EXTENT_PREV_LEAF, &prev_extent);
1395                                 if (retval)
1396                                         goto done;
1397                                 prev_extent.e_len++;
1398                                 retval = ext2fs_extent_replace(handle, 0,
1399                                                                &prev_extent);
1400                         } else
1401                                 retval = ext2fs_extent_insert(handle,
1402                                                               0, &newextent);
1403                         if (retval)
1404                                 goto done;
1405                         retval = ext2fs_extent_get(handle,
1406                                                    EXT2_EXTENT_NEXT_LEAF,
1407                                                    &extent);
1408                         if (retval)
1409                                 goto done;
1410                 }
1411                 extent.e_pblk++;
1412                 extent.e_lblk++;
1413                 extent.e_len--;
1414                 retval = ext2fs_extent_replace(handle, 0, &extent);
1415                 if (retval)
1416                         goto done;
1417                 retval = ext2fs_extent_fix_parents(handle);
1418                 if (retval)
1419                         goto done;
1420         } else {
1421                 __u32   orig_length;
1422                 blk64_t orig_lblk;
1423                 struct ext2fs_extent orig_extent;
1424                 errcode_t r2;
1425
1426 #ifdef DEBUG
1427                 printf("(re/un)mapping in middle of extent\n");
1428 #endif
1429                 /* need to split this extent; later */
1430                 orig_lblk = extent.e_lblk;
1431                 orig_length = extent.e_len;
1432                 orig_extent = extent;
1433
1434                 /* shorten pre-split extent */
1435                 extent.e_len = (logical - extent.e_lblk);
1436                 retval = ext2fs_extent_replace(handle, 0, &extent);
1437                 if (retval)
1438                         goto done;
1439                 /* insert our new extent, if any */
1440                 if (physical) {
1441                         /* insert new extent after current */
1442                         retval = ext2fs_extent_insert(handle,
1443                                         EXT2_EXTENT_INSERT_AFTER, &newextent);
1444                         if (retval) {
1445                                 r2 = ext2fs_extent_goto(handle, orig_lblk);
1446                                 if (r2 == 0)
1447                                         ext2fs_extent_replace(handle, 0,
1448                                                               &orig_extent);
1449                                 goto done;
1450                         }
1451                 }
1452                 /* add post-split extent */
1453                 extent.e_pblk += extent.e_len + 1;
1454                 extent.e_lblk += extent.e_len + 1;
1455                 extent.e_len = orig_length - extent.e_len - 1;
1456                 retval = ext2fs_extent_insert(handle,
1457                                 EXT2_EXTENT_INSERT_AFTER, &extent);
1458                 if (retval) {
1459                         if (physical) {
1460                                 r2 = ext2fs_extent_goto(handle,
1461                                                         newextent.e_lblk);
1462                                 if (r2 == 0)
1463                                         ext2fs_extent_delete(handle, 0);
1464                         }
1465                         r2 = ext2fs_extent_goto(handle, orig_lblk);
1466                         if (r2 == 0)
1467                                 ext2fs_extent_replace(handle, 0, &orig_extent);
1468                         goto done;
1469                 }
1470         }
1471
1472 done:
1473         /* get handle back to its position */
1474         if (orig_height > handle->max_depth)
1475                 orig_height = handle->max_depth; /* In case we shortened the tree */
1476         ext2fs_extent_goto2(handle, orig_height, orig_lblk);
1477         return retval;
1478 }
1479
1480 errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, int flags)
1481 {
1482         struct extent_path              *path;
1483         char                            *cp;
1484         struct ext3_extent_header       *eh;
1485         errcode_t                       retval = 0;
1486
1487         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
1488
1489         if (!(handle->fs->flags & EXT2_FLAG_RW))
1490                 return EXT2_ET_RO_FILSYS;
1491
1492         if (!handle->path)
1493                 return EXT2_ET_NO_CURRENT_NODE;
1494
1495 #ifdef DEBUG
1496         {
1497                 struct ext2fs_extent    extent;
1498
1499                 retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
1500                                            &extent);
1501                 if (retval == 0) {
1502                         printf("extent delete %u ", handle->ino);
1503                         dbg_print_extent(0, &extent);
1504                 }
1505         }
1506 #endif
1507
1508         path = handle->path + handle->level;
1509         if (!path->curr)
1510                 return EXT2_ET_NO_CURRENT_NODE;
1511
1512         cp = path->curr;
1513
1514         if (path->left) {
1515                 memmove(cp, cp + sizeof(struct ext3_extent_idx),
1516                         path->left * sizeof(struct ext3_extent_idx));
1517                 path->left--;
1518         } else {
1519                 struct ext3_extent_idx  *ix = path->curr;
1520                 ix--;
1521                 path->curr = ix;
1522         }
1523         if (--path->entries == 0)
1524                 path->curr = 0;
1525
1526         /* if non-root node has no entries left, remove it & parent ptr to it */
1527         if (path->entries == 0 && handle->level) {
1528                 if (!(flags & EXT2_EXTENT_DELETE_KEEP_EMPTY)) {
1529                         struct ext2fs_extent    extent;
1530
1531                         retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP,
1532                                                                 &extent);
1533                         if (retval)
1534                                 return retval;
1535
1536                         retval = ext2fs_extent_delete(handle, flags);
1537                         handle->inode->i_blocks -=
1538                                 (handle->fs->blocksize *
1539                                  EXT2FS_CLUSTER_RATIO(handle->fs)) / 512;
1540                         retval = ext2fs_write_inode(handle->fs, handle->ino,
1541                                                     handle->inode);
1542                         ext2fs_block_alloc_stats2(handle->fs,
1543                                                   extent.e_pblk, -1);
1544                 }
1545         } else {
1546                 eh = (struct ext3_extent_header *) path->buf;
1547                 eh->eh_entries = ext2fs_cpu_to_le16(path->entries);
1548                 if ((path->entries == 0) && (handle->level == 0))
1549                         eh->eh_depth = handle->max_depth = 0;
1550                 retval = update_path(handle);
1551         }
1552         return retval;
1553 }
1554
1555 errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle,
1556                                  struct ext2_extent_info *info)
1557 {
1558         struct extent_path              *path;
1559
1560         EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
1561
1562         memset(info, 0, sizeof(struct ext2_extent_info));
1563
1564         path = handle->path + handle->level;
1565         if (path) {
1566                 if (path->curr)
1567                         info->curr_entry = ((char *) path->curr - path->buf) /
1568                                 sizeof(struct ext3_extent_idx);
1569                 else
1570                         info->curr_entry = 0;
1571                 info->num_entries = path->entries;
1572                 info->max_entries = path->max_entries;
1573                 info->bytes_avail = (path->max_entries - path->entries) *
1574                         sizeof(struct ext3_extent);
1575         }
1576
1577         info->curr_level = handle->level;
1578         info->max_depth = handle->max_depth;
1579         info->max_lblk = ((__u64) 1 << 32) - 1;
1580         info->max_pblk = ((__u64) 1 << 48) - 1;
1581         info->max_len = (1UL << 15);
1582         info->max_uninit_len = (1UL << 15) - 1;
1583
1584         return 0;
1585 }
1586
1587 #ifdef DEBUG
1588 /*
1589  * Override debugfs's prompt
1590  */
1591 const char *debug_prog_name = "tst_extents";
1592
1593 #endif
1594