Exemple #1
0
/*
 * Wrap up read in a retry mechanism to persist in the face of IO errors,
 * even faking data if requested.
 */
ssize_t
devread(int fd, void *buf, size_t nbytes)
{
	int		cc, i, count;
	off_t		startoffset;

#ifndef linux
	assert((nbytes & (DEV_BSIZE-1)) == 0);
#endif
	if (!forcereads)
		return read(fd, buf, nbytes);

	if ((startoffset = lseek(fd, (off_t) 0, SEEK_CUR)) < 0) {
		perror("devread: seeking to get input file ptr");
		exit(1);
	}

	count = 0;
	for (i = 0; i < IORETRIES; i++) {
		while (nbytes) {
			cc = read(fd, buf, nbytes);
			if (cc == 0)
				break;

			if (cc > 0) {
				nbytes -= cc;
				buf    += cc;
				count  += cc;
				continue;
			}

			if (i == 0) 
				fprintf(stderr, "read failed: %s, "
					"will retry %d more times\n",
					strerror(errno), IORETRIES-1);
	
			nbytes += count;
			buf    -= count;
			count   = 0;
			goto again;
		}
		return count;

	again:
		if (lseek(fd, startoffset, SEEK_SET) < 0) {
			perror("devread: seeking to set file ptr");
			exit(1);
		}
	}

	fprintf(stderr, "devread: read failed in sector range [%u-%u], "
		"returning zeros\n",
		bytestosec(startoffset), bytestosec(startoffset+nbytes));
	memset(buf, 0, nbytes);
	return nbytes;
}
static void
reloc_bsdlabel(struct disklabel *label, int reloctype)
{
	int i, npart;
	uint32_t slicesize;

	/*
	 * This relocation only makes sense in slice mode,
	 * i.e., we are installing a slice image into another slice.
	 */
	if (slice == 0)
		return;

	if (label->d_magic  != DISKMAGIC || label->d_magic2 != DISKMAGIC) {
		fprintf(stderr, "No disklabel at relocation offset\n");
		exit(1);
	}

	assert(outputmaxsize > 0);
	slicesize = bytestosec(outputmaxsize);

	/*
	 * Fixup the partition table.
	 */
	npart = label->d_npartitions;
	for (i = 0; i < npart; i++) {
		uint32_t poffset, psize;

		if (label->d_partitions[i].p_size == 0)
			continue;

		/*
		 * Don't mess with OpenBSD partitions 8-15 which map
		 * extended DOS partitions.  Also leave raw partition
		 * alone as it maps the entire disk (not just slice)
		 * and we don't know how big that is.
		 */
		if (reloctype == RELOC_OBSDDISKLABEL &&
		    (i == 2 || (i >= 8 && i < 16)))
			continue;

		/*
		 * Perform the relocation, making offsets absolute
		 */
		label->d_partitions[i].p_offset += outputminsec;

		poffset = label->d_partitions[i].p_offset;
		psize = label->d_partitions[i].p_size;

		/*
		 * Tweak sizes so BSD doesn't whine:
		 *  - truncate any partitions that exceed the slice size
		 *  - change RAW ('c') partition to match slice size
		 */
		if (poffset + psize > outputmaxsec) {
			fprintf(stderr, "WARNING: partition '%c' "
				"too large for slice, truncating\n", 'a' + i);
			label->d_partitions[i].p_size = outputmaxsec - poffset;
		} else if (i == RAW_PART && psize != slicesize) {
			assert(label->d_partitions[i].p_offset == outputminsec);
			fprintf(stderr, "WARNING: raw partition '%c' "
				"too small for slice, growing\n", 'a' + i);
			label->d_partitions[i].p_size = slicesize;
		}
	}
	label->d_checksum = 0;
	label->d_checksum = dkcksum(label);
}
/*
 * Decompress the chunk, calculating hashes
 */
