void RTC::event_callback(int event_id, int err)
{
	if(event_id == EVENT_1HZ) {
		// update calendar
		if(cur_time.initialized) {
			cur_time.increment();
		} else {
			get_host_time(&cur_time);	// resync
			cur_time.initialized = true;
		}
		read_from_cur_time();
		
		// 1sec interrupt
		rtdsr |= 4;
		update_intr();
	} else if(event_id == EVENT_32HZ) {
		// update tcnt
		regs[TCNT]++;
	} else if(event_id == EVENT_DONE) {
		int ch = (rtadr >> 1) & 0x3f;
		if(rtadr & 1) {
			// invalid address
		} else if(rtadr & 0x80) {
			// write
			if(ch <= 6) {
				regs[ch] = (uint8_t)rtobr;
				write_to_cur_time();
			} else if(ch == POWON) {
				regs[ch] = (regs[ch] & 0xe0) | (rtobr & 0x1f);
				if((rtobr & 0xe0) == 0xc0) {
					// reipl
					regs[ch] = (regs[ch] & 0x1f) | 0xc0;
					vm->reset();
				} else if((rtobr & 0xe0) == 0xe0) {
					// power off
					emu->power_off();
				}
				update_checksum();
			} else if(7 <= ch && ch < 32) {
				regs[ch] = (uint8_t)rtobr;
				update_checksum();
			}
		} else {
			// read
			if(ch < 40) {
				rtibr = regs[ch];
			}
		}
		// update flags
		rtdsr &= ~1;
		rtdsr |= 2;
		update_intr();
	}
void RTC::initialize()
{
	// load rtc regs image
	memset(regs, 0, sizeof(regs));
	regs[POWON] = 0x10;	// cleared
	
	FILEIO* fio = new FILEIO();
	if(fio->Fopen(create_local_path(_T("RTC.BIN")), FILEIO_READ_BINARY)) {
		fio->Fread(regs + 8, 32, 1);
		fio->Fclose();
	}
	delete fio;
	
	// init registers
//	regs[POWON] &= 0x1f;	// local power on
//	regs[POWOF] = 0x80;	// program power off
	regs[POWON] = 0x10;	// cleared
	regs[POWOF] = 0x20;	// illegal power off
	regs[TCNT] = 0;
	update_checksum();
	
	rtcmr = rtdsr = 0;
	
	// update calendar
	get_host_time(&cur_time);
	read_from_cur_time();
	
	// register event
	register_event_by_clock(this, EVENT_1HZ, CPU_CLOCKS, true, &register_id);
	register_event_by_clock(this, EVENT_32HZ, CPU_CLOCKS >> 5, true, NULL);
}
Exemple #3
0
void *
malloc(size_t size)
{
        void *retval = NULL;
        //debugf("malloc(%lu): ", size);
        if (sizeof(struct slab_header) != PAGE_SIZE) {
                koops("slab_header is %lu bytes", sizeof(struct slab_header));
        }
        if (int_nest_count > 0) {
                koops("malloc called in interrupt handler");
        }

        if (atomic_fetch_add(&malloc_lock, 1) != 0) {
                koops("(malloc)malloc_lock != 0");
        }

        if (size > MAX_SLAB_SIZE) {
                size_t pages = (sizeof(uint32_t) + size + PAGE_MASK) / PAGE_SIZE;
                struct malloc_region *result = alloc_pages(pages);
                result->region_size = (pages * PAGE_SIZE) - sizeof(struct malloc_region);
                debugf("Wanted %lu got %u\n", size, result->region_size);
                retval = result->data;
        } else {
                int slab_idx = map_size_to_idx(size);
                struct slab_header *slab = slabs[slab_idx];
                validate_is_slab(slab);

                uint64_t allocation_mask = bitmap_mask(slab_idx);
                uint64_t free_bits = slab->allocation_bm[0] ^ allocation_mask;
                int freebit = __builtin_ffsl(free_bits);

                if (unlikely(freebit == 0)) {
                        slab = add_new_slab(slab_idx);
                        debugf(" got new slab @ %p ", slab);
                        free_bits = slab->allocation_bm[0] ^ allocation_mask;
                        freebit = __builtin_ffsl(free_bits);
                        if(unlikely(freebit == 0)) {
                                koops("new slab for idx:%d has filled up [%"PRIu64 "/%"PRIu64" /%"PRIX64 "]!", slab_idx,
                                      slab->malloc_cnt, slab->free_cnt, slab->allocation_bm[0]);
                        }
                }
                freebit--;
                size_t offset = freebit * slab_info[slab_idx].slab_size;
                retval = &slab->data[offset];

                uint64_t free_mask = (uint64_t)1 << freebit;
                slab->allocation_bm[0] |= free_mask;
                slab->malloc_cnt++;
                update_checksum(slab);
                debugf("malloc(%lu)=%p slab=%p offset=%lx [%"PRIu64 "/%"PRIu64"]\n",
                       size, retval, slab, offset, slab->malloc_cnt, slab->free_cnt);
        }
        if (atomic_fetch_sub(&malloc_lock, 1) != 1) {
                koops("(malloc)malloc_lock != 1");
        }
        return retval;
}
Exemple #4
0
void
free(void *ptr)
{
        debugf("free(%p)=", ptr);
        if (unlikely(ptr == NULL)) {
                return;
        }
        if (int_nest_count > 0) {
                koops("malloc called in interrupt handler");
        }

        if (atomic_fetch_add(&malloc_lock, 1) != 0) {
                koops("(free)malloc_lock != 0");
        }

        uint64_t p = (uint64_t)ptr;
        struct slab_header *slab = (struct slab_header *)(p & ~PAGE_MASK);
        if (!region_is_slab(slab)) {
                size_t pages = (slab->slab_size + sizeof(struct malloc_region)) / PAGE_SIZE;
                free_pages(slab, pages);
        } else {
                validate_is_slab(slab);
                debugf("slab=%p ", slab);
                debugf("cs=%"PRIx64 "\n", slab->checksum);
                debugf("size=%u  ", slab->slab_size);
                size_t offset = (ptr - (void *)slab);
                debugf("offset=%"PRIu64, offset);
                if (unlikely(offset < 64)) {
                        koops("free(%p) offset = %lu", ptr, offset);
                }
                if (unlikely((offset - 64) % slab->slab_size)) {
                        koops("free(%p) is not on a valid boundary for slab size of %u (%lx)",
                              ptr, slab->slab_size, offset - 64);
                }
                int bit_idx = (offset-64) / slab->slab_size;
                uint64_t bitmap_mask = (uint64_t)1 << bit_idx;
                debugf("  bit_idx = %d mask=%"PRIx64, bit_idx, bitmap_mask);
                if (likely(slab->allocation_bm[0] & bitmap_mask)) {
                        slab->allocation_bm[0] &= ~bitmap_mask;
                        slab->free_cnt++;
                        debugf(" alloc_bm = %"PRIx64 " freecnt=%"PRIu64 " ", slab->allocation_bm[0], slab->free_cnt);
                } else {
                        koops("%p is not allocated, alloc=%"PRIx64 " mask = %"PRIx64,
                              ptr, slab->allocation_bm[0], bitmap_mask);
                }
                memset(ptr, 0xAA, slab->slab_size);
                update_checksum(slab);
                debugf("cs=%"PRIx64 "\n", slab->checksum);
        }
        if (atomic_fetch_sub(&malloc_lock, 1) != 1) {
                koops("(free)malloc_lock != 1");
        }
}
Exemple #5
0
// Convert a page into a slab
static struct slab_header *
add_new_slab(int slab_idx)
{
        struct slab_header *slab = alloc_pages(1);
        slab->slab_size = slab_info[slab_idx].slab_size;
        slab->lock = 0;
        slab->allocation_bm[0] = 0;
        slab->allocation_bm[1] = 0;
        strcpy(slab->signature, "MALLOC");      // for debugging
        slab->next = slabs[slab_idx];
        update_checksum(slab);
        slabs[slab_idx] = slab;

        return slab;
}
static void create_dlm_req(
      hic_message_context_t *msg_ref,
      hic_dlm_load_req_t **req_pp,
      uint32_t remaining,
      uint32_t addr)
{
   hic_dlm_load_req_t *req;
   int len;

   Mlme_CreateMessageContext(*msg_ref);
   msg_ref->msg_type = HIC_MESSAGE_TYPE_DLM;
   msg_ref->msg_id = HIC_DLM_LOAD_REQ;

   req = HIC_ALLOCATE_RAW_CONTEXT(NULL, msg_ref, hic_dlm_load_req_t);

   req->page.size = DE_MIN(remaining,(uint32_t)1400);
   len = (*dlm_state.ops->get_data)(
            dlm_state.ops,
            dlm_state.offset,
            req->page.size,
            &req->page.ref,
            &req->remaining_size);

   DE_ASSERT(len == req->page.size);

   req->address = addr;
   req->remaining_size = remaining - req->page.size;
   req->reserved = 0;

   req->checksum = update_checksum(
         dlm_state.checksum,
         req->page.ref,
         req->page.size);

   *req_pp = req;
}
Exemple #7
0
int crypto_aead_encrypt(unsigned char *c,unsigned long long *clen,
                        const unsigned char *m,unsigned long long mlen,
                        const unsigned char *ad,unsigned long long adlen,
                        const unsigned char *nsec,
                        const unsigned char *npub,
                        const unsigned char *k) {
    
  v16qi data[16];
  uint8_t buffer[16*16] = {0};
  v16qi tweakey[16*TWEAKEY_SIZE];
  uint8_t pad[16];

  v16qi *checksum = (v16qi*) &buffer[ 16 * (((mlen+15)/16)%16) ];
  v16qi auth = CV(0);

  // Associated Data
  if (adlen > 0) {
    size_t idx=0;
    tweakey_schedule(k, npub, TWEAK_AD, tweakey);
    
    for (idx=0; idx+256<adlen; idx+=16*16) {
      read128(ad+idx, data);
      encrypt_tweakey(data, tweakey);
      tweakey_increment(tweakey, idx);
      write128_checksum(data, NULL, &auth, 16);
    }

    // Final chunk
    uint8_t buffer2[16*16] = {0};
    memcpy(buffer2, ad+idx, adlen-idx);
    if ((adlen % 16) == 0) {
      tweakey_set(tweakey, (adlen-idx-1)/16, 12, TWEAK_AD_LAST_FULL);
    } else {
      tweakey_set(tweakey, (adlen-idx-1)/16, 12, TWEAK_AD_LAST_PARTIAL);
      buffer2[adlen-idx] = 0x80;
    }
    tweakey_set(tweakey, (adlen-idx-1)/16, 13, 0);
    tweakey_set(tweakey, (adlen-idx-1)/16, 14, 0);
    tweakey_set(tweakey, (adlen-idx-1)/16, 15, 0);
    read128(buffer2, data);
    encrypt_tweakey(data, tweakey);
    write128_checksum(data, NULL, &auth, (adlen-idx+15)/16);
  }

  size_t idx=0;
  tweakey_schedule(k, npub, TWEAK_MESSAGE, tweakey);

  if (mlen > 0) {
    
    for (idx=0; idx+16*16<mlen; idx+=16*16) {
      read128_with_checksum(m+idx, data, checksum, 16);
      encrypt_tweakey(data, tweakey);
      tweakey_increment(tweakey, idx);
      write128(data, c+idx);
    }

    // Final chunk(s)
    if ((mlen % 16) == 0) {
      tweakey_set(tweakey, (mlen-idx-1)/16, 12, TWEAK_MESSAGE_LAST_FULL);
    } else {
      tweakey_set(tweakey, (mlen-idx-1)/16, 12, TWEAK_MESSAGE_LAST_PARTIAL);
    }
    tweakey_set(tweakey, (mlen-idx-1)/16, 13, 0);
    tweakey_set(tweakey, (mlen-idx-1)/16, 14, 0);
    tweakey_set(tweakey, (mlen-idx-1)/16, 15, 0);

    if (mlen > idx+240) {
      // Almost full chunk: encrypt length for final block; extra chunk for checksum
      uint8_t buffer2[16*16] = {0};
      memcpy(buffer2, m+idx, 240);
      buffer2[255] = 8*((mlen-1)%16)+8;
      read128_with_checksum(buffer2, data, checksum, 15);
      update_checksum(m+idx+240, checksum, mlen-idx-240);

      encrypt_tweakey(data, tweakey);
      tweakey_increment(tweakey, idx);
      write128(data, buffer2);
      memcpy(c+idx, buffer2, 240);
      memcpy(pad,   buffer2+240, 16);
      idx = mlen;
    } else {
      // Partial chunk: encrypt length for final block; checksum included
      memcpy(buffer, m+idx, mlen-idx);
      update_checksum(buffer, checksum, mlen-idx);

      // Encrypt partial block length
      memset(&buffer[((mlen-idx-1)|15)-15], 0, 16);
      buffer[(mlen-idx-1)|15] = 8*((mlen-1)%16)+8;
    }
  }

  int l = mlen%16? mlen%16: mlen? 16: 0;
  int fullblocks = (mlen-idx-1)/16;

  // Tag generation
  tweakey_set(tweakey, ((mlen-idx+15)/16), 15, 0);
  tweakey_set(tweakey, ((mlen-idx+15)/16), 14, 0);
  tweakey_set(tweakey, ((mlen-idx+15)/16), 13, 0);
  if (mlen%16) {
    tweakey_set(tweakey, ((mlen-idx+15)/16), 12, TWEAK_TAG_LAST_PARTIAL);
  } else {
    tweakey_set(tweakey, ((mlen-idx+15)/16), 12, TWEAK_TAG_LAST_FULL);
  }

  read128(buffer, data);
  encrypt_tweakey(data, tweakey);
  write128(data, buffer);

  *checksum ^= auth;

  memcpy(c+mlen, checksum, CRYPTO_ABYTES);

  if (mlen-idx) {
    memcpy(c+idx, buffer, 16*fullblocks);
    memcpy(pad,   buffer+16*fullblocks, l);
  }
  
  unsigned i;
  for (i=0; i < l; i++)
    c[16*((mlen-1)/16)+i] = m[16*((mlen-1)/16)+i] ^ pad[i];

  *clen = mlen+CRYPTO_ABYTES;

  return 0;
}
Exemple #8
0
int crypto_aead_decrypt(unsigned char *m,unsigned long long *outputmlen,
                        unsigned char *nsec,
                        const unsigned char *c,unsigned long long clen,
                        const unsigned char *ad,unsigned long long adlen,
                        const unsigned char *npub,
                        const unsigned char *k) {
  v16qi data[16];
  uint8_t buffer[16*16] = {0};
  v16qi tweakey[16*TWEAKEY_SIZE];
  *outputmlen = clen-CRYPTO_ABYTES;

  v16qi auth = CV(0);
  v16qi checksum = CV(0);

  // Associated Data
  if (adlen > 0) {
    size_t idx=0;
    tweakey_schedule(k, npub, TWEAK_AD, tweakey);
    
    for (idx=0; idx+256<adlen; idx+=16*16) {
      read128(ad+idx, data);
      encrypt_tweakey(data, tweakey);
      tweakey_increment(tweakey, idx);
      write128_checksum(data, NULL, &auth, 16);
    }

    // Final chunk
    uint8_t buffer2[16*16] = {0};
    memcpy(buffer2, ad+idx, adlen-idx);
    if ((adlen % 16) == 0) {
      tweakey_set(tweakey, (adlen-idx-1)/16, 12, TWEAK_AD_LAST_FULL);
    } else {
      tweakey_set(tweakey, (adlen-idx-1)/16, 12, TWEAK_AD_LAST_PARTIAL);
      buffer2[adlen-idx] = 0x80;
    }
    tweakey_set(tweakey, (adlen-idx-1)/16, 13, 0);
    tweakey_set(tweakey, (adlen-idx-1)/16, 14, 0);
    tweakey_set(tweakey, (adlen-idx-1)/16, 15, 0);
    read128(buffer2, data);
    encrypt_tweakey(data, tweakey);
    write128_checksum(data, NULL, &auth, (adlen-idx+15)/16);
  }

  auth ^= sse_load(c+*outputmlen);

  // Message
  size_t idx=0;
  tweakey_schedule(k, npub, TWEAK_MESSAGE, tweakey);
  for (idx=0; idx+256 < *outputmlen; idx+=256) {
    read128(c+idx, data);
    decrypt_tweakey(data, tweakey);
    tweakey_increment(tweakey, idx);
    write128_checksum(data, m+idx, &checksum, 16);
  }

  int l = *outputmlen%16? *outputmlen%16: *outputmlen? 16: 0;
  int fullblocks = (*outputmlen-l-idx)/16;

  // Final block
  // use slot fullblocks (tweak will be used for tag generation)
  tweakey_set(tweakey, fullblocks, 13, 0);
  tweakey_set(tweakey, fullblocks, 14, 0);
  tweakey_set(tweakey, fullblocks, 15, 0);

  if (*outputmlen) {
    if (*outputmlen%16) {
      tweakey_set(tweakey, fullblocks, 12, TWEAK_MESSAGE_LAST_PARTIAL);
    } else {
      tweakey_set(tweakey, fullblocks, 12, TWEAK_MESSAGE_LAST_FULL);
    }
    
    uint8_t buffer2[16*16] = {0};
    buffer2[16*fullblocks+15] = 8*l;
    read128(buffer2, data);
    
    encrypt_tweakey(data, tweakey);
    write128(data, buffer2);
    unsigned i;
    for (i=0; i<l; i++)
      m[*outputmlen-l+i] = c[*outputmlen-l+i] ^ buffer2[16*fullblocks+i];
    update_checksum(m+*outputmlen-l, &checksum, l);
  }

  // Last chunk: remaining full blocks, and checksum
  memcpy(buffer, c+idx, 16*fullblocks);
  sse_store(buffer+16*fullblocks, auth);
  if (*outputmlen%16) {
    tweakey_set(tweakey, fullblocks, 12, TWEAK_TAG_LAST_PARTIAL);
  } else {
    tweakey_set(tweakey, fullblocks, 12, TWEAK_TAG_LAST_FULL);
  }
  read128(buffer, data);
  decrypt_tweakey(data, tweakey);
  write128_checksum2(data, buffer, &checksum, fullblocks+1, fullblocks);
  memcpy(m+idx, buffer, 16*fullblocks);

  // Verify tag
  if (memcmp(&checksum, buffer+16*fullblocks, 16) != 0) {
    memset(m, 0, *outputmlen);
    return -1;
  }

  return 0;
}
Exemple #9
0
/**
 * main function - for clone 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
	int			dfr, dfw;		/// file descriptor for source and target
	int			r_size, w_size;		/// read and write size
	unsigned		cs_size = 0;		/// checksum_size
	int			cs_reseed = 1;
	int			start, stop;		/// start, range, stop number for progress bar
	unsigned long *bitmap = NULL;		/// the point for bitmap data
	int			debug = 0;		/// debug level
	int			tui = 0;		/// text user interface
	int			pui = 0;		/// progress mode(default text)
	
	int			flag;
	int			pres = 0;
	pthread_t		prog_thread;
	void			*p_result;

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

	file_system_info fs_info;   /// description of the file system
	image_options    img_opt;

	init_fs_info(&fs_info);
	init_image_options(&img_opt);

	/**
	 * 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;

	//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)) {
		opt.ncurses = 0;
		pui = TEXT;
		log_mesg(1, 0, 0, debug, "Open Ncurses User Interface Error.\n");
	}

	/// print partclone info
	print_partclone_info(opt);

#ifndef CHKIMG
	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");
#endif

	/// ignore crc check
	if (opt.ignore_crc)
		log_mesg(1, 0, 1, debug, "Ignore CRC errors\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
	 */
	source = opt.source;
	target = opt.target;
	log_mesg(1, 0, 0, debug, "source=%s, target=%s \n", source, target);
	dfr = open_source(source, &opt);
	if (dfr == -1) {
		log_mesg(0, 1, 1, debug, "Error exit\n");
	}

#ifndef CHKIMG
	dfw = open_target(target, &opt);
	if (dfw == -1) {
		log_mesg(0, 1, 1, debug, "Error exit\n");
	}
#else
	dfw = -1;
#endif

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

		log_mesg(1, 0, 0, debug, "Initiate image options - version %s\n", IMAGE_VERSION_CURRENT);

		img_opt.checksum_mode = opt.checksum_mode;
		img_opt.checksum_size = get_checksum_size(opt.checksum_mode, opt.debug);
		img_opt.blocks_per_checksum = opt.blocks_per_checksum;
		img_opt.reseed_checksum = opt.reseed_checksum;

		cs_size = img_opt.checksum_size;
		cs_reseed = img_opt.reseed_checksum;

		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
		read_super_blocks(source, &fs_info);

		if (img_opt.checksum_mode != CSM_NONE && img_opt.blocks_per_checksum == 0) {

			const unsigned int buffer_capacity = opt.buffer_size > fs_info.block_size
				? opt.buffer_size / fs_info.block_size : 1; // in blocks

			img_opt.blocks_per_checksum = buffer_capacity;

		}
		log_mesg(1, 0, 0, debug, "%u blocks per checksum\n", img_opt.blocks_per_checksum);

		check_mem_size(fs_info, img_opt, opt);

		/// alloc a memory to store bitmap
		bitmap = pc_alloc_bitmap(fs_info.totalblock);
		if (bitmap == NULL) {
			log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__);
		}

		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 partition
		log_mesg(0, 0, 1, debug, "Calculating bitmap... Please wait... \n");
		read_bitmap(source, fs_info, bitmap, pui);
		update_used_blocks_count(&fs_info, bitmap);

		if (opt.check) {

			unsigned long long needed_space = 0;

			needed_space += sizeof(image_head) + sizeof(file_system_info) + sizeof(image_options);
			needed_space += get_bitmap_size_on_disk(&fs_info, &img_opt, &opt);
			needed_space += cnv_blocks_to_bytes(0, fs_info.usedblocks, fs_info.block_size, &img_opt);

			check_free_space(&dfw, needed_space);
		}

		log_mesg(2, 0, 0, debug, "check main bitmap pointer %p\n", bitmap);
		log_mesg(1, 0, 0, debug, "Writing super block and bitmap...\n");

		write_image_desc(&dfw, fs_info, img_opt, &opt);
		write_image_bitmap(&dfw, fs_info, img_opt, bitmap, &opt);

		log_mesg(0, 0, 1, debug, "done!\n");

	} else if (opt.restore) {

		image_head_v2 img_head;

		log_mesg(1, 0, 0, debug, "restore image hdr - get information from image file\n");
		log_mesg(1, 0, 1, debug, "Reading Super Block\n");

		/// get image information from image file
		load_image_desc(&dfr, &opt, &img_head, &fs_info, &img_opt);
		cs_size = img_opt.checksum_size;
		cs_reseed = img_opt.reseed_checksum;

		check_mem_size(fs_info, img_opt, opt);

		/// alloc a memory to restore bitmap
		bitmap = pc_alloc_bitmap(fs_info.totalblock);
		if (bitmap == NULL) {
			log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__);
		}

		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... Please wait...\n");
		load_image_bitmap(&dfr, opt, fs_info, img_opt, bitmap);

