image.c revision 265725
1265574Smarcel/*-
2265574Smarcel * Copyright (c) 2014 Juniper Networks, Inc.
3265574Smarcel * All rights reserved.
4265574Smarcel *
5265574Smarcel * Redistribution and use in source and binary forms, with or without
6265574Smarcel * modification, are permitted provided that the following conditions
7265574Smarcel * are met:
8265574Smarcel * 1. Redistributions of source code must retain the above copyright
9265574Smarcel *    notice, this list of conditions and the following disclaimer.
10265574Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11265574Smarcel *    notice, this list of conditions and the following disclaimer in the
12265574Smarcel *    documentation and/or other materials provided with the distribution.
13265574Smarcel *
14265574Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15265574Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16265574Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17265574Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18265574Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19265574Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20265574Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21265574Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22265574Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23265574Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24265574Smarcel * SUCH DAMAGE.
25265574Smarcel */
26265574Smarcel
27265574Smarcel#include <sys/cdefs.h>
28265574Smarcel__FBSDID("$FreeBSD: user/marcel/mkimg/image.c 265725 2014-05-09 01:13:14Z marcel $");
29265574Smarcel
30265574Smarcel#include <sys/types.h>
31265574Smarcel#include <assert.h>
32265574Smarcel#include <errno.h>
33265574Smarcel#include <stdlib.h>
34265574Smarcel#include <unistd.h>
35265574Smarcel
36265579Smarcel#include "image.h"
37265574Smarcel#include "mkimg.h"
38265574Smarcel
39265574Smarcel#define	BUFFER_SIZE	(1024*1024)
40265574Smarcel
41265618Smarcelstatic char image_tmpfile[] = "/tmp/mkimg-XXXXXX";
42265618Smarcelstatic int image_fd = -1;
43265725Smarcelstatic lba_t image_size;
44265618Smarcel
45265618Smarcelstatic void
46265618Smarcelcleanup(void)
47265618Smarcel{
48265618Smarcel
49265618Smarcel	if (image_fd != -1)
50265618Smarcel		close(image_fd);
51265618Smarcel	unlink(image_tmpfile);
52265618Smarcel}
53265618Smarcel
54265574Smarcelint
55265574Smarcelimage_copyin(lba_t blk, int fd, uint64_t *sizep)
56265574Smarcel{
57265574Smarcel	char *buffer;
58265574Smarcel	uint64_t bytesize;
59265574Smarcel	ssize_t bcnt, rdsz;
60265574Smarcel	int error, partial;
61265574Smarcel
62265574Smarcel	assert(BUFFER_SIZE % secsz == 0);
63265574Smarcel
64265574Smarcel	buffer = malloc(BUFFER_SIZE);
65265574Smarcel	if (buffer == NULL)
66265574Smarcel		return (ENOMEM);
67265574Smarcel	bytesize = 0;
68265574Smarcel	partial = 0;
69265574Smarcel	while (1) {
70265574Smarcel		rdsz = read(fd, buffer, BUFFER_SIZE);
71265574Smarcel		if (rdsz <= 0) {
72265574Smarcel			error = (rdsz < 0) ? errno : 0;
73265574Smarcel			break;
74265574Smarcel		}
75265574Smarcel		if (partial)
76265574Smarcel			abort();
77265574Smarcel		bytesize += rdsz;
78265574Smarcel		bcnt = (rdsz + secsz - 1) / secsz;
79265574Smarcel		error = image_write(blk, buffer, bcnt);
80265574Smarcel		if (error)
81265574Smarcel			break;
82265574Smarcel		blk += bcnt;
83265574Smarcel		partial = (bcnt * secsz != rdsz) ? 1 : 0;
84265574Smarcel	}
85265574Smarcel	free(buffer);
86265574Smarcel	if (sizep != NULL)
87265574Smarcel		*sizep = bytesize;
88265574Smarcel	return (error);
89265574Smarcel}
90265574Smarcel
91265574Smarcelint
92265618Smarcelimage_copyout(int fd)
93265574Smarcel{
94265618Smarcel	char *buffer;
95265618Smarcel	off_t ofs;
96265618Smarcel	ssize_t rdsz, wrsz;
97265618Smarcel	int error;
98265574Smarcel
99265618Smarcel	ofs = lseek(fd, 0L, SEEK_CUR);
100265618Smarcel
101265618Smarcel	buffer = malloc(BUFFER_SIZE);
102265618Smarcel	if (buffer == NULL)
103265618Smarcel		return (errno);
104265618Smarcel	if (lseek(image_fd, 0, SEEK_SET) != 0)
105265618Smarcel		return (errno);
106265618Smarcel	error = 0;
107265618Smarcel	while (1) {
108265618Smarcel		rdsz = read(image_fd, buffer, BUFFER_SIZE);
109265618Smarcel		if (rdsz <= 0) {
110265618Smarcel			error = (rdsz < 0) ? errno : 0;
111265618Smarcel			break;
112265618Smarcel		}
113265618Smarcel		wrsz = (ofs == -1) ?
114265618Smarcel		    write(fd, buffer, rdsz) :
115265618Smarcel		    sparse_write(fd, buffer, rdsz);
116265618Smarcel		if (wrsz < 0) {
117265618Smarcel			error = errno;
118265618Smarcel			break;
119265618Smarcel		}
120265618Smarcel	}
121265618Smarcel	free(buffer);
122265623Smarcel	ofs = lseek(fd, 0L, SEEK_CUR);
123265623Smarcel	ftruncate(fd, ofs);
124265618Smarcel	return (error);
125265618Smarcel}
126265618Smarcel
127265725Smarcellba_t
128265725Smarcelimage_get_size(void)
129265725Smarcel{
130265725Smarcel
131265725Smarcel	return (image_size);
132265725Smarcel}
133265725Smarcel
134265618Smarcelint
135265618Smarcelimage_set_size(lba_t blk)
136265618Smarcel{
137265618Smarcel
138265725Smarcel	image_size = blk;
139265618Smarcel	if (ftruncate(image_fd, blk * secsz) == -1)
140265618Smarcel		return (errno);
141265574Smarcel	return (0);
142265574Smarcel}
143265574Smarcel
144265574Smarcelint
145265618Smarcelimage_write(lba_t blk, void *buf, ssize_t len)
146265574Smarcel{
147265574Smarcel
148265618Smarcel	blk *= secsz;
149265618Smarcel	if (lseek(image_fd, blk, SEEK_SET) != blk)
150265618Smarcel		return (errno);
151265618Smarcel	len *= secsz;
152265685Smarcel	if (sparse_write(image_fd, buf, len) != len)
153265618Smarcel		return (errno);
154265574Smarcel	return (0);
155265574Smarcel}
156265618Smarcel
157265618Smarcelint
158265618Smarcelimage_init(void)
159265618Smarcel{
160265618Smarcel
161265618Smarcel	if (atexit(cleanup) == -1)
162265618Smarcel		return (errno);
163265618Smarcel	image_fd = mkstemp(image_tmpfile);
164265618Smarcel	if (image_fd == -1)
165265618Smarcel		return (errno);
166265618Smarcel	return (0);
167265618Smarcel}
168