/* the first one of the mainest functions */
int expand_fs(void) {
	struct reiserfs_super_block *  sb;
	struct buffer_head * bm_bh;
	int block_r, block_r_new;
	int i;
	
	sb = (struct reiserfs_super_block *) g_sb_bh->b_data;

	/* count used bits in last bitmap block */
	block_r = sb->s_block_count -
		((sb->s_bmap_nr - 1) * sb->s_blocksize * 8);
	
	/* count bitmap blocks in new fs */
	g_bmap_nr_new = g_block_count_new / (sb->s_blocksize * 8);
	block_r_new = g_block_count_new -
		g_bmap_nr_new * sb->s_blocksize	* 8;
	if(block_r_new)
		g_bmap_nr_new++;
	else 
		block_r_new = sb->s_blocksize * 8;

	/* clear bits in last bitmap block (old layout) */
	bm_bh = get_bm_blk(g_sb_bh->b_dev, sb->s_bmap_nr - 1, sb->s_blocksize);
	for (i = block_r; i < sb->s_blocksize * 8; i++)
		clear_bit(i, bm_bh->b_data);
	bwrite_cond(bm_bh);
	
	/* add new bitmap blocks */
	for (i = sb->s_bmap_nr; i < g_bmap_nr_new; i++) {
		memset(bm_bh->b_data, 0, bm_bh->b_size);
		set_bit(0, bm_bh->b_data);
		bm_bh->b_blocknr =  			/* It is not a first BM block */
			i * sb->s_blocksize * 8;	/* with special location */
		bwrite_cond(bm_bh);
	}
	
	/* set unused bits in last bitmap block (new layout) */
	for (i = block_r_new; i < sb->s_blocksize * 8; i++)
		set_bit(i, bm_bh->b_data);
	bwrite_cond(bm_bh);

	/* update super block buffer*/
	sb->s_free_blocks += g_block_count_new - sb->s_block_count
		- (g_bmap_nr_new - sb->s_bmap_nr);
	sb->s_block_count = g_block_count_new;
	sb->s_bmap_nr = g_bmap_nr_new;

	/* commit changes */
	bwrite_cond(g_sb_bh);

	brelse(g_sb_bh);
	brelse(bm_bh);
	
	return 0;
}
/* the first one of the mainest functions */
int expand_fs (reiserfs_filsys_t fs, unsigned long block_count_new) {
    int block_r, block_r_new;
    unsigned int bmap_nr_new, bmap_nr_old;
    int i;

    reiserfs_bitmap_t bmp;
    struct reiserfs_super_block * rs = fs->s_rs;

    reiserfs_reopen(fs, O_RDWR);
    set_state (fs->s_rs, REISERFS_ERROR_FS);
    bwrite_cond(SB_BUFFER_WITH_SB(fs));

    bmp = reiserfs_create_bitmap(rs_block_count(rs));
    if (!bmp)
        die ("cannot create bitmap\n");
    reiserfs_fetch_disk_bitmap(bmp, fs);
    reiserfs_free_bitmap_blocks(fs);
    if (reiserfs_expand_bitmap(bmp, block_count_new))
        die ("cannot expand bitmap\n");

    /* clean bits in old bitmap tail */
    for (i = rs_block_count(rs);
            i < rs_bmap_nr(rs) * rs_blocksize(rs) * 8 && i < block_count_new;
            i++) {
        reiserfs_bitmap_clear_bit(bmp, i);
    }

    /* count used bits in last bitmap block */
    block_r = rs_block_count(rs) - ((rs_bmap_nr(rs) - 1) * rs_blocksize(rs) * 8);

    /* count bitmap blocks in new fs */
    bmap_nr_new = (block_count_new - 1) / (rs_blocksize(rs) * 8) + 1;
    block_r_new = block_count_new - (bmap_nr_new - 1) * rs_blocksize(rs) * 8;

    bmap_nr_old = rs_bmap_nr(rs);

    /* update super block buffer*/
    set_free_blocks (rs, rs_free_blocks(rs) + block_count_new
                     - rs_block_count(rs) - (bmap_nr_new - rs_bmap_nr(rs)));
    set_block_count (rs, block_count_new);
    set_bmap_nr (rs, bmap_nr_new);

    reiserfs_read_bitmap_blocks(fs);
    for (i = bmap_nr_old; i < bmap_nr_new; i++) /* fix new bitmap blocks */
        reiserfs_bitmap_set_bit(bmp, SB_AP_BITMAP(fs)[i]->b_blocknr);
    reiserfs_flush_bitmap(bmp, fs);

    return 0;
}
int main(int argc, char *argv[]) {
    char * bytes_count_str = NULL;
    char * devname;
    reiserfs_filsys_t fs;
    struct reiserfs_super_block * rs;

    int c;
    int error;

    struct reiserfs_super_block *sb_old;

    unsigned long block_count_new;

    print_banner ("resize_reiserfs");

    while ((c = getopt(argc, argv, "fvcqs:")) != EOF) {
        switch (c) {
        case 's' :
            if (!optarg)
                die("%s: Missing argument to -s option", argv[0]);
            bytes_count_str = optarg;
            break;
        case 'f':
            opt_force = 1;
            break;
        case 'v':
            opt_verbose++;
            break;
        case 'n':
            /* no nowrite option at this moment */
            /* opt_nowrite = 1; */
            break;
        case 'c':
            opt_safe = 1;
            break;
        case 'q':
            opt_verbose = 0;
            break;
        default:
            print_usage_and_exit ();
        }
    }

    if (optind == argc )
        print_usage_and_exit();
    devname = argv[optind];

    fs = reiserfs_open(devname, O_RDONLY, &error, 0);
    if (!fs)
        die ("%s: can not open '%s': %s", argv[0], devname, strerror(error));

    if (no_reiserfs_found (fs)) {
        die ("resize_reiserfs: no reiserfs found on the device");
    }
    if (!spread_bitmaps (fs)) {
        die ("resize_reiserfs: cannot resize reiserfs in old (not spread bitmap) format.\n");
    }

    rs = fs->s_rs;

    if(bytes_count_str) {	/* new fs size is specified by user */
        block_count_new = calc_new_fs_size(rs_block_count(rs), fs->s_blocksize, bytes_count_str);
    } else {		/* use whole device */
        block_count_new = count_blocks(devname, fs->s_blocksize, -1);
    }

    if (is_mounted (devname)) {
        reiserfs_close(fs);
        return resize_fs_online(devname, block_count_new);
    }

    if (rs_state(rs) != REISERFS_VALID_FS)
        die ("%s: the file system isn't in valid state\n", argv[0]);

    if(!valid_offset(fs->s_dev, (loff_t) block_count_new * fs->s_blocksize - 1))
        die ("%s: %s too small", argv[0], devname);

    sb_old = 0;		/* Needed to keep idiot compiler from issuing false warning */
    /* save SB for reporting */
    if(opt_verbose) {
        sb_old = getmem(SB_SIZE);
        memcpy(sb_old, SB_DISK_SUPER_BLOCK(fs), SB_SIZE);
    }

    if (block_count_new == SB_BLOCK_COUNT(fs))
        die ("%s: Calculated fs size is the same as the previous one.", argv[0]);

    if (block_count_new > SB_BLOCK_COUNT(fs))
        expand_fs(fs, block_count_new);
    else
        shrink_fs(fs, block_count_new);

    if(opt_verbose) {
        sb_report(rs, sb_old);
        freemem(sb_old);
    }

    set_state (rs, REISERFS_VALID_FS);
    bwrite_cond(SB_BUFFER_WITH_SB(fs));

    if (opt_verbose) {
        printf("\nSyncing..");
        fflush(stdout);
    }
    reiserfs_close (fs);
    if (opt_verbose)
        printf("done\n");

    return 0;
}