Coverage Report

Created: 2026-03-12 06:19

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