summaryrefslogtreecommitdiff
path: root/lib/ext2fs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ext2fs')
-rw-r--r--lib/ext2fs/Makefile.in146
-rw-r--r--lib/ext2fs/alloc.c86
-rw-r--r--lib/ext2fs/alloc_sb.c13
-rw-r--r--lib/ext2fs/alloc_stats.c41
-rw-r--r--lib/ext2fs/alloc_tables.c26
-rw-r--r--lib/ext2fs/bitops.c40
-rw-r--r--lib/ext2fs/bitops.h173
-rw-r--r--lib/ext2fs/blkmap64_ba.c83
-rw-r--r--lib/ext2fs/blkmap64_rb.c331
-rw-r--r--lib/ext2fs/blknum.c7
-rw-r--r--lib/ext2fs/block.c23
-rw-r--r--lib/ext2fs/bmap.c82
-rw-r--r--lib/ext2fs/bmap64.h4
-rw-r--r--lib/ext2fs/brel.h18
-rw-r--r--lib/ext2fs/brel_ma.c24
-rw-r--r--lib/ext2fs/check_desc.c3
-rw-r--r--lib/ext2fs/closefs.c33
-rw-r--r--lib/ext2fs/crc32c.c16
-rw-r--r--lib/ext2fs/csum.c58
-rw-r--r--lib/ext2fs/dblist.c5
-rw-r--r--lib/ext2fs/dir_iterate.c20
-rw-r--r--lib/ext2fs/dupfs.c25
-rw-r--r--lib/ext2fs/e2image.h9
-rw-r--r--lib/ext2fs/expanddir.c2
-rw-r--r--lib/ext2fs/ext2_err.et.in39
-rw-r--r--lib/ext2fs/ext2_fs.h10
-rw-r--r--lib/ext2fs/ext2_io.h3
-rw-r--r--lib/ext2fs/ext2_types.h.in16
-rw-r--r--lib/ext2fs/ext2fs.h156
-rw-r--r--lib/ext2fs/ext2fs.pc.in2
-rw-r--r--lib/ext2fs/ext2fsP.h6
-rw-r--r--lib/ext2fs/extent.c531
-rw-r--r--lib/ext2fs/extent_dbg.ct74
-rw-r--r--lib/ext2fs/fiemap.h2
-rw-r--r--lib/ext2fs/fileio.c105
-rw-r--r--lib/ext2fs/flushb.c2
-rw-r--r--lib/ext2fs/freefs.c2
-rw-r--r--lib/ext2fs/gen_bitmap.c47
-rw-r--r--lib/ext2fs/gen_bitmap64.c138
-rw-r--r--lib/ext2fs/get_pathname.c10
-rw-r--r--lib/ext2fs/getsectsize.c26
-rw-r--r--lib/ext2fs/getsize.c121
-rw-r--r--lib/ext2fs/icount.c26
-rw-r--r--lib/ext2fs/imager.c15
-rw-r--r--lib/ext2fs/initialize.c61
-rw-r--r--lib/ext2fs/inline.c53
-rw-r--r--lib/ext2fs/inode.c14
-rw-r--r--lib/ext2fs/io_manager.c17
-rw-r--r--lib/ext2fs/irel.h2
-rw-r--r--lib/ext2fs/ismounted.c83
-rw-r--r--lib/ext2fs/kernel-jbd.h6
-rw-r--r--lib/ext2fs/kernel-list.h3
-rw-r--r--lib/ext2fs/link.c3
-rw-r--r--lib/ext2fs/llseek.c18
-rw-r--r--lib/ext2fs/mkjournal.c112
-rw-r--r--lib/ext2fs/mmp.c48
-rw-r--r--lib/ext2fs/namei.c9
-rw-r--r--lib/ext2fs/newdir.c8
-rw-r--r--lib/ext2fs/openfs.c91
-rw-r--r--lib/ext2fs/progress.c14
-rw-r--r--lib/ext2fs/punch.c192
-rw-r--r--lib/ext2fs/qcow2.c22
-rw-r--r--lib/ext2fs/rbtree.c4
-rw-r--r--lib/ext2fs/rbtree.h6
-rw-r--r--lib/ext2fs/read_bb_file.c7
-rw-r--r--lib/ext2fs/res_gdt.c13
-rw-r--r--lib/ext2fs/rw_bitmaps.c71
-rw-r--r--lib/ext2fs/sparse.c79
-rw-r--r--lib/ext2fs/swapfs.c8
-rw-r--r--lib/ext2fs/symlink.c150
-rw-r--r--lib/ext2fs/test_io.c134
-rw-r--r--lib/ext2fs/tst_bitmaps.c167
-rw-r--r--lib/ext2fs/tst_bitmaps_cmd.ct12
-rw-r--r--lib/ext2fs/tst_bitmaps_cmds102
-rw-r--r--lib/ext2fs/tst_bitmaps_exp217
-rw-r--r--lib/ext2fs/tst_inode_size.c3
-rw-r--r--lib/ext2fs/tst_iscan.c4
-rw-r--r--lib/ext2fs/tst_super_size.c6
-rw-r--r--lib/ext2fs/undo_io.c55
-rw-r--r--lib/ext2fs/unix_io.c181
80 files changed, 2931 insertions, 1643 deletions
diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index 8840a321..c4a83298 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -79,6 +79,7 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
res_gdt.o \
rw_bitmaps.o \
swapfs.o \
+ symlink.o \
tdb.o \
undo_io.o \
unix_io.o \
@@ -153,6 +154,7 @@ SRCS= ext2_err.c \
$(srcdir)/res_gdt.c \
$(srcdir)/rw_bitmaps.c \
$(srcdir)/swapfs.c \
+ $(srcdir)/symlink.c \
$(srcdir)/tdb.c \
$(srcdir)/test_io.c \
$(srcdir)/tst_badblocks.c \
@@ -180,7 +182,7 @@ ELF_SO_VERSION = 2
ELF_IMAGE = libext2fs
ELF_MYDIR = ext2fs
ELF_INSTALL_DIR = $(root_libdir)
-ELF_OTHER_LIBS = -L../.. -lcom_err
+ELF_OTHER_LIBS = -lcom_err
BSDLIB_VERSION = 2.1
BSDLIB_IMAGE = libext2fs
@@ -198,6 +200,7 @@ all:: ext2fs.pc
.c.o:
$(E) " CC $<"
$(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
+ $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
@PROFILE_CMT@ $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
@CHECKER_CMT@ $(Q) $(CC) $(ALL_CFLAGS) -checker -g -o checker/$*.o -c $<
@ELF_CMT@ $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
@@ -219,90 +222,100 @@ ext2fs.pc: $(srcdir)/ext2fs.pc.in $(top_builddir)/config.status
$(E) " CONFIG.STATUS $@"
$(Q) cd $(top_builddir); CONFIG_FILES=lib/ext2fs/ext2fs.pc ./config.status
-tst_badblocks: tst_badblocks.o $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
+tst_badblocks: tst_badblocks.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
$(E) " LD $@"
- $(Q) $(CC) -o tst_badblocks tst_badblocks.o $(STATIC_LIBEXT2FS) \
- $(LIBCOM_ERR)
+ $(Q) $(CC) -o tst_badblocks tst_badblocks.o $(ALL_LDFLAGS) \
+ $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS)
-tst_icount: $(srcdir)/icount.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
+tst_icount: $(srcdir)/icount.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
$(E) " LD $@"
$(Q) $(CC) -o tst_icount $(srcdir)/icount.c -DDEBUG $(ALL_CFLAGS) \
- $(STATIC_LIBEXT2FS) $(LIBCOM_ERR)
+ $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS)
-tst_iscan: tst_iscan.o $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
+tst_iscan: tst_iscan.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
$(E) " LD $@"
- $(Q) $(CC) -o tst_iscan tst_iscan.o $(STATIC_LIBEXT2FS) $(LIBCOM_ERR)
+ $(Q) $(CC) -o tst_iscan tst_iscan.o $(ALL_LDFLAGS) $(STATIC_LIBEXT2FS) \
+ $(STATIC_LIBCOM_ERR) $(SYSLIBS)
-tst_getsize: tst_getsize.o $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
+tst_getsize: tst_getsize.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
$(E) " LD $@"
$(Q) $(CC) -o tst_getsize tst_getsize.o $(STATIC_LIBEXT2FS) \
- $(LIBCOM_ERR)
+ $(STATIC_LIBCOM_ERR) $(SYSLIBS)
-tst_ismounted: $(srcdir)/ismounted.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
+tst_ismounted: $(srcdir)/ismounted.c $(STATIC_LIBEXT2FS) \
+ $(DEPSTATIC_LIBCOM_ERR)
$(E) " LD $@"
$(Q) $(CC) -o tst_ismounted $(srcdir)/ismounted.c \
$(STATIC_LIBEXT2FS) -DDEBUG $(ALL_CFLAGS) \
- $(LIBCOM_ERR)
+ $(STATIC_LIBCOM_ERR) $(SYSLIBS)
-tst_byteswap: tst_byteswap.o $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
+tst_byteswap: tst_byteswap.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
$(E) " LD $@"
$(Q) $(CC) -o tst_byteswap tst_byteswap.o $(STATIC_LIBEXT2FS) \
- $(LIBCOM_ERR)
+ $(STATIC_LIBCOM_ERR) $(SYSLIBS)
-tst_bitops: tst_bitops.o $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
+tst_bitops: tst_bitops.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
$(E) " LD $@"
$(Q) $(CC) -o tst_bitops tst_bitops.o $(ALL_CFLAGS) \
- $(STATIC_LIBEXT2FS) $(LIBCOM_ERR)
+ $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS)
-tst_getsectsize: tst_getsectsize.o $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
+tst_getsectsize: tst_getsectsize.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
$(E) " LD $@"
$(Q) $(CC) -o tst_sectgetsize tst_getsectsize.o \
- $(STATIC_LIBEXT2FS) $(LIBCOM_ERR)
+ $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS)
tst_types.o: $(srcdir)/tst_types.c ext2_types.h
tst_types: tst_types.o ext2_types.h
$(E) " LD $@"
- $(Q) $(CC) -o tst_types tst_types.o
+ $(Q) $(CC) -o tst_types tst_types.o $(ALL_LDFLAGS) $(SYSLIBS)
tst_super_size.o: $(srcdir)/tst_super_size.c $(srcdir)/ext2_fs.h
tst_super_size: tst_super_size.o
$(E) " LD $@"
- $(Q) $(CC) -o tst_super_size tst_super_size.o
+ $(Q) $(CC) -o tst_super_size tst_super_size.o $(ALL_LDFLAGS) $(SYSLIBS)
tst_fs_struct.o: $(srcdir)/tst_fs_struct.c $(srcdir)/ext2fs.h
tst_fs_struct: tst_fs_struct.o
$(E) " LD $@"
- $(Q) $(CC) -o tst_fs_struct tst_fs_struct.o
+ $(Q) $(CC) -o tst_fs_struct tst_fs_struct.o $(SYSLIBS)
tst_inode_size.o: $(srcdir)/tst_inode_size.c $(srcdir)/ext2_fs.h
tst_inode_size: tst_inode_size.o
$(E) " LD $@"
- $(Q) $(CC) -o tst_inode_size tst_inode_size.o
+ $(Q) $(CC) -o tst_inode_size tst_inode_size.o $(ALL_LDFLAGS) $(SYSLIBS)
ext2_tdbtool: tdbtool.o
$(E) " LD $@"
- $(Q) $(CC) -o ext2_tdbtool tdbtool.o tdb.o
+ $(Q) $(CC) -o ext2_tdbtool tdbtool.o tdb.o $(ALL_LDFLAGS) $(SYSLIBS)
extent_dbg.c: $(srcdir)/extent_dbg.ct
$(E) " MK_CMDS $<"
$(Q) $(MK_CMDS) $(srcdir)/extent_dbg.ct
debug_cmds.c debug_cmds.h: $(top_srcdir)/debugfs/debug_cmds.ct
- $(E) " MK_CMDS $<@"
+ $(E) " MK_CMDS $<"
$(Q) $(MK_CMDS) $(top_srcdir)/debugfs/debug_cmds.ct
+extent_cmds.c extent_cmds.h: $(top_srcdir)/debugfs/extent_cmds.ct
+ $(E) " MK_CMDS $<"
+ $(Q) $(MK_CMDS) $(top_srcdir)/debugfs/extent_cmds.ct
+
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
+ e2freefrag.o filefrag.o extent_inode.o extent_cmds.o zap.o
debugfs.o: $(top_srcdir)/debugfs/debugfs.c
$(E) " CC $<"
$(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
+extent_inode.o: $(top_srcdir)/debugfs/extent_inode.c
+ $(E) " CC $<"
+ $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
+
util.o: $(top_srcdir)/debugfs/util.c
$(E) " CC $<"
$(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
@@ -343,6 +356,10 @@ unused.o: $(top_srcdir)/debugfs/unused.c
$(E) " CC $<"
$(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
+zap.o: $(top_srcdir)/debugfs/zap.c
+ $(E) " CC $<"
+ $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
+
e2freefrag.o: $(top_srcdir)/misc/e2freefrag.c
$(E) " CC $<"
$(Q) $(CC) $(ALL_CFLAGS) -DDEBUGFS -I$(top_srcdir)/debugfs -c $< -o $@
@@ -355,36 +372,47 @@ tst_bitmaps_cmd.c: tst_bitmaps_cmd.ct
$(E) " MK_CMDS $@"
$(Q) DIR=$(srcdir) $(MK_CMDS) $(srcdir)/tst_bitmaps_cmd.ct
-tst_bitmaps: tst_bitmaps.o tst_bitmaps_cmd.o $(STATIC_LIBEXT2FS) $(DEPLIBSS) \
- $(DEPLIBCOM_ERR)
+tst_bitmaps: tst_bitmaps.o tst_bitmaps_cmd.o $(srcdir)/blkmap64_rb.c \
+ $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBSS) $(DEPSTATIC_LIBCOM_ERR)
+ $(E) " LD $@"
+ $(Q) $(CC) -o $@ tst_bitmaps.o tst_bitmaps_cmd.o \
+ -DDEBUG_RB $(srcdir)/blkmap64_rb.c $(ALL_CFLAGS) \
+ $(STATIC_LIBEXT2FS) $(STATIC_LIBSS) $(STATIC_LIBCOM_ERR) \
+ $(SYSLIBS)
+
+tst_extents: $(srcdir)/extent.c $(DEBUG_OBJS) $(DEPSTATIC_LIBSS) \
+ $(STATIC_LIBE2P) $(DEPLIBUUID) $(DEPLIBBLKID) $(DEPSTATIC_LIBCOM_ERR)
$(E) " LD $@"
- $(Q) $(CC) -o $@ tst_bitmaps.o tst_bitmaps_cmd.o $(ALL_CFLAGS) \
- $(STATIC_LIBEXT2FS) $(LIBSS) $(LIBCOM_ERR)
+ $(Q) $(CC) -o tst_extents $(srcdir)/extent.c \
+ $(ALL_CFLAGS) -DDEBUG $(DEBUG_OBJS) $(STATIC_LIBSS) \
+ $(STATIC_LIBE2P) $(STATIC_LIBEXT2FS) $(LIBBLKID) $(LIBUUID) \
+ $(STATIC_LIBCOM_ERR) $(SYSLIBS) -I $(top_srcdir)/debugfs
-tst_extents: $(srcdir)/extent.c extent_dbg.c $(DEBUG_OBJS) $(DEPLIBSS) \
- $(LIBE2P) $(DEPLIBUUID) $(DEPLIBBLKID) $(DEPLIBCOM_ERR)
+tst_inline: $(srcdir)/inline.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
$(E) " LD $@"
- $(Q) $(CC) -o tst_extents $(srcdir)/extent.c extent_dbg.c \
- $(ALL_CFLAGS) -DDEBUG $(DEBUG_OBJS) $(LIBSS) $(LIBE2P) \
- $(STATIC_LIBEXT2FS) $(LIBBLKID) $(LIBUUID) $(LIBCOM_ERR) \
- -I $(top_srcdir)/debugfs
+ $(Q) $(CC) -o tst_inline $(srcdir)/inline.c $(ALL_CFLAGS) -DDEBUG \
+ $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS)
-tst_csum: csum.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR) \
+tst_csum: csum.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) $(STATIC_LIBE2P) \
$(top_srcdir)/lib/e2p/e2p.h
$(E) " LD $@"
$(Q) $(CC) -o tst_csum $(srcdir)/csum.c -DDEBUG \
- $(ALL_CFLAGS) $(STATIC_LIBEXT2FS) $(LIBCOM_ERR) $(LIBE2P)
+ $(ALL_CFLAGS) $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) \
+ $(STATIC_LIBE2P) $(SYSLIBS)
-tst_crc32c: $(srcdir)/crc32c.c
+tst_crc32c: $(srcdir)/crc32c.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
$(Q) $(CC) $(BUILD_LDFLAGS) $(ALL_CFLAGS) -o tst_crc32c $(srcdir)/crc32c.c \
- -DUNITTEST
+ -DUNITTEST $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) \
+ $(SYSLIBS)
mkjournal: mkjournal.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
$(E) " LD $@"
- $(Q) $(CC) -o mkjournal $(srcdir)/mkjournal.c -DDEBUG $(STATIC_LIBEXT2FS) $(LIBCOM_ERR) $(ALL_CFLAGS)
+ $(Q) $(CC) -o mkjournal $(srcdir)/mkjournal.c -DDEBUG \
+ $(STATIC_LIBEXT2FS) $(LIBCOM_ERR) $(ALL_CFLAGS) $(SYSLIBS)
check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \
- tst_super_size tst_types tst_inode_size tst_csum tst_crc32c tst_bitmaps
+ tst_super_size tst_types tst_inode_size tst_csum tst_crc32c tst_bitmaps \
+ tst_inline
LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_bitops
LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_badblocks
LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_iscan
@@ -393,6 +421,7 @@ check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \
LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_super_size
LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_inode_size
LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_csum
+ LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_inline
LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_crc32c
LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) \
./tst_bitmaps -f $(srcdir)/tst_bitmaps_cmds > tst_bitmaps_out
@@ -403,11 +432,14 @@ check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \
LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) \
./tst_bitmaps -t 3 -f $(srcdir)/tst_bitmaps_cmds > tst_bitmaps_out
diff $(srcdir)/tst_bitmaps_exp tst_bitmaps_out
+ LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) \
+ ./tst_bitmaps -l -f $(srcdir)/tst_bitmaps_cmds > tst_bitmaps_out
+ diff $(srcdir)/tst_bitmaps_exp tst_bitmaps_out
installdirs::
$(E) " MKINSTALLDIRS $(libdir) $(includedir)/ext2fs"
$(Q) $(MKINSTALLDIRS) $(DESTDIR)$(libdir) \
- $(DESTDIR)$(includedir)/ext2fs $(DESTDIR)$(libdir)/pkgconfig
+ $(DESTDIR)$(includedir)/ext2fs $(DESTDIR)$(pkgconfigdir)
install:: all $(HFILES) $(HFILES_IN) installdirs ext2fs.pc
$(E) " INSTALL_DATA $(libdir)/libext2fs.a"
@@ -422,12 +454,12 @@ install:: all $(HFILES) $(HFILES_IN) installdirs ext2fs.pc
echo " INSTALL_DATA $(includedir)/ext2fs/$$i"; \
$(INSTALL_DATA) $$i $(DESTDIR)$(includedir)/ext2fs/$$i; \
done
- $(E) " INSTALL_DATA $(libdir)/pkgconfig/ext2fs.pc"
- $(Q) $(INSTALL_DATA) ext2fs.pc $(DESTDIR)$(libdir)/pkgconfig/ext2fs.pc
+ $(E) " INSTALL_DATA $(pkgconfigdir)/ext2fs.pc"
+ $(Q) $(INSTALL_DATA) ext2fs.pc $(DESTDIR)$(pkgconfigdir)/ext2fs.pc
uninstall::
$(RM) -f $(DESTDIR)$(libdir)/libext2fs.a \
- $(DESTDIR)$(libdir)/pkgconfig/ext2fs.pc
+ $(DESTDIR)$(pkgconfigdir)/ext2fs.pc
$(RM) -rf $(DESTDIR)$(includedir)/ext2fs
clean::
@@ -435,8 +467,9 @@ clean::
tst_badblocks tst_iscan ext2_err.et ext2_err.c ext2_err.h \
tst_byteswap tst_ismounted tst_getsize tst_sectgetsize \
tst_bitops tst_types tst_icount tst_super_size tst_csum \
- tst_bitmaps tst_bitmaps_out tst_bitmaps_cmd.c \
- ext2_tdbtool mkjournal debug_cmds.c \
+ tst_bitmaps tst_bitmaps_out tst_extents tst_inline \
+ tst_inline_data tst_inode_size tst_bitmaps_cmd.c \
+ ext2_tdbtool mkjournal debug_cmds.c extent_cmds.c \
../libext2fs.a ../libext2fs_p.a ../libext2fs_chk.a \
crc32c_table.h gen_crc32ctable tst_crc32c
@@ -453,7 +486,7 @@ $(OBJS): subdirs
gen_crc32ctable: $(srcdir)/gen_crc32ctable.c
$(E) " CC $@"
- $(Q) $(BUILD_CC) $(BUILD_CFLAGS) -o gen_crc32ctable \
+ $(Q) $(BUILD_CC) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o gen_crc32ctable \
$(srcdir)/gen_crc32ctable.c
crc32c_table.h: gen_crc32ctable
@@ -544,10 +577,11 @@ block.o: $(srcdir)/block.c $(top_builddir)/lib/config.h \
$(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
bmap.o: $(srcdir)/bmap.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
- $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
- $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
- $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
- $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
+ $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h
check_desc.o: $(srcdir)/check_desc.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
@@ -642,7 +676,7 @@ fileio.o: $(srcdir)/fileio.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
$(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
$(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
- $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/ext2fsP.h
finddev.o: $(srcdir)/finddev.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
@@ -862,6 +896,12 @@ swapfs.o: $(srcdir)/swapfs.c $(top_builddir)/lib/config.h \
$(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
$(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
$(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
+symlink.o: $(srcdir)/symlink.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
+ $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h
tdb.o: $(srcdir)/tdb.c $(top_builddir)/lib/config.h \
$(top_builddir)/lib/dirpaths.h $(srcdir)/tdb.h
test_io.o: $(srcdir)/test_io.c $(top_builddir)/lib/config.h \
diff --git a/lib/ext2fs/alloc.c b/lib/ext2fs/alloc.c
index 775dfcc4..0acbc4e6 100644
--- a/lib/ext2fs/alloc.c
+++ b/lib/ext2fs/alloc.c
@@ -27,50 +27,17 @@
#include "ext2fs.h"
/*
- * Check for uninit block bitmaps and deal with them appropriately
+ * Clear the uninit block bitmap flag if necessary
*/
-static void check_block_uninit(ext2_filsys fs, ext2fs_block_bitmap map,
- dgrp_t group)
+static void clear_block_uninit(ext2_filsys fs, dgrp_t group)
{
- blk_t i;
- blk64_t blk, super_blk, old_desc_blk, new_desc_blk;
- int old_desc_blocks;
-
if (!(EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) ||
!(ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)))
return;
- blk = (group * fs->super->s_blocks_per_group) +
- fs->super->s_first_data_block;
-
- ext2fs_super_and_bgd_loc2(fs, group, &super_blk,
- &old_desc_blk, &new_desc_blk, 0);
-
- if (fs->super->s_feature_incompat &
- EXT2_FEATURE_INCOMPAT_META_BG)
- old_desc_blocks = fs->super->s_first_meta_bg;
- else
- old_desc_blocks = fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
-
- for (i=0; i < fs->super->s_blocks_per_group; i++, blk++)
- ext2fs_fast_unmark_block_bitmap2(map, blk);
-
- blk = (group * fs->super->s_blocks_per_group) +
- fs->super->s_first_data_block;
- for (i=0; i < fs->super->s_blocks_per_group; i++, blk++) {
- if ((blk == super_blk) ||
- (old_desc_blk && old_desc_blocks &&
- (blk >= old_desc_blk) &&
- (blk < old_desc_blk + old_desc_blocks)) ||
- (new_desc_blk && (blk == new_desc_blk)) ||
- (blk == ext2fs_block_bitmap_loc(fs, group)) ||
- (blk == ext2fs_inode_bitmap_loc(fs, group)) ||
- (blk >= ext2fs_inode_table_loc(fs, group) &&
- (blk < ext2fs_inode_table_loc(fs, group)
- + fs->inode_blocks_per_group)))
- ext2fs_fast_mark_block_bitmap2(map, blk);
- }
+ /* uninit block bitmaps are now initialized in read_bitmaps() */
+
ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
ext2fs_group_desc_csum_set(fs, group);
ext2fs_mark_super_dirty(fs);
@@ -95,10 +62,11 @@ static void check_inode_uninit(ext2_filsys fs, ext2fs_inode_bitmap map,
ext2fs_fast_unmark_inode_bitmap2(map, ino);
ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
+ /* Mimics what the kernel does */
+ ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
ext2fs_group_desc_csum_set(fs, group);
ext2fs_mark_ib_dirty(fs);
ext2fs_mark_super_dirty(fs);
- check_block_uninit(fs, fs->block_map, group);
}
/*
@@ -169,8 +137,8 @@ errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal,
ext2fs_block_bitmap map, blk64_t *ret)
{
- blk64_t i;
- int c_ratio;
+ errcode_t retval;
+ blk64_t b = 0;
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
@@ -180,29 +148,21 @@ errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal,
return EXT2_ET_NO_BLOCK_BITMAP;
if (!goal || (goal >= ext2fs_blocks_count(fs->super)))
goal = fs->super->s_first_data_block;
- i = goal;
- c_ratio = 1 << ext2fs_get_bitmap_granularity(map);
- if (c_ratio > 1)
- goal &= ~EXT2FS_CLUSTER_MASK(fs);
- check_block_uninit(fs, map,
- (i - fs->super->s_first_data_block) /
- EXT2_BLOCKS_PER_GROUP(fs->super));
- do {
- if (((i - fs->super->s_first_data_block) %
- EXT2_BLOCKS_PER_GROUP(fs->super)) == 0)
- check_block_uninit(fs, map,
- (i - fs->super->s_first_data_block) /
- EXT2_BLOCKS_PER_GROUP(fs->super));
-
- if (!ext2fs_fast_test_block_bitmap2(map, i)) {
- *ret = i;
- return 0;
- }
- i = (i + c_ratio) & ~(c_ratio - 1);
- if (i >= ext2fs_blocks_count(fs->super))
- i = fs->super->s_first_data_block;
- } while (i != goal);
- return EXT2_ET_BLOCK_ALLOC_FAIL;
+ goal &= ~EXT2FS_CLUSTER_MASK(fs);
+
+ retval = ext2fs_find_first_zero_block_bitmap2(map,
+ goal, ext2fs_blocks_count(fs->super) - 1, &b);
+ if ((retval == ENOENT) && (goal != fs->super->s_first_data_block))
+ retval = ext2fs_find_first_zero_block_bitmap2(map,
+ fs->super->s_first_data_block, goal - 1, &b);
+ if (retval == ENOENT)
+ return EXT2_ET_BLOCK_ALLOC_FAIL;
+ if (retval)
+ return retval;
+
+ clear_block_uninit(fs, ext2fs_group_of_blk2(fs, b));
+ *ret = b;
+ return 0;
}
errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
diff --git a/lib/ext2fs/alloc_sb.c b/lib/ext2fs/alloc_sb.c
index 0d1c0000..8788c009 100644
--- a/lib/ext2fs/alloc_sb.c
+++ b/lib/ext2fs/alloc_sb.c
@@ -47,7 +47,7 @@ int ext2fs_reserve_super_and_bgd(ext2_filsys fs,
{
blk64_t super_blk, old_desc_blk, new_desc_blk;
blk_t used_blks;
- int j, old_desc_blocks, num_blocks;
+ int old_desc_blocks, num_blocks;
ext2fs_super_and_bgd_loc2(fs, group, &super_blk,
&old_desc_blk, &new_desc_blk, &used_blks);
@@ -65,12 +65,11 @@ int ext2fs_reserve_super_and_bgd(ext2_filsys fs,
ext2fs_mark_block_bitmap2(bmap, 0);
if (old_desc_blk) {
- if (fs->super->s_reserved_gdt_blocks && fs->block_map == bmap)
- ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
- for (j=0; j < old_desc_blocks; j++)
- if (old_desc_blk + j < ext2fs_blocks_count(fs->super))
- ext2fs_mark_block_bitmap2(bmap,
- old_desc_blk + j);
+ num_blocks = old_desc_blocks;
+ if (old_desc_blk + num_blocks >= ext2fs_blocks_count(fs->super))
+ num_blocks = ext2fs_blocks_count(fs->super) -
+ old_desc_blk;
+ ext2fs_mark_block_bitmap_range2(bmap, old_desc_blk, num_blocks);
}
if (new_desc_blk)
ext2fs_mark_block_bitmap2(bmap, new_desc_blk);
diff --git a/lib/ext2fs/alloc_stats.c b/lib/ext2fs/alloc_stats.c
index adec3636..1f58e001 100644
--- a/lib/ext2fs/alloc_stats.c
+++ b/lib/ext2fs/alloc_stats.c
@@ -106,3 +106,44 @@ void ext2fs_set_block_alloc_stats_callback(ext2_filsys fs,
fs->block_alloc_stats = func;
}
+
+void ext2fs_block_alloc_stats_range(ext2_filsys fs, blk64_t blk,
+ blk_t num, int inuse)
+{
+#ifndef OMIT_COM_ERR
+ if (blk + num > ext2fs_blocks_count(fs->super)) {
+ com_err("ext2fs_block_alloc_stats_range", 0,
+ "Illegal block range: %llu (%u) ",
+ (unsigned long long) blk, num);
+ return;
+ }
+#endif
+ if (inuse == 0)
+ return;
+ if (inuse > 0) {
+ ext2fs_mark_block_bitmap_range2(fs->block_map, blk, num);
+ inuse = 1;
+ } else {
+ ext2fs_unmark_block_bitmap_range2(fs->block_map, blk, num);
+ inuse = -1;
+ }
+ while (num) {
+ int group = ext2fs_group_of_blk2(fs, blk);
+ blk64_t last_blk = ext2fs_group_last_block2(fs, group);
+ blk_t n = num;
+
+ if (blk + num > last_blk)
+ n = last_blk - blk + 1;
+
+ ext2fs_bg_free_blocks_count_set(fs, group,
+ ext2fs_bg_free_blocks_count(fs, group) -
+ inuse*n/EXT2FS_CLUSTER_RATIO(fs));
+ ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
+ ext2fs_group_desc_csum_set(fs, group);
+ ext2fs_free_blocks_count_add(fs->super, -inuse * n);
+ blk += n;
+ num -= n;
+ }
+ ext2fs_mark_super_dirty(fs);
+ ext2fs_mark_bb_dirty(fs);
+}
diff --git a/lib/ext2fs/alloc_tables.c b/lib/ext2fs/alloc_tables.c
index 9f3d4e04..bc99943c 100644
--- a/lib/ext2fs/alloc_tables.c
+++ b/lib/ext2fs/alloc_tables.c
@@ -54,8 +54,8 @@ static blk64_t flexbg_offset(ext2_filsys fs, dgrp_t group, blk64_t start_blk,
* Don't do a long search if the previous block
* search is still valid.
*/
- if (start_blk && ext2fs_test_block_bitmap_range2(bmap, start_blk,
- elem_size))
+ if (start_blk && start_blk < ext2fs_blocks_count(fs->super) &&
+ ext2fs_test_block_bitmap_range2(bmap, start_blk, elem_size))
return start_blk;
start_blk = ext2fs_group_first_block2(fs, flexbg_size * flexbg);
@@ -83,9 +83,8 @@ static blk64_t flexbg_offset(ext2_filsys fs, dgrp_t group, blk64_t start_blk,
errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
ext2fs_block_bitmap bmap)
{
- unsigned int j;
errcode_t retval;
- blk64_t group_blk, start_blk, last_blk, new_blk, blk;
+ blk64_t group_blk, start_blk, last_blk, new_blk;
dgrp_t last_grp = 0;
int rem_grps = 0, flexbg_size = 0;
@@ -205,19 +204,12 @@ errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
bmap, &new_blk);
if (retval)
return retval;
- for (j=0, blk = new_blk;
- j < fs->inode_blocks_per_group;
- j++, blk++) {
- ext2fs_mark_block_bitmap2(bmap, blk);
- if (flexbg_size) {
- dgrp_t gr = ext2fs_group_of_blk2(fs, blk);
- ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1);
- ext2fs_free_blocks_count_add(fs->super, -1);
- ext2fs_bg_flags_clear(fs, gr,
- EXT2_BG_BLOCK_UNINIT);
- ext2fs_group_desc_csum_set(fs, gr);
- }
- }
+ if (flexbg_size)
+ ext2fs_block_alloc_stats_range(fs, new_blk,
+ fs->inode_blocks_per_group, +1);
+ else
+ ext2fs_mark_block_bitmap_range2(fs->block_map,
+ new_blk, fs->inode_blocks_per_group);
ext2fs_inode_table_loc_set(fs, group, new_blk);
}
ext2fs_group_desc_csum_set(fs, group);
diff --git a/lib/ext2fs/bitops.c b/lib/ext2fs/bitops.c
index 9322a353..8e4c05c4 100644
--- a/lib/ext2fs/bitops.c
+++ b/lib/ext2fs/bitops.c
@@ -116,3 +116,43 @@ int ext2fs_test_bit64(__u64 nr, const void * addr)
return (mask & *ADDR);
}
+static unsigned int popcount8(unsigned int w)
+{
+ unsigned int res = w - ((w >> 1) & 0x55);
+ res = (res & 0x33) + ((res >> 2) & 0x33);
+ return (res + (res >> 4)) & 0x0F;
+}
+
+static unsigned int popcount32(unsigned int w)
+{
+ unsigned int res = w - ((w >> 1) & 0x55555555);
+ res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
+ res = (res + (res >> 4)) & 0x0F0F0F0F;
+ res = res + (res >> 8);
+ return (res + (res >> 16)) & 0x000000FF;
+}
+
+unsigned int ext2fs_bitcount(const void *addr, unsigned int nbytes)
+{
+ const unsigned char *cp = addr;
+ const __u32 *p;
+ unsigned int res = 0;
+
+ while (((((unsigned long) cp) & 3) != 0) && (nbytes > 0)) {
+ res += popcount8(*cp++);
+ nbytes--;
+ }
+ p = (const __u32 *) cp;
+
+ while (nbytes > 4) {
+ res += popcount32(*p++);
+ nbytes -= 4;
+ }
+ cp = (const unsigned char *) p;
+
+ while (nbytes > 0) {
+ res += popcount8(*cp++);
+ nbytes--;
+ }
+ return res;
+}
diff --git a/lib/ext2fs/bitops.h b/lib/ext2fs/bitops.h
index 93827907..4fb7dc6e 100644
--- a/lib/ext2fs/bitops.h
+++ b/lib/ext2fs/bitops.h
@@ -10,20 +10,6 @@
* %End-Header%
*/
-extern int ext2fs_set_bit(unsigned int nr,void * addr);
-extern int ext2fs_clear_bit(unsigned int nr, void * addr);
-extern int ext2fs_test_bit(unsigned int nr, const void * addr);
-extern void ext2fs_fast_set_bit(unsigned int nr,void * addr);
-extern void ext2fs_fast_clear_bit(unsigned int nr, void * addr);
-extern int ext2fs_set_bit64(__u64 nr,void * addr);
-extern int ext2fs_clear_bit64(__u64 nr, void * addr);
-extern int ext2fs_test_bit64(__u64 nr, const void * addr);
-extern void ext2fs_fast_set_bit64(__u64 nr,void * addr);
-extern void ext2fs_fast_clear_bit64(__u64 nr, void * addr);
-extern __u16 ext2fs_swab16(__u16 val);
-extern __u32 ext2fs_swab32(__u32 val);
-extern __u64 ext2fs_swab64(__u64 val);
-
#ifdef WORDS_BIGENDIAN
#define ext2fs_cpu_to_le64(x) ext2fs_swab64((x))
#define ext2fs_le64_to_cpu(x) ext2fs_swab64((x))
@@ -67,6 +53,15 @@ extern void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
extern void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
int code, unsigned long arg);
+#ifdef NO_INLINE_FUNCS
+extern void ext2fs_fast_set_bit(unsigned int nr,void * addr);
+extern void ext2fs_fast_clear_bit(unsigned int nr, void * addr);
+extern void ext2fs_fast_set_bit64(__u64 nr,void * addr);
+extern void ext2fs_fast_clear_bit64(__u64 nr, void * addr);
+extern __u16 ext2fs_swab16(__u16 val);
+extern __u32 ext2fs_swab32(__u32 val);
+extern __u64 ext2fs_swab64(__u64 val);
+
extern int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
extern int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
blk_t block);
@@ -95,6 +90,15 @@ extern ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap);
extern blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap);
extern ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap);
+extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num);
+extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num);
+extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
+ blk_t block, int num);
+#endif
+
+/* These functions routines moved to gen_bitmap.c */
extern void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num);
extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
@@ -103,15 +107,6 @@ extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num);
extern int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap bitmap,
ino_t inode, int num);
-extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
- blk_t block, int num);
-extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
- blk_t block, int num);
-extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
- blk_t block, int num);
-extern void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map);
-
-/* These routines moved to gen_bitmap.c (actually, some of the above, too) */
extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
__u32 bitno);
extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
@@ -120,11 +115,13 @@ extern int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
blk_t bitno);
extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num);
+extern void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map);
extern __u32 ext2fs_get_generic_bitmap_start(ext2fs_generic_bitmap bitmap);
extern __u32 ext2fs_get_generic_bitmap_end(ext2fs_generic_bitmap bitmap);
/* 64-bit versions */
+#ifdef NO_INLINE_FUNCS
extern int ext2fs_mark_block_bitmap2(ext2fs_block_bitmap bitmap,
blk64_t block);
extern int ext2fs_unmark_block_bitmap2(ext2fs_block_bitmap bitmap,
@@ -153,10 +150,18 @@ extern void ext2fs_fast_unmark_inode_bitmap2(ext2fs_inode_bitmap bitmap,
extern int ext2fs_fast_test_inode_bitmap2(ext2fs_inode_bitmap bitmap,
ext2_ino_t inode);
extern errcode_t ext2fs_find_first_zero_block_bitmap2(ext2fs_block_bitmap bitmap,
+ blk64_t start,
+ blk64_t end,
+ blk64_t *out);
+extern errcode_t ext2fs_find_first_zero_inode_bitmap2(ext2fs_inode_bitmap bitmap,
ext2_ino_t start,
ext2_ino_t end,
ext2_ino_t *out);
-extern errcode_t ext2fs_find_first_zero_inode_bitmap2(ext2fs_inode_bitmap bitmap,
+extern errcode_t ext2fs_find_first_set_block_bitmap2(ext2fs_block_bitmap bitmap,
+ blk64_t start,
+ blk64_t end,
+ blk64_t *out);
+extern errcode_t ext2fs_find_first_set_inode_bitmap2(ext2fs_inode_bitmap bitmap,
ext2_ino_t start,
ext2_ino_t end,
ext2_ino_t *out);
@@ -174,6 +179,8 @@ extern void ext2fs_fast_mark_block_bitmap_range2(ext2fs_block_bitmap bitmap,
extern void ext2fs_fast_unmark_block_bitmap_range2(ext2fs_block_bitmap bitmap,
blk64_t block,
unsigned int num);
+#endif
+
/* These routines moved to gen_bitmap64.c */
extern void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap);
extern errcode_t ext2fs_compare_generic_bmap(errcode_t neq,
@@ -199,6 +206,9 @@ extern void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bitmap,
extern errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap,
__u64 start, __u64 end,
__u64 *out);
+extern errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap,
+ __u64 start, __u64 end,
+ __u64 *out);
/*
* The inline routines themselves...
@@ -209,7 +219,7 @@ extern errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitma
*/
#ifdef NO_INLINE_FUNCS
#if (defined(__GNUC__) && (defined(__i386__) || defined(__i486__) || \
- defined(__i586__) || defined(__mc68000__)))
+ defined(__i586__)))
/* This prevents bitops.c from trying to include the C */
/* function version of these functions */
#define _EXT2_HAVE_ASM_BITOPS_
@@ -218,14 +228,22 @@ extern errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitma
#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
#ifdef INCLUDE_INLINE_FUNCS
-#define _INLINE_ extern
+#if (__STDC_VERSION__ >= 199901L)
+#define _INLINE_ extern inline
#else
+#define _INLINE_ inline
+#endif
+#else /* !INCLUDE_INLINE FUNCS */
+#if (__STDC_VERSION__ >= 199901L)
+#define _INLINE_ inline
+#else /* not C99 */
#ifdef __GNUC__
#define _INLINE_ extern __inline__
#else /* For Watcom C */
#define _INLINE_ extern inline
-#endif
-#endif
+#endif /* __GNUC__ */
+#endif /* __STDC_VERSION__ >= 199901L */
+#endif /* INCLUDE_INLINE_FUNCS */
/*
* Fast bit set/clear functions that doesn't need to return the
@@ -237,7 +255,7 @@ _INLINE_ void ext2fs_fast_set_bit(unsigned int nr,void * addr)
unsigned char *ADDR = (unsigned char *) addr;
ADDR += nr >> 3;
- *ADDR |= (1 << (nr & 0x07));
+ *ADDR |= (unsigned char) (1 << (nr & 0x07));
}
_INLINE_ void ext2fs_fast_clear_bit(unsigned int nr, void * addr)
@@ -245,7 +263,7 @@ _INLINE_ void ext2fs_fast_clear_bit(unsigned int nr, void * addr)
unsigned char *ADDR = (unsigned char *) addr;
ADDR += nr >> 3;
- *ADDR &= ~(1 << (nr & 0x07));
+ *ADDR &= (unsigned char) ~(1 << (nr & 0x07));
}
@@ -254,7 +272,7 @@ _INLINE_ void ext2fs_fast_set_bit64(__u64 nr, void * addr)
unsigned char *ADDR = (unsigned char *) addr;
ADDR += nr >> 3;
- *ADDR |= (1 << (nr & 0x07));
+ *ADDR |= (unsigned char) (1 << (nr & 0x07));
}
_INLINE_ void ext2fs_fast_clear_bit64(__u64 nr, void * addr)
@@ -262,7 +280,7 @@ _INLINE_ void ext2fs_fast_clear_bit64(__u64 nr, void * addr)
unsigned char *ADDR = (unsigned char *) addr;
ADDR += nr >> 3;
- *ADDR &= ~(1 << (nr & 0x07));
+ *ADDR &= (unsigned char) ~(1 << (nr & 0x07));
}
@@ -346,49 +364,12 @@ _INLINE_ __u16 ext2fs_swab16(__u16 val)
#endif /* i386 */
-#if ((defined __GNUC__) && !defined(_EXT2_USE_C_VERSIONS_) && \
- (defined(__mc68000__)))
-
-#define _EXT2_HAVE_ASM_BITOPS_
-
-_INLINE_ int ext2fs_set_bit(unsigned int nr,void * addr)
-{
- char retval;
-
- __asm__ __volatile__ ("bfset %2@{%1:#1}; sne %0"
- : "=d" (retval) : "d" (nr^7), "a" (addr));
-
- return retval;
-}
-
-_INLINE_ int ext2fs_clear_bit(unsigned int nr, void * addr)
-{
- char retval;
-
- __asm__ __volatile__ ("bfclr %2@{%1:#1}; sne %0"
- : "=d" (retval) : "d" (nr^7), "a" (addr));
-
- return retval;
-}
-
-_INLINE_ int ext2fs_test_bit(unsigned int nr, const void * addr)
-{
- char retval;
-
- __asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0"
- : "=d" (retval) : "d" (nr^7), "a" (addr));
-
- return retval;
-}
-
-#endif /* __mc68000__ */
-
#if !defined(_EXT2_HAVE_ASM_SWAB_)
_INLINE_ __u16 ext2fs_swab16(__u16 val)
{
- return (val >> 8) | (val << 8);
+ return (val >> 8) | (__u16) (val << 8);
}
_INLINE_ __u32 ext2fs_swab32(__u32 val)
@@ -401,7 +382,7 @@ _INLINE_ __u32 ext2fs_swab32(__u32 val)
_INLINE_ __u64 ext2fs_swab64(__u64 val)
{
- return (ext2fs_swab32(val >> 32) |
+ return (ext2fs_swab32((__u32) (val >> 32)) |
(((__u64)ext2fs_swab32(val & 0xFFFFFFFFUL)) << 32));
}
@@ -605,9 +586,9 @@ _INLINE_ int ext2fs_fast_test_inode_bitmap2(ext2fs_inode_bitmap bitmap,
}
_INLINE_ errcode_t ext2fs_find_first_zero_block_bitmap2(ext2fs_block_bitmap bitmap,
- ext2_ino_t start,
- ext2_ino_t end,
- ext2_ino_t *out)
+ blk64_t start,
+ blk64_t end,
+ blk64_t *out)
{
__u64 o;
errcode_t rv;
@@ -630,10 +611,40 @@ _INLINE_ errcode_t ext2fs_find_first_zero_inode_bitmap2(ext2fs_inode_bitmap bitm
rv = ext2fs_find_first_zero_generic_bmap((ext2fs_generic_bitmap) bitmap,
start, end, &o);
if (!rv)
+ *out = (ext2_ino_t) o;
+ return rv;
+}
+
+_INLINE_ errcode_t ext2fs_find_first_set_block_bitmap2(ext2fs_block_bitmap bitmap,
+ blk64_t start,
+ blk64_t end,
+ blk64_t *out)
+{
+ __u64 o;
+ errcode_t rv;
+
+ rv = ext2fs_find_first_set_generic_bmap((ext2fs_generic_bitmap) bitmap,
+ start, end, &o);
+ if (!rv)
*out = o;
return rv;
}
+_INLINE_ errcode_t ext2fs_find_first_set_inode_bitmap2(ext2fs_inode_bitmap bitmap,
+ ext2_ino_t start,
+ ext2_ino_t end,
+ ext2_ino_t *out)
+{
+ __u64 o;
+ errcode_t rv;
+
+ rv = ext2fs_find_first_set_generic_bmap((ext2fs_generic_bitmap) bitmap,
+ start, end, &o);
+ if (!rv)
+ *out = (ext2_ino_t) o;
+ return rv;
+}
+
_INLINE_ blk64_t ext2fs_get_block_bitmap_start2(ext2fs_block_bitmap bitmap)
{
return ext2fs_get_generic_bmap_start((ext2fs_generic_bitmap) bitmap);
@@ -641,7 +652,7 @@ _INLINE_ blk64_t ext2fs_get_block_bitmap_start2(ext2fs_block_bitmap bitmap)
_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_start2(ext2fs_inode_bitmap bitmap)
{
- return ext2fs_get_generic_bmap_start((ext2fs_generic_bitmap) bitmap);
+ return (ext2_ino_t) ext2fs_get_generic_bmap_start((ext2fs_generic_bitmap) bitmap);
}
_INLINE_ blk64_t ext2fs_get_block_bitmap_end2(ext2fs_block_bitmap bitmap)
@@ -651,7 +662,7 @@ _INLINE_ blk64_t ext2fs_get_block_bitmap_end2(ext2fs_block_bitmap bitmap)
_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_end2(ext2fs_inode_bitmap bitmap)
{
- return ext2fs_get_generic_bmap_end((ext2fs_generic_bitmap) bitmap);
+ return (ext2_ino_t) ext2fs_get_generic_bmap_end((ext2fs_generic_bitmap) bitmap);
}
_INLINE_ int ext2fs_fast_test_block_bitmap_range2(ext2fs_block_bitmap bitmap,
@@ -678,3 +689,13 @@ _INLINE_ void ext2fs_fast_unmark_block_bitmap_range2(ext2fs_block_bitmap bitmap,
#undef _INLINE_
#endif
+#ifndef _EXT2_HAVE_ASM_BITOPS_
+extern int ext2fs_set_bit(unsigned int nr,void * addr);
+extern int ext2fs_clear_bit(unsigned int nr, void * addr);
+extern int ext2fs_test_bit(unsigned int nr, const void * addr);
+#endif
+
+extern int ext2fs_set_bit64(__u64 nr,void * addr);
+extern int ext2fs_clear_bit64(__u64 nr, void * addr);
+extern int ext2fs_test_bit64(__u64 nr, const void * addr);
+extern unsigned int ext2fs_bitcount(const void *addr, unsigned int nbytes);
diff --git a/lib/ext2fs/blkmap64_ba.c b/lib/ext2fs/blkmap64_ba.c
index 8eddde9a..894293a1 100644
--- a/lib/ext2fs/blkmap64_ba.c
+++ b/lib/ext2fs/blkmap64_ba.c
@@ -328,12 +328,6 @@ static errcode_t ba_find_first_zero(ext2fs_generic_bitmap bitmap,
const unsigned char *pos;
unsigned long max_loop_count, i;
- if (start < bitmap->start || end > bitmap->end || start > end)
- return EINVAL;
-
- if (bitmap->cluster_bits)
- return EINVAL;
-
/* scan bits until we hit a byte boundary */
while ((bitpos & 0x7) != 0 && count > 0) {
if (!ext2fs_test_bit64(bitpos, bp->bitarray)) {
@@ -397,6 +391,80 @@ static errcode_t ba_find_first_zero(ext2fs_generic_bitmap bitmap,
return ENOENT;
}
+/* Find the first one bit between start and end, inclusive. */
+static errcode_t ba_find_first_set(ext2fs_generic_bitmap bitmap,
+ __u64 start, __u64 end, __u64 *out)
+{
+ ext2fs_ba_private bp = (ext2fs_ba_private)bitmap->private;
+ unsigned long bitpos = start - bitmap->start;
+ unsigned long count = end - start + 1;
+ int byte_found = 0; /* whether a != 0xff byte has been found */
+ const unsigned char *pos;
+ unsigned long max_loop_count, i;
+
+ /* scan bits until we hit a byte boundary */
+ while ((bitpos & 0x7) != 0 && count > 0) {
+ if (ext2fs_test_bit64(bitpos, bp->bitarray)) {
+ *out = bitpos + bitmap->start;
+ return 0;
+ }
+ bitpos++;
+ count--;
+ }
+
+ if (!count)
+ return ENOENT;
+
+ pos = ((unsigned char *)bp->bitarray) + (bitpos >> 3);
+ /* scan bytes until 8-byte (64-bit) aligned */
+ while (count >= 8 && (((unsigned long)pos) & 0x07)) {
+ if (*pos != 0) {
+ byte_found = 1;
+ break;
+ }
+ pos++;
+ count -= 8;
+ bitpos += 8;
+ }
+
+ if (!byte_found) {
+ max_loop_count = count >> 6; /* 8-byte blocks */
+ i = max_loop_count;
+ while (i) {
+ if (*((const __u64 *)pos) != 0)
+ break;
+ pos += 8;
+ i--;
+ }
+ count -= 64 * (max_loop_count - i);
+ bitpos += 64 * (max_loop_count - i);
+
+ max_loop_count = count >> 3;
+ i = max_loop_count;
+ while (i) {
+ if (*pos != 0) {
+ byte_found = 1;
+ break;
+ }
+ pos++;
+ i--;
+ }
+ count -= 8 * (max_loop_count - i);
+ bitpos += 8 * (max_loop_count - i);
+ }
+
+ /* Here either count < 8 or byte_found == 1. */
+ while (count-- > 0) {
+ if (ext2fs_test_bit64(bitpos, bp->bitarray)) {
+ *out = bitpos + bitmap->start;
+ return 0;
+ }
+ bitpos++;
+ }
+
+ return ENOENT;
+}
+
struct ext2_bitmap_ops ext2fs_blkmap64_bitarray = {
.type = EXT2FS_BMAP64_BITARRAY,
.new_bmap = ba_new_bmap,
@@ -413,5 +481,6 @@ struct ext2_bitmap_ops ext2fs_blkmap64_bitarray = {
.get_bmap_range = ba_get_bmap_range,
.clear_bmap = ba_clear_bmap,
.print_stats = ba_print_stats,
- .find_first_zero = ba_find_first_zero
+ .find_first_zero = ba_find_first_zero,
+ .find_first_set = ba_find_first_set
};
diff --git a/lib/ext2fs/blkmap64_rb.c b/lib/ext2fs/blkmap64_rb.c
index aba7cfd3..4dcb03f9 100644
--- a/lib/ext2fs/blkmap64_rb.c
+++ b/lib/ext2fs/blkmap64_rb.c
@@ -33,19 +33,31 @@
struct bmap_rb_extent {
struct rb_node node;
__u64 start;
- __u32 count;
+ __u64 count;
};
struct ext2fs_rb_private {
struct rb_root root;
- struct bmap_rb_extent **wcursor;
- struct bmap_rb_extent **rcursor;
+ struct bmap_rb_extent *wcursor;
+ struct bmap_rb_extent *rcursor;
+ struct bmap_rb_extent *rcursor_next;
#ifdef BMAP_STATS_OPS
__u64 mark_hit;
__u64 test_hit;
#endif
};
+inline static struct bmap_rb_extent *node_to_extent(struct rb_node *node)
+{
+ /*
+ * This depends on the fact the struct rb_node is at the
+ * beginning of the bmap_rb_extent structure. We use this
+ * instead of the ext2fs_rb_entry macro because it causes gcc
+ * -Wall to generate a huge amount of noise.
+ */
+ return (struct bmap_rb_extent *) node;
+}
+
static int rb_insert_extent(__u64 start, __u64 count,
struct ext2fs_rb_private *);
static void rb_get_new_extent(struct bmap_rb_extent **, __u64, __u64);
@@ -62,30 +74,30 @@ static void print_tree(struct rb_root *root)
node = ext2fs_rb_first(root);
for (node = ext2fs_rb_first(root); node != NULL;
node = ext2fs_rb_next(node)) {
- ext = ext2fs_rb_entry(node, struct bmap_rb_extent, node);
+ ext = node_to_extent(node);
printf("\t\t\t--> (%llu -> %llu)\n",
ext->start, ext->start + ext->count);
}
printf("\t\t\t=================================\n");
}
-static int check_tree(struct rb_root *root, const char *msg)
+static void check_tree(struct rb_root *root, const char *msg)
{
struct rb_node *new_node, *node, *next;
struct bmap_rb_extent *ext, *old = NULL;
for (node = ext2fs_rb_first(root); node;
node = ext2fs_rb_next(node)) {
- ext = ext2fs_rb_entry(node, struct bmap_rb_extent, node);
- if (ext->count <= 0) {
- printf("Tree Error: count is crazy\n");
- printf("extent: %llu -> %llu (%u)\n", ext->start,
+ ext = node_to_extent(node);
+ if (ext->count == 0) {
+ printf("Tree Error: count is zero\n");
+ printf("extent: %llu -> %llu (%llu)\n", ext->start,
ext->start + ext->count, ext->count);
goto err_out;
}
- if (ext->start < 0) {
- printf("Tree Error: start is crazy\n");
- printf("extent: %llu -> %llu (%u)\n", ext->start,
+ if (ext->start + ext->count < ext->start) {
+ printf("Tree Error: start or count is crazy\n");
+ printf("extent: %llu -> %llu (%llu)\n", ext->start,
ext->start + ext->count, ext->count);
goto err_out;
}
@@ -93,20 +105,20 @@ static int check_tree(struct rb_root *root, const char *msg)
if (old) {
if (old->start > ext->start) {
printf("Tree Error: start is crazy\n");
- printf("extent: %llu -> %llu (%u)\n",
+ printf("extent: %llu -> %llu (%llu)\n",
old->start, old->start + old->count,
old->count);
- printf("extent next: %llu -> %llu (%u)\n",
+ printf("extent next: %llu -> %llu (%llu)\n",
ext->start, ext->start + ext->count,
ext->count);
goto err_out;
}
if ((old->start + old->count) >= ext->start) {
printf("Tree Error: extent is crazy\n");
- printf("extent: %llu -> %llu (%u)\n",
+ printf("extent: %llu -> %llu (%llu)\n",
old->start, old->start + old->count,
old->count);
- printf("extent next: %llu -> %llu (%u)\n",
+ printf("extent next: %llu -> %llu (%llu)\n",
ext->start, ext->start + ext->count,
ext->count);
goto err_out;
@@ -114,7 +126,7 @@ static int check_tree(struct rb_root *root, const char *msg)
}
old = ext;
}
- return 0;
+ return;
err_out:
printf("%s\n", msg);
@@ -122,8 +134,8 @@ err_out:
exit(1);
}
#else
-#define check_tree(root, msg) 0
-#define print_tree(root, msg) 0
+#define check_tree(root, msg) do {} while (0)
+#define print_tree(root) do {} while (0)
#endif
static void rb_get_new_extent(struct bmap_rb_extent **ext, __u64 start,
@@ -148,10 +160,12 @@ inline
static void rb_free_extent(struct ext2fs_rb_private *bp,
struct bmap_rb_extent *ext)
{
- if (*bp->wcursor == ext)
- *bp->wcursor = NULL;
- if (*bp->rcursor == ext)
- *bp->rcursor = NULL;
+ if (bp->wcursor == ext)
+ bp->wcursor = NULL;
+ if (bp->rcursor == ext)
+ bp->rcursor = NULL;
+ if (bp->rcursor_next == ext)
+ bp->rcursor_next = NULL;
ext2fs_free_mem(&ext);
}
@@ -165,14 +179,9 @@ static errcode_t rb_alloc_private_data (ext2fs_generic_bitmap bitmap)
return retval;
bp->root = RB_ROOT;
- retval = ext2fs_get_mem(sizeof(struct bmap_rb_extent *), &bp->rcursor);
- if (retval)
- return retval;
- retval = ext2fs_get_mem(sizeof(struct bmap_rb_extent *), &bp->wcursor);
- if (retval)
- return retval;
- *bp->rcursor = NULL;
- *bp->wcursor = NULL;
+ bp->rcursor = NULL;
+ bp->rcursor_next = NULL;
+ bp->wcursor = NULL;
#ifdef BMAP_STATS_OPS
bp->test_hit = 0;
@@ -202,7 +211,7 @@ static void rb_free_tree(struct rb_root *root)
for (node = ext2fs_rb_first(root); node; node = next) {
next = ext2fs_rb_next(node);
- ext = ext2fs_rb_entry(node, struct bmap_rb_extent, node);
+ ext = node_to_extent(node);
ext2fs_rb_erase(node, root);
ext2fs_free_mem(&ext);
}
@@ -215,8 +224,6 @@ static void rb_free_bmap(ext2fs_generic_bitmap bitmap)
bp = (struct ext2fs_rb_private *) bitmap->private;
rb_free_tree(&bp->root);
- ext2fs_free_mem(&bp->rcursor);
- ext2fs_free_mem(&bp->wcursor);
ext2fs_free_mem(&bp);
bp = 0;
}
@@ -235,12 +242,12 @@ static errcode_t rb_copy_bmap(ext2fs_generic_bitmap src,
src_bp = (struct ext2fs_rb_private *) src->private;
dest_bp = (struct ext2fs_rb_private *) dest->private;
- *src_bp->rcursor = NULL;
- *dest_bp->rcursor = NULL;
+ src_bp->rcursor = NULL;
+ dest_bp->rcursor = NULL;
src_node = ext2fs_rb_first(&src_bp->root);
while (src_node) {
- src_ext = ext2fs_rb_entry(src_node, struct bmap_rb_extent, node);
+ src_ext = node_to_extent(src_node);
retval = ext2fs_get_mem(sizeof (struct bmap_rb_extent),
&dest_ext);
if (retval)
@@ -273,7 +280,7 @@ static void rb_truncate(__u64 new_max, struct rb_root *root)
node = ext2fs_rb_last(root);
while (node) {
- ext = ext2fs_rb_entry(node, struct bmap_rb_extent, node);
+ ext = node_to_extent(node);
if ((ext->start + ext->count - 1) <= new_max)
break;
@@ -299,8 +306,8 @@ static errcode_t rb_resize_bmap(ext2fs_generic_bitmap bmap,
}
bp = (struct ext2fs_rb_private *) bmap->private;
- *bp->rcursor = NULL;
- *bp->wcursor = NULL;
+ bp->rcursor = NULL;
+ bp->wcursor = NULL;
/* truncate tree to new_real_end size */
rb_truncate(new_real_end, &bp->root);
@@ -314,13 +321,12 @@ static errcode_t rb_resize_bmap(ext2fs_generic_bitmap bmap,
inline static int
rb_test_bit(struct ext2fs_rb_private *bp, __u64 bit)
{
- struct bmap_rb_extent *rcursor;
- struct rb_node *parent = NULL;
+ struct bmap_rb_extent *rcursor, *next_ext = NULL;
+ struct rb_node *parent = NULL, *next;
struct rb_node **n = &bp->root.rb_node;
struct bmap_rb_extent *ext;
- int i=0;
- rcursor = *bp->rcursor;
+ rcursor = bp->rcursor;
if (!rcursor)
goto search_tree;
@@ -331,7 +337,26 @@ rb_test_bit(struct ext2fs_rb_private *bp, __u64 bit)
return 1;
}
- rcursor = *bp->wcursor;
+ next_ext = bp->rcursor_next;
+ if (!next_ext) {
+ next = ext2fs_rb_next(&rcursor->node);
+ if (next)
+ next_ext = node_to_extent(next);
+ bp->rcursor_next = next_ext;
+ }
+ if (next_ext) {
+ if ((bit >= rcursor->start + rcursor->count) &&
+ (bit < next_ext->start)) {
+#ifdef BMAP_STATS_OPS
+ bp->test_hit++;
+#endif
+ return 0;
+ }
+ }
+ bp->rcursor = NULL;
+ bp->rcursor_next = NULL;
+
+ rcursor = bp->wcursor;
if (!rcursor)
goto search_tree;
@@ -342,13 +367,14 @@ search_tree:
while (*n) {
parent = *n;
- ext = ext2fs_rb_entry(parent, struct bmap_rb_extent, node);
+ ext = node_to_extent(parent);
if (bit < ext->start)
n = &(*n)->rb_left;
else if (bit >= (ext->start + ext->count))
n = &(*n)->rb_right;
else {
- *bp->rcursor = ext;
+ bp->rcursor = ext;
+ bp->rcursor_next = NULL;
return 1;
}
}
@@ -365,7 +391,8 @@ static int rb_insert_extent(__u64 start, __u64 count,
struct bmap_rb_extent *ext;
int retval = 0;
- ext = *bp->wcursor;
+ bp->rcursor_next = NULL;
+ ext = bp->wcursor;
if (ext) {
if (start >= ext->start &&
start <= (ext->start + ext->count)) {
@@ -378,7 +405,7 @@ static int rb_insert_extent(__u64 start, __u64 count,
while (*n) {
parent = *n;
- ext = ext2fs_rb_entry(parent, struct bmap_rb_extent, node);
+ ext = node_to_extent(parent);
if (start < ext->start) {
n = &(*n)->rb_left;
@@ -408,11 +435,11 @@ got_extent:
new_node = &new_ext->node;
ext2fs_rb_link_node(new_node, parent, n);
ext2fs_rb_insert_color(new_node, root);
- *bp->wcursor = new_ext;
+ bp->wcursor = new_ext;
node = ext2fs_rb_prev(new_node);
if (node) {
- ext = ext2fs_rb_entry(node, struct bmap_rb_extent, node);
+ ext = node_to_extent(node);
if ((ext->start + ext->count) == start) {
start = ext->start;
count += ext->count;
@@ -425,7 +452,7 @@ skip_insert:
/* See if we can merge extent to the right */
for (node = ext2fs_rb_next(new_node); node != NULL; node = next) {
next = ext2fs_rb_next(node);
- ext = ext2fs_rb_entry(node, struct bmap_rb_extent, node);
+ ext = node_to_extent(node);
if ((ext->start + ext->count) <= start)
continue;
@@ -470,7 +497,7 @@ static int rb_remove_extent(__u64 start, __u64 count,
while (*n) {
parent = *n;
- ext = ext2fs_rb_entry(parent, struct bmap_rb_extent, node);
+ ext = node_to_extent(parent);
if (start < ext->start) {
n = &(*n)->rb_left;
continue;
@@ -513,7 +540,7 @@ static int rb_remove_extent(__u64 start, __u64 count,
/* See if we should delete or truncate extent on the right */
for (; parent != NULL; parent = node) {
node = ext2fs_rb_next(parent);
- ext = ext2fs_rb_entry(parent, struct bmap_rb_extent, node);
+ ext = node_to_extent(parent);
if ((ext->start + ext->count) <= start)
continue;
@@ -542,13 +569,14 @@ static int rb_remove_extent(__u64 start, __u64 count,
static int rb_mark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg)
{
struct ext2fs_rb_private *bp;
- int i;
-
+ int retval;
bp = (struct ext2fs_rb_private *) bitmap->private;
arg -= bitmap->start;
- return rb_insert_extent(arg, 1, bp);
+ retval = rb_insert_extent(arg, 1, bp);
+ check_tree(&bp->root, __func__);
+ return retval;
}
static int rb_unmark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg)
@@ -580,19 +608,18 @@ static void rb_mark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg,
unsigned int num)
{
struct ext2fs_rb_private *bp;
- struct bmap_rb_extent *new_ext;
bp = (struct ext2fs_rb_private *) bitmap->private;
arg -= bitmap->start;
rb_insert_extent(arg, num, bp);
+ check_tree(&bp->root, __func__);
}
static void rb_unmark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg,
unsigned int num)
{
struct ext2fs_rb_private *bp;
- int ret;
bp = (struct ext2fs_rb_private *) bitmap->private;
arg -= bitmap->start;
@@ -624,7 +651,7 @@ static int rb_test_clear_bmap_extent(ext2fs_generic_bitmap bitmap,
*/
while (*n) {
parent = *n;
- ext = ext2fs_rb_entry(parent, struct bmap_rb_extent, node);
+ ext = node_to_extent(parent);
if (start < ext->start) {
n = &(*n)->rb_left;
} else if (start >= (ext->start + ext->count)) {
@@ -641,7 +668,7 @@ static int rb_test_clear_bmap_extent(ext2fs_generic_bitmap bitmap,
node = parent;
while (node) {
next = ext2fs_rb_next(node);
- ext = ext2fs_rb_entry(node, struct bmap_rb_extent, node);
+ ext = node_to_extent(node);
node = next;
if ((ext->start + ext->count) <= start)
@@ -661,15 +688,43 @@ static errcode_t rb_set_bmap_range(ext2fs_generic_bitmap bitmap,
__u64 start, size_t num, void *in)
{
struct ext2fs_rb_private *bp;
+ unsigned char *cp = in;
size_t i;
- int ret;
+ int first_set = -1;
bp = (struct ext2fs_rb_private *) bitmap->private;
for (i = 0; i < num; i++) {
- ret = ext2fs_test_bit(i, in);
- if (ret)
- rb_insert_extent(start + i - bitmap->start, 1, bp);
+ if ((i & 7) == 0) {
+ unsigned char c = cp[i/8];
+ if (c == 0xFF) {
+ if (first_set == -1)
+ first_set = i;
+ i += 7;
+ continue;
+ }
+ if ((c == 0x00) && (first_set == -1)) {
+ i += 7;
+ continue;
+ }
+ }
+ if (ext2fs_test_bit(i, in)) {
+ if (first_set == -1)
+ first_set = i;
+ continue;
+ }
+ if (first_set == -1)
+ continue;
+
+ rb_insert_extent(start + first_set - bitmap->start,
+ i - first_set, bp);
+ check_tree(&bp->root, __func__);
+ first_set = -1;
+ }
+ if (first_set != -1) {
+ rb_insert_extent(start + first_set - bitmap->start,
+ num - first_set, bp);
+ check_tree(&bp->root, __func__);
}
return 0;
@@ -682,6 +737,7 @@ static errcode_t rb_get_bmap_range(ext2fs_generic_bitmap bitmap,
struct rb_node *parent = NULL, *next, **n;
struct ext2fs_rb_private *bp;
struct bmap_rb_extent *ext;
+ int count;
__u64 pos;
bp = (struct ext2fs_rb_private *) bitmap->private;
@@ -693,7 +749,7 @@ static errcode_t rb_get_bmap_range(ext2fs_generic_bitmap bitmap,
while (*n) {
parent = *n;
- ext = ext2fs_rb_entry(parent, struct bmap_rb_extent, node);
+ ext = node_to_extent(parent);
if (start < ext->start) {
n = &(*n)->rb_left;
} else if (start >= (ext->start + ext->count)) {
@@ -702,44 +758,139 @@ static errcode_t rb_get_bmap_range(ext2fs_generic_bitmap bitmap,
break;
}
- pos = start;
+ memset(out, 0, (num + 7) >> 3);
+
for (; parent != NULL; parent = next) {
next = ext2fs_rb_next(parent);
- ext = ext2fs_rb_entry(parent, struct bmap_rb_extent, node);
+ ext = node_to_extent(parent);
- while (((pos - start) < num) &&
- (pos < ext->start)) {
- ext2fs_fast_clear_bit64((pos - start), out);
- pos++;
+ pos = ext->start;
+ count = ext->count;
+ if (pos >= start + num)
+ break;
+ if (pos < start) {
+ count -= start - pos;
+ if (count < 0)
+ continue;
+ pos = start;
}
-
- if ((pos - start) >= num)
- return 0;
-
- while (((pos - start) < num) &&
- (pos < (ext->start + ext->count))) {
+ if (pos + count > start + num)
+ count = start + num - pos;
+
+ while (count > 0) {
+ if ((count >= 8) &&
+ ((pos - start) % 8) == 0) {
+ int nbytes = count >> 3;
+ int offset = (pos - start) >> 3;
+
+ memset(((char *) out) + offset, 0xFF, nbytes);
+ pos += nbytes << 3;
+ count -= nbytes << 3;
+ continue;
+ }
ext2fs_fast_set_bit64((pos - start), out);
pos++;
+ count--;
}
}
+ return 0;
+}
+
+static void rb_clear_bmap(ext2fs_generic_bitmap bitmap)
+{
+ struct ext2fs_rb_private *bp;
+
+ bp = (struct ext2fs_rb_private *) bitmap->private;
- while ((pos - start) < num) {
- ext2fs_fast_clear_bit64((pos - start), out);
- pos++;
+ rb_free_tree(&bp->root);
+ bp->rcursor = NULL;
+ bp->rcursor_next = NULL;
+ bp->wcursor = NULL;
+ check_tree(&bp->root, __func__);
+}
+
+static errcode_t rb_find_first_zero(ext2fs_generic_bitmap bitmap,
+ __u64 start, __u64 end, __u64 *out)
+{
+ struct rb_node *parent = NULL, **n;
+ struct ext2fs_rb_private *bp;
+ struct bmap_rb_extent *ext;
+
+ bp = (struct ext2fs_rb_private *) bitmap->private;
+ n = &bp->root.rb_node;
+ start -= bitmap->start;
+ end -= bitmap->start;
+
+ if (start > end)
+ return EINVAL;
+
+ if (EXT2FS_RB_EMPTY_ROOT(&bp->root))
+ return ENOENT;
+
+ while (*n) {
+ parent = *n;
+ ext = node_to_extent(parent);
+ if (start < ext->start) {
+ n = &(*n)->rb_left;
+ } else if (start >= (ext->start + ext->count)) {
+ n = &(*n)->rb_right;
+ } else if (ext->start + ext->count <= end) {
+ *out = ext->start + ext->count + bitmap->start;
+ return 0;
+ } else
+ return ENOENT;
}
+ *out = start + bitmap->start;
return 0;
}
-static void rb_clear_bmap(ext2fs_generic_bitmap bitmap)
+static errcode_t rb_find_first_set(ext2fs_generic_bitmap bitmap,
+ __u64 start, __u64 end, __u64 *out)
{
+ struct rb_node *parent = NULL, **n;
+ struct rb_node *node;
struct ext2fs_rb_private *bp;
+ struct bmap_rb_extent *ext;
bp = (struct ext2fs_rb_private *) bitmap->private;
+ n = &bp->root.rb_node;
+ start -= bitmap->start;
+ end -= bitmap->start;
- rb_free_tree(&bp->root);
- *bp->rcursor = NULL;
- *bp->wcursor = NULL;
+ if (start > end)
+ return EINVAL;
+
+ if (EXT2FS_RB_EMPTY_ROOT(&bp->root))
+ return ENOENT;
+
+ while (*n) {
+ parent = *n;
+ ext = node_to_extent(parent);
+ if (start < ext->start) {
+ n = &(*n)->rb_left;
+ } else if (start >= (ext->start + ext->count)) {
+ n = &(*n)->rb_right;
+ } else {
+ /* The start bit is set */
+ *out = start + bitmap->start;
+ return 0;
+ }
+ }
+
+ node = parent;
+ ext = node_to_extent(node);
+ if (ext->start < start) {
+ node = ext2fs_rb_next(node);
+ if (node == NULL)
+ return ENOENT;
+ ext = node_to_extent(node);
+ }
+ if (ext->start <= end) {
+ *out = ext->start + bitmap->start;
+ return 0;
+ }
+ return ENOENT;
}
#ifdef BMAP_STATS
@@ -752,15 +903,17 @@ static void rb_print_stats(ext2fs_generic_bitmap bitmap)
__u64 max_size = 0;
__u64 min_size = ULONG_MAX;
__u64 size = 0, avg_size = 0;
+ double eff;
+#ifdef BMAP_STATS_OPS
__u64 mark_all, test_all;
- double eff, m_hit = 0.0, t_hit = 0.0;
+ double m_hit = 0.0, t_hit = 0.0;
+#endif
bp = (struct ext2fs_rb_private *) bitmap->private;
- node = ext2fs_rb_first(&bp->root);
for (node = ext2fs_rb_first(&bp->root); node != NULL;
node = ext2fs_rb_next(node)) {
- ext = ext2fs_rb_entry(node, struct bmap_rb_extent, node);
+ ext = node_to_extent(node);
count++;
if (ext->count > max_size)
max_size = ext->count;
@@ -821,4 +974,6 @@ struct ext2_bitmap_ops ext2fs_blkmap64_rbtree = {
.get_bmap_range = rb_get_bmap_range,
.clear_bmap = rb_clear_bmap,
.print_stats = rb_print_stats,
+ .find_first_zero = rb_find_first_zero,
+ .find_first_set = rb_find_first_set,
};
diff --git a/lib/ext2fs/blknum.c b/lib/ext2fs/blknum.c
index 33da7d6f..8ced1eec 100644
--- a/lib/ext2fs/blknum.c
+++ b/lib/ext2fs/blknum.c
@@ -187,11 +187,8 @@ struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs,
struct opaque_ext2_group_desc *gdp,
dgrp_t group)
{
- if (fs->super->s_desc_size >= EXT2_MIN_DESC_SIZE_64BIT)
- return (struct ext2_group_desc *)
- ((struct ext4_group_desc *) gdp + group);
- else
- return (struct ext2_group_desc *) gdp + group;
+ return (struct ext2_group_desc *)((char *)gdp +
+ group * EXT2_DESC_SIZE(fs->super));
}
/* Do the same but as an ext4 group desc for internal use here */
diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
index 85a1803d..b8c68798 100644
--- a/lib/ext2fs/block.c
+++ b/lib/ext2fs/block.c
@@ -389,7 +389,7 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
if (inode.i_flags & EXT4_EXTENTS_FL) {
ext2_extent_handle_t handle;
- struct ext2fs_extent extent;
+ struct ext2fs_extent extent, next;
e2_blkcnt_t blockcnt = 0;
blk64_t blk, new_blk;
int op = EXT2_EXTENT_ROOT;
@@ -401,7 +401,11 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
goto abort_exit;
while (1) {
- ctx.errcode = ext2fs_extent_get(handle, op, &extent);
+ if (op == EXT2_EXTENT_CURRENT)
+ ctx.errcode = 0;
+ else
+ ctx.errcode = ext2fs_extent_get(handle, op,
+ &extent);
if (ctx.errcode) {
if (ctx.errcode != EXT2_ET_EXTENT_NO_NEXT)
break;
@@ -456,14 +460,21 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
uninit = 0;
if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
uninit = EXT2_EXTENT_SET_BMAP_UNINIT;
+
+ /*
+ * Get the next extent before we start messing
+ * with the current extent
+ */
+ retval = ext2fs_extent_get(handle, op, &next);
+
#if 0
printf("lblk %llu pblk %llu len %d blockcnt %llu\n",
extent.e_lblk, extent.e_pblk,
extent.e_len, blockcnt);
#endif
- if (extent.e_lblk + extent.e_len <= blockcnt)
+ if (extent.e_lblk + extent.e_len <= (blk64_t) blockcnt)
continue;
- if (extent.e_lblk > blockcnt)
+ if (extent.e_lblk > (blk64_t) blockcnt)
blockcnt = extent.e_lblk;
j = blockcnt - extent.e_lblk;
blk += j;
@@ -487,6 +498,10 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
if (ret & BLOCK_ABORT)
goto extent_done;
}
+ if (retval == 0) {
+ extent = next;
+ op = EXT2_EXTENT_CURRENT;
+ }
}
extent_done:
diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c
index 16d51e0b..db2fd726 100644
--- a/lib/ext2fs/bmap.c
+++ b/lib/ext2fs/bmap.c
@@ -18,7 +18,7 @@
#include <errno.h>
#include "ext2_fs.h"
-#include "ext2fs.h"
+#include "ext2fsP.h"
#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
#define _BMAP_INLINE_ __inline__
@@ -95,7 +95,7 @@ static _BMAP_INLINE_ errcode_t block_dind_bmap(ext2_filsys fs, int flags,
int *blocks_alloc,
blk_t nr, blk_t *ret_blk)
{
- blk_t b;
+ blk_t b = 0;
errcode_t retval;
blk_t addr_per_block;
@@ -115,7 +115,7 @@ static _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags,
int *blocks_alloc,
blk_t nr, blk_t *ret_blk)
{
- blk_t b;
+ blk_t b = 0;
errcode_t retval;
blk_t addr_per_block;
@@ -140,7 +140,7 @@ static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
static errcode_t implied_cluster_alloc(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
ext2_extent_handle_t handle,
- blk64_t block, blk64_t *phys_blk)
+ blk64_t lblk, blk64_t *phys_blk)
{
blk64_t base_block, pblock = 0;
int i;
@@ -149,10 +149,19 @@ static errcode_t implied_cluster_alloc(ext2_filsys fs, ext2_ino_t ino,
EXT4_FEATURE_RO_COMPAT_BIGALLOC))
return 0;
- base_block = block & ~EXT2FS_CLUSTER_MASK(fs);
+ base_block = lblk & ~EXT2FS_CLUSTER_MASK(fs);
+ /*
+ * Except for the logical block (lblk) that was passed in, search all
+ * blocks in this logical cluster for a mapping to a physical cluster.
+ * If any such map exists, calculate the physical block that maps to
+ * the logical block and return that.
+ *
+ * The old code wouldn't even look if (block % cluster_ratio) == 0;
+ * this is incorrect if we're allocating blocks in reverse order.
+ */
for (i = 0; i < EXT2FS_CLUSTER_RATIO(fs); i++) {
- if (block == base_block)
- return 0;
+ if (base_block + i == lblk)
+ continue;
extent_bmap(fs, ino, inode, handle, 0, 0,
base_block + i, 0, 0, &pblock);
if (pblock)
@@ -160,10 +169,39 @@ static errcode_t implied_cluster_alloc(ext2_filsys fs, ext2_ino_t ino,
}
if (pblock == 0)
return 0;
- *phys_blk = pblock - i + (block - base_block);
+ *phys_blk = pblock - i + (lblk - base_block);
return 0;
}
+/* Try to map a logical block to an already-allocated physical cluster. */
+errcode_t ext2fs_map_cluster_block(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode, blk64_t lblk,
+ blk64_t *pblk)
+{
+ ext2_extent_handle_t handle;
+ errcode_t retval;
+
+ /* Need bigalloc and extents to be enabled */
+ *pblk = 0;
+ if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_BIGALLOC) ||
+ !(inode->i_flags & EXT4_EXTENTS_FL))
+ return 0;
+
+ retval = ext2fs_extent_open2(fs, ino, inode, &handle);
+ if (retval)
+ goto out;
+
+ retval = implied_cluster_alloc(fs, ino, inode, handle, lblk, pblk);
+ if (retval)
+ goto out2;
+
+out2:
+ ext2fs_extent_free(handle);
+out:
+ return retval;
+}
+
static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
ext2_extent_handle_t handle,
@@ -217,8 +255,10 @@ got_block:
set_extent:
retval = ext2fs_extent_set_bmap(handle, block,
blk64, 0);
- if (retval)
+ if (retval) {
+ ext2fs_block_alloc_stats2(fs, blk64, -1);
return retval;
+ }
/* Update inode after setting extent */
retval = ext2fs_read_inode(fs, ino, inode);
if (retval)
@@ -229,6 +269,27 @@ got_block:
return 0;
}
+int ext2fs_file_block_offset_too_big(ext2_filsys fs,
+ struct ext2_inode *inode,
+ blk64_t offset)
+{
+ blk64_t addr_per_block, max_map_block;
+
+ /* Kernel seems to cut us off at 4294967294 blocks */
+ if (offset >= (1ULL << 32) - 1)
+ return 1;
+
+ if (inode->i_flags & EXT4_EXTENTS_FL)
+ return 0;
+
+ addr_per_block = fs->blocksize >> 2;
+ max_map_block = addr_per_block;
+ max_map_block += addr_per_block * addr_per_block;
+ max_map_block += addr_per_block * addr_per_block * addr_per_block;
+ max_map_block += 12;
+
+ return offset >= max_map_block;
+}
errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
char *block_buf, int bmap_flags, blk64_t block,
@@ -257,6 +318,9 @@ errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
}
addr_per_block = (blk_t) fs->blocksize >> 2;
+ if (ext2fs_file_block_offset_too_big(fs, inode, block))
+ return EXT2_ET_FILE_TOO_BIG;
+
if (!block_buf) {
retval = ext2fs_get_array(2, fs->blocksize, &buf);
if (retval)
diff --git a/lib/ext2fs/bmap64.h b/lib/ext2fs/bmap64.h
index f44d379c..9deba46c 100644
--- a/lib/ext2fs/bmap64.h
+++ b/lib/ext2fs/bmap64.h
@@ -94,6 +94,10 @@ struct ext2_bitmap_ops {
* May be NULL, in which case a generic function is used. */
errcode_t (*find_first_zero)(ext2fs_generic_bitmap bitmap,
__u64 start, __u64 end, __u64 *out);
+ /* Find the first set bit between start and end, inclusive.
+ * May be NULL, in which case a generic function is used. */
+ errcode_t (*find_first_set)(ext2fs_generic_bitmap bitmap,
+ __u64 start, __u64 end, __u64 *out);
};
extern struct ext2_bitmap_ops ext2fs_blkmap64_bitarray;
diff --git a/lib/ext2fs/brel.h b/lib/ext2fs/brel.h
index a0dd5b9c..9fdddd40 100644
--- a/lib/ext2fs/brel.h
+++ b/lib/ext2fs/brel.h
@@ -10,11 +10,11 @@
*/
struct ext2_block_relocate_entry {
- blk_t new;
+ blk64_t new;
__s16 offset;
__u16 flags;
union {
- blk_t block_ref;
+ blk64_t block_ref;
ext2_ino_t inode_ref;
} owner;
};
@@ -28,19 +28,19 @@ typedef struct ext2_block_relocation_table *ext2_brel;
struct ext2_block_relocation_table {
__u32 magic;
char *name;
- blk_t current;
+ blk64_t current;
void *priv_data;
/*
* Add a block relocation entry.
*/
- errcode_t (*put)(ext2_brel brel, blk_t old,
+ errcode_t (*put)(ext2_brel brel, blk64_t old,
struct ext2_block_relocate_entry *ent);
/*
* Get a block relocation entry.
*/
- errcode_t (*get)(ext2_brel brel, blk_t old,
+ errcode_t (*get)(ext2_brel brel, blk64_t old,
struct ext2_block_relocate_entry *ent);
/*
@@ -52,19 +52,19 @@ struct ext2_block_relocation_table {
* The iterator function for the inode relocation entries.
* Returns an inode number of 0 when out of entries.
*/
- errcode_t (*next)(ext2_brel brel, blk_t *old,
+ errcode_t (*next)(ext2_brel brel, blk64_t *old,
struct ext2_block_relocate_entry *ent);
/*
* Move the inode relocation table from one block number to
* another.
*/
- errcode_t (*move)(ext2_brel brel, blk_t old, blk_t new);
+ errcode_t (*move)(ext2_brel brel, blk64_t old, blk_t new);
/*
* Remove a block relocation entry.
*/
- errcode_t (*delete)(ext2_brel brel, blk_t old);
+ errcode_t (*delete)(ext2_brel brel, blk64_t old);
/*
@@ -73,7 +73,7 @@ struct ext2_block_relocation_table {
errcode_t (*free)(ext2_brel brel);
};
-errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
+errcode_t ext2fs_brel_memarray_create(char *name, blk64_t max_block,
ext2_brel *brel);
#define ext2fs_brel_put(brel, old, ent) ((brel)->put((brel), old, ent))
diff --git a/lib/ext2fs/brel_ma.c b/lib/ext2fs/brel_ma.c
index e8a8280e..a12afaeb 100644
--- a/lib/ext2fs/brel_ma.c
+++ b/lib/ext2fs/brel_ma.c
@@ -27,24 +27,24 @@
#include "ext2fs.h"
#include "brel.h"
-static errcode_t bma_put(ext2_brel brel, blk_t old,
+static errcode_t bma_put(ext2_brel brel, blk64_t old,
struct ext2_block_relocate_entry *ent);
-static errcode_t bma_get(ext2_brel brel, blk_t old,
+static errcode_t bma_get(ext2_brel brel, blk64_t old,
struct ext2_block_relocate_entry *ent);
static errcode_t bma_start_iter(ext2_brel brel);
-static errcode_t bma_next(ext2_brel brel, blk_t *old,
+static errcode_t bma_next(ext2_brel brel, blk64_t *old,
struct ext2_block_relocate_entry *ent);
-static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new);
-static errcode_t bma_delete(ext2_brel brel, blk_t old);
+static errcode_t bma_move(ext2_brel brel, blk64_t old, blk64_t new);
+static errcode_t bma_delete(ext2_brel brel, blk64_t old);
static errcode_t bma_free(ext2_brel brel);
struct brel_ma {
__u32 magic;
- blk_t max_block;
+ blk64_t max_block;
struct ext2_block_relocate_entry *entries;
};
-errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
+errcode_t ext2fs_brel_memarray_create(char *name, blk64_t max_block,
ext2_brel *new_brel)
{
ext2_brel brel = 0;
@@ -102,7 +102,7 @@ errout:
return retval;
}
-static errcode_t bma_put(ext2_brel brel, blk_t old,
+static errcode_t bma_put(ext2_brel brel, blk64_t old,
struct ext2_block_relocate_entry *ent)
{
struct brel_ma *ma;
@@ -114,7 +114,7 @@ static errcode_t bma_put(ext2_brel brel, blk_t old,
return 0;
}
-static errcode_t bma_get(ext2_brel brel, blk_t old,
+static errcode_t bma_get(ext2_brel brel, blk64_t old,
struct ext2_block_relocate_entry *ent)
{
struct brel_ma *ma;
@@ -134,7 +134,7 @@ static errcode_t bma_start_iter(ext2_brel brel)
return 0;
}
-static errcode_t bma_next(ext2_brel brel, blk_t *old,
+static errcode_t bma_next(ext2_brel brel, blk64_t *old,
struct ext2_block_relocate_entry *ent)
{
struct brel_ma *ma;
@@ -151,7 +151,7 @@ static errcode_t bma_next(ext2_brel brel, blk_t *old,
return 0;
}
-static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new)
+static errcode_t bma_move(ext2_brel brel, blk64_t old, blk64_t new)
{
struct brel_ma *ma;
@@ -165,7 +165,7 @@ static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new)
return 0;
}
-static errcode_t bma_delete(ext2_brel brel, blk_t old)
+static errcode_t bma_delete(ext2_brel brel, blk64_t old)
{
struct brel_ma *ma;
diff --git a/lib/ext2fs/check_desc.c b/lib/ext2fs/check_desc.c
index a6fcc454..1a768f92 100644
--- a/lib/ext2fs/check_desc.c
+++ b/lib/ext2fs/check_desc.c
@@ -42,6 +42,9 @@ errcode_t ext2fs_check_desc(ext2_filsys fs)
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+ if (EXT2_DESC_SIZE(fs->super) & (EXT2_DESC_SIZE(fs->super) - 1))
+ return EXT2_ET_BAD_DESC_SIZE;
+
retval = ext2fs_allocate_subcluster_bitmap(fs, "check_desc map", &bmap);
if (retval)
return retval;
diff --git a/lib/ext2fs/closefs.c b/lib/ext2fs/closefs.c
index 973c2a23..4e91778a 100644
--- a/lib/ext2fs/closefs.c
+++ b/lib/ext2fs/closefs.c
@@ -20,12 +20,12 @@
#include "ext2_fs.h"
#include "ext2fsP.h"
-static int test_root(int a, int b)
+static int test_root(unsigned int a, unsigned int b)
{
- if (a == 0)
- return 1;
while (1) {
- if (a == 1)
+ if (a < b)
+ return 0;
+ if (a == b)
return 1;
if (a % b)
return 0;
@@ -33,14 +33,23 @@ static int test_root(int a, int b)
}
}
-int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
+int ext2fs_bg_has_super(ext2_filsys fs, dgrp_t group)
{
- if (!(fs->super->s_feature_ro_compat &
- EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
+ if (group == 0)
return 1;
-
- if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
- test_root(group_block, 7))
+ if (fs->super->s_feature_compat & EXT4_FEATURE_COMPAT_SPARSE_SUPER2) {
+ if (group == fs->super->s_backup_bgs[0] ||
+ group == fs->super->s_backup_bgs[1])
+ return 1;
+ return 0;
+ }
+ if ((group <= 1) || !(fs->super->s_feature_ro_compat &
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
+ return 1;
+ if (!(group & 1))
+ return 0;
+ if (test_root(group, 3) || (test_root(group, 5)) ||
+ test_root(group, 7))
return 1;
return 0;
@@ -243,7 +252,7 @@ void ext2fs_update_dynamic_rev(ext2_filsys fs)
}
static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group,
- blk_t group_block,
+ blk64_t group_block,
struct ext2_super_block *super_shadow)
{
dgrp_t sgrp = group;
@@ -301,7 +310,7 @@ errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
fs->desc_blocks);
/* swap the group descriptors */
- for (j=0; j < fs->group_desc_count; j++) {
+ for (j = 0; j < fs->group_desc_count; j++) {
gdp = ext2fs_group_desc(fs, group_shadow, j);
ext2fs_swap_group_desc2(fs, gdp);
}
diff --git a/lib/ext2fs/crc32c.c b/lib/ext2fs/crc32c.c
index 6be43369..2512528a 100644
--- a/lib/ext2fs/crc32c.c
+++ b/lib/ext2fs/crc32c.c
@@ -35,9 +35,9 @@
#define __force
#define min(x, y) ((x) > (y) ? (y) : (x))
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
-#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
+#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1)
#define ALIGN(x, a) __ALIGN_KERNEL((x), (a))
-#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a)))
+#define PTR_ALIGN(p, a) ((__typeof__(p))ALIGN((unsigned long)(p), (a)))
#include "crc32c_defs.h"
#include "ext2fs.h"
@@ -224,7 +224,7 @@ static uint32_t crc32c_le_body(uint32_t crc, uint8_t const *buf, size_t len)
crc = (__force uint32_t) __cpu_to_le32(crc);
p8 = buf;
- p32 = (uint32_t *)PTR_ALIGN(p8, 8);
+ p32 = (const uint32_t *)PTR_ALIGN(p8, 8);
init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
words = (len - init_bytes) >> 3;
end_bytes = (len - init_bytes) & 7;
@@ -273,7 +273,7 @@ static uint32_t crc32c_le_body(uint32_t crc, uint8_t const *buf, size_t len)
#endif
}
- p8 = (uint8_t *)(++p32);
+ p8 = (const uint8_t *)(++p32);
for (i = 0; i < end_bytes; i++) {
#ifndef WORDS_BIGENDIAN
@@ -304,7 +304,7 @@ static uint32_t crc32c_be_body(uint32_t crc, uint8_t const *buf, size_t len)
crc = (__force uint32_t) __cpu_to_be32(crc);
p8 = buf;
- p32 = (uint32_t *)PTR_ALIGN(p8, 8);
+ p32 = (const uint32_t *)PTR_ALIGN(p8, 8);
init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
words = (len - init_bytes) >> 3;
end_bytes = (len - init_bytes) & 7;
@@ -353,7 +353,7 @@ static uint32_t crc32c_be_body(uint32_t crc, uint8_t const *buf, size_t len)
#endif
}
- p8 = (uint8_t *)(++p32);
+ p8 = (const uint8_t *)(++p32);
for (i = 0; i < end_bytes; i++) {
#ifndef WORDS_BIGENDIAN
@@ -1117,12 +1117,12 @@ static int test_crc32c(void)
be = ext2fs_crc32c_be(t->crc, test_buf + t->start, t->length);
if (le != t->crc_le) {
printf("Test %d LE fails, %x != %x\n",
- (t - test), le, t->crc_le);
+ (int) (t - test), le, t->crc_le);
failures++;
}
if (be != t->crc_be) {
printf("Test %d BE fails, %x != %x\n",
- (t - test), be, t->crc_be);
+ (int) (t - test), be, t->crc_be);
failures++;
}
t++;
diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c
index 9fa3f24f..669f8068 100644
--- a/lib/ext2fs/csum.c
+++ b/lib/ext2fs/csum.c
@@ -32,27 +32,23 @@
__u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
{
+ struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc,
+ group);
+ size_t size = EXT2_DESC_SIZE(fs->super);
__u16 crc = 0;
- struct ext2_group_desc *desc;
- size_t size;
-
- size = fs->super->s_desc_size;
- if (size < EXT2_MIN_DESC_SIZE)
- size = EXT2_MIN_DESC_SIZE;
- if (size > sizeof(struct ext4_group_desc)) {
- printf("%s: illegal s_desc_size(%zd)\n", __func__, size);
- size = sizeof(struct ext4_group_desc);
- }
-
- desc = ext2fs_group_desc(fs, fs->group_desc, group);
if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
size_t offset = offsetof(struct ext2_group_desc, bg_checksum);
#ifdef WORDS_BIGENDIAN
struct ext4_group_desc swabdesc;
+ size_t save_size = size;
+ const size_t ext4_bg_size = sizeof(struct ext4_group_desc);
+ struct ext2_group_desc *save_desc = desc;
/* Have to swab back to little-endian to do the checksum */
+ if (size > ext4_bg_size)
+ size = ext4_bg_size;
memcpy(&swabdesc, desc, size);
ext2fs_swap_group_desc2(fs,
(struct ext2_group_desc *) &swabdesc);
@@ -70,6 +66,17 @@ __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
crc = ext2fs_crc16(crc, (char *)desc + offset,
size - offset);
}
+#ifdef WORDS_BIGENDIAN
+ /*
+ * If the size of the bg descriptor is greater than 64
+ * bytes, which is the size of the traditional ext4 bg
+ * descriptor, checksum the rest of the descriptor here
+ */
+ if (save_size > ext4_bg_size)
+ crc = ext2fs_crc16(crc,
+ (char *)save_desc + ext4_bg_size,
+ save_size - ext4_bg_size);
+#endif
}
return crc;
@@ -166,21 +173,22 @@ void print_csum(const char *msg, ext2_filsys fs, dgrp_t group)
{
__u16 crc1, crc2, crc3;
dgrp_t swabgroup;
- struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc, group);
- size_t size;
+ struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc,
+ group);
+ size_t size = EXT2_DESC_SIZE(fs->super);
struct ext2_super_block *sb = fs->super;
int offset = offsetof(struct ext2_group_desc, bg_checksum);
#ifdef WORDS_BIGENDIAN
struct ext4_group_desc swabdesc;
+ struct ext2_group_desc *save_desc = desc;
+ const size_t ext4_bg_size = sizeof(struct ext4_group_desc);
+ size_t save_size = size;
#endif
- size = fs->super->s_desc_size;
- if (size < EXT2_MIN_DESC_SIZE)
- size = EXT2_MIN_DESC_SIZE;
- if (size > sizeof(struct ext4_group_desc))
- size = sizeof(struct ext4_group_desc);
#ifdef WORDS_BIGENDIAN
/* Have to swab back to little-endian to do the checksum */
+ if (size > ext4_bg_size)
+ size = ext4_bg_size;
memcpy(&swabdesc, desc, size);
ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc);
desc = (struct ext2_group_desc *) &swabdesc;
@@ -197,8 +205,13 @@ void print_csum(const char *msg, ext2_filsys fs, dgrp_t group)
/* for checksum of struct ext4_group_desc do the rest...*/
if (offset < size)
crc3 = ext2fs_crc16(crc3, (char *)desc + offset, size - offset);
+#ifdef WORDS_BIGENDIAN
+ if (save_size > ext4_bg_size)
+ crc3 = ext2fs_crc16(crc3, (char *)save_desc + ext4_bg_size,
+ save_size - ext4_bg_size);
+#endif
- printf("%s: UUID %s(%04x), grp %u(%04x): %04x=%04x\n",
+ printf("%s UUID %s=%04x, grp %u=%04x: %04x=%04x\n",
msg, e2p_uuid2str(sb->s_uuid), crc1, group, crc2, crc3,
ext2fs_group_desc_csum(fs, group));
}
@@ -216,6 +229,11 @@ int main(int argc, char **argv)
memset(&param, 0, sizeof(param));
ext2fs_blocks_count_set(&param, 32768);
+#if 0
+ param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_64BIT;
+ param.s_desc_size = 128;
+ csum_known = 0x5b6e;
+#endif
retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, &param,
test_io_manager, &fs);
diff --git a/lib/ext2fs/dblist.c b/lib/ext2fs/dblist.c
index ca1446b9..3f6ea50d 100644
--- a/lib/ext2fs/dblist.c
+++ b/lib/ext2fs/dblist.c
@@ -61,7 +61,7 @@ static errcode_t make_dblist(ext2_filsys fs, ext2_ino_t size,
struct ext2_db_entry2 *list,
ext2_dblist *ret_dblist)
{
- ext2_dblist dblist;
+ ext2_dblist dblist = NULL;
errcode_t retval;
ext2_ino_t num_dirs;
size_t len;
@@ -393,10 +393,11 @@ int ext2fs_dblist_count(ext2_dblist dblist)
errcode_t ext2fs_dblist_get_last(ext2_dblist dblist,
struct ext2_db_entry **entry)
{
- EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
static struct ext2_db_entry ret_entry;
struct ext2_db_entry2 *last;
+ EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
+
if (dblist->count == 0)
return EXT2_ET_DBLIST_EMPTY;
diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c
index 5125d199..589af692 100644
--- a/lib/ext2fs/dir_iterate.c
+++ b/lib/ext2fs/dir_iterate.c
@@ -151,16 +151,16 @@ static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)),
return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
}
-extern errcode_t ext2fs_dir_iterate(ext2_filsys fs,
- ext2_ino_t dir,
- int flags,
- char *block_buf,
- int (*func)(struct ext2_dir_entry *dirent,
- int offset,
- int blocksize,
- char *buf,
- void *priv_data),
- void *priv_data)
+errcode_t ext2fs_dir_iterate(ext2_filsys fs,
+ ext2_ino_t dir,
+ int flags,
+ char *block_buf,
+ int (*func)(struct ext2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data),
+ void *priv_data)
{
struct xlate xl;
diff --git a/lib/ext2fs/dupfs.c b/lib/ext2fs/dupfs.c
index 64d31248..02721e1a 100644
--- a/lib/ext2fs/dupfs.c
+++ b/lib/ext2fs/dupfs.c
@@ -40,6 +40,9 @@ errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest)
fs->block_map = 0;
fs->badblocks = 0;
fs->dblist = 0;
+ fs->mmp_buf = 0;
+ fs->mmp_cmp = 0;
+ fs->mmp_fd = -1;
io_channel_bumpcount(fs->io);
if (fs->icache)
@@ -87,6 +90,28 @@ errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest)
if (retval)
goto errout;
}
+ if (src->mmp_buf) {
+ retval = ext2fs_get_mem(src->blocksize, &fs->mmp_buf);
+ if (retval)
+ goto errout;
+ memcpy(fs->mmp_buf, src->mmp_buf, src->blocksize);
+ }
+ if (src->mmp_fd >= 0) {
+ fs->mmp_fd = dup(src->mmp_fd);
+ if (fs->mmp_fd < 0) {
+ retval = EXT2_ET_MMP_OPEN_DIRECT;
+ goto errout;
+ }
+ }
+ if (src->mmp_cmp) {
+ int align = ext2fs_get_dio_alignment(src->mmp_fd);
+
+ retval = ext2fs_get_memalign(src->blocksize, align,
+ &fs->mmp_cmp);
+ if (retval)
+ goto errout;
+ memcpy(fs->mmp_cmp, src->mmp_cmp, src->blocksize);
+ }
*dest = fs;
return 0;
errout:
diff --git a/lib/ext2fs/e2image.h b/lib/ext2fs/e2image.h
index c918529e..53b20cc7 100644
--- a/lib/ext2fs/e2image.h
+++ b/lib/ext2fs/e2image.h
@@ -12,15 +12,6 @@
* %End-Header%
*/
-/* Image types */
-#define E2IMAGE_RAW 1
-#define E2IMAGE_QCOW2 2
-
-/* Image flags */
-#define E2IMAGE_INSTALL_FLAG 1
-#define E2IMAGE_SCRAMBLE_FLAG 2
-#define E2IMAGE_IS_QCOW2_FLAG 3
-
struct ext2_image_hdr {
__u32 magic_number; /* This must be EXT2_ET_MAGIC_E2IMAGE */
char magic_descriptor[16]; /* "Ext2 Image 1.0", w/ null padding */
diff --git a/lib/ext2fs/expanddir.c b/lib/ext2fs/expanddir.c
index 41c40882..153b838c 100644
--- a/lib/ext2fs/expanddir.c
+++ b/lib/ext2fs/expanddir.c
@@ -54,6 +54,7 @@ static int expand_dir_proc(ext2_filsys fs,
return BLOCK_ABORT;
}
es->newblocks++;
+ ext2fs_block_alloc_stats2(fs, new_blk, +1);
}
if (blockcnt > 0) {
retval = ext2fs_new_dir_block(fs, 0, 0, &block);
@@ -80,7 +81,6 @@ static int expand_dir_proc(ext2_filsys fs,
}
ext2fs_free_mem(&block);
*blocknr = new_blk;
- ext2fs_block_alloc_stats2(fs, new_blk, +1);
if (es->done)
return (BLOCK_CHANGED | BLOCK_ABORT);
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index ccf1894a..87812ab4 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -96,10 +96,10 @@ ec EXT2_ET_INODE_BITMAP_READ,
"Can't read an inode bitmap"
ec EXT2_ET_BLOCK_BITMAP_WRITE,
- "Can't write an block bitmap"
+ "Can't write a block bitmap"
ec EXT2_ET_BLOCK_BITMAP_READ,
- "Can't read an block bitmap"
+ "Can't read a block bitmap"
ec EXT2_ET_INODE_TABLE_WRITE,
"Can't write an inode table"
@@ -416,7 +416,7 @@ ec EXT2_ET_EXTENT_INVALID_LENGTH,
ec EXT2_ET_IO_CHANNEL_NO_SUPPORT_64,
"I/O Channel does not support 64-bit block numbers"
-ec EXT2_NO_MTAB_FILE,
+ec EXT2_ET_NO_MTAB_FILE,
"Can't check if filesystem is mounted due to missing mtab file"
ec EXT2_ET_CANT_USE_LEGACY_BITMAPS,
@@ -443,4 +443,37 @@ ec EXT2_ET_MMP_CHANGE_ABORT,
ec EXT2_ET_MMP_OPEN_DIRECT,
"MMP: open with O_DIRECT failed"
+ec EXT2_ET_BAD_DESC_SIZE,
+ "Block group descriptor size incorrect"
+
+ec EXT2_ET_INODE_CSUM_INVALID,
+ "Inode checksum does not match inode"
+
+ec EXT2_ET_INODE_BITMAP_CSUM_INVALID,
+ "Inode bitmap checksum does not match bitmap"
+
+ec EXT2_ET_EXTENT_CSUM_INVALID,
+ "Extent block checksum does not match extent block"
+
+ec EXT2_ET_DIR_NO_SPACE_FOR_CSUM,
+ "Directory block does not have space for checksum"
+
+ec EXT2_ET_DIR_CSUM_INVALID,
+ "Directory block checksum does not match directory block"
+
+ec EXT2_ET_EXT_ATTR_CSUM_INVALID,
+ "Extended attribute block checksum does not match block"
+
+ec EXT2_ET_SB_CSUM_INVALID,
+ "Superblock checksum does not match superblock"
+
+ec EXT2_ET_UNKNOWN_CSUM,
+ "Unknown checksum algorithm"
+
+ec EXT2_ET_MMP_CSUM_INVALID,
+ "MMP block checksum does not match MMP block"
+
+ec EXT2_ET_FILE_EXISTS,
+ "Ext2 file already exists"
+
end
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 20decff2..d9e14d7c 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -159,7 +159,7 @@ struct ext2_group_desc
__u16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */
__u16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */
__u16 bg_itable_unused; /* Unused inodes count */
- __u16 bg_checksum; /* crc16(s_uuid+grouo_num+group_desc)*/
+ __u16 bg_checksum; /* crc16(s_uuid+group_num+group_desc)*/
};
/*
@@ -301,6 +301,7 @@ struct ext2_dx_countlimit {
#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */
/* EXT4_EOFBLOCKS_FL 0x00400000 was here */
+#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
#define EXT4_SNAPFILE_FL 0x01000000 /* Inode is a snapshot */
#define EXT4_SNAPFILE_DELETED_FL 0x04000000 /* Snapshot is being deleted */
#define EXT4_SNAPFILE_SHRUNK_FL 0x08000000 /* Snapshot shrink has completed */
@@ -644,7 +645,8 @@ struct ext2_super_block {
__u32 s_usr_quota_inum; /* inode number of user quota file */
__u32 s_grp_quota_inum; /* inode number of group quota file */
__u32 s_overhead_blocks; /* overhead blocks/clusters in fs */
- __u32 s_reserved[108]; /* Padding to the end of the block */
+ __u32 s_backup_bgs[2]; /* If sparse_super2 enabled */
+ __u32 s_reserved[106]; /* Padding to the end of the block */
__u32 s_checksum; /* crc32c(superblock) */
};
@@ -695,6 +697,7 @@ struct ext2_super_block {
#define EXT2_FEATURE_COMPAT_LAZY_BG 0x0040
/* #define EXT2_FEATURE_COMPAT_EXCLUDE_INODE 0x0080 not used, legacy */
#define EXT2_FEATURE_COMPAT_EXCLUDE_BITMAP 0x0100
+#define EXT4_FEATURE_COMPAT_SPARSE_SUPER2 0x0200
#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
@@ -721,6 +724,9 @@ struct ext2_super_block {
#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400
#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000
+/* 0x2000 was EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM but this was never used */
+#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */
+#define EXT4_FEATURE_INCOMPAT_INLINEDATA 0x8000 /* data in inode */
#define EXT2_FEATURE_COMPAT_SUPP 0
#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
diff --git a/lib/ext2fs/ext2_io.h b/lib/ext2fs/ext2_io.h
index bcc2f876..1894fb8c 100644
--- a/lib/ext2fs/ext2_io.h
+++ b/lib/ext2fs/ext2_io.h
@@ -58,6 +58,7 @@ struct struct_io_channel {
long reserved[14];
void *private_data;
void *app_data;
+ int align;
};
struct struct_io_stats {
@@ -121,6 +122,8 @@ extern errcode_t io_channel_write_blk64(io_channel channel,
extern errcode_t io_channel_discard(io_channel channel,
unsigned long long block,
unsigned long long count);
+extern errcode_t io_channel_alloc_buf(io_channel channel,
+ int count, void *ptr);
/* unix_io.c */
extern io_manager unix_io_manager;
diff --git a/lib/ext2fs/ext2_types.h.in b/lib/ext2fs/ext2_types.h.in
index aa7ca3a9..5b98f715 100644
--- a/lib/ext2fs/ext2_types.h.in
+++ b/lib/ext2fs/ext2_types.h.in
@@ -92,11 +92,11 @@ typedef __U64_TYPEDEF __u64;
#if (@SIZEOF_INT@ == 8)
typedef unsigned int __u64;
#else
-#if (@SIZEOF_LONG@ == 8)
-typedef unsigned long __u64;
-#else
#if (@SIZEOF_LONG_LONG@ == 8)
typedef unsigned long long __u64;
+#else
+#if (@SIZEOF_LONG@ == 8)
+typedef unsigned long __u64;
#endif /* SIZEOF_LONG_LONG == 8 */
#endif /* SIZEOF_LONG == 8 */
#endif /* SIZEOF_INT == 8 */
@@ -108,15 +108,15 @@ typedef __S64_TYPEDEF __s64;
#if (@SIZEOF_INT@ == 8)
typedef int __s64;
#else
-#if (@SIZEOF_LONG@ == 8)
-typedef long __s64;
-#else
#if (@SIZEOF_LONG_LONG@ == 8)
#if defined(__GNUC__)
-typedef __signed__ long long __s64;
+typedef __signed__ long long __s64;
#else
-typedef signed long long __s64;
+typedef signed long long __s64;
#endif /* __GNUC__ */
+#else
+#if (@SIZEOF_LONG@ == 8)
+typedef long __s64;
#endif /* SIZEOF_LONG_LONG == 8 */
#endif /* SIZEOF_LONG == 8 */
#endif /* SIZEOF_INT == 8 */
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 4e7711ac..1491c622 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -29,10 +29,6 @@ extern "C" {
#define NO_INLINE_FUNCS
#endif
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 600 /* for posix_memalign() */
-#endif
-
/*
* Where the master copy of the superblock is located, and how big
* superblocks are supposed to be. We define SUPERBLOCK_SIZE because
@@ -57,16 +53,6 @@ extern "C" {
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#ifndef __USE_XOPEN2K
-/* If the "#define _XOPEN_SOURCE 600" didn't succeed in declaring
- * posix_memalign(), maybe due to <features.h> or <stdlib.h> included beforej
- * _XOPEN_SOURCE, declare it here to avoid compiler warnings. */
-extern int posix_memalign(void **__memptr, size_t __alignment, size_t __size);
-#endif
#if EXT2_FLAT_INCLUDES
#include "e2_types.h"
@@ -78,14 +64,20 @@ extern int posix_memalign(void **__memptr, size_t __alignment, size_t __size);
#include <ext2fs/ext3_extents.h>
#endif /* EXT2_FLAT_INCLUDES */
-typedef __u32 ext2_ino_t;
-typedef __u32 blk_t;
-typedef __u64 blk64_t;
-typedef __u32 dgrp_t;
-typedef __u32 ext2_off_t;
-typedef __u64 ext2_off64_t;
-typedef __s64 e2_blkcnt_t;
-typedef __u32 ext2_dirhash_t;
+#ifdef __CHECK_ENDIAN__
+#define __bitwise __attribute__((bitwise))
+#else
+#define __bitwise
+#endif
+
+typedef __u32 __bitwise ext2_ino_t;
+typedef __u32 __bitwise blk_t;
+typedef __u64 __bitwise blk64_t;
+typedef __u32 __bitwise dgrp_t;
+typedef __u32 __bitwise ext2_off_t;
+typedef __u64 __bitwise ext2_off64_t;
+typedef __s64 __bitwise e2_blkcnt_t;
+typedef __u32 __bitwise ext2_dirhash_t;
#if EXT2_FLAT_INCLUDES
#include "com_err.h"
@@ -211,6 +203,7 @@ typedef struct ext2_file *ext2_file_t;
*/
#define EXT2_MKJOURNAL_V1_SUPER 0x0000001 /* create V1 superblock (deprecated) */
#define EXT2_MKJOURNAL_LAZYINIT 0x0000002 /* don't zero journal inode before use*/
+#define EXT2_MKJOURNAL_NO_MNT_CHECK 0x0000004 /* don't check mount status */
struct opaque_ext2_group_desc;
@@ -557,7 +550,8 @@ typedef struct ext2_icount *ext2_icount_t;
EXT3_FEATURE_COMPAT_HAS_JOURNAL|\
EXT2_FEATURE_COMPAT_RESIZE_INODE|\
EXT2_FEATURE_COMPAT_DIR_INDEX|\
- EXT2_FEATURE_COMPAT_EXT_ATTR)
+ EXT2_FEATURE_COMPAT_EXT_ATTR|\
+ EXT4_FEATURE_COMPAT_SPARSE_SUPER2)
/* This #ifdef is temporary until compression is fully supported */
#ifdef ENABLE_COMPRESSION
@@ -639,6 +633,12 @@ typedef struct stat ext2fs_struct_stat;
* function prototypes
*/
+/* The LARGE_FILE feature should be set if we have stored files 2GB+ in size */
+static inline int ext2fs_needs_large_file_feature(unsigned long long file_size)
+{
+ return file_size >= 0x80000000ULL;
+}
+
/* alloc.c */
extern errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, int mode,
ext2fs_inode_bitmap map, ext2_ino_t *ret);
@@ -684,6 +684,8 @@ void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
int inuse, int isdir);
void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse);
void ext2fs_block_alloc_stats2(ext2_filsys fs, blk64_t blk, int inuse);
+void ext2fs_block_alloc_stats_range(ext2_filsys fs, blk64_t blk,
+ blk_t num, int inuse);
/* alloc_tables.c */
extern errcode_t ext2fs_allocate_tables(ext2_filsys fs);
@@ -907,6 +909,9 @@ extern errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
char *block_buf, int bmap_flags, blk64_t block,
int *ret_flags, blk64_t *phys_blk);
+errcode_t ext2fs_map_cluster_block(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode, blk64_t lblk,
+ blk64_t *pblk);
#if 0
/* bmove.c */
@@ -924,7 +929,7 @@ extern errcode_t ext2fs_close(ext2_filsys fs);
extern errcode_t ext2fs_close2(ext2_filsys fs, int flags);
extern errcode_t ext2fs_flush(ext2_filsys fs);
extern errcode_t ext2fs_flush2(ext2_filsys fs, int flags);
-extern int ext2fs_bg_has_super(ext2_filsys fs, int group_block);
+extern int ext2fs_bg_has_super(ext2_filsys fs, dgrp_t group_block);
extern errcode_t ext2fs_super_and_bgd_loc2(ext2_filsys fs,
dgrp_t group,
blk64_t *ret_super_blk,
@@ -1083,6 +1088,7 @@ extern errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
extern void ext2fs_extent_free(ext2_extent_handle_t handle);
extern errcode_t ext2fs_extent_get(ext2_extent_handle_t handle,
int flags, struct ext2fs_extent *extent);
+extern errcode_t ext2fs_extent_node_split(ext2_extent_handle_t handle);
extern errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle, int flags,
struct ext2fs_extent *extent);
extern errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags,
@@ -1095,6 +1101,9 @@ extern errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle,
struct ext2_extent_info *info);
extern errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
blk64_t blk);
+extern errcode_t ext2fs_extent_goto2(ext2_extent_handle_t handle,
+ int leaf_level, blk64_t blk);
+extern errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle);
/* fileio.c */
extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
@@ -1168,6 +1177,12 @@ extern errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap bmap,
errcode_t magic,
__u32 start, __u32 num,
void *in);
+extern errcode_t ext2fs_find_first_zero_generic_bitmap(ext2fs_generic_bitmap bitmap,
+ __u32 start, __u32 end,
+ __u32 *out);
+extern errcode_t ext2fs_find_first_set_generic_bitmap(ext2fs_generic_bitmap bitmap,
+ __u32 start, __u32 end,
+ __u32 *out);
/* gen_bitmap64.c */
@@ -1209,6 +1224,7 @@ extern errcode_t ext2fs_get_device_size2(const char *file, int blocksize,
blk64_t *retblocks);
/* getsectsize.c */
+extern int ext2fs_get_dio_alignment(int fd);
errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize);
errcode_t ext2fs_get_device_phys_sectsize(const char *file, int *sectsize);
@@ -1257,6 +1273,11 @@ extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount);
errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
+/* inline.c */
+
+extern errcode_t ext2fs_get_memalign(unsigned long size,
+ unsigned long align, void *ptr);
+
/* inode.c */
extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan,
@@ -1308,6 +1329,10 @@ extern errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
char *mtpt, int mtlen);
/* punch.c */
+/*
+ * NOTE: This function removes from an inode the blocks "start", "end", and
+ * every block in between.
+ */
extern errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
char *block_buf, blk64_t start,
@@ -1346,6 +1371,8 @@ extern errcode_t ext2fs_add_journal_device(ext2_filsys fs,
ext2_filsys journal_dev);
extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks,
int flags);
+extern errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks,
+ blk64_t goal, int flags);
extern int ext2fs_default_journal_size(__u64 num_blocks);
/* openfs.c */
@@ -1356,6 +1383,11 @@ extern errcode_t ext2fs_open2(const char *name, const char *io_options,
int flags, int superblock,
unsigned int block_size, io_manager manager,
ext2_filsys *ret_fs);
+/*
+ * The dgrp_t argument to these two functions is not actually a group number
+ * but a block number offset within a group table! Convert with the formula
+ * (group_number / groups_per_block).
+ */
extern blk64_t ext2fs_descriptor_block_loc2(ext2_filsys fs,
blk64_t group_block, dgrp_t i);
extern blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block,
@@ -1374,6 +1406,10 @@ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name,
ext2_ino_t ino, int flags);
+/* symlink.c */
+errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino,
+ const char *name, char *target);
+
/* mmp.c */
errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf);
errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf);
@@ -1421,6 +1457,11 @@ extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t,
struct ext2_inode *f, int hostorder);
extern void ext2fs_swap_mmp(struct mmp_struct *mmp);
+/* unix_io.c */
+extern int ext2fs_open_file(const char *pathname, int flags, mode_t mode);
+extern int ext2fs_stat(const char *path, ext2fs_struct_stat *buf);
+extern int ext2fs_fstat(int fd, ext2fs_struct_stat *buf);
+
/* valid_blk.c */
extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode);
extern int ext2fs_inode_has_valid_blocks2(ext2_filsys fs,
@@ -1438,9 +1479,8 @@ extern errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list,
/* inline functions */
+#ifdef NO_INLINE_FUNCS
extern errcode_t ext2fs_get_mem(unsigned long size, void *ptr);
-extern errcode_t ext2fs_get_memalign(unsigned long size,
- unsigned long align, void *ptr);
extern errcode_t ext2fs_get_memzero(unsigned long size, void *ptr);
extern errcode_t ext2fs_get_array(unsigned long count,
unsigned long size, void *ptr);
@@ -1459,17 +1499,15 @@ extern void ext2fs_mark_ib_dirty(ext2_filsys fs);
extern void ext2fs_mark_bb_dirty(ext2_filsys fs);
extern int ext2fs_test_ib_dirty(ext2_filsys fs);
extern int ext2fs_test_bb_dirty(ext2_filsys fs);
-extern int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk);
-extern int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino);
+extern dgrp_t ext2fs_group_of_blk(ext2_filsys fs, blk_t blk);
+extern dgrp_t ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino);
extern blk_t ext2fs_group_first_block(ext2_filsys fs, dgrp_t group);
extern blk_t ext2fs_group_last_block(ext2_filsys fs, dgrp_t group);
extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
struct ext2_inode *inode);
extern unsigned int ext2fs_div_ceil(unsigned int a, unsigned int b);
extern __u64 ext2fs_div64_ceil(__u64 a, __u64 b);
-extern int ext2fs_open_file(const char *pathname, int flags, mode_t mode);
-extern int ext2fs_stat(const char *path, ext2fs_struct_stat *buf);
-extern int ext2fs_fstat(int fd, ext2fs_struct_stat *buf);
+#endif
/*
* The actual inlined functions definitions themselves...
@@ -1481,17 +1519,21 @@ extern int ext2fs_fstat(int fd, ext2fs_struct_stat *buf);
#ifdef INCLUDE_INLINE_FUNCS
#define _INLINE_ extern
#else
+#if (__STDC_VERSION__ >= 199901L)
+#define _INLINE_ inline
+#else
#ifdef __GNUC__
#define _INLINE_ extern __inline__
#else /* For Watcom C */
#define _INLINE_ extern inline
-#endif
+#endif /* __GNUC__ */
+#endif /* __STDC_VERSION__ >= 199901L */
#endif
#ifndef EXT2_CUSTOM_MEMORY_ROUTINES
#include <string.h>
/*
- * Allocate memory
+ * Allocate memory. The 'ptr' arg must point to a pointer.
*/
_INLINE_ errcode_t ext2fs_get_mem(unsigned long size, void *ptr)
{
@@ -1538,7 +1580,7 @@ _INLINE_ errcode_t ext2fs_get_arrayzero(unsigned long count,
}
/*
- * Free memory
+ * Free memory. The 'ptr' arg must point to a pointer.
*/
_INLINE_ errcode_t ext2fs_free_mem(void *ptr)
{
@@ -1552,7 +1594,7 @@ _INLINE_ errcode_t ext2fs_free_mem(void *ptr)
}
/*
- * Resize memory
+ * Resize memory. The 'ptr' arg must point to a pointer.
*/
_INLINE_ errcode_t ext2fs_resize_mem(unsigned long EXT2FS_ATTR((unused)) old_size,
unsigned long size, void *ptr)
@@ -1653,14 +1695,14 @@ _INLINE_ int ext2fs_test_bb_dirty(ext2_filsys fs)
/*
* Return the group # of a block
*/
-_INLINE_ int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk)
+_INLINE_ dgrp_t ext2fs_group_of_blk(ext2_filsys fs, blk_t blk)
{
return ext2fs_group_of_blk2(fs, blk);
}
/*
* Return the group # of an inode number
*/
-_INLINE_ int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino)
+_INLINE_ dgrp_t ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino)
{
return (ino - 1) / fs->super->s_inodes_per_group;
}
@@ -1670,7 +1712,7 @@ _INLINE_ int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino)
*/
_INLINE_ blk_t ext2fs_group_first_block(ext2_filsys fs, dgrp_t group)
{
- return ext2fs_group_first_block2(fs, group);
+ return (blk_t) ext2fs_group_first_block2(fs, group);
}
/*
@@ -1678,13 +1720,13 @@ _INLINE_ blk_t ext2fs_group_first_block(ext2_filsys fs, dgrp_t group)
*/
_INLINE_ blk_t ext2fs_group_last_block(ext2_filsys fs, dgrp_t group)
{
- return ext2fs_group_last_block2(fs, group);
+ return (blk_t) ext2fs_group_last_block2(fs, group);
}
_INLINE_ blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
struct ext2_inode *inode)
{
- return ext2fs_inode_data_blocks2(fs, inode);
+ return (blk_t) ext2fs_inode_data_blocks2(fs, inode);
}
/*
@@ -1704,40 +1746,6 @@ _INLINE_ __u64 ext2fs_div64_ceil(__u64 a, __u64 b)
return ((a - 1) / b) + 1;
}
-_INLINE_ int ext2fs_open_file(const char *pathname, int flags, mode_t mode)
-{
- va_list args;
-
- if (mode)
-#if defined(HAVE_OPEN64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
- return open64(pathname, flags, mode);
- else
- return open64(pathname, flags);
-#else
- return open(pathname, flags, mode);
- else
- return open(pathname, flags);
-#endif
-}
-
-_INLINE_ int ext2fs_stat(const char *path, ext2fs_struct_stat *buf)
-{
-#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
- return stat64(path, buf);
-#else
- return stat(path, buf);
-#endif
-}
-
-_INLINE_ int ext2fs_fstat(int fd, ext2fs_struct_stat *buf)
-{
-#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
- return fstat64(fd, buf);
-#else
- return fstat(fd, buf);
-#endif
-}
-
#undef _INLINE_
#endif
diff --git a/lib/ext2fs/ext2fs.pc.in b/lib/ext2fs/ext2fs.pc.in
index 8db86635..efac85e3 100644
--- a/lib/ext2fs/ext2fs.pc.in
+++ b/lib/ext2fs/ext2fs.pc.in
@@ -7,5 +7,5 @@ Name: ext2fs
Description: Ext2fs library
Version: @E2FSPROGS_VERSION@
Requires.private: com_err
-Cflags: -I${includedir}/ext2fs
+Cflags: -I${includedir}/ext2fs -I${includedir}
Libs: -L${libdir} -lext2fs
diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
index 729d5c53..a88db93e 100644
--- a/lib/ext2fs/ext2fsP.h
+++ b/lib/ext2fs/ext2fsP.h
@@ -66,7 +66,7 @@ struct dir_context {
*/
struct ext2_inode_cache {
void * buffer;
- blk_t buffer_blk;
+ blk64_t buffer_blk;
int cache_last;
int cache_size;
int refcount;
@@ -141,3 +141,7 @@ extern errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bitmap,
extern void ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap,const char *func);
extern int ext2fs_mem_is_zero(const char *mem, size_t len);
+
+extern int ext2fs_file_block_offset_too_big(ext2_filsys fs,
+ struct ext2_inode *inode,
+ blk64_t offset);
diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c
index eb096d6a..0bf82ea4 100644
--- a/lib/ext2fs/extent.c
+++ b/lib/ext2fs/extent.c
@@ -160,7 +160,7 @@ errcode_t ext2fs_extent_header_verify(void *ptr, int size)
/*
* Begin functions to handle an inode's extent information
*/
-extern void ext2fs_extent_free(ext2_extent_handle_t handle)
+void ext2fs_extent_free(ext2_extent_handle_t handle)
{
int i;
@@ -177,13 +177,13 @@ extern void ext2fs_extent_free(ext2_extent_handle_t handle)
ext2fs_free_mem(&handle);
}
-extern errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino,
+errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino,
ext2_extent_handle_t *ret_handle)
{
return ext2fs_extent_open2(fs, ino, NULL, ret_handle);
}
-extern errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
+errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
ext2_extent_handle_t *ret_handle)
{
@@ -604,8 +604,8 @@ errcode_t ext2fs_extent_free_path(ext2_extent_path_t path)
* If "blk" has no mapping (hole) then handle is left at last
* extent before blk.
*/
-static errcode_t extent_goto(ext2_extent_handle_t handle,
- int leaf_level, blk64_t blk)
+errcode_t ext2fs_extent_goto2(ext2_extent_handle_t handle,
+ int leaf_level, blk64_t blk)
{
struct ext2fs_extent extent;
errcode_t retval;
@@ -694,7 +694,7 @@ static errcode_t extent_goto(ext2_extent_handle_t handle,
errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
blk64_t blk)
{
- return extent_goto(handle, 0, blk);
+ return ext2fs_extent_goto2(handle, 0, blk);
}
/*
@@ -706,12 +706,14 @@ errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
* Safe to call for any position in node; if not at the first entry,
* will simply return.
*/
-static errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle)
+errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle)
{
int retval = 0;
+ int orig_height;
blk64_t start;
struct extent_path *path;
struct ext2fs_extent extent;
+ struct ext2_extent_info info;
EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
@@ -732,6 +734,10 @@ static errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle)
/* modified node's start block */
start = extent.e_lblk;
+ if ((retval = ext2fs_extent_get_info(handle, &info)))
+ return retval;
+ orig_height = info.max_depth - info.curr_level;
+
/* traverse up until index not first, or startblk matches, or top */
while (handle->level > 0 &&
(path->left == path->entries - 1)) {
@@ -750,7 +756,7 @@ static errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle)
}
/* put handle back to where we started */
- retval = ext2fs_extent_goto(handle, start);
+ retval = ext2fs_extent_goto2(handle, orig_height, start);
done:
return retval;
}
@@ -813,7 +819,7 @@ errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle,
*
* handle will be left pointing at original record.
*/
-static errcode_t extent_node_split(ext2_extent_handle_t handle)
+errcode_t ext2fs_extent_node_split(ext2_extent_handle_t handle)
{
errcode_t retval = 0;
blk64_t new_node_pblk;
@@ -868,12 +874,12 @@ static errcode_t extent_node_split(ext2_extent_handle_t handle)
goto done;
goal_blk = extent.e_pblk;
- retval = extent_node_split(handle);
+ retval = ext2fs_extent_node_split(handle);
if (retval)
goto done;
/* get handle back to our original split position */
- retval = extent_goto(handle, orig_height, orig_lblk);
+ retval = ext2fs_extent_goto2(handle, orig_height, orig_lblk);
if (retval)
goto done;
}
@@ -928,8 +934,7 @@ static errcode_t extent_node_split(ext2_extent_handle_t handle)
if (log_flex)
group = group & ~((1 << (log_flex)) - 1);
- goal_blk = (group * handle->fs->super->s_blocks_per_group) +
- handle->fs->super->s_first_data_block;
+ goal_blk = ext2fs_group_first_block2(handle->fs, group);
}
retval = ext2fs_alloc_block2(handle->fs, goal_blk, block_buf,
&new_node_pblk);
@@ -1022,12 +1027,13 @@ static errcode_t extent_node_split(ext2_extent_handle_t handle)
}
/* get handle back to our original position */
- retval = extent_goto(handle, orig_height, orig_lblk);
+ retval = ext2fs_extent_goto2(handle, orig_height, orig_lblk);
if (retval)
goto done;
/* new node hooked in, so update inode block count (do this here?) */
- handle->inode->i_blocks += handle->fs->blocksize / 512;
+ handle->inode->i_blocks += (handle->fs->blocksize *
+ EXT2FS_CLUSTER_RATIO(handle->fs)) / 512;
retval = ext2fs_write_inode(handle->fs, handle->ino,
handle->inode);
if (retval)
@@ -1072,7 +1078,7 @@ errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags,
printf("node full (level %d) - splitting\n",
handle->level);
#endif
- retval = extent_node_split(handle);
+ retval = ext2fs_extent_node_split(handle);
if (retval)
return retval;
path = handle->path + handle->level;
@@ -1086,8 +1092,10 @@ errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags,
ix++;
path->left--;
}
- } else
+ } else {
ix = EXT_FIRST_INDEX(eh);
+ path->left = -1;
+ }
path->curr = ix;
@@ -1351,6 +1359,9 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
&next_extent);
if (retval)
goto done;
+ retval = ext2fs_extent_fix_parents(handle);
+ if (retval)
+ goto done;
} else
retval = ext2fs_extent_insert(handle,
EXT2_EXTENT_INSERT_AFTER, &newextent);
@@ -1403,15 +1414,22 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
retval = ext2fs_extent_replace(handle, 0, &extent);
if (retval)
goto done;
+ retval = ext2fs_extent_fix_parents(handle);
+ if (retval)
+ goto done;
} else {
__u32 orig_length;
+ blk64_t orig_lblk;
+ struct ext2fs_extent orig_extent;
+ errcode_t r2;
#ifdef DEBUG
printf("(re/un)mapping in middle of extent\n");
#endif
/* need to split this extent; later */
-
+ orig_lblk = extent.e_lblk;
orig_length = extent.e_len;
+ orig_extent = extent;
/* shorten pre-split extent */
extent.e_len = (logical - extent.e_lblk);
@@ -1423,8 +1441,13 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
/* insert new extent after current */
retval = ext2fs_extent_insert(handle,
EXT2_EXTENT_INSERT_AFTER, &newextent);
- if (retval)
+ if (retval) {
+ r2 = ext2fs_extent_goto(handle, orig_lblk);
+ if (r2 == 0)
+ ext2fs_extent_replace(handle, 0,
+ &orig_extent);
goto done;
+ }
}
/* add post-split extent */
extent.e_pblk += extent.e_len + 1;
@@ -1432,15 +1455,25 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
extent.e_len = orig_length - extent.e_len - 1;
retval = ext2fs_extent_insert(handle,
EXT2_EXTENT_INSERT_AFTER, &extent);
- if (retval)
+ if (retval) {
+ if (physical) {
+ r2 = ext2fs_extent_goto(handle,
+ newextent.e_lblk);
+ if (r2 == 0)
+ ext2fs_extent_delete(handle, 0);
+ }
+ r2 = ext2fs_extent_goto(handle, orig_lblk);
+ if (r2 == 0)
+ ext2fs_extent_replace(handle, 0, &orig_extent);
goto done;
+ }
}
done:
/* get handle back to its position */
if (orig_height > handle->max_depth)
orig_height = handle->max_depth; /* In case we shortened the tree */
- extent_goto(handle, orig_height, orig_lblk);
+ ext2fs_extent_goto2(handle, orig_height, orig_lblk);
return retval;
}
@@ -1501,7 +1534,9 @@ errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, int flags)
return retval;
retval = ext2fs_extent_delete(handle, flags);
- handle->inode->i_blocks -= handle->fs->blocksize / 512;
+ handle->inode->i_blocks -=
+ (handle->fs->blocksize *
+ EXT2FS_CLUSTER_RATIO(handle->fs)) / 512;
retval = ext2fs_write_inode(handle->fs, handle->ino,
handle->inode);
ext2fs_block_alloc_stats2(handle->fs,
@@ -1550,460 +1585,10 @@ errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle,
}
#ifdef DEBUG
-
-#include "ss/ss.h"
-
-#include "debugfs.h"
-
/*
- * Hook in new commands into debugfs
+ * Override debugfs's prompt
*/
const char *debug_prog_name = "tst_extents";
-extern ss_request_table extent_cmds;
-ss_request_table *extra_cmds = &extent_cmds;
-
-ext2_ino_t current_ino = 0;
-ext2_extent_handle_t current_handle;
-
-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;
-}
-
-void do_inode(int argc, char *argv[])
-{
- ext2_ino_t inode;
- int i;
- struct ext3_extent_header *eh;
- errcode_t retval;
-
- 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;
-
- printf("Loaded inode %d\n", current_ino);
-
- return;
-}
-
-void generic_goto_node(char *cmd_name, int op)
-{
- struct ext2fs_extent extent;
- errcode_t retval;
-
- if (check_fs_open(cmd_name))
- return;
-
- if (!current_handle) {
- com_err(cmd_name, 0, "Extent handle not open");
- return;
- }
-
- retval = ext2fs_extent_get(current_handle, op, &extent);
- if (retval) {
- com_err(cmd_name, retval, 0);
- return;
- }
- dbg_print_extent(0, &extent);
-}
-
-void do_current_node(int argc, char *argv[])
-{
- generic_goto_node(argv[0], EXT2_EXTENT_CURRENT);
-}
-
-void do_root_node(int argc, char *argv[])
-{
- generic_goto_node(argv[0], EXT2_EXTENT_ROOT);
-}
-
-void do_last_leaf(int argc, char *argv[])
-{
- generic_goto_node(argv[0], EXT2_EXTENT_LAST_LEAF);
-}
-
-void do_first_sib(int argc, char *argv[])
-{
- generic_goto_node(argv[0], EXT2_EXTENT_FIRST_SIB);
-}
-
-void do_last_sib(int argc, char *argv[])
-{
- generic_goto_node(argv[0], EXT2_EXTENT_LAST_SIB);
-}
-
-void do_next_sib(int argc, char *argv[])
-{
- generic_goto_node(argv[0], EXT2_EXTENT_NEXT_SIB);
-}
-
-void do_prev_sib(int argc, char *argv[])
-{
- generic_goto_node(argv[0], EXT2_EXTENT_PREV_SIB);
-}
-
-void do_next_leaf(int argc, char *argv[])
-{
- generic_goto_node(argv[0], EXT2_EXTENT_NEXT_LEAF);
-}
-
-void do_prev_leaf(int argc, char *argv[])
-{
- generic_goto_node(argv[0], EXT2_EXTENT_PREV_LEAF);
-}
-
-void do_next(int argc, char *argv[])
-{
- generic_goto_node(argv[0], EXT2_EXTENT_NEXT);
-}
-
-void do_prev(int argc, char *argv[])
-{
- generic_goto_node(argv[0], EXT2_EXTENT_PREV);
-}
-
-void do_up(int argc, char *argv[])
-{
- generic_goto_node(argv[0], EXT2_EXTENT_UP);
-}
-
-void do_down(int argc, char *argv[])
-{
- generic_goto_node(argv[0], EXT2_EXTENT_DOWN);
-}
-
-void do_delete_node(int argc, char *argv[])
-{
- errcode_t retval;
- int err;
-
- 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;
- }
- if (current_handle->path && current_handle->path[0].curr)
- do_current_node(argc, argv);
-}
-
-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;
- }
-
- extent.e_lblk = parse_ulong(argv[1], argv[0], "logical block", &err);
- if (err)
- return;
-
- extent.e_len = parse_ulong(argv[2], argv[0], "logical block", &err);
- if (err)
- return;
-
- extent.e_pblk = parse_ulong(argv[3], argv[0], "logical block", &err);
- if (err)
- return;
-
- retval = ext2fs_extent_replace(current_handle, 0, &extent);
- if (retval) {
- com_err(argv[0], retval, 0);
- return;
- }
- do_current_node(argc, argv);
-}
-
-void do_split_node(int argc, char *argv[])
-{
- errcode_t retval;
- struct ext2fs_extent extent;
- int err;
-
- if (common_extent_args_process(argc, argv, 1, 1, "split_node",
- "", CHECK_FS_RW | CHECK_FS_BITMAPS))
- return;
- retval = extent_node_split(current_handle);
- if (retval) {
- com_err(argv[0], retval, 0);
- return;
- }
- do_current_node(argc, argv);
-}
-
-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;
- }
-
- extent.e_lblk = parse_ulong(argv[1], cmd,
- "logical block", &err);
- if (err)
- return;
-
- extent.e_len = parse_ulong(argv[2], cmd,
- "length", &err);
- if (err)
- return;
-
- extent.e_pblk = parse_ulong(argv[3], cmd,
- "pysical block", &err);
- if (err)
- return;
-
- retval = ext2fs_extent_insert(current_handle, flags, &extent);
- if (retval) {
- com_err(cmd, retval, 0);
- return;
- }
- do_current_node(argc, argv);
-}
-
-void do_set_bmap(int argc, char **argv)
-{
- const char *usage = "[--uninit] <lblk> <pblk>";
- errcode_t retval;
- blk_t logical;
- blk_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;
- }
-
- logical = parse_ulong(argv[1], cmd,
- "logical block", &err);
- if (err)
- return;
-
- physical = parse_ulong(argv[2], cmd,
- "physical block", &err);
- if (err)
- return;
-
- retval = ext2fs_extent_set_bmap(current_handle, logical,
- (blk64_t) physical, flags);
- if (retval) {
- com_err(cmd, retval, 0);
- return;
- }
- if (current_handle->path && current_handle->path[0].curr)
- do_current_node(argc, argv);
-}
-
-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_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)
-{
- struct ext2fs_extent extent;
- errcode_t retval;
- int op = EXT2_EXTENT_NEXT_LEAF;
- 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], &blk))
- return;
-
- if (argc == 3) {
- level = parse_ulong(argv[2], argv[0], "level", &err);
- if (err)
- return;
- }
-
- retval = extent_goto(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(argv[0], EXT2_EXTENT_CURRENT);
-}
#endif
diff --git a/lib/ext2fs/extent_dbg.ct b/lib/ext2fs/extent_dbg.ct
deleted file mode 100644
index d0571f47..00000000
--- a/lib/ext2fs/extent_dbg.ct
+++ /dev/null
@@ -1,74 +0,0 @@
-#
-# 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_inode, "Open an inode",
- inode;
-
-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_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;
-
-end;
-
diff --git a/lib/ext2fs/fiemap.h b/lib/ext2fs/fiemap.h
index 30bf5555..895cd0ba 100644
--- a/lib/ext2fs/fiemap.h
+++ b/lib/ext2fs/fiemap.h
@@ -64,5 +64,7 @@ struct fiemap {
#define FIEMAP_EXTENT_MERGED 0x00001000 /* File does not natively
* support extents. Result
* merged for efficiency. */
+#define FIEMAP_EXTENT_SHARED 0x00002000 /* Space shared with other
+ * files. */
#endif /* _LINUX_FIEMAP_H */
diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c
index 1f7002cd..5a39c321 100644
--- a/lib/ext2fs/fileio.c
+++ b/lib/ext2fs/fileio.c
@@ -18,6 +18,7 @@
#include "ext2_fs.h"
#include "ext2fs.h"
+#include "ext2fsP.h"
struct ext2_file {
errcode_t magic;
@@ -142,8 +143,7 @@ errcode_t ext2fs_file_flush(ext2_file_t file)
return retval;
}
- retval = io_channel_write_blk(fs->io, file->physblock,
- 1, file->buf);
+ retval = io_channel_write_blk64(fs->io, file->physblock, 1, file->buf);
if (retval)
return retval;
@@ -158,7 +158,7 @@ errcode_t ext2fs_file_flush(ext2_file_t file)
*/
static errcode_t sync_buffer_position(ext2_file_t file)
{
- blk_t b;
+ blk64_t b;
errcode_t retval;
b = file->pos / file->fs->blocksize;
@@ -194,9 +194,9 @@ static errcode_t load_buffer(ext2_file_t file, int dontfill)
return retval;
if (!dontfill) {
if (file->physblock) {
- retval = io_channel_read_blk(fs->io,
- file->physblock,
- 1, file->buf);
+ retval = io_channel_read_blk64(fs->io,
+ file->physblock,
+ 1, file->buf);
if (retval)
return retval;
} else
@@ -298,6 +298,20 @@ errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
if (retval)
goto fail;
+ /*
+ * OK, the physical block hasn't been allocated yet.
+ * Allocate it.
+ */
+ if (!file->physblock) {
+ retval = ext2fs_bmap2(fs, file->ino, &file->inode,
+ BMAP_BUFFER,
+ file->ino ? BMAP_ALLOC : 0,
+ file->blockno, 0,
+ &file->physblock);
+ if (retval)
+ goto fail;
+ }
+
file->flags |= EXT2_FILE_BUF_DIRTY;
memcpy(file->buf+start, ptr, c);
file->pos += c;
@@ -307,6 +321,15 @@ errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
}
fail:
+ /* Update inode size */
+ if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) {
+ errcode_t rc;
+
+ rc = ext2fs_file_set_size2(file, file->pos);
+ if (retval == 0)
+ retval = rc;
+ }
+
if (written)
*written = count;
return retval;
@@ -371,6 +394,53 @@ ext2_off_t ext2fs_file_get_size(ext2_file_t file)
return size;
}
+/* Zero the parts of the last block that are past EOF. */
+static errcode_t ext2fs_file_zero_past_offset(ext2_file_t file,
+ ext2_off64_t offset)
+{
+ ext2_filsys fs = file->fs;
+ char *b = NULL;
+ ext2_off64_t off = offset % fs->blocksize;
+ blk64_t blk;
+ int ret_flags;
+ errcode_t retval;
+
+ if (off == 0)
+ return 0;
+
+ retval = sync_buffer_position(file);
+ if (retval)
+ return retval;
+
+ /* Is there an initialized block at the end? */
+ retval = ext2fs_bmap2(fs, file->ino, NULL, NULL, 0,
+ offset / fs->blocksize, &ret_flags, &blk);
+ if (retval)
+ return retval;
+ if ((blk == 0) || (ret_flags & BMAP_RET_UNINIT))
+ return 0;
+
+ /* Zero to the end of the block */
+ retval = ext2fs_get_mem(fs->blocksize, &b);
+ if (retval)
+ return retval;
+
+ /* Read/zero/write block */
+ retval = io_channel_read_blk64(fs->io, blk, 1, b);
+ if (retval)
+ goto out;
+
+ memset(b + off, 0, fs->blocksize - off);
+
+ retval = io_channel_write_blk64(fs->io, blk, 1, b);
+ if (retval)
+ goto out;
+
+out:
+ ext2fs_free_mem(&b);
+ return retval;
+}
+
/*
* This function sets the size of the file, truncating it if necessary
*
@@ -383,11 +453,26 @@ errcode_t ext2fs_file_set_size2(ext2_file_t file, ext2_off64_t size)
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+ if (size && ext2fs_file_block_offset_too_big(file->fs, &file->inode,
+ (size - 1) / file->fs->blocksize))
+ return EXT2_ET_FILE_TOO_BIG;
truncate_block = ((size + file->fs->blocksize - 1) >>
- EXT2_BLOCK_SIZE_BITS(file->fs->super)) + 1;
+ EXT2_BLOCK_SIZE_BITS(file->fs->super));
old_size = EXT2_I_SIZE(&file->inode);
old_truncate = ((old_size + file->fs->blocksize - 1) >>
- EXT2_BLOCK_SIZE_BITS(file->fs->super)) + 1;
+ EXT2_BLOCK_SIZE_BITS(file->fs->super));
+
+ /* If we're writing a large file, set the large_file flag */
+ if (LINUX_S_ISREG(file->inode.i_mode) &&
+ ext2fs_needs_large_file_feature(EXT2_I_SIZE(&file->inode)) &&
+ (!EXT2_HAS_RO_COMPAT_FEATURE(file->fs->super,
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE) ||
+ file->fs->super->s_rev_level == EXT2_GOOD_OLD_REV)) {
+ file->fs->super->s_feature_ro_compat |=
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
+ ext2fs_update_dynamic_rev(file->fs);
+ ext2fs_mark_super_dirty(file->fs);
+ }
file->inode.i_size = size & 0xffffffff;
file->inode.i_size_high = (size >> 32);
@@ -397,6 +482,10 @@ errcode_t ext2fs_file_set_size2(ext2_file_t file, ext2_off64_t size)
return retval;
}
+ retval = ext2fs_file_zero_past_offset(file, size);
+ if (retval)
+ return retval;
+
if (truncate_block >= old_truncate)
return 0;
diff --git a/lib/ext2fs/flushb.c b/lib/ext2fs/flushb.c
index ac8923cb..98821fc7 100644
--- a/lib/ext2fs/flushb.c
+++ b/lib/ext2fs/flushb.c
@@ -70,7 +70,7 @@ errcode_t ext2fs_sync_device(int fd, int flushb)
#warning BLKFLSBUF not defined
#endif
#ifdef FDFLUSH
- ioctl (fd, FDFLUSH, 0); /* In case this is a floppy */
+ return ioctl(fd, FDFLUSH, 0); /* In case this is a floppy */
#elif defined(__linux__)
#warning FDFLUSH not defined
#endif
diff --git a/lib/ext2fs/freefs.c b/lib/ext2fs/freefs.c
index 28c4132f..1ad2d916 100644
--- a/lib/ext2fs/freefs.c
+++ b/lib/ext2fs/freefs.c
@@ -43,6 +43,8 @@ void ext2fs_free(ext2_filsys fs)
ext2fs_free_block_bitmap(fs->block_map);
if (fs->inode_map)
ext2fs_free_inode_bitmap(fs->inode_map);
+ if (fs->image_header)
+ ext2fs_free_mem(&fs->image_header);
if (fs->badblocks)
ext2fs_badblocks_list_free(fs->badblocks);
diff --git a/lib/ext2fs/gen_bitmap.c b/lib/ext2fs/gen_bitmap.c
index 6679bffa..6cd6fe63 100644
--- a/lib/ext2fs/gen_bitmap.c
+++ b/lib/ext2fs/gen_bitmap.c
@@ -504,6 +504,52 @@ static int ext2fs_test_clear_generic_bitmap_range(ext2fs_generic_bitmap bitmap,
return ext2fs_mem_is_zero(ADDR + start_byte, len_byte);
}
+errcode_t ext2fs_find_first_zero_generic_bitmap(ext2fs_generic_bitmap bitmap,
+ __u32 start, __u32 end,
+ __u32 *out)
+{
+ blk_t b;
+
+ if (start < bitmap->start || end > bitmap->end || start > end) {
+ ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
+ return EINVAL;
+ }
+
+ while (start <= end) {
+ b = ext2fs_test_bit(start - bitmap->start, bitmap->bitmap);
+ if (!b) {
+ *out = start;
+ return 0;
+ }
+ start++;
+ }
+
+ return ENOENT;
+}
+
+errcode_t ext2fs_find_first_set_generic_bitmap(ext2fs_generic_bitmap bitmap,
+ __u32 start, __u32 end,
+ __u32 *out)
+{
+ blk_t b;
+
+ if (start < bitmap->start || end > bitmap->end || start > end) {
+ ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
+ return EINVAL;
+ }
+
+ while (start <= end) {
+ b = ext2fs_test_bit(start - bitmap->start, bitmap->bitmap);
+ if (b) {
+ *out = start;
+ return 0;
+ }
+ start++;
+ }
+
+ return ENOENT;
+}
+
int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
blk_t block, int num)
{
@@ -558,3 +604,4 @@ void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
ext2fs_fast_clear_bit(block + i - bitmap->start,
bitmap->bitmap);
}
+
diff --git a/lib/ext2fs/gen_bitmap64.c b/lib/ext2fs/gen_bitmap64.c
index b57df546..af550972 100644
--- a/lib/ext2fs/gen_bitmap64.c
+++ b/lib/ext2fs/gen_bitmap64.c
@@ -128,6 +128,7 @@ errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
if (gettimeofday(&bitmap->stats.created,
(struct timezone *) NULL) == -1) {
perror("gettimeofday");
+ ext2fs_free_mem(&bitmap);
return 1;
}
bitmap->stats.type = type;
@@ -174,11 +175,13 @@ errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
}
#ifdef BMAP_STATS
-void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap bitmap)
+static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap bitmap)
{
struct ext2_bmap_statistics *stats = &bitmap->stats;
+#ifdef BMAP_STATS_OPS
float mark_seq_perc = 0.0, test_seq_perc = 0.0;
float mark_back_perc = 0.0, test_back_perc = 0.0;
+#endif
double inuse;
struct timeval now;
@@ -298,6 +301,7 @@ errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src,
if (gettimeofday(&new_bmap->stats.created,
(struct timezone *) NULL) == -1) {
perror("gettimeofday");
+ ext2fs_free_mem(&new_bmap);
return 1;
}
new_bmap->stats.type = src->stats.type;
@@ -622,6 +626,8 @@ void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap)
int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap,
blk64_t block, unsigned int num)
{
+ __u64 end = block + num;
+
if (!bmap)
return EINVAL;
@@ -644,12 +650,26 @@ int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap,
INC_STAT(bmap, test_ext_count);
+ /* convert to clusters if necessary */
+ block >>= bmap->cluster_bits;
+ end += (1 << bmap->cluster_bits) - 1;
+ end >>= bmap->cluster_bits;
+ num = end - block;
+
+ if ((block < bmap->start) || (block+num-1 > bmap->end)) {
+ ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, block,
+ bmap->description);
+ return EINVAL;
+ }
+
return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num);
}
void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap,
blk64_t block, unsigned int num)
{
+ __u64 end = block + num;
+
if (!bmap)
return;
@@ -668,6 +688,12 @@ void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap,
INC_STAT(bmap, mark_ext_count);
+ /* convert to clusters if necessary */
+ block >>= bmap->cluster_bits;
+ end += (1 << bmap->cluster_bits) - 1;
+ end >>= bmap->cluster_bits;
+ num = end - block;
+
if ((block < bmap->start) || (block+num-1 > bmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
bmap->description);
@@ -680,6 +706,8 @@ void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap,
void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap,
blk64_t block, unsigned int num)
{
+ __u64 end = block + num;
+
if (!bmap)
return;
@@ -698,6 +726,12 @@ void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap,
INC_STAT(bmap, unmark_ext_count);
+ /* convert to clusters if necessary */
+ block >>= bmap->cluster_bits;
+ end += (1 << bmap->cluster_bits) - 1;
+ end >>= bmap->cluster_bits;
+ num = end - block;
+
if ((block < bmap->start) || (block+num-1 > bmap->end)) {
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
bmap->description);
@@ -766,27 +800,107 @@ errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs,
errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap,
__u64 start, __u64 end, __u64 *out)
{
- int b;
+ __u64 cstart, cend, cout;
+ errcode_t retval;
- if (bitmap->bitmap_ops->find_first_zero)
- return bitmap->bitmap_ops->find_first_zero(bitmap, start, end, out);
+ if (!bitmap)
+ return EINVAL;
+
+ if (EXT2FS_IS_32_BITMAP(bitmap)) {
+ blk_t blk = 0;
- if (!bitmap || !EXT2FS_IS_64_BITMAP(bitmap) || bitmap->cluster_bits)
+ if (((start) & ~0xffffffffULL) ||
+ ((end) & ~0xffffffffULL)) {
+ ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
+ return EINVAL;
+ }
+
+ retval = ext2fs_find_first_zero_generic_bitmap(bitmap, start,
+ end, &blk);
+ if (retval == 0)
+ *out = blk;
+ return retval;
+ }
+
+ if (!EXT2FS_IS_64_BITMAP(bitmap))
return EINVAL;
- if (start < bitmap->start || end > bitmap->end || start > end) {
+ cstart = start >> bitmap->cluster_bits;
+ cend = end >> bitmap->cluster_bits;
+
+ if (cstart < bitmap->start || cend > bitmap->end || start > end) {
warn_bitmap(bitmap, EXT2FS_TEST_ERROR, start);
return EINVAL;
}
- while (start <= end) {
- b = bitmap->bitmap_ops->test_bmap(bitmap, start);
- if (!b) {
- *out = start;
- return 0;
+ if (bitmap->bitmap_ops->find_first_zero) {
+ retval = bitmap->bitmap_ops->find_first_zero(bitmap, cstart,
+ cend, &cout);
+ if (retval)
+ return retval;
+ found:
+ cout <<= bitmap->cluster_bits;
+ *out = (cout >= start) ? cout : start;
+ return 0;
+ }
+
+ for (cout = cstart; cout <= cend; cout++)
+ if (!bitmap->bitmap_ops->test_bmap(bitmap, cout))
+ goto found;
+
+ return ENOENT;
+}
+
+errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap,
+ __u64 start, __u64 end, __u64 *out)
+{
+ __u64 cstart, cend, cout;
+ errcode_t retval;
+
+ if (!bitmap)
+ return EINVAL;
+
+ if (EXT2FS_IS_32_BITMAP(bitmap)) {
+ blk_t blk = 0;
+
+ if (((start) & ~0xffffffffULL) ||
+ ((end) & ~0xffffffffULL)) {
+ ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
+ return EINVAL;
}
- start++;
+
+ retval = ext2fs_find_first_set_generic_bitmap(bitmap, start,
+ end, &blk);
+ if (retval == 0)
+ *out = blk;
+ return retval;
}
+ if (!EXT2FS_IS_64_BITMAP(bitmap))
+ return EINVAL;
+
+ cstart = start >> bitmap->cluster_bits;
+ cend = end >> bitmap->cluster_bits;
+
+ if (cstart < bitmap->start || cend > bitmap->end || start > end) {
+ warn_bitmap(bitmap, EXT2FS_TEST_ERROR, start);
+ return EINVAL;
+ }
+
+ if (bitmap->bitmap_ops->find_first_set) {
+ retval = bitmap->bitmap_ops->find_first_set(bitmap, cstart,
+ cend, &cout);
+ if (retval)
+ return retval;
+ found:
+ cout <<= bitmap->cluster_bits;
+ *out = (cout >= start) ? cout : start;
+ return 0;
+ }
+
+ for (cout = cstart; cout <= cend; cout++)
+ if (bitmap->bitmap_ops->test_bmap(bitmap, cout))
+ goto found;
+
return ENOENT;
}
diff --git a/lib/ext2fs/get_pathname.c b/lib/ext2fs/get_pathname.c
index 33209949..52aea624 100644
--- a/lib/ext2fs/get_pathname.c
+++ b/lib/ext2fs/get_pathname.c
@@ -100,16 +100,16 @@ static errcode_t ext2fs_get_pathname_int(ext2_filsys fs, ext2_ino_t dir,
retval = ext2fs_dir_iterate(fs, dir, 0, buf, get_pathname_proc, &gp);
if (retval == EXT2_ET_NO_DIRECTORY) {
- char buf[32];
+ char tmp[32];
if (ino)
- snprintf(buf, sizeof(buf), "<%u>/<%u>", dir, ino);
+ snprintf(tmp, sizeof(tmp), "<%u>/<%u>", dir, ino);
else
- snprintf(buf, sizeof(buf), "<%u>", dir);
- retval = ext2fs_get_mem(strlen(buf)+1, name);
+ snprintf(tmp, sizeof(tmp), "<%u>", dir);
+ retval = ext2fs_get_mem(strlen(tmp)+1, name);
if (retval)
goto cleanup;
- strcpy(*name, buf);
+ strcpy(*name, tmp);
return 0;
} else if (retval)
goto cleanup;
diff --git a/lib/ext2fs/getsectsize.c b/lib/ext2fs/getsectsize.c
index 30faecc7..9c3f4a2e 100644
--- a/lib/ext2fs/getsectsize.c
+++ b/lib/ext2fs/getsectsize.c
@@ -62,6 +62,32 @@ errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize)
}
/*
+ * Return desired alignment for direct I/O
+ */
+int ext2fs_get_dio_alignment(int fd)
+{
+ int align = 0;
+
+#ifdef BLKSSZGET
+ if (ioctl(fd, BLKSSZGET, &align) < 0)
+ align = 0;
+#endif
+
+#ifdef _SC_PAGESIZE
+ if (align <= 0)
+ align = sysconf(_SC_PAGESIZE);
+#endif
+#ifdef HAVE_GETPAGESIZE
+ if (align <= 0)
+ align = getpagesize();
+#endif
+ if (align <= 0)
+ align = 4096;
+
+ return align;
+}
+
+/*
* Returns the physical sector size of a device
*/
errcode_t ext2fs_get_device_phys_sectsize(const char *file, int *sectsize)
diff --git a/lib/ext2fs/getsize.c b/lib/ext2fs/getsize.c
index 0a7053e3..a9a4812e 100644
--- a/lib/ext2fs/getsize.c
+++ b/lib/ext2fs/getsize.c
@@ -140,25 +140,11 @@ static int valid_offset (int fd, ext2_loff_t offset)
* Returns the number of blocks in a partition
*/
errcode_t ext2fs_get_device_size2(const char *file, int blocksize,
- blk64_t *retblocks)
+ blk64_t *retblocks)
{
int fd, rc = 0;
- int valid_blkgetsize64 = 1;
-#ifdef __linux__
- struct utsname ut;
-#endif
unsigned long long size64;
- unsigned long size;
ext2_loff_t high, low;
-#ifdef FDGETPRM
- struct floppy_struct this_floppy;
-#endif
-#ifdef HAVE_SYS_DISKLABEL_H
- int part;
- struct disklabel lab;
- struct partition *pp;
- char ch;
-#endif /* HAVE_SYS_DISKLABEL_H */
fd = ext2fs_open_file(file, O_RDONLY, 0);
if (fd < 0)
@@ -172,63 +158,83 @@ errcode_t ext2fs_get_device_size2(const char *file, int blocksize,
#endif
#ifdef BLKGETSIZE64
+ {
+ int valid_blkgetsize64 = 1;
#ifdef __linux__
- if ((uname(&ut) == 0) &&
- ((ut.release[0] == '2') && (ut.release[1] == '.') &&
- (ut.release[2] < '6') && (ut.release[3] == '.')))
- valid_blkgetsize64 = 0;
+ struct utsname ut;
+
+ if ((uname(&ut) == 0) &&
+ ((ut.release[0] == '2') && (ut.release[1] == '.') &&
+ (ut.release[2] < '6') && (ut.release[3] == '.')))
+ valid_blkgetsize64 = 0;
#endif
- if (valid_blkgetsize64 &&
- ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
- *retblocks = size64 / blocksize;
- goto out;
+ if (valid_blkgetsize64 &&
+ ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
+ *retblocks = size64 / blocksize;
+ goto out;
+ }
}
#endif /* BLKGETSIZE64 */
#ifdef BLKGETSIZE
- if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
- *retblocks = size / (blocksize / 512);
- goto out;
+ {
+ unsigned long size;
+
+ if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
+ *retblocks = size / (blocksize / 512);
+ goto out;
+ }
}
#endif
#ifdef FDGETPRM
- if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
- *retblocks = this_floppy.size / (blocksize / 512);
- goto out;
+ {
+ struct floppy_struct this_floppy;
+
+ if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
+ *retblocks = this_floppy.size / (blocksize / 512);
+ goto out;
+ }
}
#endif
#ifdef HAVE_SYS_DISKLABEL_H
-#if defined(DIOCGMEDIASIZE)
{
- off_t ms;
- u_int bs;
- if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) {
- *retblocks = ms / blocksize;
- goto out;
- }
- }
+ int part;
+ struct disklabel lab;
+ struct partition *pp;
+ char ch;
+
+#if defined(DIOCGMEDIASIZE)
+ {
+ off_t ms;
+ u_int bs;
+ if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) {
+ *retblocks = ms / blocksize;
+ goto out;
+ }
+ }
#elif defined(DIOCGDINFO)
- /* old disklabel interface */
- part = strlen(file) - 1;
- if (part >= 0) {
- ch = file[part];
- if (isdigit(ch))
- part = 0;
- else if (ch >= 'a' && ch <= 'h')
- part = ch - 'a';
- else
- part = -1;
- }
- if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
- pp = &lab.d_partitions[part];
- if (pp->p_size) {
- *retblocks = pp->p_size / (blocksize / 512);
- goto out;
+ /* old disklabel interface */
+ part = strlen(file) - 1;
+ if (part >= 0) {
+ ch = file[part];
+ if (isdigit(ch))
+ part = 0;
+ else if (ch >= 'a' && ch <= 'h')
+ part = ch - 'a';
+ else
+ part = -1;
+ }
+ if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
+ pp = &lab.d_partitions[part];
+ if (pp->p_size) {
+ *retblocks = pp->p_size / (blocksize / 512);
+ goto out;
+ }
}
- }
#endif /* defined(DIOCG*) */
+ }
#endif /* HAVE_SYS_DISKLABEL_H */
{
@@ -247,10 +253,9 @@ errcode_t ext2fs_get_device_size2(const char *file, int blocksize,
* find the size of the partition.
*/
low = 0;
- for (high = 1024; valid_offset (fd, high); high *= 2)
+ for (high = 1024; valid_offset(fd, high); high *= 2)
low = high;
- while (low < high - 1)
- {
+ while (low < high - 1) {
const ext2_loff_t mid = (low + high) / 2;
if (valid_offset (fd, mid))
@@ -258,7 +263,7 @@ errcode_t ext2fs_get_device_size2(const char *file, int blocksize,
else
high = mid;
}
- valid_offset (fd, 0);
+ valid_offset(fd, 0);
size64 = low + 1;
*retblocks = size64 / blocksize;
out:
diff --git a/lib/ext2fs/icount.c b/lib/ext2fs/icount.c
index 8b46eda4..a3b20f06 100644
--- a/lib/ext2fs/icount.c
+++ b/lib/ext2fs/icount.c
@@ -181,6 +181,7 @@ errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir,
errcode_t retval;
char *fn, uuid[40];
ext2_ino_t num_inodes;
+ mode_t save_umask;
int fd;
retval = alloc_icount(fs, flags, &icount);
@@ -192,8 +193,14 @@ errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir,
goto errout;
uuid_unparse(fs->super->s_uuid, uuid);
sprintf(fn, "%s/%s-icount-XXXXXX", tdb_dir, uuid);
+ icount->tdb_fn = fn;
+ save_umask = umask(077);
fd = mkstemp(fn);
-
+ if (fd < 0) {
+ retval = errno;
+ goto errout;
+ }
+ umask(save_umask);
/*
* This is an overestimate of the size that we will need; the
* ideal value is the number of used inodes with a count
@@ -204,18 +211,15 @@ errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir,
*/
num_inodes = fs->super->s_inodes_count - fs->super->s_free_inodes_count;
- icount->tdb_fn = fn;
icount->tdb = tdb_open(fn, num_inodes, TDB_NOLOCK | TDB_NOSYNC,
O_RDWR | O_CREAT | O_TRUNC, 0600);
- if (icount->tdb) {
- close(fd);
- *ret = icount;
- return 0;
- }
-
- retval = errno;
close(fd);
-
+ if (icount->tdb == NULL) {
+ retval = errno;
+ goto errout;
+ }
+ *ret = icount;
+ return 0;
errout:
ext2fs_free_icount(icount);
return(retval);
@@ -351,9 +355,7 @@ static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount,
static struct ext2_icount_el *get_icount_el(ext2_icount_t icount,
ext2_ino_t ino, int create)
{
- float range;
int low, high, mid;
- ext2_ino_t lowval, highval;
if (!icount || !icount->list)
return 0;
diff --git a/lib/ext2fs/imager.c b/lib/ext2fs/imager.c
index a0fb81e4..378a3c88 100644
--- a/lib/ext2fs/imager.c
+++ b/lib/ext2fs/imager.c
@@ -66,6 +66,7 @@ errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
blk64_t blk;
ssize_t actual;
errcode_t retval;
+ off_t r;
buf = malloc(fs->blocksize * BUF_BLOCKS);
if (!buf)
@@ -97,7 +98,11 @@ errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
blk++;
left--;
cp += fs->blocksize;
- lseek(fd, fs->blocksize, SEEK_CUR);
+ r = lseek(fd, fs->blocksize, SEEK_CUR);
+ if (r < 0) {
+ retval = errno;
+ goto errout;
+ }
continue;
}
/* Find non-zero blocks */
@@ -279,7 +284,7 @@ errout:
errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
{
ext2fs_generic_bitmap bmap;
- errcode_t err, retval;
+ errcode_t retval;
ssize_t actual;
__u32 itr, cnt, size;
int c, total_size;
@@ -292,7 +297,6 @@ errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
return retval;
}
bmap = fs->inode_map;
- err = EXT2_ET_MAGIC_INODE_BITMAP;
itr = 1;
cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
@@ -303,7 +307,6 @@ errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
return retval;
}
bmap = fs->block_map;
- err = EXT2_ET_MAGIC_BLOCK_BITMAP;
itr = fs->super->s_first_data_block;
cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
@@ -356,7 +359,7 @@ errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
{
ext2fs_generic_bitmap bmap;
- errcode_t err, retval;
+ errcode_t retval;
__u32 itr, cnt;
char buf[1024];
unsigned int size;
@@ -369,7 +372,6 @@ errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
return retval;
}
bmap = fs->inode_map;
- err = EXT2_ET_MAGIC_INODE_BITMAP;
itr = 1;
cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
@@ -380,7 +382,6 @@ errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
return retval;
}
bmap = fs->block_map;
- err = EXT2_ET_MAGIC_BLOCK_BITMAP;
itr = fs->super->s_first_data_block;
cnt = EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count;
size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
index b06371cf..36c94a9a 100644
--- a/lib/ext2fs/initialize.c
+++ b/lib/ext2fs/initialize.c
@@ -98,8 +98,10 @@ errcode_t ext2fs_initialize(const char *name, int flags,
int csum_flag;
int bigalloc_flag;
int io_flags;
+ unsigned reserved_inos;
char *buf = 0;
char c;
+ double reserved_ratio;
if (!param || !ext2fs_blocks_count(param))
return EXT2_ET_INVALID_ARGUMENT;
@@ -171,6 +173,8 @@ errcode_t ext2fs_initialize(const char *name, int flags,
set_field(s_raid_stripe_width, 0); /* default stripe width: 0 */
set_field(s_log_groups_per_flex, 0);
set_field(s_flags, 0);
+ assign_field(s_backup_bgs[0]);
+ assign_field(s_backup_bgs[1]);
if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
retval = EXT2_ET_UNSUPP_FEATURE;
goto cleanup;
@@ -205,6 +209,8 @@ errcode_t ext2fs_initialize(const char *name, int flags,
super->s_log_block_size;
if (bigalloc_flag) {
+ unsigned long long bpg;
+
if (param->s_blocks_per_group &&
param->s_clusters_per_group &&
((param->s_clusters_per_group * EXT2FS_CLUSTER_RATIO(fs)) !=
@@ -218,12 +224,19 @@ errcode_t ext2fs_initialize(const char *name, int flags,
super->s_clusters_per_group =
param->s_blocks_per_group /
EXT2FS_CLUSTER_RATIO(fs);
- else
+ else if (super->s_log_cluster_size + 15 < 32)
super->s_clusters_per_group = fs->blocksize * 8;
+ else
+ super->s_clusters_per_group = (fs->blocksize - 1) * 8;
if (super->s_clusters_per_group > EXT2_MAX_CLUSTERS_PER_GROUP(super))
super->s_clusters_per_group = EXT2_MAX_CLUSTERS_PER_GROUP(super);
- super->s_blocks_per_group = EXT2FS_C2B(fs,
- super->s_clusters_per_group);
+ bpg = EXT2FS_C2B(fs,
+ (unsigned long long) super->s_clusters_per_group);
+ if (bpg >= (((unsigned long long) 1) << 32)) {
+ retval = EXT2_ET_INVALID_ARGUMENT;
+ goto cleanup;
+ }
+ super->s_blocks_per_group = bpg;
} else {
set_field(s_blocks_per_group, fs->blocksize * 8);
if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super))
@@ -239,6 +252,8 @@ errcode_t ext2fs_initialize(const char *name, int flags,
goto cleanup;
}
+ set_field(s_mmp_update_interval, 0);
+
/*
* If we're creating an external journal device, we don't need
* to bother with the rest.
@@ -259,8 +274,9 @@ retry:
goto cleanup;
}
- if (super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)
- super->s_desc_size = EXT2_MIN_DESC_SIZE_64BIT;
+ set_field(s_desc_size,
+ super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT ?
+ EXT2_MIN_DESC_SIZE_64BIT : 0);
fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
EXT2_DESC_PER_BLOCK(super));
@@ -390,6 +406,14 @@ ipg_retry:
if (rem && (rem < overhead+50)) {
ext2fs_blocks_count_set(super, ext2fs_blocks_count(super) -
rem);
+ /*
+ * If blocks count is changed, we need to recalculate
+ * reserved blocks count not to exceed 50%.
+ */
+ reserved_ratio = 100.0 * ext2fs_r_blocks_count(param) /
+ ext2fs_blocks_count(param);
+ ext2fs_r_blocks_count_set(super, reserved_ratio *
+ ext2fs_blocks_count(super) / 100.0);
goto retry;
}
@@ -400,6 +424,21 @@ ipg_retry:
* count.
*/
+ /* Set up the locations of the backup superblocks */
+ if (super->s_feature_compat & EXT4_FEATURE_COMPAT_SPARSE_SUPER2) {
+ if (super->s_backup_bgs[0] >= fs->group_desc_count)
+ super->s_backup_bgs[0] = fs->group_desc_count - 1;
+ if (super->s_backup_bgs[1] >= fs->group_desc_count)
+ super->s_backup_bgs[1] = fs->group_desc_count - 1;
+ if (super->s_backup_bgs[0] == super->s_backup_bgs[1])
+ super->s_backup_bgs[1] = 0;
+ if (super->s_backup_bgs[0] > super->s_backup_bgs[1]) {
+ __u32 t = super->s_backup_bgs[0];
+ super->s_backup_bgs[0] = super->s_backup_bgs[1];
+ super->s_backup_bgs[1] = t;
+ }
+ }
+
retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
if (retval)
goto cleanup;
@@ -439,6 +478,7 @@ ipg_retry:
free_blocks = 0;
csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+ reserved_inos = super->s_first_ino;
for (i = 0; i < fs->group_desc_count; i++) {
/*
* Don't set the BLOCK_UNINIT group for the last group
@@ -450,8 +490,15 @@ ipg_retry:
EXT2_BG_BLOCK_UNINIT);
ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT);
numblocks = super->s_inodes_per_group;
- if (i == 0)
- numblocks -= super->s_first_ino;
+ if (reserved_inos) {
+ if (numblocks > reserved_inos) {
+ numblocks -= reserved_inos;
+ reserved_inos = 0;
+ } else {
+ reserved_inos -= numblocks;
+ numblocks = 0;
+ }
+ }
ext2fs_bg_itable_unused_set(fs, i, numblocks);
}
numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map);
diff --git a/lib/ext2fs/inline.c b/lib/ext2fs/inline.c
index ad0c3683..05da1f79 100644
--- a/lib/ext2fs/inline.c
+++ b/lib/ext2fs/inline.c
@@ -11,6 +11,9 @@
* %End-Header%
*/
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 600 /* for posix_memalign() */
+#endif
#include "config.h"
#include <stdio.h>
@@ -45,7 +48,7 @@ errcode_t ext2fs_get_memalign(unsigned long size,
errcode_t retval;
void **p = ptr;
- if (align == 0)
+ if (align < 8)
align = 8;
#ifdef HAVE_POSIX_MEMALIGN
retval = posix_memalign(p, align, size);
@@ -64,9 +67,55 @@ errcode_t ext2fs_get_memalign(unsigned long size,
return EXT2_ET_NO_MEMORY;
}
#else
-#error memalign or posix_memalign must be defined!
+#ifdef HAVE_VALLOC
+ if (align > sizeof(long long))
+ *p = valloc(size);
+ else
+#endif
+ *p = malloc(size);
+ if ((unsigned long) *p & (align - 1)) {
+ free(*p);
+ *p = 0;
+ }
+ if (*p == 0)
+ return EXT2_ET_NO_MEMORY;
#endif
#endif
return 0;
}
+#ifdef DEBUG
+static int isaligned(void *ptr, unsigned long align)
+{
+ return (((unsigned long) ptr & (align - 1)) == 0);
+}
+
+static errcode_t test_memalign(unsigned long align)
+{
+ void *ptr = 0;
+ errcode_t retval;
+
+ retval = ext2fs_get_memalign(32, align, &ptr);
+ if (!retval && !isaligned(ptr, align))
+ retval = EINVAL;
+ free(ptr);
+ printf("tst_memalign(%lu) is %s\n", align,
+ retval ? error_message(retval) : "OK");
+ return retval;
+}
+
+int main(int argc, char **argv)
+{
+ int err = 0;
+
+ if (test_memalign(4))
+ err++;
+ if (test_memalign(32))
+ err++;
+ if (test_memalign(1024))
+ err++;
+ if (test_memalign(4096))
+ err++;
+ return err;
+}
+#endif
diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
index 6c524ff2..573a8fa5 100644
--- a/lib/ext2fs/inode.c
+++ b/lib/ext2fs/inode.c
@@ -157,8 +157,8 @@ errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
(fs->blocksize / scan->inode_size - 1)) *
scan->inode_size / fs->blocksize;
}
- retval = ext2fs_get_memalign(scan->inode_buffer_blocks * fs->blocksize,
- fs->blocksize, &scan->inode_buffer);
+ retval = io_channel_alloc_buf(fs->io, scan->inode_buffer_blocks,
+ &scan->inode_buffer);
scan->done_group = 0;
scan->done_group_data = 0;
scan->bad_block_ptr = 0;
@@ -270,9 +270,9 @@ errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
* increasing order.
*/
static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
- blk_t *num_blocks)
+ blk64_t *num_blocks)
{
- blk_t blk = scan->current_block;
+ blk64_t blk = scan->current_block;
badblocks_list bb = scan->fs->badblocks;
/*
@@ -329,7 +329,7 @@ static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
*/
static errcode_t get_next_blocks(ext2_inode_scan scan)
{
- blk_t num_blocks;
+ blk64_t num_blocks;
errcode_t retval;
/*
@@ -533,7 +533,9 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
/* Check to see if user has an override function */
- if (fs->read_inode) {
+ if (fs->read_inode &&
+ ((bufsize == sizeof(struct ext2_inode)) ||
+ (EXT2_INODE_SIZE(fs->super) == sizeof(struct ext2_inode)))) {
retval = (fs->read_inode)(fs, ino, inode);
if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
return retval;
diff --git a/lib/ext2fs/io_manager.c b/lib/ext2fs/io_manager.c
index 25df59ec..34e48592 100644
--- a/lib/ext2fs/io_manager.c
+++ b/lib/ext2fs/io_manager.c
@@ -111,3 +111,20 @@ errcode_t io_channel_discard(io_channel channel, unsigned long long block,
return EXT2_ET_UNIMPLEMENTED;
}
+
+errcode_t io_channel_alloc_buf(io_channel io, int count, void *ptr)
+{
+ size_t size;
+
+ if (count == 0)
+ size = io->block_size;
+ else if (count > 0)
+ size = io->block_size * count;
+ else
+ size = -count;
+
+ if (io->align)
+ return ext2fs_get_memalign(size, io->align, ptr);
+ else
+ return ext2fs_get_mem(size, ptr);
+}
diff --git a/lib/ext2fs/irel.h b/lib/ext2fs/irel.h
index 9a4958be..8aaa2d2b 100644
--- a/lib/ext2fs/irel.h
+++ b/lib/ext2fs/irel.h
@@ -10,7 +10,7 @@
*/
struct ext2_inode_reference {
- blk_t block;
+ blk64_t block;
__u16 offset;
};
diff --git a/lib/ext2fs/ismounted.c b/lib/ext2fs/ismounted.c
index 823eb3fe..6c6ecff0 100644
--- a/lib/ext2fs/ismounted.c
+++ b/lib/ext2fs/ismounted.c
@@ -21,6 +21,13 @@
#ifdef HAVE_LINUX_FD_H
#include <linux/fd.h>
#endif
+#ifdef HAVE_LINUX_LOOP_H
+#include <linux/loop.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_LINUX_MAJOR_H
+#include <linux/major.h>
+#endif /* HAVE_LINUX_MAJOR_H */
+#endif /* HAVE_LINUX_LOOP_H */
#ifdef HAVE_MNTENT_H
#include <mntent.h>
#endif
@@ -35,7 +42,37 @@
#include "ext2_fs.h"
#include "ext2fs.h"
-#ifdef HAVE_MNTENT_H
+/*
+ * Check to see if a regular file is mounted.
+ * If /etc/mtab/ is a symlink of /proc/mounts, you will need the following check
+ * because the name in /proc/mounts is a loopback device not a regular file.
+ */
+static int check_loop_mounted(const char *mnt_fsname, dev_t mnt_rdev,
+ dev_t file_dev, ino_t file_ino)
+{
+#if defined(HAVE_LINUX_LOOP_H) && defined(HAVE_LINUX_MAJOR_H)
+ struct loop_info64 loopinfo;
+ int loop_fd, ret;
+
+ if (major(mnt_rdev) == LOOP_MAJOR) {
+ loop_fd = open(mnt_fsname, O_RDONLY);
+ if (loop_fd < 0)
+ return -1;
+
+ ret = ioctl(loop_fd, LOOP_GET_STATUS64, &loopinfo);
+ close(loop_fd);
+ if (ret < 0)
+ return -1;
+
+ if (file_dev == loopinfo.lo_device &&
+ file_ino == loopinfo.lo_inode)
+ return 1;
+ }
+#endif /* defined(HAVE_LINUX_LOOP_H) && defined(HAVE_LINUX_MAJOR_H) */
+ return 0;
+}
+
+#ifdef HAVE_SETMNTENT
/*
* Helper function which checks a file in /etc/mtab format to see if a
* filesystem is mounted. Returns an error if the file doesn't exist
@@ -53,8 +90,15 @@ static errcode_t check_mntent_file(const char *mtab_file, const char *file,
int fd;
*mount_flags = 0;
- if ((f = setmntent (mtab_file, "r")) == NULL)
- return (errno == ENOENT ? EXT2_NO_MTAB_FILE : errno);
+ if ((f = setmntent (mtab_file, "r")) == NULL) {
+ if (errno == ENOENT) {
+ if (getenv("EXT2FS_NO_MTAB_OK"))
+ return 0;
+ else
+ return EXT2_ET_NO_MTAB_FILE;
+ }
+ return errno;
+ }
if (stat(file, &st_buf) == 0) {
if (S_ISBLK(st_buf.st_mode)) {
#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
@@ -75,6 +119,10 @@ static errcode_t check_mntent_file(const char *mtab_file, const char *file,
#ifndef __GNU__
if (file_rdev && (file_rdev == st_buf.st_rdev))
break;
+ if (check_loop_mounted(mnt->mnt_fsname,
+ st_buf.st_rdev, file_dev,
+ file_ino) == 1)
+ break;
#endif /* __GNU__ */
} else {
if (file_dev && ((file_dev == st_buf.st_dev) &&
@@ -231,7 +279,7 @@ static errcode_t check_getmntinfo(const char *file, int *mount_flags,
return 0;
}
#endif /* HAVE_GETMNTINFO */
-#endif /* HAVE_MNTENT_H */
+#endif /* HAVE_SETMNTENT */
/*
* Check to see if we're dealing with the swap device.
@@ -302,15 +350,13 @@ leave:
errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
char *mtpt, int mtlen)
{
- struct stat st_buf;
errcode_t retval = 0;
- int fd;
if (is_swap_device(device)) {
*mount_flags = EXT2_MF_MOUNTED | EXT2_MF_SWAP;
strncpy(mtpt, "<swap>", mtlen);
} else {
-#ifdef HAVE_MNTENT_H
+#ifdef HAVE_SETMNTENT
retval = check_mntent(device, mount_flags, mtpt, mtlen);
#else
#ifdef HAVE_GETMNTINFO
@@ -321,21 +367,24 @@ errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
#endif
*mount_flags = 0;
#endif /* HAVE_GETMNTINFO */
-#endif /* HAVE_MNTENT_H */
+#endif /* HAVE_SETMNTENT */
}
if (retval)
return retval;
#ifdef __linux__ /* This only works on Linux 2.6+ systems */
- if ((stat(device, &st_buf) != 0) ||
- !S_ISBLK(st_buf.st_mode))
- return 0;
- fd = open(device, O_RDONLY | O_EXCL);
- if (fd < 0) {
- if (errno == EBUSY)
- *mount_flags |= EXT2_MF_BUSY;
- } else
- close(fd);
+ {
+ struct stat st_buf;
+
+ if (stat(device, &st_buf) == 0 && S_ISBLK(st_buf.st_mode)) {
+ int fd = open(device, O_RDONLY | O_EXCL);
+
+ if (fd >= 0)
+ close(fd);
+ else if (errno == EBUSY)
+ *mount_flags |= EXT2_MF_BUSY;
+ }
+ }
#endif
return 0;
diff --git a/lib/ext2fs/kernel-jbd.h b/lib/ext2fs/kernel-jbd.h
index 066c031e..059bf8fa 100644
--- a/lib/ext2fs/kernel-jbd.h
+++ b/lib/ext2fs/kernel-jbd.h
@@ -214,13 +214,13 @@ typedef struct journal_superblock_s
#define JFS_HAS_COMPAT_FEATURE(j,mask) \
((j)->j_format_version >= 2 && \
- ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask))))
+ ((j)->j_superblock->s_feature_compat & ext2fs_cpu_to_be32((mask))))
#define JFS_HAS_RO_COMPAT_FEATURE(j,mask) \
((j)->j_format_version >= 2 && \
- ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask))))
+ ((j)->j_superblock->s_feature_ro_compat & ext2fs_cpu_to_be32((mask))))
#define JFS_HAS_INCOMPAT_FEATURE(j,mask) \
((j)->j_format_version >= 2 && \
- ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask))))
+ ((j)->j_superblock->s_feature_incompat & ext2fs_cpu_to_be32((mask))))
#define JFS_FEATURE_COMPAT_CHECKSUM 0x00000001
diff --git a/lib/ext2fs/kernel-list.h b/lib/ext2fs/kernel-list.h
index e07d06b6..01f4f6b9 100644
--- a/lib/ext2fs/kernel-list.h
+++ b/lib/ext2fs/kernel-list.h
@@ -17,9 +17,6 @@ struct list_head {
#define LIST_HEAD_INIT(name) { &(name), &(name) }
-#define LIST_HEAD(name) \
- struct list_head name = { &name, &name }
-
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c
index 2d03b573..bf3c859a 100644
--- a/lib/ext2fs/link.c
+++ b/lib/ext2fs/link.c
@@ -42,6 +42,9 @@ static int link_proc(struct ext2_dir_entry *dirent,
unsigned int rec_len, min_rec_len, curr_rec_len;
int ret = 0;
+ if (ls->done)
+ return DIRENT_ABORT;
+
rec_len = EXT2_DIR_REC_LEN(ls->namelen);
ls->err = ext2fs_get_rec_len(ls->fs, dirent, &curr_rec_len);
diff --git a/lib/ext2fs/llseek.c b/lib/ext2fs/llseek.c
index b0576e40..c3a98a2c 100644
--- a/lib/ext2fs/llseek.c
+++ b/lib/ext2fs/llseek.c
@@ -90,17 +90,14 @@ static ext2_loff_t my_llseek (int fd, ext2_loff_t offset, int origin)
ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin)
{
+#if SIZEOF_OFF_T >= SIZEOF_LONG_LONG
+ return lseek (fd, offset, origin);
+#else
ext2_loff_t result;
static int do_compat = 0;
- if ((sizeof(off_t) >= sizeof(ext2_loff_t)) ||
- (offset < ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1))))
- return lseek(fd, (off_t) offset, origin);
-
- if (do_compat) {
- errno = EINVAL;
- return -1;
- }
+ if (do_compat)
+ goto fallback;
result = my_llseek (fd, offset, origin);
if (result == -1 && errno == ENOSYS) {
@@ -109,9 +106,14 @@ ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin)
* which does not support the llseek system call
*/
do_compat++;
+ fallback:
+ if (offset < ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))
+ return lseek(fd, (off_t) offset, origin);
errno = EINVAL;
+ return -1;
}
return result;
+#endif
}
#else /* !linux */
diff --git a/lib/ext2fs/mkjournal.c b/lib/ext2fs/mkjournal.c
index 838d751c..884d9c07 100644
--- a/lib/ext2fs/mkjournal.c
+++ b/lib/ext2fs/mkjournal.c
@@ -250,6 +250,7 @@ static int mkjournal_proc(ext2_filsys fs,
es->err = retval;
return BLOCK_ABORT;
}
+ ext2fs_block_alloc_stats2(fs, new_blk, +1);
es->newblocks++;
}
if (blockcnt >= 0)
@@ -285,7 +286,6 @@ static int mkjournal_proc(ext2_filsys fs,
return BLOCK_ABORT;
}
*blocknr = es->goal = new_blk;
- ext2fs_block_alloc_stats2(fs, new_blk, +1);
if (es->num_blocks == 0)
return (BLOCK_CHANGED | BLOCK_ABORT);
@@ -295,13 +295,43 @@ static int mkjournal_proc(ext2_filsys fs,
}
/*
+ * Calculate the initial goal block to be roughly at the middle of the
+ * filesystem. Pick a group that has the largest number of free
+ * blocks.
+ */
+static blk64_t get_midpoint_journal_block(ext2_filsys fs)
+{
+ dgrp_t group, start, end, i, log_flex;
+
+ group = ext2fs_group_of_blk2(fs, (ext2fs_blocks_count(fs->super) -
+ fs->super->s_first_data_block) / 2);
+ log_flex = 1 << fs->super->s_log_groups_per_flex;
+ if (fs->super->s_log_groups_per_flex && (group > log_flex)) {
+ group = group & ~(log_flex - 1);
+ while ((group < fs->group_desc_count) &&
+ ext2fs_bg_free_blocks_count(fs, group) == 0)
+ group++;
+ if (group == fs->group_desc_count)
+ group = 0;
+ start = group;
+ } else
+ start = (group > 0) ? group-1 : group;
+ end = ((group+1) < fs->group_desc_count) ? group+1 : group;
+ group = start;
+ for (i = start + 1; i <= end; i++)
+ if (ext2fs_bg_free_blocks_count(fs, i) >
+ ext2fs_bg_free_blocks_count(fs, group))
+ group = i;
+ return ext2fs_group_first_block2(fs, group);
+}
+
+/*
* This function creates a journal using direct I/O routines.
*/
static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
- blk_t num_blocks, int flags)
+ blk_t num_blocks, blk64_t goal, int flags)
{
char *buf;
- dgrp_t group, start, end, i, log_flex;
errcode_t retval;
struct ext2_inode inode;
unsigned long long inode_size;
@@ -312,13 +342,15 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
return retval;
if ((retval = ext2fs_read_bitmaps(fs)))
- return retval;
+ goto out2;
if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
- return retval;
+ goto out2;
- if (inode.i_blocks > 0)
- return EEXIST;
+ if (inode.i_blocks > 0) {
+ retval = EEXIST;
+ goto out2;
+ }
es.num_blocks = num_blocks;
es.newblocks = 0;
@@ -326,41 +358,14 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
es.err = 0;
es.flags = flags;
es.zero_count = 0;
+ es.goal = (goal != ~0ULL) ? goal : get_midpoint_journal_block(fs);
if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
inode.i_flags |= EXT4_EXTENTS_FL;
if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
- return retval;
+ goto out2;
}
- /*
- * Set the initial goal block to be roughly at the middle of
- * the filesystem. Pick a group that has the largest number
- * of free blocks.
- */
- group = ext2fs_group_of_blk2(fs, (ext2fs_blocks_count(fs->super) -
- fs->super->s_first_data_block) / 2);
- log_flex = 1 << fs->super->s_log_groups_per_flex;
- if (fs->super->s_log_groups_per_flex && (group > log_flex)) {
- group = group & ~(log_flex - 1);
- while ((group < fs->group_desc_count) &&
- ext2fs_bg_free_blocks_count(fs, group) == 0)
- group++;
- if (group == fs->group_desc_count)
- group = 0;
- start = group;
- } else
- start = (group > 0) ? group-1 : group;
- end = ((group+1) < fs->group_desc_count) ? group+1 : group;
- group = start;
- for (i=start+1; i <= end; i++)
- if (ext2fs_bg_free_blocks_count(fs, i) >
- ext2fs_bg_free_blocks_count(fs, group))
- group = i;
-
- es.goal = (fs->super->s_blocks_per_group * group) +
- fs->super->s_first_data_block;
-
retval = ext2fs_block_iterate3(fs, journal_ino, BLOCK_FLAG_APPEND,
0, mkjournal_proc, &es);
if (es.err) {
@@ -380,7 +385,7 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
inode_size = (unsigned long long)fs->blocksize * num_blocks;
inode.i_size = inode_size & 0xFFFFFFFF;
inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF;
- if (inode.i_size_high)
+ if (ext2fs_needs_large_file_feature(inode_size))
fs->super->s_feature_ro_compat |=
EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
@@ -400,6 +405,7 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
errout:
ext2fs_zero_blocks2(0, 0, 0, 0, 0);
+out2:
ext2fs_free_mem(&buf);
return retval;
}
@@ -490,20 +496,27 @@ errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
* POSIX routines if the filesystem is mounted, or using direct I/O
* functions if it is not.
*/
-errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags)
+errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks,
+ blk64_t goal, int flags)
{
errcode_t retval;
ext2_ino_t journal_ino;
struct stat st;
char jfile[1024];
- int mount_flags, f;
+ int mount_flags;
int fd = -1;
- if ((retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
- jfile, sizeof(jfile)-10)))
+ if (flags & EXT2_MKJOURNAL_NO_MNT_CHECK)
+ mount_flags = 0;
+ else if ((retval = ext2fs_check_mount_point(fs->device_name,
+ &mount_flags,
+ jfile, sizeof(jfile)-10)))
return retval;
if (mount_flags & EXT2_MF_MOUNTED) {
+#if HAVE_EXT2_IOCTLS
+ int f = 0;
+#endif
strcat(jfile, "/.journal");
/*
@@ -516,9 +529,10 @@ errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags)
#if HAVE_EXT2_IOCTLS
fd = open(jfile, O_RDONLY);
if (fd >= 0) {
- f = 0;
- ioctl(fd, EXT2_IOC_SETFLAGS, &f);
+ retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
close(fd);
+ if (retval)
+ return retval;
}
#endif
#endif
@@ -574,7 +588,7 @@ errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags)
}
journal_ino = EXT2_JOURNAL_INO;
if ((retval = write_journal_inode(fs, journal_ino,
- num_blocks, flags)))
+ num_blocks, goal, flags)))
return retval;
}
@@ -587,11 +601,17 @@ errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags)
ext2fs_mark_super_dirty(fs);
return 0;
errout:
- if (fd > 0)
+ if (fd >= 0)
close(fd);
return retval;
}
+errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags)
+{
+ return ext2fs_add_journal_inode2(fs, num_blocks, ~0ULL, flags);
+}
+
+
#ifdef DEBUG
main(int argc, char **argv)
{
@@ -612,7 +632,7 @@ main(int argc, char **argv)
exit(1);
}
- retval = ext2fs_add_journal_inode(fs, 1024);
+ retval = ext2fs_add_journal_inode(fs, 1024, 0);
if (retval) {
com_err(argv[0], retval, "while adding journal to %s",
device_name);
diff --git a/lib/ext2fs/mmp.c b/lib/ext2fs/mmp.c
index 49a11da9..e4c7dccd 100644
--- a/lib/ext2fs/mmp.c
+++ b/lib/ext2fs/mmp.c
@@ -4,8 +4,8 @@
* Copyright (C) 2011 Whamcloud, Inc.
*
* %Begin-Header%
- * This file may be redistributed under the terms of the GNU Public
- * License.
+ * This file may be redistributed under the terms of the GNU Library
+ * General Public License, version 2.
* %End-Header%
*/
@@ -27,20 +27,6 @@
#include "ext2fs/ext2_fs.h"
#include "ext2fs/ext2fs.h"
-static int mmp_pagesize(void)
-{
-#ifdef _SC_PAGESIZE
- int sysval = sysconf(_SC_PAGESIZE);
- if (sysval > 0)
- return sysval;
-#endif /* _SC_PAGESIZE */
-#ifdef HAVE_GETPAGESIZE
- return getpagesize();
-#else
- return 4096;
-#endif
-}
-
#ifndef O_DIRECT
#define O_DIRECT 0
#endif
@@ -51,23 +37,9 @@ errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf)
errcode_t retval = 0;
if ((mmp_blk <= fs->super->s_first_data_block) ||
- (mmp_blk >= fs->super->s_blocks_count))
+ (mmp_blk >= ext2fs_blocks_count(fs->super)))
return EXT2_ET_MMP_BAD_BLOCK;
- if (fs->mmp_cmp == NULL) {
- /* O_DIRECT in linux 2.4: page aligned
- * O_DIRECT in linux 2.6: sector aligned
- * A filesystem cannot be created with blocksize < sector size,
- * or with blocksize > page_size. */
- int bufsize = fs->blocksize;
-
- if (bufsize < mmp_pagesize())
- bufsize = mmp_pagesize();
- retval = ext2fs_get_memalign(bufsize, bufsize, &fs->mmp_cmp);
- if (retval)
- return retval;
- }
-
/* ext2fs_open() reserves fd0,1,2 to avoid stdio collision, so checking
* mmp_fd <= 0 is OK to validate that the fd is valid. This opens its
* own fd to read the MMP block to ensure that it is using O_DIRECT,
@@ -81,7 +53,17 @@ errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf)
}
}
- if (ext2fs_llseek(fs->mmp_fd, mmp_blk * fs->blocksize, SEEK_SET) !=
+ if (fs->mmp_cmp == NULL) {
+ int align = ext2fs_get_dio_alignment(fs->mmp_fd);
+
+ retval = ext2fs_get_memalign(fs->blocksize, align,
+ &fs->mmp_cmp);
+ if (retval)
+ return retval;
+ }
+
+ if ((blk64_t) ext2fs_llseek(fs->mmp_fd, mmp_blk * fs->blocksize,
+ SEEK_SET) !=
mmp_blk * fs->blocksize) {
retval = EXT2_ET_LLSEEK_FAILED;
goto out;
@@ -145,7 +127,7 @@ errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf)
#define rand() random()
#endif
-unsigned ext2fs_mmp_new_seq()
+unsigned ext2fs_mmp_new_seq(void)
{
unsigned new_seq;
struct timeval tv;
diff --git a/lib/ext2fs/namei.c b/lib/ext2fs/namei.c
index efcc02b7..307aecc8 100644
--- a/lib/ext2fs/namei.c
+++ b/lib/ext2fs/namei.c
@@ -34,6 +34,7 @@ static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
char *buffer = 0;
errcode_t retval;
struct ext2_inode ei;
+ blk64_t blk;
#ifdef NAMEI_DEBUG
printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n",
@@ -49,12 +50,16 @@ static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
if (link_count++ >= EXT2FS_MAX_NESTED_LINKS)
return EXT2_ET_SYMLINK_LOOP;
- /* FIXME-64: Actually, this is FIXME EXTENTS */
if (ext2fs_inode_data_blocks(fs,&ei)) {
+ retval = ext2fs_bmap2(fs, inode, &ei, NULL, 0, 0, NULL, &blk);
+ if (retval)
+ return retval;
+
retval = ext2fs_get_mem(fs->blocksize, &buffer);
if (retval)
return retval;
- retval = io_channel_read_blk(fs->io, ei.i_block[0], 1, buffer);
+
+ retval = io_channel_read_blk64(fs->io, blk, 1, buffer);
if (retval) {
ext2fs_free_mem(&buffer);
return retval;
diff --git a/lib/ext2fs/newdir.c b/lib/ext2fs/newdir.c
index b0a1e476..3e2c0dbe 100644
--- a/lib/ext2fs/newdir.c
+++ b/lib/ext2fs/newdir.c
@@ -44,8 +44,10 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
dir = (struct ext2_dir_entry *) buf;
retval = ext2fs_set_rec_len(fs, fs->blocksize, dir);
- if (retval)
+ if (retval) {
+ ext2fs_free_mem(&buf);
return retval;
+ }
if (dir_ino) {
if (fs->super->s_feature_incompat &
@@ -65,8 +67,10 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
*/
dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
retval = ext2fs_set_rec_len(fs, rec_len, dir);
- if (retval)
+ if (retval) {
+ ext2fs_free_mem(&buf);
return retval;
+ }
dir->inode = parent_ino;
dir->name_len = 2 | filetype;
dir->name[0] = '.';
diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c
index 220d954b..a1a35176 100644
--- a/lib/ext2fs/openfs.c
+++ b/lib/ext2fs/openfs.c
@@ -37,17 +37,24 @@ blk64_t ext2fs_descriptor_block_loc2(ext2_filsys fs, blk64_t group_block,
dgrp_t i)
{
int bg;
- int has_super = 0;
+ int has_super = 0, group_zero_adjust = 0;
blk64_t ret_blk;
+ /*
+ * On a bigalloc FS with 1K blocks, block 0 is reserved for non-ext4
+ * stuff, so adjust for that if we're being asked for group 0.
+ */
+ if (i == 0 && fs->blocksize == 1024 && EXT2FS_CLUSTER_RATIO(fs) > 1)
+ group_zero_adjust = 1;
+
if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
(i < fs->super->s_first_meta_bg))
- return (group_block + i + 1);
+ return group_block + i + 1 + group_zero_adjust;
bg = EXT2_DESC_PER_BLOCK(fs->super) * i;
if (ext2fs_bg_has_super(fs, bg))
has_super = 1;
- ret_blk = ext2fs_group_first_block2(fs, bg) + has_super;
+ ret_blk = ext2fs_group_first_block2(fs, bg);
/*
* If group_block is not the normal value, we're trying to use
* the backup group descriptors and superblock --- so use the
@@ -57,10 +64,21 @@ blk64_t ext2fs_descriptor_block_loc2(ext2_filsys fs, blk64_t group_block,
* have the infrastructure in place to do that.
*/
if (group_block != fs->super->s_first_data_block &&
- ((ret_blk + fs->super->s_blocks_per_group) <
- ext2fs_blocks_count(fs->super)))
+ ((ret_blk + has_super + fs->super->s_blocks_per_group) <
+ ext2fs_blocks_count(fs->super))) {
ret_blk += fs->super->s_blocks_per_group;
- return ret_blk;
+
+ /*
+ * If we're going to jump forward a block group, make sure
+ * that we adjust has_super to account for the next group's
+ * backup superblock (or lack thereof).
+ */
+ if (ext2fs_bg_has_super(fs, bg + 1))
+ has_super = 1;
+ else
+ has_super = 0;
+ }
+ return ret_blk + has_super + group_zero_adjust;
}
blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i)
@@ -99,10 +117,12 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
errcode_t retval;
unsigned long i, first_meta_bg;
__u32 features;
- unsigned int groups_per_block, blocks_per_group, io_flags;
+ unsigned int blocks_per_group, io_flags;
blk64_t group_block, blk;
char *dest, *cp;
+ int group_zero_adjust = 0;
#ifdef WORDS_BIGENDIAN
+ unsigned int groups_per_block;
struct ext2_group_desc *gdp;
int j;
#endif
@@ -144,7 +164,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
goto cleanup;
fs->image_io = fs->io;
fs->io->app_data = fs;
- retval = ext2fs_get_memalign(SUPERBLOCK_SIZE, 512, &fs->super);
+ retval = io_channel_alloc_buf(fs->io, -SUPERBLOCK_SIZE, &fs->super);
if (retval)
goto cleanup;
if (flags & EXT2_FLAG_IMAGE_FILE) {
@@ -252,6 +272,18 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
retval = EXT2_ET_CORRUPT_SUPERBLOCK;
goto cleanup;
}
+
+ /*
+ * bigalloc requires cluster-aware bitfield operations, which at the
+ * moment means we need EXT2_FLAG_64BITS.
+ */
+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+ EXT4_FEATURE_RO_COMPAT_BIGALLOC) &&
+ !(flags & EXT2_FLAG_64BITS)) {
+ retval = EXT2_ET_CANT_USE_LEGACY_BITMAPS;
+ goto cleanup;
+ }
+
if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
EXT4_FEATURE_RO_COMPAT_BIGALLOC) &&
(fs->super->s_log_block_size != fs->super->s_log_cluster_size)) {
@@ -329,16 +361,30 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
goto cleanup;
if (!group_block)
group_block = fs->super->s_first_data_block;
+ /*
+ * On a FS with a 1K blocksize, block 0 is reserved for bootloaders
+ * so we must increment block numbers to any group 0 items.
+ *
+ * However, we cannot touch group_block directly because in the meta_bg
+ * case, the ext2fs_descriptor_block_loc2() function will interpret
+ * group_block != s_first_data_block to mean that we want to access the
+ * backup group descriptors. This is not what we want if the caller
+ * set superblock == 0 (i.e. auto-detect the superblock), which is
+ * what's going on here.
+ */
if (group_block == 0 && fs->blocksize == 1024)
- group_block = 1; /* Deal with 1024 blocksize && bigalloc */
+ group_zero_adjust = 1;
dest = (char *) fs->group_desc;
+#ifdef WORDS_BIGENDIAN
groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
+#endif
if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
first_meta_bg = fs->super->s_first_meta_bg;
else
first_meta_bg = fs->desc_blocks;
if (first_meta_bg) {
- retval = io_channel_read_blk(fs->io, group_block+1,
+ retval = io_channel_read_blk(fs->io, group_block +
+ group_zero_adjust + 1,
first_meta_bg, dest);
if (retval)
goto cleanup;
@@ -388,9 +434,6 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
ext2fs_mark_super_dirty(fs);
}
- fs->flags &= ~EXT2_FLAG_NOFREE_ON_ERROR;
- *ret_fs = fs;
-
if ((fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) &&
!(flags & EXT2_FLAG_SKIP_MMP) &&
(flags & (EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE))) {
@@ -402,12 +445,16 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
}
}
+ fs->flags &= ~EXT2_FLAG_NOFREE_ON_ERROR;
+ *ret_fs = fs;
+
return 0;
cleanup:
- if (flags & EXT2_FLAG_NOFREE_ON_ERROR)
- *ret_fs = fs;
- else
+ if (!(flags & EXT2_FLAG_NOFREE_ON_ERROR)) {
ext2fs_free(fs);
+ fs = NULL;
+ }
+ *ret_fs = fs;
return retval;
}
@@ -436,8 +483,20 @@ errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io)
errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io)
{
+ errcode_t err;
+
if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
return EXT2_ET_NOT_IMAGE_FILE;
+ err = io_channel_set_blksize(new_io, fs->blocksize);
+ if (err)
+ return err;
+ if ((new_io == fs->image_io) || (new_io == fs->io))
+ return 0;
+ if ((fs->image_io != fs->io) &&
+ fs->image_io)
+ io_channel_close(fs->image_io);
+ if (fs->io)
+ io_channel_close(fs->io);
fs->io = fs->image_io = new_io;
fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW |
EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
diff --git a/lib/ext2fs/progress.c b/lib/ext2fs/progress.c
index 37d15096..8c9a6f1d 100644
--- a/lib/ext2fs/progress.c
+++ b/lib/ext2fs/progress.c
@@ -14,7 +14,10 @@
#include "ext2fs.h"
#include "ext2fsP.h"
+#include <time.h>
+
static char spaces[80], backspaces[80];
+static time_t last_update;
static int int_log10(unsigned int arg)
{
@@ -42,11 +45,11 @@ void ext2fs_numeric_progress_init(ext2_filsys fs,
spaces[sizeof(spaces)-1] = 0;
memset(backspaces, '\b', sizeof(backspaces)-1);
backspaces[sizeof(backspaces)-1] = 0;
- progress->skip_progress = 0;
+
+ memset(progress, 0, sizeof(*progress));
if (getenv("E2FSPROGS_SKIP_PROGRESS"))
progress->skip_progress++;
- memset(progress, 0, sizeof(*progress));
/*
* Figure out how many digits we need
@@ -58,16 +61,23 @@ void ext2fs_numeric_progress_init(ext2_filsys fs,
fputs(label, stdout);
fflush(stdout);
}
+ last_update = 0;
}
void ext2fs_numeric_progress_update(ext2_filsys fs,
struct ext2fs_numeric_progress_struct * progress,
__u64 val)
{
+ time_t now;
+
if (!(fs->flags & EXT2_FLAG_PRINT_PROGRESS))
return;
if (progress->skip_progress)
return;
+ now = time(0);
+ if (now == last_update)
+ return;
+ last_update = now;
printf("%*llu/%*llu", progress->log_max, val,
progress->log_max, progress->max);
diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c
index b53653a0..a3d020ec 100644
--- a/lib/ext2fs/punch.c
+++ b/lib/ext2fs/punch.c
@@ -50,17 +50,18 @@ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode,
blk_t start, blk_t count, int max)
{
errcode_t retval;
- blk_t b, offset;
- int i, incr;
+ blk_t b;
+ int i;
+ blk64_t offset, incr;
int freed = 0;
#ifdef PUNCH_DEBUG
printf("Entering ind_punch, level %d, start %u, count %u, "
"max %d\n", level, start, count, max);
#endif
- incr = 1 << ((EXT2_BLOCK_SIZE_BITS(fs->super)-2)*level);
+ incr = 1ULL << ((EXT2_BLOCK_SIZE_BITS(fs->super)-2)*level);
for (i=0, offset=0; i < max; i++, p++, offset += incr) {
- if (offset > count)
+ if (offset >= start + count)
break;
if (*p == 0 || (offset+incr) <= start)
continue;
@@ -87,7 +88,7 @@ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode,
continue;
}
#ifdef PUNCH_DEBUG
- printf("Freeing block %u (offset %d)\n", b, offset);
+ printf("Freeing block %u (offset %llu)\n", b, offset);
#endif
ext2fs_block_alloc_stats(fs, b, -1);
*p = 0;
@@ -108,7 +109,7 @@ static errcode_t ext2fs_punch_ind(ext2_filsys fs, struct ext2_inode *inode,
int num = EXT2_NDIR_BLOCKS;
blk_t *bp = inode->i_block;
blk_t addr_per_block;
- blk_t max = EXT2_NDIR_BLOCKS;
+ blk64_t max = EXT2_NDIR_BLOCKS;
if (!block_buf) {
retval = ext2fs_get_array(3, fs->blocksize, &buf);
@@ -119,10 +120,10 @@ static errcode_t ext2fs_punch_ind(ext2_filsys fs, struct ext2_inode *inode,
addr_per_block = (blk_t) fs->blocksize >> 2;
- for (level=0; level < 4; level++, max *= addr_per_block) {
+ for (level = 0; level < 4; level++, max *= (blk64_t)addr_per_block) {
#ifdef PUNCH_DEBUG
printf("Main loop level %d, start %u count %u "
- "max %d num %d\n", level, start, count, max, num);
+ "max %llu num %d\n", level, start, count, max, num);
#endif
if (start < max) {
retval = ind_punch(fs, inode, block_buf, bp, level,
@@ -176,6 +177,75 @@ static void dbg_print_extent(char *desc, struct ext2fs_extent *extent)
#define dbg_printf(f, a...) do { } while (0)
#endif
+/* Free a range of blocks, respecting cluster boundaries */
+static errcode_t punch_extent_blocks(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode,
+ blk64_t lfree_start, blk64_t free_start,
+ __u32 free_count, int *freed)
+{
+ blk64_t pblk;
+ int freed_now = 0;
+ __u32 cluster_freed;
+ errcode_t retval = 0;
+
+ /* No bigalloc? Just free each block. */
+ if (EXT2FS_CLUSTER_RATIO(fs) == 1) {
+ *freed += free_count;
+ while (free_count-- > 0)
+ ext2fs_block_alloc_stats2(fs, free_start++, -1);
+ return retval;
+ }
+
+ /*
+ * Try to free up to the next cluster boundary. We assume that all
+ * blocks in a logical cluster map to blocks from the same physical
+ * cluster, and that the offsets within the [pl]clusters match.
+ */
+ if (free_start & EXT2FS_CLUSTER_MASK(fs)) {
+ retval = ext2fs_map_cluster_block(fs, ino, inode,
+ lfree_start, &pblk);
+ if (retval)
+ goto errout;
+ if (!pblk) {
+ ext2fs_block_alloc_stats2(fs, free_start, -1);
+ freed_now++;
+ }
+ cluster_freed = EXT2FS_CLUSTER_RATIO(fs) -
+ (free_start & EXT2FS_CLUSTER_MASK(fs));
+ if (cluster_freed > free_count)
+ cluster_freed = free_count;
+ free_count -= cluster_freed;
+ free_start += cluster_freed;
+ lfree_start += cluster_freed;
+ }
+
+ /* Free whole clusters from the middle of the range. */
+ while (free_count > 0 && free_count >= EXT2FS_CLUSTER_RATIO(fs)) {
+ ext2fs_block_alloc_stats2(fs, free_start, -1);
+ freed_now++;
+ cluster_freed = EXT2FS_CLUSTER_RATIO(fs);
+ free_count -= cluster_freed;
+ free_start += cluster_freed;
+ lfree_start += cluster_freed;
+ }
+
+ /* Try to free the last cluster. */
+ if (free_count > 0) {
+ retval = ext2fs_map_cluster_block(fs, ino, inode,
+ lfree_start, &pblk);
+ if (retval)
+ goto errout;
+ if (!pblk) {
+ ext2fs_block_alloc_stats2(fs, free_start, -1);
+ freed_now++;
+ }
+ }
+
+errout:
+ *freed += freed_now;
+ return retval;
+}
+
static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
blk64_t start, blk64_t end)
@@ -183,18 +253,34 @@ static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
ext2_extent_handle_t handle = 0;
struct ext2fs_extent extent;
errcode_t retval;
- blk64_t free_start, next;
+ blk64_t free_start, next, lfree_start;
__u32 free_count, newlen;
int freed = 0;
+ int op;
retval = ext2fs_extent_open2(fs, ino, inode, &handle);
if (retval)
return retval;
+ /*
+ * Find the extent closest to the start of the punch range. We don't
+ * check the return value because _goto() sets the current node to the
+ * next-lowest extent if 'start' is in a hole, and doesn't set a
+ * current node if there was a real error reading the extent tree.
+ * In that case, _get() will error out.
+ *
+ * Note: If _get() returns 'no current node', that simply means that
+ * there aren't any blocks mapped past this point in the file, so we're
+ * done.
+ */
ext2fs_extent_goto(handle, start);
retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
- if (retval)
+ if (retval == EXT2_ET_NO_CURRENT_NODE) {
+ retval = 0;
+ goto errout;
+ } else if (retval)
goto errout;
while (1) {
+ op = EXT2_EXTENT_NEXT_LEAF;
dbg_print_extent("main loop", &extent);
next = extent.e_lblk + extent.e_len;
dbg_printf("start %llu, end %llu, next %llu\n",
@@ -202,12 +288,17 @@ static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
(unsigned long long) end,
(unsigned long long) next);
if (start <= extent.e_lblk) {
+ /*
+ * Have we iterated past the end of the punch region?
+ * If so, we can stop.
+ */
if (end < extent.e_lblk)
- goto next_extent;
+ break;
dbg_printf("Case #%d\n", 1);
/* Start of deleted region before extent;
adjust beginning of extent */
free_start = extent.e_pblk;
+ lfree_start = extent.e_lblk;
if (next > end)
free_count = end - extent.e_lblk + 1;
else
@@ -216,13 +307,19 @@ static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
extent.e_lblk += free_count;
extent.e_pblk += free_count;
} else if (end >= next-1) {
+ /*
+ * Is the punch region beyond this extent? This can
+ * happen if start is already inside a hole. Try to
+ * advance to the next extent if this is the case.
+ */
if (start >= next)
- break;
+ goto next_extent;
/* End of deleted region after extent;
adjust end of extent */
dbg_printf("Case #%d\n", 2);
newlen = start - extent.e_lblk;
free_start = extent.e_pblk + newlen;
+ lfree_start = extent.e_lblk + newlen;
free_count = extent.e_len - newlen;
extent.e_len = newlen;
} else {
@@ -238,6 +335,7 @@ static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
extent.e_len = start - extent.e_lblk;
free_start = extent.e_pblk + extent.e_len;
+ lfree_start = extent.e_lblk + extent.e_len;
free_count = end - start + 1;
dbg_print_extent("inserting", &newex);
@@ -255,22 +353,65 @@ static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
if (extent.e_len) {
dbg_print_extent("replacing", &extent);
retval = ext2fs_extent_replace(handle, 0, &extent);
+ if (retval)
+ goto errout;
+ retval = ext2fs_extent_fix_parents(handle);
} else {
+ struct ext2fs_extent newex;
+ blk64_t old_lblk, next_lblk;
dbg_printf("deleting current extent%s\n", "");
+
+ /*
+ * Save the location of the next leaf, then slip
+ * back to the current extent.
+ */
+ retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
+ &newex);
+ if (retval)
+ goto errout;
+ old_lblk = newex.e_lblk;
+
+ retval = ext2fs_extent_get(handle,
+ EXT2_EXTENT_NEXT_LEAF,
+ &newex);
+ if (retval == EXT2_ET_EXTENT_NO_NEXT)
+ next_lblk = old_lblk;
+ else if (retval)
+ goto errout;
+ else
+ next_lblk = newex.e_lblk;
+
+ retval = ext2fs_extent_goto(handle, old_lblk);
+ if (retval)
+ goto errout;
+
+ /* Now delete the extent. */
retval = ext2fs_extent_delete(handle, 0);
+ if (retval)
+ goto errout;
+
+ retval = ext2fs_extent_fix_parents(handle);
+ if (retval && retval != EXT2_ET_NO_CURRENT_NODE)
+ goto errout;
+ retval = 0;
+
+ /* Jump forward to the next extent. */
+ ext2fs_extent_goto(handle, next_lblk);
+ op = EXT2_EXTENT_CURRENT;
}
if (retval)
goto errout;
dbg_printf("Free start %llu, free count = %u\n",
free_start, free_count);
- while (free_count-- > 0) {
- ext2fs_block_alloc_stats(fs, free_start++, -1);
- freed++;
- }
+ retval = punch_extent_blocks(fs, ino, inode, lfree_start,
+ free_start, free_count, &freed);
+ if (retval)
+ goto errout;
next_extent:
- retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF,
+ retval = ext2fs_extent_get(handle, op,
&extent);
- if (retval == EXT2_ET_EXTENT_NO_NEXT)
+ if (retval == EXT2_ET_EXTENT_NO_NEXT ||
+ retval == EXT2_ET_NO_CURRENT_NODE)
break;
if (retval)
goto errout;
@@ -286,10 +427,10 @@ errout:
* Deallocate all logical blocks starting at start to end, inclusive.
* If end is ~0, then this is effectively truncate.
*/
-extern errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
- struct ext2_inode *inode,
- char *block_buf, blk64_t start,
- blk64_t end)
+errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
+ struct ext2_inode *inode,
+ char *block_buf, blk64_t start,
+ blk64_t end)
{
errcode_t retval;
struct ext2_inode inode_buf;
@@ -297,9 +438,6 @@ extern errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
if (start > end)
return EINVAL;
- if (start == end)
- return 0;
-
/* Read inode structure if necessary */
if (!inode) {
retval = ext2fs_read_inode(fs, ino, &inode_buf);
@@ -314,7 +452,9 @@ extern errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
if (start > ~0U)
return 0;
- count = ((end - start) < ~0U) ? (end - start) : ~0U;
+ if (end > ~0U)
+ end = ~0U;
+ count = ((end - start + 1) < ~0U) ? (end - start + 1) : ~0U;
retval = ext2fs_punch_ind(fs, inode, block_buf,
(blk_t) start, count);
}
diff --git a/lib/ext2fs/qcow2.c b/lib/ext2fs/qcow2.c
index b0a02783..c7cdbee8 100644
--- a/lib/ext2fs/qcow2.c
+++ b/lib/ext2fs/qcow2.c
@@ -60,8 +60,10 @@ struct ext2_qcow2_hdr *qcow2_read_header(int fd)
return NULL;
memset(buffer, 0, sizeof(struct ext2_qcow2_hdr));
- if (ext2fs_llseek(fd, 0, SEEK_SET < 0))
+ if (ext2fs_llseek(fd, 0, SEEK_SET < 0)) {
+ ext2fs_free_mem(&buffer);
return NULL;
+ }
size = read(fd, buffer, sizeof(struct ext2_qcow2_hdr));
if (size != sizeof(struct ext2_qcow2_hdr)) {
@@ -91,8 +93,10 @@ static int qcow2_read_l1_table(struct ext2_qcow2_image *img)
if (ret)
return ret;
- if (ext2fs_llseek(fd, img->l1_offset, SEEK_SET) < 0)
+ if (ext2fs_llseek(fd, img->l1_offset, SEEK_SET) < 0) {
+ ext2fs_free_mem(&table);
return errno;
+ }
size = read(fd, table, l1_size);
if (size != l1_size) {
@@ -155,7 +159,7 @@ int qcow2_write_raw_image(int qcow2_fd, int raw_fd,
errcode_t ret = 0;
unsigned int l1_index, l2_index;
ext2_off64_t offset;
- blk64_t *l1_table, *l2_table;
+ blk64_t *l1_table, *l2_table = NULL;
void *copy_buf = NULL;
size_t size;
@@ -231,13 +235,17 @@ int qcow2_write_raw_image(int qcow2_fd, int raw_fd,
}
/* Resize the output image to the filesystem size */
- if (ext2fs_llseek(raw_fd, img.image_size - 1, SEEK_SET) < 0)
- return errno;
+ if (ext2fs_llseek(raw_fd, img.image_size - 1, SEEK_SET) < 0) {
+ ret = errno;
+ goto out;
+ }
((char *)copy_buf)[0] = 0;
size = write(raw_fd, copy_buf, 1);
- if (size != 1)
- return errno;
+ if (size != 1) {
+ ret = errno;
+ goto out;
+ }
out:
if (copy_buf)
diff --git a/lib/ext2fs/rbtree.c b/lib/ext2fs/rbtree.c
index 7467e10e..94393030 100644
--- a/lib/ext2fs/rbtree.c
+++ b/lib/ext2fs/rbtree.c
@@ -375,7 +375,7 @@ struct rb_node *ext2fs_rb_last(const struct rb_root *root)
return n;
}
-struct rb_node *ext2fs_rb_next(const struct rb_node *node)
+struct rb_node *ext2fs_rb_next(struct rb_node *node)
{
struct rb_node *parent;
@@ -403,7 +403,7 @@ struct rb_node *ext2fs_rb_next(const struct rb_node *node)
return parent;
}
-struct rb_node *ext2fs_rb_prev(const struct rb_node *node)
+struct rb_node *ext2fs_rb_prev(struct rb_node *node)
{
struct rb_node *parent;
diff --git a/lib/ext2fs/rbtree.h b/lib/ext2fs/rbtree.h
index 972297bf..3b0b0784 100644
--- a/lib/ext2fs/rbtree.h
+++ b/lib/ext2fs/rbtree.h
@@ -104,7 +104,7 @@ static inline struct page * rb_insert_page_cache(struct inode * inode,
#endif
#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
struct rb_node
@@ -158,8 +158,8 @@ extern void ext2fs_rb_augment_erase_end(struct rb_node *node,
rb_augment_f func, void *data);
/* Find logical next and previous nodes in a tree */
-extern struct rb_node *ext2fs_rb_next(const struct rb_node *);
-extern struct rb_node *ext2fs_rb_prev(const struct rb_node *);
+extern struct rb_node *ext2fs_rb_next(struct rb_node *);
+extern struct rb_node *ext2fs_rb_prev(struct rb_node *);
extern struct rb_node *ext2fs_rb_first(const struct rb_root *);
extern struct rb_node *ext2fs_rb_last(const struct rb_root *);
diff --git a/lib/ext2fs/read_bb_file.c b/lib/ext2fs/read_bb_file.c
index 7d7bb7aa..8d1ad1a5 100644
--- a/lib/ext2fs/read_bb_file.c
+++ b/lib/ext2fs/read_bb_file.c
@@ -39,7 +39,7 @@ errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f,
void *priv_data))
{
errcode_t retval;
- blk_t blockno;
+ blk64_t blockno;
int count;
char buf[128];
@@ -55,9 +55,12 @@ errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f,
while (!feof (f)) {
if (fgets(buf, sizeof(buf), f) == NULL)
break;
- count = sscanf(buf, "%u", &blockno);
+ count = sscanf(buf, "%llu", &blockno);
if (count <= 0)
continue;
+ /* Badblocks isn't going to be updated for 64bit */
+ if (blockno >> 32)
+ return EOVERFLOW;
if (fs &&
((blockno < fs->super->s_first_data_block) ||
(blockno >= ext2fs_blocks_count(fs->super)))) {
diff --git a/lib/ext2fs/res_gdt.c b/lib/ext2fs/res_gdt.c
index 6449228c..e61c3303 100644
--- a/lib/ext2fs/res_gdt.c
+++ b/lib/ext2fs/res_gdt.c
@@ -31,6 +31,19 @@ static unsigned int list_backups(ext2_filsys fs, unsigned int *three,
int mult = 3;
unsigned int ret;
+ if (fs->super->s_feature_compat & EXT4_FEATURE_COMPAT_SPARSE_SUPER2) {
+ if (*min == 1) {
+ *min += 1;
+ if (fs->super->s_backup_bgs[0])
+ return fs->super->s_backup_bgs[0];
+ }
+ if (*min == 2) {
+ *min += 1;
+ if (fs->super->s_backup_bgs[1])
+ return fs->super->s_backup_bgs[1];
+ }
+ return fs->group_desc_count;
+ }
if (!(fs->super->s_feature_ro_compat &
EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
ret = *min;
diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c
index 1d5f7b2b..d24ba9a3 100644
--- a/lib/ext2fs/rw_bitmaps.c
+++ b/lib/ext2fs/rw_bitmaps.c
@@ -53,8 +53,7 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
inode_nbytes = block_nbytes = 0;
if (do_block) {
block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
- retval = ext2fs_get_memalign(fs->blocksize, fs->blocksize,
- &block_buf);
+ retval = io_channel_alloc_buf(fs->io, 0, &block_buf);
if (retval)
goto errout;
memset(block_buf, 0xff, fs->blocksize);
@@ -62,8 +61,7 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
if (do_inode) {
inode_nbytes = (size_t)
((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
- retval = ext2fs_get_memalign(fs->blocksize, fs->blocksize,
- &inode_buf);
+ retval = io_channel_alloc_buf(fs->io, 0, &inode_buf);
if (retval)
goto errout;
memset(inode_buf, 0xff, fs->blocksize);
@@ -147,6 +145,43 @@ errout:
return retval;
}
+static errcode_t mark_uninit_bg_group_blocks(ext2_filsys fs)
+{
+ dgrp_t i;
+ blk64_t blk;
+ ext2fs_block_bitmap bmap = fs->block_map;
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT))
+ continue;
+
+ ext2fs_reserve_super_and_bgd(fs, i, bmap);
+
+ /*
+ * Mark the blocks used for the inode table
+ */
+ blk = ext2fs_inode_table_loc(fs, i);
+ if (blk)
+ ext2fs_mark_block_bitmap_range2(bmap, blk,
+ fs->inode_blocks_per_group);
+
+ /*
+ * Mark block used for the block bitmap
+ */
+ blk = ext2fs_block_bitmap_loc(fs, i);
+ if (blk)
+ ext2fs_mark_block_bitmap2(bmap, blk);
+
+ /*
+ * Mark block used for the inode bitmap
+ */
+ blk = ext2fs_inode_bitmap_loc(fs, i);
+ if (blk)
+ ext2fs_mark_block_bitmap2(bmap, blk);
+ }
+ return 0;
+}
+
static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
{
dgrp_t i;
@@ -156,7 +191,6 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
int csum_flag = 0;
- int do_image = fs->flags & EXT2_FLAG_IMAGE_FILE;
unsigned int cnt;
blk64_t blk;
blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block);
@@ -166,6 +200,10 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+ if ((block_nbytes > (int) fs->blocksize) ||
+ (inode_nbytes > (int) fs->blocksize))
+ return EXT2_ET_CORRUPT_SUPERBLOCK;
+
fs->write_bitmaps = ext2fs_write_bitmaps;
if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
@@ -183,13 +221,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
if (retval)
goto cleanup;
- if (do_image)
- retval = ext2fs_get_mem(fs->blocksize, &block_bitmap);
- else
- retval = ext2fs_get_memalign((unsigned) block_nbytes,
- fs->blocksize,
- &block_bitmap);
-
+ retval = io_channel_alloc_buf(fs->io, 0, &block_bitmap);
if (retval)
goto cleanup;
} else
@@ -202,8 +234,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
if (retval)
goto cleanup;
- retval = ext2fs_get_mem(do_image ? fs->blocksize :
- (unsigned) inode_nbytes, &inode_bitmap);
+ retval = io_channel_alloc_buf(fs->io, 0, &inode_bitmap);
if (retval)
goto cleanup;
} else
@@ -261,7 +292,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
blk = 0;
if (blk) {
retval = io_channel_read_blk64(fs->io, blk,
- -block_nbytes, block_bitmap);
+ 1, block_bitmap);
if (retval) {
retval = EXT2_ET_BLOCK_BITMAP_READ;
goto cleanup;
@@ -283,7 +314,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
blk = 0;
if (blk) {
retval = io_channel_read_blk64(fs->io, blk,
- -inode_nbytes, inode_bitmap);
+ 1, inode_bitmap);
if (retval) {
retval = EXT2_ET_INODE_BITMAP_READ;
goto cleanup;
@@ -298,6 +329,14 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
ino_itr += inode_nbytes << 3;
}
}
+
+ /* Mark group blocks for any BLOCK_UNINIT groups */
+ if (do_block) {
+ retval = mark_uninit_bg_group_blocks(fs);
+ if (retval)
+ goto cleanup;
+ }
+
success_cleanup:
if (inode_bitmap)
ext2fs_free_mem(&inode_bitmap);
diff --git a/lib/ext2fs/sparse.c b/lib/ext2fs/sparse.c
deleted file mode 100644
index 3a0877b8..00000000
--- a/lib/ext2fs/sparse.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * sparse.c --- find the groups in an ext2 filesystem with metadata backups
- *
- * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
- * Copyright (C) 2002 Andreas Dilger.
- *
- * %Begin-Header%
- * This file may be redistributed under the terms of the GNU Library
- * General Public License, version 2.
- * %End-Header%
- */
-
-#include "config.h"
-#include <stdio.h>
-
-#include "ext2_fs.h"
-#include "ext2fsP.h"
-
-static int test_root(int a, int b)
-{
- if (a == 0)
- return 1;
- while (1) {
- if (a == 1)
- return 1;
- if (a % b)
- return 0;
- a = a / b;
- }
-}
-
-int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
-{
- if (!(fs->super->s_feature_ro_compat &
- EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
- return 1;
-
- if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
- test_root(group_block, 7))
- return 1;
-
- return 0;
-}
-
-/*
- * Iterate through the groups which hold BACKUP superblock/GDT copies in an
- * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before
- * calling this for the first time. In a sparse filesystem it will be the
- * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
- * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
- */
-unsigned int ext2fs_list_backups(ext2_filsys fs, unsigned int *three,
- unsigned int *five, unsigned int *seven)
-{
- unsigned int *min = three;
- int mult = 3;
- unsigned int ret;
-
- if (!(fs->super->s_feature_ro_compat &
- EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
- ret = *min;
- *min += 1;
- return ret;
- }
-
- if (*five < *min) {
- min = five;
- mult = 5;
- }
- if (*seven < *min) {
- min = seven;
- mult = 7;
- }
-
- ret = *min;
- *min *= mult;
-
- return ret;
-}
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index 7c99373c..2a7b768c 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -99,10 +99,14 @@ void ext2fs_swap_super(struct ext2_super_block * sb)
}
for (; i < 17; i++)
sb->s_jnl_blocks[i] = ext2fs_swab32(sb->s_jnl_blocks[i]);
+ sb->s_backup_bgs[0] = ext2fs_swab32(sb->s_backup_bgs[0]);
+ sb->s_backup_bgs[1] = ext2fs_swab32(sb->s_backup_bgs[1]);
}
void ext2fs_swap_group_desc2(ext2_filsys fs, struct ext2_group_desc *gdp)
{
+ struct ext4_group_desc *gdp4 = (struct ext4_group_desc *)gdp;
+
/* Do the 32-bit parts first */
gdp->bg_block_bitmap = ext2fs_swab32(gdp->bg_block_bitmap);
gdp->bg_inode_bitmap = ext2fs_swab32(gdp->bg_inode_bitmap);
@@ -119,12 +123,10 @@ void ext2fs_swap_group_desc2(ext2_filsys fs, struct ext2_group_desc *gdp)
gdp->bg_itable_unused = ext2fs_swab16(gdp->bg_itable_unused);
gdp->bg_checksum = ext2fs_swab16(gdp->bg_checksum);
/* If we're 32-bit, we're done */
- if (fs && (!fs->super->s_desc_size ||
- (fs->super->s_desc_size < EXT2_MIN_DESC_SIZE_64BIT)))
+ if (fs == NULL || EXT2_DESC_SIZE(fs->super) < EXT2_MIN_DESC_SIZE_64BIT)
return;
/* Swap the 64-bit parts */
- struct ext4_group_desc *gdp4 = (struct ext4_group_desc *) gdp;
gdp4->bg_block_bitmap_hi = ext2fs_swab32(gdp4->bg_block_bitmap_hi);
gdp4->bg_inode_bitmap_hi = ext2fs_swab32(gdp4->bg_inode_bitmap_hi);
gdp4->bg_inode_table_hi = ext2fs_swab32(gdp4->bg_inode_table_hi);
diff --git a/lib/ext2fs/symlink.c b/lib/ext2fs/symlink.c
new file mode 100644
index 00000000..b2ef66c2
--- /dev/null
+++ b/lib/ext2fs/symlink.c
@@ -0,0 +1,150 @@
+/*
+ * symlink.c --- make a symlink in the filesystem, based on mkdir.c
+ *
+ * Copyright (c) 2012, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Library
+ * General Public License, version 2.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino,
+ const char *name, char *target)
+{
+ errcode_t retval;
+ struct ext2_inode inode;
+ ext2_ino_t scratch_ino;
+ blk64_t blk;
+ int fastlink;
+ unsigned int target_len;
+ char *block_buf = 0;
+
+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+ /* The Linux kernel doesn't allow for links longer than a block */
+ target_len = strlen(target);
+ if (target_len > fs->blocksize) {
+ retval = EXT2_ET_INVALID_ARGUMENT;
+ goto cleanup;
+ }
+
+ /*
+ * Allocate a data block for slow links
+ */
+ fastlink = (target_len < sizeof(inode.i_block));
+ if (!fastlink) {
+ retval = ext2fs_new_block2(fs, 0, 0, &blk);
+ if (retval)
+ goto cleanup;
+ retval = ext2fs_get_mem(fs->blocksize, &block_buf);
+ if (retval)
+ goto cleanup;
+ }
+
+ /*
+ * Allocate an inode, if necessary
+ */
+ if (!ino) {
+ retval = ext2fs_new_inode(fs, parent, LINUX_S_IFLNK | 0755,
+ 0, &ino);
+ if (retval)
+ goto cleanup;
+ }
+
+ /*
+ * Create the inode structure....
+ */
+ memset(&inode, 0, sizeof(struct ext2_inode));
+ inode.i_mode = LINUX_S_IFLNK | 0777;
+ inode.i_uid = inode.i_gid = 0;
+ ext2fs_iblk_set(fs, &inode, fastlink ? 0 : 1);
+ inode.i_links_count = 1;
+ inode.i_size = target_len;
+ /* The time fields are set by ext2fs_write_new_inode() */
+
+ if (fastlink) {
+ /* Fast symlinks, target stored in inode */
+ strcpy((char *)&inode.i_block, target);
+ } else {
+ /* Slow symlinks, target stored in the first block */
+ memset(block_buf, 0, fs->blocksize);
+ strcpy(block_buf, target);
+ if (fs->super->s_feature_incompat &
+ EXT3_FEATURE_INCOMPAT_EXTENTS) {
+ /*
+ * The extent bmap is setup after the inode and block
+ * have been written out below.
+ */
+ inode.i_flags |= EXT4_EXTENTS_FL;
+ }
+ }
+
+ /*
+ * Write out the inode and inode data block. The inode generation
+ * number is assigned by write_new_inode, which means that the
+ * operations using ino must come after it.
+ */
+ retval = ext2fs_write_new_inode(fs, ino, &inode);
+ if (retval)
+ goto cleanup;
+
+ if (!fastlink) {
+ retval = ext2fs_bmap2(fs, ino, &inode, NULL, BMAP_SET, 0, NULL,
+ &blk);
+ if (retval)
+ goto cleanup;
+
+ retval = io_channel_write_blk64(fs->io, blk, 1, block_buf);
+ if (retval)
+ goto cleanup;
+ }
+
+ /*
+ * Link the symlink into the filesystem hierarchy
+ */
+ if (name) {
+ retval = ext2fs_lookup(fs, parent, name, strlen(name), 0,
+ &scratch_ino);
+ if (!retval) {
+ retval = EXT2_ET_FILE_EXISTS;
+ goto cleanup;
+ }
+ if (retval != EXT2_ET_FILE_NOT_FOUND)
+ goto cleanup;
+ retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_SYMLINK);
+ if (retval)
+ goto cleanup;
+ }
+
+ /*
+ * Update accounting....
+ */
+ if (!fastlink)
+ ext2fs_block_alloc_stats2(fs, blk, +1);
+ ext2fs_inode_alloc_stats2(fs, ino, +1, 0);
+
+cleanup:
+ if (block_buf)
+ ext2fs_free_mem(&block_buf);
+ return retval;
+}
diff --git a/lib/ext2fs/test_io.c b/lib/ext2fs/test_io.c
index f67f6aeb..2f1c4f66 100644
--- a/lib/ext2fs/test_io.c
+++ b/lib/ext2fs/test_io.c
@@ -10,6 +10,12 @@
*/
#include "config.h"
+#if HAVE_SECURE_GETENV
+#define _GNU_SOURCE
+#endif
+#if HAVE_SECURE_GETENV
+#define _GNU_SOURCE
+#endif
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
@@ -57,45 +63,6 @@ struct test_private_data {
void (*write_blk64)(unsigned long long block, int count, errcode_t err);
};
-static errcode_t test_open(const char *name, int flags, io_channel *channel);
-static errcode_t test_close(io_channel channel);
-static errcode_t test_set_blksize(io_channel channel, int blksize);
-static errcode_t test_read_blk(io_channel channel, unsigned long block,
- int count, void *data);
-static errcode_t test_write_blk(io_channel channel, unsigned long block,
- int count, const void *data);
-static errcode_t test_read_blk64(io_channel channel, unsigned long long block,
- int count, void *data);
-static errcode_t test_write_blk64(io_channel channel, unsigned long long block,
- int count, const void *data);
-static errcode_t test_flush(io_channel channel);
-static errcode_t test_write_byte(io_channel channel, unsigned long offset,
- int count, const void *buf);
-static errcode_t test_set_option(io_channel channel, const char *option,
- const char *arg);
-static errcode_t test_get_stats(io_channel channel, io_stats *stats);
-static errcode_t test_discard(io_channel channel, unsigned long long block,
- unsigned long long count);
-
-static struct struct_io_manager struct_test_manager = {
- EXT2_ET_MAGIC_IO_MANAGER,
- "Test I/O Manager",
- test_open,
- test_close,
- test_set_blksize,
- test_read_blk,
- test_write_blk,
- test_flush,
- test_write_byte,
- test_set_option,
- test_get_stats,
- test_read_blk64,
- test_write_blk64,
- test_discard,
-};
-
-io_manager test_io_manager = &struct_test_manager;
-
/*
* These global variable can be set by the test program as
* necessary *before* calling test_open
@@ -145,6 +112,28 @@ static void test_dump_block(io_channel channel,
}
}
+/*
+ * Flush data buffers to disk.
+ */
+static errcode_t test_flush(io_channel channel)
+{
+ struct test_private_data *data;
+ errcode_t retval = 0;
+
+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+ data = (struct test_private_data *)channel->private_data;
+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+ if (data->real)
+ retval = io_channel_flush(data->real);
+
+ if (data->flags & TEST_FLAG_FLUSH)
+ fprintf(data->outfile, "Test_io: flush() returned %s\n",
+ retval ? error_message(retval) : "OK");
+
+ return retval;
+}
+
static void test_abort(io_channel channel, unsigned long block)
{
struct test_private_data *data;
@@ -173,7 +162,9 @@ static char *safe_getenv(const char *arg)
#endif
#endif
-#ifdef HAVE___SECURE_GETENV
+#if defined(HAVE_SECURE_GETENV)
+ return secure_getenv(arg);
+#elif defined(HAVE___SECURE_GETENV)
return __secure_getenv(arg);
#else
return getenv(arg);
@@ -216,14 +207,15 @@ static errcode_t test_open(const char *name, int flags, io_channel *channel)
&data->real);
if (retval)
goto cleanup;
- } else
+ } else {
data->real = 0;
- data->read_blk = test_io_cb_read_blk;
- data->write_blk = test_io_cb_write_blk;
- data->set_blksize = test_io_cb_set_blksize;
- data->write_byte = test_io_cb_write_byte;
- data->read_blk64 = test_io_cb_read_blk64;
- data->write_blk64 = test_io_cb_write_blk64;
+ }
+ data->read_blk = test_io_cb_read_blk;
+ data->write_blk = test_io_cb_write_blk;
+ data->set_blksize = test_io_cb_set_blksize;
+ data->write_byte = test_io_cb_write_byte;
+ data->read_blk64 = test_io_cb_read_blk64;
+ data->write_blk64 = test_io_cb_write_blk64;
data->outfile = NULL;
if ((value = safe_getenv("TEST_IO_LOGFILE")) != NULL)
@@ -247,6 +239,9 @@ static errcode_t test_open(const char *name, int flags, io_channel *channel)
if ((value = safe_getenv("TEST_IO_WRITE_ABORT")) != NULL)
data->write_abort_count = strtoul(value, NULL, 0);
+ if (data->real)
+ io->align = data->real->align;
+
*channel = io;
return 0;
@@ -292,8 +287,10 @@ static errcode_t test_set_blksize(io_channel channel, int blksize)
data = (struct test_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
- if (data->real)
+ if (data->real) {
retval = io_channel_set_blksize(data->real, blksize);
+ channel->align = data->real->align;
+ }
if (data->set_blksize)
data->set_blksize(blksize, retval);
if (data->flags & TEST_FLAG_SET_BLKSIZE)
@@ -434,28 +431,6 @@ static errcode_t test_write_byte(io_channel channel, unsigned long offset,
return retval;
}
-/*
- * Flush data buffers to disk.
- */
-static errcode_t test_flush(io_channel channel)
-{
- struct test_private_data *data;
- errcode_t retval = 0;
-
- EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
- data = (struct test_private_data *) channel->private_data;
- EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
-
- if (data->real)
- retval = io_channel_flush(data->real);
-
- if (data->flags & TEST_FLAG_FLUSH)
- fprintf(data->outfile, "Test_io: flush() returned %s\n",
- retval ? error_message(retval) : "OK");
-
- return retval;
-}
-
static errcode_t test_set_option(io_channel channel, const char *option,
const char *arg)
{
@@ -516,3 +491,22 @@ static errcode_t test_discard(io_channel channel, unsigned long long block,
block, count, retval ? error_message(retval) : "OK");
return retval;
}
+
+static struct struct_io_manager struct_test_manager = {
+ EXT2_ET_MAGIC_IO_MANAGER,
+ "Test I/O Manager",
+ test_open,
+ test_close,
+ test_set_blksize,
+ test_read_blk,
+ test_write_blk,
+ test_flush,
+ test_write_byte,
+ test_set_option,
+ test_get_stats,
+ test_read_blk64,
+ test_write_blk64,
+ test_discard,
+};
+
+io_manager test_io_manager = &struct_test_manager;
diff --git a/lib/ext2fs/tst_bitmaps.c b/lib/ext2fs/tst_bitmaps.c
index 27722e53..4e02aded 100644
--- a/lib/ext2fs/tst_bitmaps.c
+++ b/lib/ext2fs/tst_bitmaps.c
@@ -151,7 +151,7 @@ int check_fs_open(char *name)
static void setup_filesystem(const char *name,
unsigned int blocks, unsigned int inodes,
- unsigned int type)
+ unsigned int type, int flags)
{
struct ext2_super_block param;
errcode_t retval;
@@ -160,7 +160,7 @@ static void setup_filesystem(const char *name,
ext2fs_blocks_count_set(&param, blocks);
param.s_inodes_count = inodes;
- retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, &param,
+ retval = ext2fs_initialize("test fs", flags, &param,
test_io_manager, &test_fs);
if (retval) {
@@ -193,11 +193,11 @@ errout:
void setup_cmd(int argc, char **argv)
{
- errcode_t retval;
- int i, c, err;
+ int c, err;
unsigned int blocks = 128;
unsigned int inodes = 0;
unsigned int type = EXT2FS_BMAP64_BITARRAY;
+ int flags = EXT2_FLAG_64BITS;
if (test_fs) {
ext2fs_close(test_fs);
@@ -205,7 +205,7 @@ void setup_cmd(int argc, char **argv)
}
reset_getopt();
- while ((c = getopt(argc, argv, "b:i:t:")) != EOF) {
+ while ((c = getopt(argc, argv, "b:i:lt:")) != EOF) {
switch (c) {
case 'b':
blocks = parse_ulong(optarg, argv[0],
@@ -219,6 +219,9 @@ void setup_cmd(int argc, char **argv)
if (err)
return;
break;
+ case 'l': /* Legacy bitmaps */
+ flags = 0;
+ break;
case 't':
type = parse_ulong(optarg, argv[0],
"bitmap backend type", &err);
@@ -231,7 +234,7 @@ void setup_cmd(int argc, char **argv)
return;
}
}
- setup_filesystem(argv[0], blocks, inodes, type);
+ setup_filesystem(argv[0], blocks, inodes, type, flags);
}
void close_cmd(int argc, char **argv)
@@ -266,6 +269,7 @@ void dump_bitmap(ext2fs_generic_bitmap bmap, unsigned int start, unsigned num)
for (i=0; i < len; i++)
printf("%02x", buf[i]);
printf("\n");
+ printf("bits set: %u\n", ext2fs_bitcount(buf, len));
free(buf);
}
@@ -368,7 +372,7 @@ void do_testb(int argc, char *argv[])
{
unsigned int block, num;
int err;
- int test_result, op_result;
+ int test_result;
if (check_fs_open(argv[0]))
return;
@@ -399,6 +403,73 @@ void do_testb(int argc, char *argv[])
printf("Block %u is %s\n", block, test_result ? "set" : "clear");
}
+void do_ffzb(int argc, char *argv[])
+{
+ unsigned int start, end;
+ int err;
+ errcode_t retval;
+ blk64_t out;
+
+ if (check_fs_open(argv[0]))
+ return;
+
+ if (argc != 3 && argc != 3) {
+ com_err(argv[0], 0, "Usage: ffzb <start> <end>");
+ return;
+ }
+
+ start = parse_ulong(argv[1], argv[0], "start", &err);
+ if (err)
+ return;
+
+ end = parse_ulong(argv[2], argv[0], "end", &err);
+ if (err)
+ return;
+
+ retval = ext2fs_find_first_zero_block_bitmap2(test_fs->block_map,
+ start, end, &out);
+ if (retval) {
+ printf("ext2fs_find_first_zero_block_bitmap2() returned %s\n",
+ error_message(retval));
+ return;
+ }
+ printf("First unmarked block is %llu\n", out);
+}
+
+void do_ffsb(int argc, char *argv[])
+{
+ unsigned int start, end;
+ int err;
+ errcode_t retval;
+ blk64_t out;
+
+ if (check_fs_open(argv[0]))
+ return;
+
+ if (argc != 3 && argc != 3) {
+ com_err(argv[0], 0, "Usage: ffsb <start> <end>");
+ return;
+ }
+
+ start = parse_ulong(argv[1], argv[0], "start", &err);
+ if (err)
+ return;
+
+ end = parse_ulong(argv[2], argv[0], "end", &err);
+ if (err)
+ return;
+
+ retval = ext2fs_find_first_set_block_bitmap2(test_fs->block_map,
+ start, end, &out);
+ if (retval) {
+ printf("ext2fs_find_first_set_block_bitmap2() returned %s\n",
+ error_message(retval));
+ return;
+ }
+ printf("First marked block is %llu\n", out);
+}
+
+
void do_zerob(int argc, char *argv[])
{
if (check_fs_open(argv[0]))
@@ -470,7 +541,7 @@ void do_testi(int argc, char *argv[])
{
unsigned int inode;
int err;
- int test_result, op_result;
+ int test_result;
if (check_fs_open(argv[0]))
return;
@@ -488,6 +559,72 @@ void do_testi(int argc, char *argv[])
printf("Inode %u is %s\n", inode, test_result ? "set" : "clear");
}
+void do_ffzi(int argc, char *argv[])
+{
+ unsigned int start, end;
+ int err;
+ errcode_t retval;
+ ext2_ino_t out;
+
+ if (check_fs_open(argv[0]))
+ return;
+
+ if (argc != 3 && argc != 3) {
+ com_err(argv[0], 0, "Usage: ffzi <start> <end>");
+ return;
+ }
+
+ start = parse_ulong(argv[1], argv[0], "start", &err);
+ if (err)
+ return;
+
+ end = parse_ulong(argv[2], argv[0], "end", &err);
+ if (err)
+ return;
+
+ retval = ext2fs_find_first_zero_inode_bitmap2(test_fs->inode_map,
+ start, end, &out);
+ if (retval) {
+ printf("ext2fs_find_first_zero_inode_bitmap2() returned %s\n",
+ error_message(retval));
+ return;
+ }
+ printf("First unmarked inode is %u\n", out);
+}
+
+void do_ffsi(int argc, char *argv[])
+{
+ unsigned int start, end;
+ int err;
+ errcode_t retval;
+ ext2_ino_t out;
+
+ if (check_fs_open(argv[0]))
+ return;
+
+ if (argc != 3 && argc != 3) {
+ com_err(argv[0], 0, "Usage: ffsi <start> <end>");
+ return;
+ }
+
+ start = parse_ulong(argv[1], argv[0], "start", &err);
+ if (err)
+ return;
+
+ end = parse_ulong(argv[2], argv[0], "end", &err);
+ if (err)
+ return;
+
+ retval = ext2fs_find_first_set_inode_bitmap2(test_fs->inode_map,
+ start, end, &out);
+ if (retval) {
+ printf("ext2fs_find_first_set_inode_bitmap2() returned %s\n",
+ error_message(retval));
+ return;
+ }
+ printf("First marked inode is %u\n", out);
+}
+
void do_zeroi(int argc, char *argv[])
{
if (check_fs_open(argv[0]))
@@ -506,28 +643,32 @@ int main(int argc, char **argv)
char *request = (char *)NULL;
char *cmd_file = 0;
int sci_idx;
+ int flags = EXT2_FLAG_64BITS;
add_error_table(&et_ss_error_table);
add_error_table(&et_ext2_error_table);
- while ((c = getopt (argc, argv, "b:i:t:R:f:")) != EOF) {
+ while ((c = getopt (argc, argv, "b:i:lt:R:f:")) != EOF) {
switch (c) {
case 'b':
blocks = parse_ulong(optarg, argv[0],
"number of blocks", &err);
if (err)
- return;
+ exit(1);
break;
case 'i':
inodes = parse_ulong(optarg, argv[0],
"number of blocks", &err);
if (err)
- return;
+ exit(1);
+ break;
+ case 'l': /* Legacy bitmaps */
+ flags = 0;
break;
case 't':
type = parse_ulong(optarg, argv[0],
"bitmap backend type", &err);
if (err)
- return;
+ exit(1);
break;
case 'R':
request = optarg;
@@ -558,7 +699,7 @@ int main(int argc, char **argv)
printf("%s %s. Type '?' for a list of commands.\n\n",
subsystem_name, version);
- setup_filesystem(argv[0], blocks, inodes, type);
+ setup_filesystem(argv[0], blocks, inodes, type, flags);
if (request) {
code = ss_execute_line(sci_idx, request);
diff --git a/lib/ext2fs/tst_bitmaps_cmd.ct b/lib/ext2fs/tst_bitmaps_cmd.ct
index 5a51d23c..13b7fa7c 100644
--- a/lib/ext2fs/tst_bitmaps_cmd.ct
+++ b/lib/ext2fs/tst_bitmaps_cmd.ct
@@ -21,6 +21,12 @@ request do_clearb, "Clear block",
request do_testb, "Test block",
test_block, testb;
+request do_ffzb, "Find first zero block",
+ find_first_zero_block, ffzb;
+
+request do_ffsb, "Find first set block",
+ find_first_set_block, ffsb;
+
request do_zerob, "Clear block bitmap",
clear_block_bitmap, zerob;
@@ -33,6 +39,12 @@ request do_cleari, "Clear inode",
request do_testi, "Test inode",
test_inode, testi;
+request do_ffzi, "Find first zero inode",
+ find_first_zero_inode, ffzi;
+
+request do_ffsi, "Find first set inode",
+ find_first_set_inode, ffsi;
+
request do_zeroi, "Clear inode bitmap",
clear_inode_bitmap, zeroi;
diff --git a/lib/ext2fs/tst_bitmaps_cmds b/lib/ext2fs/tst_bitmaps_cmds
index 13f4ea83..7492592f 100644
--- a/lib/ext2fs/tst_bitmaps_cmds
+++ b/lib/ext2fs/tst_bitmaps_cmds
@@ -16,6 +16,21 @@ testb 11
testb 15
testb 16
dump_bb
+ffzb 11 16
+ffzb 12 16
+ffzb 12 20
+ffsb 0 127
+ffsb 1 128
+ffsb 1 127
+ffsb 1 10
+ffsb 1 11
+ffsb 12 12
+ffsb 13 12
+ffsb 12 15
+clearb 13
+ffzb 12 20
+ffsb 13 18
+setb 13
clearb 12 7
testb 12 7
setb 15
@@ -33,6 +48,18 @@ seti 5
testi 6
testi 1
dump_ib
+ffzi 1 6
+ffzi 2 5
+ffzi 2 6
+ffsi 0 31
+ffsi 1 33
+ffsi 1 32
+ffsi 2 32
+ffsi 6 32
+cleari 4
+ffzi 2 6
+ffsi 4 32
+ffsi 5 32
zeroi
testi 5
seti 5
@@ -42,5 +69,80 @@ cleari 5
testi 17
testi 6
testi 4
+clearb 7 12
+dump_bb
+setb 1
+dump_bb
+setb 2
+dump_bb
+setb 3
+dump_bb
+setb 4
+dump_bb
+setb 5
+dump_bb
+setb 6
+dump_bb
+setb 7
+dump_bb
+setb 8
+dump_bb
+setb 10
+setb 12
+setb 14
+setb 17
+setb 19
+setb 24
+setb 26
+setb 27
+setb 30
+setb 31
+setb 32
+setb 35
+setb 39
+setb 40
+setb 44
+setb 46
+setb 47
+setb 49
+setb 51
+setb 52
+clearb 2
+clearb 3
+clearb 7
+dump_bb
+ffsb 14 127
+ffsb 15 127
+ffsb 36 127
+ffsb 32 127
+ffsb 52 127
+ffsb 53 127
+ffsb 46 127
+ffsb 45 127
+ffsb 41 127
+ffsb 20 127
+ffsb 1 127
+ffsb 2 127
+ffsb 3 127
+ffsb 4 127
+ffsb 5 127
+ffsb 6 127
+ffsb 7 127
+ffsb 8 127
+ffzb 1 127
+ffzb 2 127
+ffzb 3 127
+ffzb 4 127
+ffzb 5 127
+ffzb 6 127
+ffzb 7 127
+ffzb 8 127
+ffzb 45 127
+ffzb 46 127
+ffzb 47 127
+ffzb 48 127
+ffzb 49 127
+ffzb 50 127
+ffzb 51 127
quit
diff --git a/lib/ext2fs/tst_bitmaps_exp b/lib/ext2fs/tst_bitmaps_exp
index aa64ae72..6b226662 100644
--- a/lib/ext2fs/tst_bitmaps_exp
+++ b/lib/ext2fs/tst_bitmaps_exp
@@ -36,6 +36,37 @@ tst_bitmaps: testb 16
Block 16 is set
tst_bitmaps: dump_bb
block bitmap: 00f80000000000000000000000000000
+bits set: 5
+tst_bitmaps: ffzb 11 16
+First unmarked block is 11
+tst_bitmaps: ffzb 12 16
+ext2fs_find_first_zero_block_bitmap2() returned No such file or directory
+tst_bitmaps: ffzb 12 20
+First unmarked block is 17
+tst_bitmaps: ffsb 0 127
+ext2fs_find_first_set_block_bitmap2() returned Invalid argument
+tst_bitmaps: ffsb 1 128
+ext2fs_find_first_set_block_bitmap2() returned Invalid argument
+tst_bitmaps: ffsb 1 127
+First marked block is 12
+tst_bitmaps: ffsb 1 10
+ext2fs_find_first_set_block_bitmap2() returned No such file or directory
+tst_bitmaps: ffsb 1 11
+ext2fs_find_first_set_block_bitmap2() returned No such file or directory
+tst_bitmaps: ffsb 12 12
+First marked block is 12
+tst_bitmaps: ffsb 13 12
+ext2fs_find_first_set_block_bitmap2() returned Invalid argument
+tst_bitmaps: ffsb 12 15
+First marked block is 12
+tst_bitmaps: clearb 13
+Clearing block 13, was set before
+tst_bitmaps: ffzb 12 20
+First unmarked block is 13
+tst_bitmaps: ffsb 13 18
+First marked block is 14
+tst_bitmaps: setb 13
+Setting block 13, was clear before
tst_bitmaps: clearb 12 7
Clearing blocks 12 to 18
tst_bitmaps: testb 12 7
@@ -52,6 +83,7 @@ tst_bitmaps: setb 12 7
Marking blocks 12 to 18
tst_bitmaps: dump_bb
block bitmap: 00f80300000000000000000000000000
+bits set: 7
tst_bitmaps: seti 2
Setting inode 2, was clear before
tst_bitmaps: seti 5
@@ -70,6 +102,31 @@ tst_bitmaps: testi 1
Inode 1 is clear
tst_bitmaps: dump_ib
inode bitmap: 1e000000
+bits set: 4
+tst_bitmaps: ffzi 1 6
+First unmarked inode is 1
+tst_bitmaps: ffzi 2 5
+ext2fs_find_first_zero_inode_bitmap2() returned No such file or directory
+tst_bitmaps: ffzi 2 6
+First unmarked inode is 6
+tst_bitmaps: ffsi 0 31
+ext2fs_find_first_set_inode_bitmap2() returned Invalid argument
+tst_bitmaps: ffsi 1 33
+ext2fs_find_first_set_inode_bitmap2() returned Invalid argument
+tst_bitmaps: ffsi 1 32
+First marked inode is 2
+tst_bitmaps: ffsi 2 32
+First marked inode is 2
+tst_bitmaps: ffsi 6 32
+ext2fs_find_first_set_inode_bitmap2() returned No such file or directory
+tst_bitmaps: cleari 4
+Clearing inode 4, was set before
+tst_bitmaps: ffzi 2 6
+First unmarked inode is 4
+tst_bitmaps: ffsi 4 32
+First marked inode is 5
+tst_bitmaps: ffsi 5 32
+First marked inode is 5
tst_bitmaps: zeroi
Clearing inode bitmap.
tst_bitmaps: testi 5
@@ -88,5 +145,165 @@ tst_bitmaps: testi 6
Inode 6 is clear
tst_bitmaps: testi 4
Inode 4 is clear
+tst_bitmaps: clearb 7 12
+Clearing blocks 7 to 18
+tst_bitmaps: dump_bb
+block bitmap: 00000000000000000000000000000000
+bits set: 0
+tst_bitmaps: setb 1
+Setting block 1, was clear before
+tst_bitmaps: dump_bb
+block bitmap: 01000000000000000000000000000000
+bits set: 1
+tst_bitmaps: setb 2
+Setting block 2, was clear before
+tst_bitmaps: dump_bb
+block bitmap: 03000000000000000000000000000000
+bits set: 2
+tst_bitmaps: setb 3
+Setting block 3, was clear before
+tst_bitmaps: dump_bb
+block bitmap: 07000000000000000000000000000000
+bits set: 3
+tst_bitmaps: setb 4
+Setting block 4, was clear before
+tst_bitmaps: dump_bb
+block bitmap: 0f000000000000000000000000000000
+bits set: 4
+tst_bitmaps: setb 5
+Setting block 5, was clear before
+tst_bitmaps: dump_bb
+block bitmap: 1f000000000000000000000000000000
+bits set: 5
+tst_bitmaps: setb 6
+Setting block 6, was clear before
+tst_bitmaps: dump_bb
+block bitmap: 3f000000000000000000000000000000
+bits set: 6
+tst_bitmaps: setb 7
+Setting block 7, was clear before
+tst_bitmaps: dump_bb
+block bitmap: 7f000000000000000000000000000000
+bits set: 7
+tst_bitmaps: setb 8
+Setting block 8, was clear before
+tst_bitmaps: dump_bb
+block bitmap: ff000000000000000000000000000000
+bits set: 8
+tst_bitmaps: setb 10
+Setting block 10, was clear before
+tst_bitmaps: setb 12
+Setting block 12, was clear before
+tst_bitmaps: setb 14
+Setting block 14, was clear before
+tst_bitmaps: setb 17
+Setting block 17, was clear before
+tst_bitmaps: setb 19
+Setting block 19, was clear before
+tst_bitmaps: setb 24
+Setting block 24, was clear before
+tst_bitmaps: setb 26
+Setting block 26, was clear before
+tst_bitmaps: setb 27
+Setting block 27, was clear before
+tst_bitmaps: setb 30
+Setting block 30, was clear before
+tst_bitmaps: setb 31
+Setting block 31, was clear before
+tst_bitmaps: setb 32
+Setting block 32, was clear before
+tst_bitmaps: setb 35
+Setting block 35, was clear before
+tst_bitmaps: setb 39
+Setting block 39, was clear before
+tst_bitmaps: setb 40
+Setting block 40, was clear before
+tst_bitmaps: setb 44
+Setting block 44, was clear before
+tst_bitmaps: setb 46
+Setting block 46, was clear before
+tst_bitmaps: setb 47
+Setting block 47, was clear before
+tst_bitmaps: setb 49
+Setting block 49, was clear before
+tst_bitmaps: setb 51
+Setting block 51, was clear before
+tst_bitmaps: setb 52
+Setting block 52, was clear before
+tst_bitmaps: clearb 2
+Clearing block 2, was set before
+tst_bitmaps: clearb 3
+Clearing block 3, was set before
+tst_bitmaps: clearb 7
+Clearing block 7, was set before
+tst_bitmaps: dump_bb
+block bitmap: b92a85e6c4680d000000000000000000
+bits set: 25
+tst_bitmaps: ffsb 14 127
+First marked block is 14
+tst_bitmaps: ffsb 15 127
+First marked block is 17
+tst_bitmaps: ffsb 36 127
+First marked block is 39
+tst_bitmaps: ffsb 32 127
+First marked block is 32
+tst_bitmaps: ffsb 52 127
+First marked block is 52
+tst_bitmaps: ffsb 53 127
+ext2fs_find_first_set_block_bitmap2() returned No such file or directory
+tst_bitmaps: ffsb 46 127
+First marked block is 46
+tst_bitmaps: ffsb 45 127
+First marked block is 46
+tst_bitmaps: ffsb 41 127
+First marked block is 44
+tst_bitmaps: ffsb 20 127
+First marked block is 24
+tst_bitmaps: ffsb 1 127
+First marked block is 1
+tst_bitmaps: ffsb 2 127
+First marked block is 4
+tst_bitmaps: ffsb 3 127
+First marked block is 4
+tst_bitmaps: ffsb 4 127
+First marked block is 4
+tst_bitmaps: ffsb 5 127
+First marked block is 5
+tst_bitmaps: ffsb 6 127
+First marked block is 6
+tst_bitmaps: ffsb 7 127
+First marked block is 8
+tst_bitmaps: ffsb 8 127
+First marked block is 8
+tst_bitmaps: ffzb 1 127
+First unmarked block is 2
+tst_bitmaps: ffzb 2 127
+First unmarked block is 2
+tst_bitmaps: ffzb 3 127
+First unmarked block is 3
+tst_bitmaps: ffzb 4 127
+First unmarked block is 7
+tst_bitmaps: ffzb 5 127
+First unmarked block is 7
+tst_bitmaps: ffzb 6 127
+First unmarked block is 7
+tst_bitmaps: ffzb 7 127
+First unmarked block is 7
+tst_bitmaps: ffzb 8 127
+First unmarked block is 9
+tst_bitmaps: ffzb 45 127
+First unmarked block is 45
+tst_bitmaps: ffzb 46 127
+First unmarked block is 48
+tst_bitmaps: ffzb 47 127
+First unmarked block is 48
+tst_bitmaps: ffzb 48 127
+First unmarked block is 48
+tst_bitmaps: ffzb 49 127
+First unmarked block is 50
+tst_bitmaps: ffzb 50 127
+First unmarked block is 50
+tst_bitmaps: ffzb 51 127
+First unmarked block is 53
tst_bitmaps: quit
tst_bitmaps:
diff --git a/lib/ext2fs/tst_inode_size.c b/lib/ext2fs/tst_inode_size.c
index 3e43d9f4..e20ec981 100644
--- a/lib/ext2fs/tst_inode_size.c
+++ b/lib/ext2fs/tst_inode_size.c
@@ -18,7 +18,10 @@
struct ext2_inode_large inode;
+#ifndef offsetof
#define offsetof(type, member) __builtin_offsetof(type, member)
+#endif
+
#define check_field(x, s) cur_offset = do_field(#x, s, sizeof(inode.x), \
offsetof(struct ext2_inode_large, x), \
cur_offset)
diff --git a/lib/ext2fs/tst_iscan.c b/lib/ext2fs/tst_iscan.c
index 6f783c38..70bfbecc 100644
--- a/lib/ext2fs/tst_iscan.c
+++ b/lib/ext2fs/tst_iscan.c
@@ -26,7 +26,7 @@
#include "ext2_fs.h"
#include "ext2fs.h"
-blk_t test_vec[] = { 8, 12, 24, 34, 43, 44, 100, 0 };
+blk64_t test_vec[] = { 8, 12, 24, 34, 43, 44, 100, 0 };
ext2_filsys test_fs;
ext2fs_block_bitmap bad_block_map, touched_map;
@@ -182,7 +182,7 @@ static void check_map(void)
for (i=0; test_vec[i]; i++) {
if (ext2fs_test_block_bitmap2(touched_map, test_vec[i])) {
- printf("Bad block was touched --- %u\n", test_vec[i]);
+ printf("Bad block was touched --- %llu\n", test_vec[i]);
failed++;
first_no_comma = 1;
}
diff --git a/lib/ext2fs/tst_super_size.c b/lib/ext2fs/tst_super_size.c
index 76e6e6fe..f9cec8af 100644
--- a/lib/ext2fs/tst_super_size.c
+++ b/lib/ext2fs/tst_super_size.c
@@ -21,7 +21,10 @@
struct sb_struct sb;
+#ifndef offsetof
#define offsetof(type, member) __builtin_offsetof (type, member)
+#endif
+
#define check_field(x, s) cur_offset = do_field(#x, s, sizeof(sb.x), \
offsetof(struct sb_struct, x), \
cur_offset)
@@ -132,7 +135,8 @@ int main(int argc, char **argv)
check_field(s_usr_quota_inum, 4);
check_field(s_grp_quota_inum, 4);
check_field(s_overhead_blocks, 4);
- check_field(s_reserved, 108 * 4);
+ check_field(s_backup_bgs, 8);
+ check_field(s_reserved, 106 * 4);
check_field(s_checksum, 4);
do_field("Superblock end", 0, 0, cur_offset, 1024);
#endif
diff --git a/lib/ext2fs/undo_io.c b/lib/ext2fs/undo_io.c
index 56b0eeb5..0e05c933 100644
--- a/lib/ext2fs/undo_io.c
+++ b/lib/ext2fs/undo_io.c
@@ -71,42 +71,7 @@ struct undo_private_data {
ext2_loff_t offset;
};
-static errcode_t undo_open(const char *name, int flags, io_channel *channel);
-static errcode_t undo_close(io_channel channel);
-static errcode_t undo_set_blksize(io_channel channel, int blksize);
-static errcode_t undo_read_blk64(io_channel channel, unsigned long long block,
- int count, void *data);
-static errcode_t undo_write_blk64(io_channel channel, unsigned long long block,
- int count, const void *data);
-static errcode_t undo_read_blk(io_channel channel, unsigned long block,
- int count, void *data);
-static errcode_t undo_write_blk(io_channel channel, unsigned long block,
- int count, const void *data);
-static errcode_t undo_flush(io_channel channel);
-static errcode_t undo_write_byte(io_channel channel, unsigned long offset,
- int size, const void *data);
-static errcode_t undo_set_option(io_channel channel, const char *option,
- const char *arg);
-static errcode_t undo_get_stats(io_channel channel, io_stats *stats);
-
-static struct struct_io_manager struct_undo_manager = {
- EXT2_ET_MAGIC_IO_MANAGER,
- "Undo I/O Manager",
- undo_open,
- undo_close,
- undo_set_blksize,
- undo_read_blk,
- undo_write_blk,
- undo_flush,
- undo_write_byte,
- undo_set_option,
- undo_get_stats,
- undo_read_blk64,
- undo_write_blk64,
-};
-
-io_manager undo_io_manager = &struct_undo_manager;
-static io_manager undo_io_backing_manager ;
+static io_manager undo_io_backing_manager;
static char *tdb_file;
static int actual_size;
@@ -621,3 +586,21 @@ static errcode_t undo_get_stats(io_channel channel, io_stats *stats)
return retval;
}
+
+static struct struct_io_manager struct_undo_manager = {
+ EXT2_ET_MAGIC_IO_MANAGER,
+ "Undo I/O Manager",
+ undo_open,
+ undo_close,
+ undo_set_blksize,
+ undo_read_blk,
+ undo_write_blk,
+ undo_flush,
+ undo_write_byte,
+ undo_set_option,
+ undo_get_stats,
+ undo_read_blk64,
+ undo_write_blk64,
+};
+
+io_manager undo_io_manager = &struct_undo_manager;
diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
index da3f8fde..c3185b6a 100644
--- a/lib/ext2fs/unix_io.c
+++ b/lib/ext2fs/unix_io.c
@@ -1,13 +1,13 @@
/*
* unix_io.c --- This is the Unix (well, really POSIX) implementation
- * of the I/O manager.
+ * of the I/O manager.
*
* Implements a one-block write-through cache.
*
* Includes support for Windows NT support under Cygwin.
*
* Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- * 2002 by Theodore Ts'o.
+ * 2002 by Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Library
@@ -58,10 +58,6 @@
#define BLKROGET _IO(0x12, 94) /* Get read-only status (0 = read_write). */
#endif
-#if defined(__linux__) && defined(_IO) && !defined(BLKSSZGET)
-#define BLKSSZGET _IO(0x12,104)/* get block device sector size */
-#endif
-
#undef ALIGN_DEBUG
#include "ext2_fs.h"
@@ -75,11 +71,11 @@
if ((struct)->magic != (code)) return (code)
struct unix_cache {
- char *buf;
- unsigned long block;
- int access_time;
- unsigned dirty:1;
- unsigned in_use:1;
+ char *buf;
+ unsigned long long block;
+ int access_time;
+ unsigned dirty:1;
+ unsigned in_use:1;
};
#define CACHE_SIZE 8
@@ -101,51 +97,9 @@ struct unix_private_data {
#define IS_ALIGNED(n, align) ((((unsigned long) n) & \
((unsigned long) ((align)-1))) == 0)
-static errcode_t unix_open(const char *name, int flags, io_channel *channel);
-static errcode_t unix_close(io_channel channel);
-static errcode_t unix_set_blksize(io_channel channel, int blksize);
-static errcode_t unix_read_blk(io_channel channel, unsigned long block,
- int count, void *data);
-static errcode_t unix_write_blk(io_channel channel, unsigned long block,
- int count, const void *data);
-static errcode_t unix_flush(io_channel channel);
-static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
- int size, const void *data);
-static errcode_t unix_set_option(io_channel channel, const char *option,
- const char *arg);
-static errcode_t unix_get_stats(io_channel channel, io_stats *stats)
-;
-static void reuse_cache(io_channel channel, struct unix_private_data *data,
- struct unix_cache *cache, unsigned long long block);
-static errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
- int count, void *data);
-static errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
- int count, const void *data);
-static errcode_t unix_discard(io_channel channel, unsigned long long block,
- unsigned long long count);
-
-static struct struct_io_manager struct_unix_manager = {
- EXT2_ET_MAGIC_IO_MANAGER,
- "Unix I/O Manager",
- unix_open,
- unix_close,
- unix_set_blksize,
- unix_read_blk,
- unix_write_blk,
- unix_flush,
- unix_write_byte,
- unix_set_option,
- unix_get_stats,
- unix_read_blk64,
- unix_write_blk64,
- unix_discard,
-};
-
-io_manager unix_io_manager = &struct_unix_manager;
-
static errcode_t unix_get_stats(io_channel channel, io_stats *stats)
{
- errcode_t retval = 0;
+ errcode_t retval = 0;
struct unix_private_data *data;
@@ -180,8 +134,9 @@ static errcode_t raw_read_blk(io_channel channel,
retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
goto error_out;
}
- if ((data->align == 0) ||
- ((IS_ALIGNED(buf, data->align)) && IS_ALIGNED(size, data->align))) {
+ if ((channel->align == 0) ||
+ (IS_ALIGNED(buf, channel->align) &&
+ IS_ALIGNED(size, channel->align))) {
actual = read(data->dev, buf, size);
if (actual != size) {
short_read:
@@ -250,8 +205,9 @@ static errcode_t raw_write_blk(io_channel channel,
goto error_out;
}
- if ((data->align == 0) ||
- ((IS_ALIGNED(buf, data->align)) && IS_ALIGNED(size, data->align))) {
+ if ((channel->align == 0) ||
+ (IS_ALIGNED(buf, channel->align) &&
+ IS_ALIGNED(size, channel->align))) {
actual = write(data->dev, buf, size);
if (actual != size) {
short_write:
@@ -318,16 +274,14 @@ static errcode_t alloc_cache(io_channel channel,
cache->in_use = 0;
if (cache->buf)
ext2fs_free_mem(&cache->buf);
- retval = ext2fs_get_memalign(channel->block_size,
- data->align, &cache->buf);
+ retval = io_channel_alloc_buf(channel, 0, &cache->buf);
if (retval)
return retval;
}
- if (data->align) {
+ if (channel->align) {
if (data->bounce)
ext2fs_free_mem(&data->bounce);
- retval = ext2fs_get_memalign(channel->block_size, data->align,
- &data->bounce);
+ retval = io_channel_alloc_buf(channel, 0, &data->bounce);
}
return retval;
}
@@ -439,16 +393,48 @@ static errcode_t flush_cached_blocks(io_channel channel,
#endif
#endif
+int ext2fs_open_file(const char *pathname, int flags, mode_t mode)
+{
+ if (mode)
+#if defined(HAVE_OPEN64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
+ return open64(pathname, flags, mode);
+ else
+ return open64(pathname, flags);
+#else
+ return open(pathname, flags, mode);
+ else
+ return open(pathname, flags);
+#endif
+}
+
+int ext2fs_stat(const char *path, ext2fs_struct_stat *buf)
+{
+#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
+ return stat64(path, buf);
+#else
+ return stat(path, buf);
+#endif
+}
+
+int ext2fs_fstat(int fd, ext2fs_struct_stat *buf)
+{
+#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED)
+ return fstat64(fd, buf);
+#else
+ return fstat(fd, buf);
+#endif
+}
+
static errcode_t unix_open(const char *name, int flags, io_channel *channel)
{
io_channel io = NULL;
struct unix_private_data *data = NULL;
errcode_t retval;
- int open_flags, zeroes = 0;
+ int open_flags;
int f_nocache = 0;
ext2fs_struct_stat st;
#ifdef __linux__
- struct utsname ut;
+ struct utsname ut;
#endif
if (name == 0)
@@ -477,16 +463,21 @@ static errcode_t unix_open(const char *name, int flags, io_channel *channel)
memset(data, 0, sizeof(struct unix_private_data));
data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
data->io_stats.num_fields = 2;
+ data->dev = -1;
open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
if (flags & IO_FLAG_EXCLUSIVE)
open_flags |= O_EXCL;
#if defined(O_DIRECT)
- if (flags & IO_FLAG_DIRECT_IO)
+ if (flags & IO_FLAG_DIRECT_IO) {
open_flags |= O_DIRECT;
+ io->align = ext2fs_get_dio_alignment(data->dev);
+ }
#elif defined(F_NOCACHE)
- if (flags & IO_FLAG_DIRECT_IO)
+ if (flags & IO_FLAG_DIRECT_IO) {
f_nocache = F_NOCACHE;
+ io->align = 4096;
+ }
#endif
data->flags = flags;
@@ -516,17 +507,13 @@ static errcode_t unix_open(const char *name, int flags, io_channel *channel)
io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES;
}
-#ifdef BLKSSZGET
- if (flags & IO_FLAG_DIRECT_IO) {
- if (ioctl(data->dev, BLKSSZGET, &data->align) != 0)
- data->align = io->block_size;
- }
-#endif
-
#ifdef BLKDISCARDZEROES
- ioctl(data->dev, BLKDISCARDZEROES, &zeroes);
- if (zeroes)
- io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES;
+ {
+ int zeroes = 0;
+ if (ioctl(data->dev, BLKDISCARDZEROES, &zeroes) == 0 &&
+ zeroes)
+ io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES;
+ }
#endif
#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -534,7 +521,8 @@ static errcode_t unix_open(const char *name, int flags, io_channel *channel)
* Some operating systems require that the buffers be aligned,
* regardless of O_DIRECT
*/
- data->align = 512;
+ if (!io->align)
+ io->align = 512;
#endif
@@ -549,7 +537,6 @@ static errcode_t unix_open(const char *name, int flags, io_channel *channel)
/* Is the block device actually writable? */
error = ioctl(data->dev, BLKROGET, &readonly);
if (!error && readonly) {
- close(data->dev);
retval = EPERM;
goto cleanup;
}
@@ -595,11 +582,17 @@ static errcode_t unix_open(const char *name, int flags, io_channel *channel)
cleanup:
if (data) {
+ if (data->dev >= 0)
+ close(data->dev);
free_cache(data);
ext2fs_free_mem(&data);
}
- if (io)
+ if (io) {
+ if (io->name) {
+ ext2fs_free_mem(&io->name);
+ }
ext2fs_free_mem(&io);
+ }
return retval;
}
@@ -810,7 +803,7 @@ static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
data = (struct unix_private_data *) channel->private_data;
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
- if (data->align != 0) {
+ if (channel->align != 0) {
#ifdef ALIGN_DEBUG
printf("unix_write_byte: O_DIRECT fallback\n");
#endif
@@ -888,7 +881,6 @@ static errcode_t unix_discard(io_channel channel, unsigned long long block,
unsigned long long count)
{
struct unix_private_data *data;
- __uint64_t range[2];
int ret;
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
@@ -897,8 +889,10 @@ static errcode_t unix_discard(io_channel channel, unsigned long long block,
if (channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE) {
#ifdef BLKDISCARD
- range[0] = (__uint64_t)(block) * channel->block_size;
- range[1] = (__uint64_t)(count) * channel->block_size;
+ __u64 range[2];
+
+ range[0] = (__u64)(block) * channel->block_size;
+ range[1] = (__u64)(count) * channel->block_size;
ret = ioctl(data->dev, BLKDISCARD, &range);
#else
@@ -927,3 +921,22 @@ static errcode_t unix_discard(io_channel channel, unsigned long long block,
unimplemented:
return EXT2_ET_UNIMPLEMENTED;
}
+
+static struct struct_io_manager struct_unix_manager = {
+ EXT2_ET_MAGIC_IO_MANAGER,
+ "Unix I/O Manager",
+ unix_open,
+ unix_close,
+ unix_set_blksize,
+ unix_read_blk,
+ unix_write_blk,
+ unix_flush,
+ unix_write_byte,
+ unix_set_option,
+ unix_get_stats,
+ unix_read_blk64,
+ unix_write_blk64,
+ unix_discard,
+};
+
+io_manager unix_io_manager = &struct_unix_manager;