Beispiel #1
0
extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui){
    unsigned long zones = get_nzones();
    unsigned long imaps = get_nimaps();
    unsigned long zmaps = get_nzmaps();
    char * inode_map;
    char * zone_map;
    ssize_t rc;
    unsigned long test_block = 0, test_zone = 0;

    fs_open(device);

    unsigned long block_size = get_block_size();

    if (fs_version == 3){
	if (lseek(dev, block_size*2, SEEK_SET) != 8192)
	    log_mesg(0, 1, 1, fs_opt.debug, "%s: seek failed", __FILE__);
    }

    inode_map = malloc(imaps * block_size);
    if (!inode_map)
	log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to allocate buffer for inode map", __FILE__);
    zone_map = malloc(zmaps * block_size);
    if (!inode_map)
	log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to allocate buffer for zone map", __FILE__);
    memset(inode_map,0,sizeof(inode_map));
    memset(zone_map,0,sizeof(zone_map));
    memset(bitmap,0,sizeof(unsigned long)*LONGS(image_hdr.totalblock));

    rc = read(dev, inode_map, imaps * block_size);
    if (rc < 0 || imaps * block_size != (size_t) rc)
	log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to read inode map", __FILE__);

    rc = read(dev, zone_map, zmaps * block_size);
    if (rc < 0 || zmaps * block_size != (size_t) rc)
	log_mesg(0, 1, 1, fs_opt.debug, "%s: Unable to read zone map", __FILE__);

    log_mesg(0, 0, 0, fs_opt.debug, "%s: %ld blocks\n", __FILE__, zones);
    log_mesg(0, 0, 0, fs_opt.debug, "%s: log2 block/zone: %lu\n", __FILE__, get_zone_size());
    log_mesg(0, 0, 0, fs_opt.debug, "%s: Zonesize=%d\n", __FILE__,block_size<<get_zone_size());
    log_mesg(0, 0, 0, fs_opt.debug, "%s: Maxsize=%ld\n", __FILE__, get_max_size());


    for (test_block = 0; test_block < zones; test_block++){
	test_zone = test_block - get_first_zone()+1;
	if ((test_zone < 0) || (test_zone > zones+get_first_zone()))
	    test_zone = 0;
	if(isset(zone_map,test_zone)){
	    log_mesg(3, 0, 0, fs_opt.debug, "%s: test_block %lu in use\n", __FILE__, test_block);    
	    pc_set_bit(test_block, bitmap);
	}else{
	    log_mesg(3, 0, 0, fs_opt.debug, "%s: test_block %lu not use\n", __FILE__, test_block);    
	}
    }
    fs_close();
}
Beispiel #2
0
/// check free memory size
int check_mem_size(image_head image_hdr, cmd_opt opt, unsigned long long *mem_size) {
	unsigned long long image_head_size = 0;
	unsigned long long bitmap_size = 0;
	int crc_io_size = 0;
	void *test_mem;

	image_head_size = sizeof(image_head);
	bitmap_size = sizeof(unsigned long)*LONGS(image_hdr.totalblock);
	crc_io_size = CRC_SIZE+image_hdr.block_size;
	*mem_size = image_head_size + bitmap_size + crc_io_size;
	log_mesg(0, 0, 0, 1, "we need memory: %llu bytes\nimage head %llu, bitmap %llu, crc %i bytes\n", *mem_size, image_head_size, bitmap_size, crc_io_size);

	test_mem = malloc(*mem_size);
	if (test_mem == NULL){
		free(test_mem);
		return -1;
	} else {
		free(test_mem);
	}
	return 1;
}
Beispiel #3
0
/// get_used_block - get FAT used blocks
static unsigned long long get_used_block()
{
    unsigned long long i = 0;
    int fat_stat = 0;
    unsigned long long block = 0, bfree = 0, bused = 0, DamagedClusters = 0;
    unsigned long long cluster_count = 0, total_sector = 0;
    unsigned long long real_back_block= 0;
    int FatReservedBytes = 0;
    unsigned long *fat_bitmap;

    log_mesg(2, 0, 0, fs_opt.debug, "%s: get_used_block start\n", __FILE__);

    total_sector = get_total_sector();
    cluster_count = get_cluster_count();

    fat_bitmap = (unsigned long *)calloc(sizeof(unsigned long), LONGS(total_sector));
    if (fat_bitmap == NULL)
        log_mesg(2, 1, 1, fs_opt.debug, "%s: bitmapalloc error\n", __FILE__);
    memset(fat_bitmap, 0xFF, sizeof(unsigned long)*LONGS(total_sector));

    /// A) B) C)
    block = mark_reserved_sectors(fat_bitmap, block);

    /// D) The clusters
    FatReservedBytes = fat_sb.sector_size * fat_sb.reserved;

    /// The first fat will be seek
    lseek(ret, FatReservedBytes, SEEK_SET);

    /// The second fat is used to check FAT status
    fat_stat = check_fat_status();
    if (fat_stat == 1)
        log_mesg(0, 1, 1, fs_opt.debug, "%s: Filesystem isn't in valid state. May be it is not cleanly unmounted.\n\n", __FILE__);
    else if (fat_stat == 2)
        log_mesg(0, 1, 1, fs_opt.debug, "%s: I/O error! %X\n", __FILE__);

    for (i=0; i < cluster_count; i++){
        /// If FAT16
        if(FS == FAT_16){
            block = check_fat16_entry(fat_bitmap, block, &bfree, &bused, &DamagedClusters);
        } else if (FS == FAT_32){ /// FAT32
            block = check_fat32_entry(fat_bitmap, block, &bfree, &bused, &DamagedClusters);
        } else if (FS == FAT_12){ /// FAT12
            block = check_fat12_entry(fat_bitmap, block, &bfree, &bused, &DamagedClusters);
        } else 
            log_mesg(2, 0, 0, fs_opt.debug, "%s: error fs\n", __FILE__);
    }

    while(block < total_sector){
        pc_set_bit(block, fat_bitmap);
        block++;
    }


    for (block = 0; block < total_sector; block++)
    {
        if (pc_test_bit(block, fat_bitmap)) {
            real_back_block++;
        }
    }
    free(fat_bitmap);
    log_mesg(2, 0, 0, fs_opt.debug, "%s: get_used_block down\n", __FILE__);

    return real_back_block;
}
Beispiel #4
0
/// readbitmap - read and check bitmap
extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui)
{
    unsigned long long i = 0;
    int fat_stat = 0;
    unsigned long long block = 0, bfree = 0, bused = 0, DamagedClusters = 0;
    unsigned long long cluster_count = 0;
    unsigned long long total_sector = 0;
    unsigned long long FatReservedBytes = 0;
    int start = 0;
    int bit_size = 1;

    fs_open(device);

    total_sector = get_total_sector();
    cluster_count = get_cluster_count();

    /// init progress
    progress_bar   prog;	/// progress_bar structure defined in progress.h
    progress_init(&prog, start, cluster_count, image_hdr.totalblock, BITMAP, bit_size);

    /// init bitmap
    memset(bitmap, 0xFF, sizeof(unsigned long)*LONGS(total_sector));

    /// A) B) C)
    block = mark_reserved_sectors(bitmap, block);

    /// D) The clusters
    FatReservedBytes = fat_sb.sector_size * fat_sb.reserved;

    /// The first cluster will be seek
    lseek(ret, FatReservedBytes, SEEK_SET);

    /// The second used to check FAT status
    fat_stat = check_fat_status();
    if(fs_opt.ignore_fschk){
        log_mesg(1, 0, 0, fs_opt.debug, "%s: Ignore filesystem check\n", __FILE__);
    }else{
        if (fat_stat == 1)
            log_mesg(0, 1, 1, fs_opt.debug, "%s: Filesystem isn't in valid state. May be it is not cleanly unmounted.\n\n", __FILE__);
        else if (fat_stat == 2)
            log_mesg(0, 1, 1, fs_opt.debug, "%s: I/O error! %X\n", __FILE__);
    }

    for (i=0; i < cluster_count; i++){
        /// If FAT16
        if(FS == FAT_16){
            block = check_fat16_entry(bitmap, block, &bfree, &bused, &DamagedClusters);
        } else if (FS == FAT_32){ /// FAT32
            block = check_fat32_entry(bitmap, block, &bfree, &bused, &DamagedClusters);
        } else if (FS == FAT_12){ /// FAT12
            block = check_fat12_entry(bitmap, block, &bfree, &bused, &DamagedClusters);
        } else 
            log_mesg(2, 0, 0, fs_opt.debug, "%s: error fs\n", __FILE__);
        /// update progress
        update_pui(&prog, i, i, 0);//keep update
    }

    log_mesg(2, 0, 0, fs_opt.debug, "%s: done\n", __FILE__);
    fs_close();

    /// update progress
    update_pui(&prog, 1, 1, 1);//finish
}
Beispiel #5
0
/// readbitmap - cread and heck bitmap, reference dumpe2fs
extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui){
    errcode_t retval;
    unsigned long group;
    unsigned long long current_block, block;
    unsigned long long free, gfree;
    char *block_bitmap=NULL;
    int block_nbytes;
    unsigned long long blk_itr;
    int bg_flags = 0;
    int start = 0;
    int bit_size = 1;
    int B_UN_INIT = 0;
    int ext4_gfree_mismatch = 0;

    log_mesg(2, 0, 0, fs_opt.debug, "%s: readbitmap %p\n", __FILE__, bitmap);

    fs_open(device);
    retval = ext2fs_read_bitmaps(fs); /// open extfs bitmap
    if (retval)
	log_mesg(0, 1, 1, fs_opt.debug, "%s: Couldn't find valid filesystem bitmap.\n", __FILE__);

    block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
    if (fs->block_map)
	block_bitmap = malloc(block_nbytes);

    /// initial image bitmap as 1 (all block are used)
    memset(bitmap, 0xFF, sizeof(unsigned long)*LONGS(image_hdr.totalblock));

    free = 0;
    current_block = 0;
    blk_itr = fs->super->s_first_data_block;

    /// init progress
    progress_bar	prog;		/// progress_bar structure defined in progress.h
    progress_init(&prog, start, image_hdr.totalblock, image_hdr.totalblock, BITMAP, bit_size);

    /// each group
    for (group = 0; group < fs->group_desc_count; group++) {

	gfree = 0;
	B_UN_INIT = 0;

	if (block_bitmap) {
	    ext2fs_get_block_bitmap_range(fs->block_map, blk_itr, block_nbytes << 3, block_bitmap);

	    if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM){
#ifdef EXTFS_1_41		
		    bg_flags = fs->group_desc[group].bg_flags;
#else
		    bg_flags = ext2fs_bg_flags(fs, group);
#endif
		    if (bg_flags&EXT2_BG_BLOCK_UNINIT){
			log_mesg(1, 0, 0, fs_opt.debug, "%s: BLOCK_UNINIT for group %lu\n", __FILE__, group);
			B_UN_INIT = 1;
		    } else {
			log_mesg(2, 0, 0, fs_opt.debug, "%s: BLOCK_INIT for group %lu\n", __FILE__, group);
		    }
	    }
	    /// each block in group
	    for (block = 0; ((block < fs->super->s_blocks_per_group) && (current_block < (image_hdr.totalblock-1))); block++) {
		current_block = block + blk_itr;

		/// check block is used or not
		if ((!in_use (block_bitmap, block)) || (B_UN_INIT)) {
		    free++;
		    gfree++;
		    pc_clear_bit(current_block, bitmap);
		    log_mesg(3, 0, 0, fs_opt.debug, "%s: free block %llu at group %lu init %i\n", __FILE__, current_block, group, (int)B_UN_INIT);
		} else {
		    pc_set_bit(current_block, bitmap);
		    log_mesg(3, 0, 0, fs_opt.debug, "%s: used block %llu at group %lu\n", __FILE__, current_block, group);
		}
		/// update progress
		update_pui(&prog, current_block, current_block, 0);//keep update
	    }
	    blk_itr += fs->super->s_blocks_per_group;
	}
	/// check free blocks in group
#ifdef EXTFS_1_41		
	if (gfree != fs->group_desc[group].bg_free_blocks_count){	
#else
	if (gfree != ext2fs_bg_free_blocks_count(fs, group)){
#endif
	    if (!B_UN_INIT)
		log_mesg(0, 1, 1, fs_opt.debug, "%s: bitmap error at %lu group.\n", __FILE__, group);
	    else
		ext4_gfree_mismatch = 1;
	}
    }
    /// check all free blocks in partition
    if (free != fs->super->s_free_blocks_count) {
	if ((fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) && (ext4_gfree_mismatch))
	    log_mesg(1, 0, 0, fs_opt.debug, "%s: EXT4 bitmap metadata mismatch\n", __FILE__);
	else
	    log_mesg(0, 1, 1, fs_opt.debug, "%s: bitmap free count err, free:%llu\n", __FILE__, free);
    }

    fs_close();
    /// update progress
    update_pui(&prog, 1, 1, 1);//finish
}

