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, ®ister_id); register_event_by_clock(this, EVENT_32HZ, CPU_CLOCKS >> 5, true, NULL); }
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; }
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"); } }
// 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; }
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; }
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; }
/** * 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 }
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; }