#ifndef CHKIMG
		/// check the dest partition size.
		if (opt.restore_raw_file)
			check_free_space(&dfw, fs_info.device_size);
		else if (opt.check)
			check_size(&dfw, fs_info.device_size);
#endif

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

	} else if (opt.dd || opt.domain) {

		log_mesg(1, 0, 0, debug, "Initiate image options - version %s\n", IMAGE_VERSION_CURRENT);
		img_opt.checksum_mode = opt.checksum_mode;
		img_opt.checksum_size = get_checksum_size(opt.checksum_mode, opt.debug);
		img_opt.blocks_per_checksum = opt.blocks_per_checksum;
		img_opt.reseed_checksum = opt.reseed_checksum;
		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
		read_super_blocks(source, &fs_info);

		check_mem_size(fs_info, img_opt, opt);

		/// alloc a memory to restore bitmap
		bitmap = pc_alloc_bitmap(fs_info.totalblock);
		if (bitmap == NULL) {
			log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__);
		}

		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 partition
		log_mesg(0, 0, 1, debug, "Calculating bitmap... Please wait... ");
		read_bitmap(source, fs_info, bitmap, pui);

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

		log_mesg(2, 0, 0, debug, "check main bitmap pointer %p\n", bitmap);
		log_mesg(0, 0, 1, debug, "done!\n");
	} else if (opt.ddd){

		if (dfr != 0)
		    read_super_blocks(source, &fs_info);
		else
		    read_super_blocks(target, &fs_info);

		img_opt.checksum_mode = opt.checksum_mode;
		img_opt.checksum_size = get_checksum_size(opt.checksum_mode, opt.debug);
		img_opt.blocks_per_checksum = opt.blocks_per_checksum;
		check_mem_size(fs_info, img_opt, opt);

		/// alloc a memory to restore bitmap
		bitmap = pc_alloc_bitmap(fs_info.totalblock);
		if (bitmap == NULL) {
			log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__);
		}

		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 partition
		log_mesg(0, 0, 1, debug, "Calculating bitmap... Please wait... ");
		read_bitmap(source, fs_info, bitmap, pui);

		/// check the dest partition size.
		if (opt.check) {

		    struct stat target_stat;
		    if ((stat(opt.target, &target_stat) != -1) && (strcmp(opt.target, "-") != 0)) {
			if (S_ISBLK(target_stat.st_mode)) 
			    check_size(&dfw, fs_info.device_size);
			else {
			    unsigned long long needed_space = 0;

			    needed_space += sizeof(image_head) + sizeof(file_system_info) + sizeof(image_options);
			    needed_space += get_bitmap_size_on_disk(&fs_info, &img_opt, &opt);
			    needed_space += cnv_blocks_to_bytes(0, fs_info.usedblocks, fs_info.block_size, &img_opt);

			    check_free_space(&dfw, needed_space);
			}
		    }
		}

		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 information\n");

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

	print_file_system_info(fs_info, opt);

	/**
	 * initial progress bar
	 */
	start = 0;				/// start number of progress bar
	stop = (fs_info.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, fs_info.totalblock, flag, fs_info.block_size);
	copied = 0;				/// initial number is 0

	/**
	 * thread to print progress
	 */
	pres = pthread_create(&prog_thread, NULL, thread_update_pui, NULL);
	if(pres)
	    log_mesg(0, 1, 1, debug, "%s, %i, thread create error\n", __func__, __LINE__);


	/**
	 * start read and write data between source and destination
	 */
	if (opt.clone) {

		const unsigned long long blocks_total = fs_info.totalblock;
		const unsigned int block_size = fs_info.block_size;
		const unsigned int buffer_capacity = opt.buffer_size > block_size ? opt.buffer_size / block_size : 1; // in blocks
		unsigned char checksum[cs_size];
		unsigned int blocks_in_cs, blocks_per_cs, write_size;
		char *read_buffer, *write_buffer;

		blocks_per_cs = img_opt.blocks_per_checksum;

		log_mesg(1, 0, 0, debug, "#\nBuffer capacity = %u, Blocks per cs = %u\n#\n", buffer_capacity, blocks_per_cs);

		write_size = cnv_blocks_to_bytes(0, buffer_capacity, block_size, &img_opt);

		read_buffer = (char*)malloc(buffer_capacity * block_size);
		write_buffer = (char*)malloc(write_size + cs_size);

		if (read_buffer == NULL || write_buffer == NULL) {
			log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__);
		}

		/// read data from the first block
		if (lseek(dfr, 0, SEEK_SET) == (off_t)-1)
			log_mesg(0, 1, 1, debug, "source seek ERROR:%s\n", strerror(errno));

		log_mesg(0, 0, 0, debug, "Total block %llu\n", blocks_total);

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

		blocks_in_cs = 0;
		init_checksum(img_opt.checksum_mode, checksum, debug);

		block_id = 0;
		do {
			/// scan bitmap
			unsigned long long i, blocks_skip, blocks_read;
			unsigned int cs_added = 0, write_offset = 0;
			off_t offset;

			/// skip unused blocks
			for (blocks_skip = 0;
			     block_id + blocks_skip < blocks_total &&
			     !pc_test_bit(block_id + blocks_skip, bitmap);
			     blocks_skip++);
			if (block_id + blocks_skip == blocks_total)
				break;

			if (blocks_skip)
				block_id += blocks_skip;

			/// read blocks
			for (blocks_read = 0;
			     block_id + blocks_read < blocks_total && blocks_read < buffer_capacity &&
			     pc_test_bit(block_id + blocks_read, bitmap);
			     ++blocks_read);
			if (!blocks_read)
				break;

			offset = (off_t)(block_id * block_size);
			if (lseek(dfr, offset, SEEK_SET) == (off_t)-1)
				log_mesg(0, 1, 1, debug, "source seek ERROR:%s\n", strerror(errno));

			r_size = read_all(&dfr, read_buffer, blocks_read * block_size, &opt);
			if (r_size != (int)(blocks_read * block_size)) {
				if ((r_size == -1) && (errno == EIO)) {
					if (opt.rescue) {
						memset(read_buffer, 0, blocks_read * block_size);
						for (r_size = 0; r_size < blocks_read * block_size; r_size += PART_SECTOR_SIZE)
							rescue_sector(&dfr, offset + r_size, read_buffer + r_size, &opt);
					} else
						log_mesg(0, 1, 1, debug, "%s", bad_sectors_warning_msg);
				} else
					log_mesg(0, 1, 1, debug, "read error: %s\n", strerror(errno));
			}

			/// calculate checksum
			log_mesg(2, 0, 0, debug, "blocks_read = %i\n", blocks_read);
			for (i = 0; i < blocks_read; ++i) {

				memcpy(write_buffer + write_offset,
					read_buffer + i * block_size, block_size);

				write_offset += block_size;

				update_checksum(checksum, read_buffer + i * block_size, block_size);

				if (blocks_per_cs > 0 && ++blocks_in_cs == blocks_per_cs) {
				    log_mesg(3, 0, 0, debug, "CRC = %x%x%x%x \n", checksum[0], checksum[1], checksum[2], checksum[3]);

					memcpy(write_buffer + write_offset, checksum, cs_size);

					++cs_added;
					write_offset += cs_size;

					blocks_in_cs = 0;
					if (cs_reseed)
						init_checksum(img_opt.checksum_mode, checksum, debug);
				}
			}

			/// write buffer to target
			w_size = write_all(&dfw, write_buffer, write_offset, &opt);
			if (w_size != write_offset)
				log_mesg(0, 1, 1, debug, "image write ERROR:%s\n", strerror(errno));

			/// count copied block
			copied += blocks_read;
			log_mesg(2, 0, 0, debug, "copied = %lld\n", copied);

			/// next block
			block_id += blocks_read;

			/// read or write error
			if (r_size + cs_added * cs_size != w_size)
				log_mesg(0, 1, 1, debug, "read(%i) and write(%i) different\n", r_size, w_size);

		} while (1);

		if (blocks_in_cs > 0) {

			// Write the checksum for the latest blocks
			log_mesg(1, 0, 0, debug, "Write the checksum for the latest blocks. size = %i\n", cs_size);
			log_mesg(3, 0, 0, debug, "CRC = %x%x%x%x \n", checksum[0], checksum[1], checksum[2], checksum[3]);
			w_size = write_all(&dfw, (char*)checksum, cs_size, &opt);
			if (w_size != cs_size)
				log_mesg(0, 1, 1, debug, "image write ERROR:%s\n", strerror(errno));
		}

		free(write_buffer);
		free(read_buffer);

	// check only the size when the image does not contains checksums and does not
	// comes from a pipe
	} else if (opt.chkimg && img_opt.checksum_mode == CSM_NONE
		&& strcmp(opt.source, "-") != 0) {

		unsigned long long total_offset = (fs_info.usedblocks - 1) * fs_info.block_size;
		char last_block[fs_info.block_size];
		off_t partial_offset = INT32_MAX;

		while (total_offset) {

			if (partial_offset > total_offset)
				partial_offset = total_offset;

			if (lseek(dfr, partial_offset, SEEK_CUR) == (off_t)-1)
				log_mesg(0, 1, 1, debug, "source seek ERROR: %s\n", strerror(errno));

			total_offset -= partial_offset;
		}

		if (read_all(&dfr, last_block, fs_info.block_size, &opt) != fs_info.block_size)
			log_mesg(0, 1, 1, debug, "ERROR: source image too short\n");

	} else if (opt.restore) {

		const unsigned long long blocks_total = fs_info.totalblock;
		const unsigned int block_size = fs_info.block_size;
		const unsigned int buffer_capacity = opt.buffer_size > block_size ? opt.buffer_size / block_size : 1; // in blocks
		const unsigned int blocks_per_cs = img_opt.blocks_per_checksum;
		unsigned long long blocks_used = fs_info.usedblocks;
		unsigned int blocks_in_cs, buffer_size, read_offset;
		unsigned char checksum[cs_size];
		char *read_buffer, *write_buffer;
		unsigned long long blocks_used_fix = 0, test_block = 0;

		log_mesg(1, 0, 0, debug, "#\nBuffer capacity = %u, Blocks per cs = %u\n#\n", buffer_capacity, blocks_per_cs);

		// fix some super block record incorrect
		for (test_block = 0; test_block < blocks_total; ++test_block)
			if (pc_test_bit(test_block, bitmap))
				blocks_used_fix++;

		if (blocks_used_fix != blocks_used) {
			blocks_used = blocks_used_fix;
			log_mesg(1, 0, 0, debug, "info: fixed used blocks count\n");
		}
		buffer_size = cnv_blocks_to_bytes(0, buffer_capacity, block_size, &img_opt);

		if (img_opt.image_version != 0x0001)
			read_buffer = (char*)malloc(buffer_size);
		else {
			// Allocate more memory in case the image is affected by the 64 bits bug
			read_buffer = (char*)malloc(buffer_size + buffer_capacity * cs_size);
		}
		write_buffer = (char*)malloc(buffer_capacity * block_size);
		if (read_buffer == NULL || write_buffer == NULL) {
			log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__);
		}

