Example #1
0
/*
 * Stupid algorithm --- we now just search forward starting from the
 * goal.  Should put in a smarter one someday....
 */
errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal,
			   ext2fs_block_bitmap map, blk64_t *ret)
{
	errcode_t retval;
	blk64_t	b = 0;

	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);

	if (!map)
		map = fs->block_map;
	if (!map)
		return EXT2_ET_NO_BLOCK_BITMAP;
	if (!goal || (goal >= ext2fs_blocks_count(fs->super)))
		goal = fs->super->s_first_data_block;
	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;
}
Example #2
0
/*
 * Calculate the number of GDT blocks to reserve for online filesystem growth.
 * The absolute maximum number of GDT blocks we can reserve is determined by
 * the number of block pointers that can fit into a single block.
 */
static unsigned int calc_reserved_gdt_blocks(ext2_filsys fs)
{
	struct ext2_super_block *sb = fs->super;
	unsigned long bpg = sb->s_blocks_per_group;
	unsigned int gdpb = EXT2_DESC_PER_BLOCK(sb);
	unsigned long max_blocks = 0xffffffff;
	unsigned long rsv_groups;
	unsigned int rsv_gdb;

	/* We set it at 1024x the current filesystem size, or
	 * the upper block count limit (2^32), whichever is lower.
	 */
	if (ext2fs_blocks_count(sb) < max_blocks / 1024)
		max_blocks = ext2fs_blocks_count(sb) * 1024;
	/*
	 * ext2fs_div64_ceil() is unnecessary because max_blocks is
	 * max _GDT_ blocks, which is limited to 32 bits.
	 */
	rsv_groups = ext2fs_div_ceil(max_blocks - sb->s_first_data_block, bpg);
	rsv_gdb = ext2fs_div_ceil(rsv_groups, gdpb) - fs->desc_blocks;
	if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb))
		rsv_gdb = EXT2_ADDR_PER_BLOCK(sb);
#ifdef RES_GDT_DEBUG
	printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %u\n",
	       max_blocks, rsv_groups, rsv_gdb);
#endif

	return rsv_gdb;
}
Example #3
0
errcode_t ext2fs_get_free_blocks2(ext2_filsys fs, blk64_t start, blk64_t finish,
				 int num, ext2fs_block_bitmap map, blk64_t *ret)
{
	blk64_t	b = start;
	int	c_ratio;

	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);

	if (!map)
		map = fs->block_map;
	if (!map)
		return EXT2_ET_NO_BLOCK_BITMAP;
	if (!b)
		b = fs->super->s_first_data_block;
	if (!finish)
		finish = start;
	if (!num)
		num = 1;
	c_ratio = 1 << ext2fs_get_bitmap_granularity(map);
	b &= ~(c_ratio - 1);
	finish &= ~(c_ratio -1);
	do {
		if (b+num-1 > ext2fs_blocks_count(fs->super))
			b = fs->super->s_first_data_block;
		if (ext2fs_fast_test_block_bitmap_range2(map, b, num)) {
			*ret = b;
			return 0;
		}
		b += c_ratio;
	} while (b != finish);
	return EXT2_ET_BLOCK_ALLOC_FAIL;
}
Example #4
0
/*
 * Determine the number of journal blocks to use, either via
 * user-specified # of megabytes, or via some intelligently selected
 * defaults.
 *
 * Find a reasonable journal file size (in blocks) given the number of blocks
 * in the filesystem.  For very small filesystems, it is not reasonable to
 * have a journal that fills more than half of the filesystem.
 */
unsigned int figure_journal_size(int size, ext2_filsys fs)
{
	int j_blocks;

	j_blocks = ext2fs_default_journal_size(ext2fs_blocks_count(fs->super));
	if (j_blocks < 0) {
		fputs(_("\nFilesystem too small for a journal\n"), stderr);
		return 0;
	}

	if (size > 0) {
		j_blocks = size * 1024 / (fs->blocksize	/ 1024);
		if (j_blocks < 1024 || j_blocks > 10240000) {
			fprintf(stderr, _("\nThe requested journal "
				"size is %d blocks; it must be\n"
				"between 1024 and 10240000 blocks.  "
				"Aborting.\n"),
				j_blocks);
			exit(1);
		}
		if ((unsigned) j_blocks > ext2fs_free_blocks_count(fs->super) / 2) {
			fputs(_("\nJournal size too big for filesystem.\n"),
			      stderr);
			exit(1);
		}
	}
	return j_blocks;
}
Example #5
0
/*
 * Find the place where we should start allocating blocks for the huge
 * files.  Leave <slack> free blocks at the beginning of the file
 * system for things like metadata blocks.
 */
static blk64_t get_start_block(ext2_filsys fs, blk64_t slack)
{
    errcode_t retval;
    blk64_t blk = fs->super->s_first_data_block, next;
    blk64_t last_blk = ext2fs_blocks_count(fs->super) - 1;

    while (slack) {
        retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
                 blk, last_blk, &blk);
        if (retval)
            break;

        retval = ext2fs_find_first_set_block_bitmap2(fs->block_map,
                 blk, last_blk, &next);
        if (retval)
            next = last_blk;

        if (next - blk > slack) {
            blk += slack;
            break;
        }

        slack -= (next - blk);
        blk = next;
    }
    return blk;
}
Example #6
0
static int block_map_looks_insane(ext2_filsys fs,
				  struct ext2_inode_large *inode)
{
	unsigned int i, bad;

	/* We're only interested in block mapped files, dirs, and symlinks */
	if ((inode->i_flags & EXT4_INLINE_DATA_FL) ||
	    (inode->i_flags & EXT4_EXTENTS_FL))
		return 0;
	if (!LINUX_S_ISREG(inode->i_mode) &&
	    !LINUX_S_ISLNK(inode->i_mode) &&
	    !LINUX_S_ISDIR(inode->i_mode))
		return 0;
	if (LINUX_S_ISLNK(inode->i_mode) &&
	    EXT2_I_SIZE(inode) <= sizeof(inode->i_block))
		return 0;

	/* Unused inodes probably aren't insane */
	if (inode->i_links_count == 0)
		return 0;

	/* See if more than half the block maps are insane */
	for (i = 0, bad = 0; i < EXT2_N_BLOCKS; i++)
		if (inode->i_block[i] != 0 &&
		    (inode->i_block[i] < fs->super->s_first_data_block ||
		     inode->i_block[i] >= ext2fs_blocks_count(fs->super)))
			bad++;
	return bad > EXT2_N_BLOCKS / 2;
}
Example #7
0
errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf)
{
	struct mmp_struct *mmp_s = buf;
	struct timeval tv;
	errcode_t retval = 0;

	gettimeofday(&tv, 0);
	mmp_s->mmp_time = tv.tv_sec;
	fs->mmp_last_written = tv.tv_sec;

	if (fs->super->s_mmp_block < fs->super->s_first_data_block ||
	    fs->super->s_mmp_block > ext2fs_blocks_count(fs->super))
		return EXT2_ET_MMP_BAD_BLOCK;

#ifdef WORDS_BIGENDIAN
	ext2fs_swap_mmp(mmp_s);
#endif

	/* I was tempted to make this use O_DIRECT and the mmp_fd, but
	 * this caused no end of grief, while leaving it as-is works. */
	retval = io_channel_write_blk64(fs->io, mmp_blk, -(int)sizeof(struct mmp_struct), buf);

#ifdef WORDS_BIGENDIAN
	ext2fs_swap_mmp(mmp_s);
#endif

	/* Make sure the block gets to disk quickly */
	io_channel_flush(fs->io);
	return retval;
}
void do_dump_unused(int argc EXT2FS_ATTR((unused)), char **argv)
{
	blk64_t		blk;
	unsigned char	buf[EXT2_MAX_BLOCK_SIZE];
	unsigned int	i;
	errcode_t	retval;

	if (common_args_process(argc, argv, 1, 1,
				"dump_unused", "", 0))
		return;

	for (blk=current_fs->super->s_first_data_block;
	     blk < ext2fs_blocks_count(current_fs->super); blk++) {
		if (ext2fs_test_block_bitmap2(current_fs->block_map,blk))
			continue;
		retval = io_channel_read_blk64(current_fs->io, blk, 1, buf);
		if (retval) {
			com_err(argv[0], retval, "While reading block\n");
			return;
		}
		for (i=0; i < current_fs->blocksize; i++)
			if (buf[i])
				break;
		if (i >= current_fs->blocksize)
			continue;
		printf("\nUnused block %llu contains non-zero data:\n\n",
		       blk);
		for (i=0; i < current_fs->blocksize; i++)
			fputc(buf[i], stdout);
	}
}
Example #9
0
/*
 * This function is called by ext2fs_get_next_inode when it needs to
 * get ready to read in a new blockgroup.
 */
