svn commit: r269177 - stable/10/usr.bin/mkimg

Marcel Moolenaar marcel at FreeBSD.org
Mon Jul 28 02:07:19 UTC 2014


Author: marcel
Date: Mon Jul 28 02:07:16 2014
New Revision: 269177
URL: http://svnweb.freebsd.org/changeset/base/269177

Log:
  MFC r268236,268264,268524,268646,268802,269021:
  This brings VHD support to mkimg(1); both dynamic and fixed file formats.
  Dynamic VHD and VMDK file images are now sparsely written, meaning that
  "free" sectors do not occupy space.
  
  Relnotes: yes

Added:
  stable/10/usr.bin/mkimg/vhd.c
     - copied, changed from r268236, head/usr.bin/mkimg/vhd.c
Modified:
  stable/10/usr.bin/mkimg/Makefile
  stable/10/usr.bin/mkimg/apm.c
  stable/10/usr.bin/mkimg/gpt.c
  stable/10/usr.bin/mkimg/image.c
  stable/10/usr.bin/mkimg/image.h
  stable/10/usr.bin/mkimg/mkimg.1
  stable/10/usr.bin/mkimg/mkimg.c
  stable/10/usr.bin/mkimg/mkimg.h
  stable/10/usr.bin/mkimg/raw.c
  stable/10/usr.bin/mkimg/vmdk.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/usr.bin/mkimg/Makefile
==============================================================================
--- stable/10/usr.bin/mkimg/Makefile	Mon Jul 28 01:25:49 2014	(r269176)
+++ stable/10/usr.bin/mkimg/Makefile	Mon Jul 28 02:07:16 2014	(r269177)
@@ -9,6 +9,7 @@ CFLAGS+=-DSPARSE_WRITE
 # List of formats to support
 SRCS+= \
 	raw.c \
+	vhd.c \
 	vmdk.c
 
 # List of schemes to support

Modified: stable/10/usr.bin/mkimg/apm.c
==============================================================================
--- stable/10/usr.bin/mkimg/apm.c	Mon Jul 28 01:25:49 2014	(r269176)
+++ stable/10/usr.bin/mkimg/apm.c	Mon Jul 28 02:07:16 2014	(r269177)
@@ -39,6 +39,9 @@ __FBSDID("$FreeBSD$");
 #include "mkimg.h"
 #include "scheme.h"
 
+#ifndef APM_ENT_TYPE_APPLE_BOOT
+#define	APM_ENT_TYPE_APPLE_BOOT		"Apple_Bootstrap"
+#endif
 #ifndef APM_ENT_TYPE_FREEBSD_NANDFS
 #define	APM_ENT_TYPE_FREEBSD_NANDFS	"FreeBSD-nandfs"
 #endif