#ifndef CHKIMG
		/// seek to the first
		if (lseek(dfw, opt.offset, SEEK_SET) == (off_t)-1)
			log_mesg(0, 1, 1, debug, "target seek ERROR:%s\n", strerror(errno));
#endif

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

		blocks_in_cs = 0;
		if (!opt.ignore_crc)
			init_checksum(img_opt.checksum_mode, checksum, debug);

		block_id = 0;
		do {
			unsigned int i;
			unsigned long long blocks_written, bytes_skip;
			unsigned int read_size;
			// max chunk to read using one read(2) syscall
			int blocks_read = copied + buffer_capacity < blocks_used ?
				buffer_capacity : blocks_used - copied;
			if (!blocks_read)
				break;

			log_mesg(1, 0, 0, debug, "blocks_read = %d and copied = %lld\n", blocks_read, copied);
			read_size = cnv_blocks_to_bytes(copied, blocks_read, block_size, &img_opt);

			// increase read_size to make room for the oversized checksum
			if (blocks_per_cs && blocks_read < buffer_capacity &&
					(blocks_read % blocks_per_cs) && (blocks_used % blocks_per_cs)) {
				/// it is the last read and there is a partial chunk at the end
				log_mesg(1, 0, 0, debug, "# PARTIAL CHUNK\n");
				read_size += cs_size;
			}

			// read chunk from image
			log_mesg(1, 0, 0, debug, "read more: ");

			r_size = read_all(&dfr, read_buffer, read_size, &opt);
			if (r_size != read_size)
				log_mesg(0, 1, 1, debug, "read ERROR:%s\n", strerror(errno));

			// read buffer is the follows:
			// <blocks_per_cs><cs1><blocks_per_cs><cs2>...

			// write buffer should be the following:
			// <block1><block2>...

			read_offset = 0;
			for (i = 0; i < blocks_read; ++i) {

				memcpy(write_buffer + i * block_size,
					read_buffer + read_offset, block_size);

				if (opt.ignore_crc) {
					read_offset += block_size;
					if (++blocks_in_cs == blocks_per_cs)
						read_offset += cs_size;
					continue;
				}

				update_checksum(checksum, read_buffer + read_offset, block_size);

				if (++blocks_in_cs == blocks_per_cs) {

				    unsigned char checksum_orig[cs_size];
				    memcpy(checksum_orig, read_buffer + read_offset + block_size, cs_size);
				    log_mesg(3, 0, 0, debug, "CRC = %x%x%x%x \n", checksum[0], checksum[1], checksum[2], checksum[3]);
				    log_mesg(3, 0, 0, debug, "CRC.orig = %x%x%x%x \n", checksum_orig[0], checksum_orig[1], checksum_orig[2], checksum_orig[3]);
					if (memcmp(read_buffer + read_offset + block_size, checksum, cs_size)) {
					    log_mesg(0, 1, 1, debug, "CRC error, block_id=%llu...\n ", block_id + i);
					}

					read_offset += cs_size;

					blocks_in_cs = 0;
					if (cs_reseed)
						init_checksum(img_opt.checksum_mode, checksum, debug);
				}

				read_offset += block_size;
			}
			if (blocks_in_cs && blocks_per_cs && blocks_read < buffer_capacity &&
					(blocks_read % blocks_per_cs)) {

			    log_mesg(1, 0, 0, debug, "check latest chunk's checksum covering %u blocks\n", blocks_in_cs);
			    if (memcmp(read_buffer + read_offset, checksum, cs_size)){
				unsigned char checksum_orig[cs_size];
				memcpy(checksum_orig, read_buffer + read_offset, cs_size);
				log_mesg(1, 0, 0, debug, "CRC = %x%x%x%x \n", checksum[0], checksum[1], checksum[2], checksum[3]);
				log_mesg(1, 0, 0, debug, "CRC.orig = %x%x%x%x \n", checksum_orig[0], checksum_orig[1], checksum_orig[2], checksum_orig[3]);
				log_mesg(0, 1, 1, debug, "CRC error, block_id=%llu...\n ", block_id + i);
			    }

			}


			blocks_written = 0;
			do {
				int blocks_write;

				/// count bytes to skip
				for (bytes_skip = 0;
				     block_id < blocks_total &&
				     !pc_test_bit(block_id, bitmap);
				     block_id++, bytes_skip += block_size);

#ifndef CHKIMG
				/// skip empty blocks
				if (bytes_skip > 0 && lseek(dfw, (off_t)bytes_skip, SEEK_CUR) == (off_t)-1)
					log_mesg(0, 1, 1, debug, "target seek ERROR:%s\n", strerror(errno));
#endif

				/// blocks to write
				for (blocks_write = 0;
				     block_id + blocks_write < blocks_total &&
				     blocks_written + blocks_write < blocks_read &&
				     pc_test_bit(block_id + blocks_write, bitmap);
				     blocks_write++);

#ifndef CHKIMG
				// write blocks
				if (blocks_write > 0) {
					w_size = write_all(&dfw, write_buffer + blocks_written * block_size,
						blocks_write * block_size, &opt);
					if (w_size != blocks_write * block_size) {
						if (!opt.skip_write_error)
							log_mesg(0, 1, 1, debug, "write block %llu ERROR:%s\n", block_id + blocks_written, strerror(errno));
						else
							log_mesg(0, 0, 1, debug, "skip write block %llu error:%s\n", block_id + blocks_written, strerror(errno));
					}
				}
#endif

				blocks_written += blocks_write;
				block_id += blocks_write;
				copied += blocks_write;
			} while (blocks_written < blocks_read);

		} while(1);
		free(write_buffer);
		free(read_buffer);

