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