static errcode_t get_next_blockgroup(ext2_inode_scan scan)
{
	ext2_filsys fs = scan->fs;

	scan->current_group++;
	scan->groups_left--;

	scan->current_block = ext2fs_inode_table_loc(scan->fs,
						     scan->current_group);
	scan->current_inode = scan->current_group *
		EXT2_INODES_PER_GROUP(fs->super);

	scan->bytes_left = 0;
	scan->inodes_left = EXT2_INODES_PER_GROUP(fs->super);
	scan->blocks_left = fs->inode_blocks_per_group;
	if (ext2fs_has_group_desc_csum(fs)) {
		__u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group);
		if (scan->inodes_left > unused)
			scan->inodes_left -= unused;
		else
			scan->inodes_left = 0;
		scan->blocks_left =
			(scan->inodes_left +
			 (fs->blocksize / scan->inode_size - 1)) *
			scan->inode_size / fs->blocksize;
	}
	if (scan->current_block &&
	    ((scan->current_block < fs->super->s_first_data_block) ||
	     (scan->current_block + fs->inode_blocks_per_group - 1 >=
	      ext2fs_blocks_count(fs->super))))
		return EXT2_ET_GDESC_BAD_INODE_TABLE;
	return 0;
}
Example #10
0
errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
				       const char *descr,
				       ext2fs_block_bitmap *ret)
{
	__u64		start, end, real_end;

	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);

	fs->write_bitmaps = ext2fs_write_bitmaps;

	start = fs->super->s_first_data_block;
	end = ext2fs_blocks_count(fs->super)-1;
	real_end = ((__u64) EXT2_BLOCKS_PER_GROUP(fs->super)
		    * (__u64) fs->group_desc_count)-1 + start;

	if (fs->flags & EXT2_FLAG_64BITS)
		return (ext2fs_alloc_generic_bmap(fs,
				  EXT2_ET_MAGIC_BLOCK_BITMAP64,
				  EXT2FS_BMAP64_BITARRAY,
				  start, end, real_end, descr, ret));

	if ((end > ~0U) || (real_end > ~0U))
		return EXT2_ET_CANT_USE_LEGACY_BITMAPS;

	return (ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, fs,
					   start, end, real_end,
					   descr, 0,
					   (ext2fs_generic_bitmap *) ret));
}
/*
 * ext2fs_allocate_block_bitmap() really allocates a per-cluster
 * bitmap for backwards compatibility.  This function allocates a
 * block bitmap which is truly per-block, even if clusters/bigalloc
 * are enabled.  mke2fs and e2fsck need this for tracking the
 * allocation of the file system metadata blocks.
 */
errcode_t ext2fs_allocate_subcluster_bitmap(ext2_filsys fs,
					    const char *descr,
					    ext2fs_block_bitmap *ret)
{
	__u64			start, end, real_end;
	ext2fs_generic_bitmap	bmap;
	errcode_t		retval;

	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);

	fs->write_bitmaps = ext2fs_write_bitmaps;

	if (!fs->cluster_ratio_bits)
		return ext2fs_allocate_block_bitmap(fs, descr, ret);

	if ((fs->flags & EXT2_FLAG_64BITS) == 0)
		return EXT2_ET_CANT_USE_LEGACY_BITMAPS;

	start = fs->super->s_first_data_block;
	end = ext2fs_blocks_count(fs->super)-1;
	real_end = ((__u64) EXT2_BLOCKS_PER_GROUP(fs->super)
		    * (__u64) fs->group_desc_count)-1 + start;

	retval = ext2fs_alloc_generic_bmap(fs, EXT2_ET_MAGIC_BLOCK_BITMAP64,
					   fs->default_bitmap_type, start,
					   end, real_end, descr, &bmap);
	if (retval)
		return retval;
	bmap->cluster_bits = 0;
	*ret = bmap;
	return 0;
}
Example #12
0
blk64_t ext2fs_descriptor_block_loc2(ext2_filsys fs, blk64_t group_block,
				     dgrp_t i)
{
	int	bg;
	int	has_super = 0;
	blk64_t	ret_blk;

	if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
	    (i < fs->super->s_first_meta_bg))
		return (group_block + i + 1);

	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;
	/*
	 * If group_block is not the normal value, we're trying to use
	 * the backup group descriptors and superblock --- so use the
	 * alternate location of the second block group in the
	 * metablock group.  Ideally we should be testing each bg
	 * descriptor block individually for correctness, but we don't
	 * 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 += fs->super->s_blocks_per_group;
	return ret_blk;
}
Example #13
0
/*
 * 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);
}
static int process_block(ext2_filsys fs, blk64_t *block_nr,
			 e2_blkcnt_t blockcnt, blk64_t ref_block,
			 int ref_offset, void *priv_data)
{
	struct process_block_struct *pb;
	errcode_t	retval;
	int		ret;
	blk64_t		block, orig;

	pb = (struct process_block_struct *) priv_data;
	block = orig = *block_nr;
	ret = 0;

	/*
	 * Let's see if this is one which we need to relocate
	 */
	if (ext2fs_test_block_bitmap2(pb->reserve, block)) {
		do {
			if (++block >= ext2fs_blocks_count(fs->super))
				block = fs->super->s_first_data_block;
			if (block == orig) {
				pb->error = EXT2_ET_BLOCK_ALLOC_FAIL;
				return BLOCK_ABORT;
			}
		} while (ext2fs_test_block_bitmap2(pb->reserve, block) ||
			 ext2fs_test_block_bitmap2(pb->alloc_map, block));

		retval = io_channel_read_blk64(fs->io, orig, 1, pb->buf);
		if (retval) {
			pb->error = retval;
			return BLOCK_ABORT;
		}
		retval = io_channel_write_blk64(fs->io, block, 1, pb->buf);
		if (retval) {
			pb->error = retval;
			return BLOCK_ABORT;
		}
		*block_nr = block;
		ext2fs_mark_block_bitmap2(pb->alloc_map, block);
		ret = BLOCK_CHANGED;
		if (pb->flags & EXT2_BMOVE_DEBUG)
			printf("ino=%u, blockcnt=%lld, %llu->%llu\n",
			       (unsigned) pb->ino, blockcnt, 
			       (unsigned long long) orig,
			       (unsigned long long) block);
	}
	if (pb->add_dir) {
		retval = ext2fs_add_dir_block2(fs->dblist, pb->ino,
					       block, blockcnt);
		if (retval) {
			pb->error = retval;
			ret |= BLOCK_ABORT;
		}
	}
	return ret;
}
Example #15
0
/*
 * Stupid algorithm --- we now just search forward starting from the
 * goal.  Should put in a smarter one someday....
 */
errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal,
			   ext2fs_block_bitmap map, blk64_t *ret)
{
	blk64_t	i;
	int	c_ratio;

	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);

	if (!map)
		map = fs->block_map;
	if (!map)
		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;
}
static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
				e2_blkcnt_t blockcnt,
				blk_t ref_block EXT2FS_ATTR((unused)),
				int ref_offset EXT2FS_ATTR((unused)),
				void *priv_data)
{
	struct set_badblock_record *rec = (struct set_badblock_record *)
		priv_data;
	errcode_t	retval;
	unsigned long 	old_size;

	if (!*block_nr)
		return 0;

	/*
	 * If the block number is outrageous, clear it and ignore it.
	 */
	if (*block_nr >= ext2fs_blocks_count(fs->super) ||
	    *block_nr < fs->super->s_first_data_block) {
		*block_nr = 0;
		return BLOCK_CHANGED;
	}

	if (blockcnt < 0) {
		if (rec->ind_blocks_size >= rec->max_ind_blocks) {
			old_size = rec->max_ind_blocks * sizeof(blk_t);
			rec->max_ind_blocks += 10;
			retval = ext2fs_resize_mem(old_size,
				   rec->max_ind_blocks * sizeof(blk_t),
				   &rec->ind_blocks);
			if (retval) {
				rec->max_ind_blocks -= 10;
				rec->err = retval;
				return BLOCK_ABORT;
			}
		}
		rec->ind_blocks[rec->ind_blocks_size++] = *block_nr;
	}

	/*
	 * Mark the block as unused, and update accounting information
	 */
	ext2fs_block_alloc_stats2(fs, *block_nr, -1);

	*block_nr = 0;
	return BLOCK_CHANGED;
}
Example #17
0
blk64_t ext2fs_descriptor_block_loc2(ext2_filsys fs, blk64_t group_block,
				     dgrp_t i)
{
	int	bg;
	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 (!ext2fs_has_feature_meta_bg(fs->super) ||
	    (i < fs->super->s_first_meta_bg))
		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);
	/*
	 * If group_block is not the normal value, we're trying to use
	 * the backup group descriptors and superblock --- so use the
	 * alternate location of the second block group in the
	 * metablock group.  Ideally we should be testing each bg
	 * descriptor block individually for correctness, but we don't
	 * have the infrastructure in place to do that.
	 */
	if (group_block != fs->super->s_first_data_block &&
	    ((ret_blk + has_super + fs->super->s_blocks_per_group) <
	     ext2fs_blocks_count(fs->super))) {
		ret_blk += fs->super->s_blocks_per_group;

		/*
		 * 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;
}
Example #18
0
/*
 * This function returns the location of the superblock, block group
 * descriptors for a given block group.  It currently returns the
 * number of free blocks assuming that inode table and allocation
 * bitmaps will be in the group.  This is not necessarily the case
 * when the flex_bg feature is enabled, so callers should take care!
 * It was only really intended for use by mke2fs, and even there it's
 * not that useful.
 *
 * The ext2fs_super_and_bgd_loc2() function is 64-bit block number
 * capable and returns the number of blocks used by super block and
 * group descriptors.
 */
int ext2fs_super_and_bgd_loc(ext2_filsys fs,
			     dgrp_t group,
			     blk_t *ret_super_blk,
			     blk_t *ret_old_desc_blk,
			     blk_t *ret_new_desc_blk,
			     int *ret_meta_bg)
{
	blk64_t ret_super_blk2;
	blk64_t ret_old_desc_blk2;
	blk64_t ret_new_desc_blk2;
	blk_t ret_used_blks;
	blk_t numblocks;
	unsigned int meta_bg_size;

	ext2fs_super_and_bgd_loc2(fs, group, &ret_super_blk2,
					&ret_old_desc_blk2,
					&ret_new_desc_blk2,
					&ret_used_blks);

	if (group == fs->group_desc_count-1) {
		numblocks = (ext2fs_blocks_count(fs->super) -
			     (blk64_t) fs->super->s_first_data_block) %
			(blk64_t) fs->super->s_blocks_per_group;
		if (!numblocks)
			numblocks = fs->super->s_blocks_per_group;
	} else
		numblocks = fs->super->s_blocks_per_group;

	if (ret_super_blk)
		*ret_super_blk = (blk_t)ret_super_blk2;
	if (ret_old_desc_blk)
		*ret_old_desc_blk = (blk_t)ret_old_desc_blk2;
	if (ret_new_desc_blk)
		*ret_new_desc_blk = (blk_t)ret_new_desc_blk2;
	if (ret_meta_bg) {
		meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
		*ret_meta_bg = group / meta_bg_size;
	}

	numblocks -= 2 + fs->inode_blocks_per_group + ret_used_blks;

	return numblocks;
}
Example #19
0
/*
 * This function is called to deallocate a block, and is an interator
 * functioned called by deallocate inode via ext2fs_iterate_block().
 */
static int deallocate_inode_block(ext2_filsys fs,
				  blk64_t	*block_nr,
				  e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
				  blk64_t ref_block EXT2FS_ATTR((unused)),
				  int ref_offset EXT2FS_ATTR((unused)),
				  void *priv_data)
{
	struct del_block *p = priv_data;

	if (HOLE_BLKADDR(*block_nr))
		return 0;
	if ((*block_nr < fs->super->s_first_data_block) ||
	    (*block_nr >= ext2fs_blocks_count(fs->super)))
		return 0;
	ext2fs_unmark_block_bitmap2(p->ctx->block_found_map, *block_nr);
	ext2fs_block_alloc_stats2(fs, *block_nr, -1);
	p->num++;
	return 0;
}
static int mark_bad_block(ext2_filsys fs, blk_t *block_nr,
			  e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
			  blk_t ref_block EXT2FS_ATTR((unused)),
			  int ref_offset EXT2FS_ATTR((unused)),
			  void *priv_data)
{
	struct read_bb_record *rb = (struct read_bb_record *) priv_data;

	if (blockcnt < 0)
		return 0;

	if ((*block_nr < fs->super->s_first_data_block) ||
	    (*block_nr >= ext2fs_blocks_count(fs->super)))
		return 0;	/* Ignore illegal blocks */

	rb->err = ext2fs_badblocks_list_add(rb->bb_list, *block_nr);
	if (rb->err)
		return BLOCK_ABORT;
	return 0;
}
static int process_journal_block(ext2_filsys fs,
				 blk64_t	*block_nr,
				 e2_blkcnt_t blockcnt,
				 blk64_t ref_block EXT2FS_ATTR((unused)),
				 int ref_offset EXT2FS_ATTR((unused)),
				 void *priv_data)
{
	struct process_block_struct *p;
	blk64_t	blk = *block_nr;

	p = (struct process_block_struct *) priv_data;

	if (!blk || blk < fs->super->s_first_data_block ||
	    blk >= ext2fs_blocks_count(fs->super))
		return BLOCK_ABORT;

	if (blockcnt >= 0)
		p->last_block = blockcnt;
	return 0;
}
Example #22
0
/*
 * Reads a list of bad blocks from  a FILE *
 */
errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f,
			       ext2_badblocks_list *bb_list,
			       void *priv_data,
			       void (*invalid)(ext2_filsys fs,
					       blk_t blk,
					       char *badstr,
					       void *priv_data))
{
	errcode_t	retval;
	blk_t		blockno;
	int		count;
	char		buf[128];

	if (fs)
		EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);

	if (!*bb_list) {
		retval = ext2fs_badblocks_list_create(bb_list, 10);
		if (retval)
			return retval;
	}

	while (!feof (f)) {
		if (fgets(buf, sizeof(buf), f) == NULL)
			break;
		count = sscanf(buf, "%u", &blockno);
		if (count <= 0)
			continue;
		if (fs &&
		    ((blockno < fs->super->s_first_data_block) ||
		     (blockno >= ext2fs_blocks_count(fs->super)))) {
			if (invalid)
				(invalid)(fs, blockno, buf, priv_data);
			continue;
		}
		retval = ext2fs_badblocks_list_add(*bb_list, blockno);
		if (retval)
			return retval;
	}
	return 0;
}
Example #23
0
/*
 * This function reserves the superblock and block group descriptors
 * for a given block group.  It currently returns the number of free
 * blocks assuming that inode table and allocation bitmaps will be in
 * the group.  This is not necessarily the case when the flex_bg
 * feature is enabled, so callers should take care!  It was only
 * really intended for use by mke2fs, and even there it's not that
 * useful.  In the future, when we redo this function for 64-bit block
 * numbers, we should probably return the number of blocks used by the
 * super block and group descriptors instead.
 *
 * See also the comment for ext2fs_super_and_bgd_loc()
 */
int ext2fs_reserve_super_and_bgd(ext2_filsys fs,
                                 dgrp_t group,
                                 ext2fs_block_bitmap bmap)
{
    blk64_t	super_blk, old_desc_blk, new_desc_blk;
    blk_t	used_blks;
    int	j, old_desc_blocks, num_blocks;

    ext2fs_super_and_bgd_loc2(fs, group, &super_blk,
                              &old_desc_blk, &new_desc_blk, &used_blks);

    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;

    if (super_blk || (group == 0))
        ext2fs_mark_block_bitmap2(bmap, super_blk);
    if ((group == 0) && (fs->blocksize == 1024) &&
            EXT2FS_CLUSTER_RATIO(fs) > 1)
        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);
    }
    if (new_desc_blk)
        ext2fs_mark_block_bitmap2(bmap, new_desc_blk);

    num_blocks = ext2fs_group_blocks_count(fs, group);
    num_blocks -= 2 + fs->inode_blocks_per_group + used_blks;

    return num_blocks  ;
}
Example #24
0
static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
{
	dgrp_t 		i;
	unsigned int	j;
	int		block_nbytes, inode_nbytes;
	unsigned int	nbits;
	errcode_t	retval;
	char		*block_buf = NULL, *inode_buf = NULL;
	int		csum_flag = 0;
	blk64_t		blk;
	blk64_t		blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block);
	ext2_ino_t	ino_itr = 1;

	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);

	if (!(fs->flags & EXT2_FLAG_RW))
		return EXT2_ET_RO_FILSYS;

	if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
				       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
		csum_flag = 1;

	inode_nbytes = block_nbytes = 0;
	if (do_block) {
		block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
		retval = io_channel_alloc_buf(fs->io, 0, &block_buf);
		if (retval)
			goto errout;
		memset(block_buf, 0xff, fs->blocksize);
	}
	if (do_inode) {
		inode_nbytes = (size_t)
			((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
		retval = io_channel_alloc_buf(fs->io, 0, &inode_buf);
		if (retval)
			goto errout;
		memset(inode_buf, 0xff, fs->blocksize);
	}

	for (i = 0; i < fs->group_desc_count; i++) {
		if (!do_block)
			goto skip_block_bitmap;

		if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT)
		    )
			goto skip_this_block_bitmap;

		retval = ext2fs_get_block_bitmap_range2(fs->block_map,
				blk_itr, block_nbytes << 3, block_buf);
		if (retval)
			goto errout;

		if (i == fs->group_desc_count - 1) {
			/* Force bitmap padding for the last group */
			nbits = EXT2FS_NUM_B2C(fs,
				((ext2fs_blocks_count(fs->super)
				  - (__u64) fs->super->s_first_data_block)
				 % (__u64) EXT2_BLOCKS_PER_GROUP(fs->super)));
			if (nbits)
				for (j = nbits; j < fs->blocksize * 8; j++)
					ext2fs_set_bit(j, block_buf);
		}
		blk = ext2fs_block_bitmap_loc(fs, i);
		if (blk) {
			retval = io_channel_write_blk64(fs->io, blk, 1,
							block_buf);
			if (retval) {
				retval = EXT2_ET_BLOCK_BITMAP_WRITE;
				goto errout;
			}
		}
	skip_this_block_bitmap:
		blk_itr += block_nbytes << 3;
	skip_block_bitmap:

		if (!do_inode)
			continue;

		if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT)
		    )
			goto skip_this_inode_bitmap;

		retval = ext2fs_get_inode_bitmap_range2(fs->inode_map,
				ino_itr, inode_nbytes << 3, inode_buf);
		if (retval)
			goto errout;

		blk = ext2fs_inode_bitmap_loc(fs, i);
		if (blk) {
			retval = io_channel_write_blk64(fs->io, blk, 1,
						      inode_buf);
			if (retval) {
				retval = EXT2_ET_INODE_BITMAP_WRITE;
				goto errout;
			}
		}
	skip_this_inode_bitmap:
		ino_itr += inode_nbytes << 3;

	}
	if (do_block) {
		fs->flags &= ~EXT2_FLAG_BB_DIRTY;
		ext2fs_free_mem(&block_buf);
	}
	if (do_inode) {
		fs->flags &= ~EXT2_FLAG_IB_DIRTY;
		ext2fs_free_mem(&inode_buf);
	}
	return 0;