Modified: stable/10/usr.bin/mkimg/gpt.c
==============================================================================
--- stable/10/usr.bin/mkimg/gpt.c	Mon Jul 28 01:25:49 2014	(r269176)
+++ stable/10/usr.bin/mkimg/gpt.c	Mon Jul 28 02:07:16 2014	(r269177)
@@ -211,7 +211,7 @@ gpt_mktbl(u_int tblsz)
 	STAILQ_FOREACH(part, &partlist, link) {
 		ent = tbl + part->index;
 		gpt_uuid_enc(&ent->ent_type, ALIAS_TYPE2PTR(part->type));
-		uuidgen(&uuid, 1);
+		mkimg_uuid(&uuid);
 		gpt_uuid_enc(&ent->ent_uuid, &uuid);
 		le64enc(&ent->ent_lba_start, part->block);
 		le64enc(&ent->ent_lba_end, part->block + part->size - 1);
@@ -279,7 +279,7 @@ gpt_write(lba_t imgsz, void *bootcode)
 	le32enc(&hdr->hdr_size, offsetof(struct gpt_hdr, padding));
 	le64enc(&hdr->hdr_lba_start, 2 + tblsz);
 	le64enc(&hdr->hdr_lba_end, imgsz - tblsz - 2);
-	uuidgen(&uuid, 1);
+	mkimg_uuid(&uuid);
 	gpt_uuid_enc(&hdr->hdr_uuid, &uuid);
 	le32enc(&hdr->hdr_entries, nparts);
 	le32enc(&hdr->hdr_entsz, sizeof(struct gpt_ent));

Modified: stable/10/usr.bin/mkimg/image.c
==============================================================================
--- stable/10/usr.bin/mkimg/image.c	Mon Jul 28 01:25:49 2014	(r269176)
+++ stable/10/usr.bin/mkimg/image.c	Mon Jul 28 02:07:16 2014	(r269177)
@@ -94,21 +94,49 @@ image_copyin(lba_t blk, int fd, uint64_t
 int
 image_copyout(int fd)
 {
+	int error;
+
+	error = image_copyout_region(fd, 0, image_size);
+	if (!error)
+		error = image_copyout_done(fd);
+	return (error);
+}
+
+int
+image_copyout_done(int fd)
+{
+	off_t ofs;
+	int error;
+
+	ofs = lseek(fd, 0L, SEEK_CUR);
+	if (ofs == -1)
+		return (0);
+	error = (ftruncate(fd, ofs) == -1) ? errno : 0;
+	return (error);
+}
+
+int
+image_copyout_region(int fd, lba_t blk, lba_t size)
+{
 	char *buffer;
 	off_t ofs;
+	size_t sz;
 	ssize_t rdsz, wrsz;
 	int error;
 
 	ofs = lseek(fd, 0L, SEEK_CUR);
 
-	if (lseek(image_fd, 0, SEEK_SET) != 0)
+	blk *= secsz;
+	if (lseek(image_fd, blk, SEEK_SET) != blk)
 		return (errno);
 	buffer = malloc(BUFFER_SIZE);
 	if (buffer == NULL)
 		return (errno);
 	error = 0;
-	while (1) {
-		rdsz = read(image_fd, buffer, BUFFER_SIZE);
+	size *= secsz;
+	while (size > 0) {
+		sz = (BUFFER_SIZE < size) ? BUFFER_SIZE : size;
+		rdsz = read(image_fd, buffer, sz);
 		if (rdsz <= 0) {
 			error = (rdsz < 0) ? errno : 0;
 			break;
@@ -120,17 +148,40 @@ image_copyout(int fd)
 			error = errno;
 			break;
 		}
+		assert(wrsz == rdsz);
+		size -= rdsz;
 	}
 	free(buffer);
-	if (error)
-		return (error);
-	ofs = lseek(fd, 0L, SEEK_CUR);
-	if (ofs == -1)
-		return (errno);
-	error = (ftruncate(fd, ofs) == -1) ? errno : 0;
 	return (error);
 }
 
+int
+image_data(lba_t blk, lba_t size)
+{
+	char *buffer, *p;
+
+	blk *= secsz;
+	if (lseek(image_fd, blk, SEEK_SET) != blk)
+		return (1);
+
+	size *= secsz;
+	buffer = malloc(size);
+	if (buffer == NULL)
+		return (1);
+
+	if (read(image_fd, buffer, size) != (ssize_t)size) {
+		free(buffer);
+		return (1);
+	}
+
+	p = buffer;
+	while (size > 0 && *p == '\0')
+		size--, p++;
+
+	free(buffer);
+	return ((size == 0) ? 0 : 1);
+}
+
 lba_t
 image_get_size(void)
 {

Modified: stable/10/usr.bin/mkimg/image.h
==============================================================================
--- stable/10/usr.bin/mkimg/image.h	Mon Jul 28 01:25:49 2014	(r269176)
+++ stable/10/usr.bin/mkimg/image.h	Mon Jul 28 02:07:16 2014	(r269177)
@@ -33,6 +33,9 @@ typedef int64_t lba_t;
 
 int image_copyin(lba_t blk, int fd, uint64_t *sizep);
 int image_copyout(int fd);
+int image_copyout_done(int fd);
+int image_copyout_region(int fd, lba_t blk, lba_t size);
+int image_data(lba_t blk, lba_t size);
 lba_t image_get_size(void);
 int image_init(void);
 int image_set_size(lba_t blk);

Modified: stable/10/usr.bin/mkimg/mkimg.1
==============================================================================
--- stable/10/usr.bin/mkimg/mkimg.1	Mon Jul 28 01:25:49 2014	(r269176)
+++ stable/10/usr.bin/mkimg/mkimg.1	Mon Jul 28 02:07:16 2014	(r269177)
@@ -24,12 +24,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd July 2, 2014
+.Dd July 4, 2014
 .Dt MKIMG 1
 .Os
 .Sh NAME
 .Nm mkimg
-.Nd "utility to make a disk image"
+.Nd "utility to make disk images"
 .Sh SYNOPSIS
 .Nm
 .Op Fl H Ar heads
@@ -40,6 +40,7 @@
 .Op Fl f Ar format
 .Op Fl o Ar outfile
 .Op Fl v
+.Op Fl y
 .Fl s Ar scheme
 .Fl p Ar partition
 .Op Fl p Ar partition ...
@@ -111,6 +112,16 @@ option increases the level of output tha
 .Nm
 utility prints.
 .Pp
+The
+.Op Fl y
+option is used for testing purposes only and is not to be used in production.
+When present, the
+.Nm
+utility will generate predictable values for Universally Unique Identifiers
+(UUIDs) and time stamps so that consecutive runs of the
+.Nm
+utility will create images that are identical.
+.Pp
 For a complete list of supported partitioning schemes or supported output
 format, or for a detailed description of how to specify partitions, run the
 .Nm

Modified: stable/10/usr.bin/mkimg/mkimg.c
==============================================================================
--- stable/10/usr.bin/mkimg/mkimg.c	Mon Jul 28 01:25:49 2014	(r269176)
+++ stable/10/usr.bin/mkimg/mkimg.c	Mon Jul 28 02:07:16 2014	(r269177)
@@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/queue.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/uuid.h>
 #include <errno.h>
 #include <err.h>
 #include <fcntl.h>
@@ -50,6 +51,7 @@ __FBSDID("$FreeBSD$");
 struct partlisthead partlist = STAILQ_HEAD_INITIALIZER(partlist);
 u_int nparts = 0;
 
+u_int unit_testing;
 u_int verbose;
 
 u_int ncyls = 0;
@@ -73,6 +75,8 @@ usage(const char *why)
 	fprintf(stderr, "\t-o <file>\t-  file to write image into\n");
 	fprintf(stderr, "\t-p <partition>\n");
 	fprintf(stderr, "\t-s <scheme>\n");
+	fprintf(stderr, "\t-v\t\t-  increase verbosity\n");
+	fprintf(stderr, "\t-y\t\t-  [developers] enable unit test\n");
 	fprintf(stderr, "\t-H <num>\t-  number of heads to simulate\n");
 	fprintf(stderr, "\t-P <num>\t-  physical sector size\n");
 	fprintf(stderr, "\t-S <num>\t-  logical sector size\n");
@@ -258,6 +262,22 @@ sparse_write(int fd, const void *ptr, si
 }
 #endif /* SPARSE_WRITE */
 
+void
+mkimg_uuid(struct uuid *uuid)
+{
+	static uint8_t gen[sizeof(struct uuid)];
+	u_int i;
+
+	if (!unit_testing) {
+		uuidgen(uuid, 1);
+		return;
+	}
+
+	for (i = 0; i < sizeof(gen); i++)
+		gen[i]++;
+	memcpy(uuid, gen, sizeof(uuid_t));
+}
+
 static void
 mkimg(void)
 {
@@ -337,7 +357,7 @@ main(int argc, char *argv[])
 
 	bcfd = -1;
 	outfd = 1;	/* Write to stdout by default */
-	while ((c = getopt(argc, argv, "b:f:o:p:s:vH:P:S:T:")) != -1) {
+	while ((c = getopt(argc, argv, "b:f:o:p:s:vyH:P:S:T:")) != -1) {
 		switch (c) {
 		case 'b':	/* BOOT CODE */
 			if (bcfd != -1)
@@ -373,6 +393,9 @@ main(int argc, char *argv[])
 			if (error)
 				errc(EX_DATAERR, error, "scheme");
 			break;
+		case 'y':
+			unit_testing++;
+			break;
 		case 'v':
 			verbose++;
 			break;

Modified: stable/10/usr.bin/mkimg/mkimg.h
==============================================================================
--- stable/10/usr.bin/mkimg/mkimg.h	Mon Jul 28 01:25:49 2014	(r269176)
+++ stable/10/usr.bin/mkimg/mkimg.h	Mon Jul 28 02:07:16 2014	(r269177)
@@ -50,6 +50,7 @@ struct part {
 extern STAILQ_HEAD(partlisthead, part) partlist;
 extern u_int nparts;
 
+extern u_int unit_testing;
 extern u_int verbose;
 
 extern u_int ncyls;
@@ -71,4 +72,7 @@ round_block(lba_t n)
 ssize_t sparse_write(int, const void *, size_t);
 #endif
 
+struct uuid;
+void mkimg_uuid(struct uuid *);
+
 #endif /* _MKIMG_MKIMG_H_ */

Modified: stable/10/usr.bin/mkimg/raw.c
==============================================================================
--- stable/10/usr.bin/mkimg/raw.c	Mon Jul 28 01:25:49 2014	(r269176)
+++ stable/10/usr.bin/mkimg/raw.c	Mon Jul 28 02:07:16 2014	(r269177)
@@ -28,7 +28,6 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
-#include <sys/apm.h>
 #include <sys/endian.h>
 #include <sys/errno.h>
 #include <stdlib.h>

Copied and modified: stable/10/usr.bin/mkimg/vhd.c (from r268236, head/usr.bin/mkimg/vhd.c)
==============================================================================
--- head/usr.bin/mkimg/vhd.c	Thu Jul  3 20:31:43 2014	(r268236, copy source)
+++ stable/10/usr.bin/mkimg/vhd.c	Mon Jul 28 02:07:16 2014	(r269177)
@@ -40,16 +40,23 @@ __FBSDID("$FreeBSD$");
 #include "format.h"
 #include "mkimg.h"
 
+#ifndef __has_extension
+#define	__has_extension(x)	0
+#endif
+
 /*
- * Notes:
+ * General notes:
  * o   File is in network byte order.
- * o   File layout:
- *	copy of disk footer
- *	dynamic disk header
- *	block allocation table (BAT)
- *	data blocks
- *	disk footer
  * o   The timestamp is seconds since 1/1/2000 12:00:00 AM UTC
+ *
+ * This file is divided in 3 parts:
+ * 1.  Common definitions
+ * 2.  Dynamic VHD support
+ * 3.  Fixed VHD support
+ */
+
+/*
+ * PART 1: Common definitions
  */
 
 #define	VHD_SECTOR_SIZE	512
@@ -85,43 +92,10 @@ struct vhd_footer {
 	uint8_t		saved_state;
 	uint8_t		_reserved[427];
 };
+#if __has_extension(c_static_assert)
 _Static_assert(sizeof(struct vhd_footer) == VHD_SECTOR_SIZE,
     "Wrong size for footer");
-
-struct vhd_dyn_header {
-	uint64_t	cookie;
-#define	VHD_HEADER_COOKIE	0x6378737061727365
-	uint64_t	data_offset;
-	uint64_t	table_offset;
-	uint32_t	version;
-	uint32_t	max_entries;
-	uint32_t	block_size;
-	uint32_t	checksum;
-	uuid_t		parent_id;
-	uint32_t	parent_timestamp;
-	char		_reserved1[4];
-	uint16_t	parent_name[256];	/* UTF-16 */
-	struct {
-		uint32_t	code;
-		uint32_t	data_space;
-		uint32_t	data_length;
-		uint32_t	_reserved;
-		uint64_t	data_offset;
-	} parent_locator[8];
-	char		_reserved2[256];
-};
-_Static_assert(sizeof(struct vhd_dyn_header) == VHD_SECTOR_SIZE * 2,
-    "Wrong size for header");
-
-static int
-vhd_resize(lba_t imgsz)
-{
-	uint64_t imagesz;
-
-	imagesz = imgsz * secsz;
-	imagesz = (imagesz + VHD_BLOCK_SIZE - 1) & ~(VHD_BLOCK_SIZE - 1);
-	return (image_set_size(imagesz / secsz));
-}
+#endif
 
 static uint32_t
 vhd_checksum(void *buf, size_t sz)
@@ -136,36 +110,8 @@ vhd_checksum(void *buf, size_t sz)
 	return (~sum);
 }
 
-static uint32_t
-vhd_timestamp(void)
-{
-	time_t t;
-
-	if (!unit_testing) {
-		t = time(NULL);
-		return (t - 0x386d4380);
-	}
-
-	return (0x01234567);
-}
-
-static void
-vhd_uuid_enc(void *buf, const uuid_t *uuid)
-{
-	uint8_t *p = buf;
-	int i;
-
-	be32enc(p, uuid->time_low);
-	be16enc(p + 4, uuid->time_mid);
-	be16enc(p + 6, uuid->time_hi_and_version);
-	p[8] = uuid->clock_seq_hi_and_reserved;
-	p[9] = uuid->clock_seq_low;
-	for (i = 0; i < _UUID_NODE_LEN; i++)
-		p[10 + i] = uuid->node[i];
-}
-
 static void
-vhd_geometry(struct vhd_footer *footer)
+vhd_geometry(struct vhd_footer *footer, uint64_t image_size)
 {
 	lba_t imgsz;
 	long cth;
@@ -180,7 +126,7 @@ vhd_geometry(struct vhd_footer *footer)
 		return;
 	}
 
-	imgsz = (image_get_size() * secsz) / VHD_SECTOR_SIZE;
+	imgsz = image_size / VHD_SECTOR_SIZE;
 	if (imgsz > 65536 * 16 * 255)
 		imgsz = 65536 * 16 * 255;
 	if (imgsz >= 65535 * 16 * 63) {
@@ -207,14 +153,121 @@ vhd_geometry(struct vhd_footer *footer)
 	be16enc(&footer->cylinders, cth / footer->heads);
 }
 
+static uint32_t
+vhd_timestamp(void)
+{
+	time_t t;
+
+	if (!unit_testing) {
+		t = time(NULL);
+		return (t - 0x386d4380);
+	}
+
+	return (0x01234567);
+}
+
+static void
+vhd_uuid_enc(void *buf, const uuid_t *uuid)
+{
+	uint8_t *p = buf;
+	int i;
+
+	be32enc(p, uuid->time_low);
+	be16enc(p + 4, uuid->time_mid);
+	be16enc(p + 6, uuid->time_hi_and_version);
+	p[8] = uuid->clock_seq_hi_and_reserved;
+	p[9] = uuid->clock_seq_low;
+	for (i = 0; i < _UUID_NODE_LEN; i++)
+		p[10 + i] = uuid->node[i];
+}
+
+static void
+vhd_make_footer(struct vhd_footer *footer, uint64_t image_size,
+    uint32_t disk_type, uint64_t data_offset)
+{
+	uuid_t id;
+
+	memset(footer, 0, sizeof(*footer));
+	be64enc(&footer->cookie, VHD_FOOTER_COOKIE);
+	be32enc(&footer->features, VHD_FEATURES_RESERVED);
+	be32enc(&footer->version, VHD_VERSION);
+	be64enc(&footer->data_offset, data_offset);
+	be32enc(&footer->timestamp, vhd_timestamp());
+	be32enc(&footer->creator_tool, VHD_CREATOR_TOOL);
+	be32enc(&footer->creator_version, VHD_CREATOR_VERSION);
+	be32enc(&footer->creator_os, VHD_CREATOR_OS);
+	be64enc(&footer->original_size, image_size);
+	be64enc(&footer->current_size, image_size);
+	vhd_geometry(footer, image_size);
+	be32enc(&footer->disk_type, disk_type);
+	mkimg_uuid(&id);
+	vhd_uuid_enc(&footer->id, &id);
+	be32enc(&footer->checksum, vhd_checksum(footer, sizeof(*footer)));
+}
+
+/*
+ * We round the image size to 2MB for both the dynamic and
+ * fixed VHD formats. For dynamic VHD, this is needed to
+ * have the image size be a multiple of the grain size. For
+ * fixed VHD this is not really needed, but makes sure that
+ * it's easy to convert from fixed VHD to dynamic VHD.
+ */
 static int
-vhd_write(int fd)
+vhd_resize(lba_t imgsz)
+{
+	uint64_t imagesz;
+
+	imagesz = imgsz * secsz;
+	imagesz = (imagesz + VHD_BLOCK_SIZE - 1) & ~(VHD_BLOCK_SIZE - 1);
+	return (image_set_size(imagesz / secsz));
+}
+
+/*
+ * PART 2: Dynamic VHD support
+ *
+ * Notes:
+ * o   File layout:
+ *	copy of disk footer
+ *	dynamic disk header
+ *	block allocation table (BAT)
+ *	data blocks
+ *	disk footer
+ */
+
+struct vhd_dyn_header {
+	uint64_t	cookie;
+#define	VHD_HEADER_COOKIE	0x6378737061727365
+	uint64_t	data_offset;
+	uint64_t	table_offset;
+	uint32_t	version;
+	uint32_t	max_entries;
+	uint32_t	block_size;
+	uint32_t	checksum;
+	uuid_t		parent_id;
+	uint32_t	parent_timestamp;
+	char		_reserved1[4];
+	uint16_t	parent_name[256];	/* UTF-16 */
+	struct {
+		uint32_t	code;
+		uint32_t	data_space;
+		uint32_t	data_length;
+		uint32_t	_reserved;
+		uint64_t	data_offset;
+	} parent_locator[8];
+	char		_reserved2[256];
+};
+#if __has_extension(c_static_assert)
+_Static_assert(sizeof(struct vhd_dyn_header) == VHD_SECTOR_SIZE * 2,
+    "Wrong size for header");
+#endif
+
+static int
+vhd_dyn_write(int fd)
 {
 	struct vhd_footer footer;
 	struct vhd_dyn_header header;
-	uuid_t id;
 	uint64_t imgsz;
-	lba_t blk, nblks;
+	lba_t blk, blkcnt, nblks;
 	uint32_t *bat;
 	void *bitmap;
 	size_t batsz;
@@ -224,22 +277,7 @@ vhd_write(int fd)
 	imgsz = image_get_size() * secsz;
 	bat_entries = imgsz / VHD_BLOCK_SIZE;
 
-	memset(&footer, 0, sizeof(footer));
-	be64enc(&footer.cookie, VHD_FOOTER_COOKIE);
-	be32enc(&footer.features, VHD_FEATURES_RESERVED);
-	be32enc(&footer.version, VHD_VERSION);
-	be64enc(&footer.data_offset, sizeof(footer));
-	be32enc(&footer.timestamp, vhd_timestamp());
-	be32enc(&footer.creator_tool, VHD_CREATOR_TOOL);
-	be32enc(&footer.creator_version, VHD_CREATOR_VERSION);
-	be32enc(&footer.creator_os, VHD_CREATOR_OS);
-	be64enc(&footer.original_size, imgsz);
-	be64enc(&footer.current_size, imgsz);
-	vhd_geometry(&footer);
-	be32enc(&footer.disk_type, VHD_DISK_TYPE_DYNAMIC);
-	mkimg_uuid(&id);
-	vhd_uuid_enc(&footer.id, &id);
-	be32enc(&footer.checksum, vhd_checksum(&footer, sizeof(footer)));
+	vhd_make_footer(&footer, imgsz, VHD_DISK_TYPE_DYNAMIC, sizeof(footer));
 	if (sparse_write(fd, &footer, sizeof(footer)) < 0)
 		return (errno);
 
@@ -260,10 +298,14 @@ vhd_write(int fd)
 	if (bat == NULL)
 		return (errno);
 	memset(bat, 0xff, batsz);
+	blkcnt = VHD_BLOCK_SIZE / secsz;
 	sector = (sizeof(footer) + sizeof(header) + batsz) / VHD_SECTOR_SIZE;
 	for (entry = 0; entry < bat_entries; entry++) {
-		be32enc(&bat[entry], sector);
-		sector += (VHD_BLOCK_SIZE / VHD_SECTOR_SIZE) + 1;
+		blk = entry * blkcnt;
+		if (image_data(blk, blkcnt)) {
+			be32enc(&bat[entry], sector);
+			sector += (VHD_BLOCK_SIZE / VHD_SECTOR_SIZE) + 1;
+		}
 	}
 	if (sparse_write(fd, bat, batsz) < 0) {
 		free(bat);
@@ -277,16 +319,21 @@ vhd_write(int fd)
 	memset(bitmap, 0xff, VHD_SECTOR_SIZE);
 
 	blk = 0;
+	blkcnt = VHD_BLOCK_SIZE / secsz;
 	nblks = image_get_size();
 	while (blk < nblks) {
+		if (!image_data(blk, blkcnt)) {
+			blk += blkcnt;
+			continue;
+		}
 		if (sparse_write(fd, bitmap, VHD_SECTOR_SIZE) < 0) {
 			error = errno;
 			break;
 		}
-		error = image_copyout_region(fd, blk, VHD_BLOCK_SIZE / secsz);
+		error = image_copyout_region(fd, blk, blkcnt);
 		if (error)
 			break;
-		blk += VHD_BLOCK_SIZE / secsz;
+		blk += blkcnt;
 	}
 	free(bitmap);
 	if (blk != nblks)
@@ -298,11 +345,41 @@ vhd_write(int fd)
 	return (0);
 }
 
-static struct mkimg_format vhd_format = {
+static struct mkimg_format vhd_dyn_format = {
 	.name = "vhd",
 	.description = "Virtual Hard Disk",
 	.resize = vhd_resize,
-	.write = vhd_write,
+	.write = vhd_dyn_write,
+};
+
+FORMAT_DEFINE(vhd_dyn_format);
+
+/*
+ * PART 2: Fixed VHD
+ */
+
+static int
+vhd_fix_write(int fd)
+{
+	struct vhd_footer footer;
+	uint64_t imgsz;
+	int error;
+
+	error = image_copyout(fd);
+	if (!error) {
+		imgsz = image_get_size() * secsz;
+		vhd_make_footer(&footer, imgsz, VHD_DISK_TYPE_FIXED, ~0ULL);
+		if (sparse_write(fd, &footer, sizeof(footer)) < 0)
+			error = errno;
+	}
+	return (error);
+}
+
+static struct mkimg_format vhd_fix_format = {
+        .name = "vhdf",
+        .description = "Fixed Virtual Hard Disk",
+        .resize = vhd_resize,
+        .write = vhd_fix_write,
 };
 
-FORMAT_DEFINE(vhd_format);
+FORMAT_DEFINE(vhd_fix_format);

Modified: stable/10/usr.bin/mkimg/vmdk.c
==============================================================================
--- stable/10/usr.bin/mkimg/vmdk.c	Mon Jul 28 01:25:49 2014	(r269176)
+++ stable/10/usr.bin/mkimg/vmdk.c	Mon Jul 28 02:07:16 2014	(r269177)
@@ -28,7 +28,6 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
-#include <sys/apm.h>
 #include <sys/endian.h>
 #include <sys/errno.h>
 #include <stdint.h>
@@ -115,8 +114,9 @@ vmdk_write(int fd)
 	char *buf, *desc;
 	off_t cur, lim;
 	uint64_t imagesz;
+	lba_t blkofs, blkcnt;
 	size_t gdsz, gtsz;
-	uint32_t sec;
+	uint32_t sec, cursec;
 	int error, desc_len, n, ngrains, ngts;
 
 	imagesz = (image_get_size() * secsz) / VMDK_SECTOR_SIZE;
@@ -179,8 +179,15 @@ vmdk_write(int fd)
 		return (ENOMEM);
 	}
 
-	for (n = 0; n < ngrains; n++)
-		le32enc(gt + n, sec + n * grainsz);
+	cursec = sec;
+	blkcnt = (grainsz * VMDK_SECTOR_SIZE) / secsz;
+	for (n = 0; n < ngrains; n++) {
+		blkofs = n * blkcnt;
+		if (image_data(blkofs, blkcnt)) {
+			le32enc(gt + n, cursec);
+			cursec += grainsz;
+		}
+	}
 
 	error = 0;
 	if (!error && sparse_write(fd, &hdr, VMDK_SECTOR_SIZE) < 0)
@@ -211,9 +218,19 @@ vmdk_write(int fd)
 		if (buf != NULL)
 			free(buf);
 	}
-	if (!error)
-		error = image_copyout(fd);
-	return (error);
+	if (error)
+		return (error);
+
+	blkcnt = (grainsz * VMDK_SECTOR_SIZE) / secsz;
+	for (n = 0; n < ngrains; n++) {
+		blkofs = n * blkcnt;
+		if (image_data(blkofs, blkcnt)) {
+			error = image_copyout_region(fd, blkofs, blkcnt);
+			if (error)
+				return (error);
+		}
+	}
+	return (image_copyout_done(fd));
 }
 
 static struct mkimg_format vmdk_format = {


More information about the svn-src-all mailing list