/// get extfs type
static int test_extfs_type(char* device){
    int ext2 = 1;
    int ext3 = 2;
    int ext4 = 3;
    int device_type;

    fs_open(device);
    if(fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM){
	log_mesg(1, 0, 0, fs_opt.debug, "%s: test feature as EXT4\n", __FILE__);
	device_type = ext4;
    } else if (fs->super->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL){
	log_mesg(1, 0, 0, fs_opt.debug, "%s: test feature as EXT3\n", __FILE__);
	device_type = ext3;
    } else {
	log_mesg(1, 0, 0, fs_opt.debug, "%s: test feature as EXT2\n", __FILE__);
	device_type = ext2;
    }
    fs_close();
    return device_type;
}
Beispiel #6
0
/**
 * main functiom - for colne or restore data
 */
int main(int argc, char **argv){ 

    int			dfr;		/// file descriptor for source and target
    int			r_size;		/// read and write size
    char*		buffer;		/// buffer data
    char*		buffer2;		/// buffer data
    //unsigned long long	block_id, copied = 0;	/// block_id is every block in partition
    /// copied is copied block count
    off_t		offset = 0, sf = 0;	/// seek postition, lseek result
    int			start, stop;		/// start, range, stop number for progress bar
    char		bitmagic[8] = "BiTmAgIc";// only for check postition
    char		bitmagic_r[8];		/// read magic string from image
    int			cmp;			/// compare magic string
    unsigned long	*bitmap;		/// the point for bitmap data
    int			debug = 0;		/// debug or not
    unsigned long	crc = 0xffffffffL;	/// CRC32 check code for writint to image
    unsigned long	crc_ck = 0xffffffffL;	/// CRC32 check code for checking
    unsigned long	crc_ck2 = 0xffffffffL;	/// CRC32 check code for checking
    int			c_size;			/// CRC32 code size
    //int			done = 0;
    int			tui = 0;		/// text user interface
    int			pui = 0;		/// progress mode(default text)
    int			flag = 0;

    int pres;
    pthread_t prog_thread;
    void *p_result;

    //progress_bar	prog;			/// progress_bar structure defined in progress.h
    image_head		image_hdr;		/// image_head structure defined in partclone.h

    /**
     * get option and assign to opt structure
     * check parameter and read from argv
     */
    parse_option_chkimg(argc, argv, &opt);

    /**
     * if "-d / --debug" given
     * open debug file in "/var/log/partclone.log" for log message 
     */
    debug = opt.debug;
    open_log(opt.logfile);

    /**
     * using Text User Interface
     */
    if (opt.ncurses){
        pui = NCURSES;
        log_mesg(1, 0, 0, debug, "Using Ncurses User Interface mode.\n");
    } else
        pui = TEXT;

    tui = open_pui(pui, opt.fresh);
    if ((opt.ncurses) && (tui == 0)){
        opt.ncurses = 0;
        log_mesg(1, 0, 0, debug, "Open Ncurses User Interface Error.\n");
    }

    /// print partclone info
    print_partclone_info(opt);

    /*
    if (geteuid() != 0)
        log_mesg(0, 1, 1, debug, "You are not logged as root. You may have \"access denied\" errors when working.\n"); 
    else
        log_mesg(1, 0, 0, debug, "UID is root.\n");
     */
    /// ignore crc check
    if(opt.ignore_crc)
	log_mesg(1, 0, 1, debug, "Ignore CRC\n");

    /**
     * open source and target 
     * clone mode, source is device and target is image file/stdout
     * restore mode, source is image file/stdin and target is device
     * dd mode, source is device and target is device !!not complete
     */
#ifdef _FILE_OFFSET_BITS
    log_mesg(1, 0, 0, debug, "enable _FILE_OFFSET_BITS %i\n", _FILE_OFFSET_BITS);
#endif
    dfr = open_source(opt.source, &opt);
    if (dfr == -1) {
        log_mesg(0, 1, 1, debug, "Erro EXIT.\n");
    }

    /**
     * get partition information like super block, image_head, bitmap
     * from device or image file.
     */


    log_mesg(1, 0, 0, debug, "Checking image hdr - get image_head from image file\n");

    restore_image_hdr(&dfr, &opt, &image_hdr);
    /// check the image magic
    if (memcmp(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE) != 0)
        log_mesg(0, 1, 1, debug, "The Image magic error. This file is NOT partclone Image\n");

    /// alloc a memory to restore bitmap
    bitmap = (unsigned long*)calloc(sizeof(unsigned long), LONGS(image_hdr.totalblock));
    if(bitmap == NULL){
        log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
    }

    log_mesg(2, 0, 0, debug, "initial main bitmap pointer %p\n", bitmap);
    log_mesg(1, 0, 0, debug, "Initial image hdr - read bitmap table\n");

    /// read and check bitmap from image file
    log_mesg(0, 0, 1, debug, "Calculating bitmap... ");
    log_mesg(0, 0, 1, debug, "Please wait... ");
    get_image_bitmap(&dfr, opt, image_hdr, bitmap);

    log_mesg(2, 0, 0, debug, "check main bitmap pointer %p\n", bitmap);
    log_mesg(0, 0, 1, debug, "done!\n");

    log_mesg(1, 0, 0, debug, "print image_head\n");

    /// print option to log file
    if (debug)
        print_opt(opt);

    /// print image_head
    print_image_hdr_info(image_hdr, opt);

    /**
     * initial progress bar
     */
    start = 0;				/// start number of progress bar
    stop = image_hdr.usedblocks;	/// get the end of progress number, only used block
    log_mesg(1, 0, 0, debug, "Initial Progress bar\n");
    /// Initial progress bar
    if (opt.no_block_detail)
	flag = NO_BLOCK_DETAIL;
    else
	flag = IO;
    progress_init(&prog, start, stop, image_hdr.totalblock, flag, image_hdr.block_size);
    copied = 0;

    /**
     * thread to print progress
     */
    pres = pthread_create(&prog_thread, NULL, thread_update_pui, NULL);

    /**
     * start read and write data between device and image file
     */

    /**
     * read magic string from image file
     * and check it.
     */
    r_size = read_all(&dfr, bitmagic_r, 8, &opt); /// read a magic string
    cmp = memcmp(bitmagic, bitmagic_r, 8);
    if(cmp != 0)
        log_mesg(0, 1, 1, debug, "bitmagic error %i\n", cmp);

    /// start restore image file to partition
    for( block_id = 0; block_id < image_hdr.totalblock; block_id++ ){

        r_size = 0;

        if (pc_test_bit(block_id, bitmap)){
            /// The block is used
            log_mesg(2, 0, 0, debug, "block_id=%llu, ",block_id);
            log_mesg(1, 0, 0, debug, "bitmap=%i, ",pc_test_bit(block_id, bitmap));

            offset = (off_t)(block_id * image_hdr.block_size);
            buffer = (char*)malloc(image_hdr.block_size); ///alloc a memory to copy data
            if(buffer == NULL){
                log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
            }
            r_size = read_all(&dfr, buffer, image_hdr.block_size, &opt);
            log_mesg(1, 0, 0, debug, "bs=%i and r=%i, ",image_hdr.block_size, r_size);
            if (r_size <0)
                log_mesg(0, 1, 1, debug, "read errno = %i \n", errno);

            /// read crc32 code and check it.
            crc_ck = crc32(crc_ck, buffer, r_size);
            char crc_buffer[CRC_SIZE];
            c_size = read_all(&dfr, crc_buffer, CRC_SIZE, &opt);
            if (c_size < CRC_SIZE){
                log_mesg(0, 0, 1, debug, "read CRC error, please check your image file. \n");
                log_mesg(0, 0, 1, debug, "read CRC size (%i), %s. \n", c_size, strerror(errno));
		lseek(dfr, (int)(CRC_SIZE-c_size), SEEK_CUR);
		}
            if ((memcmp(crc_buffer, &crc_ck, CRC_SIZE) != 0) && (!opt.ignore_crc)){
		log_mesg(1, 0, 0, debug, "Ignore_crc 2 %i\n ", opt.ignore_crc);

                log_mesg(1, 0, 0, debug, "CRC Check error. 64bit bug before v0.1.0 (Rev:250M), enlarge crc size and recheck again....\n ");
                /// check again
                buffer2 = (char*)malloc(image_hdr.block_size+CRC_SIZE); ///alloc a memory to copy data
                if(buffer2 == NULL){
                    log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
                }
                memcpy(buffer2, buffer, image_hdr.block_size);
                memcpy(buffer2+image_hdr.block_size, crc_buffer, CRC_SIZE);
                memcpy(buffer, buffer2+CRC_SIZE, image_hdr.block_size);

                crc_ck2 = crc32(crc_ck2, buffer, r_size);
                c_size = read_all(&dfr, crc_buffer, CRC_SIZE, &opt);
                if (c_size < CRC_SIZE)
                    log_mesg(0, 1, 1, debug, "read CRC error: %s, please check your image file. \n", strerror(errno));
                memcpy(&crc, crc_buffer, CRC_SIZE);
                if ((memcmp(&crc, &crc_ck2, CRC_SIZE) != 0) && (!opt.ignore_crc)){
                    log_mesg(0, 1, 1, debug, "CRC error again at %ji...\n ", (intmax_t)sf);
                } else {
                    crc_ck = crc_ck2;
                }
                free(buffer2);

            } else {
                crc_ck2 = crc_ck;
            }

            /// free buffer
            free(buffer);
            copied++;					/// count copied block
            log_mesg(1, 0, 0, debug, "end\n");
        }

	//update_pui(&prog, copied, block_id, done);
    } // end of for
    done = 1;
    pres = pthread_join(prog_thread, &p_result);
    update_pui(&prog, copied, block_id, done);
    print_finish_info(opt);

    close (dfr);    /// close source
    free(bitmap);   /// free bitmp
    close_pui(pui);
    printf("Checked successfully.\n");
    if(opt.debug)
        close_log();
    return 0;	    /// finish
}
Beispiel #7
0
/// readbitmap - read bitmap
extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui)
{
	/// initial image bitmap as 1 (all block are used)
	memset(bitmap, 0xFF, sizeof(unsigned long)*LONGS(image_hdr.totalblock));
}
Beispiel #8
0
/**
 * main functiom - for colne or restore data
 */