errout:
	if (inode_buf)
		ext2fs_free_mem(&inode_buf);
	if (block_buf)
		ext2fs_free_mem(&block_buf);
	return retval;
}
static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
{
	struct process_block_struct pb;
	struct ext2_super_block *sb = ctx->fs->super;
	struct ext2_super_block jsuper;
	struct problem_context	pctx;
	struct buffer_head 	*bh;
	struct inode		*j_inode = NULL;
	struct kdev_s		*dev_fs = NULL, *dev_journal;
	const char		*journal_name = 0;
	journal_t		*journal = NULL;
	errcode_t		retval = 0;
	io_manager		io_ptr = 0;
	unsigned long long	start = 0;
	int			ext_journal = 0;
	int			tried_backup_jnl = 0;

	clear_problem_context(&pctx);

	journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
	if (!journal) {
		return EXT2_ET_NO_MEMORY;
	}

	dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
	if (!dev_fs) {
		retval = EXT2_ET_NO_MEMORY;
		goto errout;
	}
	dev_journal = dev_fs+1;

	dev_fs->k_ctx = dev_journal->k_ctx = ctx;
	dev_fs->k_dev = K_DEV_FS;
	dev_journal->k_dev = K_DEV_JOURNAL;

	journal->j_dev = dev_journal;
	journal->j_fs_dev = dev_fs;
	journal->j_inode = NULL;
	journal->j_blocksize = ctx->fs->blocksize;

	if (uuid_is_null(sb->s_journal_uuid)) {
		if (!sb->s_journal_inum) {
			retval = EXT2_ET_BAD_INODE_NUM;
			goto errout;
		}
		j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
						 "journal inode");
		if (!j_inode) {
			retval = EXT2_ET_NO_MEMORY;
			goto errout;
		}

		j_inode->i_ctx = ctx;
		j_inode->i_ino = sb->s_journal_inum;

		if ((retval = ext2fs_read_inode(ctx->fs,
						sb->s_journal_inum,
						&j_inode->i_ext2))) {
		try_backup_journal:
			if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
			    tried_backup_jnl)
				goto errout;
			memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
			memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
			       EXT2_N_BLOCKS*4);
			j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15];
			j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
			j_inode->i_ext2.i_links_count = 1;
			j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
			e2fsck_use_inode_shortcuts(ctx, 1);
			ctx->stashed_ino = j_inode->i_ino;
			ctx->stashed_inode = &j_inode->i_ext2;
			tried_backup_jnl++;
		}
		if (!j_inode->i_ext2.i_links_count ||
		    !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
			retval = EXT2_ET_NO_JOURNAL;
			goto try_backup_journal;
		}
		if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize <
		    JFS_MIN_JOURNAL_BLOCKS) {
			retval = EXT2_ET_JOURNAL_TOO_SMALL;
			goto try_backup_journal;
		}
		pb.last_block = -1;
		retval = ext2fs_block_iterate3(ctx->fs, j_inode->i_ino,
					       BLOCK_FLAG_HOLE, 0,
					       process_journal_block, &pb);
		if ((pb.last_block + 1) * ctx->fs->blocksize <
		    EXT2_I_SIZE(&j_inode->i_ext2)) {
			retval = EXT2_ET_JOURNAL_TOO_SMALL;
			goto try_backup_journal;
		}
		if (tried_backup_jnl && !(ctx->options & E2F_OPT_READONLY)) {
			retval = ext2fs_write_inode(ctx->fs, sb->s_journal_inum,
						    &j_inode->i_ext2);
			if (retval)
				goto errout;
		}

		journal->j_maxlen = EXT2_I_SIZE(&j_inode->i_ext2) /
			journal->j_blocksize;

#ifdef USE_INODE_IO
		retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
						 &j_inode->i_ext2,
						 &journal_name);
		if (retval)
			goto errout;

		io_ptr = inode_io_manager;
#else
		journal->j_inode = j_inode;
		ctx->journal_io = ctx->fs->io;
		if ((retval = journal_bmap(journal, 0, &start)) != 0)
			goto errout;
#endif
	} else {
		ext_journal = 1;
		if (!ctx->journal_name) {
			char uuid[37];

			uuid_unparse(sb->s_journal_uuid, uuid);
			ctx->journal_name = blkid_get_devname(ctx->blkid,
							      "UUID", uuid);
			if (!ctx->journal_name)
				ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
		}
		journal_name = ctx->journal_name;

		if (!journal_name) {
			fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
			retval = EXT2_ET_LOAD_EXT_JOURNAL;
			goto errout;
		}

		jfs_debug(1, "Using journal file %s\n", journal_name);
		io_ptr = unix_io_manager;
	}

#if 0
	test_io_backing_manager = io_ptr;
	io_ptr = test_io_manager;
#endif
#ifndef USE_INODE_IO
	if (ext_journal)
#endif
		retval = io_ptr->open(journal_name,
				      IO_FLAG_RW | IO_FLAG_EXCLUSIVE,
				      &ctx->journal_io);
	if (retval)
		goto errout;

	io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);

	if (ext_journal) {
		if (ctx->fs->blocksize == 1024)
			start = 1;
		bh = getblk(dev_journal, start, ctx->fs->blocksize);
		if (!bh) {
			retval = EXT2_ET_NO_MEMORY;
			goto errout;
		}
		ll_rw_block(READ, 1, &bh);
		if ((retval = bh->b_err) != 0) {
			brelse(bh);
			goto errout;
		}
		memcpy(&jsuper, start ? bh->b_data :  bh->b_data + 1024,
		       sizeof(jsuper));
		brelse(bh);
#ifdef WORDS_BIGENDIAN
		if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
			ext2fs_swap_super(&jsuper);
#endif
		if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
		    !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
			fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
			retval = EXT2_ET_LOAD_EXT_JOURNAL;
			goto errout;
		}
		/* Make sure the journal UUID is correct */
		if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
			   sizeof(jsuper.s_uuid))) {
			fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
			retval = EXT2_ET_LOAD_EXT_JOURNAL;
			goto errout;
		}

		journal->j_maxlen = ext2fs_blocks_count(&jsuper);
		start++;
	}

	if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
		retval = EXT2_ET_NO_MEMORY;
		goto errout;
	}

	journal->j_sb_buffer = bh;
	journal->j_superblock = (journal_superblock_t *)bh->b_data;

#ifdef USE_INODE_IO
	if (j_inode)
		ext2fs_free_mem(&j_inode);
#endif

	*ret_journal = journal;
	e2fsck_use_inode_shortcuts(ctx, 0);
	return 0;

