blob: 25b89465d67757ddc5b3a852ad32afaea01bd254 [file] [log] [blame]
JP Abgralle0ed7402014-03-19 19:08:39 -07001/*
2 * extent_inode.c --- direct extent tree manipulation
3 *
4 * Copyright (C) 2012 Theodore Ts'o. This file may be redistributed
5 * under the terms of the GNU Public License.
6 */
7
8#include <stdio.h>
9#include <unistd.h>
10#include <stdlib.h>
11#include <ctype.h>
12#include <string.h>
13#include <time.h>
14#ifdef HAVE_ERRNO_H
15#include <errno.h>
16#endif
17#include <sys/types.h>
18#ifdef HAVE_GETOPT_H
19#include <getopt.h>
20#else
21extern int optind;
22extern char *optarg;
23#endif
24
25#include "debugfs.h"
26
27static ext2_ino_t current_ino;
28static ext2_extent_handle_t current_handle;
29
30static void dbg_print_extent(char *desc, struct ext2fs_extent *extent)
31{
32 if (desc)
33 printf("%s: ", desc);
34 printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ",
35 extent->e_lblk, extent->e_lblk + extent->e_len - 1,
36 extent->e_len, extent->e_pblk);
37 if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF)
38 fputs("LEAF ", stdout);
39 if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
40 fputs("UNINIT ", stdout);
41 if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
42 fputs("2ND_VISIT ", stdout);
43 if (!extent->e_flags)
44 fputs("(none)", stdout);
45 fputc('\n', stdout);
46
47}
48
49static int common_extent_args_process(int argc, char *argv[], int min_argc,
50 int max_argc, const char *cmd,
51 const char *usage, int flags)
52{
53 if (common_args_process(argc, argv, min_argc, max_argc, cmd,
54 usage, flags))
55 return 1;
56
57 if (!current_handle) {
58 com_err(cmd, 0, "Extent handle not open");
59 return 1;
60 }
61 return 0;
62}
63
64static char *orig_prompt, *extent_prompt;
65
66void do_extent_open(int argc, char *argv[])
67{
68 ext2_ino_t inode;
69 int ret;
70 errcode_t retval;
71 char *cp;
72
73 if (check_fs_open(argv[0]))
74 return;
75
76 if (argc == 1) {
77 if (current_ino)
78 printf("Current inode is %d\n", current_ino);
79 else
80 printf("No current inode\n");
81 return;
82 }
83
84 if (common_inode_args_process(argc, argv, &inode, 0))
85 return;
86
87 current_ino = 0;
88
89 retval = ext2fs_extent_open(current_fs, inode, &current_handle);
90 if (retval) {
91 com_err(argv[1], retval, "while opening extent handle");
92 return;
93 }
94
95 current_ino = inode;
96
97 orig_prompt = ss_get_prompt(sci_idx);
98 extent_prompt = malloc(strlen(orig_prompt) + 32);
99 strcpy(extent_prompt, orig_prompt);
100 cp = strchr(extent_prompt, ':');
101 if (cp)
102 *cp = 0;
103 sprintf(extent_prompt + strlen(extent_prompt), " (extent ino %d): ",
104 current_ino);
105 ss_add_request_table(sci_idx, &extent_cmds, 1, &ret);
106 ss_set_prompt(sci_idx, extent_prompt);
107 return;
108}
109
110void do_extent_close(int argc, char *argv[])
111{
112 int ret;
113
114 if (common_args_process(argc, argv, 1, 1,
115 "extent_close", "", 0))
116 return;
117
118 if (!current_handle) {
119 com_err(argv[0], 0, "Extent handle not open");
120 return;
121 }
122
123 ext2fs_extent_free(current_handle);
124 current_handle = NULL;
125 current_ino = 0;
126 ss_delete_request_table(sci_idx, &extent_cmds, &ret);
127 ss_set_prompt(sci_idx, orig_prompt);
128 free(extent_prompt);
129 extent_prompt = NULL;
130}
131
132static void generic_goto_node(const char *my_name, int argc,
133 char **argv, int op)
134{
135 struct ext2fs_extent extent;
136 errcode_t retval;
137
138 if (my_name && common_args_process(argc, argv, 1, 1,
139 my_name, "", 0))
140 return;
141
142 if (!current_handle) {
143 com_err(argv[0], 0, "Extent handle not open");
144 return;
145 }
146
147 retval = ext2fs_extent_get(current_handle, op, &extent);
148 if (retval) {
149 com_err(argv[0], retval, 0);
150 return;
151 }
152 dbg_print_extent(0, &extent);
153}
154
155void do_current_node(int argc, char *argv[])
156{
157 generic_goto_node("current_node", argc, argv, EXT2_EXTENT_CURRENT);
158}
159
160void do_root_node(int argc, char *argv[])
161{
162 generic_goto_node("root_node", argc, argv, EXT2_EXTENT_ROOT);
163}
164
165void do_last_leaf(int argc, char *argv[])
166{
167 generic_goto_node("last_leaf", argc, argv, EXT2_EXTENT_LAST_LEAF);
168}
169
170void do_first_sib(int argc, char *argv[])
171{
172 generic_goto_node("first_sib", argc, argv, EXT2_EXTENT_FIRST_SIB);
173}
174
175void do_last_sib(int argc, char *argv[])
176{
177 generic_goto_node("next_sib", argc, argv, EXT2_EXTENT_LAST_SIB);
178}
179
180void do_next_sib(int argc, char *argv[])
181{
182 generic_goto_node("next_sib", argc, argv, EXT2_EXTENT_NEXT_SIB);
183}
184
185void do_prev_sib(int argc, char *argv[])
186{
187 generic_goto_node("prev_sib", argc, argv, EXT2_EXTENT_PREV_SIB);
188}
189
190void do_next_leaf(int argc, char *argv[])
191{
192 generic_goto_node("next_leaf", argc, argv, EXT2_EXTENT_NEXT_LEAF);
193}
194
195void do_prev_leaf(int argc, char *argv[])
196{
197 generic_goto_node("prev_leaf", argc, argv, EXT2_EXTENT_PREV_LEAF);
198}
199
200void do_next(int argc, char *argv[])
201{
202 generic_goto_node("next", argc, argv, EXT2_EXTENT_NEXT);
203}
204
205void do_prev(int argc, char *argv[])
206{
207 generic_goto_node("prev", argc, argv, EXT2_EXTENT_PREV);
208}
209
210void do_up(int argc, char *argv[])
211{
212 generic_goto_node("up", argc, argv, EXT2_EXTENT_UP);
213}
214
215void do_down(int argc, char *argv[])
216{
217 generic_goto_node("down", argc, argv, EXT2_EXTENT_DOWN);
218}
219
220void do_delete_node(int argc, char *argv[])
221{
222 struct ext2fs_extent extent;
223 errcode_t retval;
224
225 if (common_extent_args_process(argc, argv, 1, 1, "delete_node",
226 "", CHECK_FS_RW | CHECK_FS_BITMAPS))
227 return;
228
229 retval = ext2fs_extent_delete(current_handle, 0);
230 if (retval) {
231 com_err(argv[0], retval, 0);
232 return;
233 }
234
235 retval = ext2fs_extent_get(current_handle, EXT2_EXTENT_CURRENT,
236 &extent);
237 if (retval)
238 return;
239 dbg_print_extent(0, &extent);
240}
241
242void do_replace_node(int argc, char *argv[])
243{
244 const char *usage = "[--uninit] <lblk> <len> <pblk>";
245 errcode_t retval;
246 struct ext2fs_extent extent;
247 int err;
248
249 if (common_extent_args_process(argc, argv, 3, 5, "replace_node",
250 usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
251 return;
252
253 extent.e_flags = 0;
254
255 if (!strcmp(argv[1], "--uninit")) {
256 argc--;
257 argv++;
258 extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
259 }
260
261 if (argc != 4) {
262 fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
263 return;
264 }
265
266 err = strtoblk(argv[0], argv[1], &extent.e_lblk);
267 if (err)
268 return;
269
270 extent.e_len = parse_ulong(argv[2], argv[0], "logical block", &err);
271 if (err)
272 return;
273
274 err = strtoblk(argv[0], argv[3], &extent.e_pblk);
275 if (err)
276 return;
277
278 retval = ext2fs_extent_replace(current_handle, 0, &extent);
279 if (retval) {
280 com_err(argv[0], retval, 0);
281 return;
282 }
283 generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
284}
285
286void do_split_node(int argc, char *argv[])
287{
288 errcode_t retval;
289
290 if (common_extent_args_process(argc, argv, 1, 1, "split_node",
291 "", CHECK_FS_RW | CHECK_FS_BITMAPS))
292 return;
293
294 retval = ext2fs_extent_node_split(current_handle);
295 if (retval) {
296 com_err(argv[0], retval, 0);
297 return;
298 }
299 generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
300}
301
302void do_insert_node(int argc, char *argv[])
303{
304 const char *usage = "[--after] [--uninit] <lblk> <len> <pblk>";
305 errcode_t retval;
306 struct ext2fs_extent extent;
307 char *cmd;
308 int err;
309 int flags = 0;
310
311 if (common_extent_args_process(argc, argv, 3, 6, "insert_node",
312 usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
313 return;
314
315 cmd = argv[0];
316
317 extent.e_flags = 0;
318
319 while (argc > 2) {
320 if (!strcmp(argv[1], "--after")) {
321 argc--;
322 argv++;
323 flags |= EXT2_EXTENT_INSERT_AFTER;
324 continue;
325 }
326 if (!strcmp(argv[1], "--uninit")) {
327 argc--;
328 argv++;
329 extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
330 continue;
331 }
332 break;
333 }
334
335 if (argc != 4) {
336 fprintf(stderr, "usage: %s %s\n", cmd, usage);
337 return;
338 }
339
340 err = strtoblk(cmd, argv[1], &extent.e_lblk);
341 if (err)
342 return;
343
344 extent.e_len = parse_ulong(argv[2], cmd,
345 "length", &err);
346 if (err)
347 return;
348
349 err = strtoblk(cmd, argv[3], &extent.e_pblk);
350 if (err)
351 return;
352
353 retval = ext2fs_extent_insert(current_handle, flags, &extent);
354 if (retval) {
355 com_err(cmd, retval, 0);
356 return;
357 }
358 generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
359}
360
361void do_set_bmap(int argc, char **argv)
362{
363 const char *usage = "[--uninit] <lblk> <pblk>";
364 struct ext2fs_extent extent;
365 errcode_t retval;
366 blk64_t logical;
367 blk64_t physical;
368 char *cmd = argv[0];
369 int flags = 0;
370 int err;
371
372 if (common_extent_args_process(argc, argv, 3, 5, "set_bmap",
373 usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
374 return;
375
376 if (argc > 2 && !strcmp(argv[1], "--uninit")) {
377 argc--;
378 argv++;
379 flags |= EXT2_EXTENT_SET_BMAP_UNINIT;
380 }
381
382 if (argc != 3) {
383 fprintf(stderr, "Usage: %s %s\n", cmd, usage);
384 return;
385 }
386
387 err = strtoblk(cmd, argv[1], &logical);
388 if (err)
389 return;
390
391 err = strtoblk(cmd, argv[2], &physical);
392 if (err)
393 return;
394
395 retval = ext2fs_extent_set_bmap(current_handle, logical,
396 physical, flags);
397 if (retval) {
398 com_err(cmd, retval, 0);
399 return;
400 }
401
402 retval = ext2fs_extent_get(current_handle, EXT2_EXTENT_CURRENT,
403 &extent);
404 if (retval)
405 return;
406 dbg_print_extent(0, &extent);
407}
408
409void do_print_all(int argc, char **argv)
410{
411 const char *usage = "[--leaf-only|--reverse|--reverse-leaf]";
412 struct ext2fs_extent extent;
413 errcode_t retval;
414 errcode_t end_err = EXT2_ET_EXTENT_NO_NEXT;
415 int op = EXT2_EXTENT_NEXT;
416 int first_op = EXT2_EXTENT_ROOT;
417
418
419 if (common_extent_args_process(argc, argv, 1, 2, "print_all",
420 usage, 0))
421 return;
422
423 if (argc == 2) {
424 if (!strcmp(argv[1], "--leaf-only"))
425 op = EXT2_EXTENT_NEXT_LEAF;
426 else if (!strcmp(argv[1], "--reverse")) {
427 op = EXT2_EXTENT_PREV;
428 first_op = EXT2_EXTENT_LAST_LEAF;
429 end_err = EXT2_ET_EXTENT_NO_PREV;
430 } else if (!strcmp(argv[1], "--reverse-leaf")) {
431 op = EXT2_EXTENT_PREV_LEAF;
432 first_op = EXT2_EXTENT_LAST_LEAF;
433 end_err = EXT2_ET_EXTENT_NO_PREV;
434 } else {
435 fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
436 return;
437 }
438 }
439
440 retval = ext2fs_extent_get(current_handle, first_op, &extent);
441 if (retval) {
442 com_err(argv[0], retval, 0);
443 return;
444 }
445 dbg_print_extent(0, &extent);
446
447 while (1) {
448 retval = ext2fs_extent_get(current_handle, op, &extent);
449 if (retval == end_err)
450 break;
451
452 if (retval) {
453 com_err(argv[0], retval, 0);
454 return;
455 }
456 dbg_print_extent(0, &extent);
457 }
458}
459
460void do_fix_parents(int argc, char **argv)
461{
462 errcode_t retval;
463
464 if (common_extent_args_process(argc, argv, 1, 1, "fix_parents", "",
465 CHECK_FS_RW))
466 return;
467
468 retval = ext2fs_extent_fix_parents(current_handle);
469 if (retval) {
470 com_err(argv[0], retval, 0);
471 return;
472 }
473}
474
475void do_info(int argc, char **argv)
476{
477 struct ext2fs_extent extent;
478 struct ext2_extent_info info;
479 errcode_t retval;
480
481 if (common_extent_args_process(argc, argv, 1, 1, "info", "", 0))
482 return;
483
484 retval = ext2fs_extent_get_info(current_handle, &info);
485 if (retval) {
486 com_err(argv[0], retval, 0);
487 return;
488 }
489
490 retval = ext2fs_extent_get(current_handle,
491 EXT2_EXTENT_CURRENT, &extent);
492 if (retval) {
493 com_err(argv[0], retval, 0);
494 return;
495 }
496
497 dbg_print_extent(0, &extent);
498
499 printf("Current handle location: %d/%d (max: %d, bytes %d), level %d/%d\n",
500 info.curr_entry, info.num_entries, info.max_entries,
501 info.bytes_avail, info.curr_level, info.max_depth);
502 printf("\tmax lblk: %llu, max pblk: %llu\n", info.max_lblk,
503 info.max_pblk);
504 printf("\tmax_len: %u, max_uninit_len: %u\n", info.max_len,
505 info.max_uninit_len);
506}
507
508void do_goto_block(int argc, char **argv)
509{
510 errcode_t retval;
511 blk64_t blk;
512 int level = 0, err;
513
514 if (common_extent_args_process(argc, argv, 2, 3, "goto_block",
515 "block [level]", 0))
516 return;
517
518 if (strtoblk(argv[0], argv[1], &blk))
519 return;
520
521 if (argc == 3) {
522 level = parse_ulong(argv[2], argv[0], "level", &err);
523 if (err)
524 return;
525 }
526
527 retval = ext2fs_extent_goto2(current_handle, level, (blk64_t) blk);
528
529 if (retval) {
530 com_err(argv[0], retval,
531 "while trying to go to block %llu, level %d",
532 (unsigned long long) blk, level);
533 return;
534 }
535
536 generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
537}