void validate_map(partition_map_header *map) { range_list *list; char *name; unsigned int i; u32 limit; int printed; //printf("Validation not implemented yet.\n"); if (map == NULL) { the_map = 0; if (get_string_argument("Name of device: ", &name, 1) == 0) { bad_input("Bad name"); return; } the_media = open_pathname_as_media(name, O_RDONLY); if (the_media == 0) { error(errno, "can't open file '%s'", name); free(name); return; } g = media_granularity(the_media); if (g < PBLOCK_SIZE) { g = PBLOCK_SIZE; } the_media = open_deblock_media(PBLOCK_SIZE, the_media); buffer = malloc(PBLOCK_SIZE); if (buffer == NULL) { error(errno, "can't allocate memory for disk buffer"); goto done; } } else { name = 0; the_map = map; g = map->logical_block; } initialize_list(&list); // get block 0 if (get_block_zero() == 0) { printf("unable to read block 0\n"); goto check_map; } // XXX signature valid // XXX size & count match DeviceCapacity // XXX number of descriptors matches array size // XXX each descriptor wholly contained in a partition // XXX the range below here is in physical blocks but the map is in logical blocks!!! add_range(&list, 1, b0->sbBlkCount-1, 0); /* subtract one since args are base & len */ check_map: // compute size of map if (map != NULL) { limit = the_map->blocks_in_map; } else { if (get_block_n(1) == 0) { printf("unable to get first block\n"); goto done; } else { if (mb->dpme_signature != DPME_SIGNATURE) { limit = -1; } else { limit = mb->dpme_map_entries; } } } // for each entry for (i = 1; ; i++) { #if 0 if (limit < 0) { /* XXX what to use for end of list? */ if (i > 5) { break; } } else #endif if (i > limit) { break; } printf("block %d:\n", i); // get entry if (get_block_n(i) == 0) { printf("\tunable to get\n"); goto post_processing; } printed = 0; // signature matches if (mb->dpme_signature != DPME_SIGNATURE) { printed = 1; printf("\tsignature is 0x%x, should be 0x%x\n", mb->dpme_signature, DPME_SIGNATURE); } // reserved1 == 0 if (mb->dpme_reserved_1 != 0) { printed = 1; printf("\treserved word is 0x%x, should be 0\n", mb->dpme_reserved_1); } // entry count matches #if 0 if (limit < 0) { printed = 1; printf("\tentry count is 0x%lx, real value unknown\n", mb->dpme_map_entries); } else #endif if (mb->dpme_map_entries != limit) { printed = 1; printf("\tentry count is 0x%lx, should be %ld\n", mb->dpme_map_entries, limit); } // lblocks contained within physical if (mb->dpme_lblock_start >= mb->dpme_pblocks || mb->dpme_lblocks > mb->dpme_pblocks - mb->dpme_lblock_start) { printed = 1; printf("\tlogical blocks (%ld for %ld) not within physical size (%ld)\n", mb->dpme_lblock_start, mb->dpme_lblocks, mb->dpme_pblocks); } // remember stuff for post processing add_range(&list, mb->dpme_pblock_start, mb->dpme_pblocks, 1); // XXX type is known type? // XXX no unknown flags? // XXX boot blocks either within or outside of logical // XXX checksum matches contents // XXX other fields zero if boot_bytes is zero // XXX processor id is known value? // XXX no data in reserved3 if (printed == 0) { printf("\tokay\n"); } } post_processing: // properties of whole map // every block on disk in one & only one partition coalesce_list(list); print_range_list(list); // there is a partition for the map // map fits within partition that contains it // try to detect 512/2048 mixed partition map? done: if (map == NULL) { close_media(the_media); free(buffer); free(name); } }
/***************************************************************** Start here *****************************************************************/ int main(int np, char **p) { char src_drive[NAME_LENGTH] = "/dev/hda", /* source drive */ dst_drive[NAME_LENGTH] = "/dev/hdb"; /* destination drive */ int help = 0, /* set to true to indicate problem with command line */ ask_for_partitions = 1, /* default is true; set to false if partitions given on command line */ status, /* error return on I/O operations */ i; /* loop index */ static disk_control_block *src_disk,*dst_disk; static off_t lba = 0, /* a sector LBA address usually found as a loop index */ common, /* number of sectors common to source & destination */ diffs = 0, /* count of sectors that don't match */ src_lba, /* address of current sector on source */ dst_lba, /* address of current sector on destination */ byte_diffs = 0, /* count of bytes that differ between src and dst */ match = 0, /* number of matching sectors */ /* zero .. other apply to dst sectors beyond common area */ zero = 0, /* number of zero filled sectors */ sfill = 0, /* number of sectors filled with src fill char */ dfill = 0, /* number of sectors filled with dst fill char */ ofill = 0, /* number of sectors filled with some other fill char */ other = 0; /* number of remaining (unfilled) sectors */ static unsigned long nz, /* number of zero filled bytes in a sector */ nfill; /* number of fill bytes in a sector */ int big_src = 0, /* true if src bigger than dst */ big_dst = 0, /* true if dst bigger than src */ is_diff, boot_track_too = 0; /* include boot track in compare */ int src_status, dst_status; /* I/O error returns */ static unsigned char *src_buff,*dst_buff; /* sector buffers */ static time_t from; /* run start time */ FILE *log; /* log file */ int is_debug = 0, log_diffs = 0; unsigned char src_fill_char, dst_fill_char; /* fill characters */ int fill_char; int src_px,dst_px; /* partition table indices from command line */ off_t src_base, /* LBA address of source partition */ src_n, /* size (number of sectors in) source partition */ dst_base, /* ditto dst */ dst_n; /* range_ptr is used to track a list of ranges. In this case the ranges are disk areas specified in LBA addresses */ range_ptr d_r = create_range_list(), /* common area sectors that don't match */ zf_r = create_range_list(), /* zero filled sectors */ sf_r = create_range_list(), /* sectors with src-fill */ df_r = create_range_list(), /* sectors with dst-fill */ of_r = create_range_list(), /* sectors with some other fill */ o_r = create_range_list(); /* other (unfilled) sectors */ static char comment[NAME_LENGTH] = "", log_name[NAME_LENGTH] = "cmpptlog.txt", access[2] = "a"; /***************************************************************** get start run time and decode command line *****************************************************************/ time(&from); if (np < 8) { printf ("%s: Missing parameters\n",p[0]); print_help(p[0]); return 1; } /***************************************************************** get fill characters from command line *****************************************************************/ sscanf (p[5],"%2x",&fill_char); src_fill_char = fill_char; sscanf (p[7],"%2x",&fill_char); dst_fill_char = fill_char; /***************************************************************** get options from command line *****************************************************************/ for (i = 8; i < np; i++) { if (strcmp (p[i],"-h") == 0) help = 1; /* ask for help */ else if (strcmp (p[i],"-select") == 0) { /* /select src_ix dst_ix */ i = i + 2; if (i >= np) { printf ("%s -select requires two parameters: src partition index\n", p[0]); printf ("and dst partition index\n"); help = 1; } else { sscanf (p[i-1],"%d",&src_px); sscanf (p[i],"%d",&dst_px); ask_for_partitions = 0; /* we got 'em so don't ask */ } } else if (strcmp (p[i],"-new_log")== 0) access[0] = 'w'; else if (strcmp (p[i], "-log_name") == 0) { if(++i >= np) { printf("%s: -log_name option requires a logfile name\n", p[0]); help = 1; } else strncpy(log_name, p[i], NAME_LENGTH - 1); } else if (strcmp (p[i],"-boot")== 0) boot_track_too = 1; else if (strcmp (p[i],"-comment")== 0) { i++; if ( i>=np){ printf ("%s: comment required with -comment\n", p[0]); help = 1; } else strncpy (comment,p[i], NAME_LENGTH - 1); } else { printf("Invalid parameter: %s\n", p[i]); help = 1; } } /***************************************************************** get source and destination drives (in hex) from command line *****************************************************************/ strncpy(src_drive, p[4], NAME_LENGTH - 1); strncpy(dst_drive, p[6], NAME_LENGTH - 1); if (!strcmp(src_drive, dst_drive)) { help = 1; printf ("Source and destination drives must be different\n"); } /***************************************************************** If there is a problem on command line, then print help message *****************************************************************/ if (help) { print_help(p[0]); return 0; } /***************************************************************** Open log file, source disk and destination disk *****************************************************************/ log = log_open (log_name, access, comment, SCCS_ID, np, p); status = setup_disk (src_drive, "Source disk", log, p, ask_for_partitions, src_px, &src_base, &src_n, &src_disk); status = status || setup_disk (dst_drive, "Destination disk", log, p, ask_for_partitions, dst_px, &dst_base, &dst_n, &dst_disk); if (status) return 1; /***************************************************************** get ready to do the compare see which is bigger: src or dst *****************************************************************/ if (src_n != dst_n) { if ( src_n < dst_n) { common = src_n; big_dst = 1; } else { common = dst_n; big_src = 1; } } else common = src_n; printf ("Source disk fill byte %2X\n", src_fill_char); printf ("Destination disk fill byte %2X\n", dst_fill_char); fprintf (log, "Source disk fill byte %2X\n", src_fill_char); fprintf (log, "Destination disk fill byte %2X\n", dst_fill_char); src_lba = src_base; dst_lba = dst_base; if (boot_track_too) { common += 63; src_lba -= 63; dst_lba -= 63; src_base -= 63; dst_base -= 63; src_n += 63; dst_n += 63; } fprintf (log,"Source base sector %llu Destination base sector %llu\n", src_base,dst_base); /***************************************************************** Main compare loop: for each sector in common read src sector read dst sector if match then increment match count else increment different count *****************************************************************/ for (lba = 0; lba < common; lba++) { feedback (from, 0, lba, big_dst ? dst_n : common); /* give progress feedback to user */ is_diff = 0; src_status = read_lba(src_disk, src_lba++, &src_buff); dst_status = read_lba(dst_disk, dst_lba++, &dst_buff); if (src_status || dst_status) { fprintf (log,"read error at sector %llu: src %d dst %d\n", lba, src_status, dst_status); printf ("read error at lba %llu: src %d dst %d\n", lba, src_status, dst_status); return 1; } /***************************************************************** Compare corresponding sectors *****************************************************************/ for (i = 0; i < BYTES_PER_SECTOR; i++) { if (src_buff[i] != dst_buff[i]) { is_diff = 1; byte_diffs++; } } if (is_diff) { diffs++; add_to_range (d_r,lba); if (log_diffs && (diffs <= 50)) { fprintf (log,"%12llu ",lba); if ((diffs%5) == 0) fprintf (log,"\n"); } } else { match++; } } /***************************************************************** Log results for corresponding sectors *****************************************************************/ if (log_diffs && (diffs)) fprintf (log,"\n"); fprintf (log,"Sectors compared: %12llu\n",common); fprintf (log,"Sectors match: %12llu\n",match); fprintf (log,"Sectors differ: %12llu\n",diffs); fprintf (log,"Bytes differ: %12llu\n",byte_diffs); print_range_list(log,"Diffs range: ",d_r); if (big_src) { fprintf (log,"Source (%llu) has %llu more sectors than destination (%llu)\n", src_n, src_n - dst_n, dst_n); } /***************************************************************** If the destination is larger than the source then look at the remainder of the destination *****************************************************************/ else if (big_dst) { fprintf (log,"Source (%llu) has %llu fewer sectors than destination (%llu)\n", src_n, dst_n - src_n, dst_n); zero = 0; ofill = sfill = dfill = 0; other = 0; printf ("Destination larger than source; scanning %llu sectors\n", dst_n-common); for (lba = common; lba < dst_n; is_debug?(lba+=100):lba++){ feedback (from, 0, lba, dst_n); if((dst_status = read_lba(dst_disk, dst_lba++, &dst_buff))) { fprintf (log,"read error at sector %llu: dst %d\n", lba, dst_status); printf ("read error at lba %llu: dst %d\n", lba, dst_status); } nz = 0; nfill = 0; /***************************************************************** classify sector: count zero bytes and fill bytes how to count fill bytes? the rule is: all bytes after byte [23] are the same. i.e., 488 bytes of the sector are the same. We use 480 to give some slack. *****************************************************************/ for (i = 0; i < BYTES_PER_SECTOR; i++) { if ( dst_buff[i] == 0) nz++; else if (dst_buff[i] == dst_buff[BUFF_OFF]) nfill++; } if (nz == BYTES_PER_SECTOR) { zero++; add_to_range(zf_r,lba); } else if (nfill > 480) { if (dst_buff[BUFF_OFF] == src_fill_char) { sfill++; add_to_range(sf_r,lba); } else if (dst_buff[BUFF_OFF] == dst_fill_char) { dfill++; add_to_range(df_r,lba); } else { ofill++; add_to_range(of_r,lba); } } else { other++; add_to_range (o_r,lba); } } /***************************************************************** log results to log file *****************************************************************/ if (log_diffs && (other)) fprintf (log, "\n"); fprintf (log,"Zero fill: %llu\n", zero); fprintf (log,"Src Byte fill (%02X): %llu\n", src_fill_char, sfill); if (src_fill_char == dst_fill_char) fprintf (log, "Dst Fill Byte same as Src Fill Byte\n"); else fprintf (log, "Dst Byte fill (%02X): %lu\n", dst_fill_char, dfill); fprintf (log,"Other fill: %llu\n", ofill); fprintf (log,"Other no fill: %llu\n", other); print_range_list(log,"Zero fill range: ", zf_r); print_range_list(log,"Src fill range: ", sf_r); print_range_list(log,"Dst fill range: ", df_r); print_range_list(log,"Other fill range: ", of_r); print_range_list(log,"Other not filled range: ", o_r); } log_close(log, from); return 0; }
/****************************************************************************** Examine a part of the destination disk that does not correspond to any area on the source disk. This is either (1) the sectors of a destination chunk that do not correspond to the source sectors of the corresponding chunk. or (2) destination chunk of sectors not allocated to a corresponding source chunk. To say this another way, source partitions are compared to destination partitions that are a little larger. Sectors in (1) above are the excess destination sectors. If the source has unallocated (i.e., not in a partition) sectors between two partitions, the area between is treated as a partition. Sectors in (2) are the excess sectors after the last partition on the destination. ******************************************************************************/ void scan_region (FILE *log, /* the log file */ disk_control_ptr dst_disk, /* the destination disk */ off_t common, /* starting sector LBA address */ off_t dst_n, /* number of sectors to scan */ unsigned char src_fill_char, /* the source fill character */ unsigned char dst_fill_char, /* the destination fill character */ time_t start_time, /* time the program started running */ off_t *tz, /* update value: running total of zero fill sectors */ off_t *tnz) /* update value: running total of non-zero sectors */ { range_ptr zf_r = create_range_list(), /* range of zero fill sectors */ sf_r = create_range_list(), /* range of source fill sectors */ df_r = create_range_list(), /* range of destination fill sectors */ of_r = create_range_list(), /* range of other fill sectors */ o_r = create_range_list(); /* range of other sectors */ unsigned char *dst_buff, /* the sector to scan */ other_fill_char = 0; /* last other fill char seen */ int dst_status; /* disk I/O status return */ off_t lba = 0, /* the sector relative to start address */ nz, /* count of zero bytes in a sector */ nfill, /* count of fill bytes in a sector */ dst_lba, /* the absolute lba of sector to examine */ zero = 0, /* number of zero sectors */ sfill = 0, /* number of sectors filled with source byte */ dfill = 0, /* number of sectors filled with dst byte */ ofill = 0, /* number of sectors filled with something else */ other = 0; /* count of other sectors */ int i, /* look index */ other_fill_seen = 0, /* flag indicating fill other than src/dst */ new_fill = 0; printf ("scanning %llu unmatched sectors: %llu--%llu\n",dst_n-common,common,dst_n); fprintf (log,"scanning %llu unmatched sectors: %llu--%llu\n",dst_n-common,common,dst_n); /****************************************************************************** Loop to scan dst_n sectors from common up to common + dst_n ******************************************************************************/ dst_lba = common; for (lba = common; lba < dst_n; lba++) { feedback (start_time,0,dst_lba,n_sectors(dst_disk)); dst_status = read_lba(dst_disk,dst_lba++,&dst_buff); if (dst_status) { fprintf (log,"dst read error 0x%02X on track starting at lba %llu\n",dst_status,dst_lba-1); printf ("dst read error 0x%02X on track starting at lba %llu\n",dst_status,dst_lba-1); exit(1); } nz = 0; nfill = 0; /****************************************************************************** scan the sector, count number of zero bytes and number of fill bytes. To count fill bytes: assume sector is filled (from diskwipe) then ... bytes 1-27 has the sector address and the remaining bytes are the same. so pick byte # 30 and count the number of bytes that match dst_buff[30], if enough match (480) then call it filled. The magic constants 30 and 480 allow some room for diskwipe to be off by a few bytes. ******************************************************************************/ for (i = 0; i < BYTES_PER_SECTOR; i++) { if ( dst_buff[i] == 0) nz++; else if (dst_buff[i] == dst_buff[BUFF_OFF]) nfill++; } if (nz == BYTES_PER_SECTOR) { zero++; add_to_range(zf_r,lba); } /* zero sector */ else if ((nfill > 480) && (dst_buff[BUFF_OFF] != 0x00)) { /* filled sector */ if (dst_buff[BUFF_OFF] == src_fill_char) { /* src fill */ sfill++; add_to_range(sf_r,lba); } else if (dst_buff[BUFF_OFF] == dst_fill_char) { /* dst fill */ dfill++; add_to_range(df_r,lba); } else { /* filled with something other than src or dst!! */ ofill++; add_to_range(of_r,lba); if (other_fill_seen) { if (dst_buff[BUFF_OFF] != other_fill_char) new_fill = 1; } else { /* remember the other fill char */ other_fill_char = dst_buff[BUFF_OFF]; new_fill = 0; } } } else { other++; /* not zero and not filled */ add_to_range (o_r,lba); } } /****************************************************************************** Log results ******************************************************************************/ fprintf (log,"Zero fill: %llu\n",zero); fprintf (log,"Src Byte fill (%02X): %llu\n",src_fill_char,sfill); if (src_fill_char == dst_fill_char ) fprintf (log,"Dst Fill Byte same as Src Fill Byte\n"); else fprintf (log,"Dst Byte fill (%02X): %llu\n",dst_fill_char,dfill); fprintf (log,"Other fill %c(%02X): %llu\n",new_fill?'+':' ', other_fill_char,ofill); fprintf (log,"Other no fill: %llu\n",other); print_range_list (log,"Zero fill range: ",zf_r); print_range_list (log,"Src fill range: ",sf_r); print_range_list (log,"Dst fill range: ",df_r); print_range_list (log,"Other fill range: ",of_r); print_range_list (log,"Other not filled range: ",o_r); /****************************************************************************** Update running totals for summary ******************************************************************************/ *tz = *tz + zero; *tnz = *tnz + sfill + dfill + ofill + other; }
/****************************************************************************** Compare a source chunk to a destination chunk log number of sectors compared, # match, # diff, etc If dst is larger, (almost certain) then run scan_region on excess sectors ******************************************************************************/ int cmp_region (FILE *log, /* the log file */ /* source parameters: disk, chunk description, fill char */ disk_control_ptr src_disk, layout_ptr src, char src_fill, /* destination parameters: disk, chunk description, fill char */ disk_control_ptr dst_disk, layout_ptr dst, char dst_fill, time_t start_time, /* time the program started running (for user feedback) */ totals_ptr t) /* summary totals */ { unsigned char *src_buff, *dst_buff; /* sector read buffers */ int src_status, dst_status; /* disk read status return */ off_t lba = 0, /* index for main loop; relative sector in partition */ common, /* number of sectors with both a src and dst sector */ diffs = 0, /* number of sectors that differ */ src_lba, /* absolute LBA of src sector */ dst_lba, /* absolute LBA of dst sector */ byte_diffs = 0, /* number of bytes that differ */ match = 0; /* number of sectors that match */ int big_src = 0, /* src is bigger than dst */ big_dst = 0, /* dst is bigger than src */ is_diff, /* src and dst do not match */ i; /* loop index */ range_ptr d_r = create_range_list(); /* sectors that do not match */ if (src->n_sectors == dst->n_sectors) common = src->n_sectors; else if (src->n_sectors > dst->n_sectors) { common = dst->n_sectors; big_src = 1; } else { common = src->n_sectors; big_dst = 1; } src_lba = src->lba_start; dst_lba = dst->lba_start; fprintf (log,"Src base %llu Dst base %llu\n", src_lba,dst_lba); for (lba = 0; lba < common;lba++) { /* main loop: scan sectors that correspond */ is_diff = 0; feedback(start_time,0,dst_lba,n_sectors(dst_disk)); src_status = read_lba(src_disk,src_lba++,&src_buff); dst_status = read_lba(dst_disk,dst_lba++,&dst_buff); if (src_status) { fprintf (log,"src read error 0x%02X on track starting at lba %llu\n",src_status,lba); printf ("src read error 0x%02X on track starting at lba %llu\n",src_status,lba); } if (dst_status) { fprintf (log,"dst read error 0x%02X on track starting at lba %llu\n",dst_status,lba); printf ("dst read error 0x%02X on track starting at lba %llu\n",dst_status,lba); } if(src_status || dst_status) return 1; /* scan the sectors; note any diffs */ for (i = 0; i < BYTES_PER_SECTOR; i++) { if (src_buff[i] != dst_buff[i]) { is_diff = 1; byte_diffs++; } } if (is_diff) { /* rats! not a match */ diffs++; add_to_range (d_r,lba); } else { /* the source and dst are the same */ match++; } } /* log results */ fprintf (log,"Sectors compared: %12llu\n",common); fprintf (log,"Sectors match: %12llu\n",match); fprintf (log,"Sectors differ: %12llu\n",diffs); fprintf (log,"Bytes differ: %12llu\n",byte_diffs); print_range_list(log,"Diffs range: ",d_r); if (big_src) { fprintf (log,"Source (%llu) has %llu more sectors than destination (%llu)\n", src->n_sectors,src->n_sectors - dst->n_sectors, dst->n_sectors); } else if (big_dst) { /* dst has more sectors to examine */ fprintf (log,"Source (%llu) has %llu fewer sectors than destination (%llu)\n", src->n_sectors,dst->n_sectors - src->n_sectors, dst->n_sectors); printf ("Source (%llu) has %llu fewer sectors than destination (%llu)\n", src->n_sectors,dst->n_sectors - src->n_sectors, dst->n_sectors); if (dst->chunk_class == CHUNK_UNALLOCATED) /* look at excess sectors in chunk */ scan_region (log, dst_disk,dst_lba,dst->lba_start + dst->n_sectors, src_fill, dst_fill,start_time, &t->excess_zero,&t->excess_non_zero); else scan_region (log, dst_disk,dst_lba,dst->lba_start + dst->n_sectors, src_fill, dst_fill,start_time, &t->fill_zero,&t->fill_non_zero); } /****************************************************************************** Update summary totals ******************************************************************************/ if (dst->chunk_class == CHUNK_PARTITION) { /* partition summary */ t->n_partitions++; t->partition_diffs += diffs; t->n_common += common; } else if (dst->chunk_class == CHUNK_UNALLOCATED) { /* nothing to do for unallocated chunk */ t->n_unalloc++; t->unalloc_diffs += diffs; t->n_common_unalloc += common; } else { /* boot track summary */ t->n_boot_tracks++; t->boot_track_diffs += diffs; } return 0; }
main (int np, char **p) { char src_drive[NAME_LENGTH], dst_drive[NAME_LENGTH]; /* drive devices */ int help = 0, status, i; static disk_control_ptr src_disk, dst_disk; /* disk information */ off_t lba = 0, /* index for looping through disk sectors */ common, /* number of sectors common to source and dst */ diffs = 0, /* number of sectors that do not match */ nz, /* number of zero bytes in current sector */ nfill,/* number of filled bytes in current sector */ src_ns,dst_ns, /* number of sectors on src and dst */ /* counts: sectors that ... */ byte_diffs = 0, match = 0, zero = 0, sfill = 0, dfill = 0, ofill = 0, other = 0; int big_src = 0, big_dst = 0, is_diff, src_status, dst_status; /* read status codes (should be zero) */ static unsigned char *src_buff, *dst_buff; /* current src and dst sector data */ static time_t from; /* program start time */ FILE *log; /* the log file */ int is_debug = 0; unsigned char other_fill_char, src_fill_char, dst_fill_char; /* the fill characters */ int fill_char, other_fill_seen = 0; off_t n_src_err = 0, n_dst_err = 0; /* count of number of read errs */ char comment[NAME_LENGTH] = "", access[2] = "a"; /* the user comment */ char log_name[NAME_LENGTH] = "cmplog.txt"; /* sectors that ... */ range_ptr d_r = create_range_list(), /* ... differ (do not match) */ zf_r = create_range_list(), /* ... zeros filled */ sf_r = create_range_list(),/* ... source filled */ df_r = create_range_list(), /* ... dst filled */ of_r = create_range_list(), /* ... filled with something else */ o_r = create_range_list(); /* ... are not filled */ time(&from); src_disk = dst_disk = NULL; /***************************************************************** Get the command line *****************************************************************/ if (np < 8) { print_help(p[0]); /* not enough parameters */ return 1; } strncpy(src_drive, p[4], NAME_LENGTH - 1); strncpy(dst_drive, p[6], NAME_LENGTH - 1); printf ("Src drive %s dst drive %s\n",src_drive,dst_drive); sscanf (p[5],"%2x",&fill_char); src_fill_char = fill_char; sscanf (p[7],"%2x",&fill_char); dst_fill_char = fill_char; printf ("Src fill 0x%02X dst fill 0x%02X\n",src_fill_char,dst_fill_char); for (i = 8; i < np; i++) { /* optional parameters */ if (strcmp (p[i],"-h") == 0) help = 1; else if (strcmp (p[i],"-debug")== 0) is_debug = 1; else if (strcmp (p[i],"-new_log")== 0) access[0] = 'w'; else if (strcmp (p[i], "-log_name") == 0) { if(++i >= np) { printf("%s: -log_name option requires a logfile name\n", p[0]); help = 1; } else strncpy(log_name, p[i], NAME_LENGTH - 1); } else if (strcmp (p[i],"-comment")== 0) { if (++i >= np) { printf ("%s: comment required with -comment\n", p[0]); help = 1; } else strncpy (comment, p[i], NAME_LENGTH - 1); } else { printf("Invalid parameter: %s\n", p[i]); help = 1; } } if (help) { print_help(p[0]); return 0; } /***************************************************************** Start log file *****************************************************************/ log = log_open(log_name,access,comment,SCCS_ID,np,p); src_disk = open_disk (src_drive,&status); if (status) { printf ("%s could not access src drive %s status code %d\n", p[0],src_drive,status); fprintf (log,"%s could not access src drive %s status code %d\n", p[0],src_drive,status); return 1; } log_disk(log,"Source",src_disk); dst_disk = open_disk (dst_drive,&status); if (status){ printf ("%s could not access dst drive %s status code %d\n", p[0],dst_drive,status); fprintf (log,"%s could not access dst drive %s status code %d\n", p[0],dst_drive,status); return 1; } log_disk(log,"Destination",dst_disk); src_ns = n_sectors(src_disk); dst_ns = n_sectors(dst_disk); if (src_ns != dst_ns){ if ( src_ns < dst_ns){ common = src_ns; big_dst = 1; } else { common = dst_ns; big_src = 1; } } else common = src_ns; /***************************************************************** Main scan loop: read corresponding sectors and compare *****************************************************************/ for (lba = 0; lba < common; is_debug?(lba+=100):lba++){ is_diff = 0; feedback (from,0,lba,big_dst?dst_ns:common); src_status = read_lba(src_disk,lba,&src_buff); dst_status = read_lba(dst_disk,lba,&dst_buff); if (src_status) { /* if bad sectors, keep list of first 10 */ n_src_err++; if (n_src_err < 11) { fprintf (log,"src read error 0x%02X on track starting at lba %llu\n", src_status,lba); printf ("src read error 0x%02X at lba %llu\n",src_status,lba); } else if (n_src_err == 11) { fprintf (log,"... more src read errors\n"); printf ("... more src read errors\n"); } continue; } if (dst_status) { /* if bad sectors, keep list of first 10 */ n_dst_err++; if (n_dst_err < 11) { fprintf (log,"dst read error 0x%02X on track starting at lba %llu\n", dst_status,lba); printf ("dst read error 0x%02X at lba %llu\n",dst_status,lba); } else if (n_dst_err == 11) { fprintf (log,"... more dst read errors\n"); printf ("... more dst read errors\n"); } continue; } for (i = 0; i < BYTES_PER_SECTOR; i++){ /* count bytes different */ if (src_buff[i] != dst_buff[i]){ is_diff = 1; byte_diffs++; } } if (is_diff){/* sectors do not match */ diffs++; add_to_range (d_r,lba); } else { match++; } } /* log results for corresponding sectors */ fprintf (log,"Sectors compared: %8llu\n",common); fprintf (log,"Sectors match: %8llu\n",match); fprintf (log,"Sectors differ: %8llu\n",diffs); if (n_src_err + n_dst_err){ /* note any I/O errors */ fprintf (log, "Sectors skipped: %8llu (due to %llu src & %llu dst I/O errors)\n", n_src_err+n_dst_err,n_src_err,n_dst_err); } fprintf (log,"Bytes differ: %8llu\n",byte_diffs); print_range_list(log,"Diffs range",d_r); if (big_src){ fprintf (log,"Source (%llu) has %llu more sectors than destination (%llu)\n", src_ns,src_ns - dst_ns, dst_ns); } else if (big_dst){ /* examine remainder of a larger destination */ fprintf (log,"Source (%llu) has %llu fewer sectors than destination (%llu)\n", src_ns,dst_ns - src_ns, dst_ns); zero = 0; ofill = sfill = dfill = 0; other = 0; printf ("Destination larger than source; scanning %llu sectors\n", dst_ns-common); for (lba = common; lba < dst_ns; is_debug?(lba+=100):lba++){ feedback (from,0,lba,dst_ns); dst_status = read_lba(dst_disk,lba,&dst_buff); if (dst_status){ n_dst_err++; if (n_dst_err < 11){ fprintf (log,"dst read error 0x%02X on track starting at lba %llu\n", dst_status,lba); printf ("dst read error 0x%02X at lba %llu\n",dst_status,lba); } if (n_dst_err == 11) { fprintf (log,"... more dst read errors\n"); printf ("... more dst read errors\n"); } continue; } nz = 0; nfill = 0; for (i = 0; i < BYTES_PER_SECTOR; i++) { if (dst_buff[i] == 0) nz++; else if (dst_buff[i] == dst_buff[BUFF_OFF]) nfill++; } if (nz == BYTES_PER_SECTOR) {zero++; add_to_range(zf_r,lba);} else if (nfill > 480){ /* filled sector: figure out src, dst or other */ if (dst_buff[BUFF_OFF] == src_fill_char){ sfill++; add_to_range(sf_r,lba); } else if (dst_buff[BUFF_OFF] == dst_fill_char){ dfill++; add_to_range(df_r,lba); } else { ofill++; add_to_range(of_r,lba); other_fill_seen = 1; other_fill_char = dst_buff[BUFF_OFF]; } } else { other++; add_to_range (o_r,lba); } } /* log results of scan of extra dst sectors */ fprintf (log,"Zero fill: %8llu\n",zero); fprintf (log,"Src Byte fill (%02X): %8llu\n",src_fill_char,sfill); if (src_fill_char == dst_fill_char) fprintf (log,"Dst Fill Byte same as Src Fill Byte\n"); else fprintf (log,"Dst Byte fill (%02X): %8llu\n",dst_fill_char,dfill); if (other_fill_seen) fprintf (log,"Other fill (%02X): %8llu\n",other_fill_char,ofill); else fprintf (log,"Other fill: %8llu\n",ofill); fprintf (log,"Other no fill: %8llu\n",other); print_range_list (log,"Zero fill range: ",zf_r); print_range_list (log,"Src fill range: ",sf_r); print_range_list (log,"Dst fill range: ",df_r); print_range_list (log,"Other fill range: ",of_r); print_range_list (log,"Other not filled range: ",o_r); } fprintf (log,"%llu source read errors, %llu destination read errors\n", n_src_err,n_dst_err); log_close(log,from); return 0; }