static void
hashchunk(int chunkno, char *chunkbufp, struct hashinfo **hinfop)
{
	blockhdr_t *blockhdr;
	struct region *regp;
	z_stream z;
	int err, nreg;
	char hash[HASH_MAXSIZE];
	unsigned char *(*hashfunc)(const unsigned char *, unsigned long,
				   unsigned char *);
	readbuf_t *rbuf;
#ifdef TIMEIT
	u_int64_t sstamp, estamp;
#endif

	z.zalloc = Z_NULL;
	z.zfree    = Z_NULL;
	z.opaque   = Z_NULL;
	z.next_in  = Z_NULL;
	z.avail_in = 0;
	z.next_out = Z_NULL;

	err = inflateInit(&z);
	CHECK_ERR(err, "inflateInit");
	
	memset(hash, 0, sizeof hash);

	/*
	 * Grab the header. It is uncompressed, and holds the real
	 * image size and the magic number. Advance the pointer too.
	 */
	blockhdr = (blockhdr_t *)chunkbufp;
	chunkbufp += DEFAULTREGIONSIZE;
	nregions += blockhdr->regioncount;
	z.next_in = chunkbufp;
	z.avail_in = blockhdr->size;
	
	switch (blockhdr->magic) {
	case COMPRESSED_V1:
		regp = (struct region *)((struct blockhdr_V1 *)blockhdr + 1);
		break;

	case COMPRESSED_V2:
		regp = (struct region *)((struct blockhdr_V2 *)blockhdr + 1);
		break;

	default:
		fprintf(stderr, "Bad Magic Number!\n");
		exit(1);
	}

	/*
	 * Deterimine the hash function
	 */
	switch (hashtype) {
	case HASH_TYPE_MD5:
	default:
		hashfunc = MD5;
		break;
	case HASH_TYPE_SHA1:
		hashfunc = SHA1;
		break;
	}

	/*
	 * Loop through all regions, decompressing and hashing data
	 * in HASHBLK_SIZE or smaller blocks.
	 */
	rbuf = alloc_readbuf(0, bytestosec(HASHBLK_SIZE), 0);
	if (rbuf == NULL) {
		fprintf(stderr, "no memory\n");
		exit(1);
	}
	for (nreg = 0; nreg < blockhdr->regioncount; nreg++) {
		uint32_t rstart, rsize, hsize;

		rstart = regp->start;
		rsize = regp->size;
		ndatabytes += sectobytes(rsize);
		while (rsize > 0) {
			if (rsize > bytestosec(HASHBLK_SIZE))
				hsize = bytestosec(HASHBLK_SIZE);
			else
				hsize = rsize;

			z.next_out = rbuf->data;
			z.avail_out = sectobytes(hsize);
#ifdef TIMEIT
			sstamp = rdtsc();
#endif
			err = inflate(&z, Z_SYNC_FLUSH);
#ifdef TIMEIT
			estamp = rdtsc();
			dcycles += (estamp - sstamp);
#endif
			if (err != Z_OK && err != Z_STREAM_END) {
				fprintf(stderr, "inflate failed, err=%d\n",
					err);
				exit(1);
			}

			/*
			 * Make sure we are still in synch
			 */
			if (z.avail_out != 0) {
				fprintf(stderr,
					"inflate failed to fill buf, %d left\n",
					z.avail_out);
				exit(1);
			}
			if (err == Z_STREAM_END && hsize != rsize) {
				fprintf(stderr,
					"inflate ran out of input, %d left\n",
					rsize - hsize);
				exit(1);
			}

			/*
			 * Compute the hash
			 */
			(void)(*hashfunc)(rbuf->data, sectobytes(hsize), hash);
			addhash(hinfop, chunkno, rstart, hsize, hash);

			rstart += hsize;
			rsize -= hsize;
		}
		regp++;
	}
	free_readbuf(rbuf);
	if (z.avail_in != 0) {
		fprintf(stderr,
			"too much input for chunk, %d left\n", z.avail_in);
		exit(1);
	}
}
Exemple #4
0
void
report_hash_stats(int pnum)
{
#ifdef HASHSTATS
	uint32_t b1, b2;
	double t;
	struct stat sb;

	fprintf(stderr,"\nHASH STATS:\n\n");

	fprintf(stderr, "Signature file:         %s ", hashfile);
	sb.st_mtime = 0;
	if (lstat(hashfile, &sb) >= 0 && S_ISLNK(sb.st_mode)) {
		char nbuf[128];
		int i;

		i = readlink(hashfile, nbuf, sizeof(nbuf));
		if (i > 0) {
			nbuf[i] = 0;
			fprintf(stderr, "-> %s ", nbuf);
		}
		stat(hashfile, &sb);
	}
	fprintf(stderr, "(%u)\n", (unsigned)sb.st_mtime);
	fprintf(stderr, "Partition:              %d\n", pnum);

	fprintf(stderr, "Max hash block size:    %u sectors\n\n",
		bytestosec(hashdatasize));
	fprintf(stderr, "Hash incomplete ranges: %d\n", hash_free);

	t = time_curr_read.tv_sec + (double)time_curr_read.tv_usec / 1000000.0;
	fprintf(stderr, "Disk read time:         %7.3f sec\n", t);

	t = time_hash.tv_sec + (double)time_hash.tv_usec / 1000000.0;
	fprintf(stderr, "Hash time:              %7.3f sec\n", t);

	t = time_hash_and_cmp.tv_sec +
		(double)time_hash_and_cmp.tv_usec / 1000000.0;
	fprintf(stderr, "Read+hash time:         %7.3f sec\n\n", t);

	b1 = hashstats.hash_compares;
	b2 = hashstats.hash_identical;
	fprintf(stderr, "Hash blocks compared:   %10u\n",
		b1);
	fprintf(stderr, "  Identical:            %10u (%.1f%%)\n",
		b2, ((double)b2 / b1) * 100.0);

	b1 = hashstats.hash_scompares;
	b2 = hashstats.hash_sidentical;
	fprintf(stderr, "Total sectors compared: %10u\n",
		b1);
	fprintf(stderr, "  Identical:            %10u (%.1f%%)\n\n",
		b2, ((double)b2 / b1) * 100.0);

	b1 = hashstats.orig_allocated;
	fprintf(stderr, "Original sectors:       %10u\n", b1);

	b1 = hashstats.cur_allocated;
	fprintf(stderr, "Current sectors:        %10u\n", b1);

	b1 = hashstats.shared;
	fprintf(stderr, "Common sectors:         %10u\n", b1);

	b1 = hashstats.orig_allocated;
	b2 = hashstats.orig_only + hashstats.gapsects;		
	fprintf(stderr, "Deleted from original:  %10u (%.1f%%)\n",
		b2, ((double)b2 / b1) * 100.0);

	b2 = hashstats.cur_only;
	fprintf(stderr, "Added to original:      %10u (%.1f%%)\n",
		b2, ((double)b2 / b1) * 100.0);

	b2 = (hashstats.shared - hashstats.unchanged);
	fprintf(stderr, "Modified from original: %10u (%.1f%%)\n\n",
		b2, ((double)b2 / b1) * 100.0);

	fprintf(stderr, "Hash blocks covering free sectors:   %u\n",
		hashstats.gaps);
	fprintf(stderr, "  Total free sectors covered:        %u\n",
		hashstats.gapsects);
	fprintf(stderr, "  Hash blocks compared identical:    %u\n",
		hashstats.unchangedgaps);
	fprintf(stderr, "  Free sectors compared identical:   %u\n",
		hashstats.gapunchanged);
	fprintf(stderr, "  Allocated sectors assumed changed: %u\n",
		hashstats.nocompare);
	fprintf(stderr, "    Assumed changed due to fixups:   %u\n",
		hashstats.fixup);

	fprintf(stderr,"\nEND HASH STATS\n");
#endif
}
Exemple #5
0
/*
 * BSD partition table offsets are relative to the start of the raw disk.
 * Very convenient.
 */