errout:
	e2fsck_use_inode_shortcuts(ctx, 0);
	if (dev_fs)
		ext2fs_free_mem(&dev_fs);
	if (j_inode)
		ext2fs_free_mem(&j_inode);
	if (journal)
		ext2fs_free_mem(&journal);
	return retval;
}
Example #26
0
/*
 * 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)
{
	char			*buf;
	dgrp_t			group, start, end, i, log_flex;
	errcode_t		retval;
	struct ext2_inode	inode;
	unsigned long long	inode_size;
	struct mkjournal_struct	es;

	if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags,
						       &buf)))
		return retval;

	if ((retval = ext2fs_read_bitmaps(fs)))
		goto out2;

	if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
		goto out2;

	if (inode.i_blocks > 0) {
		retval = EEXIST;
		goto out2;
	}

	es.num_blocks = num_blocks;
	es.newblocks = 0;
	es.buf = buf;
	es.err = 0;
	es.flags = flags;
	es.zero_count = 0;

	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)))
			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 = ext2fs_group_first_block2(fs, group);
	retval = ext2fs_block_iterate3(fs, journal_ino, BLOCK_FLAG_APPEND,
				       0, mkjournal_proc, &es);
	if (es.err) {
		retval = es.err;
		goto errout;
	}
	if (es.zero_count) {
		retval = ext2fs_zero_blocks2(fs, es.blk_to_zero,
					    es.zero_count, 0, 0);
		if (retval)
			goto errout;
	}

	if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
		goto errout;

	inode_size = (unsigned long long)fs->blocksize * num_blocks;
	inode.i_size = inode_size & 0xFFFFFFFF;
	inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF;
	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);
	inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0);
	inode.i_links_count = 1;
	inode.i_mode = LINUX_S_IFREG | 0600;

	if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode)))
		goto errout;
	retval = 0;

	memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
	fs->super->s_jnl_blocks[15] = inode.i_size_high;
	fs->super->s_jnl_blocks[16] = inode.i_size;
	fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
	ext2fs_mark_super_dirty(fs);

errout:
	ext2fs_zero_blocks2(0, 0, 0, 0, 0);
out2:
	ext2fs_free_mem(&buf);
	return retval;
}
Example #27
0
extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
				    ext2_ino_t ino, char *buf)
{
	ext2_filsys fs = ctx->fs;
	struct ext2_inode	inode;
	int			inode_modified = 0;
	int			not_fixed = 0;
	unsigned char		*frag, *fsize;
	struct problem_context	pctx;
	int	problem = 0;

	e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");

	clear_problem_context(&pctx);
	pctx.ino = ino;
	pctx.dir = dir;
	pctx.inode = &inode;

	if (ext2fs_file_acl_block(fs, &inode) &&
	    !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
		if (fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
			ext2fs_file_acl_block_set(fs, &inode, 0);
			inode_modified++;
		} else
			not_fixed++;
	}

	if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
	    !LINUX_S_ISCHR(inode.i_mode) && !LINUX_S_ISBLK(inode.i_mode) &&
	    !LINUX_S_ISLNK(inode.i_mode) && !LINUX_S_ISFIFO(inode.i_mode) &&
	    !(LINUX_S_ISSOCK(inode.i_mode)))
		problem = PR_2_BAD_MODE;
	else if (LINUX_S_ISCHR(inode.i_mode)
		 && !e2fsck_pass1_check_device_inode(fs, &inode))
		problem = PR_2_BAD_CHAR_DEV;
	else if (LINUX_S_ISBLK(inode.i_mode)
		 && !e2fsck_pass1_check_device_inode(fs, &inode))
		problem = PR_2_BAD_BLOCK_DEV;
	else if (LINUX_S_ISFIFO(inode.i_mode)
		 && !e2fsck_pass1_check_device_inode(fs, &inode))
		problem = PR_2_BAD_FIFO;
	else if (LINUX_S_ISSOCK(inode.i_mode)
		 && !e2fsck_pass1_check_device_inode(fs, &inode))
		problem = PR_2_BAD_SOCKET;
	else if (LINUX_S_ISLNK(inode.i_mode)
		 && !e2fsck_pass1_check_symlink(fs, ino, &inode, buf)) {
		problem = PR_2_INVALID_SYMLINK;
	}

	if (problem) {
		if (fix_problem(ctx, problem, &pctx)) {
			deallocate_inode(ctx, ino, 0);
			if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
				return 0;
			return 1;
		} else
			not_fixed++;
		problem = 0;
	}

	if (inode.i_faddr) {
		if (fix_problem(ctx, PR_2_FADDR_ZERO, &pctx)) {
			inode.i_faddr = 0;
			inode_modified++;
		} else
			not_fixed++;
	}

	switch (fs->super->s_creator_os) {
	    case EXT2_OS_HURD:
		frag = &inode.osd2.hurd2.h_i_frag;
		fsize = &inode.osd2.hurd2.h_i_fsize;
		break;
	    default:
		frag = fsize = 0;
	}
	if (frag && *frag) {
		pctx.num = *frag;
		if (fix_problem(ctx, PR_2_FRAG_ZERO, &pctx)) {
			*frag = 0;
			inode_modified++;
		} else
			not_fixed++;
		pctx.num = 0;
	}
	if (fsize && *fsize) {
		pctx.num = *fsize;
		if (fix_problem(ctx, PR_2_FSIZE_ZERO, &pctx)) {
			*fsize = 0;
			inode_modified++;
		} else
			not_fixed++;
		pctx.num = 0;
	}

	if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
	    !(fs->super->s_feature_ro_compat &
	      EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
	    (inode.osd2.linux2.l_i_blocks_hi != 0)) {
		pctx.num = inode.osd2.linux2.l_i_blocks_hi;
		if (fix_problem(ctx, PR_2_BLOCKS_HI_ZERO, &pctx)) {
			inode.osd2.linux2.l_i_blocks_hi = 0;
			inode_modified++;
		}
	}

	if (!(fs->super->s_feature_incompat & 
	     EXT4_FEATURE_INCOMPAT_64BIT) &&
	    inode.osd2.linux2.l_i_file_acl_high != 0) {
		pctx.num = inode.osd2.linux2.l_i_file_acl_high;
		if (fix_problem(ctx, PR_2_I_FILE_ACL_HI_ZERO, &pctx)) {
			inode.osd2.linux2.l_i_file_acl_high = 0;
			inode_modified++;
		} else
			not_fixed++;
	}

	if (ext2fs_file_acl_block(fs, &inode) &&
	    ((ext2fs_file_acl_block(fs, &inode) < fs->super->s_first_data_block) ||
	     (ext2fs_file_acl_block(fs, &inode) >= ext2fs_blocks_count(fs->super)))) {
		if (fix_problem(ctx, PR_2_FILE_ACL_BAD, &pctx)) {
			ext2fs_file_acl_block_set(fs, &inode, 0);
			inode_modified++;
		} else
			not_fixed++;
	}
	if (inode.i_dir_acl &&
	    LINUX_S_ISDIR(inode.i_mode)) {
		if (fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
			inode.i_dir_acl = 0;
			inode_modified++;
		} else
			not_fixed++;
	}

	if (inode_modified)
		e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
	if (!not_fixed && ctx->inode_bad_map)
		ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino);
	return 0;
}
Example #28
0
/*
 *  Note: if superblock is non-zero, block-size must also be non-zero.
 * 	Superblock and block_size can be zero to use the default size.
 *
 * Valid flags for ext2fs_open()
 *
 * 	EXT2_FLAG_RW	- Open the filesystem for read/write.
 * 	EXT2_FLAG_FORCE - Open the filesystem even if some of the
 *				features aren't supported.
 *	EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device
 *	EXT2_FLAG_SKIP_MMP - Open without multi-mount protection check.
 *	EXT2_FLAG_64BITS - Allow 64-bit bitfields (needed for large
 *				filesystems)
 */
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)
{
	ext2_filsys	fs;
	errcode_t	retval;
	unsigned long	i, first_meta_bg;
	__u32		features;
	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
	char		*time_env;

	EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);

	retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
	if (retval)
		return retval;

	memset(fs, 0, sizeof(struct struct_ext2_filsys));
	fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
	fs->flags = flags;
	/* don't overwrite sb backups unless flag is explicitly cleared */
	fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
	fs->umask = 022;

	time_env = getenv("E2FSPROGS_FAKE_TIME");
	if (time_env)
		fs->now = strtoul(time_env, NULL, 0);

	retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
	if (retval)
		goto cleanup;
	strcpy(fs->device_name, name);
	cp = strchr(fs->device_name, '?');
	if (!io_options && cp) {
		*cp++ = 0;
		io_options = cp;
	}

	io_flags = 0;
	if (flags & EXT2_FLAG_RW)
		io_flags |= IO_FLAG_RW;
	if (flags & EXT2_FLAG_EXCLUSIVE)
		io_flags |= IO_FLAG_EXCLUSIVE;
	if (flags & EXT2_FLAG_DIRECT_IO)
		io_flags |= IO_FLAG_DIRECT_IO;
	retval = manager->open(fs->device_name, io_flags, &fs->io);
	if (retval)
		goto cleanup;
	if (io_options &&
	    (retval = io_channel_set_options(fs->io, io_options)))
		goto cleanup;
	fs->image_io = fs->io;
	fs->io->app_data = fs;
	retval = io_channel_alloc_buf(fs->io, -SUPERBLOCK_SIZE, &fs->super);
	if (retval)
		goto cleanup;
	if (flags & EXT2_FLAG_IMAGE_FILE) {
		retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr),
					&fs->image_header);
		if (retval)
			goto cleanup;
		retval = io_channel_read_blk(fs->io, 0,
					     -(int)sizeof(struct ext2_image_hdr),
					     fs->image_header);
		if (retval)
			goto cleanup;
		if (fs->image_header->magic_number != EXT2_ET_MAGIC_E2IMAGE)
			return EXT2_ET_MAGIC_E2IMAGE;
		superblock = 1;
		block_size = fs->image_header->fs_blocksize;
	}

	/*
	 * If the user specifies a specific block # for the
	 * superblock, then he/she must also specify the block size!
	 * Otherwise, read the master superblock located at offset
	 * SUPERBLOCK_OFFSET from the start of the partition.
	 *
	 * Note: we only save a backup copy of the superblock if we
	 * are reading the superblock from the primary superblock location.
	 */
	if (superblock) {
		if (!block_size) {
			retval = EXT2_ET_INVALID_ARGUMENT;
			goto cleanup;
		}
		io_channel_set_blksize(fs->io, block_size);
		group_block = superblock;
		fs->orig_super = 0;
	} else {
		io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
		superblock = 1;
		group_block = 0;
		retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
		if (retval)
			goto cleanup;
	}
	retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE,
				     fs->super);
	if (retval)
		goto cleanup;
	if (fs->orig_super)
		memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);

	if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) {
		retval = 0;
		if (!ext2fs_verify_csum_type(fs, fs->super))
			retval = EXT2_ET_UNKNOWN_CSUM;
		if (!ext2fs_superblock_csum_verify(fs, fs->super))
			retval = EXT2_ET_SB_CSUM_INVALID;
	}

