Example #1
0
/*****************************************************************
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;
}
Example #2
0
/*
 * Intersect the current allocated disk ranges (curranges) with the
 * hashinfo ranges read from the signature file (hfile).
 * Return the resulting range list.
 */
struct range *
hashmap_compute_delta(struct range *curranges, char *hfile, int infd,
		      uint32_t ssect)
{
	uint32_t		gapstart, gapsize, lastdrangeend = 0;
	unsigned int		hashlen;
	unsigned char		*(*hashfunc)(const unsigned char *,
					     size_t, unsigned char *);
	struct range		dummy_head, *range_tail;
	struct hashregion	*hreg, *ereg;
	char			*hashstr;
	struct hashinfo		*hinfo;
	struct range		*drange;
	int			retval, changed, gapcount;
	
	/*
	 * No allocated ranges, that was easy!
	 */
	if (curranges == NULL)
		return NULL;

	/*
	 * First we read the hashfile to get hash ranges and values
	 */
	retval = readhashinfo(hfile, &hinfo, ssect);
	if (retval < 0) {
		fprintf(stderr, "readhashinfo: failed !\n"
			" * * * Aborting * * *\n");
		exit(1);
	}

	/*
	 * Deterimine the hash function
	 */
	switch (hinfo->hashtype) {
	case HASH_TYPE_MD5:
	default:
		hashlen = 16;
		hashfunc = MD5;
		hashstr = "MD5 digest";
		break;
	case HASH_TYPE_SHA1:
		hashlen = 20;
		hashfunc = SHA1;
		hashstr = "SHA1 digest";
		break;
	}

	/*
	 * The new range list.  Use a dummy element as the head and
	 * keep track of the tail for easy appending.  The dummy element
	 * is initialized such that add_to_range() will not coalesce
	 * anything with it and it will remain distinct.
	 */
	dummy_head.start = ~0;
	dummy_head.size = 0;
	dummy_head.next = 0;
	range_tail = &dummy_head;

	/*
	 * Loop through all hash regions, comparing with the currently
	 * allocated disk regions.
	 */
	drange = curranges;
	ereg = hinfo->regions + hinfo->nregions;
	for (hreg = hinfo->regions; hreg < ereg; hreg++) {
		assert(drange && drange->size > 0);
#ifdef FOLLOW
		fprintf(stderr, "H: [%u-%u] start\n",
			hreg->region.start,
			hreg->region.start + hreg->region.size - 1);
		fprintf(stderr, "  D: [%u-%u] start\n",
			drange->start,
			drange->start + drange->size - 1);
#endif

		/*
		 * Any allocated ranges on disk that are before the
		 * hash range are newly allocated, and must be put in the image.
		 */
		while (drange &&
		       (drange->start + drange->size) <= hreg->region.start) {
#ifdef FOLLOW
			fprintf(stderr, "    D: [%u-%u] pre-hreg skip\n",
				drange->start,
				drange->start + drange->size - 1);
#endif
#ifdef HASHSTATS
			hashstats.cur_allocated += drange->size;
			hashstats.cur_only += drange->size;
#endif
			if (add_to_range(&range_tail,
					 drange->start, drange->size) < 0)
				goto error;

			lastdrangeend = drange->start + drange->size;
			drange = drange->next;
			assert(drange == NULL || drange->size > 0);
		}
		if (drange == NULL)
			break;
		assert(hreg->region.start < (drange->start + drange->size));

#ifdef FOLLOW
		fprintf(stderr, "  D: [%u-%u] after pre-hreg skip\n",
			drange->start,
			drange->start + drange->size - 1);
#endif

		/*
		 * Any allocated range in the original image that is below our
		 * first allocated range on the current disk can be ignored.
		 * (The blocks must have been deallocated.)
		 */

		if (hreg->region.start + hreg->region.size <= drange->start) {
#ifdef HASHSTATS
			hashstats.orig_only += hreg->region.size;
#endif
			continue;
		}

		/*
		 * Otherwise there is some overlap between the current drange
		 * and hreg.  To simplfy things, we split drange so that we can
		 * treat the portion of drange before the overlap seperately.
		 * thus aligning with hash boundaries
		 */
		assert(hreg->region.start + hreg->region.size > drange->start);
		assert(hreg->region.start < drange->start + drange->size);

		/*
		 * Any part of the drange that falls before the hreg is
		 * new data and needs to be in the image.
		 */
		if (drange->start < hreg->region.start) {
			uint32_t before = hreg->region.start - drange->start;
#ifdef HASHSTATS
			hashstats.cur_allocated += before;
			hashstats.cur_only += before;
#endif
			if (add_to_range(&range_tail,
					 drange->start, before) < 0)
				goto error;
			
#ifdef FOLLOW
			fprintf(stderr, "  D: [%u-%u]/[%u-%u] drange head split\n",
				drange->start,
				drange->start + before - 1,
				drange->start + before,
				drange->start + drange->size);
#endif
			/*
			 * Update drange with new start and size to account
			 * for the stuff we've taken off.  We continue
			 * processing with this new range.
			 */
			drange->start += before;
			drange->size -= before;
		}

		/*
		 * We have now isolated one or more dranges that are "covered"
		 * by the current hreg.  Here we might use the hash value
		 * associated with the hreg to determine whether the
		 * corresponding disk contents have changed.  If there is a
		 * single drange that exactly matches the hreg, then we
		 * obviously do this.  But what if there are gaps in the
		 * coverage, i.e., multiple non-adjacent dranges covered by
		 * the hreg?  This implies that not all blocks described by
		 * the original hash are still important in the current image.
		 * In fact there could be as little as a single disk block
		 * still valid for a very large hrange.
		 *
		 * In this case we can either blindly include the dranges
		 * in the merged list (hash_free==0), or we can go ahead and
		 * do the hash over the entire range (hash_free==1) on the
		 * chance that the blocks that are no longer allocated (the
		 * "gaps" between dranges) have not changed content and the
		 * hash will still match and thus we can avoid including the
		 * dranges in the merged list.  The latter is valid, but is
		 * it likely to pay off?  We will have to see.
		 */
		if (hash_free ||
		    (drange->start == hreg->region.start &&
		     drange->size >= hreg->region.size)) {

			/*
			 * XXX if there is a fixup, all bets are off
			 * (e.g., they might compare equal now, but not
			 * after the fixup).  Just force inclusion of all
			 * data.
			 *
			 * XXX we could do this on a drange by drange basis
			 * below, but I deem it not worth the trouble since
			 * all this code will be changing anyway.
			 */
			if (hasfixup(hreg->region.start, hreg->region.size)) {
				changed = 3;
#ifdef FOLLOW
				fprintf(stderr, "  H: [%u-%u] fixup overlap\n",
					hreg->region.start,
					hreg->region.start + hreg->region.size-1);
#endif
			} else {
				
				TIMEOP(
				       changed = hash_and_cmp(infd, hashfunc,
							      hashlen, hreg,
							      ereg - hreg),
				       time_hash_and_cmp);
				if (changed < 0)
					goto error;

#ifdef FOLLOW
				fprintf(stderr, "  H: [%u-%u] hash %s\n",
					hreg->region.start,
					hreg->region.start + hreg->region.size-1,
					changed ? "differs" : "matches");
#endif
			}
		} else {
			/*
			 * There is a gap in the dranges covered by the hreg.
			 * Just save all dranges covered by this hreg.
			 */
			changed = 2;
#ifdef FOLLOW
			fprintf(stderr, "  H: [%u-%u] no compare\n",
				hreg->region.start,
				hreg->region.start + hreg->region.size - 1);
#endif
		}

#ifdef HASHSTATS
		hashstats.shared += hreg->region.size;
		if (!changed)
			hashstats.unchanged += hreg->region.size;
		else if (changed > 1) {
			hashstats.nocompare += hreg->region.size;
			if (changed == 3)
				hashstats.fixup += hreg->region.size;
		}
		gapstart = hreg->region.start;
		gapsize = gapcount = 0;
#endif
		/*
		 * Loop through all dranges completely covered by the hreg
		 * and add them or skip them depending on changed.
		 */
		assert(drange &&
		       drange->start < hreg->region.start + hreg->region.size);
		while (drange &&
		       drange->start < hreg->region.start + hreg->region.size) {
			uint32_t curstart = drange->start;
			uint32_t curend = curstart + drange->size;
			uint32_t hregstart = hreg->region.start;
			uint32_t hregend = hregstart + hreg->region.size;

			/*
			 * There may be a final drange which crosses over the
			 * hreg end, in which case we split it, treating the
			 * initial part here, and leaving the rest for the next
			 * iteration.
			 */
			if (curend > hregend) {
				uint32_t after = curend - hregend;
#ifdef FOLLOW
				fprintf(stderr, "    D: [%u-%u]/[%u-%u] drange tail split\n",
					curstart,
					hregend - 1,
					hregend,
					curend - 1);
#endif

				drange->start = hregend;
				drange->size = after;

				curend = hregend;
			}

			assert(curstart >= hregstart);
			assert(curend <= hregend);

#ifdef FOLLOW
			fprintf(stderr, "    D: [%u-%u] drange covered\n",
				curstart,
				curend - 1);
#endif

#ifdef HASHSTATS
			/*
			 * Keep track of the gaps
			 */
			if (gapstart < curstart) {
#ifdef FOLLOW
				fprintf(stderr,
					"    G: [%u-%u]\n",
					gapstart, curstart - 1);
#endif
				gapsize += curstart - gapstart;
				gapcount++;
			}
			gapstart = curend;
			hashstats.cur_allocated += curend - curstart;
#endif
			if (changed) {
				/*
				 * add the overlapping region.
				 */
				if (add_to_range(&range_tail, curstart,
						 curend - curstart) < 0)
					goto error;

			}

			/*
			 * Unless we split the current entry, bump
			 * drange to the next entry.
			 */
			if (curstart == drange->start) {
				lastdrangeend = curend;
				drange = drange->next;
				assert(drange == NULL || drange->size > 0);
			}
		}

#ifdef HASHSTATS
		/*
		 * Check for an end gap
		 */
		if (gapstart < hreg->region.start + hreg->region.size) {
			uint32_t hregend =
				hreg->region.start + hreg->region.size;
#ifdef FOLLOW
			fprintf(stderr, "    G: [%u-%u]\n",
				gapstart, hregend - 1);
#endif
			gapsize += hregend - gapstart;
			gapcount++;
		}

		/*
		 * Properly account for gaps.
		 * Earlier we counted the gap as part of the shared
		 * space and as either unchanged or uncompared--adjust
		 * those counts now.
		 */
		if (gapcount) {
			hashstats.gaps++;

			/* note adjustment of counts set above */
			hashstats.shared -= gapsize;
			hashstats.gapsects += gapsize;
			if (!changed) {
				hashstats.unchanged -= gapsize;
				hashstats.unchangedgaps++;
				hashstats.gapunchanged += gapsize;
			} else if (changed > 1) {
				hashstats.nocompare -= gapsize;
				if (changed == 3)
					hashstats.fixup -= gapsize;
				hashstats.gapnocompare += gapsize;
			}
#ifdef FOLLOW
			fprintf(stderr, "  H: [%u-%u] %d/%d free\n",
				hreg->region.start,
				hreg->region.start + hreg->region.size - 1,
				gapsize, hreg->region.size);
#endif
		}
#endif
		if (drange == NULL)
			break;
		assert(drange->start >= hreg->region.start + hreg->region.size);
	}
	assert(drange == NULL || hreg == ereg);
	assert(lastdrangeend > 0);

	/*
	 * Remaining hash entries are ignored since they are deallocated
	 * space.  We do keep stats about them however.
	 */
#ifdef HASHSTATS
	while (hreg < ereg) {
		uint32_t size;

		/*
		 * If we ran out of dranges in the middle of an hreg,
		 * the rest of the hreg is deallocated.
		 */
		if (lastdrangeend > 0 &&
		    lastdrangeend <= hreg->region.start + hreg->region.size) {
			size = hreg->region.start + hreg->region.size -
				lastdrangeend;
#ifdef FOLLOW
			fprintf(stderr, "H: [%u-%u]/[",
				hreg->region.start,
				lastdrangeend - 1);
			if (size)
				fprintf(stderr, "%u-%u",
					lastdrangeend,
					hreg->region.start +
					hreg->region.size - 1);
			fprintf(stderr, "] split, tail skipped\n");
#endif
		} else {
			size = hreg->region.size;
#ifdef FOLLOW
			fprintf(stderr, "H: [%u-%u] skipped\n",
				hreg->region.start,
				hreg->region.start + hreg->region.size - 1);
#endif
		}
		hashstats.orig_only += size;

		lastdrangeend = 0;
		hreg++;
	}
#endif

	/*
	 * Remaining dranges are added to the changed blocks list.
	 */
	while (drange) {
		assert(hreg == ereg);
#ifdef HASHSTATS
		hashstats.cur_allocated += drange->size;
		hashstats.cur_only += drange->size;
#endif
		if (add_to_range(&range_tail, drange->start, drange->size) < 0)
			goto error;

		drange = drange->next;
		assert(drange == NULL || drange->size > 0);
	}

	return dummy_head.next;

error:
	freeranges(dummy_head.next);
	return NULL;
}
Example #3
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;
}
Example #4
0
/******************************************************************************
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;
}
Example #5
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;
}