static int
read_bsdpartition(int infd, struct disklabel *dlabel, int part)
{
	int		i, cc, rval = 0;
	struct fs	fs;
	union {
		struct cg cg;
		char pad[MAXBSIZE];
	} cg;
	u_int32_t	size, offset, fssect;
	int32_t		sbfree;

	offset = dlabel->d_partitions[part].p_offset;
	size   = dlabel->d_partitions[part].p_size;
	
	if (dlabel->d_partitions[part].p_fstype == FS_SWAP) {
		addskip(offset, size);
		return 0;
	}

	if (dlabel->d_partitions[part].p_fstype != FS_BSDFFS) {
		warnx("BSD Partition '%c': Not a BSD Filesystem",
		      BSDPARTNAME(part));
		return 1;
	}

	if (read_bsdsblock(infd, offset, part, &fs))
		return 1;

	sbfree = (fs.fs_cstotal.cs_nbfree * fs.fs_frag) +
		fs.fs_cstotal.cs_nffree;

	if (debug) {
		fprintf(stderr, "        bfree %9lld, bsize %9d, cgsize %9d\n",
			(long long)fs.fs_cstotal.cs_nbfree,
			fs.fs_bsize, fs.fs_cgsize);
	}
	assert(fs.fs_cgsize <= MAXBSIZE);
	assert((fs.fs_cgsize % secsize) == 0);

	/*
	 * See if the filesystem is smaller than the containing partition.
	 * If so, and we are skipping such space, inform the user.
	 */
	fssect = bytestosec(fs.fs_fsize * (off_t)fs.fs_size);
	if (excludenonfs && fssect < size) {
		warnx("BSD Partition '%c': filesystem smaller than partition, "
		      "excluding [%u-%u]",
		      BSDPARTNAME(part), offset+fssect, offset+size-1);
		addskip(offset + fssect, size - fssect);
	}

	freecount = 0;
	for (i = 0; i < fs.fs_ncg; i++) {
		unsigned long	cgoff;

		cgoff = fsbtodb(&fs, cgtod(&fs, i)) + offset;

		if (devlseek(infd, sectobytes(cgoff), SEEK_SET) < 0) {
			warn("BSD Partition '%c': "
			     "Could not seek to cg %d at %lld",
			     BSDPARTNAME(part), i,
			     (long long)sectobytes(cgoff));
			return 1;
		}
		if ((cc = devread(infd, &cg, fs.fs_cgsize)) < 0) {
			warn("BSD Partition '%c': Could not read cg %d",
			     BSDPARTNAME(part), i);
			return 1;
		}
		if (cc != fs.fs_cgsize) {
			warn("BSD Partition '%c': Truncated cg %d",
			     BSDPARTNAME(part), i);
			return 1;
		}
		if (debug > 1) {
			fprintf(stderr,
				"        CG%d\t offset %9ld, bfree %6d\n",
				i, cgoff, cg.cg.cg_cs.cs_nbfree);
		}
		
		rval = read_bsdcg(&fs, &cg.cg, i, offset);
		if (rval)
			return rval;
	}

	if (rval == 0 && freecount != sbfree) {
		warnx("BSD Partition '%c': "
		      "computed free count (%d) != expected free count (%d)",
		      BSDPARTNAME(part), freecount, sbfree);
	}

	return rval;
}