From owner-svn-src-all@FreeBSD.ORG Mon Jul 28 02:07:19 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 2BD10793; Mon, 28 Jul 2014 02:07:19 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 0D47021C4; Mon, 28 Jul 2014 02:07:19 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s6S27Ibu038615; Mon, 28 Jul 2014 02:07:18 GMT (envelope-from marcel@svn.freebsd.org) Received: (from marcel@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s6S27G0T038597; Mon, 28 Jul 2014 02:07:16 GMT (envelope-from marcel@svn.freebsd.org) Message-Id: <201407280207.s6S27G0T038597@svn.freebsd.org> From: Marcel Moolenaar Date: Mon, 28 Jul 2014 02:07:16 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r269177 - stable/10/usr.bin/mkimg X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 28 Jul 2014 02:07:19 -0000 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 #include #include +#include #include #include #include @@ -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 \t- file to write image into\n"); fprintf(stderr, "\t-p \n"); fprintf(stderr, "\t-s \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 \t- number of heads to simulate\n"); fprintf(stderr, "\t-P \t- physical sector size\n"); fprintf(stderr, "\t-S \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 -#include #include #include #include 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 -#include #include #include #include @@ -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 = {