2 * debugfs.c --- a program which allows you to attach an ext2fs
3 * filesystem and play with it.
5 * Copyright (C) 1993 Theodore Ts'o. This file may be redistributed
6 * under the terms of the GNU Public License.
8 * Modifications by Robert Sanders <gt8134b@prism.gatech.edu>
24 extern int optreset
; /* defined by BSD, but not others */
30 #include <sys/types.h>
33 #include "et/com_err.h"
37 extern ss_request_table debug_cmds
;
39 ext2_filsys fs
= NULL
;
42 static void open_filesystem(char *device
, int open_flags
)
46 retval
= ext2fs_open(device
, open_flags
, 0, 0, unix_io_manager
, &fs
);
48 com_err(device
, retval
, "while opening filesystem");
52 retval
= ext2fs_read_inode_bitmap(fs
);
54 com_err(device
, retval
, "while reading inode bitmap");
57 retval
= ext2fs_read_block_bitmap(fs
);
59 com_err(device
, retval
, "while reading block bitmap");
62 root
= cwd
= EXT2_ROOT_INO
;
66 retval
= ext2fs_close(fs
);
68 com_err(device
, retval
, "while trying to close filesystem");
72 void do_open_filesys(int argc
, char **argv
)
74 const char *usage
= "Usage: open [-w] <device>";
80 optreset
= 1; /* Makes BSD getopt happy */
82 while ((c
= getopt (argc
, argv
, "w")) != EOF
) {
85 open_flags
= EXT2_FLAG_RW
;
88 com_err(argv
[0], 0, usage
);
92 if (optind
!= argc
-1) {
93 com_err(argv
[0], 0, usage
);
96 if (check_fs_not_open(argv
[0]))
98 open_filesystem(argv
[optind
], open_flags
);
101 static void close_filesystem(NOARGS
)
105 if (fs
->flags
& EXT2_FLAG_IB_DIRTY
) {
106 retval
= ext2fs_write_inode_bitmap(fs
);
108 com_err("ext2fs_write_inode_bitmap", retval
, "");
110 if (fs
->flags
& EXT2_FLAG_BB_DIRTY
) {
111 retval
= ext2fs_write_block_bitmap(fs
);
113 com_err("ext2fs_write_block_bitmap", retval
, "");
115 retval
= ext2fs_close(fs
);
117 com_err("ext2fs_close", retval
, "");
122 void do_close_filesys(int argc
, char **argv
)
125 com_err(argv
[0], 0, "Usage: close_filesys");
128 if (check_fs_open(argv
[0]))
133 void do_init_filesys(int argc
, char **argv
)
135 const char *usage
= "Usage: initialize <device> <blocksize>";
136 struct ext2_super_block param
;
141 com_err(argv
[0], 0, usage
);
144 if (check_fs_not_open(argv
[0]))
147 memset(¶m
, 0, sizeof(struct ext2_super_block
));
148 param
.s_blocks_count
= strtoul(argv
[2], &tmp
, 0);
150 com_err(argv
[0], 0, "Bad blocks count - %s", argv
[2]);
153 retval
= ext2fs_initialize(argv
[1], 0, ¶m
, unix_io_manager
, &fs
);
155 com_err(argv
[1], retval
, "while initializing filesystem");
159 root
= cwd
= EXT2_ROOT_INO
;
163 void do_show_super_stats(int argc
, char *argv
[])
169 com_err(argv
[0], 0, "Usage: show_super");
172 if (check_fs_open(argv
[0]))
175 fprintf(out
, "Filesystem is read-%s\n", fs
->flags
& EXT2_FLAG_RW
?
177 fprintf(out
, "Last mount time = %s", ctime(&fs
->super
->s_mtime
));
178 fprintf(out
, "Last write time = %s", ctime(&fs
->super
->s_wtime
));
179 fprintf(out
, "Mount counts = %d (maximal = %d)\n",
180 fs
->super
->s_mnt_count
, fs
->super
->s_max_mnt_count
);
181 fprintf(out
, "Superblock size = %d\n", sizeof(struct ext2_super_block
));
182 fprintf(out
, "Block size = %d, fragment size = %d\n",
183 EXT2_BLOCK_SIZE(fs
->super
), EXT2_FRAG_SIZE(fs
->super
));
184 fprintf(out
, "Inode size = %d\n", EXT2_INODE_SIZE(fs
->super
));
185 fprintf(out
, "%d inodes, %d free\n", fs
->super
->s_inodes_count
,
186 fs
->super
->s_free_inodes_count
);
187 fprintf(out
, "%d blocks, %d free, %d reserved, first block = %d\n",
188 fs
->super
->s_blocks_count
, fs
->super
->s_free_blocks_count
,
189 fs
->super
->s_r_blocks_count
, fs
->super
->s_first_data_block
);
190 fprintf(out
, "%d blocks per group\n", fs
->super
->s_blocks_per_group
);
191 fprintf(out
, "%d fragments per group\n", fs
->super
->s_frags_per_group
);
192 fprintf(out
, "%d inodes per group\n", EXT2_INODES_PER_GROUP(fs
->super
));
193 fprintf(out
, "%ld group%s (%ld descriptors block%s)\n",
194 fs
->group_desc_count
, (fs
->group_desc_count
!= 1) ? "s" : "",
195 fs
->desc_blocks
, (fs
->desc_blocks
!= 1) ? "s" : "");
196 for (i
= 0; i
< fs
->group_desc_count
; i
++)
197 fprintf(out
, " Group %2d: block bitmap at %d, "
198 "inode bitmap at %d, "
199 "inode table at %d\n"
202 "%d used director%s\n",
203 i
, fs
->group_desc
[i
].bg_block_bitmap
,
204 fs
->group_desc
[i
].bg_inode_bitmap
,
205 fs
->group_desc
[i
].bg_inode_table
,
206 fs
->group_desc
[i
].bg_free_blocks_count
,
207 fs
->group_desc
[i
].bg_free_blocks_count
!= 1 ? "s" : "",
208 fs
->group_desc
[i
].bg_free_inodes_count
,
209 fs
->group_desc
[i
].bg_free_inodes_count
!= 1 ? "s" : "",
210 fs
->group_desc
[i
].bg_used_dirs_count
,
211 fs
->group_desc
[i
].bg_used_dirs_count
!= 1 ? "ies" : "y");
215 struct list_blocks_struct
{
220 static int list_blocks_proc(ext2_filsys fs
, blk_t
*blocknr
, int blockcnt
,
223 struct list_blocks_struct
*lb
= (struct list_blocks_struct
*) private;
225 fprintf(lb
->f
, "%d ", *blocknr
);
231 static void dump_blocks(FILE *f
, ino_t inode
)
233 struct list_blocks_struct lb
;
235 fprintf(f
, "BLOCKS:\n");
238 ext2fs_block_iterate(fs
,inode
,0,NULL
,list_blocks_proc
,(void *)&lb
);
240 fprintf(f
, "\nTOTAL: %d\n", lb
.total
);
245 static void dump_inode(ino_t inode_num
, struct ext2_inode inode
)
251 if (LINUX_S_ISDIR(inode
.i_mode
)) i_type
= "directory";
252 else if (LINUX_S_ISREG(inode
.i_mode
)) i_type
= "regular";
253 else if (LINUX_S_ISLNK(inode
.i_mode
)) i_type
= "symlink";
254 else if (LINUX_S_ISBLK(inode
.i_mode
)) i_type
= "block special";
255 else if (LINUX_S_ISCHR(inode
.i_mode
)) i_type
= "character special";
256 else if (LINUX_S_ISFIFO(inode
.i_mode
)) i_type
= "FIFO";
257 else if (LINUX_S_ISSOCK(inode
.i_mode
)) i_type
= "socket";
258 else i_type
= "bad type";
259 fprintf(out
, "Inode: %ld Type: %s ", inode_num
, i_type
);
260 fprintf(out
, "Mode: %04o Flags: 0x%x Version: %d\n",
261 inode
.i_mode
& 0777, inode
.i_flags
, inode
.i_version
);
262 fprintf(out
, "User: %5d Group: %5d Size: %d\n",
263 inode
.i_uid
, inode
.i_gid
, inode
.i_size
);
264 if (fs
->super
->s_creator_os
== EXT2_OS_HURD
)
266 "File ACL: %d Directory ACL: %d Translator: %d\n",
267 inode
.i_file_acl
, inode
.i_dir_acl
,
268 inode
.osd1
.hurd1
.h_i_translator
);
270 fprintf(out
, "File ACL: %d Directory ACL: %d\n",
271 inode
.i_file_acl
, inode
.i_dir_acl
);
272 fprintf(out
, "Links: %d Blockcount: %d\n", inode
.i_links_count
,
275 fprintf(out
, "Fragment: Address: %d Number: %d Size: %d\n",
276 inode
.i_faddr
, inode
.i_frag
, inode
.i_fsize
);
278 fprintf(out
, "ctime: 0x%08x -- %s", inode
.i_ctime
,
279 ctime(&inode
.i_ctime
));
280 fprintf(out
, "atime: 0x%08x -- %s", inode
.i_atime
,
281 ctime(&inode
.i_atime
));
282 fprintf(out
, "mtime: 0x%08x -- %s", inode
.i_mtime
,
283 ctime(&inode
.i_mtime
));
285 fprintf(out
, "dtime: 0x%08x -- %s", inode
.i_dtime
,
286 ctime(&inode
.i_dtime
));
287 if (LINUX_S_ISLNK(inode
.i_mode
) && inode
.i_blocks
== 0)
288 fprintf(out
, "Fast_link_dest: %s\n", (char *)inode
.i_block
);
290 dump_blocks(out
, inode_num
);
295 void do_stat(int argc
, char *argv
[])
298 struct ext2_inode inode_buf
;
302 com_err(argv
[0], 0, "Usage: stat <file>");
305 if (check_fs_open(argv
[0]))
307 inode
= string_to_inode(argv
[1]);
311 retval
= ext2fs_read_inode(fs
,inode
,&inode_buf
);
314 com_err(argv
[0], 0, "Reading inode");
318 dump_inode(inode
,inode_buf
);
322 void do_chroot(int argc
, char *argv
[])
328 com_err(argv
[0], 0, "Usage: chroot <file>");
331 if (check_fs_open(argv
[0]))
333 inode
= string_to_inode(argv
[1]);
337 retval
= ext2fs_check_directory(fs
, inode
);
339 com_err(argv
[1], retval
, "");
345 void do_clri(int argc
, char *argv
[])
349 struct ext2_inode inode_buf
;
352 com_err(argv
[0], 0, "Usage: clri <file>");
355 if (check_fs_open(argv
[0]))
357 if (!(fs
->flags
& EXT2_FLAG_RW
)) {
358 com_err(argv
[0], 0, "Filesystem opened read/only");
361 inode
= string_to_inode(argv
[1]);
365 retval
= ext2fs_read_inode(fs
, inode
, &inode_buf
);
367 com_err(argv
[0], 0, "while trying to read inode %d", inode
);
370 memset(&inode_buf
, 0, sizeof(inode_buf
));
371 retval
= ext2fs_write_inode(fs
, inode
, &inode_buf
);
373 com_err(argv
[0], retval
, "while trying to write inode %d",
379 void do_freei(int argc
, char *argv
[])
384 com_err(argv
[0], 0, "Usage: freei <file>");
387 if (check_fs_open(argv
[0]))
389 if (!(fs
->flags
& EXT2_FLAG_RW
)) {
390 com_err(argv
[0], 0, "Filesystem opened read/only");
393 inode
= string_to_inode(argv
[1]);
397 if (!ext2fs_test_inode_bitmap(fs
->inode_map
,inode
))
398 com_err(argv
[0], 0, "Warning: inode already clear");
399 ext2fs_unmark_inode_bitmap(fs
->inode_map
,inode
);
400 ext2fs_mark_ib_dirty(fs
);
403 void do_seti(int argc
, char *argv
[])
408 com_err(argv
[0], 0, "Usage: seti <file>");
411 if (check_fs_open(argv
[0]))
413 if (!(fs
->flags
& EXT2_FLAG_RW
)) {
414 com_err(argv
[0], 0, "Filesystem opened read/only");
417 inode
= string_to_inode(argv
[1]);
421 if (ext2fs_test_inode_bitmap(fs
->inode_map
,inode
))
422 com_err(argv
[0], 0, "Warning: inode already set");
423 ext2fs_mark_inode_bitmap(fs
->inode_map
,inode
);
424 ext2fs_mark_ib_dirty(fs
);
427 void do_testi(int argc
, char *argv
[])
432 com_err(argv
[0], 0, "Usage: testi <file>");
435 if (check_fs_open(argv
[0]))
437 inode
= string_to_inode(argv
[1]);
441 if (ext2fs_test_inode_bitmap(fs
->inode_map
,inode
))
442 printf("Inode %ld is marked in use\n", inode
);
444 printf("Inode %ld is not in use\n", inode
);
448 void do_freeb(int argc
, char *argv
[])
454 com_err(argv
[0], 0, "Usage: freeb <block>");
457 if (check_fs_open(argv
[0]))
459 if (!(fs
->flags
& EXT2_FLAG_RW
)) {
460 com_err(argv
[0], 0, "Filesystem opened read/only");
463 block
= strtoul(argv
[1], &tmp
, 0);
464 if (!block
|| *tmp
) {
465 com_err(argv
[0], 0, "No block 0");
468 if (!ext2fs_test_block_bitmap(fs
->block_map
,block
))
469 com_err(argv
[0], 0, "Warning: block already clear");
470 ext2fs_unmark_block_bitmap(fs
->block_map
,block
);
471 ext2fs_mark_bb_dirty(fs
);
474 void do_setb(int argc
, char *argv
[])
480 com_err(argv
[0], 0, "Usage: setb <block>");
483 if (check_fs_open(argv
[0]))
485 if (!(fs
->flags
& EXT2_FLAG_RW
)) {
486 com_err(argv
[0], 0, "Filesystem opened read/only");
489 block
= strtoul(argv
[1], &tmp
, 0);
490 if (!block
|| *tmp
) {
491 com_err(argv
[0], 0, "No block 0");
494 if (ext2fs_test_block_bitmap(fs
->block_map
,block
))
495 com_err(argv
[0], 0, "Warning: block already set");
496 ext2fs_mark_block_bitmap(fs
->block_map
,block
);
497 ext2fs_mark_bb_dirty(fs
);
500 void do_testb(int argc
, char *argv
[])
506 com_err(argv
[0], 0, "Usage: testb <block>");
509 if (check_fs_open(argv
[0]))
511 block
= strtoul(argv
[1], &tmp
, 0);
512 if (!block
|| *tmp
) {
513 com_err(argv
[0], 0, "No block 0");
516 if (ext2fs_test_block_bitmap(fs
->block_map
,block
))
517 printf("Block %d marked in use\n", block
);
518 else printf("Block %d not in use\n", block
);
521 static void modify_u8(char *com
, const char *prompt
,
522 const char *format
, __u8
*val
)
528 sprintf(buf
, format
, *val
);
529 printf("%30s [%s] ", prompt
, buf
);
530 fgets(buf
, sizeof(buf
), stdin
);
531 if (buf
[strlen (buf
) - 1] == '\n')
532 buf
[strlen (buf
) - 1] = '\0';
535 v
= strtol(buf
, &tmp
, 0);
537 com_err(com
, 0, "Bad value - %s", buf
);
542 static void modify_u16(char *com
, const char *prompt
,
543 const char *format
, __u16
*val
)
549 sprintf(buf
, format
, *val
);
550 printf("%30s [%s] ", prompt
, buf
);
551 fgets(buf
, sizeof(buf
), stdin
);
552 if (buf
[strlen (buf
) - 1] == '\n')
553 buf
[strlen (buf
) - 1] = '\0';
556 v
= strtol(buf
, &tmp
, 0);
558 com_err(com
, 0, "Bad value - %s", buf
);
563 static void modify_u32(char *com
, const char *prompt
,
564 const char *format
, __u32
*val
)
570 sprintf(buf
, format
, *val
);
571 printf("%30s [%s] ", prompt
, buf
);
572 fgets(buf
, sizeof(buf
), stdin
);
573 if (buf
[strlen (buf
) - 1] == '\n')
574 buf
[strlen (buf
) - 1] = '\0';
577 v
= strtol(buf
, &tmp
, 0);
579 com_err(com
, 0, "Bad value - %s", buf
);
585 void do_modify_inode(int argc
, char *argv
[])
587 struct ext2_inode inode
;
592 const char *hex_format
= "0x%x";
593 const char *octal_format
= "0%o";
594 const char *decimal_format
= "%d";
597 com_err(argv
[0], 0, "Usage: modify_inode <file>");
600 if (check_fs_open(argv
[0]))
602 if (!(fs
->flags
& EXT2_FLAG_RW
)) {
603 com_err(argv
[0], 0, "Filesystem opened read/only");
607 inode_num
= string_to_inode(argv
[1]);
611 retval
= ext2fs_read_inode(fs
, inode_num
, &inode
);
613 com_err(argv
[1], retval
, "while trying to read inode %d",
618 modify_u16(argv
[0], "Mode", octal_format
, &inode
.i_mode
);
619 modify_u16(argv
[0], "User ID", decimal_format
, &inode
.i_uid
);
620 modify_u16(argv
[0], "Group ID", decimal_format
, &inode
.i_gid
);
621 modify_u32(argv
[0], "Size", decimal_format
, &inode
.i_size
);
622 modify_u32(argv
[0], "Creation time", decimal_format
, &inode
.i_ctime
);
623 modify_u32(argv
[0], "Modification time", decimal_format
, &inode
.i_mtime
);
624 modify_u32(argv
[0], "Access time", decimal_format
, &inode
.i_atime
);
625 modify_u32(argv
[0], "Deletion time", decimal_format
, &inode
.i_dtime
);
626 modify_u16(argv
[0], "Link count", decimal_format
, &inode
.i_links_count
);
627 modify_u32(argv
[0], "Block count", decimal_format
, &inode
.i_blocks
);
628 modify_u32(argv
[0], "File flags", hex_format
, &inode
.i_flags
);
630 modify_u32(argv
[0], "Reserved1", decimal_format
, &inode
.i_reserved1
);
632 modify_u32(argv
[0], "File acl", decimal_format
, &inode
.i_file_acl
);
633 modify_u32(argv
[0], "Directory acl", decimal_format
, &inode
.i_dir_acl
);
635 if (fs
->super
->s_creator_os
== EXT2_OS_HURD
)
636 modify_u32(argv
[0], "Translator Block",
637 decimal_format
, &inode
.osd1
.hurd1
.h_i_translator
);
639 modify_u32(argv
[0], "Fragment address", decimal_format
, &inode
.i_faddr
);
641 modify_u8(argv
[0], "Fragment number", decimal_format
, &inode
.i_frag
);
642 modify_u8(argv
[0], "Fragment size", decimal_format
, &inode
.i_fsize
);
644 for (i
=0; i
< EXT2_NDIR_BLOCKS
; i
++) {
645 sprintf(buf
, "Direct Block #%d", i
);
646 modify_u32(argv
[0], buf
, decimal_format
, &inode
.i_block
[i
]);
648 modify_u32(argv
[0], "Indirect Block", decimal_format
,
649 &inode
.i_block
[EXT2_IND_BLOCK
]);
650 modify_u32(argv
[0], "Double Indirect Block", decimal_format
,
651 &inode
.i_block
[EXT2_DIND_BLOCK
]);
652 modify_u32(argv
[0], "Triple Indirect Block", decimal_format
,
653 &inode
.i_block
[EXT2_TIND_BLOCK
]);
654 retval
= ext2fs_write_inode(fs
, inode_num
, &inode
);
656 com_err(argv
[1], retval
, "while trying to write inode %d",
666 struct list_dir_struct
{
671 static int list_dir_proc(struct ext2_dir_entry
*dirent
,
677 char name
[EXT2_NAME_LEN
];
678 char tmp
[EXT2_NAME_LEN
+ 16];
680 struct list_dir_struct
*ls
= (struct list_dir_struct
*) private;
683 thislen
= (dirent
->name_len
< EXT2_NAME_LEN
) ? dirent
->name_len
:
685 strncpy(name
, dirent
->name
, thislen
);
686 name
[thislen
] = '\0';
688 sprintf(tmp
, "%d (%d) %s ", dirent
->inode
, dirent
->rec_len
, name
);
689 thislen
= strlen(tmp
);
691 if (ls
->col
+ thislen
> 80) {
692 fprintf(ls
->f
, "\n");
695 fprintf(ls
->f
, "%s", tmp
);
701 void do_list_dir(int argc
, char *argv
[])
705 struct list_dir_struct ls
;
708 com_err(argv
[0], 0, "Usage: list_dir [pathname]");
711 if (check_fs_open(argv
[0]))
715 inode
= string_to_inode(argv
[1]);
723 retval
= ext2fs_dir_iterate(fs
, inode
, DIRENT_FLAG_INCLUDE_EMPTY
,
724 0, list_dir_proc
, &ls
);
728 com_err(argv
[1], retval
, "");
733 void do_change_working_dir(int argc
, char *argv
[])
739 com_err(argv
[0], 0, "Usage: cd <file>");
742 if (check_fs_open(argv
[0]))
745 inode
= string_to_inode(argv
[1]);
749 retval
= ext2fs_check_directory(fs
, inode
);
751 com_err(argv
[1], retval
, "");
758 void do_print_working_directory(int argc
, char *argv
[])
761 char *pathname
= NULL
;
764 com_err(argv
[0], 0, "Usage: print_working_directory");
767 if (check_fs_open(argv
[0]))
770 retval
= ext2fs_get_pathname(fs
, cwd
, 0, &pathname
);
772 com_err(argv
[0], retval
,
773 "while trying to get pathname of cwd");
775 printf("[pwd] INODE: %6ld PATH: %s\n", cwd
, pathname
);
777 retval
= ext2fs_get_pathname(fs
, root
, 0, &pathname
);
779 com_err(argv
[0], retval
,
780 "while trying to get pathname of root");
782 printf("[root] INODE: %6ld PATH: %s\n", root
, pathname
);
787 static void make_link(char *sourcename
, char *destname
)
792 char *dest
, *cp
, *basename
;
795 * Get the source inode
797 inode
= string_to_inode(sourcename
);
800 basename
= strrchr(sourcename
, '/');
804 basename
= sourcename
;
806 * Figure out the destination. First see if it exists and is
809 if (! (retval
=ext2fs_namei(fs
, root
, cwd
, destname
, &dir
)))
813 * OK, it doesn't exist. See if it is
814 * '<dir>/basename' or 'basename'
816 cp
= strrchr(destname
, '/');
819 dir
= string_to_inode(destname
);
829 retval
= ext2fs_link(fs
, dir
, dest
, inode
, 0);
831 com_err("make_link", retval
, "");
836 void do_link(int argc
, char *argv
[])
839 com_err(argv
[0], 0, "Usage: link <source_file> <dest_name>");
842 if (check_fs_open(argv
[0]))
845 make_link(argv
[1], argv
[2]);
848 static void unlink_file_by_name(char *filename
)
854 basename
= strrchr(filename
, '/');
857 dir
= string_to_inode(filename
);
864 retval
= ext2fs_unlink(fs
, dir
, basename
, 0, 0);
866 com_err("unlink_file_by_name", retval
, "");
870 void do_unlink(int argc
, char *argv
[])
873 com_err(argv
[0], 0, "Usage: unlink <pathname>");
876 if (check_fs_open(argv
[0]))
879 unlink_file_by_name(argv
[1]);
882 void do_find_free_block(int argc
, char *argv
[])
884 blk_t free_blk
, goal
;
888 if ((argc
> 2) || (argc
==2 && *argv
[1] == '?')) {
889 com_err(argv
[0], 0, "Usage: find_free_block [goal]");
892 if (check_fs_open(argv
[0]))
896 goal
= strtol(argv
[1], &tmp
, 0);
898 com_err(argv
[0], 0, "Bad goal - %s", argv
[1]);
903 goal
= fs
->super
->s_first_data_block
;
905 retval
= ext2fs_new_block(fs
, goal
, 0, &free_blk
);
907 com_err("ext2fs_new_block", retval
, "");
909 printf("Free block found: %d\n", free_blk
);
913 void do_find_free_inode(int argc
, char *argv
[])
915 ino_t free_inode
, dir
;
920 if (argc
> 3 || (argc
>1 && *argv
[1] == '?')) {
921 com_err(argv
[0], 0, "Usage: find_free_inode [dir] [mode]");
924 if (check_fs_open(argv
[0]))
928 dir
= strtol(argv
[1], &tmp
, 0);
930 com_err(argv
[0], 0, "Bad dir - %s", argv
[1]);
937 mode
= strtol(argv
[2], &tmp
, 0);
939 com_err(argv
[0], 0, "Bad mode - %s", argv
[2]);
945 retval
= ext2fs_new_inode(fs
, dir
, mode
, 0, &free_inode
);
947 com_err("ext2fs_new_inode", retval
, "");
949 printf("Free inode found: %ld\n", free_inode
);
952 struct copy_file_struct
{
954 int done
, fd
, blocks
;
958 static int copy_file_proc(ext2_filsys fs
,
963 struct copy_file_struct
*cs
= (struct copy_file_struct
*) private;
965 static blk_t last_blk
= 0;
974 retval
= ext2fs_new_block(fs
, last_blk
, 0, &new_blk
);
981 block
= malloc(fs
->blocksize
);
987 nr
= read(cs
->fd
, block
, fs
->blocksize
);
990 memset(block
, 0, nr
);
1000 retval
= io_channel_write_blk(fs
->io
, new_blk
, 1, block
);
1008 cs
->blocks
+= fs
->blocksize
/ 512;
1009 printf("%ld(%d) ", cs
->size
, blockcnt
);
1011 if (nr
< fs
->blocksize
) {
1016 ext2fs_mark_block_bitmap(fs
->block_map
, new_blk
);
1017 ext2fs_mark_bb_dirty(fs
);
1018 group
= ext2fs_group_of_blk(fs
, new_blk
);
1019 fs
->group_desc
[group
].bg_free_blocks_count
--;
1020 fs
->super
->s_free_blocks_count
--;
1021 ext2fs_mark_super_dirty(fs
);
1023 return (BLOCK_CHANGED
| BLOCK_ABORT
);
1025 return BLOCK_CHANGED
;
1028 static errcode_t
copy_file(int fd
, ino_t newfile
)
1031 struct copy_file_struct cs
;
1032 struct ext2_inode inode
;
1040 retval
= ext2fs_block_iterate(fs
, newfile
, BLOCK_FLAG_APPEND
,
1041 0, copy_file_proc
, &cs
);
1046 return EXT2_ET_EXPAND_DIR_ERR
;
1049 * Update the size and block count fields in the inode.
1051 retval
= ext2fs_read_inode(fs
, newfile
, &inode
);
1055 inode
.i_blocks
+= cs
.blocks
;
1057 retval
= ext2fs_write_inode(fs
, newfile
, &inode
);
1064 void do_write(int argc
, char *argv
[])
1067 struct stat statbuf
;
1070 struct ext2_inode inode
;
1072 if (check_fs_open(argv
[0]))
1075 com_err(argv
[0], 0, "Usage: write <nativefile> <newfile>");
1078 if (!(fs
->flags
& EXT2_FLAG_RW
)) {
1079 com_err(argv
[0], 0, "read-only filesystem");
1082 fd
= open(argv
[1], O_RDONLY
);
1084 com_err(argv
[1], fd
, "");
1087 if (fstat(fd
, &statbuf
) < 0) {
1088 com_err(argv
[1], errno
, "");
1093 retval
= ext2fs_new_inode(fs
, cwd
, 010755, 0, &newfile
);
1095 com_err(argv
[0], retval
, "");
1099 printf("Allocated inode: %ld\n", newfile
);
1100 retval
= ext2fs_link(fs
, cwd
, argv
[2], newfile
, 0);
1102 com_err(argv
[2], retval
, "");
1106 if (ext2fs_test_inode_bitmap(fs
->inode_map
,newfile
))
1107 com_err(argv
[0], 0, "Warning: inode already set");
1108 ext2fs_mark_inode_bitmap(fs
->inode_map
,newfile
);
1109 ext2fs_mark_ib_dirty(fs
);
1110 memset(&inode
, 0, sizeof(inode
));
1111 inode
.i_mode
= statbuf
.st_mode
;
1112 inode
.i_atime
= inode
.i_ctime
= inode
.i_mtime
= time(NULL
);
1113 inode
.i_links_count
= 1;
1114 inode
.i_size
= statbuf
.st_size
;
1115 ext2fs_write_inode(fs
, newfile
, &inode
);
1116 retval
= ext2fs_write_inode(fs
, newfile
, &inode
);
1118 com_err(argv
[0], retval
, "while trying to write inode %d", inode
);
1122 if (LINUX_S_ISREG(inode
.i_mode
)) {
1123 retval
= copy_file(fd
, newfile
);
1125 com_err("copy_file", retval
, "");
1130 void do_mknod(int argc
, char *argv
[])
1132 unsigned long mode
, major
, minor
, nr
;
1135 struct ext2_inode inode
;
1137 if (check_fs_open(argv
[0]))
1139 if (argc
< 3 || argv
[2][1]) {
1140 com_err(argv
[0], 0, "Usage: mknod <name> [p| [c|b] <major> <minor>]");
1143 mode
= minor
= major
= 0;
1144 switch (argv
[2][0]) {
1146 mode
= LINUX_S_IFIFO
;
1150 mode
= LINUX_S_IFCHR
;
1154 mode
= LINUX_S_IFBLK
;
1161 major
= strtoul(argv
[3], argv
+3, 0);
1162 minor
= strtoul(argv
[4], argv
+4, 0);
1163 if (major
> 255 || minor
> 255 || argv
[3][0] || argv
[4][0])
1167 com_err(argv
[0], 0, "Usage: mknod <name> [p| [c|b] <major> <minor>]");
1170 if (!(fs
->flags
& EXT2_FLAG_RW
)) {
1171 com_err(argv
[0], 0, "read-only filesystem");
1174 retval
= ext2fs_new_inode(fs
, cwd
, 010755, 0, &newfile
);
1176 com_err(argv
[0], retval
, "");
1179 printf("Allocated inode: %ld\n", newfile
);
1180 retval
= ext2fs_link(fs
, cwd
, argv
[1], newfile
, 0);
1182 if (retval
== EXT2_ET_DIR_NO_SPACE
) {
1183 retval
= ext2fs_expand_dir(fs
, cwd
);
1185 retval
= ext2fs_link(fs
, cwd
, argv
[1], newfile
, 0);
1188 com_err(argv
[1], retval
, "");
1192 if (ext2fs_test_inode_bitmap(fs
->inode_map
,newfile
))
1193 com_err(argv
[0], 0, "Warning: inode already set");
1194 ext2fs_mark_inode_bitmap(fs
->inode_map
,newfile
);
1195 ext2fs_mark_ib_dirty(fs
);
1196 memset(&inode
, 0, sizeof(inode
));
1197 inode
.i_mode
= mode
;
1198 inode
.i_atime
= inode
.i_ctime
= inode
.i_mtime
= time(NULL
);
1199 inode
.i_block
[0] = major
*256+minor
;
1200 inode
.i_links_count
= 1;
1201 ext2fs_write_inode(fs
, newfile
, &inode
);
1202 retval
= ext2fs_write_inode(fs
, newfile
, &inode
);
1204 com_err(argv
[0], retval
, "while trying to write inode %d", inode
);
1209 void do_mkdir(int argc
, char *argv
[])
1216 if (check_fs_open(argv
[0]))
1220 com_err(argv
[0], 0, "Usage: mkdir <file>");
1224 cp
= strrchr(argv
[1], '/');
1227 parent
= string_to_inode(argv
[1]);
1229 com_err(argv
[1], ENOENT
, "");
1239 retval
= ext2fs_mkdir(fs
, parent
, 0, name
);
1241 com_err("ext2fs_mkdir", retval
, "");
1247 void do_rmdir(int argc
, char *argv
[])
1249 printf("Unimplemented\n");
1253 static int release_blocks_proc(ext2_filsys fs
, blk_t
*blocknr
,
1254 int blockcnt
, void *private)
1256 printf("%d ", *blocknr
);
1257 ext2fs_unmark_block_bitmap(fs
->block_map
,*blocknr
);
1261 void kill_file_by_inode(ino_t inode
)
1263 struct ext2_inode inode_buf
;
1265 ext2fs_read_inode(fs
, inode
, &inode_buf
);
1266 inode_buf
.i_dtime
= time(NULL
);
1267 ext2fs_write_inode(fs
, inode
, &inode_buf
);
1269 printf("Kill file by inode %ld\n", inode
);
1270 ext2fs_block_iterate(fs
,inode
,0,NULL
,release_blocks_proc
,NULL
);
1271 ext2fs_unmark_inode_bitmap(fs
->inode_map
,inode
);
1273 ext2fs_mark_bb_dirty(fs
);
1274 ext2fs_mark_ib_dirty(fs
);
1278 void do_kill_file(int argc
, char *argv
[])
1283 com_err(argv
[0], 0, "Usage: kill_file <file>");
1286 if (check_fs_open(argv
[0]))
1289 inode_num
= string_to_inode(argv
[1]);
1291 com_err(argv
[0], 0, "Cannot find file");
1294 kill_file_by_inode(inode_num
);
1297 void do_rm(int argc
, char *argv
[])
1301 struct ext2_inode inode
;
1304 com_err(argv
[0], 0, "Usage: rm <filename>");
1307 if (check_fs_open(argv
[0]))
1310 retval
= ext2fs_namei(fs
, root
, cwd
, argv
[1], &inode_num
);
1312 com_err(argv
[0], 0, "Cannot find file");
1316 retval
= ext2fs_read_inode(fs
,inode_num
,&inode
);
1318 com_err(argv
[0], retval
, "while reading file's inode");
1322 if (LINUX_S_ISDIR(inode
.i_mode
)) {
1323 com_err(argv
[0], 0, "file is a directory");
1327 --inode
.i_links_count
;
1328 retval
= ext2fs_write_inode(fs
,inode_num
,&inode
);
1330 com_err(argv
[0], retval
, "while writing inode");
1334 unlink_file_by_name(argv
[1]);
1335 if (inode
.i_links_count
== 0)
1336 kill_file_by_inode(inode_num
);
1339 void do_show_debugfs_params(int argc
, char *argv
[])
1343 fprintf(out
, "Open mode: read-%s\n",
1344 fs
->flags
& EXT2_FLAG_RW
? "write" : "only");
1345 fprintf(out
, "Filesystem in use: %s\n",
1346 fs
? fs
->device_name
: "--none--");
1349 void do_expand_dir(int argc
, char *argv
[])
1355 com_err(argv
[0], 0, "Usage: expand_dir <file>");
1358 if (check_fs_open(argv
[0]))
1360 inode
= string_to_inode(argv
[1]);
1364 retval
= ext2fs_expand_dir(fs
, inode
);
1366 com_err("ext2fs_expand_dir", retval
, "");
1370 void main(int argc
, char **argv
)
1374 const char *usage
= "Usage: debugfs [[-w] device]";
1378 initialize_ext2_error_table();
1380 while ((c
= getopt (argc
, argv
, "w")) != EOF
) {
1383 open_flags
= EXT2_FLAG_RW
;
1386 com_err(argv
[0], 0, usage
);
1391 open_filesystem(argv
[optind
], open_flags
);
1393 sci_idx
= ss_create_invocation("debugfs", "0.0", (char *) NULL
,
1394 &debug_cmds
, &retval
);
1396 ss_perror(sci_idx
, retval
, "creating invocation");
1400 (void) ss_add_request_table (sci_idx
, &ss_std_requests
, 1, &retval
);
1402 ss_perror(sci_idx
, retval
, "adding standard requests");