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