diff options
Diffstat (limited to 'lib/ext2fs')
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(¶m, 0, sizeof(param)); ext2fs_blocks_count_set(¶m, 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, ¶m, 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, ¤t_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(¶m, blocks); param.s_inodes_count = inodes; - retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, ¶m, + retval = ext2fs_initialize("test fs", flags, ¶m, 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; |