#ifndef CHKIMG
		/// restore_raw_file option
		if (opt.restore_raw_file && !pc_test_bit(blocks_total - 1, bitmap)) {
			if (ftruncate(dfw, (off_t)(blocks_total * block_size)) == -1)
				log_mesg(0, 0, 1, debug, "ftruncate ERROR:%s\n", strerror(errno));
		}
#endif

	} else if (opt.dd) {

		char *buffer;
		int block_size = fs_info.block_size;
		unsigned long long blocks_total = fs_info.totalblock;
		int buffer_capacity = block_size < opt.buffer_size ? opt.buffer_size / block_size : 1;

		buffer = (char*)malloc(buffer_capacity * block_size);
		if (buffer == NULL) {
			log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__);
		}

		block_id = 0;

		if (lseek(dfr, 0, SEEK_SET) == (off_t)-1)
			log_mesg(0, 1, 1, debug, "source seek ERROR:%d\n", strerror(errno));

		log_mesg(0, 0, 0, debug, "Total block %llu\n", blocks_total);

		/// start clone partition to partition
		log_mesg(1, 0, 0, debug, "start backup data device-to-device...\n");
		do {
			/// scan bitmap
			unsigned long long blocks_skip, blocks_read;
			off_t offset;

			/// skip unused blocks
			for (blocks_skip = 0;
			     block_id + blocks_skip < blocks_total &&
			     !pc_test_bit(block_id + blocks_skip, bitmap);
			     blocks_skip++);

			if (block_id + blocks_skip == blocks_total)
				break;

			if (blocks_skip)
				block_id += blocks_skip;

			/// read chunk from source
			for (blocks_read = 0;
			     block_id + blocks_read < blocks_total && blocks_read < buffer_capacity &&
			     pc_test_bit(block_id + blocks_read, bitmap);
			     ++blocks_read);

			if (!blocks_read)
				break;

			offset = (off_t)(block_id * block_size);
			if (lseek(dfr, offset, SEEK_SET) == (off_t)-1)
				log_mesg(0, 1, 1, debug, "source seek ERROR:%s\n", strerror(errno));
			if (lseek(dfw, offset + opt.offset, SEEK_SET) == (off_t)-1)
				log_mesg(0, 1, 1, debug, "target seek ERROR:%s\n", strerror(errno));

			r_size = read_all(&dfr, buffer, blocks_read * block_size, &opt);
			if (r_size != (int)(blocks_read * block_size)) {
				if ((r_size == -1) && (errno == EIO)) {
					if (opt.rescue) {
						memset(buffer, 0, blocks_read * block_size);
						for (r_size = 0; r_size < blocks_read * block_size; r_size += PART_SECTOR_SIZE)
							rescue_sector(&dfr, offset + r_size, buffer + r_size, &opt);
					} else
						log_mesg(0, 1, 1, debug, "%s", bad_sectors_warning_msg);
				} else
					log_mesg(0, 1, 1, debug, "source read ERROR %s\n", strerror(errno));
			}

			/// write buffer to target
			w_size = write_all(&dfw, buffer, blocks_read * block_size, &opt);
			if (w_size != (int)(blocks_read * block_size)) {
				if (opt.skip_write_error)
					log_mesg(0, 0, 1, debug, "skip write block %lli error:%s\n", block_id, strerror(errno));
				else
					log_mesg(0, 1, 1, debug, "write block %lli ERROR:%s\n", block_id, strerror(errno));
			}

			/// count copied block
			copied += blocks_read;

			/// next block
			block_id += blocks_read;

			/// read or write error
			if (r_size != w_size) {
				if (opt.skip_write_error)
					log_mesg(0, 0, 1, debug, "read and write different\n");
				else
					log_mesg(0, 1, 1, debug, "read and write different\n");
			}
		} while (1);

		free(buffer);

		/// restore_raw_file option
		if (opt.restore_raw_file && !pc_test_bit(blocks_total - 1, bitmap)) {
			if (ftruncate(dfw, (off_t)(blocks_total * block_size)) == -1)
				log_mesg(0, 0, 1, debug, "ftruncate ERROR:%s\n", strerror(errno));
		}

	} else if (opt.domain) {

		int cmp, nx_current = 0;
		unsigned long long next_block_id = 0;
		log_mesg(0, 0, 0, debug, "Total block %i\n", fs_info.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", get_exec_name(), 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 + (fs_info.totalblock * fs_info.block_size));
		dprintf(dfw, "#      pos        size  status\n");
		// start logging the used/unused areas
		cmp = pc_test_bit(0, bitmap);
		for (block_id = 0; block_id <= fs_info.totalblock; block_id++) {
			if (block_id < fs_info.totalblock) {
				nx_current = pc_test_bit(block_id, bitmap);
				if (nx_current)
					copied++;
			} else
				nx_current = -1;
			if (nx_current != cmp) {
				dprintf(dfw, "0x%08llX  0x%08llX  %c\n",
					opt.offset_domain + (next_block_id * fs_info.block_size),
					(block_id - next_block_id) * fs_info.block_size,
					cmp ? '+' : '?');
				next_block_id = block_id;
				cmp = nx_current;
			}
			// don't bother updating progress
		} /// end of for
	} else if (opt.ddd) {

		char *buffer;
		int block_size = fs_info.block_size;
		unsigned long long blocks_total = fs_info.totalblock;
		int blocks_in_buffer = block_size < opt.buffer_size ? opt.buffer_size / block_size : 1;

		buffer = (char*)malloc(blocks_in_buffer * block_size);
		if (buffer == NULL) {
			log_mesg(0, 1, 1, debug, "%s, %i, not enough memory\n", __func__, __LINE__);
		}

		block_id = 0;


		log_mesg(0, 0, 0, debug, "Total block %llu\n", blocks_total);

		/// start clone partition to partition
		log_mesg(1, 0, 0, debug, "start backup data device-to-device...\n");
		do {
			/// scan bitmap
			unsigned long long blocks_read;

			/// read chunk from source
			for (blocks_read = 0;
			     block_id + blocks_read < blocks_total && blocks_read < blocks_in_buffer &&
			     pc_test_bit(block_id + blocks_read, bitmap);
			     blocks_read++);

			if (!blocks_read)
				break;

			r_size = read_all(&dfr, buffer, blocks_read * block_size, &opt);
			if (r_size != (int)(blocks_read * block_size)) {
				if ((r_size == -1) && (errno == EIO)) {
					if (opt.rescue) {
						memset(buffer, 0, blocks_read * block_size);
						for (r_size = 0; r_size < blocks_read * block_size; r_size += PART_SECTOR_SIZE)
							rescue_sector(&dfr, r_size, buffer + r_size, &opt);
					} else
						log_mesg(0, 1, 1, debug, "%s", bad_sectors_warning_msg);
				} else if (r_size == 0){ // done for ddd
				    /// write buffer to target
				    w_size = write_all(&dfw, buffer, rescue_write_size, &opt);
				    break;
				} else
					log_mesg(0, 1, 1, debug, "source read ERROR %s\n", strerror(errno));
			}

			/// write buffer to target
			w_size = write_all(&dfw, buffer, blocks_read * block_size, &opt);
			if (w_size != (int)(blocks_read * block_size)) {
				if (opt.skip_write_error)
					log_mesg(0, 0, 1, debug, "skip write block %lli error:%s\n", block_id, strerror(errno));
				else
					log_mesg(0, 1, 1, debug, "write block %lli ERROR:%s\n", block_id, strerror(errno));
			}

			/// count copied block
			copied += blocks_read;

			/// next block
			block_id += blocks_read;

			/// read or write error
			if (r_size != w_size) {
				if (opt.skip_write_error)
					log_mesg(0, 0, 1, debug, "read and write different\n");
				else
					log_mesg(0, 1, 1, debug, "read and write different\n");
			}
		} while (1);

		free(buffer);

		/// restore_raw_file option
		if (opt.restore_raw_file && !pc_test_bit(blocks_total - 1, bitmap)) {
			if (ftruncate(dfw, (off_t)(blocks_total * block_size)) == -1)
				log_mesg(0, 0, 1, debug, "ftruncate ERROR:%s\n", strerror(errno));
		}



	}

	done = 1;
	pres = pthread_join(prog_thread, &p_result);
	if(pres)
	    log_mesg(0, 1, 1, debug, "%s, %i, thread join error\n", __func__, __LINE__);
	update_pui(&prog, copied, block_id, done);
#ifndef CHKIMG
	sync_data(dfw, &opt);
#endif
	print_finish_info(opt);

	/// close source
	close(dfr);
	/// close target
	if (dfw != -1)
		close(dfw);
	/// free bitmp
	free(bitmap);
	close_pui(pui);
#ifndef CHKIMG
	fprintf(stderr, "Cloned successfully.\n");
#else
	printf("Checked successfully.\n");
#endif
	if (opt.debug)
		close_log();
#ifdef MEMTRACE
	muntrace();
#endif
	return 0;      /// finish
}
Exemple #10
0
int main(int argc, char* argv[])
{
    int mismatch;
    int optc;
    register int i;

    if (argc < 2)
    {
        fprintf(stderr, "Correct syntax:  %s <filepath> [options]\n", argv[0]);
        fgetc(stdin);
        return 1;
    }
    i = import_EEPROM(argv[1]);
    if (i != 0)
    {
        fputs("Unable to import EEPROM.\n", stderr);
        return 1;
    }

    if (EEPROM[0x080] == 0x08)
        global_data = EEPROM + 0x080;
    else
    {
        if (EEPROM[0x000] != 0x08)
            printf("Warning:  %s\n", "Failed magic number tests.");
        global_data = EEPROM + 0x000;
    }

    game = file[3]; /* default (Rareware adds new games bottom-up.) */
    for (i = 0; i < 3; i++)
        if (file[i][0x00A] == 0x00)
            continue;
    i -= i >> 2; /* i = (i >= 4) ? 3 : i; */
    game = file[i];
/*
 * When updating an existing game save, Rareware likes to zero all 64 bits
 * at the start of the game save block and transfer the new data elsewhere.
 *
 * As if that wasn't enough to throw us off, they also like to alternate and
 * switch which copy is the real game save and which one they corrupted.
 * It can break save editors AND your view of save updates in a hex editor.
 *
 * IF, due to hacks, there is a tie in conditions, or two save blocks both
 * qualify as fully valid game data for the save file, it should be
 * remembered that the ROM defaults to the bottom-most data in EEPROM depths.
 */
    if (file[0][0x00A] != 0x00)
    {
        if (file[0][0x00A] == file[3][0x00A])
            game = (*(i64 *)(file[0] + 0x000) == 0) ? file[3] : file[0];
        else if (file[0][0x00A] == file[2][0x00A])
            game = (*(i64 *)(file[0] + 0x000) == 0) ? file[2] : file[0];
        else if (file[0][0x00A] == file[1][0x00A])
            game = (*(i64 *)(file[0] + 0x000) == 0) ? file[1] : file[0];
    }
    if (file[1][0x00A] != 0x00)
    {
        if (file[1][0x00A] == file[3][0x00A])
            game = (*(i64 *)(file[1] + 0x000) == 0) ? file[3] : file[1];
        else if (file[1][0x00A] == file[2][0x00A])
            game = (*(i64 *)(file[1] + 0x000) == 0) ? file[2] : file[1];
    }
    if (file[2][0x00A] != 0x00)
        if (file[2][0x00A] == file[3][0x00A])
            game = (*(i64 *)(file[2] + 0x000) == 0) ? file[3] : file[2];

    mismatch = trace_Banjo_checksum((unsigned)(global_data - EEPROM)/8, 120);
    if (mismatch != 0)
        printf(
            "Warning:  %s.\n%s\n%s\n\n",
            "Overwriting global data checksum mismatch.",
        checksum_stored, checksum_actual);
    mismatch = trace_Banjo_checksum((unsigned)(game - EEPROM)/8, 440);
    if (mismatch != 0)
        printf(
            "Warning:  %s.\n%s\n%s\n\n",
            "Overwriting save file checksum mismatch.",
        checksum_stored, checksum_actual);

    for (optc = 0; argc > 0; --argc, ++optc)
    {
        if (argv[optc][0] != '-')
            continue;
        execute_option(argc, &argv[optc]);
    }
/*
 * Fill in the magic numbers so the ROM recognizes the data as valid.
 * Wouldn't want to edit deleted or wiped parts of the EEPROM, would we?
 */
    global_data[0x00] = 0x08;
    game[0x000] = 'K'; game[0x001] = 'H'; game[0x002] = 'J'; game[0x003] = 'C';
    game[0x004] = 0x01; game[0x005] = 0x02; game[0x006] = 0x1E;
 /* doesn't seem to care what game[0x007] is set to */
    game[0x008] = 0x02;
 /* game[0x009] = 0x01; */
    if (game[0x00A] == 0x00)
    {
        printf("Warning:  %s\n", "Saved minimalist game data to a new slot.\n");
        game[0x00A] = 0x01; /* If no data was present, default to file 1. */
    }
 /* game[0x00B] = 0x03; */
 /* game[0x00C] = 0x1C; */

    update_checksum(
        global_data + 0x78, (unsigned)(global_data - EEPROM)/8, 120);
    update_checksum(
        game + 0x1B8, (unsigned)(game - EEPROM)/8, 440);

    i = export_EEPROM(argv[1]);
    if (i != 0)
    {
        fputs("Unable to export EEPROM.\n", stderr);
        return 1;
    }
    return 0;
}