From owner-svn-src-user@FreeBSD.ORG  Wed Oct  1 01:18:26 2014
Return-Path: <owner-svn-src-user@FreeBSD.ORG>
Delivered-To: svn-src-user@freebsd.org
Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115])
 (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))
 (No client certificate requested)
 by hub.freebsd.org (Postfix) with ESMTPS id 2087FD2F;
 Wed,  1 Oct 2014 01:18:26 +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 0D883FFD;
 Wed,  1 Oct 2014 01:18:26 +0000 (UTC)
Received: from svn.freebsd.org ([127.0.1.70])
 by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s911IPCn039777;
 Wed, 1 Oct 2014 01:18:25 GMT (envelope-from marcel@FreeBSD.org)
Received: (from marcel@localhost)
 by svn.freebsd.org (8.14.9/8.14.9/Submit) id s911IPb0039776;
 Wed, 1 Oct 2014 01:18:25 GMT (envelope-from marcel@FreeBSD.org)
Message-Id: <201410010118.s911IPb0039776@svn.freebsd.org>
X-Authentication-Warning: svn.freebsd.org: marcel set sender to
 marcel@FreeBSD.org using -f
From: Marcel Moolenaar <marcel@FreeBSD.org>
Date: Wed, 1 Oct 2014 01:18:25 +0000 (UTC)
To: src-committers@freebsd.org, svn-src-user@freebsd.org
Subject: svn commit: r272338 - user/marcel/mkimg
X-SVN-Group: user
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-BeenThere: svn-src-user@freebsd.org
X-Mailman-Version: 2.1.18-1
Precedence: list
List-Id: "SVN commit messages for the experimental &quot; user&quot;
 src tree" <svn-src-user.freebsd.org>
List-Unsubscribe: <http://lists.freebsd.org/mailman/options/svn-src-user>,
 <mailto:svn-src-user-request@freebsd.org?subject=unsubscribe>
List-Archive: <http://lists.freebsd.org/pipermail/svn-src-user/>
List-Post: <mailto:svn-src-user@freebsd.org>
List-Help: <mailto:svn-src-user-request@freebsd.org?subject=help>
List-Subscribe: <http://lists.freebsd.org/mailman/listinfo/svn-src-user>,
 <mailto:svn-src-user-request@freebsd.org?subject=subscribe>
X-List-Received-Date: Wed, 01 Oct 2014 01:18:26 -0000

Author: marcel
Date: Wed Oct  1 01:18:25 2014
New Revision: 272338
URL: http://svnweb.freebsd.org/changeset/base/272338

Log:
  Implement image_copyout_region(): This is the one function that is
  responsible for writing to the output file. For eack chunk that
  covers all or parts of the region to write, call a corresponding
  function that knows how to write a chunk of that type:
  
  image_copyout_memory():	Use write(2) to write the buffer.
  image_copyout_zeroes():	Try and seek forward to create a sparse
  	file. If that fails, scribble zeroes to the output file to
  	support writing to stdout. Use image_copyout_memoryIO for
  	that.
  image_copyout_file():	Iteratively map bits of the input file and
  	use image_copyout_memory() to write the bits to the output
  	file.
  
  With this commit all unit tests pass again.

Modified:
  user/marcel/mkimg/image.c

Modified: user/marcel/mkimg/image.c
==============================================================================
--- user/marcel/mkimg/image.c	Tue Sep 30 23:29:06 2014	(r272337)
+++ user/marcel/mkimg/image.c	Wed Oct  1 01:18:25 2014	(r272338)
@@ -499,6 +499,10 @@ image_copyin(lba_t blk, int fd, uint64_t
 	return (error);
 }
 
+/*
+ * Output/sink file handling.
+ */
+
 int
 image_copyout(int fd)
 {
@@ -523,46 +527,103 @@ image_copyout_done(int fd)
 	return (error);
 }
 
-int
-image_copyout_region(int fd, lba_t blk, lba_t size)
+static int
+image_copyout_memory(int fd, size_t size, void *ptr)
 {
-	char *buffer;
-	off_t ofs;
-	size_t bufsz, sz;
-	ssize_t rdsz, wrsz;
+
+	if (write(fd, ptr, size) == -1)
+		return (errno);
+	return (0);
+}
+
+static int
+image_copyout_zeroes(int fd, size_t size)
+{
+	static uint8_t *zeroes = NULL;
+	size_t sz;
 	int error;
 
-	bufsz = secsz * image_swap_pgsz;
+	if (lseek(fd, (off_t)size, SEEK_CUR) != -1)
+		return (0);
 
-	ofs = lseek(fd, 0L, SEEK_CUR);
+	/*
+	 * If we can't seek, we must write.
+	 */
+
+	if (zeroes == NULL) {
+		zeroes = calloc(1, secsz);
+		if (zeroes == NULL)
+			return (ENOMEM);
+	}
+
+	while (size > 0) {
+		sz = (size > secsz) ? secsz : size;
+		error = image_copyout_memory(fd, sz, zeroes);
+		if (error)
+			return (error);
+		size -= sz;
+	}
+	return (0);
+}
+
+static int
+image_copyout_file(int fd, size_t size, int ifd, off_t iofs)
+{
+	void *buf;
+	size_t iosz, sz;
+	int error;
+
+	iosz = secsz * image_swap_pgsz;
+
+	while (size > 0) {
+		sz = (size > iosz) ? iosz : size;
+		buf = image_file_map(ifd, iofs, sz);
+		if (buf == NULL)
+			return (errno);
+		error = image_copyout_memory(fd, sz, buf);
+		image_file_unmap(buf, sz);
+		if (error)
+			return (error);
+		size -= sz;
+		iofs += sz;
+	}
+	return (0);
+}
+
+int
+image_copyout_region(int fd, lba_t blk, lba_t size)
+{
+	struct chunk *ch;
+	size_t ofs, sz;
+	int error;
 
-	blk *= secsz;
-	if (lseek(image_swap_fd, blk, SEEK_SET) != blk)
-		return (errno);
-	buffer = malloc(bufsz);
-	if (buffer == NULL)
-		return (errno);
-	error = 0;
 	size *= secsz;
+
 	while (size > 0) {
-		sz = ((ssize_t)bufsz < size) ? bufsz : (size_t)size;
-		rdsz = read(image_swap_fd, buffer, sz);
-		if (rdsz <= 0) {
-			error = (rdsz < 0) ? errno : 0;
+		ch = image_chunk_find(blk);
+		if (ch == NULL)
+			return (EINVAL);
+		ofs = (blk - ch->ch_block) * secsz;
+		sz = ch->ch_size - ofs;
+		sz = ((lba_t)sz < size) ? sz : (size_t)size;
+		switch (ch->ch_type) {
+		case CH_TYPE_ZEROES:
+			error = image_copyout_zeroes(fd, sz);
 			break;
-		}
-		wrsz = (ofs == -1) ?
-		    write(fd, buffer, rdsz) :
-		    sparse_write(fd, buffer, rdsz);
-		if (wrsz < 0) {
-			error = errno;
+		case CH_TYPE_FILE:
+			error = image_copyout_file(fd, sz, ch->ch_u.file.fd,
+			    ch->ch_u.file.ofs + ofs);
 			break;
+		case CH_TYPE_MEMORY:
+			error = image_copyout_memory(fd, sz, ch->ch_u.mem.ptr);
+			break;
+		default:
+			return (EDOOFUS);
 		}
-		assert(wrsz == rdsz);
-		size -= rdsz;
+		size -= sz;
+		blk += sz / secsz;
 	}
-	free(buffer);
-	return (error);
+	return (0);
 }
 
 int