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(); }
/// 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; }
/// 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; }
/// 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 }
/// 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; }
/** * 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 }
/// 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)); }
/** * 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 }
/** * 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 }