int main(int argc, char **argv) {
#ifdef MEMTRACE
    setenv("MALLOC_TRACE", "partclone_mtrace.log", 1);
    mtrace();
#endif
    char*		source;			/// source data
    char*		target;			/// target data
    char*		buffer;			/// buffer data for malloc used
    char*		buffer2;			/// buffer data for malloc used
    int			dfr, dfw;		/// file descriptor for source and target
    int			r_size, w_size;		/// read and write size
    //unsigned long long	block_id, copied = 0;	/// block_id is every block in partition
    /// copied is copied block count
    off_t		offset = 0, sf = 0;	/// seek postition, lseek result
    int			start, stop;		/// start, range, stop number for progress bar
    unsigned long long	total_write = 0;	/// the copied size
    unsigned long long	needed_size = 0;	/// the copied size
    unsigned long long	needed_mem  = 0;	/// the copied size
    char		bitmagic[8] = "BiTmAgIc";// only for check postition
    char		bitmagic_r[8]="00000000";/// read magic string from image
    int			cmp;			/// compare magic string
    unsigned long	*bitmap;		/// the point for bitmap data
    int			debug = 0;		/// debug or not
    unsigned long	crc = 0xffffffffL;	/// CRC32 check code for writint to image
    unsigned long	crc_ck = 0xffffffffL;	/// CRC32 check code for checking
    unsigned long	crc_ck2 = 0xffffffffL;	/// CRC32 check code for checking
    int			c_size;			/// CRC32 code size
    int			n_crc_size = CRC_SIZE;
    char*		crc_buffer;		/// buffer data for malloc crc code
    //int			done = 0;
    int			s_count = 0;
    int			rescue_num = 0;
    unsigned long long			rescue_pos = 0;
    unsigned long long			main_pos = 0;
    int			tui = 0;		/// text user interface
    int			pui = 0;		/// progress mode(default text)
    int                 next=1,next_int=1,next_max_count=7,next_count=7,i;
    unsigned long long  next_block_id;
    char*               cache_buffer;
    int                 nx_current=0;
    char                bbuffer[4096];
    int flag;
    int pres;
    pthread_t prog_thread;
    void *p_result;

    char *bad_sectors_warning_msg =
        "*************************************************************************\n"
        "* WARNING: The disk has bad sector. This means physical damage on the   *\n"
        "* disk surface caused by deterioration, manufacturing faults or other   *\n"
        "* reason. The reliability of the disk may stay stable or degrade fast.  *\n"
        "* Use the --rescue option to efficiently save as much data as possible! *\n"
        "*************************************************************************\n";

    image_head		image_hdr;		/// image_head structure defined in partclone.h
    memset(&image_hdr, 0, sizeof(image_hdr));

    /**
     * get option and assign to opt structure
     * check parameter and read from argv
     */
    parse_options(argc, argv, &opt);

    /**
     * if "-d / --debug" given
     * open debug file in "/var/log/partclone.log" for log message
     */
    memset(&fs_opt, 0, sizeof(fs_cmd_opt));
    debug = opt.debug;
    fs_opt.debug = debug;
    fs_opt.ignore_fschk = opt.ignore_fschk;

    next_max_count = opt.max_block_cache-1;
    next_count = opt.max_block_cache-1;

    //if(opt.debug)
    open_log(opt.logfile);

    /**
     * using Text User Interface
     */
    if (opt.ncurses) {
        pui = NCURSES;
        log_mesg(1, 0, 0, debug, "Using Ncurses User Interface mode.\n");
    } else
        pui = TEXT;

    tui = open_pui(pui, opt.fresh);
    if ((opt.ncurses) && (tui == 0)) {
        opt.ncurses = 0;
        log_mesg(1, 0, 0, debug, "Open Ncurses User Interface Error.\n");
    }

    /// print partclone info
    print_partclone_info(opt);

    if (geteuid() != 0)
        log_mesg(0, 1, 1, debug, "You are not logged as root. You may have \"access denied\" errors when working.\n");
    else
        log_mesg(1, 0, 0, debug, "UID is root.\n");

    /// ignore crc check
    if(opt.ignore_crc)
        log_mesg(1, 0, 1, debug, "Ignore CRC error\n");

    /**
     * open source and target
     * clone mode, source is device and target is image file/stdout
     * restore mode, source is image file/stdin and target is device
     * dd mode, source is device and target is device !!not complete
     */
#ifdef _FILE_OFFSET_BITS
    log_mesg(1, 0, 0, debug, "enable _FILE_OFFSET_BITS %i\n", _FILE_OFFSET_BITS);
#endif
    source = opt.source;
    target = opt.target;
    dfr = open_source(source, &opt);
    if (dfr == -1) {
        log_mesg(0, 1, 1, debug, "Erro EXIT.\n");
    }

    dfw = open_target(target, &opt);
    if (dfw == -1) {
        log_mesg(0, 1, 1, debug, "Error Exit.\n");
    }

    /**
     * get partition information like super block, image_head, bitmap
     * from device or image file.
     */
    if (opt.clone) {

        log_mesg(1, 0, 0, debug, "Initial image hdr - get Super Block from partition\n");
        log_mesg(0, 0, 1, debug, "Reading Super Block\n");

        /// get Super Block information from partition
        initial_image_hdr(source, &image_hdr);

        /// check memory size
        if (check_mem_size(image_hdr, opt, &needed_mem) == -1)
            log_mesg(0, 1, 1, debug, "Ther is no enough free memory, partclone suggests you should have %lld bytes memory\n", needed_mem);

        strncpy(image_hdr.version, IMAGE_VERSION, VERSION_SIZE);

        /// alloc a memory to restore bitmap
        bitmap = (unsigned long*)calloc(sizeof(unsigned long), LONGS(image_hdr.totalblock));
        if(bitmap == NULL) {
            log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
        }

        log_mesg(2, 0, 0, debug, "initial main bitmap pointer %i\n", bitmap);
        log_mesg(1, 0, 0, debug, "Initial image hdr - read bitmap table\n");

        /// read and check bitmap from partition
        log_mesg(0, 0, 1, debug, "Calculating bitmap... Please wait... ");
        readbitmap(source, image_hdr, bitmap, pui);

        needed_size = (unsigned long long)(((image_hdr.block_size+sizeof(unsigned long))*image_hdr.usedblocks)+sizeof(image_hdr)+sizeof(char)*image_hdr.totalblock);
        if (opt.check)
            check_free_space(&dfw, needed_size);

        log_mesg(2, 0, 0, debug, "check main bitmap pointer %i\n", bitmap);

        log_mesg(1, 0, 0, debug, "Writing super block and bitmap... ");
        // write image_head to image file
        w_size = write_all(&dfw, (char *)&image_hdr, sizeof(image_head), &opt);
        if(w_size == -1)
            log_mesg(0, 1, 1, debug, "write image_hdr to image error\n");

        // write bitmap information to image file
        for (i = 0; i < image_hdr.totalblock; i++) {
            if (pc_test_bit(i, bitmap)) {
                bbuffer[i % sizeof(bbuffer)] = 1;
            } else {
                bbuffer[i % sizeof(bbuffer)] = 0;
            }
            if (i % sizeof(bbuffer) == sizeof(bbuffer) - 1 || i == image_hdr.totalblock - 1) {
                w_size = write_all(&dfw, bbuffer, 1 + (i % sizeof(bbuffer)), &opt);
                if(w_size == -1)
                    log_mesg(0, 1, 1, debug, "write bitmap to image error\n");
            }
        }
        log_mesg(0, 0, 1, debug, "done!\n");
    } else if (opt.restore) {

        log_mesg(1, 0, 0, debug, "restore image hdr - get image_head from image file\n");
        log_mesg(1, 0, 1, debug, "Reading Super Block\n");
        /// get image information from image file
        restore_image_hdr(&dfr, &opt, &image_hdr);

        /// check memory size
        if (check_mem_size(image_hdr, opt, &needed_mem) == -1)
            log_mesg(0, 1, 1, debug, "Ther is no enough free memory, partclone suggests you should have %lld bytes memory\n", needed_mem);

        /// alloc a memory to restore bitmap
        bitmap = (unsigned long*)calloc(sizeof(unsigned long), LONGS(image_hdr.totalblock));
        if(bitmap == NULL) {
            log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
        }

        /// check the image magic
        if (memcmp(image_hdr.magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE) != 0)
            log_mesg(0, 1, 1, debug, "This is not partclone image.\n");

        /// check the file system
        //if (strcmp(image_hdr.fs, FS) != 0)
        //    log_mesg(0, 1, 1, debug, "%s can't restore from the image which filesystem is %s not %s\n", argv[0], image_hdr.fs, FS);

        log_mesg(2, 0, 0, debug, "initial main bitmap pointer %lli\n", bitmap);
        log_mesg(1, 0, 0, debug, "Initial image hdr - read bitmap table\n");

        /// read and check bitmap from image file
        log_mesg(0, 0, 1, debug, "Calculating bitmap... Please wait... ");
        get_image_bitmap(&dfr, opt, image_hdr, bitmap);

        /// check the dest partition size.
        if (opt.restore_row_file)
            check_free_space(&dfw, image_hdr.device_size);
        else if(opt.check)
            check_size(&dfw, image_hdr.device_size);

        log_mesg(2, 0, 0, debug, "check main bitmap pointer %i\n", bitmap);
        log_mesg(0, 0, 1, debug, "done!\n");
    } else if (opt.dd) {
        log_mesg(1, 0, 0, debug, "Initial image hdr - get Super Block from partition\n");
        log_mesg(1, 0, 1, debug, "Reading Super Block\n");

        /// get Super Block information from partition
        initial_image_hdr(source, &image_hdr);

        /// check memory size
        if (check_mem_size(image_hdr, opt, &needed_mem) == -1)
            log_mesg(0, 1, 1, debug, "Ther is no enough free memory, partclone suggests you should have %lld bytes memory\n", needed_mem);

        strncpy(image_hdr.version, IMAGE_VERSION, VERSION_SIZE);

        /// alloc a memory to restore bitmap
        bitmap = (unsigned long*)calloc(sizeof(unsigned long), LONGS(image_hdr.totalblock));
        if(bitmap == NULL) {
            log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
        }

        log_mesg(2, 0, 0, debug, "initial main bitmap pointer %i\n", bitmap);
        log_mesg(1, 0, 0, debug, "Initial image hdr - read bitmap table\n");

        /// read and check bitmap from partition
        log_mesg(0, 0, 1, debug, "Calculating bitmap... Please wait... ");
        readbitmap(source, image_hdr, bitmap, pui);

        /// check the dest partition size.
        if(opt.check) {
            check_size(&dfw, image_hdr.device_size);
        }

        log_mesg(2, 0, 0, debug, "check main bitmap pointer %i\n", bitmap);
        log_mesg(0, 0, 1, debug, "done!\n");
    } else if (opt.domain) {
        log_mesg(1, 0, 0, debug, "Initial image hdr - get Super Block from partition\n");
        log_mesg(1, 0, 1, debug, "Reading Super Block\n");

        /// get Super Block information from partition
        initial_image_hdr(source, &image_hdr);

        /// check memory size
        if (check_mem_size(image_hdr, opt, &needed_mem) == -1)
            log_mesg(0, 1, 1, debug, "Ther is no enough free memory, partclone suggests you should have %lld bytes memory\n", needed_mem);

        strncpy(image_hdr.version, IMAGE_VERSION, VERSION_SIZE);

        /// alloc a memory to restore bitmap
        bitmap = (unsigned long*)calloc(sizeof(unsigned long), LONGS(image_hdr.totalblock));
        if(bitmap == NULL) {
            log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
        }

        log_mesg(2, 0, 0, debug, "initial main bitmap pointer %i\n", bitmap);
        log_mesg(1, 0, 0, debug, "Initial image hdr - read bitmap table\n");

        /// read and check bitmap from partition
        log_mesg(0, 0, 1, debug, "Calculating bitmap... Please wait... ");
        readbitmap(source, image_hdr, bitmap, pui);

        log_mesg(2, 0, 0, debug, "check main bitmap pointer %i\n", bitmap);
        log_mesg(0, 0, 1, debug, "done!\n");
    }

    log_mesg(1, 0, 0, debug, "print image_head\n");

    /// print option to log file
    if (debug)
        print_opt(opt);

    /// print image_head
    print_image_hdr_info(image_hdr, opt);

    /**
     * initial progress bar
     */
    //progress_bar	prog;		/// progress_bar structure defined in progress.h
    start = 0;				/// start number of progress bar
    stop = (image_hdr.usedblocks);	/// get the end of progress number, only used block
    log_mesg(1, 0, 0, debug, "Initial Progress bar\n");
    /// Initial progress bar
    if (opt.no_block_detail)
        flag = NO_BLOCK_DETAIL;
    else
        flag = IO;
    progress_init(&prog, start, stop, image_hdr.totalblock, flag, image_hdr.block_size);
    copied = 0;				/// initial number is 0

    /**
     * thread to print progress
     */
    pres = pthread_create(&prog_thread, NULL, thread_update_pui, NULL);

    /**
     * start read and write data between device and image file
     */
    if (opt.clone) {

        w_size = write_all(&dfw, bitmagic, 8, &opt); /// write a magic string

        /// read data from the first block and log the offset
        sf = lseek(dfr, 0, SEEK_SET);
        log_mesg(1, 0, 0, debug, "seek %lli for reading data string\n",sf);
        if (sf == (off_t)-1)
            log_mesg(0, 1, 1, debug, "seek set %lli\n", sf);

        buffer = (char*)malloc(image_hdr.block_size); ///alloc a memory to copy data
        if(buffer == NULL) {
            log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
        }

        log_mesg(0, 0, 0, debug, "Total block %i\n", image_hdr.totalblock);


        /// start clone partition to image file
        log_mesg(1, 0, 0, debug, "start backup data...\n");
        for( block_id = 0; block_id < image_hdr.totalblock; block_id++ ) {

            r_size = 0;
            w_size = 0;

            main_pos = lseek(dfr, 0, SEEK_CUR);
            log_mesg(3, 0, 0, debug, "man pos = %lli\n", main_pos);

            if (pc_test_bit(block_id, bitmap)) {
                /// if the block is used
                log_mesg(1, 0, 0, debug, "block_id=%lli, ",block_id);
                log_mesg(2, 0, 0, debug, "bitmap=%i, ",pc_test_bit(block_id, bitmap));

                offset = (off_t)(block_id * image_hdr.block_size);
#ifdef _FILE_OFFSET_BITS
                sf = lseek(dfr, offset, SEEK_SET);
                if (sf == -1)
                    log_mesg(0, 1, 1, debug, "source seek error = %lli, ",sf);
#endif
                /// read data from source to buffer
                memset(buffer, 0, image_hdr.block_size);
                rescue_pos = lseek(dfr, 0, SEEK_CUR);
                r_size = read_all(&dfr, buffer, image_hdr.block_size, &opt);
                log_mesg(3, 0, 0, debug, "bs=%i and r=%i, ",image_hdr.block_size, r_size);
                if (r_size != (int)image_hdr.block_size) {

                    if ((r_size == -1) && (errno == EIO)) {
                        if (opt.rescue) {
                            r_size = 0;
                            for (rescue_num = 0; rescue_num < image_hdr.block_size; rescue_num += SECTOR_SIZE) {
                                rescue_sector(&dfr, rescue_pos + rescue_num, buffer + rescue_num, &opt);
                                r_size+=SECTOR_SIZE;
                            }
                        } else
                            log_mesg(0, 1, 1, debug, "%s", bad_sectors_warning_msg);

                    } else
                        log_mesg(0, 1, 1, debug, "read error: %s(%i) \n", strerror(errno), errno);
                }

                /// write buffer to target
                w_size = write_all(&dfw, buffer, image_hdr.block_size, &opt);
                log_mesg(3, 0, 0, debug, "bs=%i and w=%i, ",image_hdr.block_size, w_size);
                if (w_size != (int)image_hdr.block_size)
                    log_mesg(0, 1, 1, debug, "write error %i \n", w_size);

                /// generate crc32 code and write it.
                crc_buffer = (char*)malloc(CRC_SIZE); ///alloc a memory to copy data
                if(crc_buffer == NULL) {
                    log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
                }
                crc = crc32(crc, buffer, w_size);
                memcpy(crc_buffer, &crc, CRC_SIZE);
                c_size = write_all(&dfw, crc_buffer, CRC_SIZE, &opt);

                /// free buffer
                free(crc_buffer);

                copied++;					/// count copied block
                total_write += (unsigned long long)(w_size);	/// count copied size
                log_mesg(3, 0, 0, debug, "total=%lli, ", total_write);

                /// read or write error
                if (r_size != w_size)
                    log_mesg(0, 1, 1, debug, "read(%i) and write(%i) different\n", r_size, w_size);
                log_mesg(2, 0, 0, debug, "end\n");
            } else {
#ifndef _FILE_OFFSET_BITS
                /// if the block is not used, I just skip it.
                log_mesg(2, 0, 0, debug, "block_id=%lli, ",block_id);
                sf = lseek(dfr, image_hdr.block_size, SEEK_CUR);
                log_mesg(2, 0, 0, debug, "skip seek=%lli, ",sf);
                if (sf == (off_t)-1)
                    log_mesg(0, 1, 1, debug, "clone seek error %lli errno=%i\n", (long long)offset, (int)errno);

                log_mesg(2, 0, 0, debug, "end\n");
#endif
            }
        } /// end of for
        free(buffer);
    } else if (opt.restore) {

        /**
         * read magic string from image file
         * and check it.
         */
        r_size = read_all(&dfr, bitmagic_r, 8, &opt); /// read a magic string
        cmp = memcmp(bitmagic, bitmagic_r, 8);
        if(cmp != 0)
            log_mesg(0, 1, 1, debug, "bitmagic error %i\n", cmp);

        /// seek to the first
        sf = lseek(dfw, 0, SEEK_SET);
        log_mesg(1, 0, 0, debug, "seek %lli for writing dtat string\n",sf);
        if (sf == (off_t)-1)
            log_mesg(0, 1, 1, debug, "seek set %lli\n", sf);

        cache_buffer = (char*)malloc(image_hdr.block_size * (next_max_count+1));
        if(cache_buffer == NULL) {
            log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
        }

        buffer = (char*)malloc(image_hdr.block_size); ///alloc a memory to copy data
        if(buffer == NULL) {
            log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
        }

        /// start restore image file to partition
        log_mesg(1, 0, 0, debug, "start restore data...\n");

        for( block_id = 0; block_id < image_hdr.totalblock; block_id++ ) {

            r_size = 0;
            w_size = 0;


            if (pc_test_bit(block_id, bitmap)) {
                /// The block is used
                log_mesg(1, 0, 0, debug, "block_id=%lli, ",block_id);
                log_mesg(2, 0, 0, debug, "bitmap=%i, ",pc_test_bit(block_id, bitmap));

                memset(buffer, 0, image_hdr.block_size);
                r_size = read_all(&dfr, buffer, image_hdr.block_size, &opt);
                log_mesg(3, 0, 0, debug, "bs=%i and r=%i, ",image_hdr.block_size, r_size);
                if (r_size <0)
                    log_mesg(0, 1, 1, debug, "read errno = %i \n", errno);

                /// read crc32 code and check it.
                crc_ck = crc32(crc_ck, buffer, r_size);
                crc_buffer = (char*)malloc(CRC_SIZE); ///alloc a memory to copy data
                if(crc_buffer == NULL) {
                    log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
                }
                c_size = read_all(&dfr, crc_buffer, CRC_SIZE, &opt);
                if (c_size < CRC_SIZE)
                    log_mesg(0, 1, 1, debug, "read CRC error: %s, please check your image file. \n", strerror(errno));

                memcpy(&crc, crc_buffer, CRC_SIZE);
                /*FIX: 64bit image can't ignore crc error*/
                if ((memcmp(&crc, &crc_ck, CRC_SIZE) != 0) && (!opt.ignore_crc)) {
                    log_mesg(1, 0, 0, debug, "CRC Check error. 64bit bug before v0.1.0 (Rev:250M), enlarge crc size and recheck again....\n ");
                    /// check again
                    buffer2 = (char*)malloc(image_hdr.block_size+CRC_SIZE); ///alloc a memory to copy data
                    if(buffer2 == NULL) {
                        log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
                    }
                    memcpy(buffer2, buffer, image_hdr.block_size);
                    memcpy(buffer2+image_hdr.block_size, crc_buffer, CRC_SIZE);
                    memcpy(buffer, buffer2+CRC_SIZE, image_hdr.block_size);

                    crc_ck2 = crc32(crc_ck2, buffer, r_size);
                    c_size = read_all(&dfr, crc_buffer, CRC_SIZE, &opt);
                    if (c_size < CRC_SIZE)
                        log_mesg(0, 1, 1, debug, "read CRC error: %s, please check your image file. \n", strerror(errno));
                    memcpy(&crc, crc_buffer, CRC_SIZE);
                    if ((memcmp(&crc, &crc_ck2, CRC_SIZE) != 0 )&& (!opt.ignore_crc)) {
                        log_mesg(0, 1, 1, debug, "CRC error again at %i...\n ", sf);
                    } else {
                        crc_ck = crc_ck2;
                    }
                    free(buffer2);
                } else {
                    crc_ck2 = crc_ck;
                }

                if(next != next_count) {
                    memset(cache_buffer, 0, image_hdr.block_size*next_max_count);
                    for (next_int = 1; next_int <= next_max_count; next_int++)
                    {
                        next_block_id = block_id+next_int;
                        if (pc_test_bit(next_block_id, bitmap)) {
                            next++;
                        } else {
                            next_count = next;
                            break;
                        }
                        next_count = next;
                    }
                    log_mesg(1, 0, 0, debug, "next = %i\n",next);
                }

                if ((next == next_count) &&(nx_current < next)) {
                    memcpy(cache_buffer+(image_hdr.block_size*nx_current), buffer, image_hdr.block_size);
                    w_size = 0;
                    nx_current++;
                }

                if ((next == next_count) && (nx_current == next)) {
#ifdef _FILE_OFFSET_BITS
                    offset = (off_t)((block_id-next+1) * image_hdr.block_size);
                    sf = lseek(dfw, offset, SEEK_SET);
                    if (sf == -1)
                        log_mesg(0, 1, 1, debug, "target seek error = %lli, ",sf);
#endif
                    /// write block from buffer to partition
                    w_size = write_all(&dfw, cache_buffer, (image_hdr.block_size*nx_current), &opt);
                    log_mesg(1, 0, 0, debug, "bs=%i and w=%i, ",(image_hdr.block_size*nx_current), w_size);
                    if (w_size != (int)image_hdr.block_size*nx_current)
                        log_mesg(0, 1, 1, debug, "write error %i \n", w_size);
                    next = 1;
                    next_count = next_max_count;
                    nx_current=0;
                }

                /// free buffer
                free(crc_buffer);
                copied++;					/// count copied block
                total_write += (unsigned long long) w_size;	/// count copied size

                /// read or write error
                //if ((r_size != w_size) || (r_size != image_hdr.block_size))
                //	log_mesg(0, 1, 1, debug, "read and write different\n");
                log_mesg(1, 0, 0, debug, "end\n");
            } else {
                /// for restore to row file, mount -o loop used.
                if ((block_id == (image_hdr.totalblock-1)) && (opt.restore_row_file)) {
                    write_last_block(&dfw, image_hdr.block_size, block_id, &opt);

                } else {
#ifndef _FILE_OFFSET_BITS
                    /// if the block is not used, I just skip it.
                    log_mesg(2, 0, 0, debug, "block_id=%lli, ",block_id);
                    sf = lseek(dfw, image_hdr.block_size, SEEK_CUR);
                    log_mesg(2, 0, 0, debug, "seek=%lli, ",sf);
                    if (sf == (off_t)-1)
                        log_mesg(0, 1, 1, debug, "seek error %lli errno=%i\n", (long long)offset, (int)errno);
                    log_mesg(2, 0, 0, debug, "end\n");
#endif
                }
            }
        } // end of for
        free(buffer);
    } else if (opt.dd) {
        sf = lseek(dfr, 0, SEEK_SET);
        log_mesg(1, 0, 0, debug, "seek %lli for reading data string\n",sf);
        if (sf == (off_t)-1)
            log_mesg(0, 1, 1, debug, "seek set %lli\n", sf);

        main_pos = lseek(dfr, 0, SEEK_CUR);
        log_mesg(1, 0, 0, debug, "man pos = %lli\n", main_pos);

        log_mesg(0, 0, 0, debug, "Total block %i\n", image_hdr.totalblock);

        buffer = (char*)malloc(image_hdr.block_size); ///alloc a memory to copy data
        if(buffer == NULL) {
            log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
        }

        /// start clone partition to image file
        log_mesg(1, 0, 0, debug, "start backup data device-to-device...\n");
        for( block_id = 0; block_id < image_hdr.totalblock; block_id++ ) {
            r_size = 0;
            w_size = 0;

            if (pc_test_bit(block_id, bitmap)) {
                /// if the block is used

                log_mesg(1, 0, 0, debug, "block_id=%lli, ",block_id);
                log_mesg(2, 0, 0, debug, "bitmap=%i, ",pc_test_bit(block_id, bitmap));
                offset = (off_t)(block_id * image_hdr.block_size);
#ifdef _FILE_OFFSET_BITS
                sf = lseek(dfr, offset, SEEK_SET);
                if (sf == -1)
                    log_mesg(0, 1, 1, debug, "source seek error = %lli, ",sf);
                sf = lseek(dfw, offset, SEEK_SET);
                if (sf == -1)
                    log_mesg(0, 1, 1, debug, "target seek error = %lli, ",sf);
#endif
                /// read data from source to buffer
                memset(buffer, 0, image_hdr.block_size);
                rescue_pos = lseek(dfr, 0, SEEK_CUR);
                r_size = read_all(&dfr, buffer, image_hdr.block_size, &opt);
                log_mesg(3, 0, 0, debug, "bs=%i and r=%i, ",image_hdr.block_size, r_size);
                if (r_size != (int)image_hdr.block_size) {
                    if ((r_size == -1) && (errno == EIO)) {
                        if (opt.rescue) {
                            r_size = 0;
                            for (rescue_num = 0; rescue_num < image_hdr.block_size; rescue_num += SECTOR_SIZE) {
                                rescue_sector(&dfr, rescue_pos + rescue_num, buffer + rescue_num, &opt);
                                r_size+=SECTOR_SIZE;
                            }
                        } else
                            log_mesg(0, 1, 1, debug, "%s", bad_sectors_warning_msg);

                    } else
                        log_mesg(0, 1, 1, debug, "read error: %s(%i) \n", strerror(errno), errno);
                }

                /// write buffer to target
                w_size = write_all(&dfw, buffer, image_hdr.block_size, &opt);
                log_mesg(3, 0, 0, debug, "bs=%i and w=%i, ",image_hdr.block_size, w_size);
                if (w_size != (int)image_hdr.block_size)
                    log_mesg(0, 1, 1, debug, "write error %i \n", w_size);

                copied++;                                       /// count copied block
                total_write += (unsigned long long)(w_size);    /// count copied size
                log_mesg(2, 0, 0, debug, "total=%lli, ", total_write);
                /// read or write error
                if (r_size != w_size)
                    log_mesg(0, 1, 1, debug, "read and write different\n");
                log_mesg(1, 0, 0, debug, "end\n");
            } else {
#ifndef _FILE_OFFSET_BITS
                /// if the block is not used, I just skip it.
                log_mesg(2, 0, 0, debug, "block_id=%lli, ",block_id);
                sf = lseek(dfr, image_hdr.block_size, SEEK_CUR);
                log_mesg(2, 0, 0, debug, "skip source seek=%lli, ",sf);
                sf = lseek(dfw, image_hdr.block_size, SEEK_CUR);
                log_mesg(2, 0, 0, debug, "skip target seek=%lli, ",sf);
                if (sf == (off_t)-1)
                    log_mesg(0, 1, 1, debug, "clone seek error %lli errno=%i\n", (long long)offset, (int)errno);
#endif
            }
        } /// end of for
        free(buffer);
    } else if (opt.domain) {
        log_mesg(0, 0, 0, debug, "Total block %i\n", image_hdr.totalblock);
        log_mesg(1, 0, 0, debug, "start writing domain log...\n");
        // write domain log comment and status line
        dprintf(dfw, "# Domain logfile created by %s v%s\n", EXECNAME, VERSION);
        dprintf(dfw, "# Source: %s\n", opt.source);
        dprintf(dfw, "# Offset: 0x%08llX\n", opt.offset_domain);
        dprintf(dfw, "# current_pos  current_status\n");
        dprintf(dfw, "0x%08llX     ?\n",
                opt.offset_domain + (image_hdr.totalblock * image_hdr.block_size));
        dprintf(dfw, "#      pos        size  status\n");
        // start logging the used/unused areas
        next_block_id = 0;
        cmp = pc_test_bit(0, bitmap);
        for( block_id = 0; block_id <= image_hdr.totalblock; block_id++ ) {
            if (block_id < image_hdr.totalblock) {
                nx_current = pc_test_bit(block_id, bitmap);
                if (nx_current == 1)
                    copied++;
            } else
                nx_current = -1;
            if (nx_current != cmp) {
                dprintf(dfw, "0x%08llX  0x%08llX  %c\n",
                        opt.offset_domain + (next_block_id * image_hdr.block_size),
                        (block_id - next_block_id) * image_hdr.block_size,
                        cmp ? '+' : '?');
                next_block_id = block_id;
                cmp = nx_current;
            }
            // don't bother updating progress
        } /// end of for
    }

    done = 1;
    pres = pthread_join(prog_thread, &p_result);
    update_pui(&prog, copied, block_id, done);
    sync_data(dfw, &opt);
    print_finish_info(opt);

    close (dfr);    /// close source
    close (dfw);    /// close target
    free(bitmap);   /// free bitmp
    close_pui(pui);
    printf("Cloned successfully.\n");
    if(opt.debug)
        close_log();
#ifdef MEMTRACE
    muntrace();
#endif
    return 0;	    /// finish
}
Beispiel #9
0
/**
 * main functiom - for colne or restore data
 */