#ifdef WORDS_BIGENDIAN
	fs->flags |= EXT2_FLAG_SWAP_BYTES;
	ext2fs_swap_super(fs->super);
#else
	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
		retval = EXT2_ET_UNIMPLEMENTED;
		goto cleanup;
	}
#endif

	if (fs->super->s_magic != EXT2_SUPER_MAGIC)
		retval = EXT2_ET_BAD_MAGIC;
	if (retval)
		goto cleanup;

	if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) {
		retval = EXT2_ET_REV_TOO_HIGH;
		goto cleanup;
	}

	/*
	 * Check for feature set incompatibility
	 */
	if (!(flags & EXT2_FLAG_FORCE)) {
		features = fs->super->s_feature_incompat;
#ifdef EXT2_LIB_SOFTSUPP_INCOMPAT
		if (flags & EXT2_FLAG_SOFTSUPP_FEATURES)
			features &= ~EXT2_LIB_SOFTSUPP_INCOMPAT;
#endif
		if (features & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
			retval = EXT2_ET_UNSUPP_FEATURE;
			goto cleanup;
		}

		features = fs->super->s_feature_ro_compat;
#ifdef EXT2_LIB_SOFTSUPP_RO_COMPAT
		if (flags & EXT2_FLAG_SOFTSUPP_FEATURES)
			features &= ~EXT2_LIB_SOFTSUPP_RO_COMPAT;
#endif
		if ((flags & EXT2_FLAG_RW) &&
		    (features & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
			retval = EXT2_ET_RO_UNSUPP_FEATURE;
			goto cleanup;
		}

		if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) &&
		    ext2fs_has_feature_journal_dev(fs->super)) {
			retval = EXT2_ET_UNSUPP_FEATURE;
			goto cleanup;
		}
	}

	if ((fs->super->s_log_block_size + EXT2_MIN_BLOCK_LOG_SIZE) >
	    EXT2_MAX_BLOCK_LOG_SIZE) {
		retval = EXT2_ET_CORRUPT_SUPERBLOCK;
		goto cleanup;
	}

	/*
	 * bigalloc requires cluster-aware bitfield operations, which at the
	 * moment means we need EXT2_FLAG_64BITS.
	 */
	if (ext2fs_has_feature_bigalloc(fs->super) &&
	    !(flags & EXT2_FLAG_64BITS)) {
		retval = EXT2_ET_CANT_USE_LEGACY_BITMAPS;
		goto cleanup;
	}

	if (!ext2fs_has_feature_bigalloc(fs->super) &&
	    (fs->super->s_log_block_size != fs->super->s_log_cluster_size)) {
		retval = EXT2_ET_CORRUPT_SUPERBLOCK;
		goto cleanup;
	}
	fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
	if (EXT2_INODE_SIZE(fs->super) < EXT2_GOOD_OLD_INODE_SIZE) {
		retval = EXT2_ET_CORRUPT_SUPERBLOCK;
		goto cleanup;
	}

	/* Enforce the block group descriptor size */
	if (ext2fs_has_feature_64bit(fs->super)) {
		if (fs->super->s_desc_size < EXT2_MIN_DESC_SIZE_64BIT) {
			retval = EXT2_ET_BAD_DESC_SIZE;
			goto cleanup;
		}
	} else {
		if (fs->super->s_desc_size &&
		    fs->super->s_desc_size != EXT2_MIN_DESC_SIZE) {
			retval = EXT2_ET_BAD_DESC_SIZE;
			goto cleanup;
		}
	}

	fs->cluster_ratio_bits = fs->super->s_log_cluster_size -
		fs->super->s_log_block_size;
	if (EXT2_BLOCKS_PER_GROUP(fs->super) !=
	    EXT2_CLUSTERS_PER_GROUP(fs->super) << fs->cluster_ratio_bits) {
		retval = EXT2_ET_CORRUPT_SUPERBLOCK;
		goto cleanup;
	}
	fs->inode_blocks_per_group = ((EXT2_INODES_PER_GROUP(fs->super) *
				       EXT2_INODE_SIZE(fs->super) +
				       EXT2_BLOCK_SIZE(fs->super) - 1) /
				      EXT2_BLOCK_SIZE(fs->super));
	if (block_size) {
		if (block_size != fs->blocksize) {
			retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE;
			goto cleanup;
		}
	}
	/*
	 * Set the blocksize to the filesystem's blocksize.
	 */
	io_channel_set_blksize(fs->io, fs->blocksize);

	/*
	 * If this is an external journal device, don't try to read
	 * the group descriptors, because they're not there.
	 */
	if (ext2fs_has_feature_journal_dev(fs->super)) {
		fs->group_desc_count = 0;
		*ret_fs = fs;
		return 0;
	}

	if (EXT2_INODES_PER_GROUP(fs->super) == 0) {
		retval = EXT2_ET_CORRUPT_SUPERBLOCK;
		goto cleanup;
	}
	/* Precompute the FS UUID to seed other checksums */
	ext2fs_init_csum_seed(fs);

	/*
	 * Read group descriptors
	 */
	blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super);
	if (blocks_per_group == 0 ||
	    blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) ||
	    fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super) ||
           EXT2_DESC_PER_BLOCK(fs->super) == 0 ||
           fs->super->s_first_data_block >= ext2fs_blocks_count(fs->super)) {
		retval = EXT2_ET_CORRUPT_SUPERBLOCK;
		goto cleanup;
	}
	fs->group_desc_count = ext2fs_div64_ceil(ext2fs_blocks_count(fs->super) -
						 fs->super->s_first_data_block,
						 blocks_per_group);
	if (fs->group_desc_count * EXT2_INODES_PER_GROUP(fs->super) !=
	    fs->super->s_inodes_count) {
		retval = EXT2_ET_CORRUPT_SUPERBLOCK;
		goto cleanup;
	}
	fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
					  EXT2_DESC_PER_BLOCK(fs->super));
	retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize,
				&fs->group_desc);
	if (retval)
		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_zero_adjust = 1;
	dest = (char *) fs->group_desc;
#ifdef WORDS_BIGENDIAN
	groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
