2 * extent_inode.c --- direct extent tree manipulation
4 * Copyright (C) 2012 Theodore Ts'o. This file may be redistributed
5 * under the terms of the GNU Public License.
18 #include <sys/types.h>
28 static ext2_ino_t current_ino
;
29 static ext2_extent_handle_t current_handle
;
31 static void dbg_print_extent(char *desc
, struct ext2fs_extent
*extent
)
35 printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ",
36 extent
->e_lblk
, extent
->e_lblk
+ extent
->e_len
- 1,
37 extent
->e_len
, extent
->e_pblk
);
38 if (extent
->e_flags
& EXT2_EXTENT_FLAGS_LEAF
)
39 fputs("LEAF ", stdout
);
40 if (extent
->e_flags
& EXT2_EXTENT_FLAGS_UNINIT
)
41 fputs("UNINIT ", stdout
);
42 if (extent
->e_flags
& EXT2_EXTENT_FLAGS_SECOND_VISIT
)
43 fputs("2ND_VISIT ", stdout
);
45 fputs("(none)", stdout
);
50 static int common_extent_args_process(int argc
, char *argv
[], int min_argc
,
51 int max_argc
, const char *cmd
,
52 const char *usage
, int flags
)
54 if (common_args_process(argc
, argv
, min_argc
, max_argc
, cmd
,
58 if (!current_handle
) {
59 com_err(cmd
, 0, "Extent handle not open");
65 static char *orig_prompt
, *extent_prompt
;
67 void do_extent_open(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
68 void *infop
EXT2FS_ATTR((unused
)))
75 if (check_fs_open(argv
[0]))
80 printf("Current inode is %d\n", current_ino
);
82 printf("No current inode\n");
86 if (common_inode_args_process(argc
, argv
, &inode
, 0))
91 retval
= ext2fs_extent_open(current_fs
, inode
, ¤t_handle
);
93 com_err(argv
[1], retval
, "while opening extent handle");
99 orig_prompt
= ss_get_prompt(sci_idx
);
100 extent_prompt
= malloc(strlen(orig_prompt
) + 32);
101 if (extent_prompt
== NULL
) {
102 com_err(argv
[1], retval
, "out of memory");
106 strcpy(extent_prompt
, orig_prompt
);
107 cp
= strchr(extent_prompt
, ':');
110 sprintf(extent_prompt
+ strlen(extent_prompt
), " (extent ino %d): ",
112 ss_add_request_table(sci_idx
, &extent_cmds
, 1, &ret
);
113 ss_set_prompt(sci_idx
, extent_prompt
);
117 void do_extent_close(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
118 void *infop
EXT2FS_ATTR((unused
)))
122 if (common_args_process(argc
, argv
, 1, 1,
123 "extent_close", "", 0))
126 if (!current_handle
) {
127 com_err(argv
[0], 0, "Extent handle not open");
131 ext2fs_extent_free(current_handle
);
132 current_handle
= NULL
;
134 ss_delete_request_table(sci_idx
, &extent_cmds
, &ret
);
135 ss_set_prompt(sci_idx
, orig_prompt
);
137 extent_prompt
= NULL
;
140 static void generic_goto_node(const char *my_name
, int argc
,
143 struct ext2fs_extent extent
;
146 if (my_name
&& common_args_process(argc
, argv
, 1, 1,
150 if (!current_handle
) {
151 com_err(argv
[0], 0, "Extent handle not open");
155 retval
= ext2fs_extent_get(current_handle
, op
, &extent
);
157 com_err(argv
[0], retval
, 0);
160 dbg_print_extent(0, &extent
);
163 void do_current_node(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
164 void *infop
EXT2FS_ATTR((unused
)))
166 generic_goto_node("current_node", argc
, argv
, EXT2_EXTENT_CURRENT
);
169 void do_root_node(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
170 void *infop
EXT2FS_ATTR((unused
)))
172 generic_goto_node("root_node", argc
, argv
, EXT2_EXTENT_ROOT
);
175 void do_last_leaf(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
176 void *infop
EXT2FS_ATTR((unused
)))
178 generic_goto_node("last_leaf", argc
, argv
, EXT2_EXTENT_LAST_LEAF
);
181 void do_first_sib(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
182 void *infop
EXT2FS_ATTR((unused
)))
184 generic_goto_node("first_sib", argc
, argv
, EXT2_EXTENT_FIRST_SIB
);
187 void do_last_sib(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
188 void *infop
EXT2FS_ATTR((unused
)))
190 generic_goto_node("next_sib", argc
, argv
, EXT2_EXTENT_LAST_SIB
);
193 void do_next_sib(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
194 void *infop
EXT2FS_ATTR((unused
)))
196 generic_goto_node("next_sib", argc
, argv
, EXT2_EXTENT_NEXT_SIB
);
199 void do_prev_sib(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
200 void *infop
EXT2FS_ATTR((unused
)))
202 generic_goto_node("prev_sib", argc
, argv
, EXT2_EXTENT_PREV_SIB
);
205 void do_next_leaf(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
206 void *infop
EXT2FS_ATTR((unused
)))
208 generic_goto_node("next_leaf", argc
, argv
, EXT2_EXTENT_NEXT_LEAF
);
211 void do_prev_leaf(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
212 void *infop
EXT2FS_ATTR((unused
)))
214 generic_goto_node("prev_leaf", argc
, argv
, EXT2_EXTENT_PREV_LEAF
);
217 void do_next(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
218 void *infop
EXT2FS_ATTR((unused
)))
220 generic_goto_node("next", argc
, argv
, EXT2_EXTENT_NEXT
);
223 void do_prev(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
224 void *infop
EXT2FS_ATTR((unused
)))
226 generic_goto_node("prev", argc
, argv
, EXT2_EXTENT_PREV
);
229 void do_up(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
230 void *infop
EXT2FS_ATTR((unused
)))
232 generic_goto_node("up", argc
, argv
, EXT2_EXTENT_UP
);
235 void do_down(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
236 void *infop
EXT2FS_ATTR((unused
)))
238 generic_goto_node("down", argc
, argv
, EXT2_EXTENT_DOWN
);
241 void do_delete_node(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
242 void *infop
EXT2FS_ATTR((unused
)))
244 struct ext2fs_extent extent
;
247 if (common_extent_args_process(argc
, argv
, 1, 1, "delete_node",
248 "", CHECK_FS_RW
| CHECK_FS_BITMAPS
))
251 retval
= ext2fs_extent_delete(current_handle
, 0);
253 com_err(argv
[0], retval
, 0);
257 retval
= ext2fs_extent_get(current_handle
, EXT2_EXTENT_CURRENT
,
261 dbg_print_extent(0, &extent
);
264 void do_replace_node(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
265 void *infop
EXT2FS_ATTR((unused
)))
267 const char *usage
= "[--uninit] <lblk> <len> <pblk>";
269 struct ext2fs_extent extent
;
272 if (common_extent_args_process(argc
, argv
, 3, 5, "replace_node",
273 usage
, CHECK_FS_RW
| CHECK_FS_BITMAPS
))
278 if (!strcmp(argv
[1], "--uninit")) {
281 extent
.e_flags
|= EXT2_EXTENT_FLAGS_UNINIT
;
285 fprintf(stderr
, "Usage: %s %s\n", argv
[0], usage
);
289 err
= strtoblk(argv
[0], argv
[1], "logical block", &extent
.e_lblk
);
293 extent
.e_len
= parse_ulong(argv
[2], argv
[0], "length", &err
);
297 err
= strtoblk(argv
[0], argv
[3], "physical block", &extent
.e_pblk
);
301 retval
= ext2fs_extent_replace(current_handle
, 0, &extent
);
303 com_err(argv
[0], retval
, 0);
306 generic_goto_node(NULL
, argc
, argv
, EXT2_EXTENT_CURRENT
);
309 void do_split_node(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
310 void *infop
EXT2FS_ATTR((unused
)))
314 if (common_extent_args_process(argc
, argv
, 1, 1, "split_node",
315 "", CHECK_FS_RW
| CHECK_FS_BITMAPS
))
318 retval
= ext2fs_extent_node_split(current_handle
);
320 com_err(argv
[0], retval
, 0);
323 generic_goto_node(NULL
, argc
, argv
, EXT2_EXTENT_CURRENT
);
326 void do_insert_node(int argc
, char *argv
[], int sci_idx
EXT2FS_ATTR((unused
)),
327 void *infop
EXT2FS_ATTR((unused
)))
329 const char *usage
= "[--after] [--uninit] <lblk> <len> <pblk>";
331 struct ext2fs_extent extent
;
336 if (common_extent_args_process(argc
, argv
, 3, 6, "insert_node",
337 usage
, CHECK_FS_RW
| CHECK_FS_BITMAPS
))
345 if (!strcmp(argv
[1], "--after")) {
348 flags
|= EXT2_EXTENT_INSERT_AFTER
;
351 if (!strcmp(argv
[1], "--uninit")) {
354 extent
.e_flags
|= EXT2_EXTENT_FLAGS_UNINIT
;
361 fprintf(stderr
, "usage: %s %s\n", cmd
, usage
);
365 err
= strtoblk(cmd
, argv
[1], "logical block", &extent
.e_lblk
);
369 extent
.e_len
= parse_ulong(argv
[2], cmd
, "length", &err
);
373 err
= strtoblk(cmd
, argv
[3], "physical block", &extent
.e_pblk
);
377 retval
= ext2fs_extent_insert(current_handle
, flags
, &extent
);
379 com_err(cmd
, retval
, 0);
382 generic_goto_node(NULL
, argc
, argv
, EXT2_EXTENT_CURRENT
);
385 void do_set_bmap(int argc
, char **argv
, int sci_idx
EXT2FS_ATTR((unused
)),
386 void *infop
EXT2FS_ATTR((unused
)))
388 const char *usage
= "[--uninit] <lblk> <pblk>";
389 struct ext2fs_extent extent
;
397 if (common_extent_args_process(argc
, argv
, 3, 5, "set_bmap",
398 usage
, CHECK_FS_RW
| CHECK_FS_BITMAPS
))
401 if (argc
> 2 && !strcmp(argv
[1], "--uninit")) {
404 flags
|= EXT2_EXTENT_SET_BMAP_UNINIT
;
408 fprintf(stderr
, "Usage: %s %s\n", cmd
, usage
);
412 err
= strtoblk(cmd
, argv
[1], "logical block", &logical
);
416 err
= strtoblk(cmd
, argv
[2], "physical block", &physical
);
420 retval
= ext2fs_extent_set_bmap(current_handle
, logical
,
423 com_err(cmd
, retval
, 0);
427 retval
= ext2fs_extent_get(current_handle
, EXT2_EXTENT_CURRENT
,
431 dbg_print_extent(0, &extent
);
434 void do_print_all(int argc
, char **argv
, int sci_idx
EXT2FS_ATTR((unused
)),
435 void *infop
EXT2FS_ATTR((unused
)))
437 const char *usage
= "[--leaf-only|--reverse|--reverse-leaf]";
438 struct ext2fs_extent extent
;
440 errcode_t end_err
= EXT2_ET_EXTENT_NO_NEXT
;
441 int op
= EXT2_EXTENT_NEXT
;
442 int first_op
= EXT2_EXTENT_ROOT
;
445 if (common_extent_args_process(argc
, argv
, 1, 2, "print_all",
450 if (!strcmp(argv
[1], "--leaf-only"))
451 op
= EXT2_EXTENT_NEXT_LEAF
;
452 else if (!strcmp(argv
[1], "--reverse")) {
453 op
= EXT2_EXTENT_PREV
;
454 first_op
= EXT2_EXTENT_LAST_LEAF
;
455 end_err
= EXT2_ET_EXTENT_NO_PREV
;
456 } else if (!strcmp(argv
[1], "--reverse-leaf")) {
457 op
= EXT2_EXTENT_PREV_LEAF
;
458 first_op
= EXT2_EXTENT_LAST_LEAF
;
459 end_err
= EXT2_ET_EXTENT_NO_PREV
;
461 fprintf(stderr
, "Usage: %s %s\n", argv
[0], usage
);
466 retval
= ext2fs_extent_get(current_handle
, first_op
, &extent
);
468 com_err(argv
[0], retval
, 0);
471 dbg_print_extent(0, &extent
);
474 retval
= ext2fs_extent_get(current_handle
, op
, &extent
);
475 if (retval
== end_err
)
479 com_err(argv
[0], retval
, 0);
482 dbg_print_extent(0, &extent
);
486 void do_fix_parents(int argc
, char **argv
, int sci_idx
EXT2FS_ATTR((unused
)),
487 void *infop
EXT2FS_ATTR((unused
)))
491 if (common_extent_args_process(argc
, argv
, 1, 1, "fix_parents", "",
495 retval
= ext2fs_extent_fix_parents(current_handle
);
497 com_err(argv
[0], retval
, 0);
502 void do_info(int argc
, char **argv
, int sci_idx
EXT2FS_ATTR((unused
)),
503 void *infop
EXT2FS_ATTR((unused
)))
505 struct ext2fs_extent extent
;
506 struct ext2_extent_info info
;
509 if (common_extent_args_process(argc
, argv
, 1, 1, "info", "", 0))
512 retval
= ext2fs_extent_get_info(current_handle
, &info
);
514 com_err(argv
[0], retval
, 0);
518 retval
= ext2fs_extent_get(current_handle
,
519 EXT2_EXTENT_CURRENT
, &extent
);
521 com_err(argv
[0], retval
, 0);
525 dbg_print_extent(0, &extent
);
527 printf("Current handle location: %d/%d (max: %d, bytes %d), level %d/%d\n",
528 info
.curr_entry
, info
.num_entries
, info
.max_entries
,
529 info
.bytes_avail
, info
.curr_level
, info
.max_depth
);
530 printf("\tmax lblk: %llu, max pblk: %llu\n", info
.max_lblk
,
532 printf("\tmax_len: %u, max_uninit_len: %u\n", info
.max_len
,
533 info
.max_uninit_len
);
536 void do_goto_block(int argc
, char **argv
, int sci_idx
EXT2FS_ATTR((unused
)),
537 void *infop
EXT2FS_ATTR((unused
)))
543 if (common_extent_args_process(argc
, argv
, 2, 3, "goto_block",
547 if (strtoblk(argv
[0], argv
[1], NULL
, &blk
))
551 level
= parse_ulong(argv
[2], argv
[0], "level", &err
);
556 retval
= ext2fs_extent_goto2(current_handle
, level
, (blk64_t
) blk
);
559 com_err(argv
[0], retval
,
560 "while trying to go to block %llu, level %d",
561 (unsigned long long) blk
, level
);
565 generic_goto_node(NULL
, argc
, argv
, EXT2_EXTENT_CURRENT
);