summaryrefslogtreecommitdiff
path: root/debugfs
diff options
context:
space:
mode:
Diffstat (limited to 'debugfs')
-rw-r--r--debugfs/Makefile.in196
-rw-r--r--debugfs/debug_cmds.ct20
-rw-r--r--debugfs/debugfs.8.in462
-rw-r--r--debugfs/debugfs.c200
-rw-r--r--debugfs/debugfs.h46
-rw-r--r--debugfs/dump.c24
-rw-r--r--debugfs/extent_cmds.ct77
-rw-r--r--debugfs/extent_inode.c537
-rw-r--r--debugfs/filefrag.c2
-rw-r--r--debugfs/htree.c4
-rw-r--r--debugfs/icheck.c2
-rw-r--r--debugfs/logdump.c62
-rw-r--r--debugfs/lsdel.c2
-rw-r--r--debugfs/quota.c171
-rw-r--r--debugfs/ro_debug_cmds.ct10
-rw-r--r--debugfs/set_fields.c30
-rw-r--r--debugfs/util.c46
-rw-r--r--debugfs/zap.c260
18 files changed, 1789 insertions, 362 deletions
diff --git a/debugfs/Makefile.in b/debugfs/Makefile.in
index 7e71c3f4..3dd06f03 100644
--- a/debugfs/Makefile.in
+++ b/debugfs/Makefile.in
@@ -18,25 +18,35 @@ MK_CMDS= _SS_DIR_OVERRIDE=../lib/ss ../lib/ss/mk_cmds
DEBUG_OBJS= debug_cmds.o debugfs.o util.o ncheck.o icheck.o ls.o \
lsdel.o dump.o set_fields.o logdump.o htree.o unused.o e2freefrag.o \
- filefrag.o
+ filefrag.o extent_cmds.o extent_inode.o zap.o quota.o
RO_DEBUG_OBJS= ro_debug_cmds.o ro_debugfs.o util.o ncheck.o icheck.o ls.o \
- lsdel.o logdump.o htree.o e2freefrag.o filefrag.o
+ lsdel.o logdump.o htree.o e2freefrag.o filefrag.o extent_cmds.o \
+ extent_inode.o quota.o
SRCS= debug_cmds.c $(srcdir)/debugfs.c $(srcdir)/util.c $(srcdir)/ls.c \
$(srcdir)/ncheck.c $(srcdir)/icheck.c $(srcdir)/lsdel.c \
$(srcdir)/dump.c $(srcdir)/set_fields.c ${srcdir}/logdump.c \
$(srcdir)/htree.c $(srcdir)/unused.c ${srcdir}/../misc/e2freefrag.c \
- $(srcdir)/filefrag.c
+ $(srcdir)/filefrag.c $(srcdir)/extent_inode.c $(srcdir)/zap.c \
+ $(srcdir)/quota.c
-LIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \
- $(LIBUUID)
-DEPLIBS= $(LIBEXT2FS) $(LIBE2P) $(DEPLIBSS) $(DEPLIBCOM_ERR) \
+LIBS= $(LIBQUOTA) $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \
+ $(LIBUUID) $(SYSLIBS)
+DEPLIBS= $(DEPLIBQUOTA) $(LIBEXT2FS) $(LIBE2P) $(DEPLIBSS) $(DEPLIBCOM_ERR) \
$(DEPLIBBLKID) $(DEPLIBUUID)
+STATIC_LIBS= $(STATIC_LIBQUOTA) $(STATIC_LIBEXT2FS) $(STATIC_LIBSS) \
+ $(STATIC_LIBCOM_ERR) $(STATIC_LIBBLKID) $(STATIC_LIBUUID) \
+ $(STATIC_LIBE2P) $(SYSLIBS)
+STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBSS) \
+ $(DEPSTATIC_LIBCOM_ERR) $(DEPSTATIC_LIBUUID) \
+ $(DEPSTATIC_LIBE2P)
+
.c.o:
$(E) " CC $<"
$(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@
+ $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
all:: $(PROGS) $(MANPAGES)
@@ -44,6 +54,11 @@ debugfs: $(DEBUG_OBJS) $(DEPLIBS)
$(E) " LD $@"
$(Q) $(CC) $(ALL_LDFLAGS) -o debugfs $(DEBUG_OBJS) $(LIBS)
+debugfs.static: $(DEBUG_OBJS) $(STATIC_DEPLIBS)
+ $(E) " LD $@"
+ $(Q) $(CC) $(LDFLAGS_STATIC) -o debugfs.static $(DEBUG_OBJS) \
+ $(STATIC_LIBS) $(READLINE_LIB)
+
rdebugfs: $(RO_DEBUG_OBJS) $(DEPLIBS)
$(E) " LD $@"
$(Q) $(CC) $(ALL_LDFLAGS) -o rdebugfs $(RO_DEBUG_OBJS) $(LIBS)
@@ -52,6 +67,10 @@ debug_cmds.c debug_cmds.h: debug_cmds.ct
$(E) " MK_CMDS $@"
$(Q) $(MK_CMDS) $(srcdir)/debug_cmds.ct
+extent_cmds.c extent_cmds.h: extent_cmds.ct
+ $(E) " MK_CMDS $@"
+ $(Q) $(MK_CMDS) $(srcdir)/extent_cmds.ct
+
ro_debug_cmds.c ro_debug_cmds.h: ro_debug_cmds.ct
$(E) " MK_CMDS $@"
$(Q) $(MK_CMDS) $(srcdir)/ro_debug_cmds.ct
@@ -100,9 +119,9 @@ uninstall:
$(RM) -f $(DESTDIR)$(man8dir)/$$i; \
done
-clean:
+clean::
$(RM) -f $(PROGS) debugfs.8 \#* *.s *.o *.a *~ debug_cmds.c \
- ro_debug_cmds.c core rdebugfs
+ extent_cmds.c ro_debug_cmds.c core rdebugfs debugfs.static
mostlyclean: clean
distclean: clean
@@ -116,76 +135,153 @@ distclean: clean
#
debug_cmds.o: debug_cmds.c $(top_srcdir)/lib/ss/ss.h \
$(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
-debugfs.o: $(srcdir)/debugfs.c $(top_srcdir)/lib/et/com_err.h \
- $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
+debugfs.o: $(srcdir)/debugfs.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/version.h $(srcdir)/jfs_user.h \
+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
+ $(top_srcdir)/lib/ext2fs/kernel-list.h
+util.o: $(srcdir)/util.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
$(srcdir)/debugfs.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
$(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
$(top_builddir)/lib/ext2fs/ext2_err.h \
$(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
- $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/version.h $(srcdir)/jfs_user.h \
- $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
- $(top_srcdir)/lib/ext2fs/kernel-list.h
-util.o: $(srcdir)/util.c $(srcdir)/debugfs.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h
+ls.o: $(srcdir)/ls.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h
-ls.o: $(srcdir)/ls.c $(srcdir)/debugfs.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h
-ncheck.o: $(srcdir)/ncheck.c $(srcdir)/debugfs.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h
+ncheck.o: $(srcdir)/ncheck.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h
-icheck.o: $(srcdir)/icheck.c $(srcdir)/debugfs.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h
+icheck.o: $(srcdir)/icheck.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h
-lsdel.o: $(srcdir)/lsdel.c $(srcdir)/debugfs.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h
+lsdel.o: $(srcdir)/lsdel.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h
-dump.o: $(srcdir)/dump.c $(srcdir)/debugfs.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h
+dump.o: $(srcdir)/dump.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h
-set_fields.o: $(srcdir)/set_fields.c $(srcdir)/debugfs.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h
+set_fields.o: $(srcdir)/set_fields.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h \
$(top_srcdir)/lib/e2p/e2p.h
-logdump.o: $(srcdir)/logdump.c $(srcdir)/debugfs.h \
+logdump.o: $(srcdir)/logdump.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h \
$(srcdir)/jfs_user.h $(top_srcdir)/lib/ext2fs/kernel-jbd.h \
$(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h
-htree.o: $(srcdir)/htree.c $(srcdir)/debugfs.h \
+htree.o: $(srcdir)/htree.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h \
$(top_srcdir)/lib/e2p/e2p.h
-unused.o: $(srcdir)/unused.c $(srcdir)/debugfs.h \
+unused.o: $(srcdir)/unused.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
$(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h
+e2freefrag.o: $(srcdir)/../misc/e2freefrag.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
+ $(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(srcdir)/../misc/e2freefrag.h
+filefrag.o: $(srcdir)/filefrag.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h
+extent_inode.o: $(srcdir)/extent_inode.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h
+zap.o: $(srcdir)/zap.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h
+quota.o: $(srcdir)/quota.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
+ $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
+ $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h
diff --git a/debugfs/debug_cmds.ct b/debugfs/debug_cmds.ct
index af969b1c..6a18df67 100644
--- a/debugfs/debug_cmds.ct
+++ b/debugfs/debug_cmds.ct
@@ -160,13 +160,16 @@ request do_bmap, "Calculate the logical->physical block mapping for an inode",
request do_punch, "Punch (or truncate) blocks from an inode by deallocating them",
punch, truncate;
+request do_symlink, "Create a symbolic link",
+ symlink;
+
request do_imap, "Calculate the location of an inode",
imap;
request do_dump_unused, "Dump unused blocks",
dump_unused;
-request do_set_current_time, "Set current time to use when setting filesystme fields",
+request do_set_current_time, "Set current time to use when setting filesystem fields",
set_current_time;
request do_supported_features, "Print features supported by this version of e2fsprogs",
@@ -178,5 +181,20 @@ request do_dump_mmp, "Dump MMP information",
request do_set_mmp_value, "Set MMP value",
set_mmp_value, smmp;
+request do_extent_open, "Open inode for extent manipulation",
+ extent_open, eo;
+
+request do_zap_block, "Zap block: fill with 0, pattern, flip bits etc.",
+ zap_block, zap;
+
+request do_block_dump, "Dump contents of a block",
+ block_dump, bd;
+
+request do_list_quota, "List quota",
+ list_quota, lq;
+
+request do_get_quota, "Get quota",
+ get_quota, gq;
+
end;
diff --git a/debugfs/debugfs.8.in b/debugfs/debugfs.8.in
index ea3375e3..73254d31 100644
--- a/debugfs/debugfs.8.in
+++ b/debugfs/debugfs.8.in
@@ -1,7 +1,7 @@
.\" -*- nroff -*-
.\" Copyright 1993, 1994, 1995 by Theodore Ts'o. All Rights Reserved.
.\" This file may be copied under the terms of the GNU Public License.
-.\"
+.\"
.TH DEBUGFS 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
.SH NAME
debugfs \- ext2/ext3/ext4 file system debugger
@@ -19,7 +19,7 @@ blocksize
superblock
]
[
-.B \-f
+.B \-f
cmd_file
]
[
@@ -34,8 +34,8 @@ data_source_device
device
]
.SH DESCRIPTION
-The
-.B debugfs
+The
+.B debugfs
program is an interactive file system debugger. It can be used to
examine and change the state of an ext2, ext3, or ext4 file system.
.br
@@ -55,30 +55,30 @@ useful for filesystems with significant corruption, but because of this,
catastrophic mode forces the filesystem to be opened read-only.
.TP
.I \-i
-Specifies that
+Specifies that
.I device
represents an ext2 image file created by the
.B e2image
program. Since the ext2 image file only contains the superblock, block
-group descriptor, block and inode allocation bitmaps, and
+group descriptor, block and inode allocation bitmaps, and
the inode table, many
.B debugfs
-commands will not function properly.
+commands will not function properly.
.B Warning:
-no safety checks are in place, and
-.B debugfs
+no safety checks are in place, and
+.B debugfs
may fail in interesting ways if commands such as
-.IR ls ", " dump ", "
-etc. are tried without specifying the
+.IR ls ", " dump ", "
+etc. are tried without specifying the
.I data_source_device
-using the
+using the
.I \-d
option.
-.B debugfs
+.B debugfs
is a debugging tool. It has rough edges!
.TP
.I -d data_source_device
-Used with the
+Used with the
.I \-i
option, specifies that
.I data_source_device
@@ -99,11 +99,11 @@ option, you must also provide the blocksize of the filesystem via the
option.
.TP
.I -f cmd_file
-Causes
+Causes
.B debugfs
-to read in commands from
-.IR cmd_file ,
-and execute them. When
+to read in commands from
+.IR cmd_file ,
+and execute them. When
.B debugfs
is finished executing those commands, it will exit.
.TP
@@ -115,14 +115,14 @@ that some Linux devices, notably device mapper as of this writing, do
not support Direct I/O.
.TP
.I -R request
-Causes
+Causes
.B debugfs
-to execute the single command
+to execute the single command
.IR request ,
and then exit.
.TP
.I -V
-print the version number of
+print the version number of
.B debugfs
and exit.
.SH SPECIFYING FILES
@@ -130,128 +130,140 @@ Many
.B debugfs
commands take a
.I filespec
-as an argument to specify an inode (as opposed to a pathname)
-in the filesystem which is currently opened by
-.BR debugfs .
+as an argument to specify an inode (as opposed to a pathname)
+in the filesystem which is currently opened by
+.BR debugfs .
The
.I filespec
-argument may be specified in two forms. The first form is an inode
-number surrounded by angle brackets, e.g.,
+argument may be specified in two forms. The first form is an inode
+number surrounded by angle brackets, e.g.,
.IR <2> .
The second form is a pathname; if the pathname is prefixed by a forward slash
-('/'), then it is interpreted relative to the root of the filesystem
-which is currently opened by
+('/'), then it is interpreted relative to the root of the filesystem
+which is currently opened by
+.BR debugfs .
+If not, the pathname is
+interpreted relative to the current working directory as maintained by
.BR debugfs .
-If not, the pathname is
-interpreted relative to the current working directory as maintained by
-.BR debugfs .
-This may be modified by using the
+This may be modified by using the
.B debugfs
command
.IR cd .
-.\"
+.\"
.\"
.\"
.SH COMMANDS
-This is a list of the commands which
+This is a list of the commands which
.B debugfs
supports.
.TP
-.I blocks filespace
+.BI blocks " filespace"
Print the blocks used by the inode
.I filespec
to stdout.
.TP
-.I bmap filespec logical_block
+.BI bmap " filespec logical_block"
Print the physical block number corresponding to the logical block number
.I logical_block
in the inode
.IR filespec .
.TP
-.I cat filespec
-Dump the contents of the inode
+.BI block_dump " [-f filespec] block_num"
+Dump the filesystem block given by
+.I block_num
+in hex and ASCII format to the console. If the
+.I -f
+option is specified, the block number is relative to the start of the given
+.BR filespec .
+.TP
+.BI cat " filespec"
+Dump the contents of the inode
.I filespec
to stdout.
.TP
-.I cd filespec
-Change the current working directory to
+.BI cd " filespec"
+Change the current working directory to
.IR filespec .
.TP
-.I chroot filespec
-Change the root directory to be the directory
+.BI chroot " filespec"
+Change the root directory to be the directory
.IR filespec .
.TP
-.I close [-a]
-Close the currently open file system. If the
+.BI close " [-a]"
+Close the currently open file system. If the
.I -a
option is specified, write out any changes to the superblock and block
group descriptors to all of the backup superblocks, not just to the
master superblock.
.TP
-.I clri file
-Clear the contents of the inode
-.IR file .
+.BI clri " filespec"
+Clear the contents of the inode
+.IR filespec .
.TP
-.I dirsearch filespec filename
+.BI dirsearch " filespec filename"
Search the directory
.I filespec
for
.IR filename .
.TP
-.I dump [-p] filespec out_file
-Dump the contents of the inode
+.B dirty
+Mark the filesystem as dirty, so that the superblocks will be written on exit.
+.TP
+.BI dump " [-p] filespec out_file"
+Dump the contents of the inode
.I filespec
-to the output file
-.IR out_file .
-If the
-.I -p
-option is given set the owner, group and permissions information on
-.I out_file
-to match
+to the output file
+.IR out_file .
+If the
+.I -p
+option is given set the owner, group and permissions information on
+.I out_file
+to match
.IR filespec .
.TP
-.I dump_mmp
+.B dump_mmp
Display the multiple-mount protection (mmp) field values.
.TP
-.I dx_hash [-h hash_alg] [-s hash_seed] filename
+.BI dx_hash " [-h hash_alg] [-s hash_seed] filename"
Calculate the directory hash of
.IR filename .
The hash algorithm specified with
.I -h
-may be "legacy" "half_md4" or "tea".
+may be
+.BR legacy , " half_md4" ", or " tea .
The hash seed specified with
.I -s
must be in UUID format.
.TP
-.I dump_extents [-n] [-l] filespec
+.BI dump_extents " [-n] [-l] filespec"
Dump the the extent tree of the inode
.IR filespec .
-The
+The
.I -n
flag will cause
-.I dump_extents
+.B dump_extents
to only display the interior nodes in the extent tree. The
-.I -l
-flag cause
-.I dump_extents
+.I -l
+flag will cause
+.B dump_extents
to only display the leaf nodes in the extent tree.
.IP
(Please note that the length and range of blocks for the last extent in
an interior node is an estimate by the extents library functions, and is
not stored in filesystem data structures. Hence, the values displayed
-may not necessarily by accurate and does not indicate a problem or
+may not necessarily by accurate and does not indicate a problem or
corruption in the file system.)
.TP
-.I expand_dir filespec
+.BI expand_dir " filespec"
Expand the directory
.IR filespec .
.TP
-.I feature [fs_feature] [-fs_feature] ...
+.BI feature " [fs_feature] [-fs_feature] ..."
Set or clear various filesystem features in the superblock. After setting
or clearing any filesystem features that were requested, print the current
state of the filesystem feature set.
.TP
-.I filefrag [-dvr] filespec
+.BI filefrag " [-dvr] filespec"
Print the number of contiguous extents in
.IR filespec .
If
@@ -272,36 +284,39 @@ option will cause
.I filefrag
to do a recursive listing of the directory.
.TP
-.I find_free_block [count [goal]]
-Find the first
+.BI find_free_block " [count [goal]]"
+Find the first
.I count
free blocks, starting from
.I goal
-and allocate it.
+and allocate it. Also available as
+.BR ffb .
.TP
-.I find_free_inode [dir [mode]]
-Find a free inode and allocate it. If present,
+.BI find_free_inode " [dir [mode]]"
+Find a free inode and allocate it. If present,
.I dir
-specifies the inode number of the directory
-which the inode is to be located. The second
+specifies the inode number of the directory
+which the inode is to be located. The second
optional argument
.I mode
specifies the permissions of the new inode. (If the directory bit is set
-on the mode, the allocation routine will function differently.)
+on the mode, the allocation routine will function differently.) Also
+available as
+.BR ffi .
.TP
-.I freeb block [count]
+.BI freeb " block [count]"
Mark the block number
.I block
as not allocated.
-If the optional argument
-.I count
-is present, then
+If the optional argument
+.I count
+is present, then
.I count
blocks starting at block number
.I block
will be marked as not allocated.
.TP
-.I freefrag [-c chunk_kb ]
+.BI freefrag " [-c chunk_kb]"
Report free space fragmentation on the currently open file system.
If the
.I \-c
@@ -311,145 +326,159 @@ chunks of size
can be found in the file system. The chunk size must be a power of two
and be larger than the file system block size.
.TP
-.I freei filespec [num]
-Free the inode specified by
+.BI freei " filespec [num]"
+Free the inode specified by
.IR filespec .
If
.I num
is specified, also clear num-1 inodes after the specified inode.
.TP
-.I help
-Print a list of commands understood by
+.B help
+Print a list of commands understood by
.BR debugfs .
.TP
-.I htree_dump filespec
+.BI htree_dump " filespec"
Dump the hash-indexed directory
.IR filespec ,
showing its tree structure.
.TP
-.I icheck block ...
+.BI icheck " block ..."
Print a listing of the inodes which use the one or more blocks specified
on the command line.
.TP
-.I imap filespec
-Print the location of the inode data structure (in the inode table)
+.BI imap " filespec"
+Print the location of the inode data structure (in the inode table)
of the inode
.IR filespec .
.TP
-.I init_filesys device blocksize
+.BI init_filesys " device blocksize"
Create an ext2 file system on
.I device
with device size
.IR blocksize .
-Note that this does not fully initialize all of the data structures;
-to do this, use the
+Note that this does not fully initialize all of the data structures;
+to do this, use the
.BR mke2fs (8)
program. This is just a call to the low-level library, which sets up
the superblock and block descriptors.
.TP
-.I kill_file filespec
-Deallocate the inode
+.BI kill_file " filespec"
+Deallocate the inode
.I filespec
and its blocks. Note that this does not remove any directory
-entries (if any) to this inode. See the
+entries (if any) to this inode. See the
.BR rm (1)
command if you wish to unlink a file.
.TP
-.I lcd directory
+.BI lcd " directory"
Change the current working directory of the
.B debugfs
process to
.I directory
on the native filesystem.
.TP
-.I ln filespec dest_file
-Create a link named
+.BI ln " filespec dest_file"
+Create a link named
.I dest_file
-which is a link to
+which is a hard link to
.IR filespec .
Note this does not adjust the inode reference counts.
.TP
-.I logdump [-acs] [-b<block>] [-i<filespec>] [-f<journal_file>] [output_file]
-Dump the contents of the ext3 journal. By default, the journal inode as
-specified in the superblock. However, this can be overridden with the
+.BI logdump " [-acs] [-b block] [-i filespec] [-f journal_file] [output_file]"
+Dump the contents of the ext3 journal. By default, dump the journal inode as
+specified in the superblock. However, this can be overridden with the
.I \-i
-option, which uses an inode specifier to specify the journal to be
-used. A file containing journal data can be specified using the
+option, which dumps the journal from the internal inode given by
+.IR filespec .
+A regular file containing journal data can be specified using the
.I \-f
-option. Finally, the
+option. Finally, the
.I \-s
option utilizes the backup information in the superblock to locate the
journal.
.IP
-The
+The
.I \-a
-option causes the
-.I logdump
+option causes the
+.B logdump
program to print the contents of all of the descriptor blocks.
-The
+The
.I \-b
-option causes
-.I logdump
-to print all journal records that are refer to the specified block.
-The
+option causes
+.B logdump
+to print all journal records that are refer to the specified block.
+The
.I \-c
option will print out the contents of all of the data blocks selected by
-the
+the
.I \-a
-and
+and
.I \-b
options.
.TP
-.I ls [-l] [-d] [-p] filespec
+.BI ls " [-d] [-l] [-p] filespec"
Print a listing of the files in the directory
.IR filespec .
-The
-.I \-l
-flag will list files using a more verbose format.
The
.I \-d
flag will list deleted entries in the directory.
-The
+The
+.I \-l
+flag will list files using a more verbose format.
+The
.I \-p
flag will list the files in a format which is more easily parsable by
scripts, as well as making it more clear when there are spaces or other
non-printing characters at the end of filenames.
.TP
-.I modify_inode filespec
+.BI list_deleted_inodes " [limit]"
+List deleted inodes, optionally limited to those deleted within
+.I limit
+seconds ago. Also available as
+.BR lsdel .
+.IP
+This command was useful for recovering from accidental file deletions
+for ext2 file systems. Unfortunately, it is not useful for this purpose
+if the files were deleted using ext3 or ext4, since the inode's
+data blocks are no longer available after the inode is released.
+.TP
+.BI modify_inode " filespec"
Modify the contents of the inode structure in the inode
.IR filespec .
+Also available as
+.BR mi .
.TP
-.I mkdir filespec
+.BI mkdir " filespec"
Make a directory.
.TP
-.I mknod filespec [p|[[c|b] major minor]]
+.BI mknod " filespec [p|[[c|b] major minor]]"
Create a special device file (a named pipe, character or block device).
-If a character or block device is to be made, the
+If a character or block device is to be made, the
.I major
and
.I minor
device numbers must be specified.
.TP
-.I ncheck [-c] inode_num ...
+.BI ncheck " [-c] inode_num ..."
Take the requested list of inode numbers, and print a listing of pathnames
to those inodes. The
.I -c
flag will enable checking the file type information in the directory
entry to make sure it matches the inode's type.
.TP
-.I open [-w] [-e] [-f] [-i] [-c] [-D] [-b blocksize] [-s superblock] device
-Open a filesystem for editing. The
-.I -f
-flag forces the filesystem to be opened even if there are some unknown
-or incompatible filesystem features which would normally
+.BI open " [-weficD] [-b blocksize] [-s superblock] device"
+Open a filesystem for editing. The
+.I -f
+flag forces the filesystem to be opened even if there are some unknown
+or incompatible filesystem features which would normally
prevent the filesystem from being opened. The
.I -e
flag causes the filesystem to be opened in exclusive mode. The
.IR -b ", " -c ", " -i ", " -s ", " -w ", and " -D
-options behave the same as the command-line options to
+options behave the same as the command-line options to
.BR debugfs .
.TP
-.I punch filespec start_blk [end_blk]
+.BI punch " filespec start_blk [end_blk]"
Delete the blocks in the inode ranging from
.I start_blk
to
@@ -461,14 +490,17 @@ is, all of the blocks starting at
.I start_blk
through to the end of the file will be deallocated.
.TP
-.I pwd
+.BI symlink " filespec target"
+Make a symbolic link.
+.TP
+.B pwd
Print the current working directory.
.TP
-.I quit
+.B quit
Quit
.B debugfs
.TP
-.I rdump directory destination
+.BI rdump " directory destination"
Recursively dump
.I directory
and all its contents (including regular files, symbolic links, and other
@@ -476,161 +508,202 @@ directories) into the named
.I destination
which should be an existing directory on the native filesystem.
.TP
-.I rm pathname
-Unlink
+.BI rm " pathname"
+Unlink
.IR pathname .
-If this causes the inode pointed to by
+If this causes the inode pointed to by
.I pathname
to have no other references, deallocate the file. This command functions
as the unlink() system call.
-.I
+.I
.TP
-.I rmdir filespec
+.BI rmdir " filespec"
Remove the directory
.IR filespec .
.TP
-.I setb block [count]
+.BI setb " block [count]"
Mark the block number
.I block
as allocated.
-If the optional argument
-.I count
-is present, then
+If the optional argument
+.I count
+is present, then
.I count
blocks starting at block number
.I block
will be marked as allocated.
.TP
-.I set_block_group bgnum field value
+.BI set_block_group " bgnum field value"
Modify the block group descriptor specified by
.I bgnum
so that the block group descriptor field
.I field
has value
-.I value.
+.IR value .
+Also available as
+.BR set_bg .
.TP
-.I seti filespec [num]
-Mark inode
+.BI seti " filespec [num]"
+Mark inode
.I filespec
as in use in the inode bitmap. If
.I num
is specified, also set num-1 inodes after the specified inode.
.TP
-.I set_inode_field filespec field value
-Modify the inode specified by
+.BI set_inode_field " filespec field value"
+Modify the inode specified by
.I filespec
so that the inode field
.I field
-has value
+has value
.I value.
-The list of valid inode fields which can be set via this command
+The list of valid inode fields which can be set via this command
can be displayed by using the command:
.B set_inode_field -l
+Also available as
+.BR sif .
.TP
-.I set_mmp_value field value
-Modify the multiple-mount protection (mmp) data so that the
-mmp field
+.BI set_mmp_value " field value"
+Modify the multiple-mount protection (MMP) data so that the MMP field
.I field
has value
.I value.
-The list of valid mmp fields which can be set via this command
+The list of valid MMP fields which can be set via this command
can be displayed by using the command:
.B set_mmp_value -l
+Also available as
+.BR smmp .
.TP
-.I set_super_value field value
+.BI set_super_value " field value"
Set the superblock field
.I field
-to
+to
.I value.
-The list of valid superblock fields which can be set via this command
+The list of valid superblock fields which can be set via this command
can be displayed by using the command:
.B set_super_value -l
+Also available as
+.BR ssv .
.TP
-.I show_super_stats [-h]
+.BI show_super_stats " [-h]"
List the contents of the super block and the block group descriptors. If the
.I -h
-flag is given, only print out the superblock contents.
+flag is given, only print out the superblock contents. Also available as
+.BR stats .
.TP
-.I stat filespec
+.BI stat " filespec"
Display the contents of the inode structure of the inode
.IR filespec .
.TP
-.I testb block [count]
+.BI testb " block [count]"
Test if the block number
.I block
is marked as allocated in the block bitmap.
-If the optional argument
-.I count
-is present, then
+If the optional argument
+.I count
+is present, then
.I count
blocks starting at block number
.I block
will be tested.
.TP
-.I testi filespec
-Test if the inode
+.BI testi " filespec"
+Test if the inode
.I filespec
is marked as allocated in the inode bitmap.
.TP
-.I undel <inode num> [pathname]
+.BI undel " <inode_number> [pathname]"
Undelete the specified inode number (which must be surrounded by angle
brackets) so that it and its blocks are marked in use, and optionally
-link the recovered inode to the specified pathname. The
+link the recovered inode to the specified pathname. The
.B e2fsck
-command should always be run after using the
+command should always be run after using the
.B undel
command to recover deleted files.
.IP
Note that if you are recovering a large number of deleted files, linking
the inode to a directory may require the directory to be expanded, which
could allocate a block that had been used by one of the
-yet-to-be-undeleted files. So it is safer to undelete all of the
+yet-to-be-undeleted files. So it is safer to undelete all of the
inodes without specifying a destination pathname, and then in a separate
pass, use the debugfs
.B link
-command to link the inode to the destination pathname, or use
+command to link the inode to the destination pathname, or use
.B e2fsck
to check the filesystem and link all of the recovered inodes to the
lost+found directory.
.TP
-.I unlink pathname
-Remove the link specified by
-.I pathname
+.BI unlink " pathname"
+Remove the link specified by
+.I pathname
to an inode. Note this does not adjust the inode reference counts.
.TP
-.I write source_file out_file
-Create a file in the filesystem named
-.IR out_file ,
-and copy the contents of
+.BI write " source_file out_file"
+Copy the contents of
.I source_file
-into the destination file.
+into a newly-created file in the filesystem named
+.IR out_file .
+.TP
+.BI zap_block " [-f filespec] [-o offset] [-l length] [-p pattern] block_num"
+.TP
+Overwrite the block specified by
+.I block_num
+with zero (NUL) bytes, or if
+.I -p
+is given use the byte specified by
+.IR pattern .
+If
+.I -f
+is given then
+.I block_num
+is relative to the start of the file given by
+.IR filespec .
+The
+.I -o
+and
+.I -l
+options limit the range of bytes to zap to the specified
+.I offset
+and
+.I length
+relative to the start of the block.
+.TP
+.BI zap_block " [-f filespec] [-b bit] block_num"
+Bit-flip portions of the physical
+.IR block_num .
+If
+.I -f
+is given, then
+.I block_num
+is a logical block relative to the start of
+.IR filespec .
.SH ENVIRONMENT VARIABLES
.TP
.B DEBUGFS_PAGER, PAGER
The
.B debugfs
program always pipes the output of the some commands through a
-pager program. These commands include:
-.IR show_super_stats ,
-.IR list_directory ,
-.IR show_inode_info ,
-.IR list_deleted_inodes ,
+pager program. These commands include:
+.IR show_super_stats " (" stats ),
+.IR list_directory " (" ls ),
+.IR show_inode_info " (" stat ),
+.IR list_deleted_inodes " (" lsdel ),
and
.IR htree_dump .
The specific pager can explicitly specified by the
.B DEBUGFS_PAGER
environment variable, and if it is not set, by the
.B PAGER
-environment variable.
+environment variable.
.IP
-Note that since a pager is always used, the
+Note that since a pager is always used, the
.BR less (1)
pager is not particularly appropriate, since it clears the screen before
displaying the output of the command and clears the output the screen
-when the pager is exited. Many users prefer to use the
+when the pager is exited. Many users prefer to use the
.BR less (1)
-pager for most purposes, which is why the
-.B DEBUGFS_PAGER
+pager for most purposes, which is why the
+.B DEBUGFS_PAGER
environment variable is available to override the more general
.B PAGER
environment variable.
@@ -641,4 +714,5 @@ was written by Theodore Ts'o <tytso@mit.edu>.
.BR dumpe2fs (8),
.BR tune2fs (8),
.BR e2fsck (8),
-.BR mke2fs (8)
+.BR mke2fs (8),
+.BR ext4 (5)
diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index e82dddb4..326f41e8 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -28,8 +28,6 @@ extern char *optarg;
#include <sys/types.h>
#include <sys/stat.h>
-#include "et/com_err.h"
-#include "ss/ss.h"
#include "debugfs.h"
#include "uuid/uuid.h"
#include "e2p/e2p.h"
@@ -39,11 +37,26 @@ extern char *optarg;
#include "../version.h"
#include "jfs_user.h"
-extern ss_request_table debug_cmds;
+#ifndef BUFSIZ
+#define BUFSIZ 8192
+#endif
+
+/* 64KiB is the minimium blksize to best minimize system call overhead. */
+#ifndef IO_BUFSIZE
+#define IO_BUFSIZE 64*1024
+#endif
+
+/* Block size for `st_blocks' */
+#ifndef S_BLKSIZE
+#define S_BLKSIZE 512
+#endif
+
ss_request_table *extra_cmds;
const char *debug_prog_name;
+int sci_idx;
ext2_filsys current_fs = NULL;
+quota_ctx_t current_qctx;
ext2_ino_t root, cwd;
static void open_filesystem(char *device, int open_flags, blk64_t superblock,
@@ -169,8 +182,8 @@ void do_open_filesys(int argc, char **argv)
return;
break;
case 's':
- superblock = parse_ulong(optarg, argv[0],
- "superblock number", &err);
+ err = strtoblk(argv[0], optarg,
+ "superblock block number", &superblock);
if (err)
return;
break;
@@ -189,7 +202,8 @@ void do_open_filesys(int argc, char **argv)
return;
print_usage:
- fprintf(stderr, "%s: Usage: open [-s superblock] [-b blocksize] [-c] "
+ fprintf(stderr, "%s: Usage: open [-s superblock] [-b blocksize] "
+ "[-d image_filename] [-c] [-i] [-f] [-e] [-D] "
#ifndef READ_ONLY
"[-w] "
#endif
@@ -225,6 +239,8 @@ static void close_filesystem(NOARGS)
if (retval)
com_err("ext2fs_write_block_bitmap", retval, 0);
}
+ if (current_qctx)
+ quota_release_context(&current_qctx);
retval = ext2fs_close(current_fs);
if (retval)
com_err("ext2fs_close", retval, 0);
@@ -265,16 +281,17 @@ void do_init_filesys(int argc, char **argv)
struct ext2_super_block param;
errcode_t retval;
int err;
+ blk64_t blocks;
if (common_args_process(argc, argv, 3, 3, "initialize",
- "<device> <blocksize>", CHECK_FS_NOTOPEN))
+ "<device> <blocks>", CHECK_FS_NOTOPEN))
return;
memset(&param, 0, sizeof(struct ext2_super_block));
- ext2fs_blocks_count_set(&param, parse_ulong(argv[2], argv[0],
- "blocks count", &err));
+ err = strtoblk(argv[0], argv[2], "blocks count", &blocks);
if (err)
return;
+ ext2fs_blocks_count_set(&param, blocks);
retval = ext2fs_initialize(argv[1], 0, &param,
unix_io_manager, &current_fs);
if (retval) {
@@ -1000,7 +1017,7 @@ void do_freei(int argc, char *argv[])
if (common_args_process(argc, argv, 2, 3, argv[0], "<file> [num]",
CHECK_FS_RW | CHECK_FS_BITMAPS))
- return 1;
+ return;
if (check_fs_read_write(argv[0]))
return;
@@ -1018,7 +1035,7 @@ void do_freei(int argc, char *argv[])
!ext2fs_test_inode_bitmap2(current_fs->inode_map,inode))
com_err(argv[0], 0, "Warning: inode already clear");
while (len-- > 0)
- ext2fs_unmark_inode_bitmap2(current_fs->inode_map, inode);
+ ext2fs_unmark_inode_bitmap2(current_fs->inode_map, inode++);
ext2fs_mark_ib_dirty(current_fs);
}
@@ -1561,22 +1578,38 @@ void do_find_free_inode(int argc, char *argv[])
}
#ifndef READ_ONLY
-static errcode_t copy_file(int fd, ext2_ino_t newfile)
+static errcode_t copy_file(int fd, ext2_ino_t newfile, int bufsize, int make_holes)
{
ext2_file_t e2_file;
errcode_t retval;
int got;
unsigned int written;
- char buf[8192];
+ char *buf;
char *ptr;
+ char *zero_buf;
+ int cmp;
retval = ext2fs_file_open(current_fs, newfile,
EXT2_FILE_WRITE, &e2_file);
if (retval)
return retval;
+ retval = ext2fs_get_mem(bufsize, &buf);
+ if (retval) {
+ com_err("copy_file", retval, "can't allocate buffer\n");
+ return retval;
+ }
+
+ /* This is used for checking whether the whole block is zero */
+ retval = ext2fs_get_memzero(bufsize, &zero_buf);
+ if (retval) {
+ com_err("copy_file", retval, "can't allocate buffer\n");
+ ext2fs_free_mem(&buf);
+ return retval;
+ }
+
while (1) {
- got = read(fd, buf, sizeof(buf));
+ got = read(fd, buf, bufsize);
if (got == 0)
break;
if (got < 0) {
@@ -1584,6 +1617,21 @@ static errcode_t copy_file(int fd, ext2_ino_t newfile)
goto fail;
}
ptr = buf;
+
+ /* Sparse copy */
+ if (make_holes) {
+ /* Check whether all is zero */
+ cmp = memcmp(ptr, zero_buf, got);
+ if (cmp == 0) {
+ /* The whole block is zero, make a hole */
+ retval = ext2fs_file_lseek(e2_file, got, EXT2_SEEK_CUR, NULL);
+ if (retval)
+ goto fail;
+ got = 0;
+ }
+ }
+
+ /* Normal copy */
while (got > 0) {
retval = ext2fs_file_write(e2_file, ptr,
got, &written);
@@ -1594,10 +1642,14 @@ static errcode_t copy_file(int fd, ext2_ino_t newfile)
ptr += written;
}
}
+ ext2fs_free_mem(&buf);
+ ext2fs_free_mem(&zero_buf);
retval = ext2fs_file_close(e2_file);
return retval;
fail:
+ ext2fs_free_mem(&buf);
+ ext2fs_free_mem(&zero_buf);
(void) ext2fs_file_close(e2_file);
return retval;
}
@@ -1610,6 +1662,8 @@ void do_write(int argc, char *argv[])
ext2_ino_t newfile;
errcode_t retval;
struct ext2_inode inode;
+ int bufsize = IO_BUFSIZE;
+ int make_holes = 0;
if (common_args_process(argc, argv, 3, 3, "write",
"<native file> <new file>", CHECK_FS_RW))
@@ -1667,14 +1721,33 @@ void do_write(int argc, char *argv[])
inode.i_links_count = 1;
inode.i_size = statbuf.st_size;
if (current_fs->super->s_feature_incompat &
- EXT3_FEATURE_INCOMPAT_EXTENTS)
+ EXT3_FEATURE_INCOMPAT_EXTENTS) {
+ int i;
+ struct ext3_extent_header *eh;
+
+ eh = (struct ext3_extent_header *) &inode.i_block[0];
+ eh->eh_depth = 0;
+ eh->eh_entries = 0;
+ eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
+ i = (sizeof(inode.i_block) - sizeof(*eh)) /
+ sizeof(struct ext3_extent);
+ eh->eh_max = ext2fs_cpu_to_le16(i);
inode.i_flags |= EXT4_EXTENTS_FL;
+ }
if (debugfs_write_new_inode(newfile, &inode, argv[0])) {
close(fd);
return;
}
if (LINUX_S_ISREG(inode.i_mode)) {
- retval = copy_file(fd, newfile);
+ if (statbuf.st_blocks < statbuf.st_size / S_BLKSIZE) {
+ make_holes = 1;
+ /*
+ * Use I/O blocksize as buffer size when
+ * copying sparse files.
+ */
+ bufsize = statbuf.st_blksize;
+ }
+ retval = copy_file(fd, newfile, bufsize, make_holes);
if (retval)
com_err("copy_file", retval, 0);
}
@@ -1749,8 +1822,7 @@ void do_mknod(int argc, char *argv[])
}
if (ext2fs_test_inode_bitmap2(current_fs->inode_map,newfile))
com_err(argv[0], 0, "Warning: inode already set");
- ext2fs_mark_inode_bitmap2(current_fs->inode_map, newfile);
- ext2fs_mark_ib_dirty(current_fs);
+ ext2fs_inode_alloc_stats2(current_fs, newfile, +1, 0);
memset(&inode, 0, sizeof(inode));
inode.i_mode = mode;
inode.i_atime = inode.i_ctime = inode.i_mtime =
@@ -1973,13 +2045,11 @@ void do_rmdir(int argc, char *argv[])
void do_show_debugfs_params(int argc EXT2FS_ATTR((unused)),
char *argv[] EXT2FS_ATTR((unused)))
{
- FILE *out = stdout;
-
if (current_fs)
- fprintf(out, "Open mode: read-%s\n",
- current_fs->flags & EXT2_FLAG_RW ? "write" : "only");
- fprintf(out, "Filesystem in use: %s\n",
- current_fs ? current_fs->device_name : "--none--");
+ printf("Open mode: read-%s\n",
+ current_fs->flags & EXT2_FLAG_RW ? "write" : "only");
+ printf("Filesystem in use: %s\n",
+ current_fs ? current_fs->device_name : "--none--");
}
#ifndef READ_ONLY
@@ -2032,11 +2102,13 @@ void do_bmap(int argc, char *argv[])
ino = string_to_inode(argv[1]);
if (!ino)
return;
- blk = parse_ulong(argv[2], argv[0], "logical_block", &err);
+ err = strtoblk(argv[0], argv[2], "logical block", &blk);
+ if (err)
+ return;
errcode = ext2fs_bmap2(current_fs, ino, 0, 0, 0, blk, 0, &pblk);
if (errcode) {
- com_err("argv[0]", errcode,
+ com_err(argv[0], errcode,
"while mapping logical block %llu\n", blk);
return;
}
@@ -2177,10 +2249,14 @@ void do_punch(int argc, char *argv[])
ino = string_to_inode(argv[1]);
if (!ino)
return;
- start = parse_ulong(argv[2], argv[0], "logical_block", &err);
- if (argc == 4)
- end = parse_ulong(argv[3], argv[0], "logical_block", &err);
- else
+ err = strtoblk(argv[0], argv[2], "logical block", &start);
+ if (err)
+ return;
+ if (argc == 4) {
+ err = strtoblk(argv[0], argv[3], "logical block", &end);
+ if (err)
+ return;
+ } else
end = ~0;
errcode = ext2fs_punch(current_fs, ino, 0, 0, start, end);
@@ -2194,6 +2270,49 @@ void do_punch(int argc, char *argv[])
}
#endif /* READ_ONLY */
+void do_symlink(int argc, char *argv[])
+{
+ char *cp;
+ ext2_ino_t parent;
+ char *name, *target;
+ errcode_t retval;
+
+ if (common_args_process(argc, argv, 3, 3, "symlink",
+ "<filename> <target>", CHECK_FS_RW))
+ return;
+
+ cp = strrchr(argv[1], '/');
+ if (cp) {
+ *cp = 0;
+ parent = string_to_inode(argv[1]);
+ if (!parent) {
+ com_err(argv[1], ENOENT, 0);
+ return;
+ }
+ name = cp+1;
+ } else {
+ parent = cwd;
+ name = argv[1];
+ }
+ target = argv[2];
+
+try_again:
+ retval = ext2fs_symlink(current_fs, parent, 0, name, target);
+ if (retval == EXT2_ET_DIR_NO_SPACE) {
+ retval = ext2fs_expand_dir(current_fs, parent);
+ if (retval) {
+ com_err(argv[0], retval, "while expanding directory");
+ return;
+ }
+ goto try_again;
+ }
+ if (retval) {
+ com_err("ext2fs_symlink", retval, 0);
+ return;
+ }
+
+}
+
void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[])
{
struct ext2_super_block *sb;
@@ -2205,11 +2324,6 @@ void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[])
return;
sb = current_fs->super;
- if (sb->s_mmp_block <= sb->s_first_data_block ||
- sb->s_mmp_block >= ext2fs_blocks_count(sb)) {
- com_err(argv[0], EXT2_ET_MMP_BAD_BLOCK, "while dumping it.\n");
- return;
- }
if (current_fs->mmp_buf == NULL) {
retval = ext2fs_get_mem(current_fs->blocksize,
@@ -2241,10 +2355,10 @@ void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[])
fprintf(stdout, "magic: 0x%x\n", mmp_s->mmp_magic);
}
-static int source_file(const char *cmd_file, int sci_idx)
+static int source_file(const char *cmd_file, int ss_idx)
{
FILE *f;
- char buf[256];
+ char buf[BUFSIZ];
char *cp;
int exit_status = 0;
int retval;
@@ -2272,9 +2386,9 @@ static int source_file(const char *cmd_file, int sci_idx)
if (cp)
*cp = 0;
printf("debugfs: %s\n", buf);
- retval = ss_execute_line(sci_idx, buf);
+ retval = ss_execute_line(ss_idx, buf);
if (retval) {
- ss_perror(sci_idx, retval, buf);
+ ss_perror(ss_idx, retval, buf);
exit_status++;
}
}
@@ -2286,7 +2400,6 @@ static int source_file(const char *cmd_file, int sci_idx)
int main(int argc, char **argv)
{
int retval;
- int sci_idx;
const char *usage =
"Usage: %s [-b blocksize] [-s superblock] [-f cmd_file] "
"[-R request] [-V] ["
@@ -2346,8 +2459,11 @@ int main(int argc, char **argv)
"block size", 0);
break;
case 's':
- superblock = parse_ulong(optarg, argv[0],
- "superblock number", 0);
+ retval = strtoblk(argv[0], optarg,
+ "superblock block number",
+ &superblock);
+ if (retval)
+ return 1;
break;
case 'c':
catastrophic = 1;
diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h
index 994577ce..9b67f69c 100644
--- a/debugfs/debugfs.h
+++ b/debugfs/debugfs.h
@@ -2,8 +2,10 @@
* debugfs.h --- header file for the debugfs program
*/
+#include "ss/ss.h"
#include "ext2fs/ext2_fs.h"
#include "ext2fs/ext2fs.h"
+#include "quota/quotaio.h"
#ifdef __STDC__
#define NOARGS void
@@ -20,7 +22,10 @@
#define CHECK_FS_NOTOPEN 0x0004
extern ext2_filsys current_fs;
+extern quota_ctx_t current_qctx;
extern ext2_ino_t root, cwd;
+extern int sci_idx;
+extern ss_request_table debug_cmds, extent_cmds;
extern void reset_getopt(void);
extern FILE *open_pager(void);
@@ -36,7 +41,8 @@ extern unsigned long parse_ulong(const char *str, const char *cmd,
const char *descr, int *err);
extern unsigned long long parse_ulonglong(const char *str, const char *cmd,
const char *descr, int *err);
-extern int strtoblk(const char *cmd, const char *str, blk64_t *ret);
+extern int strtoblk(const char *cmd, const char *str, const char *errmsg,
+ blk64_t *ret);
extern int common_args_process(int argc, char *argv[], int min_argc,
int max_argc, const char *cmd,
const char *usage, int flags);
@@ -63,6 +69,32 @@ extern void do_dump(int argc, char **argv);
extern void do_cat(int argc, char **argv);
extern void do_rdump(int argc, char **argv);
+/* extent_inode.c */
+extern void do_extent_open(int argc, char **argv);
+extern void do_extent_close(int argc, char **argv);
+extern void do_current_node(int argc, char **argv);
+extern void do_root_node(int argc, char **argv);
+extern void do_last_leaf(int argc, char **argv);
+extern void do_first_sib(int argc, char **argv);
+extern void do_last_sib(int argc, char **argv);
+extern void do_next_sib(int argc, char **argv);
+extern void do_prev_sib(int argc, char **argv);
+extern void do_next_leaf(int argc, char **argv);
+extern void do_prev_leaf(int argc, char **argv);
+extern void do_next(int argc, char **argv);
+extern void do_prev(int argc, char **argv);
+extern void do_up(int argc, char **argv);
+extern void do_down(int argc, char **argv);
+extern void do_delete_node(int argc, char **argv);
+extern void do_replace_node(int argc, char **argv);
+extern void do_split_node(int argc, char **argv);
+extern void do_insert_node(int argc, char **argv);
+extern void do_set_bmap(int argc, char **argv);
+extern void do_print_all(int argc, char **argv);
+extern void do_fix_parents(int argc, char **argv);
+extern void do_info(int argc, char **argv);
+extern void do_goto_block(int argc, char **argv);
+
/* htree.c */
extern void do_htree_dump(int argc, char **argv);
extern void do_dx_hash(int argc, char **argv);
@@ -133,9 +165,21 @@ extern void do_imap(int argc, char **argv);
extern void do_set_current_time(int argc, char **argv);
extern void do_supported_features(int argc, char **argv);
extern void do_punch(int argc, char **argv);
+extern void do_symlink(int argc, char **argv);
extern void do_dump_mmp(int argc, char **argv);
extern void do_set_mmp_value(int argc, char **argv);
extern void do_freefrag(int argc, char **argv);
extern void do_filefrag(int argc, char *argv[]);
+
+/* quota.c */
+extern void do_list_quota(int argc, char *argv[]);
+extern void do_get_quota(int argc, char *argv[]);
+
+/* util.c */
+extern time_t string_to_time(const char *arg);
+
+/* zap.c */
+extern void do_zap_block(int argc, char **argv);
+extern void do_block_dump(int argc, char **argv);
diff --git a/debugfs/dump.c b/debugfs/dump.c
index a15a0b73..51bc734a 100644
--- a/debugfs/dump.c
+++ b/debugfs/dump.c
@@ -105,10 +105,10 @@ static void dump_file(const char *cmdname, ext2_ino_t ino, int fd,
{
errcode_t retval;
struct ext2_inode inode;
- char buf[8192];
+ char *buf = 0;
ext2_file_t e2_file;
int nbytes;
- unsigned int got;
+ unsigned int got, blocksize = current_fs->blocksize;
if (debugfs_read_inode(ino, &inode, cmdname))
return;
@@ -118,8 +118,13 @@ static void dump_file(const char *cmdname, ext2_ino_t ino, int fd,
com_err(cmdname, retval, "while opening ext2 file");
return;
}
+ retval = ext2fs_get_mem(blocksize, &buf);
+ if (retval) {
+ com_err(cmdname, retval, "while allocating memory");
+ return;
+ }
while (1) {
- retval = ext2fs_file_read(e2_file, buf, sizeof(buf), &got);
+ retval = ext2fs_file_read(e2_file, buf, blocksize, &got);
if (retval)
com_err(cmdname, retval, "while reading ext2 file");
if (got == 0)
@@ -128,6 +133,8 @@ static void dump_file(const char *cmdname, ext2_ino_t ino, int fd,
if ((unsigned) nbytes != got)
com_err(cmdname, errno, "while writing file");
}
+ if (buf)
+ ext2fs_free_mem(&buf);
retval = ext2fs_file_close(e2_file);
if (retval) {
com_err(cmdname, retval, "while closing ext2 file");
@@ -136,8 +143,6 @@ static void dump_file(const char *cmdname, ext2_ino_t ino, int fd,
if (preserve)
fix_perms("dump_file", &inode, fd, outname);
- else if (fd != 1)
- close(fd);
return;
}
@@ -184,6 +189,11 @@ void do_dump(int argc, char **argv)
}
dump_file(argv[0], inode, fd, preserve, out_fn);
+ if (close(fd) != 0) {
+ com_err(argv[0], errno, "while closing %s for dump_inode",
+ out_fn);
+ return;
+ }
return;
}
@@ -266,6 +276,10 @@ static void rdump_inode(ext2_ino_t ino, struct ext2_inode *inode,
goto errout;
}
dump_file("rdump", ino, fd, 1, fullname);
+ if (close(fd) != 0) {
+ com_err("rdump", errno, "while dumping %s", fullname);
+ goto errout;
+ }
}
else if (LINUX_S_ISDIR(inode->i_mode) && strcmp(name, ".") && strcmp(name, "..")) {
errcode_t retval;
diff --git a/debugfs/extent_cmds.ct b/debugfs/extent_cmds.ct
new file mode 100644
index 00000000..e1c4395c
--- /dev/null
+++ b/debugfs/extent_cmds.ct
@@ -0,0 +1,77 @@
+#
+# Copyright (C) 1993 Theodore Ts'o. This file may be redistributed
+# under the terms of the GNU Public License.
+#
+command_table extent_cmds;
+
+request do_current_node, "Current extent node",
+ current_node, current;
+
+request do_root_node, "Goto root extent",
+ root_node, root;
+
+request do_last_leaf, "Goto last leaf",
+ last_leaf;
+
+request do_first_sib, "Goto first sibling",
+ first_sibling, first_sib;
+
+request do_last_sib, "Goto last sibling",
+ last_sibling, last_sib;
+
+request do_next_sib, "Goto next sibling",
+ next_sibling, next_sib, ns;
+
+request do_prev_sib, "Goto previous sibling",
+ prev_sibling, prev_sib, ps;
+
+request do_next_leaf, "Goto next leaf",
+ next_leaf, nl;
+
+request do_prev_leaf, "Goto previous leaf",
+ prev_leaf, pl;
+
+request do_next, "Goto next node",
+ next, n;
+
+request do_prev, "Goto previous node",
+ previous, prev, p;
+
+request do_up, "Up node",
+ up_node, up, u;
+
+request do_down, "Down node",
+ down_node, down, d;
+
+request do_delete_node, "Delete node",
+ delete_node, delete;
+
+request do_insert_node, "Insert node",
+ insert_node, insert;
+
+request do_split_node, "Split node",
+ split_node, split;
+
+request do_fix_parents, "Fix parents",
+ fix_parents, fixp;
+
+request do_set_bmap, "Set block mapping",
+ set_bmap;
+
+request do_replace_node, "Insert node",
+ replace_node, replace;
+
+request do_print_all, "Iterate over all nodes and print them",
+ print_all, all;
+
+request do_goto_block, "Goto extent containing specified block",
+ goto_block, goto;
+
+request do_info, "Print extent info",
+ info;
+
+request do_extent_close, "Close extent handle",
+ extent_close, ec;
+
+end;
+
diff --git a/debugfs/extent_inode.c b/debugfs/extent_inode.c
new file mode 100644
index 00000000..8b22f5e3
--- /dev/null
+++ b/debugfs/extent_inode.c
@@ -0,0 +1,537 @@
+/*
+ * extent_inode.c --- direct extent tree manipulation
+ *
+ * Copyright (C) 2012 Theodore Ts'o. This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern int optind;
+extern char *optarg;
+#endif
+
+#include "debugfs.h"
+
+static ext2_ino_t current_ino;
+static ext2_extent_handle_t current_handle;
+
+static void dbg_print_extent(char *desc, struct ext2fs_extent *extent)
+{
+ if (desc)
+ printf("%s: ", desc);
+ printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ",
+ extent->e_lblk, extent->e_lblk + extent->e_len - 1,
+ extent->e_len, extent->e_pblk);
+ if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF)
+ fputs("LEAF ", stdout);
+ if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
+ fputs("UNINIT ", stdout);
+ if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
+ fputs("2ND_VISIT ", stdout);
+ if (!extent->e_flags)
+ fputs("(none)", stdout);
+ fputc('\n', stdout);
+
+}
+
+static int common_extent_args_process(int argc, char *argv[], int min_argc,
+ int max_argc, const char *cmd,
+ const char *usage, int flags)
+{
+ if (common_args_process(argc, argv, min_argc, max_argc, cmd,
+ usage, flags))
+ return 1;
+
+ if (!current_handle) {
+ com_err(cmd, 0, "Extent handle not open");
+ return 1;
+ }
+ return 0;
+}
+
+static char *orig_prompt, *extent_prompt;
+
+void do_extent_open(int argc, char *argv[])
+{
+ ext2_ino_t inode;
+ int ret;
+ errcode_t retval;
+ char *cp;
+
+ if (check_fs_open(argv[0]))
+ return;
+
+ if (argc == 1) {
+ if (current_ino)
+ printf("Current inode is %d\n", current_ino);
+ else
+ printf("No current inode\n");
+ return;
+ }
+
+ if (common_inode_args_process(argc, argv, &inode, 0))
+ return;
+
+ current_ino = 0;
+
+ retval = ext2fs_extent_open(current_fs, inode, &current_handle);
+ if (retval) {
+ com_err(argv[1], retval, "while opening extent handle");
+ return;
+ }
+
+ current_ino = inode;
+
+ orig_prompt = ss_get_prompt(sci_idx);
+ extent_prompt = malloc(strlen(orig_prompt) + 32);
+ strcpy(extent_prompt, orig_prompt);
+ cp = strchr(extent_prompt, ':');
+ if (cp)
+ *cp = 0;
+ sprintf(extent_prompt + strlen(extent_prompt), " (extent ino %d): ",
+ current_ino);
+ ss_add_request_table(sci_idx, &extent_cmds, 1, &ret);
+ ss_set_prompt(sci_idx, extent_prompt);
+ return;
+}
+
+void do_extent_close(int argc, char *argv[])
+{
+ int ret;
+
+ if (common_args_process(argc, argv, 1, 1,
+ "extent_close", "", 0))
+ return;
+
+ if (!current_handle) {
+ com_err(argv[0], 0, "Extent handle not open");
+ return;
+ }
+
+ ext2fs_extent_free(current_handle);
+ current_handle = NULL;
+ current_ino = 0;
+ ss_delete_request_table(sci_idx, &extent_cmds, &ret);
+ ss_set_prompt(sci_idx, orig_prompt);
+ free(extent_prompt);
+ extent_prompt = NULL;
+}
+
+static void generic_goto_node(const char *my_name, int argc,
+ char **argv, int op)
+{
+ struct ext2fs_extent extent;
+ errcode_t retval;
+
+ if (my_name && common_args_process(argc, argv, 1, 1,
+ my_name, "", 0))
+ return;
+
+ if (!current_handle) {
+ com_err(argv[0], 0, "Extent handle not open");
+ return;
+ }
+
+ retval = ext2fs_extent_get(current_handle, op, &extent);
+ if (retval) {
+ com_err(argv[0], retval, 0);
+ return;
+ }
+ dbg_print_extent(0, &extent);
+}
+
+void do_current_node(int argc, char *argv[])
+{
+ generic_goto_node("current_node", argc, argv, EXT2_EXTENT_CURRENT);
+}
+
+void do_root_node(int argc, char *argv[])
+{
+ generic_goto_node("root_node", argc, argv, EXT2_EXTENT_ROOT);
+}
+
+void do_last_leaf(int argc, char *argv[])
+{
+ generic_goto_node("last_leaf", argc, argv, EXT2_EXTENT_LAST_LEAF);
+}
+
+void do_first_sib(int argc, char *argv[])
+{
+ generic_goto_node("first_sib", argc, argv, EXT2_EXTENT_FIRST_SIB);
+}
+
+void do_last_sib(int argc, char *argv[])
+{
+ generic_goto_node("next_sib", argc, argv, EXT2_EXTENT_LAST_SIB);
+}
+
+void do_next_sib(int argc, char *argv[])
+{
+ generic_goto_node("next_sib", argc, argv, EXT2_EXTENT_NEXT_SIB);
+}
+
+void do_prev_sib(int argc, char *argv[])
+{
+ generic_goto_node("prev_sib", argc, argv, EXT2_EXTENT_PREV_SIB);
+}
+
+void do_next_leaf(int argc, char *argv[])
+{
+ generic_goto_node("next_leaf", argc, argv, EXT2_EXTENT_NEXT_LEAF);
+}
+
+void do_prev_leaf(int argc, char *argv[])
+{
+ generic_goto_node("prev_leaf", argc, argv, EXT2_EXTENT_PREV_LEAF);
+}
+
+void do_next(int argc, char *argv[])
+{
+ generic_goto_node("next", argc, argv, EXT2_EXTENT_NEXT);
+}
+
+void do_prev(int argc, char *argv[])
+{
+ generic_goto_node("prev", argc, argv, EXT2_EXTENT_PREV);
+}
+
+void do_up(int argc, char *argv[])
+{
+ generic_goto_node("up", argc, argv, EXT2_EXTENT_UP);
+}
+
+void do_down(int argc, char *argv[])
+{
+ generic_goto_node("down", argc, argv, EXT2_EXTENT_DOWN);
+}
+
+void do_delete_node(int argc, char *argv[])
+{
+ struct ext2fs_extent extent;
+ errcode_t retval;
+
+ if (common_extent_args_process(argc, argv, 1, 1, "delete_node",
+ "", CHECK_FS_RW | CHECK_FS_BITMAPS))
+ return;
+
+ retval = ext2fs_extent_delete(current_handle, 0);
+ if (retval) {
+ com_err(argv[0], retval, 0);
+ return;
+ }
+
+ retval = ext2fs_extent_get(current_handle, EXT2_EXTENT_CURRENT,
+ &extent);
+ if (retval)
+ return;
+ dbg_print_extent(0, &extent);
+}
+
+void do_replace_node(int argc, char *argv[])
+{
+ const char *usage = "[--uninit] <lblk> <len> <pblk>";
+ errcode_t retval;
+ struct ext2fs_extent extent;
+ int err;
+
+ if (common_extent_args_process(argc, argv, 3, 5, "replace_node",
+ usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
+ return;
+
+ extent.e_flags = 0;
+
+ if (!strcmp(argv[1], "--uninit")) {
+ argc--;
+ argv++;
+ extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
+ }
+
+ if (argc != 4) {
+ fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
+ return;
+ }
+
+ err = strtoblk(argv[0], argv[1], "logical block", &extent.e_lblk);
+ if (err)
+ return;
+
+ extent.e_len = parse_ulong(argv[2], argv[0], "length", &err);
+ if (err)
+ return;
+
+ err = strtoblk(argv[0], argv[3], "physical block", &extent.e_pblk);
+ if (err)
+ return;
+
+ retval = ext2fs_extent_replace(current_handle, 0, &extent);
+ if (retval) {
+ com_err(argv[0], retval, 0);
+ return;
+ }
+ generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
+}
+
+void do_split_node(int argc, char *argv[])
+{
+ errcode_t retval;
+
+ if (common_extent_args_process(argc, argv, 1, 1, "split_node",
+ "", CHECK_FS_RW | CHECK_FS_BITMAPS))
+ return;
+
+ retval = ext2fs_extent_node_split(current_handle);
+ if (retval) {
+ com_err(argv[0], retval, 0);
+ return;
+ }
+ generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
+}
+
+void do_insert_node(int argc, char *argv[])
+{
+ const char *usage = "[--after] [--uninit] <lblk> <len> <pblk>";
+ errcode_t retval;
+ struct ext2fs_extent extent;
+ char *cmd;
+ int err;
+ int flags = 0;
+
+ if (common_extent_args_process(argc, argv, 3, 6, "insert_node",
+ usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
+ return;
+
+ cmd = argv[0];
+
+ extent.e_flags = 0;
+
+ while (argc > 2) {
+ if (!strcmp(argv[1], "--after")) {
+ argc--;
+ argv++;
+ flags |= EXT2_EXTENT_INSERT_AFTER;
+ continue;
+ }
+ if (!strcmp(argv[1], "--uninit")) {
+ argc--;
+ argv++;
+ extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
+ continue;
+ }
+ break;
+ }
+
+ if (argc != 4) {
+ fprintf(stderr, "usage: %s %s\n", cmd, usage);
+ return;
+ }
+
+ err = strtoblk(cmd, argv[1], "logical block", &extent.e_lblk);
+ if (err)
+ return;
+
+ extent.e_len = parse_ulong(argv[2], cmd, "length", &err);
+ if (err)
+ return;
+
+ err = strtoblk(cmd, argv[3], "physical block", &extent.e_pblk);
+ if (err)
+ return;
+
+ retval = ext2fs_extent_insert(current_handle, flags, &extent);
+ if (retval) {
+ com_err(cmd, retval, 0);
+ return;
+ }
+ generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
+}
+
+void do_set_bmap(int argc, char **argv)
+{
+ const char *usage = "[--uninit] <lblk> <pblk>";
+ struct ext2fs_extent extent;
+ errcode_t retval;
+ blk64_t logical;
+ blk64_t physical;
+ char *cmd = argv[0];
+ int flags = 0;
+ int err;
+
+ if (common_extent_args_process(argc, argv, 3, 5, "set_bmap",
+ usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
+ return;
+
+ if (argc > 2 && !strcmp(argv[1], "--uninit")) {
+ argc--;
+ argv++;
+ flags |= EXT2_EXTENT_SET_BMAP_UNINIT;
+ }
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s %s\n", cmd, usage);
+ return;
+ }
+
+ err = strtoblk(cmd, argv[1], "logical block", &logical);
+ if (err)
+ return;
+
+ err = strtoblk(cmd, argv[2], "physical block", &physical);
+ if (err)
+ return;
+
+ retval = ext2fs_extent_set_bmap(current_handle, logical,
+ physical, flags);
+ if (retval) {
+ com_err(cmd, retval, 0);
+ return;
+ }
+
+ retval = ext2fs_extent_get(current_handle, EXT2_EXTENT_CURRENT,
+ &extent);
+ if (retval)
+ return;
+ dbg_print_extent(0, &extent);
+}
+
+void do_print_all(int argc, char **argv)
+{
+ const char *usage = "[--leaf-only|--reverse|--reverse-leaf]";
+ struct ext2fs_extent extent;
+ errcode_t retval;
+ errcode_t end_err = EXT2_ET_EXTENT_NO_NEXT;
+ int op = EXT2_EXTENT_NEXT;
+ int first_op = EXT2_EXTENT_ROOT;
+
+
+ if (common_extent_args_process(argc, argv, 1, 2, "print_all",
+ usage, 0))
+ return;
+
+ if (argc == 2) {
+ if (!strcmp(argv[1], "--leaf-only"))
+ op = EXT2_EXTENT_NEXT_LEAF;
+ else if (!strcmp(argv[1], "--reverse")) {
+ op = EXT2_EXTENT_PREV;
+ first_op = EXT2_EXTENT_LAST_LEAF;
+ end_err = EXT2_ET_EXTENT_NO_PREV;
+ } else if (!strcmp(argv[1], "--reverse-leaf")) {
+ op = EXT2_EXTENT_PREV_LEAF;
+ first_op = EXT2_EXTENT_LAST_LEAF;
+ end_err = EXT2_ET_EXTENT_NO_PREV;
+ } else {
+ fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
+ return;
+ }
+ }
+
+ retval = ext2fs_extent_get(current_handle, first_op, &extent);
+ if (retval) {
+ com_err(argv[0], retval, 0);
+ return;
+ }
+ dbg_print_extent(0, &extent);
+
+ while (1) {
+ retval = ext2fs_extent_get(current_handle, op, &extent);
+ if (retval == end_err)
+ break;
+
+ if (retval) {
+ com_err(argv[0], retval, 0);
+ return;
+ }
+ dbg_print_extent(0, &extent);
+ }
+}
+
+void do_fix_parents(int argc, char **argv)
+{
+ errcode_t retval;
+
+ if (common_extent_args_process(argc, argv, 1, 1, "fix_parents", "",
+ CHECK_FS_RW))
+ return;
+
+ retval = ext2fs_extent_fix_parents(current_handle);
+ if (retval) {
+ com_err(argv[0], retval, 0);
+ return;
+ }
+}
+
+void do_info(int argc, char **argv)
+{
+ struct ext2fs_extent extent;
+ struct ext2_extent_info info;
+ errcode_t retval;
+
+ if (common_extent_args_process(argc, argv, 1, 1, "info", "", 0))
+ return;
+
+ retval = ext2fs_extent_get_info(current_handle, &info);
+ if (retval) {
+ com_err(argv[0], retval, 0);
+ return;
+ }
+
+ retval = ext2fs_extent_get(current_handle,
+ EXT2_EXTENT_CURRENT, &extent);
+ if (retval) {
+ com_err(argv[0], retval, 0);
+ return;
+ }
+
+ dbg_print_extent(0, &extent);
+
+ printf("Current handle location: %d/%d (max: %d, bytes %d), level %d/%d\n",
+ info.curr_entry, info.num_entries, info.max_entries,
+ info.bytes_avail, info.curr_level, info.max_depth);
+ printf("\tmax lblk: %llu, max pblk: %llu\n", info.max_lblk,
+ info.max_pblk);
+ printf("\tmax_len: %u, max_uninit_len: %u\n", info.max_len,
+ info.max_uninit_len);
+}
+
+void do_goto_block(int argc, char **argv)
+{
+ errcode_t retval;
+ blk64_t blk;
+ int level = 0, err;
+
+ if (common_extent_args_process(argc, argv, 2, 3, "goto_block",
+ "block [level]", 0))
+ return;
+
+ if (strtoblk(argv[0], argv[1], NULL, &blk))
+ return;
+
+ if (argc == 3) {
+ level = parse_ulong(argv[2], argv[0], "level", &err);
+ if (err)
+ return;
+ }
+
+ retval = ext2fs_extent_goto2(current_handle, level, (blk64_t) blk);
+
+ if (retval) {
+ com_err(argv[0], retval,
+ "while trying to go to block %llu, level %d",
+ (unsigned long long) blk, level);
+ return;
+ }
+
+ generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
+}
diff --git a/debugfs/filefrag.c b/debugfs/filefrag.c
index 7f28bc0b..0adea405 100644
--- a/debugfs/filefrag.c
+++ b/debugfs/filefrag.c
@@ -289,7 +289,7 @@ void do_filefrag(int argc, char *argv[])
if (argc > optind+1) {
print_usage:
- com_err(0, 0, "Usage: filefrag [-dv] file");
+ com_err(0, 0, "Usage: filefrag [-dvr] file");
return;
}
diff --git a/debugfs/htree.c b/debugfs/htree.c
index 05745eb3..24f8250c 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -52,7 +52,7 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
return;
}
- printf("Reading directory block %llu, phys %llu\n", blk, pblk);
+ fprintf(pager, "Reading directory block %llu, phys %llu\n", blk, pblk);
errcode = ext2fs_read_dir_block2(current_fs, pblk, buf, 0);
if (errcode) {
com_err("htree_dump_leaf_node", errcode,
@@ -201,7 +201,6 @@ void do_htree_dump(int argc, char *argv[])
char *buf = NULL;
struct ext2_dx_root_info *rootnode;
struct ext2_dx_entry *ent;
- struct ext2_dx_countlimit *limit;
errcode_t errcode;
if (check_fs_open(argv[0]))
@@ -255,7 +254,6 @@ void do_htree_dump(int argc, char *argv[])
fprintf(pager, "\t Flags: %d\n", rootnode->unused_flags);
ent = (struct ext2_dx_entry *) (buf + 24 + rootnode->info_length);
- limit = (struct ext2_dx_countlimit *) ent;
htree_dump_int_node(current_fs, ino, &inode, rootnode, ent,
buf + current_fs->blocksize,
diff --git a/debugfs/icheck.c b/debugfs/icheck.c
index 48f432aa..3b9bd145 100644
--- a/debugfs/icheck.c
+++ b/debugfs/icheck.c
@@ -86,7 +86,7 @@ void do_icheck(int argc, char **argv)
}
for (i=1; i < argc; i++) {
- if (strtoblk(argv[0], argv[i], &bw.barray[i-1].blk))
+ if (strtoblk(argv[0], argv[i], NULL, &bw.barray[i-1].blk))
goto error_out;
}
diff --git a/debugfs/logdump.c b/debugfs/logdump.c
index 6e39b74c..d2c3b301 100644
--- a/debugfs/logdump.c
+++ b/debugfs/logdump.c
@@ -37,12 +37,12 @@ extern char *optarg;
enum journal_location {JOURNAL_IS_INTERNAL, JOURNAL_IS_EXTERNAL};
-#define ANY_BLOCK ((blk_t) -1)
+#define ANY_BLOCK ((blk64_t) -1)
-int dump_all, dump_contents, dump_descriptors;
-blk_t block_to_dump, bitmap_to_dump, inode_block_to_dump;
-unsigned int group_to_dump, inode_offset_to_dump;
-ext2_ino_t inode_to_dump;
+static int dump_all, dump_contents, dump_descriptors;
+static blk64_t block_to_dump, bitmap_to_dump, inode_block_to_dump;
+static unsigned int group_to_dump, inode_offset_to_dump;
+static ext2_ino_t inode_to_dump;
struct journal_source
{
@@ -162,7 +162,7 @@ void do_logdump(int argc, char **argv)
(group_offset / inodes_per_block);
inode_offset_to_dump = ((group_offset % inodes_per_block)
* sizeof(struct ext2_inode));
- printf("Inode %u is at group %u, block %u, offset %u\n",
+ printf("Inode %u is at group %u, block %llu, offset %u\n",
inode_to_dump, inode_group,
inode_block_to_dump, inode_offset_to_dump);
}
@@ -273,42 +273,43 @@ print_usage:
static int read_journal_block(const char *cmd, struct journal_source *source,
- off_t offset, char *buf, int size,
- unsigned int *got)
+ off_t offset, char *buf, unsigned int size)
{
int retval;
+ unsigned int got;
if (source->where == JOURNAL_IS_EXTERNAL) {
if (lseek(source->fd, offset, SEEK_SET) < 0) {
retval = errno;
- com_err(cmd, retval, "while seeking in reading journal");
- return retval;
+ goto seek_err;
}
retval = read(source->fd, buf, size);
- if (retval >= 0) {
- *got = retval;
- retval = 0;
- } else
+ if (retval < 0) {
retval = errno;
+ goto read_err;
+ }
+ got = retval;
+ retval = 0;
} else {
retval = ext2fs_file_lseek(source->file, offset,
EXT2_SEEK_SET, NULL);
if (retval) {
+ seek_err:
com_err(cmd, retval, "while seeking in reading journal");
return retval;
}
-
- retval = ext2fs_file_read(source->file, buf, size, got);
+ retval = ext2fs_file_read(source->file, buf, size, &got);
+ if (retval) {
+ read_err:
+ com_err(cmd, retval, "while reading journal");
+ return retval;
+ }
}
-
- if (retval)
- com_err(cmd, retval, "while reading journal");
- else if (*got != (unsigned int) size) {
- com_err(cmd, 0, "short read (read %d, expected %d) "
- "while reading journal", *got, size);
+ if (got != size) {
+ com_err(cmd, 0, "short read (read %u, expected %u) "
+ "while reading journal", got, size);
retval = -1;
}
-
return retval;
}
@@ -338,7 +339,6 @@ static void dump_journal(char *cmdname, FILE *out_file,
char buf[8192];
journal_superblock_t *jsb;
unsigned int blocksize = 1024;
- unsigned int got;
int retval;
__u32 magic, sequence, blocktype;
journal_header_t *header;
@@ -347,8 +347,7 @@ static void dump_journal(char *cmdname, FILE *out_file,
unsigned int blocknr = 0;
/* First, check to see if there's an ext2 superblock header */
- retval = read_journal_block(cmdname, source, 0,
- buf, 2048, &got);
+ retval = read_journal_block(cmdname, source, 0, buf, 2048);
if (retval)
return;
@@ -377,7 +376,7 @@ static void dump_journal(char *cmdname, FILE *out_file,
/* Next, read the journal superblock */
retval = read_journal_block(cmdname, source, blocknr*blocksize,
- jsb_buffer, 1024, &got);
+ jsb_buffer, 1024);
if (retval)
return;
@@ -401,8 +400,8 @@ static void dump_journal(char *cmdname, FILE *out_file,
while (1) {
retval = read_journal_block(cmdname, source,
blocknr*blocksize, buf,
- blocksize, &got);
- if (retval || got != blocksize)
+ blocksize);
+ if (retval)
return;
header = (journal_header_t *) buf;
@@ -576,7 +575,6 @@ static void dump_metadata_block(FILE *out_file, struct journal_source *source,
int blocksize,
tid_t transaction)
{
- unsigned int got;
int retval;
char buf[8192];
@@ -612,7 +610,7 @@ static void dump_metadata_block(FILE *out_file, struct journal_source *source,
retval = read_journal_block("logdump", source,
blocksize * log_blocknr,
- buf, blocksize, &got);
+ buf, blocksize);
if (retval)
return;
@@ -624,7 +622,7 @@ static void dump_metadata_block(FILE *out_file, struct journal_source *source,
offset = ((block_to_dump - super->s_first_data_block) %
super->s_blocks_per_group);
- fprintf(out_file, " (block bitmap for block %u: "
+ fprintf(out_file, " (block bitmap for block %llu: "
"block is %s)\n",
block_to_dump,
ext2fs_test_bit(offset, buf) ? "SET" : "CLEAR");
diff --git a/debugfs/lsdel.c b/debugfs/lsdel.c
index bed0ce61..e5b2d203 100644
--- a/debugfs/lsdel.c
+++ b/debugfs/lsdel.c
@@ -87,7 +87,7 @@ void do_lsdel(int argc, char **argv)
time_t now;
FILE *out;
- if (common_args_process(argc, argv, 1, 2, "ls_deleted_inodes",
+ if (common_args_process(argc, argv, 1, 2, "list_deleted_inodes",
"[secs]", 0))
return;
diff --git a/debugfs/quota.c b/debugfs/quota.c
new file mode 100644
index 00000000..95d064b2
--- /dev/null
+++ b/debugfs/quota.c
@@ -0,0 +1,171 @@
+/*
+ * quota.c --- debugfs quota commands
+ *
+ * Copyright (C) 2014 Theodore Ts'o. This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern int optind;
+extern char *optarg;
+#endif
+
+#include "debugfs.h"
+
+const char *quota_type[] = { "user", "group", NULL };
+
+static int load_quota_ctx(char *progname)
+{
+ errcode_t retval;
+
+ if (check_fs_open(progname))
+ return 1;
+
+ if (!EXT2_HAS_RO_COMPAT_FEATURE(current_fs->super,
+ EXT4_FEATURE_RO_COMPAT_QUOTA)) {
+ com_err(progname, 0, "quota feature not eanbled");
+ return 1;
+ }
+
+ if (current_qctx)
+ return 0;
+
+ retval = quota_init_context(&current_qctx, current_fs, -1);
+ if (retval) {
+ com_err(current_fs->device_name, retval,
+ "while trying to load quota information");
+ return 1;
+ }
+ return 0;
+}
+
+static int parse_quota_type(const char *cmdname, const char *str)
+{
+ errcode_t retval;
+ char *t;
+ int flags = 0;
+ int i;
+
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (strcasecmp(str, quota_type[i]) == 0)
+ break;
+ }
+ if (i >= MAXQUOTAS) {
+ i = strtol(str, &t, 0);
+ if (*t)
+ i = -1;
+ }
+ if (i < 0 || i >= MAXQUOTAS) {
+ com_err(0, 0, "Invalid quota type: %s", str);
+ printf("Valid quota types are: ");
+ for (i = 0; i < MAXQUOTAS; i++)
+ printf("%s ", quota_type[i]);
+ printf("\n");
+ return -1;
+ }
+
+ if (current_fs->flags & EXT2_FLAG_RW)
+ flags |= EXT2_FILE_WRITE;
+
+ retval = quota_file_open(current_qctx, NULL, 0, i, -1, flags);
+ if (retval) {
+ com_err(cmdname, retval,
+ "while opening quota inode (type %d)", i);
+ return -1;
+ }
+ return i;
+}
+
+
+static int list_quota_callback(struct dquot *dq, void *cb_data)
+{
+ printf("%8u %8lld %8lld %8lld %8lld %8lld %8lld\n",
+ dq->dq_id, dq->dq_dqb.dqb_curspace,
+ dq->dq_dqb.dqb_bsoftlimit, dq->dq_dqb.dqb_bhardlimit,
+ dq->dq_dqb.dqb_curinodes,
+ dq->dq_dqb.dqb_isoftlimit, dq->dq_dqb.dqb_ihardlimit);
+ return 0;
+}
+
+void do_list_quota(int argc, char *argv[])
+{
+ errcode_t retval;
+ int i, type;
+ int flags = 0;
+ struct quota_handle *qh;
+
+ if (load_quota_ctx(argv[0]))
+ return;
+
+ if (argc != 2) {
+ com_err(0, 0, "Usage: list_quota <quota_type>\n");
+ return;
+ }
+
+ type = parse_quota_type(argv[0], argv[1]);
+ if (type < 0)
+ return;
+
+ printf("%8s %8s %8s %8s %8s %8s %8s\n",
+ (type == 0) ? "user id" : "group id",
+ "blocks", "quota", "limit", "inodes", "quota", "limit");
+ qh = current_qctx->quota_file[type];
+ retval = qh->qh_ops->scan_dquots(qh, list_quota_callback, NULL);
+ if (retval) {
+ com_err(argv[0], retval, "while scanning dquots");
+ return;
+ }
+}
+
+void do_get_quota(int argc, char *argv[])
+{
+ errcode_t retval;
+ int i, err, type;
+ int flags = 0;
+ struct quota_handle *qh;
+ struct dquot *dq;
+ qid_t id;
+
+ if (load_quota_ctx(argv[0]))
+ return;
+
+ if (argc != 3) {
+ com_err(0, 0, "Usage: get_quota <quota_type> <id>\n");
+ return;
+ }
+
+ type = parse_quota_type(argv[0], argv[1]);
+ if (type < 0)
+ return;
+
+ id = parse_ulong(argv[2], argv[0], "id", &err);
+ if (err)
+ return;
+
+ printf("%8s %8s %8s %8s %8s %8s %8s\n",
+ (type == 0) ? "user id" : "group id",
+ "blocks", "quota", "limit", "inodes", "quota", "limit");
+
+ qh = current_qctx->quota_file[type];
+
+ dq = qh->qh_ops->read_dquot(qh, id);
+ if (dq) {
+ list_quota_callback(dq, NULL);
+ ext2fs_free_mem(&dq);
+ } else
+ com_err(argv[0], 0, "couldn't read quota record");
+
+}
diff --git a/debugfs/ro_debug_cmds.ct b/debugfs/ro_debug_cmds.ct
index 4feb621c..736ade6a 100644
--- a/debugfs/ro_debug_cmds.ct
+++ b/debugfs/ro_debug_cmds.ct
@@ -87,5 +87,13 @@ request do_supported_features, "Print features supported by this version of e2fs
request do_dump_mmp, "Dump MMP information",
dump_mmp;
-end;
+request do_extent_open, "Open inode for extent manipulation",
+ extent_open, eo;
+
+request do_list_quota, "List quota",
+ lost_quota, lq;
+request do_get_quota, "Get quota",
+ get_quota, gq;
+
+end;
diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c
index 08bfd8da..ffbda746 100644
--- a/debugfs/set_fields.c
+++ b/debugfs/set_fields.c
@@ -150,6 +150,8 @@ static struct field_set_info super_fields[] = {
{ "usr_quota_inum", &set_sb.s_usr_quota_inum, NULL, 4, parse_uint },
{ "grp_quota_inum", &set_sb.s_grp_quota_inum, NULL, 4, parse_uint },
{ "overhead_blocks", &set_sb.s_overhead_blocks, NULL, 4, parse_uint },
+ { "backup_bgs", &set_sb.s_backup_bgs[0], NULL, 4, parse_uint,
+ FLAG_ARRAY, 2 },
{ "checksum", &set_sb.s_checksum, NULL, 4, parse_uint },
{ 0, 0, 0, 0 }
};
@@ -389,7 +391,10 @@ static errcode_t parse_uint(struct field_set_info *info, char *field,
n = num & mask;
switch (size) {
case 8:
- *u.ptr64 = n;
+ /* Should never get here */
+ fprintf(stderr, "64-bit field %s has a second 64-bit field\n"
+ "defined; BUG?!?\n", info->name);
+ *u.ptr64 = 0;
break;
case 4:
*u.ptr32 = n;
@@ -526,22 +531,20 @@ static errcode_t parse_hashalg(struct field_set_info *info,
static errcode_t parse_bmap(struct field_set_info *info,
char *field EXT2FS_ATTR((unused)), char *arg)
{
- unsigned long num;
- blk_t blk;
+ blk64_t blk;
errcode_t retval;
char *tmp;
- num = strtoul(arg, &tmp, 0);
+ blk = strtoull(arg, &tmp, 0);
if (*tmp) {
fprintf(stderr, "Couldn't parse '%s' for field %s.\n",
arg, info->name);
return EINVAL;
}
- blk = num;
- retval = ext2fs_bmap(current_fs, set_ino,
+ retval = ext2fs_bmap2(current_fs, set_ino,
(struct ext2_inode *) &set_inode,
- 0, BMAP_SET, array_idx, &blk);
+ NULL, BMAP_SET, array_idx, NULL, &blk);
if (retval) {
com_err("set_inode", retval, "while setting block map");
}
@@ -701,11 +704,14 @@ void do_set_block_group_descriptor(int argc, char *argv[])
int size;
/*
- *Determine whether we are editing an ext2 or ext4 block
- * group descriptor
+ * Determine whether we are editing an ext2 or ext4 block group
+ * descriptor. Descriptors larger than ext4_group_desc cannot
+ * have their fields edited yet, because they do not have any
+ * names assigned. When that happens, this function needs to
+ * be updated for the new descriptor struct and fields.
*/
- if (current_fs && current_fs->super->s_feature_incompat &
- EXT4_FEATURE_INCOMPAT_64BIT) {
+ if (current_fs &&
+ EXT2_DESC_SIZE(current_fs->super) >= EXT2_MIN_DESC_SIZE_64BIT) {
table = ext4_bg_fields;
edit = &set_gd4;
size = sizeof(set_gd4);
@@ -801,7 +807,7 @@ void do_set_mmp_value(int argc, char *argv[])
if (retval) {
com_err(argv[0], retval, "reading MMP block %llu.\n",
(long long)current_fs->super->s_mmp_block);
- ext2fs_free_mem(mmp_s);
+ ext2fs_free_mem(&mmp_s);
return;
}
current_fs->mmp_buf = mmp_s;
diff --git a/debugfs/util.c b/debugfs/util.c
index f43b4704..9ddfe0ba 100644
--- a/debugfs/util.c
+++ b/debugfs/util.c
@@ -201,7 +201,7 @@ char *time_to_string(__u32 cl)
tz = ss_safe_getenv("TZ");
if (!tz)
tz = "";
- do_gmt = !strcmp(tz, "GMT");
+ do_gmt = !strcmp(tz, "GMT") | !strcmp(tz, "GMT0");
}
return asctime((do_gmt) ? gmtime(&t) : localtime(&t));
@@ -211,7 +211,7 @@ char *time_to_string(__u32 cl)
* Parse a string as a time. Return ((time_t)-1) if the string
* doesn't appear to be a sane time.
*/
-extern time_t string_to_time(const char *arg)
+time_t string_to_time(const char *arg)
{
struct tm ts;
time_t ret;
@@ -220,9 +220,20 @@ extern time_t string_to_time(const char *arg)
if (strcmp(arg, "now") == 0) {
return time(0);
}
+ if (arg[0] == '@') {
+ /* interpret it as an integer */
+ arg++;
+ fallback:
+ ret = strtoul(arg, &tmp, 0);
+ if (*tmp)
+ return ((time_t) -1);
+ return ret;
+ }
memset(&ts, 0, sizeof(ts));
#ifdef HAVE_STRPTIME
- strptime(arg, "%Y%m%d%H%M%S", &ts);
+ tmp = strptime(arg, "%Y%m%d%H%M%S", &ts);
+ if (tmp == NULL)
+ goto fallback;
#else
sscanf(arg, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon,
&ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec);
@@ -234,13 +245,9 @@ extern time_t string_to_time(const char *arg)
ts.tm_mday = 0;
#endif
ts.tm_isdst = -1;
- ret = mktime(&ts);
- if (ts.tm_mday == 0 || ret == ((time_t) -1)) {
- /* Try it as an integer... */
- ret = strtoul(arg, &tmp, 0);
- if (*tmp)
- return ((time_t) -1);
- }
+ ret = ts.tm_sec + ts.tm_min*60 + ts.tm_hour*3600 + ts.tm_yday*86400 +
+ (ts.tm_year-70)*31536000 + ((ts.tm_year-69)/4)*86400 -
+ ((ts.tm_year-1)/100)*86400 + ((ts.tm_year+299)/400)*86400;
return ret;
}
@@ -294,17 +301,20 @@ unsigned long long parse_ulonglong(const char *str, const char *cmd,
/*
* This function will convert a string to a block number. It returns
- * 0 on success, 1 on failure.
+ * 0 on success, 1 on failure. On failure, it outputs either an optionally
+ * specified error message or a default.
*/
-int strtoblk(const char *cmd, const char *str, blk64_t *ret)
+int strtoblk(const char *cmd, const char *str, const char *errmsg,
+ blk64_t *ret)
{
- blk_t blk;
+ blk64_t blk;
int err;
- blk = parse_ulonglong(str, cmd, "block number", &err);
+ if (errmsg == NULL)
+ blk = parse_ulonglong(str, cmd, "block number", &err);
+ else
+ blk = parse_ulonglong(str, cmd, errmsg, &err);
*ret = blk;
- if (err)
- com_err(cmd, 0, "Invalid block number: %s", str);
return err;
}
@@ -362,7 +372,7 @@ int common_block_args_process(int argc, char *argv[],
"<block> [count]", CHECK_FS_BITMAPS))
return 1;
- if (strtoblk(argv[0], argv[1], block))
+ if (strtoblk(argv[0], argv[1], NULL, block))
return 1;
if (*block == 0) {
com_err(argv[0], 0, "Invalid block number 0");
@@ -370,7 +380,7 @@ int common_block_args_process(int argc, char *argv[],
}
if (argc > 2) {
- *count = parse_ulong(argv[2], argv[0], "count", &err);
+ err = strtoblk(argv[0], argv[2], "count", count);
if (err)
return 1;
}
diff --git a/debugfs/zap.c b/debugfs/zap.c
new file mode 100644
index 00000000..81092097
--- /dev/null
+++ b/debugfs/zap.c
@@ -0,0 +1,260 @@
+/*
+ * zap.c --- zap block
+ *
+ * Copyright (C) 2012 Theodore Ts'o. This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern int optind;
+extern char *optarg;
+#endif
+
+#include "debugfs.h"
+
+void do_zap_block(int argc, char *argv[])
+{
+ unsigned long pattern = 0;
+ unsigned char *buf;
+ ext2_ino_t inode;
+ errcode_t errcode;
+ blk64_t block;
+ char *file = NULL;
+ int c, err;
+ int offset = -1;
+ int length = -1;
+ int bit = -1;
+
+ if (check_fs_open(argv[0]))
+ return;
+ if (check_fs_read_write(argv[0]))
+ return;
+
+ reset_getopt();
+ while ((c = getopt (argc, argv, "b:f:l:o:p:")) != EOF) {
+ switch (c) {
+ case 'f':
+ file = optarg;
+ break;
+ case 'b':
+ bit = parse_ulong(optarg, argv[0],
+ "bit", &err);
+ if (err)
+ return;
+ if (bit >= (int) current_fs->blocksize * 8) {
+ com_err(argv[0], 0, "The bit to flip "
+ "must be within a %d block\n",
+ current_fs->blocksize);
+ return;
+ }
+ break;
+ case 'p':
+ pattern = parse_ulong(optarg, argv[0],
+ "pattern", &err);
+ if (err)
+ return;
+ if (pattern >= 256) {
+ com_err(argv[0], 0, "The fill pattern must "
+ "be an 8-bit value\n");
+ return;
+ }
+ break;
+ case 'o':
+ offset = parse_ulong(optarg, argv[0],
+ "offset", &err);
+ if (err)
+ return;
+ if (offset >= (int) current_fs->blocksize) {
+ com_err(argv[0], 0, "The offset must be "
+ "within a %d block\n",
+ current_fs->blocksize);
+ return;
+ }
+ break;
+
+ break;
+ case 'l':
+ length = parse_ulong(optarg, argv[0],
+ "length", &err);
+ if (err)
+ return;
+ break;
+ default:
+ goto print_usage;
+ }
+ }
+
+ if (bit > 0 && offset > 0) {
+ com_err(argv[0], 0, "The -o and -b options can not be mixed.");
+ return;
+ }
+
+ if (offset < 0)
+ offset = 0;
+ if (length < 0)
+ length = current_fs->blocksize - offset;
+ if ((offset + length) > (int) current_fs->blocksize) {
+ com_err(argv[0], 0, "The specified length is too bug\n");
+ return;
+ }
+
+ if (argc != optind+1) {
+ print_usage:
+ com_err(0, 0, "Usage:\tzap_block [-f file] [-o offset] "
+ "[-l length] [-p pattern] block_num");
+ com_err(0, 0, "\tzap_block [-f file] [-b bit] "
+ "block_num");
+ return;
+ }
+
+ block = parse_ulonglong(argv[optind], argv[0], "block", &err);
+ if (err)
+ return;
+
+ if (file) {
+ inode = string_to_inode(file);
+ if (!inode)
+ return;
+ errcode = ext2fs_bmap2(current_fs, inode, 0, 0, 0,
+ block, 0, &block);
+ if (errcode) {
+ com_err(argv[0], errcode,
+ "while mapping logical block %llu\n", block);
+ return;
+ }
+ }
+
+ buf = malloc(current_fs->blocksize);
+ if (!buf) {
+ com_err(argv[0], 0, "Couldn't allocate block buffer");
+ return;
+ }
+
+ errcode = io_channel_read_blk64(current_fs->io, block, 1, buf);
+ if (errcode) {
+ com_err(argv[0], errcode,
+ "while reading block %llu\n", block);
+ goto errout;
+ }
+
+ if (bit >= 0)
+ buf[bit >> 3] ^= 1 << (bit & 7);
+ else
+ memset(buf+offset, pattern, length);
+
+ errcode = io_channel_write_blk64(current_fs->io, block, 1, buf);
+ if (errcode) {
+ com_err(argv[0], errcode,
+ "while write block %llu\n", block);
+ goto errout;
+ }
+
+errout:
+ free(buf);
+ return;
+}
+
+void do_block_dump(int argc, char *argv[])
+{
+ unsigned char *buf;
+ ext2_ino_t inode;
+ errcode_t errcode;
+ blk64_t block;
+ char *file = NULL;
+ unsigned int i, j;
+ int c, err;
+ int suppress = -1;
+
+ if (check_fs_open(argv[0]))
+ return;
+
+ reset_getopt();
+ while ((c = getopt (argc, argv, "f:")) != EOF) {
+ switch (c) {
+ case 'f':
+ file = optarg;
+ break;
+
+ default:
+ goto print_usage;
+ }
+ }
+
+ if (argc != optind + 1) {
+ print_usage:
+ com_err(0, 0, "Usage: block_dump [-f inode] block_num");
+ return;
+ }
+
+ block = parse_ulonglong(argv[optind], argv[0], "block", &err);
+ if (err)
+ return;
+
+ if (file) {
+ inode = string_to_inode(file);
+ if (!inode)
+ return;
+ errcode = ext2fs_bmap2(current_fs, inode, 0, 0, 0,
+ block, 0, &block);
+ if (errcode) {
+ com_err(argv[0], errcode,
+ "while mapping logical block %llu\n", block);
+ return;
+ }
+ }
+
+ buf = malloc(current_fs->blocksize);
+ if (!buf) {
+ com_err(argv[0], 0, "Couldn't allocate block buffer");
+ return;
+ }
+
+ errcode = io_channel_read_blk64(current_fs->io, block, 1, buf);
+ if (errcode) {
+ com_err(argv[0], errcode,
+ "while reading block %llu\n", block);
+ goto errout;
+ }
+
+ for (i=0; i < current_fs->blocksize; i += 16) {
+ if (suppress < 0) {
+ if (i && memcmp(buf + i, buf + i - 16, 16) == 0) {
+ suppress = i;
+ printf("*\n");
+ continue;
+ }
+ } else {
+ if (memcmp(buf + i, buf + suppress, 16) == 0)
+ continue;
+ suppress = -1;
+ }
+ printf("%04o ", i);
+ for (j = 0; j < 16; j++) {
+ printf("%02x", buf[i+j]);
+ if ((j % 2) == 1)
+ putchar(' ');
+ }
+ putchar(' ');
+ for (j = 0; j < 16; j++)
+ printf("%c", isprint(buf[i+j]) ? buf[i+j] : '.');
+ putchar('\n');
+ }
+ putchar('\n');
+
+errout:
+ free(buf);
+ return;
+}