#endif
	if (ext2fs_has_feature_meta_bg(fs->super)) {
		first_meta_bg = fs->super->s_first_meta_bg;
		if (first_meta_bg > fs->desc_blocks)
			first_meta_bg = fs->desc_blocks;
	} else
		first_meta_bg = fs->desc_blocks;
	if (first_meta_bg) {
		retval = io_channel_read_blk(fs->io, group_block +
					     group_zero_adjust + 1,
					     first_meta_bg, dest);
		if (retval)
			goto cleanup;
#ifdef WORDS_BIGENDIAN
		gdp = (struct ext2_group_desc *) dest;
		for (j=0; j < groups_per_block*first_meta_bg; j++) {
			gdp = ext2fs_group_desc(fs, fs->group_desc, j);
			ext2fs_swap_group_desc2(fs, gdp);
		}
#endif
		dest += fs->blocksize*first_meta_bg;
	}
	for (i=first_meta_bg ; i < fs->desc_blocks; i++) {
		blk = ext2fs_descriptor_block_loc2(fs, group_block, i);
		retval = io_channel_read_blk64(fs->io, blk, 1, dest);
		if (retval)
			goto cleanup;
#ifdef WORDS_BIGENDIAN
		for (j=0; j < groups_per_block; j++) {
			gdp = ext2fs_group_desc(fs, fs->group_desc,
						i * groups_per_block + j);
			ext2fs_swap_group_desc2(fs, gdp);
		}
#endif
		dest += fs->blocksize;
	}

	fs->stride = fs->super->s_raid_stride;

	/*
	 * If recovery is from backup superblock, Clear _UNININT flags &
	 * reset bg_itable_unused to zero
	 */
	if (superblock > 1 && ext2fs_has_group_desc_csum(fs)) {
		dgrp_t group;

		for (group = 0; group < fs->group_desc_count; group++) {
			ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
			ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
			ext2fs_bg_itable_unused_set(fs, group, 0);
			/* The checksum will be reset later, but fix it here
			 * anyway to avoid printing a lot of spurious errors. */
			ext2fs_group_desc_csum_set(fs, group);
		}
		if (fs->flags & EXT2_FLAG_RW)
			ext2fs_mark_super_dirty(fs);
	}

	if (ext2fs_has_feature_mmp(fs->super) &&
	    !(flags & EXT2_FLAG_SKIP_MMP) &&
	    (flags & (EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE))) {
		retval = ext2fs_mmp_start(fs);
		if (retval) {
			fs->flags |= EXT2_FLAG_SKIP_MMP; /* just do cleanup */
			ext2fs_mmp_stop(fs);
			goto cleanup;
		}
	}

	if (fs->flags & EXT2_FLAG_SHARE_DUP) {
		fs->block_sha_map = ext2fs_hashmap_create(ext2fs_djb2_hash,
					block_sha_map_free_entry, 4096);
		if (!fs->block_sha_map) {
			retval = EXT2_ET_NO_MEMORY;
			goto cleanup;
		}
		ext2fs_set_feature_shared_blocks(fs->super);
	}

	fs->flags &= ~EXT2_FLAG_NOFREE_ON_ERROR;
	*ret_fs = fs;

	return 0;
cleanup:
	if (!(flags & EXT2_FLAG_NOFREE_ON_ERROR)) {
		ext2fs_free(fs);
		fs = NULL;
	}
	*ret_fs = fs;
	return retval;
}
int main (int argc, char ** argv)
{
	errcode_t	retval;
	ext2_filsys	fs;
	int		c;
	int		flags = 0;
	int		flush = 0;
	int		force = 0;
	int		io_flags = 0;
	int		force_min_size = 0;
	int		print_min_size = 0;
	int		fd, ret;
	blk64_t		new_size = 0;
	blk64_t		max_size = 0;
	blk64_t		min_size = 0;
	io_manager	io_ptr;
	char		*new_size_str = 0;
	int		use_stride = -1;
	ext2fs_struct_stat st_buf;
	__s64		new_file_size;
	unsigned int	sys_page_size = 4096;
	long		sysval;
	int		len, mount_flags;
	char		*mtpt;

#ifdef ENABLE_NLS
	setlocale(LC_MESSAGES, "");
	setlocale(LC_CTYPE, "");
	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
	textdomain(NLS_CAT_NAME);
	set_com_err_gettext(gettext);
#endif

	add_error_table(&et_ext2_error_table);

	fprintf (stderr, "resize2fs %s (%s)\n",
		 E2FSPROGS_VERSION, E2FSPROGS_DATE);
	if (argc && *argv)
		program_name = *argv;

	while ((c = getopt (argc, argv, "d:fFhMPpS:")) != EOF) {
		switch (c) {
		case 'h':
			usage(program_name);
			break;
		case 'f':
			force = 1;
			break;
		case 'F':
			flush = 1;
			break;
		case 'M':
			force_min_size = 1;
			break;
		case 'P':
			print_min_size = 1;
			break;
		case 'd':
			flags |= atoi(optarg);
			break;
		case 'p':
			flags |= RESIZE_PERCENT_COMPLETE;
			break;
		case 'S':
			use_stride = atoi(optarg);
			break;
		default:
			usage(program_name);
		}
	}
	if (optind == argc)
		usage(program_name);

	device_name = argv[optind++];
	if (optind < argc)
		new_size_str = argv[optind++];
	if (optind < argc)
		usage(program_name);

	io_options = strchr(device_name, '?');
	if (io_options)
		*io_options++ = 0;

	/*
	 * Figure out whether or not the device is mounted, and if it is
	 * where it is mounted.
	 */
	len=80;
	while (1) {
		mtpt = malloc(len);
		if (!mtpt)
			return ENOMEM;
		mtpt[len-1] = 0;
		retval = ext2fs_check_mount_point(device_name, &mount_flags,
						  mtpt, len);
		if (retval) {
			com_err("ext2fs_check_mount_point", retval,
				_("while determining whether %s is mounted."),
				device_name);
			exit(1);
		}
		if (!(mount_flags & EXT2_MF_MOUNTED) || (mtpt[len-1] == 0))
			break;
		free(mtpt);
		len = 2 * len;
	}

	fd = ext2fs_open_file(device_name, O_RDWR, 0);
	if (fd < 0) {
		com_err("open", errno, _("while opening %s"),
			device_name);
		exit(1);
	}

	ret = ext2fs_fstat(fd, &st_buf);
	if (ret < 0) {
		com_err("open", errno,
			_("while getting stat information for %s"),
			device_name);
		exit(1);
	}

	if (flush) {
		retval = ext2fs_sync_device(fd, 1);
		if (retval) {
			com_err(argv[0], retval,
				_("while trying to flush %s"),
				device_name);
			exit(1);
		}
	}

	if (!S_ISREG(st_buf.st_mode )) {
		close(fd);
		fd = -1;
	}

#ifdef CONFIG_TESTIO_DEBUG
	if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
		io_ptr = test_io_manager;
		test_io_backing_manager = unix_io_manager;
	} else
#endif
		io_ptr = unix_io_manager;

	if (!(mount_flags & EXT2_MF_MOUNTED))
		io_flags = EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE;

	io_flags |= EXT2_FLAG_64BITS;

	retval = ext2fs_open2(device_name, io_options, io_flags,
			      0, 0, io_ptr, &fs);
	if (retval) {
		com_err (program_name, retval, _("while trying to open %s"),
			 device_name);
		printf (_("Couldn't find valid filesystem superblock.\n"));
		exit (1);
	}

	/*
	 * Check for compatibility with the feature sets.  We need to
	 * be more stringent than ext2fs_open().
	 */
	if (fs->super->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) {
		com_err(program_name, EXT2_ET_UNSUPP_FEATURE,
			"(%s)", device_name);
		exit(1);
	}

	min_size = calculate_minimum_resize_size(fs);

	if (print_min_size) {
		if (!force && ((fs->super->s_state & EXT2_ERROR_FS) ||
			       ((fs->super->s_state & EXT2_VALID_FS) == 0))) {
			fprintf(stderr,
				_("Please run 'e2fsck -f %s' first.\n\n"),
				device_name);
			exit(1);
		}
		printf(_("Estimated minimum size of the filesystem: %llu\n"),
		       min_size);
		exit(0);
	}

	/* Determine the system page size if possible */
#ifdef HAVE_SYSCONF
#if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
#define _SC_PAGESIZE _SC_PAGE_SIZE
#endif
#ifdef _SC_PAGESIZE
	sysval = sysconf(_SC_PAGESIZE);
	if (sysval > 0)
		sys_page_size = sysval;