int main(int argc, char **argv){ 

    char*		source;			/// source data
    char*		target;			/// target data
    char*		buffer;			/// buffer data for malloc used
    char*		buffer2;			/// buffer data for malloc used
    int			dfr, dfw;		/// file descriptor for source and target
    int			r_size, w_size;		/// read and write size
    //unsigned long long	block_id, copied = 0;	/// block_id is every block in partition
    /// copied is copied block count
    off_t		offset = 0, sf = 0;	/// seek postition, lseek result
    int			start, stop;		/// start, range, stop number for progress bar
    unsigned long long	total_write = 0;	/// the copied size 
    unsigned long long	needed_size = 0;	/// the copied size 
    unsigned long long	needed_mem  = 0;	/// the copied size 
    char		bitmagic[8] = "BiTmAgIc";// only for check postition
    char		bitmagic_r[8];		/// read magic string from image
    int			cmp;			/// compare magic string
    unsigned long	*bitmap;		/// the point for bitmap data
    int			debug = 0;		/// debug or not
    unsigned long	crc = 0xffffffffL;	/// CRC32 check code for writint to image
    unsigned long	crc_ck = 0xffffffffL;	/// CRC32 check code for checking
    unsigned long	crc_ck2 = 0xffffffffL;	/// CRC32 check code for checking
    int			c_size;			/// CRC32 code size
    //int			done = 0;
    int			s_count = 0;
    int			tui = 0;		/// text user interface
    int			pui = 0;		/// progress mode(default text)
    int			raw = 0;
    char		image_hdr_magic[512];
    int			next=1,next_int=1,next_max_count=7,next_count=7;
    unsigned long long	next_block_id;
    char*		cache_buffer;
    int			nx_current=0;
    int	flag;
    pthread_t prog_thread;
    int pres;
    void *p_result;
	
    //progress_bar	prog;			/// progress_bar structure defined in progress.h
    image_head		image_hdr;		/// image_head structure defined in partclone.h

    /**
     * get option and assign to opt structure
     * check parameter and read from argv
     */
    parse_options(argc, argv, &opt);

    /**
     * if "-d / --debug" given
     * open debug file in "/var/log/partclone.log" for log message 
     */
    debug = opt.debug;
    //if(opt.debug)
    open_log(opt.logfile);

    /**
     * using Text User Interface
     */
    if (opt.ncurses){
	pui = NCURSES;
	log_mesg(1, 0, 0, debug, "Using Ncurses User Interface mode.\n");
    } else
	pui = TEXT;

    tui = open_pui(pui, opt.fresh);
    if ((opt.ncurses) && (tui == 0)){
	opt.ncurses = 0;
	log_mesg(1, 0, 0, debug, "Open Ncurses User Interface Error.\n");
    }

    next_max_count = opt.max_block_cache-1;
    next_count = opt.max_block_cache-1;

    /// print partclone info
    print_partclone_info(opt);

    if (geteuid() != 0)
	log_mesg(0, 1, 1, debug, "You are not logged as root. You may have \"access denied\" errors when working.\n"); 
    else
	log_mesg(1, 0, 0, debug, "UID is root.\n");

    /// ignore crc check
    if(opt.ignore_crc)
	log_mesg(1, 0, 1, debug, "Ignore CRC error\n");

    /**
     * open source and target 
     * clone mode, source is device and target is image file/stdout
     * restore mode, source is image file/stdin and target is device
     * dd mode, source is device and target is device !!not complete
     */
#ifdef _FILE_OFFSET_BITS
    log_mesg(1, 0, 0, debug, "enable _FILE_OFFSET_BITS %i\n", _FILE_OFFSET_BITS);
#endif
    source = opt.source;
    target = opt.target;
    dfr = open_source(source, &opt);
    if (dfr == -1) {
	log_mesg(0, 1, 1, debug, "Erro EXIT.\n");
    }

    dfw = open_target(target, &opt);
    if (dfw == -1) {
	log_mesg(0, 1, 1, debug, "Error Exit.\n");
    }

    /**
     * get partition information like super block, image_head, bitmap
     * from device or image file.
     */

    if (opt.restore){

	log_mesg(1, 0, 0, debug, "restore image hdr - get image_head from image file\n");
	/// get first 512 byte
	r_size = read_all(&dfr, image_hdr_magic, 512, &opt);

	/// check the image magic
	if (memcmp(image_hdr_magic, IMAGE_MAGIC, IMAGE_MAGIC_SIZE) == 0){
	    restore_image_hdr_sp(&dfr, &opt, &image_hdr, image_hdr_magic);

	    /// check memory size
	    if (check_mem_size(image_hdr, opt, &needed_mem) == -1)
		log_mesg(0, 1, 1, debug, "Ther is no enough free memory, partclone suggests you should have %llu bytes memory\n", needed_mem);

	    /// alloc a memory to restore bitmap
	    bitmap = (unsigned long*)calloc(sizeof(unsigned long), LONGS(image_hdr.totalblock));
	    if(bitmap == NULL){
		log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
	    }

	    /// check the file system
	    //if (strcmp(image_hdr.fs, FS) != 0)
	    //    log_mesg(0, 1, 1, debug, "%s can't restore from the image which filesystem is %s not %s\n", argv[0], image_hdr.fs, FS);

	    log_mesg(2, 0, 0, debug, "initial main bitmap pointer %p\n", bitmap);
	    log_mesg(1, 0, 0, debug, "Initial image hdr - read bitmap table\n");

	    /// read and check bitmap from image file
	    log_mesg(0, 0, 1, debug, "Calculating bitmap... ");
	    log_mesg(0, 0, 1, debug, "Please wait... ");
	    get_image_bitmap(&dfr, opt, image_hdr, bitmap);

	    /// check the dest partition size.
	    if (opt.restore_raw_file)
		check_free_space(&dfw, image_hdr.device_size);
	    else if(opt.check)
		check_size(&dfw, image_hdr.device_size);

	    log_mesg(2, 0, 0, debug, "check main bitmap pointer %p\n", bitmap);
	    log_mesg(0, 0, 1, debug, "done!\n");
	}else{
	    log_mesg(1, 0, 0, debug, "This is not partclone image.\n");
	    raw = 1;
	    //sf = lseek(dfr, 0, SEEK_SET);

	    log_mesg(1, 0, 0, debug, "Initial image hdr - get Super Block from partition\n");

	    /// get Super Block information from partition
	    if (dfr != 0)
		initial_dd_hdr(dfr, &image_hdr);
	    else
		initial_dd_hdr(dfw, &image_hdr);

	    /// check the dest partition size.
	    if(opt.check){
		check_size(&dfw, image_hdr.device_size);
	    }
	}
    }

    log_mesg(1, 0, 0, debug, "print image_head\n");

    /// print option to log file
    if (debug)
	print_opt(opt);

    /// print image_head
    print_image_hdr_info(image_hdr, opt);

    /**
     * initial progress bar
     */
    start = 0;				/// start number of progress bar
    stop = (image_hdr.usedblocks+1);	/// get the end of progress number, only used block
    log_mesg(1, 0, 0, debug, "Initial Progress bar\n");
    /// Initial progress bar
    if (opt.no_block_detail)
	flag = NO_BLOCK_DETAIL;
    else
	flag = IO;
    progress_init(&prog, start, stop, image_hdr.totalblock, flag, image_hdr.block_size);
    copied = 0;				/// initial number is 0

    /**
     * thread to print progress
     */
    pres = pthread_create(&prog_thread, NULL, thread_update_pui, NULL);

    /**
     * start read and write data between device and image file
     */
    if ((opt.restore) && (!raw)) {

	/**
	 * read magic string from image file
	 * and check it.
	 */
	r_size = read_all(&dfr, bitmagic_r, 8, &opt); /// read a magic string
	cmp = memcmp(bitmagic, bitmagic_r, 8);
	if(cmp != 0)
	    log_mesg(0, 1, 1, debug, "bitmagic error %i\n", cmp);

	cache_buffer = (char*)malloc(image_hdr.block_size * (next_max_count+1));
	if(cache_buffer == NULL){
	    log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
	}
	buffer = (char*)malloc(image_hdr.block_size); ///alloc a memory to copy data
	if(buffer == NULL){
	    log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
	}

	/// seek to the first
	sf = lseek(dfw, opt.offset, SEEK_SET);
	log_mesg(1, 0, 0, debug, "seek %lli for writing dtat string\n",sf);
	if (sf == (off_t)-1)
	    log_mesg(0, 1, 1, debug, "seek set %ji\n", (intmax_t)sf);
	/// start restore image file to partition
	for( block_id = 0; block_id < image_hdr.totalblock; block_id++ ){

	    r_size = 0;
	    w_size = 0;

	    if (pc_test_bit(block_id, bitmap)){
		/// The block is used
		log_mesg(2, 0, 0, debug, "block_id=%llu, ",block_id);
		log_mesg(1, 0, 0, debug, "bitmap=%i, ",pc_test_bit(block_id, bitmap));

		memset(buffer, 0, image_hdr.block_size);
		r_size = read_all(&dfr, buffer, image_hdr.block_size, &opt);
		log_mesg(1, 0, 0, debug, "bs=%i and r=%i, ",image_hdr.block_size, r_size);
		if (r_size <0)
		    log_mesg(0, 1, 1, debug, "read errno = %i \n", errno);

		/// read crc32 code and check it.
		crc_ck = crc32(crc_ck, buffer, r_size);
		char crc_buffer[CRC_SIZE];
		c_size = read_all(&dfr, crc_buffer, CRC_SIZE, &opt);
		if (c_size < CRC_SIZE)
		    log_mesg(0, 1, 1, debug, "read CRC error: %s, please check your image file. \n", strerror(errno));
		/*FIX: 64bit image can't ignore crc error*/
		if ((memcmp(crc_buffer, &crc_ck, CRC_SIZE) != 0) && (!opt.ignore_crc) ){
		    log_mesg(1, 0, 0, debug, "CRC Check error. 64bit bug before v0.1.0 (Rev:250M), enlarge crc size and recheck again....\n ");
		    /// check again
		    buffer2 = (char*)malloc(image_hdr.block_size+CRC_SIZE); ///alloc a memory to copy data
		    if(buffer2 == NULL){
			log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
		    }
		    memcpy(buffer2, buffer, image_hdr.block_size);
		    memcpy(buffer2+image_hdr.block_size, crc_buffer, CRC_SIZE);
		    memcpy(buffer, buffer2+CRC_SIZE, image_hdr.block_size);

		    crc_ck2 = crc32(crc_ck2, buffer, r_size);
		    c_size = read_all(&dfr, crc_buffer, CRC_SIZE, &opt);
		    if (c_size < CRC_SIZE)
			log_mesg(0, 1, 1, debug, "read CRC error: %s, please check your image file. \n", strerror(errno));
		    if ((memcmp(crc_buffer, &crc_ck2, CRC_SIZE) != 0) && (!opt.ignore_crc)){
			log_mesg(0, 1, 1, debug, "CRC error again at %ji...\n ", (intmax_t)sf);
		    } else {
			crc_ck = crc_ck2;
		    }
		    free(buffer2);

		} else {
		    crc_ck2 = crc_ck;
		}

		if(next != next_count){
		    memset(cache_buffer, 0, image_hdr.block_size*next_max_count);
		    for (next_int = 1; next_int <= next_max_count; next_int++)
		    {
			next_block_id = block_id+next_int;
			if (pc_test_bit(next_block_id, bitmap)) {
			    next++;
			} else {
			    next_count = next;    
			    break;
			}
			next_count = next;
		    }
		    log_mesg(1, 0, 0, debug, "next = %i\n",next);
		}

		if ((next == next_count) &&(nx_current < next)){
		    memcpy(cache_buffer+(image_hdr.block_size*nx_current), buffer, image_hdr.block_size);
		    w_size = 0;
		    nx_current++;
		}

		if ((next == next_count) && (nx_current == next)){
#ifdef _FILE_OFFSET_BITS
		    offset = (off_t)(((block_id-next+1) * image_hdr.block_size)+opt.offset);
		    sf = lseek(dfw, offset, SEEK_SET);
		    if (sf == -1)
			log_mesg(0, 1, 1, debug, "target seek error = %ji, ", (intmax_t)sf);
#endif
		    /// write block from buffer to partition
		    w_size = write_all(&dfw, cache_buffer, (image_hdr.block_size*nx_current), &opt);
		    log_mesg(1, 0, 0, debug, "bs=%i and w=%i, ",(image_hdr.block_size*nx_current), w_size);
		    if (w_size != image_hdr.block_size*nx_current)
			log_mesg(0, 1, 1, debug, "write error %i \n", w_size);
		    next = 1;
		    next_count = next_max_count;
		    nx_current=0;
		}

		copied++;					/// count copied block
		total_write += (unsigned long long) w_size;	/// count copied size

		/// read or write error
		//if ((r_size != w_size) || (r_size != image_hdr.block_size))
		//	log_mesg(0, 1, 1, debug, "read and write different\n");
		log_mesg(1, 0, 0, debug, "end\n");
	    } else {
		/// for restore to raw file, mount -o loop used.
		if ((block_id == (image_hdr.totalblock-1)) && (opt.restore_raw_file)){
		    write_last_block(&dfw, image_hdr.block_size, block_id, &opt);

		} else {
#ifndef _FILE_OFFSET_BITS
		    /// if the block is not used, I just skip it.
		    log_mesg(2, 0, 0, debug, "block_id=%llu, ",block_id);
		    sf = lseek(dfw, image_hdr.block_size, SEEK_CUR);
		    log_mesg(2, 0, 0, debug, "seek=%ji, ", (intmax_t)sf);
		    if (sf == (off_t)-1)
			log_mesg(0, 1, 1, debug, "seek error %ji errno=%i\n", (intmax_t)offset, errno);
		    log_mesg(2, 0, 0, debug, "end\n");
#endif
		}
	    }
	    //if (!opt.quiet)
	//	update_pui(&prog, copied, block_id, done);
	} // end of for
	/// free buffer
	free(cache_buffer);
	free(buffer);
	done = 1;
	pres = pthread_join(prog_thread, &p_result);
	update_pui(&prog, copied, block_id, done);
	sync_data(dfw, &opt);	
    } else if ((opt.restore) && (raw)){
	/// start clone partition to image file

	//write image_head to image file
	w_size = write_all(&dfw, image_hdr_magic, 512, &opt);
	if(w_size == -1)
	    log_mesg(0, 1, 1, debug, "write image_hdr to image error\n");

	block_id = 1;

	buffer = (char*)malloc(image_hdr.block_size); ///alloc a memory to copy data
	if(buffer == NULL){
	    log_mesg(0, 1, 1, debug, "%s, %i, ERROR:%s", __func__, __LINE__, strerror(errno));
	}

	do {
	    r_size = 0;
	    w_size = 0;
	    memset(buffer, 0, image_hdr.block_size);

	    log_mesg(1, 0, 0, debug, "block_id=%llu, ",block_id);

	    /// read data from source to buffer
	    r_size = read_all(&dfr, buffer, image_hdr.block_size, &opt);
	    log_mesg(1, 0, 0, debug, "bs=%i and r=%i, ",image_hdr.block_size, r_size);
	    if (r_size != (int)image_hdr.block_size){
		if (r_size == 0){
		    //EIO
		    done = 1;
		} else {
		    log_mesg(0, 1, 1, debug, "read error: %s(%i) rsize=%i\n", strerror(errno), errno, r_size);
		}
	    }

	    if (r_size == image_hdr.block_size){
		/// write buffer to target
		w_size = write_all(&dfw, buffer, image_hdr.block_size, &opt);
		log_mesg(2, 0, 0, debug, "bs=%i and w=%i, ",image_hdr.block_size, w_size);
		if (w_size != (int)image_hdr.block_size)
		    log_mesg(0, 1, 1, debug, "write error %i \n", w_size);
	    } else if (r_size < image_hdr.block_size){
		/// write readed buffer to target
		w_size = write_all(&dfw, buffer, r_size, &opt);
		log_mesg(2, 0, 0, debug, "bs=%i and w=%i, ",image_hdr.block_size, w_size);
		if (w_size != r_size)
		    log_mesg(0, 1, 1, debug, "write error %i \n", w_size);
	    } else {
		w_size = 0;
	    }

	    /// read or write error
	    if (r_size != w_size)
		log_mesg(0, 1, 1, debug, "read and write different\n");
	    log_mesg(1, 0, 0, debug, "end\n");
	    block_id++;
	    copied++;					/// count copied block
	    total_write += (unsigned long long)(w_size);	/// count copied size
	    log_mesg(1, 0, 0, debug, "total=%llu, ", total_write);

	    //if (!opt.quiet)
		//update_pui(&prog, copied, block_id, done);
	} while (done == 0);/// end of for    
	pres = pthread_join(prog_thread, &p_result);
	update_pui(&prog, copied, block_id, done);
	sync_data(dfw, &opt);	
	/// free buffer
	free(buffer);
    }

    print_finish_info(opt);

    close (dfr);    /// close source
    close (dfw);    /// close target
    free(bitmap);   /// free bitmp
    close_pui(pui);
    fprintf(stderr, "Cloned successfully.\n");
    if(opt.debug)
	close_log();
    return 0;	    /// finish
}