#endif /* _SC_PAGESIZE */
#endif /* HAVE_SYSCONF */

	/*
	 * Get the size of the containing partition, and use this for
	 * defaults and for making sure the new filesystem doesn't
	 * exceed the partition size.
	 */
	retval = ext2fs_get_device_size2(device_name, fs->blocksize,
					 &max_size);
	if (retval) {
		com_err(program_name, retval,
			_("while trying to determine filesystem size"));
		exit(1);
	}
	if (force_min_size)
		new_size = min_size;
	else if (new_size_str) {
		new_size = parse_num_blocks2(new_size_str,
					     fs->super->s_log_block_size);
		if (new_size == 0) {
			com_err(program_name, 0,
				_("Invalid new size: %s\n"), new_size_str);
			exit(1);
		}
	} else {
		new_size = max_size;
		/* Round down to an even multiple of a pagesize */
		if (sys_page_size > fs->blocksize)
			new_size &= ~((sys_page_size / fs->blocksize)-1);
	}
	if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
				       EXT4_FEATURE_INCOMPAT_64BIT)) {
		/* Take 16T down to 2^32-1 blocks */
		if (new_size == (1ULL << 32))
			new_size--;
		else if (new_size > (1ULL << 32)) {
			com_err(program_name, 0,
				_("New size too large to be "
				  "expressed in 32 bits\n"));
			exit(1);
		}
	}

	if (!force && new_size < min_size) {
		com_err(program_name, 0,
			_("New size smaller than minimum (%llu)\n"), min_size);
		exit(1);
	}
	if (use_stride >= 0) {
		if (use_stride >= (int) fs->super->s_blocks_per_group) {
			com_err(program_name, 0,
				_("Invalid stride length"));
			exit(1);
		}
		fs->stride = fs->super->s_raid_stride = use_stride;
		ext2fs_mark_super_dirty(fs);
	} else
		  determine_fs_stride(fs);

	/*
	 * If we are resizing a plain file, and it's not big enough,
	 * automatically extend it in a sparse fashion by writing the
	 * last requested block.
	 */
	new_file_size = ((__u64) new_size) * fs->blocksize;
	if ((__u64) new_file_size >
	    (((__u64) 1) << (sizeof(st_buf.st_size)*8 - 1)) - 1)
		fd = -1;
	if ((new_file_size > st_buf.st_size) &&
	    (fd > 0)) {
		if ((ext2fs_llseek(fd, new_file_size-1, SEEK_SET) >= 0) &&
		    (write(fd, "0", 1) == 1))
			max_size = new_size;
	}
	if (!force && (new_size > max_size)) {
		fprintf(stderr, _("The containing partition (or device)"
			" is only %llu (%dk) blocks.\nYou requested a new size"
			" of %llu blocks.\n\n"), max_size,
			fs->blocksize / 1024, new_size);
		exit(1);
	}
	if (new_size == ext2fs_blocks_count(fs->super)) {
		fprintf(stderr, _("The filesystem is already %llu blocks "
			"long.  Nothing to do!\n\n"), new_size);
		exit(0);
	}
	if (mount_flags & EXT2_MF_MOUNTED) {
		retval = online_resize_fs(fs, mtpt, &new_size, flags);
	} else {
		if (!force && ((fs->super->s_lastcheck < fs->super->s_mtime) ||
			       (fs->super->s_state & EXT2_ERROR_FS) ||
			       ((fs->super->s_state & EXT2_VALID_FS) == 0))) {
			fprintf(stderr,
				_("Please run 'e2fsck -f %s' first.\n\n"),
				device_name);
			exit(1);
		}
		/*
		 * XXXX The combination of flex_bg and !resize_inode
		 * causes major problems for resize2fs, since when the
		 * group descriptors grow in size this can potentially
		 * require multiple inode tables to be moved aside to
		 * make room, and resize2fs chokes rather badly in
		 * this scenario.  It's a rare combination, except
		 * when a filesystem is expanded more than a certain
		 * size, so for now, we'll just prohibit that
		 * combination.  This is something we should fix
		 * eventually, though.
		 */
		if ((fs->super->s_feature_incompat &
		     EXT4_FEATURE_INCOMPAT_FLEX_BG) &&
		    !(fs->super->s_feature_compat &
		      EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
			com_err(program_name, 0, _("%s: The combination of "
				"flex_bg and\n\t!resize_inode features "
				"is not supported by resize2fs.\n"),
				device_name);
			exit(1);
		}
		printf(_("Resizing the filesystem on "
			 "%s to %llu (%dk) blocks.\n"),
		       device_name, new_size, fs->blocksize / 1024);
		retval = resize_fs(fs, &new_size, flags,
				   ((flags & RESIZE_PERCENT_COMPLETE) ?
				    resize_progress_func : 0));
	}
	free(mtpt);
	if (retval) {
		com_err(program_name, retval, _("while trying to resize %s"),
			device_name);
		fprintf(stderr,
			_("Please run 'e2fsck -fy %s' to fix the filesystem\n"
			  "after the aborted resize operation.\n"),
			device_name);
		ext2fs_close(fs);
		exit(1);
	}
	printf(_("The filesystem on %s is now %llu blocks long.\n\n"),
	       device_name, new_size);

	if ((st_buf.st_size > new_file_size) &&
	    (fd > 0)) {
#ifdef HAVE_FTRUNCATE64
		retval = ftruncate64(fd, new_file_size);
#else
		retval = 0;
		/* Only truncate if new_file_size doesn't overflow off_t */
		if (((off_t) new_file_size) == new_file_size)
			retval = ftruncate(fd, (off_t) new_file_size);
#endif
		if (retval)
			com_err(program_name, retval,
				_("while trying to truncate %s"),
				device_name);
	}
	if (fd > 0)
		close(fd);
	remove_error_table(&et_ext2_error_table);
	return (0);
}
Example #30
0
static void dump_journal(char *cmdname, FILE *out_file,
			 struct journal_source *source)
{
	struct ext2_super_block *sb;
	char			jsb_buffer[1024];
	char			buf[8192];
	journal_superblock_t	*jsb;
	unsigned int		blocksize = 1024;
	int			retval;
	__u32			magic, sequence, blocktype;
	journal_header_t	*header;
	tid_t			transaction;
	unsigned int		blocknr = 0;

	/* First, check to see if there's an ext2 superblock header */
	retval = read_journal_block(cmdname, source, 0, buf, 2048);
	if (retval)
		return;

	jsb = (journal_superblock_t *) buf;
	sb = (struct ext2_super_block *) (buf+1024);
#ifdef WORDS_BIGENDIAN
	if (sb->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
		ext2fs_swap_super(sb);
#endif

	if ((be32_to_cpu(jsb->s_header.h_magic) != JFS_MAGIC_NUMBER) &&
	    (sb->s_magic == EXT2_SUPER_MAGIC) &&
	    ext2fs_has_feature_journal_dev(sb)) {
		blocksize = EXT2_BLOCK_SIZE(sb);
		blocknr = (blocksize == 1024) ? 2 : 1;
		uuid_unparse(sb->s_uuid, jsb_buffer);
		fprintf(out_file, "Ext2 superblock header found.\n");
		if (dump_all) {
			fprintf(out_file, "\tuuid=%s\n", jsb_buffer);
			fprintf(out_file, "\tblocksize=%d\n", blocksize);
			fprintf(out_file, "\tjournal data size %lu\n",
				(unsigned long) ext2fs_blocks_count(sb));
		}
	}

	/* Next, read the journal superblock */
	retval = read_journal_block(cmdname, source,
				    ((ext2_loff_t) blocknr) * blocksize,
				    jsb_buffer, 1024);
	if (retval)
		return;

	jsb = (journal_superblock_t *) jsb_buffer;
	if (be32_to_cpu(jsb->s_header.h_magic) != JFS_MAGIC_NUMBER) {
		fprintf(out_file,
			"Journal superblock magic number invalid!\n");
		return;
	}
	blocksize = be32_to_cpu(jsb->s_blocksize);
	transaction = be32_to_cpu(jsb->s_sequence);
	blocknr = be32_to_cpu(jsb->s_start);

	fprintf(out_file, "Journal starts at block %u, transaction %u\n",
		blocknr, transaction);

	if (!blocknr) {
		/* Empty journal, nothing to do. */
		if (!dump_old)
			return;
		else
			blocknr = 1;
	}

	while (1) {
		retval = read_journal_block(cmdname, source,
				((ext2_loff_t) blocknr) * blocksize,
				buf, blocksize);
		if (retval)
			return;

		header = (journal_header_t *) buf;

		magic = be32_to_cpu(header->h_magic);
		sequence = be32_to_cpu(header->h_sequence);
		blocktype = be32_to_cpu(header->h_blocktype);

		if (magic != JFS_MAGIC_NUMBER) {
			fprintf (out_file, "No magic number at block %u: "
				 "end of journal.\n", blocknr);
			return;
		}

		if (sequence != transaction) {
			fprintf (out_file, "Found sequence %u (not %u) at "
				 "block %u: end of journal.\n",
				 sequence, transaction, blocknr);
			if (!dump_old)
				return;
		}

		if (dump_descriptors) {
			fprintf (out_file, "Found expected sequence %u, "
				 "type %u (%s) at block %u\n",
				 sequence, blocktype,
				 type_to_name(blocktype), blocknr);
		}

		switch (blocktype) {
		case JFS_DESCRIPTOR_BLOCK:
			dump_descriptor_block(out_file, source, buf, jsb,
					      &blocknr, blocksize,
					      transaction);
			continue;

		case JFS_COMMIT_BLOCK:
			transaction++;
			blocknr++;
			WRAP(jsb, blocknr);
			continue;

		case JFS_REVOKE_BLOCK:
			dump_revoke_block(out_file, buf, jsb,
					  blocknr, blocksize,
					  transaction);
			blocknr++;
			WRAP(jsb, blocknr);
			continue;

		default:
			fprintf (out_file, "Unexpected block type %u at "
				 "block %u.\n", blocktype, blocknr);
			return;
		}
	}
}